Petro Verkhogliad @ Experiment Room 4

Working with Vim and IPython

written by Petro, on Oct 4, 2009 9:03:00 PM.

Note: the text below is not for the fainthearted. Setting up Vim to communicate with IPython is currently not very straightforward. The situation will improve soon.

When I write Python code I tend to use IPython quite a bit to test and experiment. Currently this means quite a bit of reloading and writing test code in the IPython shell. I’ve always been a little jealous of the Emacs folks for being able to communicate with the Python shell with ease. Vim has a different philosophy. We use the editor to edit stuff and the shell to run it. With that in mind, one can set up Vim to talk to IPython.

There are several steps for this:

  1. Ensure that Vim is compiled with +python
  2. Get the code that enables communication with IPython
  3. Write code to send code from Vim to the server
Note: this assumes that you have Python, IPython and Twisted installed.

1. Ensure that vim is compiled with +python

Open your favorite version of Vim and do
1
:version

In there look for “+python”. If it is not there, you need to somehow get a version that has “+python”. It is also important to check which version of Python your Vim was compiled against. For this, execute the following command in vim:

1
:python import sys; print sys.version
The output should be the same as your primary version of Python. For example, I am on OS X 10.5.8. By default it ships with Apple Python 2.5. I prefer to use Python 2.6 from MacPorts. Because of this I had to build a version of Macvim from source that pointed to my installation of Python 2.6. This deserves its own post.

2. Getting the code for communicating with IPython

Matt Foster has written a plugin for Textmate called ipythontm-bundle. This Textmate bundle uses the ipy_textmateserver.py to create a Twisted server to which stuff is sent for evaluation from Vim.

This file is can be downloaded from the textmate-server branch of IPython. For Vim we only need this file. Why only this file will be explained at the end of this post. Once the file is downloaded put it in your IPython/Extensions directory. For me this directory is:

1
/opt/local/Library/Frameworks/Python.framework/Versions/Current/lib/python2.6/site-packages/IPython/Extensions

3. The Vim side of life

At the moment, Vim has no idea that there will be a server running. Therefore, we have to write a plugin. The following (very very simple) code server as said plugin.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import vim
import socket

def runner(content):
    s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    try:
        # make sure to chage the directory here
        s.connect("/YOUR/HOME/DIR/.ipython/IPYS")
        s.send(content)
        s.close()
    except:
        print "Error: could not connect to iPython server."

# --- Functions for running code in iPython --------------------------------- #

def run_current_line():
    runner(vim.current.line)

def run_selection():
    runner("\n".join(vim.current.range))

def run_buffer():
    runner("\n".join(vim.current.buffer))

# --- Clean up function

def remove_sockets():
    import os
    import sys
    os.remove("/Users/petrov/.ipython/IPYS")

Essentially, the server will create a UNIX socket. By default the socket is:

1
$HOME/.ipython/IPYS

It is possible to rename the socket or use different ones for different Vim windows. For now, I wanted to get the basics going. The Python code above should go into

1
$HOME/.vim/plugin

4. Using the code

Now that the code is in place we can start using it. Start IPython and execute the following code:
1
2
3
4
5
6
import ipy_textmateserver
# create the server
s = ipy_textmateserver.TextMateServer()
# start the server
s.start()
# to stop the server do: s.stop()
Now the server is running in that instance of the shell. Open a Python file in Vim. Create a map for executing the current line in Vim:
1
:map ,el :python run_current_line()<cr>

Put the cursor on the line of code you want to eval and do: ,el. This should send the line to IPython and you should see the results of execution in the shell.
The other two functions in on the plugin side can also be mapped to whatever you want.

Question and Answer

This is very complicated!
Yes, this is not the easiest thing in the world. But it let’s me work the way I want to work. In the future this will be packaged better as a proper Vim plugin.

Why not use the client that comes with the ipythontm-bundle.
I did try to use that code. However, it seems that Vim and Textmate do things differently. The Vim client that comes with ipythontm-bundle uses a Twisted reactor to send code to the server. This is great. However, once the reactor is stopped it can’t be restarted. Any attempts to do so result in a blocked thread. When this happens from inside Vim, it kills the whole session. This sucks. My guess is that Textmate reloads the whole client file. Vim doesn’t seem to do this. Therefore, I opted to use simple Python sockets.

Why not use ipy_vimserver.py?
I tried this as well. However, it uses socket code that doesn’t work on my machine. If you’re on Linux you should be able to use ipy_vimserver.py without any problems.

Comments

Leave a Reply