以下内容为学习VimScript时的记录,如果有兴趣,建议阅读原文。
1. 创建~/.vimrc
文件
.vimrc
是vim默认的配置文件,一般位于home目录下,在vim启动的时候回默认加载此文件,来初始化vim。
在vim中执行以下命令可获取当前vim实际加载的配置文件的路径:
:echo $MYVIMRC
2. :echo
和:echom
在vim中执行:echo
或者:echom
命令可以输出信息到vim底部,类似于c中的printf
。
执行如下命令,可以在vim底部打印出hello world!
。
:echo "hello world!"
:echo
和:echom
两个命令的区别在于:后者打印出出来的信息会保存下来,在vim中执行:messages
即可查看到打印的历史信息,如果有较为复杂的vim脚本逻辑,使用:echom
则方便调试
理解:
到这里应该有一个概念,
.vimrc
中的配置文件都是基于vimscript
脚本的,上述的两个命令其实就是脚本中的两个基础命令。vim底部的:
操作则类似于vimscript
实时执行的的控制台,
3. 注释
vimscript
中的注释使用"
, 如下:
" 这是一行注释
echo "hello world!"
4. 使用help命令
在vim中,可以使用help
命令查看任何其他命令的详细文档,如下:
:help echo
:help echom
:help messages
5. 设置选项
vim中有很bool类型的选项,比如是否显示行号的选项 number
,在vim中执行:set number
即可开启行号的显示,接着执行:set nonumber
即可关闭行号的显示。
凡是表达是否的选项,都是可以使用:set <name>
开启,:set no<name>
关闭。
尝试依次执行如下命令:
:set number
:set number!
:set number?
:set number!
:set number?
输出如下:
1. 开始行号显示
2. 关闭行号显示
3. vim底部显示nonumber
4. 开启行号显示
5. vim底部显示number
!
操作符可以对bool类型的配置选项取反。?
操作符则可以获取当前选项的值。因此,上述操作一次为:开启行号->关闭行号->获取nonumber
->开启行号->获取number
除了bool类型的开关选项之外,还有很多可以取多个值的选项,比如numberwidth
【显示行号的宽度】选项。
执行:set numberwidth=6
即可将行号的显示宽度设置为6,当然你可以根据自己的喜好设置为其他的数字。所以,其他类似的配置选项都可以使用如下命令来进行设置。
:set <name>=<value>
?
操作符对这些设置选项同样有效,如获取选项matchtime
的值:
:set matchtime?
在实际的配置中,一次set
可以对多个选项进行设置,如下:
:set number numberwidth=5
6. 基础映射
vim被很多人喜欢的原因就是高度的自定义。vimer可以按照自己的喜欢,对vim进行各种各样的配置,来提高自己的工作效率。这其中,最常用的的功能就是键位映射。
:map - x
执行完上述命令,在vim中选中一个字符,按下-
键,选中的字符消失了,如同按了x
快捷键。所以,map
命令可以实现键位上的映射,以此来达到快捷键的自定义。
所以,如果你想在按下-
的时候,删除光标所在的行,就可以执行:map - dd
,当按下-
的时候,就等同于按下dd
,光标所在的行就会被删除。再比如,执行map - viw
,这个时候按下-
就会高亮选中当前光标所在的整个单词。
这个时候你可能想这么操作:
:map <space> viw " select a word
完事儿,按下空格键可能不会按照原来设想的行为执行。vim会解析为:
viw<space>"<space>select<space>a<space>word
所以注意,不要在map所在行添加注释,此时"
及其后面的内容并不会被解析为注释。
7. 模式映射
到这里你可能会发现,map的映射除了normal模式之外,在visual模式也同样起作用。
如果只想让命令在指定的模式下生效,可以使用模式映射命令分别为:nmap
,vmap
,imap
三个命令,对应为normal,visual,insert三种模式。
nmap
和vmap
的行为符合我们直觉上操作,imap
则有一点点特殊。
:imap <c-d> dd
执行上述命令,我们的期望是:在insert模式下,按下Ctrl + d ,删除光标所在行。但是实际的情况是:输入了dd
。原因是vim此时在insert模式下,dd并不能删除当前行,只是输入了两个d字母。
imap
只能确保映射的命令在insert的模式可以被执行,但是具体被映射的命令在insert模式下执行情况是怎样的,需要考虑具体的情景。
所以,想要在insert模式下:按下<C-d>
来删除光标所在的行,需要如下的映射:
:imap <c-d> <esc>ddi
很容易理解:<esc>
确保回退到normal模式,dd
删除当前行,i
再进入insert模式。
- 精准映射
目前为止掌握的*map如下:
- map
- imap
- nmap
- vmap
尝试如下映射:
:nmap - dd
:nmap / -
第一行命令将-
映射为dd
,第二行命令将/
映射为-
。此时按下/发生什么?答案是删除了当前光标所在的行。因为/被解析为-,但是-又被映射为了dd,所以就执行了删除当前行的操作。因此*map有一个致命的问题就是会导致递归映射。这在实际中是非常麻烦的,因此在实际映射中通常建议使用精准映射:*noremap
。
在实际的映射中,建议任何时候都使用精准映射:noremap
,nnoremap
,vnoremap
,inoremap
。
执行如下命令:
:nnoremap x dd
:nnoremap - x
此时按下-
会忽略x
到dd
的映射,只会单纯的执行x
原来的行为,也就是剪贴当前字符。
至此学到的map
命令:
- map
- nmap
- vmap
- imap
- noremap
- nnoremap
- vnoremap
- inoremap
在脑子里回忆下这些map命令之间的区别。