Jade Dungeon

Vim配置开发环境

tag文件

在UNIX系统下的ctags功能比较少,所以一般我们使用Exuberant Ctags(在大多数Linux 系统上,它是缺省的ctags程序),它能够支持多达33种程序语言,足以满足我们开发的 需要了。http://ctags.sourceforge.net

macs则使用etags来生成tag文件,如果希望vim也能支持etags的tag文件格式,需要编译 vim时加入+emacs_tags选项。

tag文件格式

Tag文件需要遵循一定的格式,由Exuberant Ctags生成的tag文件,缺省是如下格式:

{tagname} {TAB} {tagfile} {TAB} {tagaddress} {term} {field} ..  
  • {tagname} – 标识符名字,例如函数名、类名、结构名、宏等。不能包含制表符。
  • {tagfile} – 包含{tagname}的文件。它不能包含制表符。
  • {tagaddress} – 可以定位到{tagname}光标位置的Ex命令。通常只包含行号或搜索 命令。出于安全的考虑,vim会限制其中某些命令的执行。
  • {term} – 设为;",这是为了兼容Vi编辑器,使Vi忽略后面的{field}字段。
  • {field} .. – 此字段可选,通常用于表示此{tagname}的类型是函数、类、宏或其它。

{tagname}{tagfile}{tagaddress}之间,采用制表符\t分隔,也就是说 {tagname}{tagfile}的内容中不能包含制表符。

Tag文件的开头可以包含以!_TAG_开头的行,用来在tag文件中加入其它信息。vim能够 识别两种这样的标记,经常用到的是_TAG_FILE_SORTED标记,例如:

!_TAG_FILE_SORTED<Tab>1<Tab>{anything} 

上面这个标记说明tag文件是经过排序的,并且排序时区分了大小写,对排序的tag,vim会 使用二分法来进行查找,大大加快了查找速度:

  • 如果值为0,则表示tag文件未经排序;
  • 如果值为1,则表示tag文件区分大小写排序;
  • 如果值为2,则表示tag文件是忽略大小写排序的。

之所以在这里介绍tag文件的格式,是因为我们在后面提到的lookupfile插件中,会自己 生成tag文件。

生成tag

虽然ctags有为数众多的选项,但通常我们所使用的非常简单。还是以vim 7.0的代码为例 ,我们执行:

cd ~/src/vim70
ctags –R src 

上面这条命令会在~/src/vim70/目录下生成一个名为tags的文件,这个文件中包含 ~/src/vim70/src/目录下所有.c.h文件中的标签。它一个文本文件,你可以用 vim打开它看一下。此文件缺省按区分字母大小写排序,所以直接可以被vim使用。

vim中使用tag

现在我们进入vim,执行下面的命令:

:cd ~/src/vim70	"切换当前目录为~/src/vim70
:set tags=tags	"设置tags选项为当前目录下的tags文件 

现在,我们设置好了tags选项,接下来我们使用它:

:tag VimMain

你会看到vim打开了src/main.c文件,并把光标定位到第167行VimMain上。

我们知道,一般主程序的函数名为main,如果你尝试下面的命令:

:tag main
# pri kind tag               file
1 F   f    main              src/xxd/xxd.c
main(argc, argv)
2 FS  d    main              src/if_python.c
46
Choice number (<Enter> cancels): 

这里并没有src/main.c文件,怎么回事呢?这是因为ctags并不是编译器,它在处理 编译预处理指令受到局限,因此并没有生成src/main.cmain()函数的标签。你可以 在生成tag文件时给ctags指定参数来解决这个问题。见ctags手册。

或者你可以用:grep:vimgrep来查找main(参见grep及vimgrep的部分):

