Technomancy in which are found tricks of the trade concerning clojure authorship

So it turns out getting set up to write Clojure code can be a little tricky. There are a lot of disconnected tidbits about how folks have figured out how to configure things, but it can be a bit tricky to tell the difference between, "hey, this is how I finally got it to work" and "this is how you really should be doing it". I figure I know about as much about using Clojure with Emacs as anybody, so here's a run-through of how I've done my setup. There are a lot of moving parts, but bear with me; most of the installation is automated.

Spoiler Alert: Using SLIME with Clojure is now much easier than the instructions detailed below indicate. This page is left up as it provides some background that may be helpful, but if you just want to get going with SLIME, use ELPA.

The Pieces

ELPA
The Emacs Lisp Package Archive functions as a centralized store for Emacs libraries and provides automated installation and upgrades.
clojure-mode
This gets you syntax highlighting, indentation, and other basic goodies for editing .clj files.
SLIME
The Superior Lisp Interaction Mode for Emacs was originally written to support interacting with Common Lisp subprocesses from within Emacs, but it's been extended to work with other lisps.
swank-clojure
An adapter for SLIME that allows it to work with Clojure.
clojure-test-mode
This provides support for running Clojure tests from within Emacs buffers and seeing the results displayed inline.
paredit
Paredit auto-balances parentheses and other matched chars to make sure you don't end up with structurally invalid expressions.

Installation

The easiest way to get started is to grab ELPA. If you use Emacs Starter Kit you've already got ELPA. (If you're new to Emacs, you might want to use the Starter Kit anyway as a base for your own customizations; also check out the PeepCode screencast.) Use M-x package-list-packages to pull up the package list. Move down to clojure-mode and press i to mark it for installation, then press x to go.

Once it's installed you should be able to work with .clj files, and you may be happy with just this. It has rudimentary subprocess support with M-x run-lisp, which is good enough for many, including Rich Hickey, the creator of Clojure. But most of us find it much more convenient to interact more richly with a running Clojure process as we code.

Pressing M-x clojure-install will kick off the Clojure installation process. Once you choose a download location, it will download a number of repositories and compile Clojure itself, so it will take a few minutes. (It requires having git, Java 1.5+, and ant installed.) When it's done, it will configure SLIME and swank-clojure, and it will give you instructions on a few lines to add to your personal config (usually found in $HOME/.emacs.d/init.el) so it will work for future sessions. Deprecated in favour of similar functionality in swank-clojure.

Usage

Hitting M-x slime will launch a new Clojure session in a *slime-repl* buffer. You can also interact with the *inferior-lisp* buffer, but the slime-repl buffer provides a higher-level interface with a few extra niceties. The REPL works as you'd expect, but you can hit , to activate some shortcuts, the most useful being i to change the current namespace (with tab-completion) and restart.

Back in your .clj buffers, C-x C-e has been rebound to execute the form under the point in Clojure instead of Elisp. This is handy, but you won't get accurate line numbers from stack traces involving functions loaded this way. Pressing C-c C-k will load the entire file and ensure stack traces come through accurately.

As you type out function calls, you should see their argument list show in the minibuffer. This is called eldoc, and it's a great way to get a quick refresher about what a function expects. For full documentation lookup you'll need to get handy with C-c C-d d though. Finally you can use M-. to jump to the definition of any given function.

Projects

Of course, after a while you'll be done with just playing at the REPL and want to hack on a real project. Since the JVM doesn't allow you to modify the classpath at runtime, you need to specify up front where it should look for code. The simplest thing to do is add src/, test/, lib/, and classes/ (for AOT compilation, if desired) directories in your project root to the classpath. Then you place your dependency jars in the lib directory. If you've got complicated dependencies, you could use maven to manage them, but if you've only got a couple it's not hard to do by hand. Use Leiningen for dependency management and other build needs.

Invoking M-x swank-clojure-project will prompt you for a project root and start SLIME with the classpath configured appropriately.

Tests

If you've written automated tests for your project using the clojure.test library (which you should), you can use clojure-test-mode to run them. Install it via M-x package-list-packages, and then you can use C-c C-, to run the tests in the current buffer. Failures and errors get highlighted, so if you want to see details about a failure, move the point to the red region and press C-c C-'.

Happy Hacking

I hope this is helpful and clears up some confusion. Now get out there and write some code.

Update: If you are using Slime with both Clojure and Common Lisp, refer to the instructions at http://felipero.posterous.com/1446961.

« 2009-05-27T17:35:46Z »

Robert Stehwien2009-05-27T20:24:14Z
Running 'clojure-install' didn't work until after I did a
M-X
load-file
~/.emacs.d/elpa/clojure-mode-1.1/clojure-mode.el

Fortunately hitting ? while in ELPA told me to do that :)
Bertrand Russell – 2009-05-28T08:59:44Z
I've been using emacs for 15 years and just discovered ESK a few nights ago. Outstanding work. I ditched my beloved .emacs and started from scratch (easier since I mostly work on clojure these days). Anyway, thanks, and you should really consider renaming it. I had ignored it previously due to the name. It's more of a modular configuration framework for emacs that comes with some nice stuff prepackaged.

