Custom alternative search path for a.vim

If you’re a C++ developer, you’ll spend a lot of time toggling back and forth between your header (.h) files and the corresponding implementation (.cpp) files. In object-oriented programming, classes will typically map one-to-one with the files — Widget objects will typically be split into Widget.h holding declarations and Widget.cpp holding the actual implementations. On the other hand, when you write templated code, it needs to go in the header file. So although the code is split up between .h and .cpp, they really should be viewed as a single unit. Typically, I’ll be coding in vim with multiple tabs, each tab holding a .h/.cpp pair split like so:

alternateHeaderImpl

Opening files can be a pain, especially when your code is tucked away in nested directory structures. You potentially waste a lot of time typing in the filename you want to open. It’s not so bad if you keep your .h and .cpp files together. In this case, you can use the a.vim (version 2.18 at the time of this writing) plugin. Open up the header file. Then, a simple :AV will open up the corresponding .cpp file in a new split pane window.

It turns out a.vim searches a handful of locations relative to the file from which you are toggling for the corresponding alternate file. For example, I’m in Widget.h, and to toggle to the .cpp file, a.vim will look in the current directory as well as ../src (it’s typical for some projects that build libraries to have separate src and include directories).

If your project’s directory structure is a little more complicated (as in the screenshot above where you have to go between src/CGAL_Qt4 and include/CGAL/Qt), you can add a new relative path to search for the alternate file. Put the following in either your user .vimrc or a project-specific .vimrc:

let g:alternateSearchPath = 'sfr:../../../src/CGAL_Qt4,sfr:../../include/CGAL/Qt'

Note that the search paths start with sfr: and are comma-separated.

Actually, setting your own g:alternateSearchPath will blow away the defaults, but you can patch a.vim to just append to the default search paths in a way you usually do with the PATH variable:

--- a.vim	2013-12-23 13:10:42.458540027 -0800
+++ a.vim.new	2013-12-23 13:10:59.270540049 -0800
@@ -108,6 +108,8 @@
 " a path in their [._]vimrc. 
 if (!exists('g:alternateSearchPath'))
   let g:alternateSearchPath = 'sfr:../source,sfr:../src,sfr:../include,sfr:../inc'
+else
+  let g:alternateSearchPath = g:alternateSearchPath . 'sfr:../source,sfr:../src,sfr:../include,sfr:../inc'
 endif
 
 " If this variable is true then a.vim will not alternate to a file/buffer which

Note the dot operator in this vim configuration language is used for string concatenation.

Vim sessions and map leader

So a common use case when you’re hacking away at a project in an IDE is that you’ve got several files open in tabs in different locations. You can have this using Vim by opening tabs or split window views, and it’s really nice especially when you’ve got full 1080p worth of screen space to exploit. The problem is when you exit Vim, you have to close all your tabs and you lose all of your context, especially when you put the project away for a little while, it can be annoying to open up all the files. There’s a simple fix for that, and it’s the mksession command.

Just running :mksession in Vim will create a snapshot of your tab and window layout etc. and save it in a session file. You can check the help on the command for the exact details. Here’s a convenient mapping that lets me hit ,wq and have all files written and tabs saved in a session file.

let mapleader=","
:map <leader>wq :wa:mksession!:qa
:map <leader>ls :source Session.vim

So my map leader is the comma. Hitting that puts Vim in a mode where if you complete one of the map rules, the corresponding command will be executed.

The first command executes three commands. First, it writes all files that are open. Then it creates a session file into Session.vim in the current working directory. The exclamation mark means overwrite Session.vim if it exists already. Last, it exits out of Vim by closing all open tabs.

The second command sets up Vim from the Session.vim in the current working directory. You run this the very first thing you do when you open Vim in the directory where your work is at, and your workspace is restored to exactly the way you left it.

I guess having the map leader is what makes this effective because it opens up a whole new range of keystrokes for defining new mappings. Some other ideas: toggle paste mode when pasting from the system clipboard. I always have to type :set paste and :set nopaste whenever I need to bring stuff into Vim through the clipboard without having the indentation go haywire, but you now I’ve got this in my rc file:

set pastetoggle=pp

Any other ideas people have? Did you already know about this? I’m constantly learning new stuff about Vim – that is, whenever I’m not just using it to do work and actually poking about the documentation and configuration.

File-specific vim configurations

vim amazes me with its ability to highlight the syntax of so many languages, but I’d been stuck with a single configuration for all file types for the longest time.  Actually, .vimrc can do much more for you.

For example, I have a blanket configuration for inserting 4 spaces for tabs in any file I type, because tabs are evil:

set shiftwidth=4 softtabstop=4 expandtab

But this is a pain when editing Makefiles, where tabs are a necessity for build rules.  You end up entering explicit tabs with <CTRL+V> <TAB>, which is tedious.  Instead, you can make vim know to use real tabs in Makefiles:

autocmd BufEnter Makefile set sw=8 sts=0 noet

Another example is for creating html files. It’d be nice to have a skeleton file that includes a strict doctype and the proper content type all ready to go.   Also, nesting can get real deep real quick so an adjusted shift width would be nice.  This does the trick:

autocmd BufNewFile *.html 0r /path/to/your/template.html
autocmd BufEnter *.html set sw=2 sts=2 et

Basically, creating new html files will source the template html file, and editing any html file will adjust the indent size to 2 spaces to save on horizontal space.

There are lots of different hooks where you can make use of autocmd. Type :help Buf and hit <CTRL+D> to see a lot more buffer-related hooks.

vim modeline

Sometimes when I peek at source code, I see some headers that give some meta-information about the file eg. a revision control header with a date and ID or maybe a line like this:


# vim: ts=2:sw=2:sts=2

I recognize it immediately as settings for handling tabs in the vim editor, and I thought that it was a nice indicator of what the author of the file used when writing up the file. Actually, these modelines as they’re called are meant to be automatically picked up and used by vim. Add the following to .vimrc:


set modeline
set modelines=5

And when you open a file with the modeline, vim will take and apply those settings.

In the documentation, the modeline setting is supposedly on by default, but I found that I had to explicitly set modeline in .vimrc for modelines to be recognized. The modelines option was already set to 5 by default, though.