vi/vim使用进阶: 开启文件类型检测

<< 返回vim使用进阶: 目录

本节所用命令的帮助入口:

:help filetype
:help setfiletype
:help modeline
:help 'modelines'
:help 'shiftwidth'
:help 'expandtab'
:help autocmd 

打开文件类型检测功能很简单,在你的vimrc中加入下面一句话就可以了:

filetype plugin indent on 

如果你用的是vim自带的示例vimrc,那么你已经打开了文件类型检测功能。或者,你也可以输入”:filetype“命令查看你的文件类型检测功能有没有打开。

这条命令究竟做了什么呢?我们在下面详细介绍。

其实,上面这一条命令,可以分为三条命令:

filetype on
filetype plugin on
filetype indent on 

我们逐条介绍这三条命令。

filetype on“命令打开文件类型检测功能,它相当于文件类型检测功能的开关。在执行”filetype on“命令时,vim实际上执行的是$vimRUNTIME/filetype.vim脚本。这个脚本使用了自动命令(autocmd)来根据文件名来判断文件的类型,如果无法根据文件名来判断出文件类型,它又会调用$vimRUNTIME/scripts.vim来根据文件的内容设置文件类型。有兴趣可以读一下这两个脚本,以获得更深的认识。

在上述步骤完成后,绝大多数已知类型的文件,都能被正确检测出文件类型。如果文件的类型未能被正确的检测出来,就需要手工设置文件类型,这可以通过”set filetype“完成,例如,如果你把main.c改名为main.c.bak1,那么它就无法被正确检测出文件类型。通过下面的Ex命令,就可以把它的文件类型设为c:

:set filetype=c 

或者,你可以在文件中加入一个模式行,来指明这个文件的类型。vim在打开文件时,会在文件首、尾的若干行(行数由’modelines‘选项决定,缺省为5行)检测具有vim特殊标记的行,称为模式行。如果检测到,就使用模式行中定义的选项值,来修改该缓冲区的选项。你可以留意一下vim的帮助页,每个文件的最后一行都是这样的模式行。

针对上例,我们可以在main.c.bak1的第一行或最后一行加上下面的内容,要指定这个文件的类型:

/* vim: ft=c */ 

这句话使用”/* */“注释起来了,因此不会影响编译。”ft“是”filetype“的缩写,vim中很多命令、选项都有缩写形式,以方便使用。注意”/*“与”vim:“间的空格。在”*/”与”ft=c“间,也需要有至少一个空格,这是模式行格式的要求,更多信息参阅”:help modeline“。

检测出文件的类型有什么作用呢?我们知道,不同类型的文件具有不同的格式,vim通过对文件类型的识别,可以为不同类型的文件,设置不同的选项值、定义不同键绑定等。例如,对于c类型的文件,它就和bash脚本有不同的注释格式、不同的缩进格式、不同的关键字等。vim在设置文件类型后,会触发FileType事件,执行FileType相关的自动命令,对不同类型的文件区别对待。

上面提到的”filetype plugin on“,允许vim加载文件类型插件。当这个选项打开时,vim会根据检测到的文件类型,在runtimepath中搜索该类型的所有插件,并执行它们。

filetype plugin on“命令,实际上是执行$vimRUNTIME/ftplugin.vim脚本,有兴趣可以读一下这个脚本。这个脚本中会设置自动命令,在runtimepath中搜索文件类型插件。

runtimepath的定义在不同的系统上不一样,对UNIX系统来说,这些路径包括:$HOME/.vim、$vim/vimfiles、$vimRUNTIME、$vim/vimfiles/after、$HOME/.vim/after。

举一个例子,当我们对一个c类型的文件打开”filetype plugin on”时,它会在上述这几个目录的ftplugin子目录中搜索所有名为c.vim、c_*.vim,和c/*.vim的脚本,并执行它们。在搜索时,它按目录在runtimepath中出现的顺序进行搜索。缺省的,它会执行$vimRUNTIME/ftplugin/c.vim,在这个脚本里,会设置c语言的注释格式、智能补全函数等等。

filetype indent on“允许vim为不同类型的文件定义不同的缩进格式。这条命令也是通过一个脚本来完成加载:$vimRUNTIME/indent.vim。和”filetype plugin on“类似,它也通过设置自动命令,在runtimepath的indent子目录中搜索缩进设置。对c类型的文件来说,它只是打开了cindent选项。

我们了解了文件类型检测的用途及它是如何工作的之后,就可以根据自己的需要,来对特定的文件类型进行特殊设置。

例如,我们在上篇文章中介绍过lookupfile插件,在它打开一个缓冲区时,会把缓冲区的filetype设置为lookupfile,我们可以利用这一点,在这个缓冲区里进行一些特殊的配置。例如,我们创建一个名为lookupfile.vim的文件,其内容为:

" close lookupfile window by two <Esc>
nnoremap <buffer> <Esc><Esc> <C-W>q
inoremap <buffer> <Esc><Esc> <Esc><C-W>q 

它定义了两个局部于缓冲区的键绑定,无论在normal模式还是插入模式,只要连按两次ESC,就关闭当前缓冲区。

把这个文件保存到你的runtimepath所指向任一目录的ftplugin子目录中(一般是放在~/.vim/ftplugin目录中)。你在下次打开lookupfile窗口时,试试连按两次ESC,是不是lookupfile窗口就关闭了?这样设置,非常适合vim中按ESC取消命令的习惯,效率也高。

如果你对vim缺省文件类型插件的设置不太满意,那么可以把这个全局插件拷贝到$HOME/.vim/plugin目录中,然后更改其中的设置。你可以留意一下vim缺省的文件类型插件,它们的头部都有这样的代码:

" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
  finish
endif 

这类似于C语言头文件中的”#ifndef XXX | #define XXX“的语句,可以防止该插件被执行多次。因此,把这个插件拷贝到$HOME/.vim/plugin中(这个目录在runtimepath中排在最前面),它将先于vim的缺省插件被加载;而它加载后,vim的缺省文件类型插件就不会再被加载了。这就达到了我们修改设置的目的。

不过我们通常不用这种方法。如果这样做,一旦vim的缺省插件做了改变,我们也要更新我们改过的插件才行。我们可以在载入全局插件以后否决一些设置。在Unix 上,我们可以把我们的设置放在~/.vim/after/ftplugin/目录中,这个目录中的脚本会在vim的缺省脚本后执行。这样就可以修改配置,或增加我们自己的定义。

举个例子,在多人一起开发项目时,为了使代码风格尽量保持一致,一般不允许在代码使用TAB符,而以4个空格代之。我们可以编辑一个文件,包含下面的内容:

set shiftwidth=4
set expandtab 

把这个文件保存为~/.vim/after/ftplugin/c.vim。这样,每次在编辑c文件时,它的自动缩进为4个空格;当你在插入模式下使用CTRL-D、CTRL-T缩进时,它也会调整4个空格的缩进;当你按TAB键时,它将会插入8个空格……如果你想上面的设置对h文件也生效的话,需要把它另存一份:~/.vim/after/ftplugin/cpp.vim,因为h文件的文件类型被设为cpp。

我们知道,vim在设置文件类型时,会触发FileType自动命令,因此,上面的例子可以用下面的自动命令来实现:

autocmd FileType c,cpp set shiftwidth=4 | set expandtab 

把这个命令放在你的vimrc中,可以起到和上例同样的效果。

vim的语法高亮功能,也要用到文件类型,来对不同的关键字进行染色。这我们将在下一篇文章中介绍。

[参考文档]

<< 返回vim使用进阶: 目录

“vi/vim使用进阶: 开启文件类型检测”的2个回复

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注