JNRowe

vim configuration snippets

Small snippets of my disturbingly large vim configuration

To quote the manual:

vim stands for Vi IMproved. It used to be Vi IMitation, but there are so many improvements that a name change was appropriate. vim is a text editor which includes almost all the commands from the Unix program "Vi" and a lot of new ones. It is very useful for editing programs and other plain text.

What it fails to mention in its own intro is how extensible it is. The functionality in the basic installation is already beyond most editors and IDEs, but with the addition of some simple configuration options and a few plugins it is almost unsurpassed.

Basics

vim's configuration files, plugins, filetype definitions all use the same language; vim script for want for want of a better term. And as such, you can use arbitrarily complex constructs in your configuration files if you so desire.

The enchanting quality is that once the language is understood all of vim's extensibility is open to you. The unappealing quality it brings to the table is that we need to understand a significant chunk of the language for even basic configuration tasks. The documentation as always in vim is absolutely fantastic, and the script language documentation can be found with :help script.

Introductions aside let's move on to the meat of the topic.

Vim server

Having been an emacs user for over 15 years I've come to depend on the client-server features, but luckily vim now includes similar support since version 6. For people unfamiliar with the emacs client-server mode it simply allows you to send commands to an already running instance in much the same way you probably do with your web browser to open new tabs or raise its window. Combined with vim 7's new tabbed interface it is an extremely powerful and comfortable way to manage a long-lived editing session.

Of course, the single biggest reason to use it is the tremendous difference it makes when you wish to start editing a file, instead of waiting for a new instance to start up and allowing it to clutter your display, the file is opened in the already running gvim window and the window is optionally raised. Other advantages include being able to use the :vimgrep and other multi-buffer commands on all open files, something that wouldn't be possible if you were using separate windows for each file.

I realise you could always open files in an already running vim instance, but this makes it a whole lot easier and you can also send complex editing commands to running servers too. With the client-server feature it has become incredibly simple to script vim's behaviour from external programs.

I alias gvim to gvim --servername ${HOSTNAME} --remote-tab in my bash startup files, so every time I call gvim I am connected to the already running server. If a server isn't already running with the specified name then a new one is started, so it is reasonably safe to use. The only caveat I have so far found is with the --remote-tab option, you must specify a filename of some kind or an error will be displayed. To get around this you can always just use "" for an empty file. I don't find this to be an issue in practise because I always specify a name when beginning a new file, for the reasons described below.

Note

As I'm sure you're aware, if you define the gvim alias it is still possible to call gvim without the alias taking effect, simply use the path to the binary and the alias won't be expanded. In my case that would be /usr/bin/gvim.

viminfo

The viminfo option controls how much state vim saves between sessions, by default it it is set to the rather cryptic value of '20,<50,s10,h. In fact I think this is probably the most cryptic setting vim has. To break it down it means:

Setting Meaning
'20 Remember the marks used in the past 20 edited files
<50 Remember 50 lines of each register between sessions
s10 Save no more than 10 kB of data from each register
h Don't highlight the last search when starting a new session

My personal viminfo setting is !,'1000,<1000,h,n~/.vim/viminfo which beyond variations of the values explained above tells vim:

Setting Meaning
! Save global variables, those whose names are all uppercase
n~~/.vim/viminfo Store the file as ~.vim/viminfo

I prefer to keep the viminfo file in the ~/.vim directory because it removes some clutter from my home directory. One should note that the n option must be last, which allows the filename to contain any special characters which would normally define another flag for the setting.

I realise the number of saved marks and register lines in my viminfo settings may seem excessive but startup time is not noticeably increased, and the file still only consumes a few hundred kilobytes of space under most circumstances. The reason I set the the values so high is that it catches pretty much every edit I make for a long period of time, when the costs of using it are so low I'd rather maintain data I don't need than lose one piece I may want.

wildmenu

The wildmenu option causes vim to display a list of options when a value is ambiguous, such as when completing the name of a file or issuing a command. It makes command line completion work in a similar way to how keyword completion works whilst editing. There are various ways to affect the completion style, see :help wildmode for more information, but the default seems to be the best option for me.

Once you start using wildmenu a lot it quickly becomes clear that you are having to cycle through a lot of files you would never wish to complete, and to stop that you can add values to wildignore. Any match to the shell-style glob patterns in the comma separated list of values will be skipped when displaying completions. The example from my configuration file is:

