本节所用命令的帮助入口:
:help ins-completion :help compl-omni :help 'omnifunc' :help i_CTRL-X_CTRL-O :help ins-completion-menu :help popupmenu-keys :help 'completeopt' :help compl-omni-filetypes :help omnicppcomplete.txt
使用过Source Insight的人一定对它的自动补全功能印象深刻,在很多的集成开发环境中,也都支持自动补全。vim做为一个出色的编辑器,这样的功能当然少不了。而且,作为一个通用的编辑器,vim实现的补全功能并不仅仅限于对程序的补全,它可以对文件名补全、根据字典进行补全、根据本缓冲区或其它缓冲区类似的内容进行补全、根据文件语法补全等等,它甚至允许用户自己编写函数来实现定制的补全。
作为vim进阶系列文章中的一篇,本文以介绍vim对程序的补全为主,也顺带介绍一下其它的补全方式。本文将分为两篇,第一篇主要介绍vim的OMNI补全,下一篇简要介绍其它的补全方式,以及SuperTab插件。
vim的OMNI补全(以下称”全能补全”)可以支持多种程序语言,包括C,C++, XML/HTML,CSS,JAVASCRIPT,PHP,RUBY等,详细列表请参阅”:help compl-omni-filetypes“。在本文中,主要介绍C及C++的全能补全。
vim在对不同类型的文件进行补全时,会根据文件类型,为其设置不同的补全函数。也就是说,要实现全能补全功能,需要打开文件类型检测。把下面的命令加到你的vimrc中:
filetype plugin indent on
你可以查看’omnifunc‘选项,来知道当前的补全函数是什么。
对C及C++代码的全能补全需要使用Exuberant ctags生成的标签文件,我们在前面的文章中介绍过如何使用Exuberant ctags程序来生成标签文件。不过,如果你的Exuberant ctags版本为5.5.4,那么需要为其打上增加”typename:“字段补丁,才能支持C的全能补全。补丁在这里下载:
ftp://ftp.vim.org/pub/vim/unstable/patches/ctags-5.5.4.patch
可以在这里找到MS-Windows上已经编译好的可执行版本:
http://georgevreilly.com/vim/ctags.html
不过我建议使用最新5.6版本Exuberant Ctags。在下面的网站可以下载:
http://ctags.sourceforge.net/
你可以直接下载已经编译好的rpm版本,或者下载源代码。如果是后者,使用以下命令对源代码进行编译:
tar zvxf ctags-5.6.tar.gz cd ctags-5.6 ./configure make make install
如果你没有系统目录的写权限,你可能要把Exuberant Ctags安装到自己的主目录,只需要把上面的”./configure“命令改为”./configure –prefix=/home/xxx“就可以了。
Ctags升级后,使用”ctags –R“更新一下标签文件,现在再进入vim就可以在C程序中全能补全了。我们依旧以vim 7.0的源代码为例。
例如,我们在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;
在下一篇文章中,将继续介绍vim提供的其它补全方式。
[参考文档]
原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]
本文链接地址: http://easwy.com/blog/archives/advanced-vim-skills-omin-complete/
文章的脚注信息由WordPress的wp-posturl插件自动生成
文本处理





