【概念】
代码自动补全和代码跳转阅读,应该是作为程序员最常用的功能之一了,具体二者是指什么我就不解释了。微软的Visual Studio就是靠这两样必杀技牢牢占据着广大windows程序员的心(这里面要有强大的VS插件Visual Assistant X一份功劳)。。。但是Linux程序员其实更幸福,不花钱就能搞定这两大功能。
从本质上说,这二者的实现都依赖于一样东西:tag。tag就是程序中的关键词,在C++中主要包括:变量、函数名、类名等。代码自动补全实际上是tag的匹配(例如,程序员输入cla时,由于存在class这个c++的tag,就可以用class匹配cla);代码跳转阅读实际上是tag的查找(例如,程序员要查找一个函数func(),只需要在别的文件中寻找这个func这个tag的位置即可)。
【准备】
我现在的系统是Ubuntu Desktop 10.04 LTS版本。当然,一切工作的前提是你能上网,而且配置好了一个可用的源。
1. 安装Vim和Vim基本插件
我们需要首先安装好Vim和Vim的基本插件。这些使用apt-get安装即可:
sudo apt-get install vim vim-doc vim-scripts
其中vim-scripts是vim的一些基本插件,包括语法高亮的支持、缩进等等。
2. Vim配置文件
Vim强大的功能,其来源基本上就两个地方:插件,以及配置文件。
上面已经下载了Vim的基本插件,下面说一下Vim的基本配置。Vim本身的系统配置文件夹是在/usr/share/vim/和/etc/vim/两个文件夹下,我们一般不要去改变这些,改了以后不容易恢复。我们需要在用户文件夹下建立自己的配置文件。假设用户的名字是user。进入用户文件夹(/home/user/)之后,用gedit新建一个名叫.vimrc的文件:
gedit .vimrc
之所以用gedit是因为vim里面不能拷贝粘贴,为了方便大段大段的文字粘贴,还是先用gedit吧。。。
然后把下面的文字拷贝进这个文件之后保存:
" This line should not be removed as it ensures that various options are " properly set to work with the Vim-related packages available in Debian. runtime! debian.vim " Uncomment the next line to make Vim more Vi-compatible " NOTE: debian.vim sets 'nocompatible'. Setting 'compatible' changes numerous " options, so any other options should be set AFTER setting 'compatible'. set nocompatible " Vim5 and later versions support syntax highlighting. Uncommenting the " following enables syntax highlighting by default. if has("syntax") syntax on endif " detect file type filetype on filetype plugin on " If using a dark background within the editing area and syntax highlighting " turn on this option as well set background=dark " Uncomment the following to have Vim jump to the last position when " reopening a file if has("autocmd") au BufReadPost * if line("'/"") > 1 && line("'/"") <= line("$") | exe "normal! g'/"" | endif "have Vim load indentation rules and plugins according to the detected filetype filetype plugin indent on endif " The following are commented out as they cause vim to behave a lot " differently from regular Vi. They are highly recommended though. set showcmd " Show (partial) command in status line. set showmatch " Show matching brackets. "set ignorecase " Do case insensitive matching "set smartcase " Do smart case matching set incsearch " Incremental search set autowrite " Automatically save before commands like :next and :make set autoindent set smartindent set tabstop=4 set shiftwidth=4 "set hidden " Hide buffers when they are abandoned set mouse=a " Enable mouse usage (all modes) set number " Enable line number set previewwindow " set history=50 " set command history to 50
注意:单个双引号开头的行是注释掉的,不起作用的。
保存文件之后,启动Vim。在我的电脑商,此时Vim已经是这种效果了(语法高亮挺漂亮的–这个是由vim-scripts中的插件支持的):
3. ctags安装和使用
在这里下载ctags:http://sourceforge.net/projects/ctags/files/
或者
sudo apt-get install exuberant-ctags (不能是emacs的ctags)(建议使用这个)
ctags的作用就是把c/c++文件分割成tag,并默认保存在一个叫tags的文件中。假设我们现在有一些.h/.c/.cpp文件在/home/user/code/文件夹下,那么在这个文件夹下执行下面的命令就能生成此项目的tags文件:
ctags -R --c++-kinds=+p --fields=+iaS --extra=+q
此时在这个目录下就能找到一个叫tags的文件了。
4. 代码跳转
经过上面的步骤之后,就可以在本项目内实现代码跳转了,但不能跳转到不是在本项目的代码中定义的tag。例如在上面的图中,本地定义了一个类A,在main函数中定义了一个A类的对象,我们可以按“Ctrl+]”组合键跳转到class A那一行。然后可以按“Ctrl+O”跳转回来。
如果想实现跳转到非本项目的tag,则必须让Vim知道这些tag在哪。刚才的项目在/home/user/code/目录下,现在假设又有一个项目在/home/user/program/下,那么我们需要在此项目下生成program这个项目的tags文件(还是用上面的ctags命令)。
生成之后,要告知Vim,需要在Vim的配置文件中(/home/user/.vimrc)添加下面的内容:
" -- ctags setting -- set tags=tags set tags+=./tags " add current directory's generated tags file set tags+=~/program/tags " add new tags file
最后一行就表示在搜寻tags文件的时候,也要搜寻/home/user/program/文件夹下的tags文件。保存以后重启,此时应该就能实现不同项目间的跳转了。这是因为我们经常会基于一些库开发软件,我们需要查看库中函数或者类的定义的时候,会经常需要此功能。
5. 自动补全的安装
自动补全功能的实现,可以通过一个Vim插件实现:OmniCppComplete。可以在这里下载到:http://www.vim.org/scripts/script.php?script_id=1520
这个插件是基于ctags数据库即tags文件实现的。
上面我们也介绍了如何独立于系统配置文件之外,建立自己的Vim配置文件。当我们自己下载Vim插件的时候,也可以另外建立目录,放置我们自己的插件。这个目录一般为/home/user/.vim,另外还需要建立一个插件子目录,一个插件文档子目录,以上的可以进入/home/user目录下通过下面的命令执行:
mkdir .vim cd .vim mkdir plugin mkdir doc
然后将下载到的zip文件放到.vim目录下,直接解压(插件也包括两个目录,一个plugin,一个doc,所以它会自动放置到对应的目录)。
注意,我在ubuntu10.10把omnicppcomplete-0.41.zip解压后有三个文件夹:after, autoload, doc我直接把这三个文件夹放在 .vim这个文件夹下,并没有放在plugin文件夹里面,因为我把这三个文件夹放在plugin文件夹下面打开vim也就是用vim编辑一个文件的时候会又出错信息,但是放在 .vim也可以正常自动补全,两种方法都试一下看看。
unzip omnicppcomplete-0.41.zip
插件这就算安装完了。然后再到vim配置文件中加入如下的配置:
"-- omnicppcomplete setting -- set completeopt=menu,menuone let OmniCpp_MayCompleteDot = 1 " autocomplete with . let OmniCpp_MayCompleteArrow = 1 " autocomplete with -> let OmniCpp_MayCompleteScope = 1 " autocomplete with :: let OmniCpp_SelectFirstItem = 2 " select first item (but don't insert) let OmniCpp_NamespaceSearch = 2 " search namespaces in this and included files let OmniCpp_ShowPrototypeInAbbr = 1 " show function prototype in popup window let OmniCpp_GlobalScopeSearch=1 let OmniCpp_DisplayMode=1 let OmniCpp_DefaultNamespaces=["std"]
(前几行就是提供了C++中的./->/::等操作符的提示和自动完成)。
6. 自动补全功能的测试
C++开发中经常会用到C++标准库的代码,因此STL的自动补全很重要。可以下载一份C++标准库的源代码来测试一下自动补全功能。
sudo apt-get install build-essential
然后在/usr/include/c++下就可以找到标准库的头文件了。在此文件夹下生成tags文件,并添加到vim的配置文件中(不再重复上面的内容),然后在编程的时候就可以使用自动补全功能了。
我直接把/usr/include/下的所有文件都做了ctags,也就是说如果你想把哪个类库加入到vim的代码提示功能下面,你只需要在这个类库的最底层文件夹下面执行 ctags -R --c++-kinds=+p --fields=+iaS --extra=+q ,这时候会在这个文件夹下面生成一个tags文件,然后把这个tags文件加入到/home/user/.vimrc配置文件中(请参考上面)
下面展示了一张vector的函数补全的效果图:
PS:在自动补全的点,Vim必须知道可能补全的定义。比如说,在namespace std命名空间下的变量和函数,必须要用using namespace std;暴露出来,否则是不能补全的。在.cpp文件中还可以,在.h文件中这样就不是好的做法了。暂时不知道这个问题是由于我自己配置错误还是程序没有实现。
以上引用自:http://xiaozhi.de/2010/code-auto-complete-and-jump-to-under-vim
1.其他的VIM插件的功能和使用:
taglist 精干,需要ctags的支撑 ,直接可以在左边列出函数列表,全局参数列表。(可以排序)
cscope 比较强大,可以对函数以及部分类型定义进行跳转,但有些BUG,好像在某些条件下无法正确找到分析枚举的定义。也就是查看你所使用的类型的定义。
global新版本可以嵌入vim使用,提供比较完整解析和类型索引,和cscope比,稍微差些的就是对类型引用的打印列表中没有标识这个引用在什么函数中进行的。其实我的感觉global可能不是为vim所生,它的主要目的是用html的方式进行表达相关的关联关系和索引,使用起来感觉没有cscope的那么贴切。
cscope和global都是查看你所使用的类型的定义。以上已经说出了两者的区别。
大家可以根据自己的需求和实际情况进行安装,以上的插件都是基于ctags的基础上的,因此必须先装ctags再装其他插件。
2、相关的扩展的安装
代码
apt-get install exuberant-ctags cscope global
cppcomplete 和 taglist 要到www.vim.org的扩展列表中下载。
taglist 的下载地址:
http://www.vim.org/scripts/script.php?script_id=273
cppcomplete 的下载地址:
http://www.vim.org/scripts/script.php?script_id=527
然后在 建立目录
代码
$HOME/.vim/plugin
将下载的cppcomplete.vim 和 taglist.vim拷贝到$HOME/.vim/plugin中。
安装了global后,最新4.8.6 以上版本有带vim的扩展,将它也拷贝到 $HOME/.vim/plugin
debian sid 版本global安装后扩展文件在
代码
/usr/share/doc/global/examples/gtags.vim.gz
需要拷贝到$HOME/.vim/plugin后解压,解压方法:
代码
gzip -d gtags.vim.gz
3、使用这些工具
1)准备工作,先修改一下$HOME/.vimrc文件
为了更好的使用cscope请添加如下内容,这样Ctrl-]的跳转将由cscope的tags进行分析。
代码
if has("cscope")
set csprg=/usr/bin/cscope
set csto=0
set cst
set nocsverb
" add any database in current directory
if filereadable("cscope.out")
cs add cscope.out
" else add database pointed to by environment
elseif $CSCOPE_DB != ""
cs add $CSCOPE_DB
endif
set csverb
set cscopetag
set cscopequickfix=s-,g-,c-,d-,t-,e-,f-,i-
endif
2)使用cscope
cscope的tag生成最简单的方法是:
c中:cscope -Rbq
在你的开发工程的最上层目录执行cscope-indexer,它会遍历下面的所有目录,生成两个文件,一个是cscope.files,这个文件记录需要生成tags的文件名,可以手工修改,另一个是cscope格式的tags文件cscope.out。
c++中使用cscope
-R: 在生成索引文件时,搜索子目录树中的代码
-b: 只生成索引文件,不进入cscope的界面
-k: 在生成索引文件时,不搜索/usr/include目录
-q: 生成cscope.in.out和cscope.po.out文件,加快cscope的索引速度
#!/bin/sh
find . -name "*.h" -o -name "*.c" -o -name "*.cc" -name "*.cpp" > cscope.files
cscope -bkq -i cscope.files
ctags -R
完成后,你在生成了cscope.out的目录打开工程的任意文件,就可以使用Ctrl-]跳转查找类型定义了。
代码
进入vim后第一件事是要把刚才生成的cscope文件导入到vim中来, 用下面的命令:
:cs add /home/wooin/vim71/cscope.out /home/wooin/vim71
上面这条命令很重要, 必须写全, 不能只写前半句:
:cs add /home/wooin/vim71/cscope.out
cs f s xxxx 查找xxxx出现的地方,它能详细列出哪些文件的哪行的哪个函数引用,以及该行的内容,比较不错
它的所有命令的使用请参考:
代码
help cscope
3)使用taglist
taglist的功能是即时生成当前文件的函数列表和全局变量列表,便于索引。
在vim中命令模式下使用
Tlist 打开或者关闭当前文件的索引;
TlistSync 立即在打开的索引窗口中定位当前的光标所在位置属于哪个函数或者结构定义中。
还有其他命令,请参考它的帮助文件。
4)ctags的使用
其实cscope是用来替代ctags功能的,ctags的应用广泛,还有其他很多的软件依赖它。
例如要生成cppcomplete需要的tags文件的话,需要运行下面的命令:
代码
ctags -n -f cppcomplete.tags --fields=+ai --C++-types=+p * -L cscope.files
注意,我在最后使用了参数"-L cscope.files" 这仅仅是借用拉cscope生成的文件索引来帮助ctags去查询相关工程文件生成tags。
5)使用cppcomplete
cppcomplete的使用我只是简单的发现它可以根据上述方法生成的tags文件来自动补全类型成员。
使用很简单,就是在你需要补全类型成员时,按F8键就可以拉。它一般第一次使用时,需要让你确认是使用已有的tags文件还是再生成一次。一般我们自己控制生成tags文件的时机,它就使用就行拉。
但它也受到ctags的分析能力比较差的限制,可能不是每次都能帮到你。
6)使用global
在工程的最上层目录执行命令:
gtags
等待它完成所有需要的global自己格式的tags的生成
生成完后,需要的就是在生成tags的目录打开你的工程的任意文件,用如下命令查询相关类型引用和关联关系:
代码
Gtags xxxx 查找xxxx的定义
Gtags -r xxxx 查找xxxx的引用
Gtags -s xxxx 查找xxxx出现的地方
它的提示信息很有显,不如cscope更直观,但对大型分析的比较完整。
有时它无法正常分析的类型 可以试试用带-s 的参数的方式找找类型定义。再不行,我就不清楚拉 smile.gif
indent -kr -nut -ts2 -i3 -l-1 *.c
valgrind --leak-check=full --leak-resolution=high --show-reachable=yes
在你的开发工程的最上层目录执行cscope-indexer
ctags -n -f cppcomplete.tags --fields=+ai --C++-types=+p * -L cscope.files
:!ctags -R
Tlist 打开或者关闭当前文件的索引;
TlistSync 立即在打开的索引窗口中定位当前的光标所在位置属于哪个函数或者结构定义中。
u 更新taglist窗口中的tag
s 更改排序方式,在按名字排序和按出现顺序排序间切换
[[ 跳到前一个文件
]] 跳到后一个文件
将光标停放在函数或者变量的位置,gd会高亮出当前文件中所有的函数或者变量,按n查看下一个
gg光标返回到文件的顶部
ctrl + p : 自动匹配 补齐
ctrl +] :跳转 ctrl + T : 返回跳转
把光标移到"stdio.h"的任一字符上,键入"gf",则Vim会自动打开/usr/include/stdio.h文件。使用"Ctrl-O" 可返回到原先的文件中。
"cscope find"的用法:
cs find c|d|e|f|g|i|s|t name
0 或 s 查找本 C 符号(可以跳过注释)
1 或 g 查找本定义
2 或 d 查找本函数调用的函数
3 或 c 查找调用本函数的函数
4 或 t 查找本字符串
6 或 e 查找本 egrep 模式
7 或 f 查找本文件
8 或 i 查找包含本文件的文件
:cw 在窗口中显示
vim :
复制5行: y5y , p
光标在单词间移动 w b
行移动: 0(行首) $(行尾)
分割窗口: :split 切换 ctrl + w
向下滚屏: ctrl +D ctrl +u
替换 : %s/four/4/g
删除多行 n dd