Code Completion with VIM 7

Code completion, also called by some ‘intellisense’, is easily setup in VIM for C/C++ files (its setup-able for essentially any language but since I am mostly a C hacker this is what this will cover.)

In Vim 7 the vim team released something called omnicompletion.  What this does is that it allows you to create an omni-function that is called whenever the omni-completion command is executed (C-X C-O by default).  The reasoning behind this is that it provides a mechanism for generic completion support rather than any particular implementation.   Since VIM is used by a great many people there are at least that many use cases for omni-completion this gives the user the power to extend their editor to allow for any sort of completion setup they might desire (albeit with sufficient technical knowledge to preform the setup).

A key tool to VIM’s omnicompletion abilities is the use of Exuberant Ctags.  For those who do not know, this utility scans source and header files and creates an optimized representation of interesting bits that other programs can use to do likewise interesting things.  So to start with the setup lets look at how to create a tags file that usable by VIM.

Lets say you want to have GTK+ intellisense in your editor.  The following incantation will create the tags file for you:

 ctags -R --c++-kinds=+p --fields=+iaS --extra=+q /usr/include/gtk-2.0

This will recursively scan every header file in the gtk-2.0 directory and create tags for every function, definition, and structure contained in there and it will spit out a file called tags in whichever directory you ran this.  I would recommend renaming this file to gtk+.tags or similar.  The parameters we pass to ctags specify which type of information we want to collect.  The reason for those particular parameters is that they provide the data the a VIM plugin called omnicppcomplete needs to functions which we will cover shortly.

Now that you’ve generated the gtk+.tags file place it whereever you would like to keep it.  VIM will always look for a file named tags in the current directory but for these sorts of tag files (whole interface dumps) it’s better to include them in your .vimrc like so:

set tags+=/path/to/gtk+.vim

You can create multiple files for each library you want completion for, or you could simply create a single tag file for the entirety of /usr/include.  Be warned using a huge /usr/include single tags file could slow down things considerably depending on your hardware.

Now that our GTK+ tags are setup we need to install omnicppcomplete.  This is a VIM plugin that provides an omnifunction for C and C++ languages obviating the need for us to create our own.  Once you have installed this (simple extracting it into your .vim folder for the most part), you now have intellisense for GTK+ like so:

 

VIM GTK+ Completion

Isn’t progress exciting ;)  Remember that VIM also looks for a tags file in the current directory.  So if you wanted to add completion support for your individual projects its as easy as creating a tags from your source tree.  I setup a key command (C-F6 in my case) that will generate this for me while I am in a VIM session so as I update structures and functions I always have current completion:

 map <C-F6> :ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .<CR>

Omnicppcomplete is smart enough to start completion when it encounters an -> or . in the code so it really is like intellisense when you’re using it.  To complete a function name you’ll still need to hit the omnicompletion command sequence but otherwise it Just Works:

VIM Project Completion

 

Finally, and this is a matter of personal preference, but one of the reasons I use VIM over EMACS is that command sequences that involve lots of Control/Meta/Shift/Alt stuff annoy the hell out of me.  So in my case C-X C-O has to go away.  I use a function that maps the tab key  in a SuperClever way that I got from the book Hacking Vim by Kim Shulz which is a great repository of various VIM tips and tricks.  What this function does is that if there is no completion that could happen it will insert a tab.  Otherwise it checks to see if there is an omnifunction available and, if so, uses it. Otherwise it falls back to Dictionary completion if there is a dictionary defined.  Finally it resorts to simple known word completion.  In general, hitting the Tab key will just do the right thing for you in any given situation.

To get this functionality just add the following to your .vimrc:

 function! SuperCleverTab()
    if strpart(getline('.'), 0, col('.') - 1) =~ '^\s*$'
        return "\<Tab>"
    else
        if &omnifunc != ''
            return "\<C-X>\<C-O>"
        elseif &dictionary != ''
            return "\<C-K>"
        else
            return "\<C-N>"
        endif
    endif
endfunction

inoremap <Tab> <C-R>=SuperCleverTab()<cr>

And there we have it.  A full, quick, and fast ‘intellisense’ setup in Vim.  I use this in my hacking every day, its really changed the way I work with Vim. If you’re a vim afficiando you really ought to give this a go.

 

Comments are closed.