set wildignore+=*.log,*.pdf,*.swp,*.o,*.py[co],*~

The above tells vim to ignore its own swap files, backup files and a variety of generated output files which you wouldn't be likely to edit. If you do wish to edit a file that matches one of the values in wildignore you can just manually type its name.

Plain text

There are some simple options that are incredibly useful when editing plain text with vim. The first is textwidth which tells vim how long you wish lines to be, by default it is set to 0 which forces you to manually break lines. If you set it to 80, :set textwidth=80, vim will automatically wrap lines when when you reach 80 characters.

And since version 7, vim has supported spell checking without any external tools or scripts, to enable it just use set spell. It will highlight any words that are misspelt, and also a few typographical abnormalities such as failing to capitalise the first word in a sentence or doubled words.

The spell checking system is smart enough to allow you to specify more than one dictionary too, which is great when you have to write in different styles. For example a good friend of mine writes user manuals for desktop software and she keeps technical words in their own specific dictionary, that way she can use spelllang=en_gb,tech when writing internal stuff and spelllang=en_gb when writing documents that shouldn't contain terms such as "MANET". Words from the technical dictionary show up as spelling errors allowing her to rewrite it as "magical invisible monkey network" or some such.

Abbreviations

One of the most immediately useful vim features is its support for abbreviations(:help abbreviations). I personally use it for inputting all manner of abbreviations and acronyms, so much so in fact that I maintain my definitions in their own file to save cluttering up the main ~/.vimrc. My abbreviations file is kept in ~/.vim/abbr, and is read by:

if filereadable(expand("~/.vim/abbr"))
    source ~/.vim/abbr
endif

We first check the file exists and is readable, so we can use the same configuration file on machines accounts that don't have an ~/.vim/abbr file. Note that the filereadable function doesn't expand the tilde in the filename unlike the source command, and we must explicitly do so with the expand function. The actual abbr file entries such as the following:

iab _AR alpha release
iab _WD working draft
iab _site http://www.jnrowe.ukfsn.org/
iab _sitemail website@jnrowe.ukfsn.org
iab _BS build system
iab _TS target system
iab OtF of the form

So when I type _AR it is expanded to alpha release. I tend to use iab because I'm only interested in using the abbreviations in insert mode. As you can see most of the abbreviation keywords begin with an underscore to stop them clashing with other words I type, but OtF doesn't as it very unlikely that I would be typing OtF as a word in any context. That being said if I did want to type OtF without it being expanded, such as in this sentence, I can just type OtF<C-v> to make vim skip it.

formatoptions

The other option I can't live without is formatoptions. vim is incredibly flexible in how it formats the text you're typing, and formatoptions is how you configure that flexibility. My favourite addition to the default is the 2 flag, which tells vim to take its formatting hints from the second line in a paragraph. Apparently, it is a product of my age and upbringing that I prefer the first line of a paragraph to have a small indent and thanks to 2 vim is happy to work that way too.

The second flag to formatoptions is l, as sometimes it is necessary to write extraordinarily long lines and this flag stops vim automatically reformatting lines if they were already over the normal line length when you entered insert mode. It comes in particularly handy when writing code snippets or other such text where wrapping can break the text's meaning, and stops you from continually having to call :j to rejoin lines that have been split by automatic wrapping.

reStructuredText

I write a lot of text in reST format, even this page is written in a mostly compatible dialect of reST using a parser I wrote for erbium. As a rule I write documentation for projects in reST, for processing by docutils or the now standalone RubPage parser from erbium, unless there is a compelling reason to use another format such as there already being a lot of existing documentation in another format.

vim comes configured with support for reST out of the box, it features syntax highlighting and reST specific indentation settings. It also includes a compiler plugin for highlighting warnings and errors in the docutils converter output.

The compiler plugin doesn't set the value of makeprg, so by default when editing reST format text calls to :make execute the system make command. This is fine if you've included a Makefile in your current directory, but if not you have to set the value of makeprg yourself. I personally use the following snippet to parse reST text using docutils' rst2html.py when I call :make:

autocmd FileType rst setlocal makeprg=rst2html.py\ %\ /dev/null

