Vim & Python: Making yourself at home

You might look at Python code every day, but what is the lens through which you view code? It's your text editor. This article was written for Python Magazine and was first in a series on Python development environments. Here, we look at how Vim users can boost their productivity by having Vim tell you as much as possible about your program, while you're writing it.

As developers, we spend a majority of our productive day interacting with code. How we interact with this code is often the last thing on our mind. Taking a step back and looking at our daily habits can often yield surprising results in productivity, and is a healthy thing to do once in a while.

The focus of this article will be on getting comfortable with Vim, but learning your tools is a worthwhile pursuit regardless of your editor-of-choice. Furthermore, we will assume you have a fair understanding of Vim. You should know how to move about, edit text, and such. If you don't know how to do this but are interested in Vim, please consult the Vim web page for a tutorial.

Customization Basics

The central place for editing your vim configuration is your .vimrc file, located in your home directory or folder. This serves as the primary file for changes to your vim configuration. The typical syntax for setting a variable is:

  set ruler  " Text after a double-quote is a comment
  set tabstop=4

As you can see, some arguments are binary (on/off) and some take more complicated arguments.

Also in your home folder is a folder called .vim. In it, there are several sub-directories which hold plugins for Vim. The basic directory structure is similar to that shown below.

  .vim
  |____after    # for overrides to system-level vim
  |____autoload # a directory for some plugins
  |____colors   # custom colorthemes
  |____doc      # documentation
  |____ftplugin # custom filetype plugins
  |____indent   # custom indentation overrides
  |____plugin   # plugin installation directory
  |____syntax   # custom syntax coloring files

Note that the directories listed above won't necessarily exist on your machine already. Furthermore, they might not all be necessary for you, depending on which plugins you decide to install down the road.

There are a few options which will make editing python code much easier. To get you started, I've included those below.

  set tabstop=4
  set shiftwidth=4
  set expandtab

The first option, tabstop, tells vim how many spaces a tab should take up. The default is 8, which seems much too wide. (Note, however, that this setting will get you into trouble if you load Python scripts from people whose editors use a mix of tabs and spaces, since, to Python, a tab always equals eight spaces; that is why it is best to never include actual tabs in your own programs!) The shiftwidth option controls the depth of autoindentation, which we'll keep the same width as tabstop. Lastly, expandtab (which doesn't take an argument), converts all tabs to spaces.

Vim also offers extensibility through a language called Vim Script. Many people have made some pretty amazing plugins in it. There are two methods of installing vim plugins: zip files, and vimballs.

To install a vimball, download it to a directory, and open it in vim. From there, type :so % which means to "source" the current file ("%").

  wget -O snippets_emu.vba http://www.vim.org/scripts/download_script.php?src_id=8450
  vim snippets_emu.vba
  :so %

The other method of installing vim plugins are through a zip file. To install the zip file, cd into your .vim folder, and extract it. Things should just go into their right places.

  cd ~/.vim
  wget -O nerd_tree.zip http://www.vim.org/scripts/download_script.php?src_id=10767
  unzip nerd_tree.zip
  rm nerd_tree.zip

To find plugins not discussed in this article, you should head over to http://www.vim.org/ where there are a ton of useful (and some not-so-useful) plugins for your browsing pleasure. Now that we have an understanding of how some things work, let's check out some source code.

Viewing Source Code

