Using Vim as a multi-language IDE

Last year, I wrote a post about using Vim as a PHP IDE. It turned out to be pretty popular, and I've been updating it despite the fact that I now write considerably more ruby than PHP.

One of the things I love about vim is the level of support for languages and text formats. If it's not supported by vim out of the box, there's a very good chance are that there are several plugins to choose from that will add the desired support.

In this post, I'm going to highlight a few language-agnostic tools that will make your life much easier. The idea is that you will be able to use these tools regardless of which language you're using, but they'll give you many of the features that you would expect from a graphical IDE.

I should probably mention that this is my opinion. There are lots of plugins that do similar jobs to those that I'm going to mention, but I'm not interested in making this an exhaustive list; these are my recommendations based on experience, and they may well change as time goes on.

  1. Syntax checking/linting

  2. File navigation

  3. Keyword searching

  4. Autocompletion

  5. Tags

  6. "Project management"

Just a quick note: this tutorial assumes that you have a working knowledge of Vim and know how to configure it on at least a basic level (i.e. you know where your vimrc file is, and you know how to install vim scripts). It also assumes that you're running at least version 7.0 of Vim.

1. Syntax checking/linting

For general syntax checking, by far the best plugin I've come across is Syntastic. This provides support for dozens of languages. It automatically detects the language of your current buffer, and runs the appropriate linter to check the syntax and display any errors. It does this when you first open the file and every time you save. It uses signs (markings in the margin) and the location list to show the errors. Here's an example of what it looks like for a ruby script with a syntax error:

A vim buffer showing errors from Syntastic checking the fileThe errors are listed below the buffer in the location list, and signs mark where the error appears in the file.

The fact that this covers so many languages, and works so seamlessly, means that I consider this plugin to be practically essential.

2. File navigagtion

In my experience, the best way for navigating through large collections of files is with Ctrl-P - it's enough to make Eclipse users jealous. I previously used the similar and better-known plugin Command-T, but that requires more setup (including some compilation). Ctrl-P has been written in pure Vimscript, which makes installation much quicker and simpler. The plugin allows you to quickly filter through files, buffers and tags by typing any part of the file name. As you type, you see the matching files change in a window at the bottom of the screen. When you see the file you want, you can just move up and down and select it. Here's a screenshot of the plugin in action:

A vim window showing the ctrl-p plugin in actionAs you type, the list of files in the window above will reduce

The nice thing is that it's pretty forgiving: I can misspell the file I'm looking for, but it will often still appear in the results. Plus, it's lightning quick; first time round, it will spend a few seconds caching the list of files, but afterwards it will zip through the list of files as you type.

When I'm working on a project I like to change the current working directory in Vim. Therefore, when I run Ctrl-P, I run it from the current working directory so that it only searches the project. However, it has some intelligent features built in so that it will try and work out the project directory - e.g. it can search directories above the current file until it comes across something like a .git folder. It's very customisable, so check out the readme to find out how to best configure it for your setup. For instance, I have different invocations mapped to different key combinations, so I can search through files or open buffers.

3. Keyword searching

Vim comes with the grep command, which is very handy for searching your project for occurrences of a particular string. It's used like this:

:grep -r "search string" directory/

That command will recursively search all files in directory for "search string" - use :help grep to get more information. It then puts all the results in the quickfix window (:help quickfix), which will allow you to jump backwards and forwards between the occurrences.

As you may well know, the grep command is a vim implementation of a very prolific unix tool. I used vim's grep for a while, until I was introduced to Ag.vim. This is a vim plugin for [Ag](, also known as "the silver surfer". It's like ack, which is like grep. Confused? All you need to know is that Ag is very quick, and the vim plugin is a drop-in replacement for vim's grep. It works in the same way as the grep command, without the need for the -rmodifier (as it searches recursively by default).

:Ag "search string" directory/

Ag isn't essential, as speed is the main benefit you get over grep. But if you find yourself using the grep command on a regular basis then I'd consider it to be worthy of a place in your vim setup.

4. Autocompletion

When I first moved to Vim, I spent a while trying to set up tag-based autocompletion. Eventually I realised that it was often more obtrusive than it was helpful, and that the delay created by searching through the tag list gradually became more and more annoying. What I do find useful is local completion, which gives you completion based on words in the current buffer, or all open buffers. This is built into modern versions of Vim; start typing a word, then, still in insert mode, type one of:

# Local file completion
# Open buffer completion

This works well, but it isn't a particularly friendly shortcut. It's a little bit Emacsy. I like having completion triggered by tab, which is extremely easy using the SuperTab plugin. Install it, and then add the following variable to your vimrc:

let g:SuperTabDefaultCompletionType = ""

Modify as desired. You can then hit tab in the middle of typing a word in insert mode, and it will bring up a list of suggestions.

5. Tags

Vim can use tag files generated by _ctags _to allow for quick, keyword-based navigation. For instance, placing your cursor over a class name and typing <C-]> will take you to wherever that class is defined. This works well, but managing tag files can be a pain: tag files need to be kept in sync with your code, meaning regular manual updates.

ctags is a command line tool that will build an index of keywords from a list of files. The output tag files are then plugged into Vim. To build a tag file from Ruby code, you might run something like:

ctags-exuberant -f ruby.tags --languages=Ruby -R

I created a plugin to do very simple tag file management, called taggatron. It watches for file saving, and automatically runs ctags commands based on the type of the updated file. You can specify different options for ctags depending on the language, as you may well want to have different rules for your JavaScript than for your Ruby or Python code. An example configuration might look like this:

let g:tagcommands = {
\ "ruby" : {"tagfile":".ruby.tags","args":"-R"},
\ "javascript" : {"tagfile":".js.tags","args":"-R"}

In this case, Ruby and JavaScript tags are managed independently, and are updated automatically when corresponding source files are updated.

"Project management"

Almost all developers will work on more than one project, and managing projects is built in to all graphical IDEs. I've used a couple of project management plugins for Vim in the past, but I felt that they were all overcomplicating the problem.

Since Vim is so scriptable, all you need is a way of managing multiple miniature vimrcs for each project that you work on. For instance, one project may require spaces instead of tabs for indentation. Another may have a different set of tag file options. One thing I like to do when I'm working on each project is change to the root directory.

Like a broken record, again I'm mentioning one of my own projects. I created vim-sauce as a way of managing lots of small vimrcs, for quick switching between projects. It creates a directory in the user's home path, where all the sauces are kept. You then use commands like SuauceNew, SauceEdit, SauceCopy, etc. to manage these files. Finally, to switch to a particular sauce, run:

:Sauce myproject

Here's an example of one of my sauces.

cd /home/jon/www/loggable

Spaces 2

" Tags for project
let g:tagcommands = {"ruby" : {"tagfile":".ruby.tags","args":"-R"}}

SetTags .ruby.tags

This is why the title of this section is in quotes. It's not really project management, but it's very unobtrusive. It allows you to write pure vimscript, with no magic, which was my aim for the project.

And that's about it

← Previous post: Understanding ssh-agent and ssh-add Next post: Major updates →
comments powered by Disqus