Saturday, July 27, 2013

How to set up a Clojure nREPL using Vim & Fireplace.

One of the cool things about using Clojure is being able to evaluate code interactively in the read-eval-print-loop (REPL).  The  vim-fireplace project on GitHub (aka Foreplay) is the newest & best way to accomplish this from within the Vim/GVim editor, so you don't even have to switch windows to copy/paste code like you would with the normal "lein repl" command.

I recently installed Fedora 18 and was trying to get everything configured for Vim + Fireplace when I got stuck.  Fortunately google lead me to a very nice article from boxuk.com that helped to clear up the sticking points.



I'm pasting the blog contents below in case it ever disappears from the web:
--------------------------------------------------------------------------------------------------------

Unboxing: vim-fireplace
Overview
Rhodri Pugh introduces vim-fireplace, a plugin providing nREPL functionality for Clojure, to see how it compares with Swank and Slime.
Author
Rhodri Pugh
Date
28 May 2013

About Unboxing

Unboxing is our regular feature where someone at Box UK spends a few hours playing with a new framework, library, tool or technique and blogs about his or her experience. You can read more Unboxing features here.

vim-fireplace

I’ve been using Vim for a few years now, and love it. When developing with Clojure, however, I’ve always felt like I’ve been missing out on the tight integration my Emacs-touting colleagues seem to enjoy. I’ve tried picking up Emacs a few times, but have always ended up coming back to Vim as I just feel much more productive with my day-to-day languages.
Until now my setup has involved using a Slime plugin to send functions to a REPL running inside a Screen session. This actually works reasonably well; the plugin just grabs chunks of text and pipes them to the screen session. It’s agnostic to the source and destination, so can be useful for many things, but it does lack the aforementioned tight integration so I’ve always hoped for something better...

What is it?

Over the last year the Clojure community has moved away from using Swank/Slime to the nREPL protocol. For Vim, there is a plugin called vim-fireplace (previously vim-foreplay) which provides this functionality. This post is a little different to ourusual unboxings where the author has no experience of the tech, as I’ve been using this for a little while, but I want to take you through what vim-fireplace is and how nicely it works.

Getting to grips

Installation is pretty straightforward. I use vundle to manage my plugins, so installing vim-fireplace is as easy as adding it to my config:
Bundle guns/vim-clojure-static
Bundle tpope/vim-fireplace
I’ve also included the vim-clojure-static plugin which provides syntax highlighting, indentation and filetype settings for Clojure and ClojureScript. If you use Pathogen then you can find the repos to clone on Github.
Unlike with Emacs where (as I’m told, anyway) it’ll start an nREPL server for you when you ‘jack in’, we need to start the REPL that Vim is going to connect to. This is easy of course with Leiningen:
$> lein repl
nREPL server started on port 55983
REPL-y 0.1.10
Clojure 1.5.1
 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=>
You’ll see that it prints out the port nREPL is listening on. This has also been written to the file target/repl-port which vim-fireplace will use. There’s no need to start Vim or nREPL before/after each other; any order will work. You can even restart the REPL and vim-fireplace will reconnect to the new one (or even connect to a running application!)
To test that it’s working, open a Clojure file from your project and enter :%Eval, which will evaluate the current namespace. You should see a message on the statusline that will be the result of the last expression in the file (probably a function name).
 Testing vim-fireplace
Then you can try executing some code. Type an invocation to one of the functions in your namespace, move the cursor to it, and then type :Eval. You should see the result of the function appear in the message window at the bottom of Vim:
Executing code
Sweet! Let’s try some other features...

Going Deeper

Using :Eval and :%Eval is fine for a demo, but not for more than a few minutes. So, I added some handy key bindings (ctrl-e, and shift-e, respectively).
nnoremap <C-e> :Eval<CR>
nnoremap E :%Eval<CR>
This makes it really quick and easy to compile and evaluate forms, and error messages will be displayed right there in Vim when they occur (so, no need to switch to another application as I had to do before).
The next useful feature is the ability to access documentation and function source code.  Documentation can be accessed either by using :Doc FUNCTION_NAME, or more handily by using K while the cursor is over a function. This will then display the documentation for that function in a message window at the bottom of the screen. Here’s an example for clojure.core/map.
Accessing documentation and function source code
This isn’t just limited to the clojure.core docs; it’ll work for all your project code and any libraries you’re using. As you can imagine, having this information one keystroke away saves a lot of time. If the docs are not enough, you can also display the source for a function using [d, like...
Displaying the source function
It’s nice to see good example code from clojure.core, but it’s invaluable when looking up that function you just wrote that you now need to reference.

Want to know more?

After using vim-fireplace for a little while now it is such a massive step-up from my Slime + Screen setup it’s not even funny. I don’t know if this is on a par with Emacs’ nREPL yet (please post a comment if you know better), but to me it feels really, really well integrated, and I love it. The project is reasonably new and very active on Github, so hopefully it’s got a solid future.


No comments:

Post a Comment