熟练使用 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(大写)