C++ AutoComplete feature in VIM
I really needed a context-sensitive C++ autocomplete feature for Vim, which would allow me to do crazy things like autocompleting class member names. As it turns out, there is a way to do that, and it works pretty well. I decided to write up how I set things up myself, in hopes that this will help others as well.
Here is what you need in order to set things up:
- Vim (d'oh!)
- The OmniCppComplete plugin
- Exuberant Ctags
- 5 minutes free time
So, you need to install Vim and Ctags (which is platform dependent, and I leave it to you to figure out how to do that in your own platform). Once you get those set up, grab the OmniCppComplete plugin, and extract it to the .vim directory under your home directory (create it if it doesn't exist). After that, you want to put the following inside your ~/.vimrc:
-
" omnicppcomplete options
-
map <C-x><C-x><C-T> :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q -f ~/.vim/commontags /usr/include /usr/local/include ~/moz/obj-ff-dbg/dist/include<CR><CR>
-
set tags+=~/.vim/commontags
-
-
" --- OmniCppComplete ---
-
" -- required --
-
set nocp " non vi compatible mode
-
filetype plugin on " enable plugins
-
-
" -- optional --
-
" auto close options when exiting insert mode or moving away
-
autocmd CursorMovedI * if pumvisible() == 0|pclose|endif
-
autocmd InsertLeave * if pumvisible() == 0|pclose|endif
-
set completeopt=menu,menuone
-
-
" -- configs --
-
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 (i.e. parameters) in popup window
-
let OmniCpp_LocalSearchDecl = 1 " don't require special style of function opening braces
-
-
" -- ctags --
-
" map <ctrl>+F12 to generate ctags for current folder:
-
map <C-x><C-t> :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .<CR><CR>
-
" add current directory's generated tags file to available tags
-
set tags+=./tags
-
-
" Setup the tab key to do autocompletion
-
function! CompleteTab()
-
let prec = strpart( getline('.'), 0, col('.')-1 )
-
if prec =~ '^\s*$' || prec =~ '\s$'
-
return "\<tab>"
-
else
-
return "\<c-x>\<c-o>"
-
endif
-
endfunction
-
-
inoremap <tab> <c-r>=CompleteTab()<cr>
You can of course customize this however you like, but the only part that you really need to customize is the second line. You would probably want to leave /usr/include and /usr/local/include there, but you can replace ~/moz/obj-ff-dbg/dist/include to whatever project specific directory which contains header files which contain definitions which you want to include in the C++ autocompletion. ~/moz/obj-ff-dbg/dist/include is a path on my system which contains all header files we use in Mozilla.
The autocompletion functionality is based on the ctags database. This is a list of all symbols found in header files. With this setup, you have two separate ctags databases, one is for your system-wide headers (which should change rarely), and the other is for your project-specific symbols. The former is stored in ~/.vim/commontags, and the latter is stored as a file named tags in your current directory. To update the system-wide ctags database, you can use Ctrl+X, Ctrl+X, Ctrl+T. To update the local ctags database (which is created from the contents of the current directory, recursively), you can use Ctrl+X Ctrl+T. You would usually update the local ctags database from time to time to make sure that the latest changes in your source files are reflected in the ctags database.
Now, open a C++ file inside Vim. Let's say you type the beginning of a symbol, and then press Tab. A list of symbols matching what you have types appear on the screen, like this:

Also, if you type ., -> or ::, you will be presented with a list of autocomplete options as well.



And that's it! If you feel adventurous, you can type :help omnicpp in Vim and start exploring what else you can do, but this setup is working perfectly fine for me.

Comments
a few other tweaks
I set this up today. Here are a few other tweaks I found useful.
1-I can't read the purple on my terminal. I added the following to my .vimrc:
highlight Pmenu ctermbg=green gui=bold
highlight Pmenu ctermfg=black gui=bold
2-I also use cscope, which can do things like find who calls a function. So I added a line to do 'cscope -bRq' when the ctags directory is rebuild.
3-I don't edit from the top-level directory, so I want vim to find my tags directory for me. I found this on stackoverflow ( http://stackoverflow.com/questions/563616/vimctags-tips-and-tricks ):
" Find the nearest ctags
function SetTags()
let curdir = getcwd()
while !filereadable("tags") && getcwd() != "/"
cd ..
endwhile
if filereadable("tags")
execute "set tags=" . getcwd() . "/tags"
endif
if filereadable("cscope.out")
execute "cs a " . getcwd() . "/cscope.out " . getcwd()
endif
execute "cd " . curdir
endfunction
call SetTags()
Hope people find that useful.
This is very cool, thank you!
This is very cool, thank you!
Also, you need Vim 7.0 or
Also, you need Vim 7.0 or later (the latest release & patchlevel is 7.2.402 as of this writing), and if you are on Windows it's not .vim/ but vimfiles/ -- still as a subfolder of your home directory (and if you're in doubt about "what" is your home directory, type ":echo $HOME" (without the quotes, and hit Enter at the end) in a running Vim, and it will tell you.
Re: Also, you need Vim 7.0 or
Thanks for the additional tips, Tony.
However, I think this can be made to work with lower versions of Vim, but anyway if someone has a lower version, they should probably consider upgrading!