22 August 2015

Self Documenting Vim Key Mappings

When configuring Vim with plugins, one of the common things that I like to do is to dedicate a letter to a single Vim plugin (or a group of similar tasks).

An example of this is below where I have some key mappings for @tpope’s Fugitive plugin:

" Fugitive mapping
nmap <leader>gb :Gblame<cr>
nmap <leader>gc :Gcommit<cr>
nmap <leader>gd :Gdiff<cr>
nmap <leader>gg :Ggrep
nmap <leader>gl :Glog<cr>
nmap <leader>gp :Git pull<cr>
nmap <leader>gP :Git push<cr>
nmap <leader>gs :Gstatus<cr>
nmap <leader>gw :Gbrowse<cr>

The Problem

Most of the mappings and plugin functions are pretty straight forward and they aren’t hard to remember. Unfortunately I have some other key mappings that are a bit harder to remember.

Take for example these cscope mappings:

nmap <C-\>s :cs find s <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>g :cs find g <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>c :cs find c <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>t :cs find t <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>e :cs find e <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <C-\>i :cs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
nmap <C-\>d :cs find d <C-R>=expand("<cword>")<CR><CR>

What the hell do all of these mean? I took these from cscope’s Vim mappings and unless I’m using them very, very regularly, it is going to take some time to learn them all.

At first I wanted to make a plugin that would be able to help with this but I was able to come up with a simpler solution even if it is a bit hacky.

Solution

The first part is just to be able to view all of these similar mappings easily. The best way I found to do this is just to run :map binding_start where you substitute in what you want to look up.

In the case of Fugitive, we just run :map <leader>g. The output looks like the following:

As you can see, the output clearly shows the key mapping as well as the command that is ran. For plugins like these, it is very easy to use it as a reference for when you forget a mapping.

Easy Access

The next part of the solution is to make that command easier to run. I like to map it to ? and match it with the previous mappings.

This means the mapping for Fugitive becomes:

" Fugitive reference
nmap <leader>g? :map <leader>g<cr>

Self Documenting

Now what can we do about those cryptic mappings that don’t make a lot of sense like the cscope example?

Well since nmap just runs a set of commands. We could just put some superfluous text that won’t affect the mapping yet show up when :map binding is ran.

I gave it a try and it turns out it works pretty well. It makes the command a bit messier (this can be tidied up by using whitespace) but this is what it looks like:

nmap <C-\>c :ec 'Find all calls to function' <bar> cs find c <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>d :ec 'Find functions that call this function' <bar> cs find d <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>e :ec 'egrep search for the word under cursor' <bar> cs find e <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>f :ec 'Open filename under cursor' <bar> cs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <C-\>g :ec 'Find all global definitions' <bar> cs find g <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>i :ec 'Find files that include the filename' <bar> cs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
nmap <C-\>s :ec 'Find all references' <bar> cs find s <C-R>=expand("<cword>")<CR><CR>
nmap <C-\>t :ec 'Find all instances to text' <bar> cs find t <C-R>=expand("<cword>")<CR><CR>

All we do is just echo out what the mapping actually does in English. Then by using <bar>, it tells Vim to run the commands together.

The end result is below:

Then the mapping to be able to run this command quickly is:

" Cscope reference
nmap <C-\>? :map <C-\><cr>

Conclusion

That’s it! I have a few other examples of this in my .vimrc, be sure to give it a look to see other examples.

Hopefully you get some use out of this. It has made it a lot easier for me to remember some of my more arcane key mappings.

Also, if there’s a better way to do it, feel free to get in contact with me on Twitter.

You're awesome for reading this. Follow me on Twitter.