Here are some of my default .vimrc settings::

  syntax on
  set list listchars=tab:▷⋅,trail:⋅,nbsp:⋅
  set statusline=%F%m%r%h%w\ [TYPE=%Y\ %{&ff}]\
  \ [%l/%L\ (%p%%)
  filetype plugin indent on
  au FileType py set autoindent
  au FileType py set smartindent
  au FileType py set textwidth=79 " PEP-8 Friendly

If you open a Python file, you'll quickly notice that you lack syntax highlighting. To fix this, type :syntax on. This will tell Vim that you want syntax highlighting. I find it a good idea to keep this on always, so it goes in the .vimrc. I also find it helpful to turn on invisibles. While Vim doesn't expressly have an option for this, its easily fixed with a bit of Unicode. The listchars will turn tabs into large triangles, and trailing spaces and blank lines with spaces into small bullets. Along with visible whitespace, you can turn on rather nice indentation with the above au commands. These are automatically run for a given file type, usually identified by extension. In our case, this is the py extension. This offers a handy way to have different settings for different kinds of file. The indentation commands above do a few complimentary, but different things. An autoindent will indent the next line when you start a new line; smartindent will also indent after things like a colon (for if or for statements) and such.

You can also get a fair amount more metadata about the file your editing with a better statusline. This statusline will tell you the filename, type of file that Vim thinks it is, what sort of line endings are used, as well as your vertical position in the file. If Vim has guessed incorrectly at the type of file you're editing you can easily rectify this with the ft (aka filetype) option. :set ft=python will turn the buffer to Python mode. Now that we have a decent looking single file, lets take a step back and see how Vim can help us within the scope of a larger project.

Browsing Source Code

  " NERD_tree config
  let NERDTreeChDirMode=2
  let NERDTreeIgnore=['\.vim$', '\~$', '\.pyc$', '\.swp$']
  let NERDTreeSortOrder=['^__\.py$', '\/$', '*', '\.swp$',  '\~$']
  let NERDTreeShowBookmarks=1
  map <F3> :NERDTreeToggle<CR>

  " Syntax for multiple tag files are
  " set tags=/my/dir1/tags, /my/dir2/tags
  set tags=tags;$HOME/.vim/tags/

  " TagList Plugin Configuration
  let Tlist_Ctags_Cmd='/usr/local/bin/ctags'
  let Tlist_GainFocus_On_ToggleOpen = 1
  let Tlist_Close_On_Select = 1
  let Tlist_Use_Right_Window = 1
  let Tlist_File_Fold_Auto_Close = 1
  map <F7> :TlistToggle<CR>

  " Viewport Controls
  " ie moving between split panes
  map <silent>,h <C-w>h
  map <silent>,j <C-w>j
  map <silent>,k <C-w>k
  map <silent>,l <C-w>l

One of the biggest parts about editing speed and efficiency is being able to get from one file to another quickly. There are two plugins which do an amazing job at this very task. Check out the above code to see how I have configured these plugins in my own home directory.

NERDTree is a fantastic file browser that slots nicely into vim when you need it, and hides from view when its not in use. It offers the ability to bookmark folders for separating out projects. It is quite reminiscent of TextMate's project drawer, but works just as well without a GUI. In my config, I've bound NERDTree to F3. From the opened pane, you can open files in split view, normal view, or as a preview. There are an array of options available for things such as sorting, ignoring and so on, but you can consult the documentation for a more in-depth look.

Another great plugin for navigating around your source-code is Taglist. This interacts with ctags to provide a class browser of your current code. You need to point it to a ctags binary as well as giving it an idea of where to find your tags files. I have it set to look in the current directory, followed by a tags sub-directory of my .vim folder. I have the pane toggle bound to F7. This setup allows me to have NERDTree on the left with my file list, and TagList open on the right with an overview of my current file. You can press F1 for a list of commands available in that buffer. The most immediately useful will be u which will update the taglist for the current file.

Now that we have a few panes to operate in, we can make some improvements on how we work with them. Instead of the old C-w left, I found it much easier to bind the viewport changing keys to ,left which seems to be a bit easier to type for me.

Writing Source Code

We've gotten a python file looking respectable, and can now easily navigate our project structure. Let's actually improve the speed we get work done. The two tips here work on the principle that the less you have to type, the faster you'll be.

The first plugin is SnippetsEmu. SnippetsEmu operates much like TextMate's bundle system, offering a few shortcuts for a variety of different languages. It helps expand something like super to:

  def {method}(self, *args, **kwargs):
      { put my cursor here when done }
      super({class}, self).{method}(*args, **kwargs)

which is a personal favorite of mine. Once you are inside of a class body, type "super", and press tab, then the substitute text above will suddenly display and the "method" section will be highlighted. As you type, your text gets written into both places. You fill in the class variable, and it will place your cursor in the proper place for editing the function.

Another fantastic feature that Vim offers is its own auto-completion. This can be invoked with Control-n and Control-p after typing a portion of a word. This does a match against the currently open buffers for a string matching the same format. This is surprisingly useful, even with how simple it is. For Python-specific tab completion, there are a few libraries attempting to offer Eclipse or VisualStudio style intellisense. The best of these seems to be Pydiction. It has extensive documentation on the download page, which should get you up and going in no time.

Handy Random Extras

  map ,p :Lodgeit<CR>         " pastes selection / file to paste.pocoo.org
  " VCS Command Configs
  let mapleader = ","

As you can see, a large majority of some of the power of vim comes from its extensive plugin community. On that front, there are a few other helpful plugins which, while they don't necessarily fit anywhere, offer a lot of great situational value.

The first of these is Lodgeit. Lodgeit is a pastebin service run by http://pocoo.org which offers a vim plugin. By highlighting a section of source code and typing, as I have it bound, =,p=, you will paste the contents of the selection to the pastebin web site, and a link will be placed in your clipboard. This is quite helpful for trading snippets of code with coworkers, or when getting help on a particular debugging problem.

From the same folks who wrote NERDTree, NerdCommenter allows for easy commenting of large regions of text. The language support they have for the various commenting features is staggering!

Another great plugin for Vim is VCS Command. This allows you to interact with your source code management tool directly from the editor. The more time you spend in your editor, the fewer context switches you make. This means you're less likely to notice the little email icon when you're alt-tabbing, and you're less likely to get side-tracked by that latest inflammatory article on HackerNews. The more time you spend in your editor, the more time you can spend getting work done.

Lastly, pyflakes is an absolutely essential plugin for Vim. As with any linter, it catches trivial mistakes that, cumulatively, can add up to a sizable amount of time lost. Furthermore, it helps encourage consistency, standards, and clean code.

Getting More Help

While this article should give you a basic understanding of how to get plugins and install them, and which plugins might be useful, there's still quite a bit more to explore, such as writing your own plugin. There are several resources for help. #vim on irc.freenode.org is a pretty excellent resource for Vim-related things. There is also quite extensive documentation built into Vim itself. If you're curious about what a particular option does, type :h <option> - for instance, :h undolevels for more information about what it does and how to configure it.

As programmers, we live in our editors every day. Any time you spend learning more about your tools will be paid ten-fold with productivity gains as you work with them on a daily basis. One great way to see what else you may want in your editor, is to give another editor a shot. Its really hard to know what's out there, until you've seen it yourself. If you'd like to browse through my vim files, you can view them on github.