38条评论 添加评论
(以下为CSDN评论的转帖)
#baikaishiuc 发表于2007-05-17 22:07:51 IP: 125.71.3.*
我想问下啊,比如我有个cpp类型的文件,其中有这么一句
string str;
然后我要使用里面的方法,比如size()
str.
然后我每次一敲入.号,Vim就停住了,然后过很5,6秒,然后跟你说,
处理function omni#cpp#complete#main..omni#cpp#namespace#GetContexts
后面有还有一大串错误,然后在给你个错误号
第 7行:
E713:Dictionary的键不能为空
我看了下那个帮助文件,看不懂,我该怎么做?
#baikaishiuc 发表于2007-05-17 22:42:17 IP: 125.71.3.*
自己解决了,似乎是因为自己以前设置path和tags的路径的时候,都是直接
set path=
set tags=
应该用
set tags+=
set path+=
,反正弄的我辛苦死了,害的我把omnicppcomplete看了两遍。感觉LZ你有很好的当老师的天赋,讲东西,都讲重点和经典,不讲难点,难点需要自己来体会的~~:)
还有个问题啊,比如,当我敲入了.后,那个补全似乎搜索的时间有点长,有没什么方法可以让他搜索速度快点。是不是我tags之类的东西没有设置好。
(以下为CSDN评论的转帖)
#easwy 发表于2007-05-18 14:33:34 IP: 213.70.90.*
补全慢应该只和计算机的速度以及tag文件的数目和大小有关
#lipengch 发表于2007-06-17 01:15:34 IP: 219.239.98.*
你好:
请教一个问题
为了自动补全我在.vimrc文件里面加了
filetype plugin on
filetype indent on
syntax on
在启动gvim的时候报下面这个错误:
— 自动命令 —“)
filetypeplugin FileType
*call s:LoadFTPlugin()
filetypeindent FileType
*call s:LoadIndent()
syntaxset FileType
*exe “set syntax=” . expand(“
请教一下可能的原因,是因为少装了什么插件吗?
还是别的原因?
#easwy 发表于2007-06-18 14:10:09 IP: 213.70.90.*
这个错误信息不全吧?
(以下为CSDN评论的转帖)
#alan 发表于2008-02-19 16:52:37 IP: 220.178.45.*
有时候,我会发现函数原形很长,以至于下拉列表的窗口宽度不够,但omnicppcomplete又不自动折行到下一行显示,结果就显示不全了。这种情况该如果处理呢?
请教!!!
#easwy 发表于2008-02-20 13:53:32 IP: 213.70.90.*
对这种情况,可以打开omnicppcomplete的preview窗口,在此窗口中可以显示出完整的函数名。
或者你改变一下omnicppcomplete的选项,把它显示的方式改一下。
另外,可以看一下脚本的源代码,看能不能把它的下拉窗口改的大一些
(以下为CSDN评论的转帖)
#mymsnzxw 发表于2008-02-22 19:21:34 IP: 58.45.197.*
楼主,看了你的vim系列,感觉学到挺多的,有一个问题还没搞懂,特向你请教下:
1:软件
vim 7.1
ctags 5.7.1
2: ~/.vimrc
filetype plugin indent on
set completeopt=longest,menu
autocmd FileType c set omnifunc=ccomplete#Complete
set tags+=~/.vim/systags
3:目录结构
~/vim71/src/num1.c
4:num1.c
#include
struct student
{
int no;
char name[10];
};
typedef struct student stud;
typedef struct addrinfo addr;
int main(void)
{
stud my_stud;
addr my_addr;
}
5:运行命令
cd ~/vim71
ctags -R -f ~/.vim/systags /usr/include /usr/local/include
ctags -R
6:vi ./src/num1.c
现在的话,用my_addr. ,再按ctrl-x,ctrl-o可以实现结构的自动补全,
但是,如果将num1.c中的“typedef struct student stud”和”typedef struct addronfo addr “去掉,把main()中的两行也去掉,用student you_stud; addrinfo you_addr代替,现在再用you_addr. ,再按ctrl-x,ctrl-o,则显示 “Omni completion (^O^N^P) Pattern not found .
麻烦你帮我解释下吧。
(以下为CSDN评论的转帖)
#uniteworld 发表于2008-02-25 15:38:48 IP: 123.116.224.*
感谢楼主的文章,使我受益非浅。
在我使用全能补全时,发现不能补全,有下面的提示:
全能补全,找不到模式
请问这是怎么回事?
#WangGuangPing 发表于2008-09-17 15:25:49 IP: 218.22.36.*
不知道是不是我的设置有问题,还是什么原因,我发现按照你说的办法用omnicppcomplete不能显示类的构造函数,不知道你们是不是也发现了这个问题?
还有一个现像,我通常是在如下几个目录中建立 tags文件:
set tags=/usr/include/qt4/tags,/usr/include/c++/tags,/usr/include/tags,
这种情况下,有时我在自动补全时,又删除前面刚刚已输的部分名称,比如 prin时按过C-x C-o,继续输入f时,又<-删除前面输的prinf时,系统就停下好一会,估计是在检索。这样子性能很差,难道你们没遇到这种情形吗?
如何处理呢?请楼主赐教。
2008-10-29 14:50:17作者回复
vim毕竟不同于专业的IDE开发工具,它的补全是通过编写脚本完成的,所以肯定会有限制。
当omni补全不能用的,可以考虑运用其它的补全方式。
如果补全等待的时间太久,可以使用ctrl-c来中断补全动作。
(以下为CSDN评论的转帖)
#panwai 发表于2008-09-27 19:36:34 IP: 61.139.87.*
老大,在上面那个3窗口的界面中,左上角的File List窗口是怎么配置的阿?谁能帮忙告诉下阿,谢了!!!
2008-10-29 14:45:00作者回复
参见 使用VIM开发软件项目 – (6) 文件浏览和缓冲区浏览 (http://blog.csdn.net/easwy/archive/2007/03/09/1525554.aspx)
#aresfe 发表于2008-11-14 14:51:10 IP: 61.172.247.*
看了楼主的文章,收获菲浅!!
#qingshi163 发表于2008-12-22 16:10:36 IP: 222.131.133.*
最好不要把所有的tags都加上,这样搜索非常费时,最好用什么加什么,tags文件也最好分类。比如当需要gtk+时 set tags+=gtktags,这样速度就很快了。
谢谢,很有帮助
好像安装了OmniCppComplete插件对C++进行补全后,如果写头文件,比如
#include
写到”.”的时候会自动提示:全能补全,找不到模式
不知道有没有办法去掉呢呵呵
喔…又是尖括号无法输入的问题,其实就是stdio.h中的”.”
谢谢,您的一系列文章对我很有帮助
@simplyzhao
好像OmniCppComplete插件做不到这么智能…在这种情况下,如果不想自动补全的话,就输入ctrl-c中止补全。
请问我根据您讲的设置:
set completeopt=longest,menu
为什么在下拉菜单里看不到函数参数呢,想看参数的话只有开启preview窗口
看您贴的图,应该是可以看到参数的
是不是有什么选项之类的可以设置?
谢谢
@simplyzhao
这需要调整OmniCppComplete插件的设置:
:help OmniCpp_ShowPrototypeInAbbr
建议你把这个插件的帮助完整看一遍。
你上面问的那个关于.补全的问题,在这个插件里其实也是可以关掉的,不过关掉的副作用太大。
你好,我在_vimrc中配置
inoremap gj
在使用弹出菜单时,按键,会马上把第一项写上就关闭菜单了(也就是不让我选择后面的),并且后面还加了“gj”这两个字符,怎么回事?盼复。谢谢
@ttuurr
你的那个映射被留言系统过滤掉了
不过从现象看,应该是你定义的映射有问题,你仔细检查一下。
请问有办法让OmniCppComplete 对::进行补全吗?
比如QTextCodec::setCodecForTr 在输入完:: 后,我手动c-x c-o弹出的补全内容不对,不会根据::前面的内容进行判断
@Easwy
补全速度太慢的话, 有另外一种方法(如果你内存比较大的话), 自己写2个小脚本1>打开所有需要的Tags,隐藏这些缓冲 2>关掉所有tags的缓冲区
然后设置让c-n,c-p不去扫描其他缓冲区(免得查到Tags得到的东西太多), 只要写程序前先载入一次就好了, 现在写QT的程序.载入全部tags后,内存占从18M升到90M,不过omni补全的时候就可以马上弹出来了
补充一下, 不是说无法判断,而是判断出来的东西少了,象这种在补全内容里面就看不到,可是tag里面有这条
@Mk2
从插件的帮助文档里看,目前只处理了.和->,好像不能设置对::后面的内容进行补全。
补全速度太慢的话, 有另外一种方法(如果你内存比较大的话), 自己写2个小脚本1>打开所有需要的Tags,隐藏这些缓冲 2>关掉所有tags的缓冲区
然后设置让c-n,c-p不去扫描其他缓冲区(免得查到Tags得到的东西太多), 只要写程序前先载入一次就好了, 现在写QT的程序.载入全部tags后,内存占从18M升到90M,不过omni补全的时候就可以马上弹出来了
=>能否告知怎么做?我使用VIM的自动补全功能 太慢了,谢谢
[...] 语法高亮 vim使用进阶: 程序员的利器 – cscope vim使用进阶: 剑不离手 – quickfix vim使用进阶: 智能补全 vim使用进阶: 自动补全 vim使用进阶: 指随意动,移动如飞 (一) vim使用进阶: [...]
[...] [2] http://easwy.com/blog/archives/advanced-vim-skills-omin-complete/ [...]
LZ,为什么我的omni自动补全没有显示出变量的类型信息呀,我找了很多原因,一直都找不到哦,你能指点一下吗?thanks
我在windows下自动补全弹出补全列表后,C-N是向上,C-P是向下,是反的。
而在linux下则是正常的,C-N是向下,C-P是向上。
请问大哥如何绑定让它改过来?
请教个问题,我定义了一个结构体A
typedef A B
typedef B C
typedef C D,
D d
那么当我用d.的时候, 他就说找不到匹配,有没有解决办法,还是说,我设置有问题,谢谢!
@xyf
检查一下你的vimrc,应该是设置的问题。
@liu1061
会不会和你所用的ctags版本有关,使用最新的ctags 5.6/5.7试试。
@yus
我试了一下,如果上述定义放在C文件里(即:set omnifunc=ccomplete#Complete),能够补全。
如果放在C++文件里(即:set omnifunc=omni#cpp#complete#Main),则不能补全。
看起来似乎是omnicppcomplete插件的问题。
可是我windows和linux两个配置文件是一样到,除了fileencoding不一样而已,
windows下是cp936,linux下是utf8
@xyf
试试下面的步骤:
1. 使用gvim -u NONE启动你的vi,这个命令会跳过vimrc。在这个环境里重复上面的测试。
:help -u
2. 使用”:imap”命令,看一下有没有<CTRL-P>和<CTRL-N>的映射,如果有,看看映射的正不正确。
:help imap
Linux可以成功补全类成员,但是windows没有反应啊,在类变量后按.没有什么反应啊。是不是不支持win下的类成员补全啊
@absolute8511
和Windows还是Linux应该没关系。
你生成tags文件了吗?tags选项的设置正不正确?
:help ‘tags’
@Easwy
用ctags -R –c++-kinds=+p –fields=+iaS –extra=+q 生成tags了,函数和类名都能自动提示,就是类成员用->和. 无法显示,如果按tab可以显示所有tag,这些包括类成员,但是我想->和.之后立即显示成员,而且不要显示其他的。
在linux下都行的啊。但是我在windows下配置了下就是不行啊,哪里出问题了啊。
@absolute8511
你是不是用了supertab插件?
感觉像是supertab屏蔽了omni-cpp插件
你确认下?
@Easwy
禁用了tab还是一样啊。郁闷了,看来还是linux好
@absolute8511
我虽然没在windows上用过,但理论上应该是没问题的
检查一下linux下的vimrc/.vim目录和windows下的有没什么区别?
加上ShowPrototypeInAbbr后,显示结果和你的不一样,感觉你这样的更加清晰。
同样,下面补全结构的成员,后面有注释就会显示,帮助中没看到。。。。
是自己修改脚本的原因吗?加上了@@?
谢谢教程,受益良多。
PS:我在没装OmniCppComplete,C文件无法补全结构的成员。
@hiessu
我这里关于C文件的抓图使用的不是OmniCppComplete插件,而是vim自带的C补全插件,用下面的命令可以设置:
:set omnifunc=ccomplete#Complete
我试了一下,它可以补全结构成员,不过好像要手动输入<C-X><C-O>
@Easwy 感谢解答!我这应该是一个结构成员因为重名的原因无法补全的问题。