All it does is call the rst2html.py script with the current file(%) as input and send output to /dev/null. rst2html.py, and the other docutils renderers, emit log messages on stderr so vim still catches them while ignoring the generated output.

As with all calls to :make I like vim to open a QuickFix window if there are any messages. To make vim open a QuickFix window if it encounters text the compiler plugin consdiers important, and add some useful keybindings for handling the QuickFix window, add the following to your ~/.vimrc:

autocmd QuickFixCmdPost * belowright cwindow 5
nmap <Leader>qfc :cclose<CR>
nmap <Leader>qfo :belowright copen 5<CR>
nmap <Leader>qn :cnext<CR>

The QuickFixCmdPost setting above tells vim to open a QuickFix window 5 lines high below the current window if any error messages have been caught. The <Leader>qfc binding closes the window, and <Leader>qfo opens the window again 5 lines high. Finally the <Leader>qn binding is for quickly moving between errors in the buffer. Both of the window opening commands open windows on the right if vertical splits are being used.

Mail

I've used vim as my editor of choice with mutt for many years now, for nearly three years it was the only thing I used vim for. It is about the closest I come to writing any significant chunks of freeform plain text with vim. Even then vim enables some options specifically for writing mail, firstly it sets the line length to a reasonable value and makes reformatting honour prefixes(such as the standard > quote character). It also sets up a nice macro to allow you to add an extra level of quoting to a message with <LocalLeader>q, where like <Leader> <LocalLeader> is \ by default.

I also use Hugo Haas' uri-ref plugin, specifically with mail but also some other filetypes, to manage a list of references to avoid having to paste 120 character URIs in to the body of a mail. Although the plugin is named uri-ref, it is basically a simple way to manage any numbered references and I often use it for footnotes too.

I don't use email signatures, so I need to tell uri-ref to just skip to the bottom of the mail and notdisplay an error when it can't find the email separator. To do this I just comment out the pattern match ?^-- $ in the plugin, as it already jumps to the end of file with the G command on the previous line. There are a lot of better ways to manage this, but sometimes the simplest option is the best.

I've been using lbdb for querying address data in mutt for a few years now, and it is really nice to integrate it in to vim too. As often seems to be the case with vim somebody has already done the hard work and you can simply download the lbdbq script. Once installed you can query the database for terms on a header line by typing <LocalLeader>lb. It is a great addition to using vim as your mail editor, all you need to do is set mutt's edit_hdrs command so that mail headers are available in your editing session.

Source code

Editing code is where, in my opinion, vim really begins to shine, but it builds on the features I mentioned above as I use a lot of setup I've already mentioned in code comments and documentation. I used to be a heavy xemacs user, but over the past year or so I've been using vim almost exclusively for coding. Initially it was because I wanted more integration with my desktop, but now I've come to realise that most of the features xemacs has that vim doesn't are entirely superfluous. And with a vim version that was built with Ruby or Python support adding any features you miss is very simple, and lot less hassle than playing with lisp.

Indentation

The first options you're likely to want to enable are autoindent, and also smartindent or cindent. autoindent does what you expect, simply indenting each line in relation to the previous line's indentation. smartindent causes lines following braces or language specific keywords to be treated specially, either further indenting or reducing the indentation. I personally find cindent to be a little too complex for my needs and smartindent already works well enough, but you may wish to try it out if you really want to customise how your code is indented.

showmatch

Another favourite of mine is showmatch which tells vim to highlight the matching bracket when the cursor is over a bracket, and quickly jump to and highlight the matching bracket when inserting a closing bracket. This option also causes vim to beep, or optionally flash the screen if visualbell is set, when you insert a closing bracket without an opening bracket which is a great sanity check when your code involves deeply nested statements.

Although I mentioned only brackets in the previous paragraph you can change the behaviour to match any character pairs by changing the matchpairs variable. By default it matches (), {} and [] but you may wish to add other pairs. For example, in HTML and XML files I like to have < and > matches highlighted and to do this I just added the following to my ~/.vimrc:

autocmd FileType xml,html setlocal matchpairs+=<:>

setlocal is used in this instance because by default it seems to be a session wide setting, regardless of what the documentation says on the matter, and having > without a < treated as an error causes an enormous number of false errors when you're coding.

matchit

