Getting a Clojure REPL in Vim With VimClojure, Nailgun, and Leiningen

| Comments

Having a Clojure REPL (Read Eval Print Loop) right inside Vim makes it easier to test ideas, get documentation, and explore your code. There are a few hoops that you need to jump through to enable it, but the payoff is worth it.

Install Leiningen

Leiningen isn’t required, but it makes managing the classpath for your REPL quite a bit easier and automates the inclusion of the files in your project so that they can be used in the REPL.

If you’ve already got clojure installed and are managing your classpath some other way, you’ll want to modify the nailgun server script below to remove the call to lein and ensure you’re getting clojure and other classes in the ng-server’s classpath.

Install Leiningen if you don’t have it already.

Download the lein script.

Put it somewhere on your PATH (such as /usr/local/bin or ~/bin).

Set it to be executable:

chmod +x lein

Then, tell it to self-install with this command:

lein self-install

Now you should have a working lein installation:

lein help

And you can create a new clojure project skeleton, with clojure 1.3.0 all ready to go with:

lein new myproj

It creates a skeleton project rectory and a project.clj file that you can use to hold lib dependencies.

Go into that project and you can use lein to go into a repl, get the project’s classpath, run tests, etc. Use lein help to see the full list of commands.

Install VimClojure in Vim

Install the VimClojure plugin in vim.

Hopefully, you’re already using Tim Pope’s vim script management script Pathogen.

If so, you should be able to just clone VimClojure into your bundle ectory:

cd .vim/bundle
git clone git://github.com/vim-scripts/VimClojure.git

If you’re not using Pathogen, install the plugin with your normal process.

Edit your .vimrc, make sure you have these settings if they’re not already there (they need to be after the method that calls pathogen to install bundles):

filetype off
call pathogen#runtime_append_all_bundles()
...
filetype plugin indent on
syntax on

and add these items to your .vimrc

let g:vimclojure#HighlightBuiltins = 1
let g:vimclojure#ParenRainbow = 1

To test that VimClojure is installed OK, edit a clojure file (like this sample one modified from (source +)):

(defn myplus
  ([] 0)
  ([x] (cast Number x))
  ([x y] (. clojure.lang.Numbers (add x y)))
  ([x y & more]
     (reduce myplus (myplus x y) more)))

If the parenthesis are differently colored in matched pairs, that means that “rainbow” parenthesis are enabled and the plugin is working. It should look something like this:

You’ll also want to update the helptags documentation for VimClojure:

:helptags ~/.vim/bundle/VimClojure/doc/

Now you can lookup help for VimClojure:

:help VimClojure

You’ve now got a functioning VimClojure installation that can already be pretty helpful. If you want to get an integrated REPL installed, there’s a bit more to do.

Setting up Nailgun to work with VimClojure

This part is the trickiest part (in the github docs, they say “Here be Dragons”). I think the biggest difficulty is that they don’t show you how to configure/launch the nailgun server, we’ll go through those steps.

Nailgun is a server that runs an instance of the JVM. On startup, you tell it what classpath this JVM should run with. Then, with a nailgun client, you can send it additional classes to execute within that JVM and it can show you the output.

It makes things much faster as the Nailgun server is already running hot when you send it things to execute. You don’t pay any JVM startup penalty.

Warning: If you’ve previously tried to install nailgun through homebrew, it will not work with clojure. The server jar that homebrew uses is half the size of the server jar that we’re going to be using for clojure. Uninstall it or put the things below earlier in the classpath.

Compile the VimClojure nailgun client

We need to compile the VimClojure nailgun client. You can either download the sources directly or else clone the bitbucket repo:

hg clone https://bitbucket.org/kotarak/vimclojure

Go into the client directory and make the ng client executable:

cd vimclojure/client  # or cd vimclojure-nailgun-client
make

This will create an executable called ng in the current directory. Copy that somewhere in your path (likely the same place you put lein above).

You should now be able to type ng and have it spit out help text.