:cd ~/src/vim70
:vimgrep /\<main\>/ src/*.c
:cw 

这时下面的quickfix窗口将显示出来,在quickfix窗口中找到我们想跳转的位置(本例中是 src/main.c),按回车,就可以跳到对应的位置了。

如果你只记得部分的标签名,那么可以使用tag命令的搜索模式,你可以输入一个 vim正则表达式来表示你所查找的名字,如:

:tag /\C\<\k\+ain\>
# pri kind tag               file
1 F   f    VimMain           src/main.c
VimMain
2 F   d    bindtextdomain    src/vim.h
483
3 F   d    bindtextdomain    src/vim.h
502
4 F   d    bindtextdomain    src/vim.h
504
5 F   f    main              src/xxd/xxd.c
main(argc, argv)
6 F   d    textdomain        src/vim.h
488
7 F   d    textdomain        src/vim.h
510
8 F   d    textdomain        src/vim.h
512
9 FS  d    bindtextdomain    src/gui_gtk.c
54
10 FS  d    bindtextdomain    src/gui_gtk_x11.c
37
11 FS  f    cmdsrv_main       src/main.c
cmdsrv_main(argc, argv, serverName_arg, serverStr)
12 FS  d    main              src/if_python.c
46
13 FS  d    textdomain        src/gui_gtk.c
51
14 FS  d    textdomain        src/gui_gtk_x11.c
34
Choice number (<Enter> cancels): 

这表示我想查找一个以一个或多个keyword开始的标签,此标签以ain做为结尾,在 查找时区分大小写。要读懂这个正则表达式,请:help pattern

vim会保存一个跳转的标签栈,以允许你在跳转到一个标签后,再跳回来,可以使用 :tags命令查找你处于标签栈的哪个位置。

我们经常用到的tag跳转命令见下(一般只需要知道CTRL-]和CTRL-T就可以了):

  • :tag {ident}:"跳转到指定的标签
  • :tags:"显示标签栈
  • CTRL-]:"跳转到当前光标下的标签
  • CTRL-T:"跳到标签栈中较早的标签

如果想了解更多命令,可以:help 29.1(强烈建议程序员完整的阅读usr_29.txtusr_30.txt)。

如果想更深入了解tag命令和相关知识,可以:help tagsrch

cscope

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

:help cscope 

在前面的文章中介绍了利用tag文件,跳转到标签定义的地方。但如果想查找函数在哪里 被调用,或者标签在哪些地方出现过,ctags就无能为力了,这时需要使用更为强大的 cscope。

Cscope具有纯正的Unix血统,它最早是由贝尔实验室为PDP-11计算机开发的,后来成为 商用的AT&T Unix发行版的组成部分。直到2000年4月,这个工具才由SCO公司以BSD license开源发行。

Cscope的主页在http://cscope.sourceforge.net/

在windows上也可以使用cscope,在cscope的主页上可以下载到由DJGPP编译器编译的 cscope for windows,不过这个版本不能和vi一起工作。或者你可以下载cygwin工具包( http://www.cygwin.com/),这个工具包中也包含了cscope。

http://iamphet.nm.ru/cscope/有Sergey Khorev预编译的一个Win32版本的cscope ,这个版本的cscope可以很好的与windows版本的vim搭配使用。

生成cscope数据库

cscope的用法很简单,首先需要为你的代码生成一个cscope数据库。在你的项目根目录 运行下面的命令:

cscope -Rbq 

这些选项的含义见后面。这个命令会生成三个文件:cscope.out,cscope.in.out, cscope.po.out

其中cscope.out是基本的符号索引,后两个文件是使用-q选项生成的,可以加快cscope的 索引速度。

在缺省情况下,cscope在生成数据库后就会进入它自己的查询界面,我们一般不用这个 界面,所以使用了-b选项。如果你已经进入了这个界面,按CTRL-D退出。

Cscope在生成数据库中,在你的项目目录中未找到的头文件,会自动到/usr/include 目录中查找。如果你想阻止它这样做,使用-k选项。

添加解析的类型

Cscope缺省只解析C文件(.c和.h)、lex文件(.l)和yacc文件(.y),虽然它也可以支持C++ 以及Java,但它在扫描目录时会跳过C++及Java后缀的文件。如果你希望cscope解析C++或 Java文件,需要把这些文件的名字和路径保存在一个名为cscope.files的文件。当cscope 发现在当前目录中存在cscope.files时,就会为cscope.files中列出的所有文件生成索引 数据库。通常我们使用find来生成cscope.files文件,仍以vim 7.0的源代码为例:

cd ~/src/vim70 
find . -type f > cscope.files
cscope -bq 

这条命令把~src/vim70目录下的所有普通文件都加入了cscope.files,这样, cscope会解析该目录下的每一个文件。上面的cscope命令并没有使用-R参数递归查找 子目录,因为在cscope.files中已经包含了子目录中的文件。

也可以手动指定要找的文件类型而不是目录下的所有文件类型:

find . -name "*.h" -o -name "*.c"-o -name "*.cc" > cscope.files

注意:find命令输出的文件以相对路径表示,所以cscope.out的索引也相对于当前路径。 如果你要在其它路径中使用当前的cscope.out,需要使用下面介绍的-P选项。

Cscope只在第一次解析时扫描全部文件,以后再调用cscope,它只扫描那些改动过的文件 ,这大大提高了cscope生成索引的速度。

下表中列出了cscope的常用选项:

  • -R: 在生成索引文件时,搜索子目录树中的代码
  • -b: 只生成索引文件,不进入cscope的界面
  • -q: 生成cscope.in.out和cscope.po.out文件,加快cscope的索引速度
  • -k: 在生成索引文件时,不搜索/usr/include目录
  • -i: 如果保存文件列表的文件名不是cscope.files时,需要加此选项告诉cscope到 哪儿去找源文件列表。可以使用-,表示由标准输入获得文件列表。
  • -Idir: 在-I选项指出的目录中查找头文件
  • -u: 扫描所有文件,重新生成交叉索引文件
  • -C: 在搜索时忽略大小写
  • -Ppath: 在以相对路径表示的文件前加上的path,这样,你不用切换到你数据库文件 所在的目录也可以使用它了。

vim中使用cscope

要在vim中使用cscope的功能,需要在编译vim时选择+cscope。vim的cscope接口先会 调用cscope的命令行接口,然后分析其输出结果找到匹配处显示给用户。

在vim中使用cscope非常简单,首先调用cscope add命令添加一个cscope数据库,然后 就可以调用cscope find命令进行查找了。vim支持8种cscope的查询功能,如下:

  • s: 查找C语言符号,即查找函数名、宏、枚举值等出现的地方
  • g: 查找函数、宏、枚举等定义的位置,类似ctags所提供的功能
  • d: 查找本函数调用的函数
  • c: 查找调用本函数的函数
  • t: 查找指定的字符串
  • e: 查找egrep模式,相当于egrep功能,但查找速度快多了
  • f: 查找并打开文件,类似vim的find功能
  • i: 查找包含本文件的文件

例如,我们想在vim 7.0的源代码中查找调用do_cscope()函数的函数,我们可以输入: :cs find c do_cscope,回车后发现没有找到匹配的功能,可能并没有函数调用 do_cscope()。我们再输入:cs find s do_cscope,查找这个C符号出现的位置,现在 vim列出了这个符号出现的所有位置。

我们还可以进行字符串查找,它会双引号或单引号括起来的内容中查找。还可以输入一个 正则表达式,这类似于egrep程序的功能,但它是在交叉索引数据库中查找,速度要快得多 。

vim提供了一些选项可以调整它的cscope功能:

  • cscopecscopeprg选项用于设置cscope程序的位置。
  • cscopecscopequickfix设定是否使用quickfix窗口来显示cscope的结果,详情请 :help cscopequickfix
  • 如果你想vim同时搜索tag文件以及cscope数据库,设置cscopecscopetag选项;
  • cscopecscopetagorder选项决定是先查找tag文件还是先查找cscope数据库。 设置为0则先查找cscope数据库,设置为1先查找tag文件。我通常设置为1,因为在 tag文件中查找到的结果,会把最佳匹配列在第一位。

vim的手册中给出了使用cscope的建议方法,使用命令:help cscope-suggestions查看。

下面是我的vimrc中关于cscope接口的设置:

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" cscope setting
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
if has("cscope")
  set csprg=/usr/bin/cscope
  set csto=1
  set cst
  set nocsverb
  " add any database in current directory
  if filereadable("cscope.out")
      cs add cscope.out
  endif
  set csverb
endif

nmap <C-@>s :cs find s <C-R>=expand("<cword>")<CR><CR>
nmap <C-@>g :cs find g <C-R>=expand("<cword>")<CR><CR>
nmap <C-@>c :cs find c <C-R>=expand("<cword>")<CR><CR>
nmap <C-@>t :cs find t <C-R>=expand("<cword>")<CR><CR>
nmap <C-@>e :cs find e <C-R>=expand("<cword>")<CR><CR>
nmap <C-@>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <C-@>i :cs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
nmap <C-@>d :cs find d <C-R>=expand("<cword>")<CR><CR>

下面的两个链接是cscope主页提供的cscope使用方法,也可以作为参考:

vim/cscope指导:http://cscope.sourceforge.net/cscope_vim_tutorial.html

在大项目中使用cscope:http://cscope.sourceforge.net/large_projects.html

在vim的网站上有很多与cscope相关的插件,有兴趣可以去看一下。

windows下cscope的错误

在windows上使用cscope时,你可能会遇到-q选项被忽略的提示,解决办法:

在cygwin的shell界面中使用cscope,没有出现上面的错误提示。但如果打开windows的 命令行窗口cmd.exe,在里面执行cscope,则会出现上面的错误。

在cygwin的shell窗口中,PATH环境变量的设置会使其先找到GNU版的sort.exe, 所以上述cscope命令执行可以成功。但在cmd.exe窗口中,PATH环境变量会使其先找到 windows自带的sort.exe而不是GNU sort.exe,所以会出现上面的错误提示。

知道了问题的原因,解决方法就很简单了,我们可以写一个批处理程序,在此程序中重设 PATH环境变量,使cscope使用GNU版的sort.exe。示例程序如下:

D:\Temp> type cs.bat
@echo off
set path=c:\cygwin\bin;
cscope -Rbkq 

在这个批处理里,首先把path环境变量指向c:\cygwin\bin;,我的cscope.exe和GNU版的 sort.exe都在此目录中。接下来现执行cscope命令,现在它使用的就是GNU版的sort.exe了 。

目前只能在unix系列操作系统下使用cscope,虽然也有windows版本的cscope,不过还有 很多bug。在Linux技术中坚站上看到有作者在win2000上成功运行了gvim + cscope,详情 可以参阅: http://www.chinalinuxpub.com/bbs/showthread.php?t=30185

(2009/04/06更新)网友mslk提供了cscope 15.7的win32编译版本下载,下载地址: http://sourceforge.net/project/showfiles.php?group_id=196604&package_id=232374

感谢他的辛勤工作,大家有时间去他的MSLK项目看看,这个项目目的是为Linux下的工具 提供预编译的windows版本。

在vim的网站上,也有人在cygwin中成功运行了vim + cscope,详情请参阅: http://vim.sourceforge.net/tips/tip.php?tip_id=338

另外,还有人在windows上安装了XFree86包,然后在Xwindow中运行gvim + cscope。 这同样可以在上面的网页中看到。

cscope的主页在:http://cscope.sourceforge.net/

taglist

当前文件中的宏、全局变量、函数等tag显示在Symbol窗口,用鼠标点上述tag,就跳到该 tag定义的位置;可以按字母序、该tag所属的类或scope,以及该tag在文件中出现的位置 进行排序;如果切换到另外一个文件,Symbol窗口更新显示这个文件中的tag。

要使用taglist plugin,必须满足:

  • 打开vim的文件类型自动检测功能:filetype on
  • 系统中装了Exuberant ctags工具,并且taglist plugin能够找到此工具(因为taglist 需要调用它来生成tag文件)
  • 你的vim支持system()调用

现在我们到http://www.vim.org/scripts/script.php?script_id=273下载最新版本的taglist plugin,目前版本是4.3。

下载后,把该文件在~/.vim/目录中解压缩,这会在你的~/.vim/plugin~/.vim/doc 目录中各放入一个文件:

plugin/taglist.vim – taglist插件
doc/taglist.txt    - taglist帮助文件 

注:windows用户需要把这个插件解压在你的$vim/vimfiles$HOME/vimfiles目录。

使用下面的命令生成帮助标签(下面的操作在vim中进行):

:helptags ~/.vim/doc 

生成帮助标签后,你就可以用下面的命令查看taglist的帮助了:

:help taglist.txt 

Taglist提供了相当多的功能,我的vimrc中这样配置:

""""""""""""""""""""""""""""""
" Tag list (ctags)
""""""""""""""""""""""""""""""
if MySys() == "windows"                "设定windows系统中ctags程序的位置
let Tlist_Ctags_Cmd = 'ctags'
elseif MySys() == "linux"              "设定linux系统中ctags程序的位置
let Tlist_Ctags_Cmd = '/usr/bin/ctags'
endif
let Tlist_Show_One_File = 1            "不同时显示多个文件的tag,只显示当前文件的
let Tlist_Exit_OnlyWindow = 1          "如果taglist窗口是最后一个窗口,则退出vim
let Tlist_Use_Right_Window = 1         "在右侧窗口中显示taglist窗口 

这样配置后,当你输入:TlistOpen时,显示taglist窗口:

在屏幕右侧出现的就是taglist窗口,你从中可以看到在main.c文件中定义的所有tag: 宏、定义、变量、函数等;你也可以双击某个tag,跳到该tag定义的位置;你还可以把 某一类的tag折叠起来(使用了vim的折行功能),方便查看,就像上图中macro和variable 那样。更多的功能,请查看taglist的帮助页,本文也会介绍一些常用功能。

下面介绍常用的taglist配置选项,你可以根据自己的习惯进行配置:

  • Tlist_Ctags_Cmd选项用于指定你的Exuberant ctags程序的位置,如果它没在你PATH 变量所定义的路径中,需要使用此选项设置一下;
  • 如果你不想同时显示多个文件中的tag,设置Tlist_Show_One_File为1。缺省为显示 多个文件中的tag;
  • 设置Tlist_Sort_Type为name可以使taglist以tag名字进行排序,缺省是按tag在 文件中出现的顺序进行排序。按tag出现的范围(即所属的namespace或class)排序, 已经加入taglist的TODO List,但尚未支持;
  • 如果你在想taglist窗口是最后一个窗口时退出vim,设置Tlist_Exit_OnlyWindow为1;
  • 如果你想taglist窗口出现在右侧,设置Tlist_Use_Right_Window1。缺省显示在 左侧。
  • 在gvim中,如果你想显示taglist菜单,设置Tlist_Show_Menu1。你可以使用 Tlist_Max_Submenu_ItemsTlist_Max_Tag_Length来控制菜单条目数和所显示 tag名字的长度;
  • 缺省情况下,在双击一个tag时,才会跳到该tag定义的位置,如果你想单击tag就跳转, 设置Tlist_Use_SingleClick1
  • 如果你想在启动vim后,自动打开taglist窗口,设置Tlist_Auto_Open为1;
  • 如果你希望在选择了tag后自动关闭taglist窗口,设置Tlist_Close_On_Select1
  • 当同时显示多个文件中的tag时,设置Tlist_File_Fold_Auto_Close1,可使 taglist只显示当前文件tag,其它文件的tag都被折叠起来。
  • 在使用:TlistToggle打开taglist窗口时,如果希望输入焦点在taglist窗口中,设置 Tlist_GainFocus_On_ToggleOpen1
  • 如果希望taglist始终解析文件中的tag,不管taglist窗口有没有打开,设置 Tlist_Process_File_Always1
  • Tlist_WinHeightTlist_WinWidth可以设置taglist窗口的高度和宽度。 Tlist_Use_Horiz_Window1设置taglist窗口横向显示;

在taglist窗口中,可以使用下面的快捷键:

  • <CR>:跳到光标下tag所定义的位置,用鼠标双击此tag功能也一样
  • o:在一个新打开的窗口中显示光标下tag
  • <Space>:显示光标下tag的原型定义
  • u:更新taglist窗口中的tag
  • s:更改排序方式,在按名字排序和按出现顺序排序间切换
  • x:taglist窗口放大和缩小,方便查看较长的tag
  • +:打开一个折叠,同zo
  • -:将tag折叠起来,同zc
  • *:打开所有的折叠,同zR
  • =:将所有tag折叠起来,同zM
  • [[:跳到前一个文件
  • ]]:跳到后一个文件
  • q:关闭taglist窗口
  • <F1>:显示帮助
  • :TlistOpen打开taglist窗口,
  • :TlistClose关闭taglist窗口。
  • :TlistToggle在打开和关闭间切换。

在我的vimrc中定义了下面的映射,使用<F9>键就可以打开/关闭taglist窗口:

map <silent> <F9> :TlistToggle<cr> 

Taglist插件还提供了很多命令,你甚至可以用这些命令创建一个taglist的会话,然后在下次进入vim时加载此会话。

[Taglist插件还可以与winmanager插件协同使用: [http://easwy.com/blog/archives/advanced-vim-skills-netrw-bufexplorer-winmanager-plugin/]]

lookupfile

Lookupfile插件可以在下面的链接下载: http://www.vim.org/scripts/script.php?script_id=1581

它使用vim 7.0中插入模式下的下拉菜单补全功能,因此只能在vim 7.0及以上版本中使用。

下载该插件后,把它解压到你的~/.vim目录中,就完成了安装。然后在vim中执行 :helptags ~/.vim/doc命令,生成help文件索引,然后就可以使用:help lookupfile 命令查看lookupfile插件的帮助文件了。

注:windows用户需要把这个插件解压在你的$vim/vimfiles$HOME/vimfiles目录。

Lookupfile插件还需要最新的genutils支持,因此,需要下载genutils: http://www.vim.org/scripts/script.php?script_id=197

这个插件提供了一些通用的函数,可供其它的脚本使用。它的安装方法也是在~/.vim目录 解压就可以了。需要注意的是,最新版本的genutils使用了新的自动加载方式,所以和 以前的版本不兼容。如果你的其它插件需要使用genutils的旧版本的话,你需要参照 genutils的说明进行配置,以便使新旧两个版本能协同工作。

现在我们介绍lookupfile插件。虽然名字为lookupfile,其实这个插件它不仅能用来查找 文件,还可以在打开的缓冲区中查找,按目录查找,等等。

项目文件查找

Lookupfile在查找文件时,需要使用tag文件。它可以使用ctags命令生成的tag文件,不过 查找效率会比较低。因此我们会专门为它生成一个包含项目中所有文件名的tag文件。

我编写了下面的shell脚本,为vim70的源代码,生成一个文件名tag文件。

#!/bin/sh
# generate tag file for lookupfile plugin
echo -e "!_TAG_FILE_SORTED\t2\t/2=foldcase/" > filenametags
find . -not -regex '.*\.\(png\|gif\)' -type f -printf "%f\t%p\t1\n" | \
    sort -f >> filenametags 

回想一下我们在使用标签(tag)文件一文中介绍的tag文件的格式。再对照脚本命令来看:

  • echo命令用来生成filenametags文件中的!_TAG_FILE_SORTED行,表明此tag文件是 经过排序的。
  • find命令用来查找所有类型为普通文件,文件后缀名不是.png和.gif的文件,找到的 文件按文件名\t文件路径\t1的格式输出出来。
  • sort命令则把find命令的输出重新排序,然后写入filenametags文件中

~/src/vim70/目录下运行该脚本,会生成一个名为filenametags的文件,包含了vim70 目录下的所有文件的名字及其所在目录。

现在我们需要让lookupfile插件知道到哪去找文件名tag文件。我们假定vim当前工作目录 为~/src/vim70/,执行下面的命令:

:let g:LookupFile_TagExpr = '"./filenametags"' 

注:如果不设定g:LookupFile_TagExpr的值,那么lookupfile插件会以tags选项定义的 文件作为它的tag文件。

现在我们就可以使用lookupfile来打开文件了,按<F5>或输入:LookupFile在当前 窗口上方打开一个lookupfile小窗口,开始输入文件名(至少4个字符),随着你的输入, 符合条件的文件就列在下拉列表中了。文件名可以使用vim的正则表达式,这大大方便了 文件的查找。你可以用CTRL-NCTRL-P(或者用上、下光标键)来在下拉列表中选择 你所需的文件。选中文件后,按回车,就可以在之前的窗口中打开此文件。

下图是使用lookupfile插件查找文件的一个例子:

在屏幕最上方的窗口就是lookupfile窗口,在这个窗口中输入gui.*x11几个字符, 查找到6个匹配文件,使用CTRL-N选中gui_x11.c文件,然后按回车,就会在前一个 vim窗口中打开src/gui_x11.c文件,lookupfile窗口也自动关闭了。是不是非常方便 ?!

缓冲区查找

在开发过程中,我经常会同时打开数十甚至上百个文件。即使是使用BufExplorer插件, 想在这么多buffer中切换到自己所要的文件,也不是件容易的事。

Lookupfile插件提供了一个按缓冲区名字查找缓冲区的方式,只要输入缓冲区的名字 (可以是正则表达式),它就可以把匹配的缓冲区列在下拉列表中,同时还会列出该 缓冲区内文件的路径,当你的buffer中有多个同名文件时,这可以帮你迅速找到你想要的文件。

使用:LUBufs命令开始在缓冲区中查找,输入缓冲区的名字,在你输入的过程中,符合 条件的缓冲区就显示在下拉列表中了,选中所需缓冲区后,按回车,就会切换你所选的 缓冲区。

浏览目录

Lookupfile插件还提供了目录浏览的功能,使用:LUWalk打开lookupfile窗口后,就可以 输入目录,lookupfile会在下拉列表中列出这个目录中的所有子目录及文件供选择,如果 选择了目录,就会显示这个目录下的子目录和文件;如果选择了文件,就在vim中打开这个 文件。

Lookupfile配置

Lookupfile插件提供了一些配置选项,通过调整这些配置选项,使它更符合你的工作习惯 。下面是我的vimrc中关于lookupfile的设置,供参考:

""""""""""""""""""""""""""""""
" lookupfile setting
""""""""""""""""""""""""""""""
let g:LookupFile_MinPatLength = 2               "最少输入2个字符才开始查找
let g:LookupFile_PreserveLastPattern = 0        "不保存上次查找的字符串
let g:LookupFile_PreservePatternHistory = 1     "保存查找历史
let g:LookupFile_AlwaysAcceptFirst = 1          "回车打开第一个匹配项目
let g:LookupFile_AllowNewFiles = 0              "不允许创建不存在的文件
if filereadable("./filenametags")                "设置tag文件的名字
let g:LookupFile_TagExpr = '"./filenametags"'
endif
"映射LookupFile为,lk
nmap <silent> <leader>lk :LUTags<cr>
"映射LUBufs为,ll
nmap <silent> <leader>ll :LUBufs<cr>
"映射LUWalk为,lw
nmap <silent> <leader>lw :LUWalk<cr>

有了上面的定义,当我输入,lk时,就会在tag文件中查找指定的文件名;当输入,ll时 ,就会在当前已打开的buffer中查找指定名字的buffer;当输入,lw时,就会在指定 目录结构中查找。

另外,我还在项目相关的配置文件vim70sx.vim(参考保存项目相关配置)中加入了 lookupfile所使用的tag文件的信息:

" lookup file tag file
let g:LookupFile_TagExpr = '"filenametags"' 

这样,在恢复前次会话时就给lookupfile插件定义了tag文件。

在用lookupfile插件查找文件时,是区分文件名的大小写的,如果想进行忽略大小写的 匹配,可以使用vim忽略大小写的正则表达式,即在文件名的前面加上\c字符。举个例子 ,当你输入\cab.c时,你可能会得到ab.cAb.cAB.c

注:如果想加快lookupfile忽略大小写查找的速度,在生成文件名tag文件时,使用混合 大小写排序。这在文章使用标签(tag)文件有所提及。

通常情况下我都进行忽略大小写的查找,每次都输入\c很麻烦。没关系,lookupfile 插件提供了扩展功能,把下面这段代码加入你的vimrc中,就可以每次在查找文件时都忽略 大小写查找了:

" lookup file with ignore case
function! LookupFile_IgnoreCaseFunc(pattern)
    let _tags = &tags
    try
        let &tags = eval(g:LookupFile_TagExpr)
        let newpattern = '\c' . a:pattern
        let tags = taglist(newpattern)
    catch
        echohl ErrorMsg | echo "Exception: " . v:exception | echohl NONE
        return ""
    finally
        let &tags = _tags
    endtry

    " Show the matches for what is typed so far.
    let files = map(tags, 'v:val["filename"]')
    return files
endfunction
let g:LookupFile_LookupFunc = 'LookupFile_IgnoreCaseFunc' 

有时在LUBufs时也需要忽略缓冲区名字的大小写,我是通过直接修改lookupfile插件的 方法,在LUBufs查找的字符串前都加上\c,使之忽略大小写。如果你不想这样,可以 每次在缓冲区名字前手动加上\c

本文关于Lookupfile插件就介绍这么多,请阅读手册获取更多的信息。

文件类型检测

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

: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 */ 

ftfiletype的缩写,vim中很多命令、选项都有缩写形式,以方便使用。 注意/*vim:间的空格。在*/与」ft=c「间,也需要有至少一个空格,这是模式行 格式的要求,更多信息参阅:help modeline

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

filetype plugin on

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

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

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

它会在上述这几个目录的ftplugin子目录中搜索所有名为c.vimc_*.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-DCTRL-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的语法高亮功能,也要用到文件类型,来对不同的关键字进行染色。这我们将在下一篇文章中介绍。

语法高亮

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

:help syn-enable
:help :colorscheme
:help :highlight
:help highlight-groups
:help 2html.vim 

启用高亮

首先,把下面的Ex命令加入你的vimrc,打开vim的语法高亮功能:

syntax enable 

这条命令,实际上是执行$vimRUNTIME/syntax/syntax.vim脚本。如果你还没有打开 文件类型检测功能,在这个脚本里会把它打开,因为要语法高亮,首先需要知道是什么 文件类型。然后它会安装Filetype自动命令,在检测到文件类型时,设置syntax选项。 而对syntax选项进行设置,又会触发Syntax自动命令,这条自动命令会在runtimepath的 syntax子目录搜寻该类型的语法文件,并使用缺省的配色方案进行染色。

配色

因此我在vimrc中加入这样一句话:

