Home > clojure, vim > How I Tamed VimClojure

How I Tamed VimClojure

October 24th, 2010

Update 1/2013: The future of Clojuring with Vim is tpope’s foreplay.vim. You can find a tutorial here.

NOTE: I really love the setup described below. But I admit it’s a lot to digest. If you just want vimclojure working now, you may be interested in vimclojure-easy


UPDATED October 7th, 2011 for VimClojure 2.3.0

TL;DR VimClojure Download List


Introduction

Like Windows users at a Ruby conference, vim-using Clojurians can feel a little left out. Everyone uses Emacs. Well, I played a ton of Rogue when I was 11, so I’ve always had a soft spot for vi/vim’s way of doing things, at least the movement keys anyway.

Up until now I’ve been doing Clojure development in a cobbled together mix of screen.vim and VimClojure. I could start a simple repl with screen and rely on VimClojure for basic syntax highlighting, indenting, etc. I’ve been aware that VimClojure had much more to offer, but the setup docs I found were varied, inconsistent and generally confusing. Other blogposts on the subject seemed to either surrender to a half solution like I already had, or were so inconvenient that I wouldn’t use it. So, I finally sucked it up, slogged through the setup, and got everything working to my liking.

Here, I’ll try to clearly document my full setup in hopes that someone else might find it useful. My main goal was a setup where I could make the most of VimClojure directly from vim without a bunch of preparation. If I want to just play around, I don’t want to fiddle around with Maven or Leiningen or anything. I want to start vim, get a repl, and start exploring!

Everything here is in my vimfiles repo on github.com

screenshot

Prerequisites

Note that throughout this document, if you’re on Windows, replace references to the ~/.vim directory with ~/vimfiles

Pathogen

If you’re not interested in using pathogen, just adjust paths accordingly throughout the rest of this post

To get going, you’ll need to download a few things. First, for vim plugin sanity, I use pathogen.vim. Download it and add pathogen.vim to ~/.vim/autoload and add the following to the top of your .vimrc file:

" Load plugins from .vim/bundles using .vim/autoload/pathogen.vim
call pathogen#runtime_append_all_bundles()

filetype off " On some Linux systems, this is necessary to make sure pathogen
             " picks up ftdetect directories in plugins! :(
syntax on
filetype plugin indent on

Now add a ~/.vim/bundle directory. This is where you’ll expand all your plugins, each in its own directory.

screen.vim

For this setup, I’m still using screen.vim as a simple way of starting up VimClojure’s Nailgun server directly from vim. It makes sure the server is killed when vim exits and is generally useful anyway. Download and install it. Since I’m not a fan of vimball (vba) installers, I just grabbed the source directly from github (hit the “Downloads” button) and dropped it in my bundle directory.

That’s it. Now you can use :ScreenShell args ... to start a simple screen session.

Note to Windows users: Obviously, Windows doesn’t have GNU screen. The least painful approach seems to be to install Cygwin. I don’t care that much for Cygwin, mostly because it has no uninstaller (wtf !?!?), but a super-minimal Cygwin install seems to be working ok for me. Just be sure to add c:\cygwin\bin (or whatever) to your system path.

VimClojure Setup

Install

And of course you need VimClojure itself. Everything here assumes VimClojure 2.3.0. Hopefully, it doesn’t change too much. Download VimClojure and extract it to your ~/.vim/bundle folder. For full interactive support, you’ll need two other things:

  • The Nailgun client (note this is 2.2.0, but still works fine with 2.3.0) – A tiny executable that allows vim to communicate with a running JVM. (as a side-note, Nailgun is an occasionally useful way to avoid the horrendous startup times of the JVM)
  • The VimClojure Nailgun server jar (you can browse here for other versions) – The other half of the Nailgun protocol where the running instance of Clojure will live in a JVM. Note that as documented in the README.markdown file in the VimClojure archive, you can also specify this as a dependency in Leiningen, Maven and friends. This isn’t that useful for ad hoc Clojure exploration though.

Assuming you’ve installed VimClojure to ~/.vim/bundle/vimclojure-2.3.0, here’s what I did with these. I created a folder, ~/.vim/bundle/vimclojure-2.3.0/lib and added the following to it:

