Make Emacs evaluate Clojure in 5 minutes

Emacs is my editor of choice for Clojure development (as for all Lisps), and according to the State of Clojure 2011 survey, that’s true for 68% of all Clojure developers.

Yet from what I’ve seen, some Emacs using Clojure developers don’t evaluate their code in Emacs, and the survey shows that 20% of all Clojure developers use the command-line REPL. Read on to figure out how to change that in just about 5 minutes.

“But why would I want to evaluate Clojure in Emacs?”, you might ask. Here’s why I can’t live without it: When I was new to Lisp, I missed the step-by-step debugger I knew from imperative languages. That changed when I started to write Emacs Lisp and got used to evaluating code in the editor. In functional programming, you avoid mutable state, especially global mutable state, so you can normally locate and fix bugs by evaluating suspicious parts of your program in isolation. Proper runtime inspection is still useful and necessary in some cases, and there are tools for that, but evaluating code in Emacs has been sufficient for me so far.

While most Clojurians seem to swear by SLIME to achieve this, I’m not particularly comfortable with it. It’s big, annoying to set up and there has been no release or tag to date, you have to get the latest code from CVS. Nothing you’re likely to get up and running in 5 minutes. If you’ve got some free time, do try SLIME, you might like it. If you, like me, would rather avoid it: Read on to learn how to set up inferior-lisp-mode (where inferior-lisp stands for Lisps other than Emacs Lisp) for Clojure.

Setting up inferior-lisp-mode

All you really need to do is set the variable inferior-lisp-program to the command that invokes the Clojure REPL.

Leiningen

If you use Leiningen for all projects, add the following to your init.el:

(add-hook 'clojure-mode-hook
          (lambda ()
            (setq inferior-lisp-program "lein repl")))

Maven

For Maven users, it takes a bit more effort. The inferior-lisp command will execute the configured command in the same directory as the file you are currently visiting, which is probably not the directory where your Maven pom.xml resides. Maven, however, wants you to execute most commands in that directory. To circumvent this, I wrote a wrapper script that locates the pom.xml before invoking Maven. Armed with that, you can set up inferior-lisp-program as follows:

(add-hook 'clojure-mode-hook
          (lambda ()
            (setq inferior-lisp-program "smvn clojure:repl")))

Both Leiningen and Maven

When you are working with both Leiningen and Maven projects (like I do), things get a little more complicated. I thought about writing an Emacs Lisp function that automatically discovers whether a project is a Leiningen or a Maven project and invokes the respective command, but decided to shave that yak later. Instead, I use Emacs’ dir local variables to set the inferior-lisp-program for each project. For a Leiningen project, just add a .dir-locals.el file with the following content to your project’s root directory:

((clojure-mode . ((inferior-lisp-program . "lein repl"))))

For Maven projects, do the same with the following content:

((clojure-mode . ((inferior-lisp-program . "smvn clojure:repl"))))

And to eliminate the annoying warning that pops up whenever the dir locals are set, add the following to your init.el:

(add-hook 'clojure-mode-hook
          (lambda ()
            (setq safe-local-variable-values
                  '((inferior-lisp-program . "lein repl")
                    (inferior-lisp-program . "smvn clojure:repl")))))

Using inferior-lisp-mode

Now that you’ve set up inferior-lisp-mode, you can just open a Clojure file and type: M-x inferior-lisp, which starts a Clojure REPL in the current Emacs window. You can then use the REPL conveniently from within Emacs, and evaluate s-expressions in your code by placing the cursor on closing parantheses and pressing C-x C-e.

That’s it, have fun :)

4 Responses to Make Emacs evaluate Clojure in 5 minutes

  1. matt briggs says:

    I don’t know if its just me, but slime with clojure never really seemed that hard to set up. step 1) m-x package-install clojure-mode. step 2) create new clojure project lein new myapp step 3) open any file in the project and do m-x clojure-jack-in. granted, if you hit problems here you are most likely in for a wild ride, but i have yet to have that happen unless i have something strange elsewhere in my setup.

  2. Brian Cooley says:

    Thanks for the handy tip! The maven tips are particularly useful.

    For what it’s worth, SLIME has gotten a lot easier these days thanks to leiningen. To check it out, install the leiningen swank-clojure plugin:

    lein plugin install swank-clojure 1.3.4

    (1.3.4 is the latest version as of this writing, but users should use whatever the latest version is on clojars.org)

    From there, you can open a project file and execute the following emacs command with the point in the project file:

    M-x clojure-jack-in

    This will start a REPL in which code will be evaluated (println statements will be evaluated in that buffer, for example). It’s a really easy way to get a SLIME session started without a lot of fuss. All of the usual SLIME commands apply (M-TAB for completion, C-x C-e for evaluation, C-M-x for compile-top-level). A set of some of the most useful SLIME commands are on the github page for swank-clojure.

    Cheers!

  3. Felix H. Dahlke says:

    Interesting, so I don’t need to check SLIME out from CVS and all that anymore? Guess I’ll give it another chance then :)

  4. Aidan Finn says:

    Thanks for the tip. I’ve been using slime for a while and love it. But on my current project I’ve been experiencing a problem where slime crashes when a function returns a large amount of data (seemed to be that above a certain size, slime would puke). It’s been very frustrating so I just setup inferior lisp mode as above. Works great and doesn’t crash on the data that slime was crashing on!

    For the previous commenters, is there any particular advantage to using slime over the approach listed in the approach above?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>