colorscheme darkblue 

有一个名为Color Scheme Explorer的插件,可以帮助你快速浏览你所安装的color scheme ,在这里下载:

http://www.vim.org/scripts/script.php?script_id=1298

选择了喜欢的colorscheme后,在vimrc中加入一条colorscheme命令,以后vim就会使用 你选定的配色方案了。

如果对配色方案某些颜色不太满意,那么你可以在原来配色方案的基础上,修改其中的 一些定义。例如,我把desert.vim拷到.vim/color目录,重命名为darkblue_my.vim 。然后做如下更改(只列出改变的内容):

let colors_name = "darkblue_my"
hi Normal guifg=#c0c0c0 guibg=#294d4a ctermfg=gray ctermbg=black
......
"Omni menu colors
hi Pmenu guibg=#444444
hi PmenuSel ctermfg=7 ctermbg=4 guibg=#555555 guifg=#ffffff
" Matched brackets
hi MatchParen ctermfg=7 ctermbg=4 

首先改变colors_name,vim在某此情况会根据这个名字重新载入color scheme。

接下来的PmenuPmenuSel用来设置vim下拉菜单的颜色,我们在使用lookupfile插件 中看到过下拉菜单。

vim 7中,当光标移到括号上时,vim会高亮与之匹配的括号,所使用的颜色就是 MatchParen,我在这里也更改这个颜色。

