1. 文件类型和关联设定
程序源代码由文件组成,不同的文件都有一个文件类型。Vim根据文件类型的不同对不同语言采取一定的处理,可能包括
- 如何对文件进行高亮
- 制表符(tab)的宽度(空格数)
- 是否在键入
<Tab>
时扩展为空格字符 - 每次缩进的空格数(是的,可以和制表符宽度不同)
- 采用何种自动缩进方法
- 其他可适用的选项
文件高亮暂不讨论,其它各项都是以选项的形式出现。这些选项都是文件本地(local)选项,即可以在一个文件里修改其数值而不影响其他文件。对于这样的选项,可以用 :setlocal
和 :setglobal
命令分别访问本地值和全局值。一般的 :set 命令在读取数值时(如 :set tabstop?)返回本地值,在写入数值时(如 :set tabstop=4)同时设置本地值和全局值。
制表符宽度对应的选项是tabstop,默认值是8,但在不同的文件类型中该值可能会不同。
是否扩展<Tab>
为空格由expandtab选项控制,该选项是布尔类型选项,如果打开了expandtab选项,那输入的tab就会转变为空格;如果关闭的话,则tab字符会被保留。
还有个softtabstop选项,软制表符宽度,设置了这个值后,再按tab键和Backsoace键会让你觉得是按设置的宽度来缩进,有相应数量的缩进或取消缩进,但实际插入的字符仍然受 expandtab 和 tabstop 两个选项控制。
1.1 文件类型判断
Vim的文件类型判断在filetype.vim中执行,用户可以在该文件中自定义一些配置。
1.2 文件类型选项
确定了文件类型,Vim 会从运行支持文件目录下载入同名的文件。以 Python 为例:
syntax/python.vim
包含了如何对 Python 进行语法加亮的设置indent/python.vim
包含了如何对 Python 代码进行缩进的设置(如在用户输入 if 时进行缩进等)ftplugin/python.vim
是文件类型插件,包含了其他跟文件类型相关的设置
在vimrc中推荐像下面这样配置:
au FileType c,cpp,objc setlocal expandtab shiftwidth=4 softtabstop=4 tabstop=4 cinoptions=:0,g0,(0,w1
au FileType json setlocal expandtab shiftwidth=2 softtabstop=2
au FileType vim setlocal expandtab shiftwidth=2 softtabstop=2
上面的含义如下,如对c类型语言,将tab扩展为空格,shiftwidth表示当你输入{和回车键时,自动产生的缩进,缩进和制表符宽度设为4
cinoptions 可以精调 C 风格缩进的方式;上面 :0
表示 switch 下面的 case 语句不进行额外缩进,g0
代表作用域声明(public:、private: 等)不额外缩进,(0
和 w1
配合代表没结束的圆括号里的内容折行时不额外缩进。
2. Tags支持
Vim 对一种叫 tags 的文本索引格式有特殊支持。
2.1 生成tags文件的工具
推荐使用Universal Ctags工具。
# 下载
git clone https://github.com/universal-ctags/ctags.git
# 如果没安装autoconf
sudo apt-get install autoconf
./autogen.sh
./configure --prefix=/where/you/want # defaults to /usr/local
make
sudo make install # may require extra privileges depending on where to install
2.2 生成tags文件的命令
要生成 tags 文件时,你可以简单地进入到一个目录下,然后执行下面的语句对该目录及子目录下的程序源文件生成一个 tags 文件:
ctags -R .
但根据场景和语言不同,你可能需要使用更多的选项。比如,对于 C++,我一般使用:
ctags --fields=+iaS --extras=+q -R .
如果是对系统的头文件生成 tags 文件——可以用来查找函数的原型信息——那我们一般还需要加上 --c-kinds=+p
选项。
2.3 使用tags文件
如果当前目录下或当前文件所在目录下存在 tags 文件,Vim 会自动使用这个文件,不需要你做额外的设定。你所需要做的就是在待搜索的关键字上(也可以在可视模式下选中需要的关键字)使用正常模式命令 <C-]>
,或者按 g(g 可理解成 go)键加鼠标单击。你愿意的话,也可以手工输入命令 :tag
后面跟空格和待搜索的符号加回车键。这样 Vim 即会跳转到该符号的定义或声明位置。
如果待搜索的符号找不到,Vim 会报错“E426: tag not found”。如果存在一个或多个匹配项,Vim 会跳转到第一个匹配的位置。下面我列举一下其他相关的常用命令:
:tnext
(缩写 :tn)跳转到下一个标签匹配位置:tNext
(缩写 :tN)或 :tprevious
(缩写 :tp)跳转到上一个标签匹配位置:tfirst
或 :trewind
跳转到第一个标签匹配位置:tlast
跳转到最后一个标签匹配位置:tselect
名称(:tselect 可缩写为 :ts)跟 :tag 类似,但会列举可能的匹配项,让你自己选择(而非跳转到第一个匹配位置)g]
跟 <C-]>
类似,但跟 :tselect
一样会给出一个列表而非直接跳转:tjump
名称(:tjump 可缩写为 :tj)跟 :tselect 类似,但在只有一个匹配项的时候会直接跳转到匹配位置g<C-]>
跟 g]
类似,但跟 :tjump
一样在只有一个匹配项时会直接跳转到匹配位置:stselect
名称(:stselect
可缩写为 :sts
)跟 :tselect
类似,但结果会打开到一个新分割的窗口中:stjump
名称(:stjump
可缩写为 :stj
)跟 :tjump
类似,但结果会打开到一个新分割的窗口中
我们的标签跳转分为 :tag
、:tselect
和 :tjump
三种不同方法,正常模式和可视模式的命令 <C-]
也同样有后两种方法的变体,对应的命令分别是 g]
和 g<C-]>
。这三个命令前面也都可以额外加上 <C-W>
,表示结果打开到新窗口中而非当前窗口。
Vim 默认只在当前目录下和文件所在目录下寻找 tags 文件。对于含多层目录的项目,这个设定就不合适了。解决方法是使用 Vim 的选项 tags。一个小技巧是根据项目的可能深度,检查上层存在的 tags 文件:
" 加入记录系统头文件的标签文件和上层的 tags 文件
set tags=./tags;,tags,/usr/local/etc/systags
3. Tagbar插件
根据上面的描述,我们可以看到 Ctags 是一个可以从源代码中提取符号的工具。事实上,这个工具在我们不生成 tags 文件也都是有用的。Vim 的插件 tagbar 就可以利用 Ctags 来提取符号,生成源代码的结构图。只要 Ctags 能支持这种语言,插件就能“识别” 这种语言,来生成结构图;识别的好坏程度也视 Ctags 对其的支持程度而定。下面是一个示例:
安装,使用minipac,在vimrc中Other plugins”那行下面加入下面的语句,并运行 :PackUpdate 来安装一下:
call minpac#add('majutsushi/tagbar')
我给它映射了快捷键 <F9>
,可以快速打开和关闭 Tagbar 的窗口:
" 开关 Tagbar 插件的键映射
nnoremap <F9> :TagbarToggle<CR>
inoremap <F9> <C-O>:TagbarToggle<CR>
4. Quickfix窗口
Vim 里有一种特殊类型的窗口,被称作 quickfix(快速修复)。这个窗口中会展示外部命令的结果,并可以通过这个窗口中的内容直接跳转到特定文件的特定位置。这个设计最初是用来加速“编辑 - 编译 - 编辑”这个循环的,但它的实际用处并不只是用来编译程序。
可以使用命令:copen
,打开quickfix窗口。另外,我们在 quickfix 窗口中也有跟之前类似的“next”类命令:
:cnext
(缩写:cn
)跳转到下一个出错位置:cNext
(缩写:cN
)或:cprevious
(缩写:cp
)跳转到上一个出错位置:cfirst
或:crewind
跳转到第一个出错位置:clast
跳转到最后一个出错位置
事实上,在这些下一个、上一个的命令中,我用得最多的就是这个快速修复里的跳转了。为了方便记忆,我对它们都映射了相似的快捷键。
" 用于 quickfix、标签和文件跳转的键映射
nmap <F11> :cn<CR>
nmap <F12> :cp<CR>
nmap <M-F11> :copen<CR>
nmap <M-F12> :cclose<CR>
nmap <C-F11> :tn<CR>
nmap <C-F12> :tp<CR>
nmap <S-F11> :n<CR>
nmap <S-F12> :prev<CR>
这是我的映射,你可以根据自己的需要进行调整。另外要留意的一点是,取决于环境,不是所有的快捷键都能被 Vim 接收到,尤其在使用终端和远程连接的时候。
4.1 :make命令的其他细节
Vim 里的 :make
命令缺省会执行 make 命令,并且这是可以通过选项 makeprg 来进行配置的。比如,如果你希望启用四路并发编译,你就可以设置 :set makeprg=make\ -j4。你也可以使用 GNU Make 之外的构建工具,但需要注意的是,如果发现 Vim 不能识别你使用的构建工具产生的错误信息,你可能需要利用 errorformat(:help errorformat)选项来告诉 Vim 如何处理错误信息。
4.2 :grep命令
可以使用 Vim 的 :grep 命令根据关键字找到相关的源代码。跟 :make 命令相似,Vim 会调用一个合适的外部程序(可通过 grepprg 选项来进行配置)来进行搜索,并从结果中找到文件名、行号等信息。
小提示:在查看搜索结果时,适时使用 zz(或 zt、zb)重定位当前行在屏幕上的位置,可能可以更清晰地查看前后的相关代码。
4.3 异步支持
上面这些命令,都有一个缺点:在执行过程中你干不了其他事情。对于执行过程可能较慢的 make,这个问题尤其严重。幸好,在 Vim 8 支持异步任务之后,这个问题也得到了解决。我们利用一个插件,就可以获得类似在一些集成开发环境中的体验,在构建过程中仍然可以继续做其他事情。
可以安装asyncrun.vim
插件,使用minpac安装,在vimrc中的合适位置加入下面这行,
call minpac#add('skywind3000/asyncrun.vim')
我们还需要一个跟 :make 相似的命令。我使用下面的命令定义
" 和 asyncrun 一起用的异步 make 命令
command! -bang -nargs=* -complete=file Make AsyncRun -program=make @ <args>
这个命令同样会使用 makeprg 选项。不过,还有个问题是默认情况下屏幕上看不到执行过程的信息。我们可以让 asyncrun 在执行命令时立即打开 quickfix 窗口:
" 异步运行命令时打开 quickfix 窗口,高度为 10 行
let g:asyncrun_open = 10
对于 C/C++ 程序员来讲,启动和停止构建应该是一个很频繁的操作吧。所以,我也给它分配了一个快捷键:
" 映射按键来快速启停构建
nnoremap <F5> :if g:asyncrun_status != 'running'<bar>
\if &modifiable<bar>
\update<bar>
\endif<bar>
\exec 'Make'<bar>
\else<bar>
\AsyncStop<bar>
\endif<CR>
上面的代码通过判断异步任务状态和窗口是否可修改,还会自动执行保存文件和终止构建等操作。
5. 查看文档
Vim 里快捷键 K 可以用来查看光标下关键字的相关文档。它的行为是由选项 keywordprg(:help 'keywordprg')控制的。这个选项的缺省值是 man,表示查看 Unix 的 man 手册,很多文件类型插件会对当前缓冲区设置一个更合适的值,如 Vim 脚本就会直接把行为改成调用 :help 命令。查看 man 手册的默认行为通常只在终端工作良好,而在图形界面 Vim 里会出现显示问题。我推荐使用 Vim 内置的 man 插件,并把全局的 keywordprg 设成 :Man:
" 启用 man 插件source $VIMRUNTIME/ftplugin/man.vim
set keywordprg=:Man
这样,我们在使用 K 命令时,将在 Vim 里直接打开 man 手册
评论