The matchit plugin is related to the match support discussed above, not only does vim display matching pairs but it allows you to jump between them with the % key. Like so many of the motion keys in vim once learned they are incredibly useful, and make moving about in your code much faster. matchit increases the functionality of these navigation techniques by an enormous amount.

The script is stored in vim's macros directory and can be enabled with the following snippet in your ~/.vimrc:

runtime macros/matchit.vim

Now not only can you move between matching brackets, or any other defined pairs in your matchpairs declaration, you can also jump about in matched code blocks. By default matchit will let you jump in and around many chunks of code, for example switch statements or #ifdef blocks, but it can also be extended with your own match patterns.

You can even define your own pairs of matches for pretty much any language imaginable, as long as you can define a RegExp that expresses the pairing. There is ample help in the matchit documentation, but in every case I've wanted to define my own matches a quick search on the vim website has yielded a pre-made solution.

autoloadTemplate

As I mentioned above I always name new files when I begin them, and for one simple reason; it makes using templates much simpler. I use the autoloadTemplate script which is a very simplistic solution to the problem, it merely allows you to use a static template file for new files of a given filetype.

I mentioned in a year in python that I defined Python's -tt command line option, which forces a mixing of tabs and spaces to be a fatal error, in my standard template. I actually define a few things in that template, a cut down version of it follows:

#! /usr/bin/python -tt
# vim: set sw=4 sts=4 et tw=80 fileencoding=utf-8:

if __name__ == '__main__':
    import doctest
    import sys
    sys.exit(doctest.testmod(optionflags=doctest.REPORT_UDIFF)[0])

I've skipped the license boilerplate and standard Python metadata, but it shows the basic point well enough. I always set -tt, even though it can cause failure when you import an external module with broken indentation, because it is the Right Thing. I also define a vim modeline that sets the indentation patterns to something sane for writing Python, and it tells vim and Python that my files should be always be UTF-8 encoded.

The final line which exists in my Python template runs the file through the doctest module's testmod function when executed directly, and exits with the number of failed tests. And more importantly from a readability point of view doctest errors are always displayed in unified diff format.

I actually have 15 different filetypes supported in my ~/.vim/templates directory, and it decreases the startup time for writing a new file by a significant chunk. The more verbose a language is, or the more boilerplate that is needed, the greater the advantage.

There is also one other great feature to using templates in this way, and that is updating specific items. I ran a simple sed expression back in January to update the copyright year to 2008 in new files, and in August of last year I only had to change the files in one place to reflect the fact I wanted new GPL-licensed files to use version 3 of the license.

QuickFix

I've already mentioned the QuickFix feature earlier, but it is that useful it deservers its own heading. vim based its QuickFix feature on a feature from the Amiga C compiler suite Manx C, which was the first C compiler I ever used back when I was still at high school. It is a feature that makes such obvious sense it seems funny that it isn't always enabled, and at the top of everybody's expectations list for an editor.

The basic premise is that when running :make vim should parse the output and if it spots any errors their positions should be remembered, so that the user can jump through them fixing the problems the compiler has found.

It is very important that you enable the autowrite setting if you're going to be making use of QuickFix, without that you have to manually save the file before calling :make (or for that matter many other commands) or you'll be building from stale sources.

Although designed with parsing compiler output in mind you can actually use it with any output that includes a line number and message. You could for example have vim display a QuickFix window for grep -l output or lint tools, as long as they either display line numbers or can be coerced in to doing so.

For example, I like to run a lot of my Python code through pylint. I don't always agree with its warnings, for example losing points for using filter and map annoys me, but it does spot some genuine problems in my code. It is really very easy to make the QuickFix feature work with the pylint command. In my ~/.vim/compiler directory I have a file named pylint.vim, and following the theme throughout this document it contains a pre-made pylint compiler script.

Conclusion

This text has actually grown a lot longer than I had originally planned, but there a lot of cool features in vim that I wanted to mention. vim is a ferociously powerful editor, one which is either capable of or can be extended to work like almost any other editor given the inclination. For a true example of its customisability look no further than the cream project which makes vim behave like a Windows-type editor, it isn't for me as I enjoy vim's modal editing model but it does show just flexible it is.

I'm always in interested in ways to streamline my editing experience, and if you know of a quicker or easier ways to accomplish something I've mentioned here please drop me a mail.

Return to Top