bundle/vimclojure-2.3.0/lib
|-- nailgun
|   |-- Makefile
|   |-- ng
|   |-- ng.exe
|   |-- ngclient
|   |   `-- ng.c
|   `-- readme.txt
`-- server-2.3.0.jar

Note that the ng executable on Unix must be built with make.

Now the only files we still need are the clojure core and contrib jars. I drop these in ~/.vim/lib. Which version you put there is up to you. We’ll set things up in .vimrc below so that this is the last resort for finding Clojure jars. If a different version is in your project, that should get used instead. If you just start up vim to experiment outside a full project, this is the version you’ll get.

.vimrc Settings

Ok, we have everything we need in our .vim folder. Now we just need to wire it all up in .vimrc. First, let’s do some stuff to make things cross-platform:

" Let's remember some things, like where the .vim folder is.
if has("win32") || has("win64")
    let windows=1
    let vimfiles=$HOME . "/vimfiles"
    let sep=";"
else
    let windows=0
    let vimfiles=$HOME . "/.vim"
    let sep=":"
endif

Now we know where the .vim folder is and the correct Java classpath separator (stupid!) to use. So we can build a generic classpath that will cover most project configurations. I tend to always open vim at the root of a project and never change working directory so your mileage may vary with this:

let classpath = join(
   \[".", 
   \ "src", "src/main/clojure", "src/main/resources", 
   \ "test", "src/test/clojure", "src/test/resources",
   \ "classes", "target/classes",
   \ "lib/*", "lib/dev/*", 
   \ "bin", 
   \ vimfiles."/lib/*"
   \], 
   \ sep)

Basically we’ve just built a big, catchall classpath. Note that the jars in .vim are at the very end so they’ll be a fallback.

Finally, we’ll pull it all together by configuring VimClojure:

" Settings for VimClojure
let vimclojureRoot = vimfiles."/bundle/vimclojure-2.3.0"
let vimclojure#HighlightBuiltins=1
let vimclojure#HighlightContrib=1
let vimclojure#DynamicHighlighting=1
let vimclojure#ParenRainbow=1
let vimclojure#WantNailgun = 1
let vimclojure#NailgunClient = vimclojureRoot."/lib/nailgun/ng"
if windows
    " In stupid windows, no forward slashes, and tack on .exe
    let vimclojure#NailgunClient = substitute(vimclojure#NailgunClient, "/", "\\", "g") . ".exe"
endif

" Start vimclojure nailgun server (uses screen.vim to manage lifetime)
nmap <silent> <Leader>sc :execute "ScreenShell java -cp \"" . classpath . sep . vimclojureRoot . "/lib/*" . "\" vimclojure.nailgun.NGServer 127.0.0.1" <cr>
" Start a generic Clojure repl (uses screen.vim)
nmap <silent> <Leader>sC :execute "ScreenShell java -cp \"" . classpath . "\" clojure.main" <cr>

Basically we tell VimClojure where our Nailgun client is (and handle Windows silliness) and set up some helpers for starting a Clojure repl (<Leader>sC) or VimClojure Nailgun server (<Leader>sc) with screen.vim. If you don’t feel like using the screen shortcut, you can of course start the server manually as described in the VimClojure docs:

$ java -cp "classpath including clojure jars and server-2.3.0.jar" vimclojure.nailgun.NGServer 127.0.0.1

Kick the Tires

With all that in place, we’re ready to give it a try:

  • Start vim
  • Hit <Leader>sc (or whatever you mapped the server to) to start up the Nailgun server. Note that it must be running before you open a Clojure buffer!
  • Open a new Clojure file: :e test.clj
  • At this point, there might be a slight, or not so slight, delay (or error message!) as the Nailgun server loads Clojure for the first time. Remember that JVM startup time I mentioned?
  • Hit <LocalLeader>sr to start a repl inside vim (see :help maplocalleader if you don’t know what <LocalLeader> is)

All the other commands and interactive features of VimClojure are described in the docs (~/.vim/bundle/vimclojure-2.3.0/doc/clojure.txt). Here’s my current shortlist:

  • <LocalLeader>sw – Show source for the word under the cursor, including clojure.core! <– this is key if you care about understanding a platform!
  • <LocalLeader>sr – Start a repl
  • <LocalLeader>sR – Start a repl in the current namespace
  • <LocalLeader>eb – Evaluate current visual block. There are several “eX” variations.
  • <LocalLeader>lw – Lookup docs for word under cursor. There are several “lX” lookup variations

Conclusion

Now we have a Clojure development environment that’s not so embarrassingly inadequate compared to Emacs. This is working well for me so far, but I’m sure there’s room for improvment. Let me know if you see anything really dumb I’m doing. Thanks!

clojure, vim ,

  1. October 25th, 2010 at 17:00 | #1

    Another handy one is et, to evaluate the enclosing top level form. If your cursor is inside a function definition this will evaluate it, so you don’t have to worry about highlighting a region or going to the end of a form or something.

  2. YAN
    October 27th, 2010 at 03:27 | #2

    Would love if you could write some words about how to do debugging effectively since neither debug-repl nor Clojure CDT work well together with vimclojure.

    It is also possible to start the nailgun server from a repl(http://groups.google.com/group/vimclojure/browse_thread/thread/a976040918ee167b?pli=1), so I would use leiningen and put the Nailgunserver startup in the :repl-init-script, this makes the classpath and library handling more comfortable and clean.

  3. YAN
    October 27th, 2010 at 03:39 | #3

    also found a leiningen plugin for vimclojure.

  4. October 27th, 2010 at 07:45 | #4

    @YAN
    Thanks. I wasn’t actually aware of debug-repl yet (just getting started), but I’ll take a look at it. Most of my debugging so far has been with print statements, lazytests, and experiments in the repl. Nothing particularly novel though. If I learn something, I’ll write about it though :)

    For an established project with Leiningen (or Maven or whatever), it makes sense to start the Nailgun server from there simply because it will get the classpath exactly right. My solution is for when I’m just firing up vim to do a quick experiment without creating project.clj or anything. Luckily, the two aren’t mutually exclusive.

  5. December 25th, 2010 at 23:32 | #5

    Thank you so much for this post! I’ve been struggling with setting up my Clojure dev environment, and Google finally pointed me to this post which wrapped it up nicely.

    Merry Christmas!

  6. October 16th, 2011 at 16:36 | #6

    Thanks, great post as usual.

    I think it’s handy to keep screen shortcuts handy, too: http://aperiodic.net/screen/quick_reference#window_management

  7. Keith Jarrin
    December 24th, 2011 at 15:11 | #7

    Thanks! This is the best write up.
    K

  8. oo
    May 26th, 2012 at 18:07 | #8

    my path:
    oo@oo:~/.vim$ ls ~/.vim/lib/
    clojure-1.4.0 nailgun server-2.3.1.jar
    oo@oo:~/.vim$ ls ~/.vim/bundle/
    screen vimclojure-2.3.1

    When I hit sc, it shows this error:

    oo@oo:~/.vim$ java -cp “.:src:src/main/clojure:src/main/resources:test:src/test/clojure:src/test/resources:classes:target/classes:lib/*:lib/dev/*:bin:/home/oo/.vim/lib/*:/home/oo/.vim/bundle/vimclojure-2.3.1/lib/*” vimclojure.nailgun.NGServer 127.0.0.1
    Exception in thread “main” java.lang.NoClassDefFoundError: clojure/lang/RT
    at vimclojure.nailgun.NGServer.(NGServer.java:52)
    Caused by: java.lang.ClassNotFoundException: clojure.lang.RT
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    … 1 more

  9. May 26th, 2012 at 18:15 | #9

    Assuming that .vim/lib/clojure-1.4.0 is a directory, you’ll either need pull the jar in there up into .vim/lib, or add .vim/lib/clojure-1.4.0/* to the classpath. That’s my guess anyway. Cheers.

  10. oo
    May 26th, 2012 at 18:23 | #10

    any way, I can start the server by:

    $ java -cp “classpath including clojure jars and server-2.3.0.jar” vimclojure.nailgun.NGServer 127.0.0.1

    in my terminal

  11. oo
    May 26th, 2012 at 18:32 | #11

    Now I change my .vimrc to:

    nmap sc :execute “ScreenShell java -cp $CLASSPATH vimclojure.nailgun.NGServer 127.0.0.1″

    And it works!
    Thanks to your great article:)

  12. May 26th, 2012 at 18:33 | #12

    @oo
    Great! Have fun :)

  13. albita
    July 22nd, 2012 at 14:14 | #13

    Dave,

    I git installed daveray/vimfiles. Unable able to find sc or any way to start Nailgun server. Any help woiuld be appreciated.

    Thanks,
    albita

  14. July 22nd, 2012 at 14:20 | #14

    @albita
    Hi. As noted at the top of the post, I highly recommend trying out vimclojure-easy (http://github.com/daveray/vimclojure-easy) and following the instructions in the README there.

    Cheers,
    Dave

  15. albita
    July 29th, 2012 at 04:55 | #15

    I’m here to learn and not interested in getting vimclojure working without understanding the configuration! If you are referring me to vimclojure-easy, what is the purpose of daveray/vimfiles? Thank you for your time but I’m not interested in your /vimclojure-easy.

  1. July 17th, 2012 at 15:08 | #1