PmenuPmenuSel,以及MatchParen,都是vim定义的缺省高亮组的名字,你可以用 :help highlight-groups命令查看有这些高亮组及其含义。

如果你打算在终端及GUI界面中使用不同的colorscheme,可以这样设:

" color scheme
if has("gui_running")
  colorscheme darkblue_my
else
  colorscheme desert_my
endif " has 

vim还提供了一个脚本,可以把你的文件按当前的颜色定义转化成HTML/XML文件,试试 :TOhtml命令吧,更多信息请:help 2html.vim

高亮当前的单词

记得Source Insight中有一个功能,按SHIFT+F8可以把光标下的词高亮出来, 在看代码时非常有用。vim下也有一个插件可以完成此功能,而且比Source Insight的这个 功能强大多了。

这个插件由Yuheng Xie所写,对这个插件有什么疑问,可以水木社区的vim版找到他 (http://www.newsmth.net/bbsdoc.php?board=vim)。 http://www.vim.org/scripts/script.php?script_id=1238下载此插件。

把此插件直接拷贝到你的.vim/plugin目录就行了。

参考配置

我在vimrc中这样设置:

""""""""""""""""""""""""""""""
" mark setting
""""""""""""""""""""""""""""""
nmap <silent> <leader>hl <Plug>MarkSet
vmap <silent> <leader>hl <Plug>MarkSet
nmap <silent> <leader>hh <Plug>MarkClear
vmap <silent> <leader>hh <Plug>MarkClear
nmap <silent> <leader>hr <Plug>MarkRegex
vmap <silent> <leader>hr <Plug>MarkRegex 

这样,当我输入,hl时,就会把光标下的单词高亮,在此单词上按,hh会清除该单词的 高亮。如果在高亮单词外输入,hh,会清除所有的高亮。

你也可以使用virsual模式选中一段文本,然后按,hl,会高亮你所选中的文本; 或者你可以用,hr来输入一个正则表达式,这会高亮所有符合这个正则表达式的文本。

你可以在高亮文本上使用,#,*来上下搜索高亮文本。在使用了,#,*后,就 可以直接输入#*来继续查找该高亮文本,直到你又用#*查找了其它文本。

如果你在启动vim后重新执行了colorscheme命令,或者载入了会话文件,那么mark插件的 颜色就会被清掉,解决的办法是重新source一下mark插件。或者像我一样,把mark插件 定义的highlight组加入到你自己的colorscheme文件中。例如,把下面的语句加到 desert_my.vimdarkblue_my.vim中:

" For mark plugin
hi MarkWord1  ctermbg=Cyan     ctermfg=Black  guibg=#8CCBEA    guifg=Black
hi MarkWord2  ctermbg=Green    ctermfg=Black  guibg=#A4E57E    guifg=Black
hi MarkWord3  ctermbg=Yellow   ctermfg=Black  guibg=#FFDB72    guifg=Black
hi MarkWord4  ctermbg=Red      ctermfg=Black  guibg=#FF7272    guifg=Black
hi MarkWord5  ctermbg=Magenta  ctermfg=Black  guibg=#FFB3FF    guifg=Black
hi MarkWord6  ctermbg=Blue     ctermfg=Black  guibg=#9999FF    guifg=Black 

不知道为什么,我的vim 7.0在切换到其它缓冲区然后再切换回来时,原来被标记的文本会 失去高亮。而作者说他并不存在此问题。如果你存在类似的问题,可以打上我所加的补丁:

--- easwy/mark.vim	2006-12-01 13:02:18.000000000 +0800
+++ plugin/mark.vim	2007-03-23 10:22:02.000000000 +0800
@@ -440,6 +440,43 @@
 	endif
 endfunction
 
+" easwy add
+" return the mark string under the cursor. multi-lines marks not supported
+function! <SID>RedoMarkWord()
+	" define variables if they don't exist
+	call s:InitMarkVariables()
+
+	let i = 1
+  while i <= g:mwCycleMax
+    if b:mwWord{i} != ""
+      " quote regexp with / etc. e.g. pattern => /pattern/
+      let quote = "/?~!@#$%^&*+-=,.:"
+      let j = 0
+      while j < strlen(quote)
+        if stridx(b:mwWord{i}, quote[j]) < 0
+          let quoted_regexp = quote[j] . b:mwWord{i} . quote[j]
+          break
+        endif
+        let j = j + 1
+      endwhile
+      if j >= strlen(quote)
+        return -1
+      endif
+
+      " highlight the word
+      exe "syntax clear MarkWord" . i
+      exe "syntax match MarkWord" . i . " " . quoted_regexp . " containedin=ALL"
+    endif
+    let i = i + 1
+  endwhile
+endfunction
+
+augroup markword
+  autocmd!
+  autocmd BufWinEnter * call <SID>RedoMarkWord()
+augroup END
+" easwy end
+
 " Restore previous 'cpo' value
 let &cpo = s:save_cpo

用法:

  • 保存该patch到某一目录,例如:/tmp/mark.vim.patch
  • cd到你的.vim目录:cd ~/.vim
  • 运行命令:cat /tmp/mark.vim.patch | patch -p0

compl-omni 补全

vim的OMNI补全(以下称」全能补全」)可以支持多种程序语言,包括C,C++, XML/HTML,CSS ,JAVASCRIPT,PHP,RUBY等,详细列表请参阅:help compl-omni-filetypes。在本文中 ,主要介绍C及C++的全能补全。

例如,我们在VimMain()函数中,输入」gui「三个字符,然后按下」CTRL-X CTRL-O「,在vim的状态行会显示」Omni Completeion「,表明现在进行的是全能补全,同时会弹出一个下拉菜单,显示所有匹配的标签。你可以使用来」CTRL-P「和」CTRL-N「上下选择,在选择的同时,所选中的项就被放在光标位置,不需要再按回车来把它放在光标位置(像Source Insight那样)。

如果更习惯于使用Source Insight这种方式,你可以使用上、下光标键来选择项目,然后按回车把选中的项目放到光标位置。不过这样一来,你的手指就会离开主编辑区,并且需要多输入一个回车键。

本文结尾处提供了一个键绑定,允许在使」CTRL-P「和」CTRL-N「时,输入回车表示补全结束,而不是插入回车。

如果补全处于激活状态,可以用」CTRL-E「停止补全并回到原来录入的文字。用」CTRL-Y「可以停止补全,并接受当前所选的项目。

下图是使用」CTRL-N」选择的抓图。该图中,我选择了」gui_exit(「函数,接下来可以直接输入这个函数的参数,这会结束当前补全,并插入我所输入的参数。

下图是对结构的成员进行补全的抓图:

缺省的,vim会使用下拉菜单和一个preview窗口(预览窗口)来显示匹配项目,下拉菜单列出所有匹配的项目,预览窗口则显示选中项目的详细信息。打开预览窗口会导致下拉菜单抖动,因此我一般都去掉预览窗口的显示,这需要改变’completeopt‘的值,我的设置如下:

set completeopt=longest,menu

上面的设置表明,只在下拉菜单中显示匹配项目,并且会自动插入所有匹配项目的相同文本。

如果要支持C++的全能补全,需要到vim主页下载OmniCppComplete插件,链接如下:

http://www.vim.org/scripts/script.php?script_id=1520

下载后,把它解压到你的.vim目录(在windows下是vimfiles目录),它会安装以下文件:

  • after\ftplugin\cpp.vim
  • autoload\omni\common\debug.vim
  • \utils.vim
  • autoload\omni\cpp\complete.vim
  • \includes.vim
  • \items.vim
  • \maycomplete.vim
  • \namespaces.vim
  • \settings.vim
  • \tokenizer.vim
  • \utils.vim
  • doc\omnicppcomplete.txt

确保你已关闭了vi兼容模式,并允许进行文件类型检测:

set nocp
filetype plugin on 

接下来,使用下面的命令,为C++文件生成标签文件,假定你的文件在src目录树下:

ctags -R --c++-kinds=+p --fields=+iaS --extra=+q src 

在对C++文件进行补全时,OmniCppComplete插件需要tag文件中包含C++的额外信息,因此上面的ctags命令不同于以前我们所使用的,它专门为C++语言生成一些额外的信息,上述选项的含义如下:

  • --c++-kinds=+p : 为C++文件增加函数原型的标签
  • --fields=+iaS : 在标签文件中加入继承信息(i)、类成员的访问控制信息(a)、以及函数的指纹(S)
  • --extra=+q : 为标签增加类修饰符。注意,如果没有此选项,将不能对类成员补全

现在,进入vim,设置好tag选项(我在前面的文章中介绍过)。好极了,vim能够对C++自动补全了!

我写了一个简单的例子,来演示C++的自动补全功能,如下图所示,在输入」t.「后,OmniCppComplete插件会自动弹出struct test1的成员供选择,而在输入」b->「后,又会自动弹出class base的成员供选择,非常方便,连」CTRL-X CTRL-O「都不必输入。OmniCppComplete插件的缺省设置比较符合我的习惯,因此不须对其设置进行调整,如果你需要调整,参阅OmniCppComplete的帮助页。 点击查看大图 点击查看大图

下表是我的vimrc中设置的键绑定,使用pumvisible()来判断下拉菜单是否显示,如果下拉菜单显示了,键映射为了一个值,如果未显示,又会映射为另一个值。

" mapping
inoremap <expr> <CR>       pumvisible()?"\<C-Y>":"\<CR>"
inoremap <expr> <C-J>      pumvisible()?"\<PageDown>\<C-N>\<C-P>":"\<C-X><C-O>"
inoremap <expr> <C-K>      pumvisible()?"\<PageUp>\<C-P>\<C-N>":"\<C-K>"
inoremap <expr> <C-U>      pumvisible()?"\<C-E>":"\<C-U>" 

上面的映射都是在插入模式下的映射,解释如下:

  • 如果下拉菜单弹出,回车映射为接受当前所选项目,否则,仍映射为回车;
  • 如果下拉菜单弹出,CTRL-J映射为在下拉菜单中向下翻页。否则映射为CTRL-X CTRL-O;
  • 如果下拉菜单弹出,CTRL-K映射为在下拉菜单中向上翻页,否则仍映射为CTRL-K;
  • 如果下拉菜单弹出,CTRL-U映射为CTRL-E,即停止补全,否则,仍映射为CTRL-U;

其他补全方式

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

:help compl-generic
:help 'complete'
:help ins-completion 

上篇文章介绍了vim的智能补全(omni补全),本篇主要介绍vim提供的其它补全方式。

除智能补全外,最常用的补全方式应该是CTRL-N和CTRL-P补全了。它们会在当前缓冲区、其它缓冲区,以及当前文件所包含的头文件中查找以光标前关键字开始的单词。智能补全不能对局部变量进行补全,而CTRL-N和CTRL-P补全则可以很好的胜任。

下图是采用CTRL-P补全的一个例子,输出字符」pa」,然后按CTRL-P,vim会在下拉菜单中列出所有的匹配功能供选择,此时再按一下CTRL-P,就选中了第一个项目,也就是我想输入的」parmp」。我们第一次输入CTRL-P的是进行补全,第二次输入的CTRL-P是在下拉菜单中向上选择,二者的含义是不同的。

我们知道,CTRL-P一般的含义是向上,因此CTRL-P补全是向上查找以进行补全,而CTRL-N是向下查找以进行补全,在不同场合使用不同的快捷键可以加速补全的速度。

使用CTRL-N和CTRL-P补全时,由’complete‘选项控制vim从哪些地方查找补全的内容。例如,对于比较大的软件项目,文件包含关系复杂,如果CTRL-N和CTRL-P补全时查找所包含的头文件,耗时会比较久。此时,可以在’complete‘选项中去掉’i‘标记,这样CTRL-N和CTRL-P补全就不在头文件中查找了,速度会快很多;当然,弊端就是你无法对头文件中出现的某些内容进行补全了。’complete‘选项中其它标记的含义,请阅读手册页。

vim中其它的补全方式包括:

  • 整行补全 CTRL-X CTRL-L
  • 根据当前文件里关键字补全 CTRL-X CTRL-N
  • 根据字典补全 CTRL-X CTRL-K
  • 根据同义词字典补全 CTRL-X CTRL-T
  • 根据头文件内关键字补全 CTRL-X CTRL-I
  • 根据标签补全 CTRL-X CTRL-]
  • 补全文件名 CTRL-X CTRL-F
  • 补全宏定义 CTRL-X CTRL-D
  • 补全vim命令 CTRL-X CTRL-V
  • 用户自定义补全方式 CTRL-X CTRL-U
  • 拼写建议 CTRL-X CTRL-S

例如,当我们按下」CTRL-X CTRL-F「时,vim就会弹出下拉菜单,显示出当前目录下的可选目录和文件,如下图所示。这样,在输入文件名时方便多了。 点击查看大图

灵活的运用这些补全方式,甚至自定义自己的补全方式,可以使你的工作更加高效。

可以在vimrc中定义下面的键绑定,以减少按键次数:

inoremap <C-]>             <C-X><C-]>
inoremap <C-F>             <C-X><C-F>
inoremap <C-D>             <C-X><C-D>
inoremap <C-L>             <C-X><C-L> 

