2010-01-30

Setting up SLIME and Clojure on Aquamacs

UPDATED 2011-04-02: This is outdated, see http://dev.clojure.org/display/doc/Getting+Started instead.

UPDATED 2010-03-06: This works with Emacs 23 (Mac/Ubuntu) and latest versions of slime, swank-clojure and paredit. Ubuntu users can use apt-get/wget instead of port/curl.

There are already some instructions for setting up SLIME and Clojure. Most suggest using ELPA (Emacs Lisp Package Archive). This is nice given that ELPA is becoming the standard for managing Emacs packages. However, as of now I prefer not to use ELPA for several reasons:
  • ELPA SLIME is not up-to-date and includes only slime and slime-repl (no fancy features e.g. fuzzy completion).
  • ELPA paredit is not up-to-date.
  • The REPL set up by ELPA is not as friendly to Clojure as it is to Common Lisp.
So after using ELPA for a while I decided to set things up "manually". Here are the steps I took.

Gather the pieces

  • Get SLIME (I used MacPorts version 20100113_0)
sudo port -v install slime
  • Get paredit (version 21)
curl -O http://mumble.net/~campbell/emacs/paredit.el
  • Get clojure & clojure-contrib
Either using MacPorts
sudo port -v install clojure clojure-contrib
Or downloading directly
curl -O http://build.clojure.org/snapshots/org/clojure/clojure/1.1.0-master-SNAPSHOT/clojure-1.1.0-master-20091202.150145-1.jar
curl -O http://build.clojure.org/snapshots/org/clojure/clojure-contrib/1.1.0-master-SNAPSHOT/clojure-contrib-1.1.0-master-20091212.205045-1.jar
  • Get clojure-mode and swank-clojure (Emacs side)
git clone http://github.com/technomancy/clojure-mode.git
git clone http://github.com/technomancy/swank-clojure.git
  • Get swank-clojure (Clojure side)
Either downloading pre-built jar file
curl -O http://repo.technomancy.us/swank-clojure-1.1.0.jar
Or building from source (assuming lein is installed)
cd path/to/dir/swank-clojure
lein jar
  • Put clojure, clojure-contrib and swank-clojure .jar files in ~/.swank-clojure or ~/.clojure (the default places where swank-clojure.el searches for them).

Configure Emacs

Add this to ~/.emacs
(add-to-list 'load-path "/opt/local/share/emacs/site-lisp/slime/")
(add-to-list 'load-path "/opt/local/share/emacs/site-lisp/slime/contrib/")
(add-to-list 'load-path "path/to/dir/clojure-mode/")
(add-to-list 'load-path "path/to/dir/swank-clojure/")
(add-to-list 'load-path "path/to/dir/paredit/")

;; Customize swank-clojure start-up to reflect possible classpath changes
;; M-x ielm `slime-lisp-implementations RET or see `swank-clojure.el' for more
(defadvice slime-read-interactive-args (before add-clojure)
(require 'assoc)
(aput 'slime-lisp-implementations 'clojure
(list (swank-clojure-cmd) :init 'swank-clojure-init)))

(require 'slime)
(require 'paredit)
(require 'clojure-mode)
(require 'swank-clojure)

(eval-after-load "slime"
  '(progn
     ;; "Extra" features (contrib)
     (slime-setup 
      '(slime-repl slime-banner slime-highlight-edits slime-fuzzy))
     (setq 
      ;; Use UTF-8 coding
      slime-net-coding-system 'utf-8-unix
      ;; Use fuzzy completion (M-Tab)
      slime-complete-symbol-function 'slime-fuzzy-complete-symbol)
     ;; Use parentheses editting mode paredit
     (defun paredit-mode-enable () (paredit-mode 1))
     (add-hook 'slime-mode-hook 'paredit-mode-enable)
     (add-hook 'slime-repl-mode-hook 'paredit-mode-enable)))

;; By default inputs and results have the same color
;; Customize result color to differentiate them
;; Look for `defface' in `slime-repl.el' if you want to further customize
(custom-set-faces
 '(slime-repl-result-face ((t (:foreground "LightGreen")))))

(eval-after-load "swank-clojure"
  '(progn
     ;; Make REPL more friendly to Clojure (ELPA does not include this?)
     ;; The function is defined in swank-clojure.el but not used?!?
    (add-hook 'slime-repl-mode-hook 
              'swank-clojure-slime-repl-modify-syntax t)
    ;; Add classpath for Incanter (just an example)
    ;; The preferred way to set classpath is to use swank-clojure-project
    (add-to-list 'swank-clojure-classpath
                 "path/to/incanter/modules/incanter-app/target/*")))

1 comment: