Thursday, September 20, 2012

Vim - tips and tweaks for C/C++ coding

Here are some tweaks I found useful while playing with C/C++ code in vim. You can try them by adding them to your .vimrc file. These aren't things I invented, but collected from net over time (Though I have added some minor modifications myself).

I am going to assume that you are familiar with ctags and cscope. Please take some time to make sure that the assumption is correct.

1) Adding cscope and ctags files automatically.

This small function will search for cscope and ctags files (cscope.out, tags) in parent folders and connect them to vim automatically.

function SetTags()
   let curdir = getcwd()
   while !filereadable("tags") && getcwd() != "/"
      cd ..
   endwhile
   if filereadable("tags")
      execute "set tags=" . getcwd() . "/tags"
   endif
   execute "cd " . curdir
   while !filereadable("cscope.out") && getcwd() != "/"
      cd ..
   endwhile
   if filereadable("cscope.out")
      execute "cscope add ".getcwd()."/cscope.out ".getcwd()
   endif
   execute "cd " . curdir
endfunction
call SetTags()

2) Quickfix and cscope

Vim has feature named quickfix window.  Next time when you want to give a make, try giving it from vim and you will see how quickfix window makes things easy.
:make something
Vim will call make and will take you to the places where compiler found errors.
:copen ~ will open the list of errors in quickfix window.
:cn  ~ will take you to the next error.
:cp  ~ well, guess it.
You can also use quickfix window with grep. Try,
:grep -r something *

Here comes the interesting part. You can use quickfix functionality along with cscope by adding the following settings to .vimrc
set cscopequickfix=s-,c-,d-,i-,t-,e-,g-

3) Invoke cscope with split window

nnoremap <C-\>s :vs<CR>:execute  ("cs find s ".expand("<cword>"))<CR>
nnoremap <C-\>g :vs<CR>:execute  ("cs find g ".expand("<cword>"))<CR>

What does it do ?
Whenever  we give a Ctrl-\ s, it will (first) split the window  vertically into two (then) invoke cscope.
We can use :cn and :cp to go forward and backward the cscope result list.

I found it useful to re assign keys[1] for :cn and :cp.
nnoremap ^[n :cn<CR>
nnoremap ^[m :cp<CR>

4) Filtering quickfix list

Try the first result/reply  here.

5) Tracking locations in multiple files

It is sometimes important to keep track of all the function call paths. Simplest option is to use global marks. All the marks with capital letters are global marks.
Try mA in one file (in normal mode) and  give 'A while you are in some other file.
(Try Ctrl-o and Ctrl-i also)

Another option is to add the locations directly to a file. It can be done easily as follows.
nmap ^[8 :call system('echo '.expand('%:p').':'.line('.').':0 >> ~/.loc_vim')<CR>

What does it do ?
It will append current_file_name:line_no:0 to a file named .loc_vim in your home folder, when you press Alt-8 (8 key has a *). [1]
We can load this location file to quickfix window using the command
:cfile ~/.loc_vim.txt

6) Debug prints

We can load the debug log file to quickfix window if we make sure that the debug prints are of the form:
file_name:line_no:debug_prints
(same format in which grep gives results with option -n)

Here is an example debug macro that can be used in C [2].

#define DEBUG_PRINT(...)\
    printf("%s:%d:",__FILE__,__LINE__);\
    printf(__VA_ARGS__);\
    printf("\n");

Collect the logs generated by your program(eg : a.out) to a file (eg: debug.log)
>> ./a.out |tee debug.log
Load the log file in  vim using
:cfile debug.log


Notes:

[1] One interesting thing about Vim is that all the "Alt" key combinations are completely free by default. But the usual Alt key binding <A-f> (or <M-f>) for Alt-f may not work(f is just an example) in non-gui version of vim. To make it work, we need to understand what vim is getting when we give Alt-f. To find that, press Ctrl-v and then press Alt-f in insert mode. It will print a set of key combinations. Use them for defining key combinations. 
For me, it gives something like ^[f (where ^[ is a single character).

[2] Beware. This is an evil, unprotected macro.
You may have to protect it with a do{ }while(0) if you want to use them in any serious code.







No comments:

Post a Comment