supertab补全

SuperTab插件会记住你上次所使用的补全方式,下次再补全时,直接使用TAB,就可以重复这种类型的补全。比如,上次你使用CTRL-X CTRL-F进行了文件名补全,接下来,你就可以使用TAB来继续进行文件名补全,直到你再使用上面列出的补全命令进行了其它形式的补全。这个插件在下面的链接下载:

http://www.vim.org/scripts/script.php?script_id=1643

下载后,把它放到.vim/plugin目录就可以了。

可以对下面两个选项进行配置,以调整SuperTab的缺省行为:

  • g:SuperTabRetainCompletionType的值缺省为1,意为记住你上次的补全方式,直到使用其它的补全命令改变它;如果把它设成2,意味着记住上次的补全方式,直到按ESC退出插入模式为止;如果设为0,意味着不记录上次的补全方式。
  • g:SuperTabDefaultCompletionType的值设置缺省的补全方式,缺省为CTRL-P。

你可以在vimrc中设置这两个变量,例如:

let g:SuperTabRetainCompletionType = 2
let g:SuperTabDefaultCompletionType = "<C-X><C-O>" 

现在你可以使用TAB来进行补全了,就像在shell中那样,方便了很多!

调试:pyclewn

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

:help pyclewn 

gvim在编译时需要使能netbeans_intg特性和autocmd特性。

