熟练使用 Vim
Vim 小技巧
情景一:自动写入文件头
在编写 C++ 程序时,总有一些东西会在每个头文件中出现,比如:
1 |
|
每次键入这些信息会非常枯燥。但只要配置好 Vim ,就可以逃避这些烦人的操作。我们可以在 .vimrc 中将需要每次键入的信息写在一个函数内,每次在创建一个特定文件时(比如 .cpp),vim 会帮我们自动把这些信息写好。下面我来介绍一下使用方法,如有需要,直接拉到最后复制粘贴。
autocmd
vim 中自带的自动命令,会在指定事件发生时自动执行。我们正打算利用这一特性,迅速完成上面场景的要求,将重复的操作自动化,提高编辑效率并减少人为操作的差错。
先从最简单的开始举例,vim 中可定义以下函数,用于在文件中插入当前日期:
1 |
|
而使用以下命令,可以手动调用此函数:
1 |
|
但每次调用函数有点太过麻烦,我们使用自动命令,在保存文件时自动执行函数,其中 FileWritePre
是 vim 中的内置事件:
1 |
|
上一句话可以简单地翻译为:“在写入文件前,需要自动执行命令 call DateInsert()
”。可用简写 :au
代替 :autocmd
。内置事件有很多种,参考知乎专栏罗列在此,官方文档可见 Vim Doc:
简单的例子介绍完了,再回到情景一的问题中,结合上面给出的表格,如果要想在创建新的 .hpp
文件后,让 vim 自动添加文件头,那么应当在 vimrc
中添加:
1 |
|
现在,每次打开一个新的 .hpp 文件后,vim 都会帮我们自动执行命令 call AddHPPHeader()
。
关于函数
那么,AddHPPHeader
函数应该怎么写呢?首先,在 vimrc
中,需要定义函数 AddHPPHeader
:
1 |
|
函数内,第一步就是判断文件类型是否为 .hpp
。这里使用 expand()
内置函数可以对当前文件进行分类。expand("%:e")
中,%
表示当前文件名,而 :e
表示只有扩展名,于是该函数返回的是当前文件名的扩展名。如果文件是 hpp
,就添加文件头:
1 |
|
添加文件头内容时,有很多办法,最简单的就是使用 setline
函数一行一行地写:
1 |
|
这里的XXXX被我们写死在了 .vimrc
中,这样不够灵活,试想若换一个文件,宏定义的具体内容必然需要改变,那岂不是又要修改 .vimrc
了?
使用变量才能保证宏定义可以随着文件名等条件变化。
关于变量
vim 中,变量使用 let
进行赋值,通过 unlet
销毁变量 ,可用 echo
打印变量的值。对于 Vim 选项还可用 set
来更方便地操作,比如 set {option}
, set no{option}
, set {option}?
。
与 bash 中的变量类似,普通变量可以直接引用,环境变量要加前缀 $
、寄存器变量要加前缀 @
、Vim 选项要加前缀 &
。如,在正常模式下:
1 |
|
.=
运算符在 Vim 中用来做字符串拼接并赋值。
Vim 选项是控制着 Vim 编辑器行为的一些变量,比如是否显示行号,使用哪种剪切板。 引用选项变量时需要添加 &
前缀。例如:
1 |
|
Vim 提供了 set
命令来更方便地操作选项变量,网上相关内容很多,这里不再赘述。
变量作用域值得一提,变量默认作用域取决于定义的位置,函数内则为函数作用域,外部则为全局变量。 赋值和引用变量时可以使用 b:
,g:
,l:
,t:
等前缀来指定要操作哪个作用域的变量。
变量作用域 | 简写 | 描述 |
---|---|---|
buffer-var | b: | Local to the current buffer |
window-var | w: | Local to the current window |
tabpage-var | t: | Local to the current tab page |
global-var | g: | Global variable |
local-var | l: | Local to a function |
vim-var | v: | Global, predefined by Vim |
function-arg | a: | Function argument (only inside function) |
回到我们要解决的问题上来,先定义一个 Vim 变量,通常宏定义都是大写,因此需要用到 toupper
函数将小写的文件名变为大写。
1 |
|
考虑到,文件名路径通常包含 /
和 .
等符号,这对宏定义来说是非法的。要使用 substitute
将非法符号替换为 _
。
1 |
|
substitute
的第一个参数是要修改的字符串,第二个是 pattern,第三个是替换的子串,第四个是替换的 flags,上面这句话将文件名路径中的 /
和 .
都替换为 _
。
综合以上几点,可以如下定义 Vim 变量:
1 |
|
其中,.
在 Vim 中充当字符串连接符。如果当前文件名为 process.hpp
,那么 macro
变量的值为 _DF_PROCESS_HPP_
。
总结
最后,我们得到了一个简短有用的 Vim 自动化脚本,可以有效地解决情景一提出的问题。
1 |
|
情景二:vundle工具和nerd文件树
vundle 插件管理器
许多 vim 的第三方插件可以让工作变得更加简单。但首先,我们需要安装一个管理插件的插件 vundle,其安装方式很简单,把它的 git 仓库存在 .vim/bundle
下就行了,执行:
1 |
|
随后,我们需要在 .vimrc
上使用这个插件管理器,使用方法很简单:
1 |
|
好,复制完上面这段代码后,我们来挨个看看他们的意思。第一句 set
命令是在指定 vundle 插件的运行路径,方便进行初始化操作。随后,call vundle#begin()
启动 vundle ,开始进行插件管理。之后紧跟的三句话表示我们的 vim 会使用到如下三个插件:Vundle.vim、nerdtree 和vim-airline ,请求 vundle 对这三个插件进行管理。最后 call vundle#end()
表示 vundle 管理结束。
nerd 文件树
使用 nerd 文件树目录可以方便我们在打开 vim 的同时看到我们目前所处的文件路径和文件树结构。其安装方法与 vundle 一样简单便捷,只需执行:
1 |
|
即可完成下载和安装。但此时你打开 vim ,你仍无法看到文件树,需要输入:NERDTreeToggle
才能打开。我们可以利用在情景一中的小知识,使用 autocmd
来自动完成打开 vim 即打开文件树目录的操作:
1 |
|
受限于 vim 平台本身,nerdtree 的使用有些小门槛,需要使用它提供的环境变量与它更好地配合,下表分享一下常用的 nerdtree 变量:
变量名 | 描述 | 值 |
---|---|---|
NERDTreeDirArrowExpandable | 设置树的显示图标,该图标表示这层目录可以被展开 | 字符 |
NERDTreeDirArrowCollapsible | 设置树的显示图标,该图标表示这层目录已经被展开 | 字符 |
NERDTreeIgnore | 用于过滤所有列表中的文件 | 例如[‘\.tmp’] 表示所有扩展名为 .tmp 或 .git 的文件都不会显示在上面 |
NERDTreeShowLineNumbers | 指示 nerd 的窗口是否需要显示行号 | 1 为需要 |
NERDTreeMinimalUI | 是否需要最小化 UI | 为 1 时不显示 ‘Press ? for help’ |
NERDTreeWinSize | 指定文件树占用的窗口宽度 | 宽度值 |
顺便秀一下我的配置吧:
关于 nerdtree 的使用,还有许多有趣的小技巧分享给大家:
- nerdtree 的刷新:打开的 vim 中,Nerdtree 目录结构是不会自动刷新的,需要按 r 手动进行刷新
- 恢复显示隐藏的文件:在 nerdtree 中按 Ctrl-I(大写)