vim-adventure
前言
vim作为编辑器来说,学习曲线确实很陡。但入门之后vim会越用越顺手,根据个人配置的vim也会越来越好用。vim-adventure提供了一个学习和游戏结合的环境(虽然最后的游戏难度可能会让人望而却步。。),可以用以入门vim的操作
游戏官网入口:Learn VIM while playing a game - VIM Adventures
参考攻略入口:最好的Vim学习教程-Vim Adventures 全攻略(附彩蛋)
在玩vim-adventure的过程中学习(或复习)了一些vim的基础知识,在本文记录笔记,作为以后万一遗忘了的搜索材料。
关卡
Level1(h,j,k,l)
使用
h,j,k,l键使光标单格进行上下左右的移动,类似于方向键。
注意如果光标在行末而每一行的长度不同的话,光标会根据长度最长的行自动调整其跳转位置。
Level2(w,b,e)
使用
w,b,e键使光标按词进行移动。
-
w使光标跳转到下个词(word)开头。 -
b使光标跳转到当前词开头,如果已经在当前词开头(back),则跳转到前个词开头。 -
e使光标跳转到当前词结尾,如果已经在当前词结尾(edge),则跳转到下个词结尾。
注意w,b,e会将标点(如引号",逗号,还有空格<space>等)当成一整个词。
Level3 & Level 4(W,B,E,x,r)
使用
W,B,E键使光标按整词进行移动。整体的移动方式类似w,b,e
与w,b,e不同的是,W,B,E会包含标点在词内,不会将标点单独当成一整个词
使用
x键删除单个字符,使用r键替换单个字符
x的作用是删除(cross)当前光标下的单个字符。等效于输入dl;大写X的作用是删除当前光标前一个光标下的单个字符。
r的作用是替换(replace),按r后输入正确字符可以替换当前字符。
Level5(d)
使用
d键配合其他按键进行删除操作
d的作用是删除(delete)字符/行/段落, 但是单独的d只是一个操作符(operator),需要根据实际的动作(motion)命令来产生效果。
比如之前移动光标的w,b,e就是动作命令。因此
dw删除字符到下个词(delete word)开头。db删除字符到当前词开头,如果已经在当前词开头(delete back),则删除字符到前个词开头。de删除字符到当前词结尾,如果已经在当前词结尾(delete edge),则删除字符到下个词结尾。
同理,dW,dB,dE删除时会包含标点在词内,不会将标点单独当成一整个词
再比如如之前上下左右移动光标的h,j,k,l也是动作命令。因此
dh删除当前光标左边的字符,即删除当前光标之前的字符(delete h)。dl删除当前光标右边的字符,即删除当前光标的字符(delete l),等效于x。dj删除当前行及其下一行的所有字符(delete j)。dk删除当前行及其上一行的所有字符(delete k)。
另外, 重复两次操作符代表对当前行操作,因此
dd删除当前行所有字符。
Level6(~,$,0,^,D)
使用
~键对单个字符进行大小写转换使用
$键跳转到行尾使用
0键跳转到行首使用
^键跳转到行首非空字符
~的操作类似于r的替换(replace),只针对单个字符使用,如果字符是大写则转换为小写,反之亦然。
同样的,$,0,^也是动作命令,也可以结合d来操作。因此
d$删除当前光标到行尾的所有字符(delete $)。d0删除当前光标到行首的所有字符(delete 0)。d^删除当前光标到行首非空字符的所有字符(delete ^)。
值得注意的是,D单键等效于d$的功能,之后还会见到一些类似功能。因此,每当想进行“剪切/删除/复制/添加” “到行尾”操作的时候,都可以先看看是不是可以使用大写字母替代其功能,减少操作次数。
小结1 ( operator + motion )
vim的基础操作模式可以分为两种。
- 单键操作
-
单键操作单个字符:
x删除单个字符r替代单个字符~单个字符大小写转换
-
单键操作跳转动作(动作命令):
h,j,k,l,跳转单个字符w,b,e,跳转单个词(W,B,E类似)$,0,^,跳转行首行末
-
- 操作符+动作命令
d删除操作符,配合动作命令完成删除
Level7(f,t,F,T,,,;,z,%,g,G)
使用
f键向后跳转到指定字符位置使用
t键向后跳转到指定字符的位置前使用
,键和;键重复查找跳转的操作
查找字符跳转操作包括f和t
-
f的作用是向后查找(find)某个特定的单个字符的位置并跳转。比如按fa后,在查找到下一个字符“a”的位置后光标会跳转到其位置。F的操作与f相同,只是方向是向前查找。 -
t的作用是向后查找直到(till)某个特定单个字符位置之前的位置并跳转。比如按ta后,在查找到下一个字符“a”的位置后光标会跳转其位置之前的位置。T的操作与t相同,只是方向是向前查找。
在完成一次f或t的单个字符的查找跳转之后,再使用;可以重复查找操作,而再使用,可以反向重复查找操作。比如按fa之后,光标会跳转到下一个字符"a"的位置;这时按;则等效重复fa的操作,查找到再下一个字符"a"的位置;而按,则等效重复Fa的操作,查找到上一个字符"a"的位置。
值得注意的是,只要操作过f或者t,操作就会被记录在寄存器中,因此这时可以随时使用;或者,重复这个操作。
同样的,f,t,F,T也是动作命令,也可以结合d来操作。因此
df+特定字符删除当前光标到下一个查找到的特定字符。比如dfa(delete find a),会从当前光标删除字符到下一个字符"a"所在位置。dt+特定字符删除当前光标直到下一个查找到的特定字符之前的位置。比如dta(delete till a),会从当前光标删除字符直到下一个字符"a"所在位置之前的位置。dT和dF的原理跟上面两个指令相同,只是查找方向相反
使用
z键配合其他按键进行窗口调整操作
z的作用是调整窗口页面视角的位置(scroll,发音类似zcroll)。类似的,z只是一个操作符(operator),会根据实际的动作(motion)命令来产生效果。z的用法比较特殊,主要是以下几个
zz调整窗口页面视角使当前行在居中位置。(重复两次操作符代表对当前行操作)zt调整窗口页面视角使当前行在最顶层(scroll top)。zb调整窗口页面视角使当前行在最底层(scroll bottom)。
使用
%键在括号间匹配跳转
%的作用是括号匹配跳转(match)。%主要用于在编程中方便地在匹配的括号(包括{},())或是成对的标签之间跳转。比如在字符{处按%,则会跳转到与之对应的}处。
在不同的编程语言中,匹配的方式是不同的。在vim中可以通过配置文件自行添加标签匹配,比如在verilog中,begin和end就是一对匹配的标签,添加后即可匹配跳转。
使用
g键进行全文跳转
g的作用是全文跳转(go)。类似的,单独的g只是一个操作符(operator),会根据实际的动作(motion)命令来产生效果。g的用法同样比较特殊,主要是以下几个
-
gg使光标跳转到全文的开头。 -
G使光标跳转到全文的结尾。
其实G可以配合数字使用跳转到指定行,不过当前这关还没有引入数字。比如5G可以跳转到第5行。
同样的,g,G也是动作命令,也可以结合d来操作。因此
-
dgg删除当前光标到全文的开头的所有字符。(delete gg) -
dG删除当前光标到全文的结尾的所有字符。 (delete G)
Level8(*,#,n,N)
使用
*键搜索距离光标最近的词,同时跳转过去(正向)。使用
#键搜索距离光标最近的词,同时跳转过去(反向)。使用
n键和N键重复搜索跳转的操作
整词搜索跳转操作包括*和#
*的作用是向后查找某个特定的词的位置并跳转。#的操作与*相同,只是方向是向前查找。
在完成一次*或#的整词搜索跳转之后,再使用n(next)可以重复搜索操作,而再使用N可以反向重复查找操作。比如按*之后,光标会跳转到下一个距离最近词的位置;这时按n则等效重复*的操作,查找到再下一个词的位置;而按N则等效重复#的操作,查找到上一个词的位置。
Level9( number )
数字操作
数字操作是一个强大的重复功能,几乎之前所有的动作命令都可以通过数字进行重复,而通过操作符+动作命令的操作同样可以通过数字进行多次重复操作。以之前每个level的一些命令为例
j使光标进行向下的移动,而2j则使光标进行向下的移动2次w使光标跳转到下个单词(word)开头,而3w则使光标跳转到往下第3个单词(3 word)的开头x的作用是删除(cross)当前光标下的单个字符,而5x则是删除(cross)当前光标往后的5个字符r的作用是替换(replace),而5r则是替换(replace)当前光标往后的5个字符为同一个字符dw删除字符到下个单词(delete word)开头,而5dw或d5w则是删除字符到下5个词(5 delete word / delete 5 word)开头,简单来说就是删除5个词dj删除当前行及其下一行的所有字符(delete j),而6dj或d6j则是删除当前行及其下6行的所有字符(6 delete j/ delete 6 j),简单来说就是加上当前行删7行dd删除当前行所有字符,而6dd或d6d则是删除当前6行的所有字符,简单来说就是加上当前行删6行$使光标跳转到行尾,而7$则是使光标跳转到往下第7个行尾fa(find a)在查找到下一个字符“a”的位置后光标会跳转到其位置,而3fa或f3a会查找到往后第3个字符“a”(3 find a / find 3 a)并跳转到其位置dtb(delete till b)会从当前光标删除字符直到下一个字符"b"所在位置之前的位置,而d2tb(delete 2 till b)会从当前光标删除字符直到**下2个字符"b"**所在位置之前的位置。5G可以跳转到第5行。- 在完成一次
*或#的整词搜索跳转之后,再使用n(next)可以重复搜索操作,而如果在这时使用5n,则会执行5次重复搜索操作。
加入数字的操作极大的减少了键盘的操作次数,可以通过数字进行大量的重复操作。
小结2( operator + number + motion)
vim的基础操作模式可以分为几种。
-
单字符操作
x删除单个字符r替代单个字符~单个字符大小写转换
-
特殊操作
z组合操作窗口调整(zz,zt,zb)g操作全文跳转(gg,G)%匹配跳转
-
跳转动作(动作命令):
h,j,k,l,跳转单个字符w,b,e,跳转单个词(W,B,E类似)$,0,^,跳转行首行末f,t,查找字符跳转;;,,,重复查找gg,G,全文跳转*,#,搜索词跳转;n,N,重复搜索
-
数字+操作符+动作命令 或 操作符+数字+动作命令
d删除操作符,配合动作命令(3中的任何动作)以及数字完成多次删除
Level10(p,P,y,:reg,"1-9,"","a-z)
使用
p键进行粘贴操作
在文本编辑器中被删除的内容一般可以通过撤销来恢复,因此被删除的内容其实是被存在了寄存器(register)中;在vim中也类似,只是可以通过操作访问各个寄存器并实现特定的复制(剪切)及粘贴操作。
寄存器包括无名寄存器(unnamed,最常用的寄存器),小删除寄存器(small delete),数字寄存器(numbered,1-9),具名寄存器(named,a-z),黑洞寄存器(black hole)等。 这些都不需要记忆,当使用的时候自然就会明白这些寄存器是拿来做什么的。
p的作用是粘贴(paste)。粘贴的可以是删除(即剪切,针对d和x)掉的内容,也可以是复制(针对y)的内容,根据最新一次的操作决定。
p的粘贴操作在当前光标之后。P的粘贴操作在当前光标之前。
"指定剪切/复制所使用的寄存器
:reg查看当前寄存器
"1,"2…"9数字寄存器(numbered)
"的作用是指定寄存器,而:reg的作用是查看寄存器。以数字寄存器(numbered)为例
由上面的图可见,在这里通过dd指令删除了4行,而4行内容被依次记录在了数字寄存器1~4中,越新的内容记录的位置越前,即1号寄存器记录最新删除的内容。因此,数字寄存器的作用是记录历史删除(即剪切,针对d和x)或复制(针对y)的内容。
假如删除了4行然后想粘贴第1行内容到当前位置怎么办呢?现在已知第1行的内容已经在4号寄存器,因此只要使用"4p(number 4 register paste)就可以了。
使用
y键配合其他按键进行复制操作
y的作用是复制(yank)字符/行/段落,类似于d,单独的y只是一个操作符(operator),需要根据实际的动作(motion)命令来产生效果。因此所有对d有效果的动作命令对y依然有效,只是动作从删除变为了复制。例如
yw复制字符到下个词(yank word)开头。yj复制当前行及其下一行的所有字符(yank j)。yy复制当前行所有字符。yG复制当前光标到全文的结尾的所有字符。 (yank G)
类似的,使用数字重复操作也同样适用于y。同时复制的内容也会存入数字寄存器。同样的,通过p或者P进行复制内容的粘贴操作。
yw复制字符到下个单词(yank word)开头,而5yw或y5w则是复制字符到下5个词(5 yank word / yank 5 word)开头,简单来说就是复制5个词yj复制当前行及其下一行的所有字符(yank j),而6yj或y6j则是复制当前行及其下6行的所有字符(6 yank j/ yank 6 j),简单来说就是加上当前行复制7行yy复制当前行所有字符,而6yy或y6y则是复制当前6行的所有字符,简单来说就是加上当前行复制6行
值得注意的是,类似于D单键等效于d$的功能,Y单键等效于y$的功能。因此,可通过Y键进行从当前光标复制到行尾的操作,减少操作次数Y单键等效于yy的功能。因此,可通过Y键进行复制当前行所有字符的操作,减少操作次数。
简而言之,所有y相关操作均可参考d。
""无名寄存器(unnamed)
最近一次删除(即剪切,针对d和x)或复制(针对y)的内容会保存在无名寄存器(unnamed),按p或P的时候调用的就是无名寄存器存储的值。
"a,"b…"z具名寄存器(named)
删除(即剪切,针对d和x)或复制(针对y)的内容可以指定存在"a-"z的具名寄存器中,通过p或P粘贴时也可以指定具名寄存器粘贴。当某个具名寄存器已有内容时,"a-"z会替换寄存器内的内容,而"A-"Z则会在对应寄存器后进行追加。
例如上图的操作中,通过"ayw复制词Through<space>替换a寄存器(register a yank word),通过"Ayw复制词God!追加到a寄存器尾部,再次通过"Ayw"复制词all到a寄存器尾部,从而实现了从多个地方复制。在最后通过"ap进行粘贴操作(register a paste)。
Level11(c,C,s,i,I,a,A,o,O)
插入模式
之前的操作均是在普通模式下进行的,即所有操作是对已经写好的文本进行剪切、复制、粘贴、转换等操作,并不进行新文本的插入。而要进行新文本的插入,则需要进入插入模式。使用一些按键(比如i,a,c)进入插入模式,通过<Esc>或者<C-[>回到普通模式。
使用
c键配合其他按键进行删除然后进入插入模式的操作
c的作用是改变(change)字符/行/段落,类似于d,单独的c只是一个操作符(operator),需要根据实际的动作(motion)命令来产生效果。因此所有对d有效果的动作命令对c依然有效,只是动作从删除变为了改变(即删除然后进入插入模式)。例如
cw删除字符到下个词(change word)开头,并进入插入模式。cj删除当前行及其下一行的所有字符(change j)。cc删除当前行所有字符,并进入插入模式。cG删除当前光标到全文的结尾的所有字符,并进入插入模式(change G)。
同时,类似于d的是,通过c删除的内容也会存储在数字寄存器内。
值得注意的是,类似于D单键等效于d$的功能,C单键等效于c$的功能。因此,可通过C键进行从当前光标删除到行尾,并进入插入模式的操作,减少操作次数。
使用
s键删除单个字符并进入插入模式
如果说c对应d+进入插入模式的话,s应该就是对应x+进入插入模式了。前者要进入插入模式插入文字,后者依旧保持普通模式,不进行文字插入。因此
dl删除当前光标右边的字符,即删除当前光标的字符(delete l),等效于x。cl删除当前光标右边的字符并进入插入模式,即改变当前光标的字符(change l),等效于s。
使用
i键在当前字符前进入插入模式。使用
a键在当前字符后进入插入模式。
i和a是最常用的进入插入模式插入文本的方法,注意i和a并不是操作符,因此并不能搭配动作指令,它们的指令效果是立刻生效的。
值得注意的是,类似于D单键等效于d$的功能,A单键等效于$a(注意a不是操作符,因此不能使用a$)的功能。因此,可通过A键进行从当前光标跳转到行尾,并在行尾后进入插入模式的操作,减少操作次数。
类似的,I单键等效于^i(注意i不是操作符,因此不能使用i^)的功能。因此,可通过I键进行从当前光标跳转到行首(非空格),并在行首前进入插入模式的操作,减少操作次数。
简而言之,通过i和a进行当前光标字符前插入和字符后插入,通过I和A进行行首插入和行末插入。
使用
o键新建空白行并进入插入模式。
o的作用是在当前光标下新建空白行并进入插入模式。O则是在上一行插入。
o的新建一行操作在当前光标之下。O的新建一行操作在当前光标之上。
数字操作
普通模式的命令进入插入模式时仍可以通过数字进行重复。以之前的一些命令为例
cw删除字符到下个词(change word)开头,并进入插入模式;而c2w会删除到下2个词(change 2 word)开头,并进入插入模式。a在当前字符后进入插入模式。 而2a会进入插入模式,并在退回普通模式时插入2次内容。o的新建一行操作在当前光标之下。而3o会进入插入模式,并在退回普通模式时候插入3行内容。
小结3( uppercase )
vim的模式有普通模式和插入模式。基础操作模式可以分为几种。
-
特殊操作
z组合操作窗口调整(zz,zt,zb)%匹配跳转
-
跳转动作(动作命令)+数字(可不加):
h,j,k,l,跳转单个字符w,b,e,跳转单个词(W,B,E类似)$,0,^,跳转行首行末f,t,查找字符跳转;;,,,重复查找gg,G,全文跳转*,#,搜索词跳转;n,N,重复搜索
-
单字符+数字(可不加)操作
x删除单个字符,r替代单个字符,s删除单个字符并进入插入模式~单个字符大小写转换i和a进入插入模式(字符前/后)
-
数字+操作符+动作命令 或 操作符+数字+动作命令
d删除操作符,配合动作命令(2中的任何动作)以及数字完成多次删除y复制操作符,配合动作命令(2中的任何动作)以及数字完成多次复制c改变操作符,配合动作命令(2中的任何动作)以及数字完成多次改变(即删除+进入插入模式)
大写按键需要注意的是,有些大写按键等效于操作符+首尾动作命令的操作,有些则是反向操作:
| 小写按键 | 意义 | 大写按键 | 意义 |
|---|---|---|---|
w b e |
字跳转 | W B E |
字跳转(带标点、空格) |
x |
向后删除单字符 | X |
向前删除单字符 |
r |
替换单字符 | R |
替换多个字符 |
f t |
查找跳转 | F T |
反向查找跳转 |
p |
粘贴在光标后 | P |
粘贴在光标前 |
i a |
进入插入模式 | I A |
行首/行尾进入插入模式 |
o |
下方新建行 | O |
上方新建行 |
d |
删除操作符 | D |
等效d$,删除到行尾 |
y |
复制操作符 | Y |
y$,复制到行尾yy,复制当前行 |
c |
改变操作符 | C |
等效c$,改变到行尾 |
上表也不需要记忆,在实际使用的时候会自然形成习惯,即用了小写的按键,自然会考虑大写按键的类似操作。
Level12((,),{,},[,],object,.)
使用
(和)进行句子跳转的操作
句子跳转操作包括(和)。句子按照标点句号.,问号?以及感叹号!作为结尾标识。
-
(的作用是向前跳转到上一句(首个非空字符)。 -
)的作用是向后跳转到下一句(首个非空字符)。
同样的,(,)也是动作命令,也可以结合d、y、c等操作符来操作。同样的,此操作仍可以通过数字进行重复。因此
d3)向后删除3句话(delete 3 sentence forward)。y2(向前复制2句话(yank 2 sentence backward)。
使用
{和}进行段落跳转的操作
段落跳转操作包括{和}。段落按照空行作为分隔标识。
{的作用是向前跳转到上一段落。}的作用是向后跳转到下一段落。
{,}也是动作命令,也可以结合d、y、c等操作符来操作。同样的,此操作仍可以通过数字进行重复。与前述按句子操作类似,在此不赘述。
使用
[]配合其他括号,包括[{,}],[(,)],[[,]],进行查找未闭合括号跳转的操作
每一对括号在代码中应该是匹配的,通过[]搜索未闭合括号的的操作可以方便查询代码结构。
-
[的作用是向前匹配到上一个未闭合括号(括号为{,(,[)。 -
]的作用是向后跳转到下一个未闭合括号(括号为},),])。
object对象操作。
i,inner object,a,an object 对象,需配合操作符使用
普通的操作符+动作命令的操作对象均是由按键决定的,比如词(w,b,e),首尾(0,^,$),搜索位置(f,t)等,但有时实际的操作对象可能要求要更精确一些。
在小结3中总结过通过操作符(d,y,c)配合动作命令和数字进行批量修改,但有时动作命令可能无法满足操作复杂度的要求。因此vim引入了对象(object)的概念。以w为例,w本身是动作命令,会使光标跳转到下个词(word)开头。 而配合动作命令则可以得到dw删除字符到下个词(delete word)开头。 假设现在的操作光标在词的中间位置,则dw无法进行完整的删除,如下图所示。
这时若将整个词(word)作为对象(object)进行处理,采用daw(delete an object word),则可以直接删除掉整个词。
常见的对象(object)包括括号(
{},(),[]),引号('',""),word(w),sentence(s),paragraph(p)等。
a和i的区别在于是否包括对象本身(边缘)。下面部分演示使用未提及的可视模式(Visual Mode)来展示对象(object)选择功能。
.重复
.的作用是重复(repeat)最近一次进行的修改。修改内容可以是删除(d),也可以是改变(c),小结3中的操作符+数字+动作命令均可通过.进行重复。.操作与配合数字操作不同的是,.的操作效果更直观,且数量控制更精确,通常.操作会配合u(undo)撤销操作一起,即重复多了就撤销,不需要在意具体的重复次数。下面演示几个简单功能来说明.操作。
-
重复删除行,重复粘贴
-
重复改变词
-
重复行尾添加分号
;
Level13(null)
13在国外不吉利,没有这关
Level14(u,<C-r>,H,L,M,|,:count,/,?,m,`,')
u撤销
<C-r>取消撤销
u的作用是撤销(undo)最近一次进行的修改。而<C-r>的作用是重做(redo)撤销的操作。类似Windows中的通用命令<C-z>撤销和<C-y>重做。
使用
HLM移动光标使用
:<count><CR>进行行跳转使用
<count>|进行列跳转
以上几个命令除了:<count><CR>平时使用较少,适合于进行某些需要精确行列号跳转的场景。
H的作用是在不滚动屏幕的状态下,将光标移动至当前屏幕显示的首行(High)。
L的作用是在不滚动屏幕的状态下,将光标移动至当前屏幕显示的尾行(Low)。
M的作用是在不滚动屏幕的状态下,将光标移动至当前屏幕显示的中间行(Middle)。
:<count><CR>的count输入任意数字可以跳转到对应行,其功能类似于<count>G。
<count>|的count输入任意数字可以跳转到对应列。
使用
/<word><CR>键全文搜索名称为<word>的词并跳转至第一个词(正向),同时高亮所有匹配的词。使用
?<word><CR>键全文搜索名称为<word>的词并跳转至第一个词(反向),同时高亮所有匹配的词。
/和?的搜索方式与*和#类似,因此依然可以使用n和N重复搜索跳转的操作。
使用
m键在指定的位置设置标记。使用
`跳转到制定的标记位置。使用
'跳转到指定的标记位置的第一个非空字符。
m的作用是标记位置(mark),例如命令 ma (mark a)表示用 a 标记当前的光标位置。可以通过输入:mark<CR>来查看当前的使用的所有mark标记。
标记包括每个缓冲区的局部标记和全局标记。局部标记可使用a-z的所有小写字母标记,而全局标记可使用A-Z的所有-大写字母标记。简单来说,局部标记可在当前文件前后跳转,全局标记可在文件间跳转。标记完成后可通过`跳转到制定的标记位置,或通过'跳转到指定的标记位置的第一个非空字符。
补:可视模式演示
本游戏vim-adventure缺少了一个重要部分,即可视模式(Visual Mode)。
v普通可视模式
V行可视模式
<C-v>(Linux or MAC)或<C-q>(Windows专用)列可视模式
可视模式的操作逻辑类似鼠标点选后修改,不过具体到vim上与其他编辑器略有不同(比如列操作时不会对所有行进行同时显示,只有退出可视模式后才会统一弹出)。这里只演示功能,不进行具体功能介绍,。
结语
本教程仅供入门,关于vim使用相关知识最全面的首推Drew Neil的Practical Vim一书,针对普通模式、插入模式、可视模式及命令行模式等多种模式、多种操作方式均有详细的技巧教程。当然因为书本身只针对vim的技术点,因此关于vim配置vimrc的相关知识就相对少一些,不过相信读完全书后每位读者都会有自己的认知和配置要求,就能自己动手开始定制自己的vim了。
完结撒花~2020/7/7















