安装pyclewn很简单,在我的计算机上,gvim安装目录在我的HOME目录,因此,也把 pyclewn安装在HOME目录,使用如下命令:

cd /home/easwy/download/pyclewn-0.7/
vimdir=$HOME/.vim python setup.py install --home=$HOME 

使用

下面通过一个例子讲解一下如何使用pyclewn进行调试。例子中所调试的程序在这里下载:

http://easwy.com/blog/uploads/2009/10/pyclewn-ex.zip

首先启动pyclewn。启动pyclewn的办法很简单,在一个终端中执行下面的命令就可以了:

pyclewn 

pyclewn启动时,它会启动一个gvim窗口,我们的调试将在这个gvim窗口中进行。运行pyclewn的终端将做为gdb的控制终端,所调试程序的输入输出都会通过这个终端进行(当然,你也可以在gdb中通过tty命令更改控制终端)。

接下来,我们在pyclewn所打开的gvim窗口中输入下面的命令,编译该程序,打开要调试的文件,并在文件中设置断点:

:cd pyclewn-ex
:make
:e main.c
:Cfile factorial
:Cbreak 14 

前面三条命令是标准的vim命令,切换到示例程序所在目录,编译该程序,并打开文件main.c。后面两条命令以大写字母C做为起始,这是pyclewn自定义的命令,pyclewn将会把字母C后的命令内容传递给GDB调试器。所以上面两条命令相当于在GDB中执行file factor和break 14,加载factor做为被调试的程序,并在main.c的第14行设置一个断点。

