Vim Scripting through Python


The Vi editor, though several decades old now, is still one of the most popular tools for programmers, especially those using Unix-family systems (Linux, Mac). It includes the basics such as programming language-specific syntax coloring, autoindent, autocomplete, interface with compilers and debuggers and so on. In addition, numerous plugins are available; for example, if one is editing Python code, one can issue a command to move the cursor to the beginning or end of the current block. GVim, a GUI version of Vim, is also popular.

I personally use Vim because I want to use the same editor no matter whether I am writing code, writing a research paper, writing e-mail etc. I've developed my own abbreviations and macros to make typing easier for myself. In my ~/.vimrc Vim startup file, for example, I have a line

abb for example for example

so that whenever I type 'frre', Vim automatially expands it to "for example". I'm writing this Web page using Vim, and I wrote the Python examples using that editor too.

Needed Background

It is assumed that the reader knows very basic Vim operations, such as in this brief tutorial. In particular you must know that Vim has insert (adding text) and noninsert (deleting text, cursor movement, file saving etc.) modes. In noninsert mode, the : key is used to get into special command mode, such as to invoke Python.

Scripting in Vim

Vim is extraordinarily configurable, using its own built-in scripting language, Vimscript. However, Vimscript is rather tedious and confining. Fortunately, Vim is actually programmable in Python!

The Basics

Extended Example

This example is from the excellent tutorial by soulseekah. With this, if you are using Vim to edit a file that contains IP addresses, you simply type '.IP' and it will inform you the country in which that address is located.

" from

python << en

import vim, urllib

def getCountryFromIP( ip ):
  # use the minimal API
  return urllib.urlopen(''+ip).read()

def getWordUnderCursor():
  return vim.eval("expand('')")
def lookupIPUnderCursor():
  ip = getWordUnderCursor()
  print "Looking up " + ip + "..."
  country = getCountryFromIP( ip )
  vim.command( "redraw" ) # discard previous messages
  print "Country: " + country

nmap  .IP :python lookupIPUnderCursor()

Things should be fairly clear from context (don't worry if you are not familiar with the Python urllib module), but a few items need explanation:

Example of Interface to Vim's Buffers

Create a file, y, with exactly the following famous contents:

How much wood,
Would a woodchuck chunk,
If a woodchuck 
Could chuck

Now, with this file open in Vim, type

:py b = vim.buffers[1]

Vim allows one to have several buffers at once, i.e. to edit several files at once. A command like

:b 2

means "switch to buffer 2." (In GVim, the GUI version of Vim, this is done by mouse.) The above Python command copies the contents of buffer 1 to the Python variable b. Now b is a Python list (i.e. array), with character-string elements, one element per line of y.

Now type

:py print b[3]

i.e. print the fourth line of the file,

Could chuck  

(Remember, Python array indices start at 0, not 1.)

Finally, type

:py b[3] = ''

and behold!

But Vim has infinite-undo capability, invoked with the u command (ctrl-r for re-do). You can do that through Python too:

:py vim.command('u')

It would be pointless to do this with Python in this little example, but the point is that one can do things like this programmatically -- and using a nice language, Python, to do it.