One more thing, you say that the user's config is in init.el, but why not mention that it's probably better to put it in .emacs.d/username/username.el. I was thinking off adding exactly this to the documentation the otherday since I had to track it down in one of the git commit entries.

Anyway, thanks again. Great stuff. Rename it!
Brian2009-05-28T14:21:42Z
Nice tutorial. In my SLIME the shortcut to change namespace is ,i rather than ,p; is this a typo?
AskMeAboutLoom – 2009-05-29T10:43:53Z
Really great tutorial :) Helped me understand what all those parts of clojure-mode are for. I had *no idea* before reading this blog post.

Can't use the emacs-starter-kit though, there's a bug in it that makes it unusable (at least for me since I don't know how to fix it myself). Displays "paredit void" after starting emacs and big parts of the config aren't loaded. Was fixed 2 days ago in the chicken-or-egg commit I think but on the same day the error returned in new commits :p My uninformed guess would be that moving paredit from elpa-to-submit to elpa has something to do with it, or at least that commit.
Phil2009-05-29T17:03:57Z
Brian: Turns out !p and i are aliases of each other; I missed the !, but i is better; thanks.



Bertrand: Thanks. I've had a couple other people suggest a rename, but nobody has come up with a better name. Also, renaming can be very disorienting to new users; it's very hard to update all pointers to the old name. Generally the Starter Kit is named at new users since most old Emacs hands are very reluctant to part with their existing config. A new name would be nice, but I'm not sure it's feasible right now.
VS – 2009-05-30T11:03:21Z
I could get everything working on Mac/Linux, but on WinXP, I'm not able to properly compile clj files. C-c C-k says it is compiling but doesn't work. Any hints?
eivind – 2009-05-30T14:02:02Z
Thanks a million for all the work you've put in all of this. I started playing around with emacs and clojure at about the same time. The learning curve is a bit steep, but the information and code you post really helps a lot.

Looking forward to your post on clojure projects. I'm having some problems setting the classpath in emacs/slime correctly, so I'll stay tuned.

cheers!
Peter – 2009-05-30T14:23:44Z
I decided to junk my old .emacs file and start from scratch using ELPA to install clojure, slime + swank. It worked perfectly the first time, I typed M-x slime and had clojure running without problems.

Unfortunately the information the ELPA install told me to add to my .emacs file was not sufficient to load everything on subsequent startups. I still haven't figured out exactly what the install process did to get clojure to be the default lisp, but I did have to add the following to my .emacs:

(add-to-list 'load-path "~/../swank-clojure")
(add-to-list 'load-path "~/../slime/contrib")
(add-to-list 'load-path "~/../slime")
(require 'slime)

(autoload 'clojure-mode "clojure-mode" "foo" t)
(add-to-list 'auto-mode-alist '("\\.clj$" . clojure-mode)

ELPA for installing slime/clojure could be so great, it's too bad there's this tiny bit of configuration information missing.
Phil2009-05-31T13:53:24Z
VS: Sorry, I don't know how compiling works on Windows.

Peter: the stuff you added to your .emacs file is almost exactly what the clojure-slime-config function does. Maybe if you set the clojure-src-root variable? I've had reports that for some reason on OS X that function doesn't work, but unfortunately I can't test on that platform. If you figure anything out please let me know.
Hingebjerg – 2009-06-01T14:05:40Z
Hi Phil,

Just installed the emacs-starter-kit and clojure-mode, and i can't delete curly braces when in clojure-mode. Is there a logical explanation for that?

/Hingebjerg
Peter – 2009-06-10T15:37:28Z
Phil: I think it was the clojure-src-root variable. I'm a little foggy on how I got it working, but I think I was trying to use the clojure-bin value instead, which clojure mode doc says I can do, but which apparently doesn't work.
Phil2009-06-12T09:37:15Z
Hingebjerg: That's a feature of paredit-mode; it enforces that you can't delete parens (or other matched chars) unless they're empty so you don't end up with invalid structure in your code. It's unbelievably handy/addictive once you get used to it, but if you're not sure what's going on it can be pretty annoying.

I meant to cover it in this post, but it got too long; I'll try to cover it in a future post. In the mean time, take a look at the cheat sheet to see how it works.

Peter: Sounds like the clojure-mode documentation needs a refresh. I'll take a look at that.
Shawn Hansen2009-06-13T14:32:05Z
I followed the instructions here to a tee (with emacs-starter-kit previously installed) and had problems starting slime. No lisp was found.

After a few retries, I noticed that if I had opened a .clj file, thus starting up clojure-mode, then slime would start up and connect to a clojure REPL without issue.

Long story short:
1. Follow the instructions in the post.
2. M-x clojure-mode (or open a .clj file)
3. M-x slime

The above three steps work every time.
Kato Hunter – 2009-07-01T10:37:25Z
Thanks for setting this up ... it's a huge time saver vs. starting from scratch! One very helpful addition would be the ability to have Clojure and Common Lisp running in the same emacs session. My .emacs setup was doing that until a recent Clojure update changed the way classpaths work; <F5> would launch an SBCL Slime REPL and <Control><F5> would launch a Clojure Slime REPL in the same session. Your contribution gives me a hands-off incantation for playing around with Clojure but I (and everyone else straddling the CL/Clojure boundary line) still need to come up with a way to get the two Lisps to coexist.
Keith – 2009-07-09T23:31:00Z
This is really excellent work, thank you. I'm probably just being thick, but I can't get clojure-project to work. Everything works for me up until I try to run clojure-project. I get this:

Symbol's value as variable is void: swank-clojure-extra-vm-args

This is on Mac OSX with Emacs 22.3.1. I have no .emacs file and a fresh install of ESK.
Jason2009-07-20T00:43:45Z
Finally got through some boneheaded errors, but seem to get one I can't resolve. When I do a M-x clojure-install, it looks like it references a git repo from kevinoneill, but there is not repo there. Rich Hickey maintains a repo on git now and I would think it should be pointing there, or at least to a 1.0 tag of that repo. Am I missing something?
Phil2009-07-20T12:20:04Z
Shawn, Jason, Keith: Recent versions of clojure-mode/starter-kit fix the problems you are seeing.

Kato: I don't use CL anymore, but if you have any code or instructions that would help for that case I'd be glad to include or link to it.
Ron2009-07-21T09:11:16Z
No, not missing anything: change "kevinoneill" to "richhickey" and it should work. (Or, at least, it did for me.)
jx – 2009-07-24T06:50:12Z
For my Win32 XP, I pointed to Rich Hickey, and wrapped all shell-command src-root args in a replace-regexp to convert forward to back slashes, a la:

(format "cd %s&& %s" (replace-regexp-in-string "/" "\\\\" src-root)

Note also the ampersands used by win32 batch language instead of semicolons. I then setq'd clojure-src-root in my startup file, ran clojure-mode first, then slime. Seems to work now.
Caspar Florian Ebeling2009-07-24T07:39:41Z
If you run into the error that M-x clojure-install cannot find the github repo, you have to manually open the clojure-mode.el and replace the kevinoneill user account with richhickey. Then everything works fine. So this is what the section in question looks like for me, line 616ff:

(message "Checking out source... this will take a while...")
(dolist (cmd '("git clone git://github.com/richhickey/clojure.git"
"git clone git://github.com/richhickey/clojure-contrib.git"
"git clone git://github.com/jochu/swank-clojure.git"
"git clone --depth 2 git://github.com/nablaone/slime.git"))
(unless (= 0 (shell-command (format "cd %s; %s" src-root cmd)))
Phil2009-07-28T09:29:24Z
Caspar: You must be using an old version of clojure-mode; recent versions contain that fix.
Caspar Florian Ebeling2009-07-29T01:04:12Z
Phil: yes, I mailed the clojure-mode maintainers and they updated the ELPA version immediately. In the repo version of clojure-mode it was fixed already.
Chad – 2009-07-29T14:05:02Z
I installed the ESK and Clojure via the instructions above. However, when I type M-x slime, I get the following error:
Search failed: "[0-9]: \\([^$(]+\\).*?\\([0-9]*\\))"

I am on Max OS X. Any ideas?

Thanks!
Chad – 2009-07-30T09:14:40Z
I solved my problem with slime not starting up by adding this line to my personal configs:
(clojure-slime-config "/Users/chad/src")
instead of the suggested
(clojure-slime-config)

Apparently, clojure-src-root doesn't get set properly on Mac OS X. This sets it explicitly in the call to clojure-slime-config.
Nilu – 2009-09-18T16:49:24Z
Has any recent changes broken the tab autocomplete functionality? Even calling slime-indent-and-complete-symbol doesn't work for me. Both return an error of "Format specifier doesn't match argument type".
chas – 2009-10-30T12:42:53Z
Perhaps I'm missing something obvious, but simple evaluations work, e.g., (+ 1 2 3). More complex ones do not. For example:

(re-seq #"[0-9]+" "abs123def345ghi567")

results in:

Debugger entered--Lisp error: (invalid-read-syntax "#")
read(#<buffer new.clj>)
eval-last-sexp-1(nil)
eval-last-sexp(nil)
call-interactively(eval-last-sexp)

while

(map (fn [x] (+ 2 x)) [1 2 3])

results in:

Debugger entered--Lisp error: (void-function fn)
(fn [x] (+ 2 x))
(map (fn [x] (+ 2 x)) [1 2 3])
eval((map (fn [x] (+ 2 x)) [1 2 3]))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
call-interactively(eval-last-sexp)
recursive-edit()
byte-code("\306^P @\307=\203!^@\310\311\312\"\210\313\311!\211^ZA@)\242\314=\203!^@\310\315\31$
debug(error (invalid-read-syntax "#"))
read(#<buffer new.clj>)
eval-last-sexp-1(nil)
eval-last-sexp(nil)
call-interactively(eval-last-sexp)

Name

URL

HTML will be escaped for now. Comments are currently moderated; sorry.