在执行pyclewn自定义的C命令时,pyclewn会在gvim中分隔出一个窗口,用于显示GDB调试器的输入输出。所以,执行完上面命令后,屏幕看起来是这样的:

在上面已经设置好断点了,现在就可以开始调试了。pyclewn已经定义了一些调试相关的键映射,我们可以通过下面的命令加载这些键映射:

:Cmapkeys 

执行完这条命令,会在clewn_console中打印出所定义的键映射,我在此不再赘述。在下面的调试过程中,我也会使用几个最常用的映射。

我们继续调试。我在上面已经定义了一个断点,所以直接按SHIFT-R键运行程序。程序运行到断点后会停下来,然后我们连按三次CTRL-N,执行三条语句,现在切换到控制终端,可以看到程序在等待输入,我们输入一个数字,然后按回车。现在看到的屏幕是这样的:

在上面的抓图中,我们把鼠标移动到变量n上,可以看到弹出了一个小气泡,显示变量n的值为4,这和我们输入的数字是一致的。

接下来再按一次CTRL-N向下执行一个语句,然后再按SHIFT-S步进到函数factorial()中,现在gvim会打开文件util/factorial.c。然后用下面的命令,把变量t和i加入到watch窗口中:

:Cdbgvar t
:Cdbgvar i 

上面的命令会创建一个名为(clewn)_dbgvar的缓冲区,不过此缓冲区并未显示出来。用下面的命令可以新建一个窗口显示此缓冲区:

:sb (clewn)_dbgvar 

现在屏幕看起来是这样的:

按一次SHIFT-C使程序运行至结束,我们的调试也就告一段落了。

从上面的调试过程可以看出,使用pyclewn调试很方便。而且,使用pyclewn也可以在windows上进行调试,不过我没有试过,有兴趣的朋友可以试一下。在windows上调试,可能需要使用cygwin中所带的gdb。

如果觉得pyclewn缺省所设置的键映射不能满足自己的需求,也可以自己定义更多GDB调试键映射,方法是把pyclewn发行目录中的.clewn_keys.gdb拷贝到你的HOME目录,然后修改此文件定制自己的键绑定即可。

cd /home/easwy/download/pyclewn-0.7/
cp runtime/.clewn_keys.gdb $HOME 

要想了解更多关于pyclewn的使用,请阅读pyclewn的帮助手册::help pyclewn