Michael Alyn Miller

whimrepl: Closing the Gap Between Vim and Clojure


whimrepl is a Leiningen plugin that makes it easy to send Clojure forms from the Win32 version of Vim to a Clojure REPL. vim-slime provides integration with Vim itself and is whimrepl’s only external dependency. Other Vim plugins (the impressive lein-tarsier, for example) provide even more functionality, but are consequently more complex in their operation.

Communication between Vim and whimrepl is accomplished using the remote_send() function in Vim. whimrepl pretends to be a Vim server process and registers itself as such using a collection of Win32 calls. Those calls are hidden away in my VimServer Java library and can easily be used outside of whimrepl.

That probably sounds like the hard part, but it turns out that getting characters from whimrepl into the REPL’s input stream is the real challenge. Suffice it to say that this almost certainly does not happen how you think it does. I may write a post on this at some point, if only to justify the craziness that is CmdExeTyper.java.

Installation

Add the whimrepl plugin to your global Leiningen config (%USERPROFILE%\.lein\profiles.clj) like so:

{:user {:plugins [[lein-whimrepl "1.0.0"]]}}

Add vim-slime to your Vim config, most likely by way of Pathogen, and then configure vim-slime to use whimrepl in your vimrc file:

" Point vim-slime at whimrepl.
let g:slime_target = "whimrepl"

Launching whimrepl

whimrepl wraps the underlying lein repl command and passes through all of the standard REPL options. The easiest way to start whimrepl is just to type lein whimrepl:

C:\Users\malyn\mycljproj> lein whimrepl
whimrepl 1.0.0 available at mycljproj
nREPL server started on port 54127
REPL-y 0.1.6
Clojure 1.4.0
    Exit: Control+D or (exit) or (quit)
Commands: (user/help)
    Docs: (doc function-name-here)
        (find-doc "part-of-name-here")
Source: (source function-name-here)
        (user/sourcery function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Examples from clojuredocs.org: [clojuredocs or cdoc]
        (user/clojuredocs name-here)
        (user/clojuredocs "ns-here" "name-here")
user=>

By default whimrepl will register itself as a Vim target with the name of your Leiningen project. If you are not in a project directory then whimrepl will default to “whimrepl”. You can override the default by supplying a target at the end of the command line invocation:

C:\Users\malyn\mycljproj> lein whimrepl replthis
whimrepl 1.0.0 available at replthis
nREPL server started on port 54172
REPL-y 0.1.6
Clojure 1.4.0
    Exit: Control+D or (exit) or (quit)
Commands: (user/help)
    Docs: (doc function-name-here)
        (find-doc "part-of-name-here")
Source: (source function-name-here)
        (user/sourcery function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Examples from clojuredocs.org: [clojuredocs or cdoc]
        (user/clojuredocs name-here)
        (user/clojuredocs "ns-here" "name-here")
user=>

Note that whimrepl is smart enough to ignore Leiningen’s :headless option and will not start a whimrepl listener when that option is present. On a related note, because whimrepl just wraps Leiningen’s normal REPL, you can use whimrepl when connected to a remote REPL using :connect.

Using whimrepl

whimrepl integrates with vim-slime, so you can send a Clojure form from Vim to your REPL with a simple Control-c, Control-c.

Why whimrepl?

My previous article talked about using tmux as a way to get access to a Clojure REPL from inside of Vim. That works great on a machine that can run tmux, but I do quite a bit of development on Windows and Windows is not supported by tmux. Some of the elements of that article are still relevant though (usage of paredit and vim-clojure-static, for example).

I considered the VimClojure + lein-tarsier route, but I didn’t like the fact that I had to remember to start VimClojure before I edited a Clojure file in Vim. whimrepl can be started at any time and is only needed by Vim when you actually want to communicate between Vim and the REPL.

No, I mean why “whimrepl”?

Ah, well, the prototype was called “vimwinrepl” and that was the name that I was going to go with. Except that sometimes I would get confused and call it “winvimrepl”. Neither one is more obvious than the other and so I was constantly using the wrong name.

Thankfully confusion begets confusion which, apparently, begets clarity: every now and then I would slip up and call the project “wimvimrepl”, which was obviously wrong, but which also sounded kind of like a combination of “Vim” and “Win”. Problem solved! Product named. Done.