Vim Tips Wiki
Register
Advertisement

Previous TipNext Tip

Tip: #384 - Easily switch between source and header file

Created: December 6, 2002 15:26 Complexity: intermediate Author: bubbleboy Version: 5.7 Karma: 124/46 Imported from: Tip#384

Switching between source and header files is a frequent operation, and so many ways to do it have been suggested. This article tries to list them all, and also list their advantages and disadvantages.

Script: a.vim

A vim script that does this can be found here: script#31, and is called a.vim.

Pros:

  • Ease of use ;
  • Handles multiple filetypes (not just C and C++), can be easily configured for more ;
  • Code is very well commented ;
  • Works with different extension styles (.C .c .cxx .cpp .CPP, .cc <--> .h .hpp .H .HPP) all at the same time - a switch will work from any source to any header extension and vice-versa ;
  • The path where the associated file must be searched can be configured.

Cons:

  • Quite large (~ 350 lines of code (not counting comments)).

Remarks:

  • It was hard to add new filetypes in older versions of the script, it is not true anymore.

By modifying ftplugins

This was the original suggestion for this article.

Pros:

  • Easy to add new filetypes
  • highly configurable.

Cons:

  • You have to modify filetype plugins (not that bad).
  • :find can be slow, especially when the file you are switching to does not exist.
  • Error when file does not exist.

To switch between header and source files very quickly, all you need to do is add a few key mappings in your filetype plugin files. Let me explain with an example:

Let's say that you're editing C files, so all you would have to do is edit your ftplugin/c_extra.vim file and include

nmap ,s :find %:t:r.c<cr> 
nmap ,S :sf %:t:r.c<cr> 

to switch to the corresponding source file, and

nmap ,h :find %:t:r.h<cr>
nmap ,H :sf %:t:r.h<cr> 

to switch to the corresponding header file.

The built-in :find command will search (recursively or not) for the specified file anywhere in your vim 'path' setting. The :sf is short for split-find, meaning that if vim finds your file it will open it in a split window. Simply add the vert keyword before sf if you want a vertical split.

The mappings can (and indeed, should) be made local to buffer with a <buffer> modifier.

You may also want to use this function that lets you to only use one binding for switching:

function! SwitchSourceHeader()
    "update!
    if (expand ("%:t") == expand ("%:t:r") . ".cpp")
        find %:t:r.h
    else
        find %:t:r.cpp
    endif
endfunction

nmap ,s :call SwitchSourceHeader()<CR>

See these help pages for a full description of these built-in features:

This method is also highly configurable. All you have to do is change the 'path' setting when switching to different projects, and modify the corresponding filetype plugin to support other languages.

Single line solution

Pros:

  • Only takes one line in .vimrc, and so is very quick to set up

Cons:

  • Only works if the header and source are in the same directory
  • Does not handle multiple extension styles simultaneously

For programmers that want to switch from foo.cpp to foo.h (or vice versa) on a single key stroke, this might help:

map <F4> :e %:p:s,.h$,.X123X,:s,.cpp$,.h,:s,.X123X$,.cpp,<CR> 

it maps (on F4) the change of the current filename. The endings ".h" and ".cpp" are exchanged (via the magic ending ".X123X").

You could use ".hpp" or ".c" filename endings by changing it in the replacement statements.

A short function

Pros:

  • Still short enough to put into vimrc

Cons:

  • :find can be slow.
  • overwrites path

Put these lines in ~/.vimrc and F2 will flip between .c and .h, .hxx and .cxx, etc. Moreover the .h file need not be in the same dir, it can be found via path variable.

set path=.,,..,../..,./*,./*/*,../*,~/,~/**,/usr/include/*

function! Mosh_Flip_Ext()
    " Switch editing between .c* and .h* files (and more).
    " Since .h file can be in a different dir, call find.
    if match(expand("%"),'\.c') > 0
        let s:flipname = substitute(expand("%"),'\.c\(.*\)','.h\1',"")
        exe ":find " s:flipname
    elseif match(expand("%"),"\\.h") > 0
        let s:flipname = substitute(expand("%"),'\.h\(.*\)','.c\1',"")
        exe ":sp " s:flipname
    endif
endfun

map <F2> :call Mosh_Flip_Ext()<CR>

Comments

You are welcome to add your own comments.



Advertisement