Thursday, November 1, 2007

Intellisense - vim => IDE

On October 20th 2007, I blogged at bloglines about Developer Productivity and my interest about evaluating vim as an IDE for C/C++ programming.

http://www.bloglines.com/blog/SanjayaK?id=14

I manage to get intellisense working in vim for C/C++ source files by using already available vim scripts.

There are two vim scripts which can be used to enable intellisense for C/C++ code in vim.

icomplete - http://www.vim.org/scripts/script.php?script_id=1265
OmniCppComplete - http://www.vim.org/scripts/script.php?script_id=1520

OmniCppComplete is a set of vim script and has a good help. icomplete make use of a program and it doesn't has a good help. Also the latest update is in April 2006. However, it has the capability to automatically generate the tag file based on included header files. Therefore, I prefer icomplete over OmniCppComplete but propose some changes to make it more usable. I have mailed these changes to the author. Hopefully he will make them available to everyone soon.

Installation Steps
==========
* Download icomplete from http://www.vim.org/scripts/script.php?script_id=1265
* Follow the instructions and get it installed
* Replaced /etc/vim/plugin/icomplete.vim and /etc/vim/autoload/cppcomlete.vim with below given files

icomplete.vim
-------------------------------------------------------------
" Vim global plugin for C/C++ codecompletion with icomplete
" Last Change: 2005 Mar 29
" Maintainer: Martin Stubenschrott
" License: This file is placed in the public domain.

if v:version < omnifunc="cppcomplete#CompleteMain"> cppcomplete#Complete()
autocmd FileType cpp,c inoremap . cppcomplete#CompleteDot()
autocmd FileType cpp,c inoremap > cppcomplete#CompleteArrow()
autocmd FileType cpp,c inoremap : cppcomplete#CompleteColon()
endif

------------------------------------------------------------------------------------------------

cppcomplete.vim
------------------------
" Vim global plugin for C/C++ codecompletion with icomplete
" Last Change: 2005 Oct 23
" Maintainer: Martin Stubenschrott <stubenschrott@gmx.net>
" License: This file is placed in the public domain.

" This function is used for the 'omnifunc' option.
function! cppcomplete#CompleteMain(findstart, base)

if a:findstart
let line = getline('.')
let start = col('.') - 1
let s:cppcomplete_col = col('.') " for calling the external icomplete command, store the col
let s:cppcomplete_line = line('.')
let s:show_overloaded = 0 " set this to true, if we want to complete all overloaded functions after a (

" save the current buffer as a temporary file
let s:cppcomplete_tmpfile = tempname()
exe "silent! write!" s:cppcomplete_tmpfile

" Locate the start of the item, including "." and "->" and "(" and "::".
while start > 0
"if line[start - 1] =~ '\w\|\.\|(' " a . or ( is the start of our completion
if line[start - 1] =~ '\w' " a . or ( is the start of our completion
let start -= 1
elseif line[start - 1] == '.'
break
elseif line[start - 1] == '('
let start -= 1
let s:show_overloaded = 1
break
elseif start > 1 && line[start - 2] == '-' && line[start - 1] == '>'
break
elseif start > 1 && line[start - 2] == ':' && line[start - 1] == ':'
break
else
break
endif
endwhile
return start
endif

" Return list of matches.
let res = []

" check if set g:cppcomplete_tagfile
if exists('g:cppcomplete_tagfile')
let s:tagparam = " --tagfile=" . g:cppcomplete_tagfile
else
let s:tagparam = ""
endif

" call icomplete and store the result in the array
" java and c# users must build their tags file manually
if &ft == "java" || &ft == "cs"
let cmd = "icomplete --cache=0 -c " . s:cppcomplete_col . " -l " . s:cppcomplete_line . s:tagparam . " " . s:cppcomplete_tmpfile
else
let cmd = "icomplete --cache=1 -c " . s:cppcomplete_col . " -l " . s:cppcomplete_line . s:tagparam . " " . s:cppcomplete_tmpfile
endif

let icomplete_output = system(cmd)
if v:shell_error != 0
echo "Could not parse expression"
return res
endif

" found some results, return them
let g:ov = s:show_overloaded
for m in split(icomplete_output, '\n')
if s:show_overloaded == 0
if m =~ '^\C' . a:base " only words which start with base text - \C force using case
let ident = matchstr(m,'^\([a-zA-Z_0-9(]\)\+\C')
call add(res, ident)
endif
else " complete function arguments
" the second match is the function prototype
let ident = matchstr(m, '\s*(.*)', 0, 2)
" placeholders
if exists("g:cppcomplete_placeholders") && g:cppcomplete_placeholders == 1
let ident = substitute(ident, '^(\s*', '\0<+', "")
let ident = substitute(ident, '\s*)', '+>\0', "")
let ident = substitute(ident, '\s*,\s*', '+>\0<+', "g")
endif
call add(res, ident)
endif
endfor
let g:res = res
return res

endfunc

function! cppcomplete#Complete()
let omni_mapping = "\<C-X>\<C-O>"
return omni_mapping
endfunc

function! cppcomplete#CompleteDot()
return '.' . cppcomplete#Complete()
endfunc

function! cppcomplete#CompleteArrow()
let index = col('.') - 2
if index >= 0
let char = getline('.')[index]
if char == '-'
return '>' . cppcomplete#Complete()
endif
endif
return '>'
endfunc

function! cppcomplete#CompleteColon()
let index = col('.') - 2
if index >= 0
let char = getline('.')[index]
if char == ':'
return ':' . cppcomplete#Complete()
endif
endif
return ':'
endfunc

----------------------------------------------------------------------------------------------

1 comment:

Martin K. Schreder said...

I personally don't like icomplete becouse it's very primitive and in a way reinvents the wheel. CppComplete is quite nice though