% ng
Usage: ng class [--nailgun-options] [args]
          (to execute a class)
   or: ng alias [--nailgun-options] [args]
          (to execute an aliased class)
   or: alias [--nailgun-options] [args]
          (to execute an aliased class, where "alias"
           is both the alias for the class and a symbolic
           link to the ng client)

where options include:
   --nailgun-D=   set/override a client environment variable
   --nailgun-version           print product version and exit
   --nailgun-showversion       print product version and continue
   --nailgun-server            to specify the address of the nailgun server
                               (default is localhost)
   --nailgun-port              to specify the port of the nailgun server
                               (default is 2113)
   --nailgun-help              print this message and exit

Setting up Nailgun Server

Download latest server jar from clojars (currently 2.3.0).

Put that jar somewhere that you won’t delete it, and then add an export for that location in your .bashrc/.vimrc, ex:

export VIMCLOJURE_SERVER_JAR="$HOME/lib/vimclojure/server-2.3.0.jar"

Now save this script as ng-server and put it somewhere in your path and make it executable:

#! /bin/bash

if [ -z $VIMCLOJURE_SERVER_JAR ]; then
    echo "Error! Need to define location of VimClojure nailgun server jar with:"
    echo "export VIMCLOJURE_SERVER_JAR="
    exit 1
fi

if [ ! -f $VIMCLOJURE_SERVER_JAR ]; then
    echo "Error! Unable to find VimClojure nailgun server jar at '$VIMCLOJURE_SERVER_JAR'"
    exit 1
fi

LEIN_CLASSPATH=$(lein classpath)

if [ ! $LEIN_CLASSPATH ]; then
    echo "Warning! Unable to get classpath from lein, just using existing classpath, expecting clojure jars to be available"
fi

NG_CLASSPATH="$VIMCLOJURE_SERVER_JAR:$LEIN_CLASSPATH:$CLASSPATH"
echo java -server -cp "$NG_CLASSPATH" vimclojure.nailgun.NGServer
java -server -cp "$NG_CLASSPATH" vimclojure.nailgun.NGServer

Then add this to your .vimrc setup:

" this should only be necessary if you don't have the ng client in your PATH
let vimclojure#NailgunClient = "/path/to/your/ng"
let vimclojure#WantNailgun = 1 

Now, from the root of a lein project, make sure you’re dependencies are updated:

lein deps   // puts things defined in project.clj into ./lib by default

Without additional configuration, you’ll likely just have the clojure-1.3.0.jar in there.

The script above leverages lein to create a classpath that the nailgun server can use. If you run lein classpath, you’ll see what it will use:

% lein classpath
/Users/tnaleid/Documents/workspace/clojure-test/myproj/test:/Users/tnaleid/Documents/workspace/clojure-test/myproj/test-resources:/Users/tnaleid/Documents/workspace/clojure-test/myproj/src:/Users/tnaleid/Documents/workspace/clojure-test/myproj/classes:/Users/tnaleid/Documents/workspace/clojure-test/myproj/resources:/Users/tnaleid/Documents/workspace/clojure-test/myproj/lib/clojure-1.3.0.jar

Now, you should be able to start up a nailgun server from the root of a lein project and have it automatically pull in all dependencies, ready to recieve client requests.

Open up the src/leinprojectname/core.clj file in vim. Then press

\sr

to get a REPL window that you can interact with. (if you’ve remapped localleader to something else, replace </code> with your custom key)

There are quite a few other things you can do with the REPL, check out :help VimClojure and go down to Keybindings for more details.

Here are some good starter ones:

\el  - eval current line
\eb  - eval current visual block selected
\ef  - eval current file

\sr  - start interactive REPL
\sR  - start interactive REPL initialized to have same namespace as current buffer

\si  - prompt for input and lookup with (source)
\fd  - prompt for input and lookup with (find-doc)

The Pain is Over, Now Reap the Rewards

Once all this configuration is done, it should be as easy as running the server in a lein project:

ng-server

And then editing your files in vim accessing the embedded REPL whenever you need it.

Comments