Clojure 101 - Getting Clojure & Slime installed

2009-12-26 21:37:29

Pull up a chair and watch as I install Swank, SLIME and Clojure on a clean Ubuntu. After my last screencast I received several comments, where people really wanted to get started developing with Clojure but did not know how. This post aims to resolve that problem.




Preface

This video is Clojure 101: Installing Swank, SLIME and Clojure in Emacs on a fresh Ubuntu. Initially I failed to understand why this was so hard for many people, but after trying to install using ELPA and Emacs22 it became very clear. The automated install fails in about 90% of the cases - After seeing this screencast, you'll know how to resolve that.


The Video

(double click for full-screen - if you're not seeing it, try hitting F5 or using Firefox)

Clojure 101 - Slime installation from Lau Jensen on Vimeo.


Aftermath

Ok, so are you all set with start your own Clojure project? There is still an abundance of tweaks which you can apply to your emacs configuration, here's some of mine:


;;;;;;;;;;;;;;; LOAD PATH AND AUTOLOADS

(add-to-list 'load-path "~/.emacs.d/")
(add-to-list 'load-path "~/.emacs.d/color-theme")
(add-to-list 'load-path "~/.emacs.d/magit/")
(add-to-list 'load-path "~/.emacs.d/slime")
(add-to-list 'load-path "~/.emacs.d/slime/contrib/")
(add-to-list 'load-path "~/coding/clojure-root/clojure-mode/")

(require 'egg)
(require 'ido)
(require 'htmlize)
(require 'color-theme)
(require 'clojure-mode)

(setq swank-clojure-jar-path "~/.swank-clojure/swank-clojure-1.0.jar"
      swank-clojure-jar-home "~/.swank-clojure/"
      swank-clojure-classpath
      (list
       "~/.swank-clojure/*"
       "~/coding/lisp/clojure/libs/*"))  ;; All my Java jars

;;;;;;;;;;;;;;; GLOBAL SETTINGS

(ido-mode t)
(setq backup-directory-alist (list (cons ".*" (expand-file-name "~/.emacsbackup/"))))
(setq x-select-enable-clipboard t)
(color-theme-initialize)
(color-theme-sitaramv-nt) ; Loading this first gives me yellow buffer names
(color-theme-charcoal-black)
(set-default-font "-unknown-Inconsolata-normal-normal-normal-*-12-*-*-*-m-0-iso10646-1")
(global-font-lock-mode 1) ;; Enable syntax highlighting when editing code.
(setq current-language-environment "UTF-8")
(show-paren-mode 1)
(tool-bar-mode -1)
(setq transient-mark-mode t)
(setq visible-bell t)
(setq inhibit-startup-screen t)

;;;;;;;;;;;;;;; GLOBAL KEYBOARD-BINDINGS
;;;;;;;;;;;;;;; (can be overridden by other modes)

(global-set-key (kbd "C-z") 'set-mark-command)  ; I have Tilda on C-spc
(global-set-key [C-tab] 'other-window)
(global-set-key "\r" 'newline-and-indent)

(global-set-key [f2] 'egg-status)
(global-set-key [f6] 'slime-load-file)  ; Hit this to eval an entire file

(global-set-key [s-left] 'enlarge-window-horizontally)  ; S = Super/Window
(global-set-key [s-right] 'shrink-window-horizontally)

;;;;;;;;;;;;;;; HOOKS

(add-hook 'clojure-mode-hook
          '(lambda ()
             (define-key clojure-mode-map "\C-c\C-e" 'lisp-eval-last-sexp)
             (define-key clojure-mode-map "\C-x\C-e" 'lisp-eval-last-sexp)
             (local-set-key (kbd "") 'slime-eval-defun)
             (local-set-key (kbd "M-RET") 'dabbrev-expand)))

(setq auto-mode-alist
      (append '(("\.lisp$" . lisp-mode)
                ("\.lsp$" . lisp-mode)
                ("\.cl$" . lisp-mode)
                ("\\.js$" . java-mode)
                ("SConstruct$" . python-mode)
                ("\.py$" . python-mode)
                ("\.asd$" . lisp-mode)
                ("\.system$" . lisp-mode)
                ("\\.org$" . org-mode)
                ("\\.mbox$" . vm-mode)
                ("\\.muse$" . muse-mode)
                ("\\.clj$" . clojure-mode))
              auto-mode-alist))

(eval-after-load "slime"
  '(progn
     (require 'slime-fuzzy)
     (setq slime-complete-symbol*-fancy t)
     (setq slime-complete-symbol-function 'slime-fuzzy-complete-symbol)
     (slime-setup)))

;;;;;; PREPARE WINDOW

; This fits my screen (1680x1024)
(when window-system
        (set-frame-height (selected-frame) 225)
        (set-frame-width (selected-frame) 230))


As you can see, I had a legacy SLIME installed under ~/.emacs.d/ so that's added to my classpath. In addition I use htmlize for the blog and Egg and Magit for my Git interface. You'll also notice I'm using 'ido' which is a handy helper that keeps track of which files you open, so that if I want to start working on ClojureQL I hit C-x C-f (open file) and type "backend", Ido then auto-completes to "/home/lau/coding/projects/clojureql/src/clojureql/backend.clj" - very handy.

Specific for my Clojure-development is only the definition of Swanks-Classpaths(+ extras). Update: There has been reported problems with the ...extra-classpaths option, so I recommend sticking with swank-clojure-classpath. When I don't start my project with M-x swank-clojure-project these are used instead of the classpath specific to that project and in libs/* I have all of my regular Java jars, which I consider part of my toolbox. Make sure, for your projects that you remember to set them up as a swank-project - hit Phils link at the bottom if you don't know how.

If you're in the unfortunate situation that you bought a PC which has Windows pre-installed don't be further discouraged, all of these commands will run on your PC as well as soon as you have installed Ubuntu, which takes about 20 minutes.

Update: I've just tried following these instructions on OSX/Aquamacs and with the exception of how to get Clojure.jar into the ~/.swank-clojure folder, it all works perfectly well leading me to believe that Windows users will have the same experience.

I'm new here, where do I go?

Allow me to point the way to a few of my regular stops


Did I leave something out, drop me a line.

bOR_
2009-12-26 23:54:51
Wow, thanks. That was a very clear screencast! Would have saved me a bit of time last week, installing emacs/clojure ;-), and contained some nice tricks about getting to the inner workings of clojure functions.
Vincent Murphy
2009-12-27 04:49:31
I'm so happy that you have started making these screencasts. The difficulty of setting up this environment for the uninitiated cannot be underestimated. I only have had 2-3 hours per week to try and learn Clojure, and I am finally getting somewhere with Emacs/Slime now. We all now that Clojure has incredible potential, if only one can overcome the hurdle of establishing a productive environment.

Thank you! I have made a small donation to encourage you to keep up the good work. I would encourage others to do likewise if they wish to show their appreciation. Your donate button is a bit illegible though; something simpler and clearer might work better for you.
Lau
2009-12-27 09:28:18
Hey Vincent,

I'm very happy that the video turned out to benefit the target audience. I remember when I initially picked up Common Lisp I spent hours trying to get over the configuration. Regarding the donation, thank you very much, that was indeed a great encouragement to keep putting in the time!

Best regards,
Lau B. Jensen
Duc
2009-12-27 21:37:34
Thanks for taking the time to do these screencasts.  Much appreciated!
Michael
2009-12-27 22:15:11
Thanks for that nice screencast. That really helped me a lot with an initial emacs + clojure setup. 

BTW: What tool are you using to do these screencasts?
Lau
2009-12-27 22:34:34
Hi Michael,

You seem to have supplied an invalid email so please double check when commenting in the future, normally I don't let comments through when nobody wants to own up to them.

Regarding my toolbox I'm very new to screencasting, so I just picked up what was handy. gtk-RecordMyDesktop to record the screen, Voice Recorder to record audio, mencoder to fuse it all together.
Phil
2009-12-27 23:45:32
Good stuff! I've just tracked down the source of the bug that's causing failed downloads in 22, so hopefully I'll get a bugfix release out soon that should simplify things significantly. Thanks for pointing this out. It's easy for me to forget that not everyone is on the latest version yet.
Kevin
2009-12-29 21:23:10
I appreciate the .emacs file you posted. In the future it would help if you also posted a textual overview of what you type in the screencast. This would make it easier to refer back to how you did something without waiting for the video to load.

Thanks.
Lau
2009-12-29 21:24:40
Hey Kevin,

Thanks for the feedback and the tip, I'll try to work it in.
Vincent Murphy
2009-12-30 03:27:54
Lau-

http://code.google.com/p/key-mon/ may help you display keyboard keys pressed in screencasts.
Paul
2009-12-30 08:43:36
Hi Lau,

thank you for your two recent sceencasts. How do you get the hello-world example function working in the REPL? I followed along but the function is not runnable for me.

Thanks.
Lau
2009-12-30 08:48:25
Hi Paul,

Sorry about the confusion - I'm looking at ways of showing the short-cut keys on-screen as I go along, Vincents solution below might do the trick. To evaluate a function, place the cursor within that function and hit C-M-x (Control+Alt+x), or alternatively M-x slime-eval-defun. Look for a small confirmation in the minibuffer saying #'user/hello-word, which tells you that the function has been evaluated.
Lau
2009-12-30 11:09:44
Hey Vincent - I've tried out KeyMon now and it works great. Thanks a lot for the tip!
Josh
2009-12-30 16:43:10
Hi Lau:

Good tutorial.  Also thanks for getting the word out about a great old tool (emacs) and a great new one (clojure).

I thought I would share my experience on Windows XP.  I started with my windows install of Emacs.  The ELPA package manager downloads the correct scripts in emacs.d/elpa/, but it does not show the prompt saying "It does not appear that clojure is installed, would you like to install it now?"

To fix this, I ran emacs 23.1 from Cygwin 1.7.1. My cygwin is install in c:\ as recommended by Steve Yegge.  This does install clojure, clojure-contrib and swank-clojure to /docs & settings/you/.swank-clojure.  Oddly, cygwin/emacs can not start the repl, but if I run my windows install of Emacs 23, it does start the repl.  

What I am stuck on now is that when I create tmp.clj and try to run it from the repl I get the following error:

java.lang.Exception: Unable to resolve symbol: hello-world in this context (NO_SOURCE_FILE:13)

Any thoughts?

Thanks again.
Lau
2009-12-30 16:53:03
Hey Josh,

Replace RET for 'hitting enter' in the following:
(defn hw [] (println "Hello World")) RET (hw) RET

If you enter that directly in the REPL and see the string being printed, then you're looking at an emacs config issue, which probably isn't anything other than you needing to bind some key combo to slime-eval-defun. Once thats done, write out the function in tmp.clj, place the cursor within the function and hit the key you assigned.

Ultimately if you want to get into some serious development, I recommend that you install some flavor of Linux instead of Windows, but let me know how it goes.
Josh
2009-12-30 17:48:08
I forgot to mention that defining the hello-world function in the repl and then running it (hello-world) works fine.

After playing around a little bit, I must have missed a step. After creating *.clj, calling Slime Compile/Load File (C-c C-k) will allow the repl to execute definitions in a clj file.

I agree that Linux is a very powerful platform for software development.  Unfortunately, I have a work computer with no Linux partition.  Cygwin has served me well in the scripting/shell department.  

I believe that Windows could serve as an acceptable development platform, however.  Any platform-specific issues related to Java development have been solved long ago.  Windows works fine for Web/J2EE/etc development, especially with an IDE that manages away package/library/jar dependencies.

Sure, Linux has more sane directory naming.  But the platform differences are all known quantities: spaces, slashes, drive letters, new line delimiters, etc.  As long as platform independent code, scripts and regular expressions are used, I don't see why Windows wouldn't be a serviceable platform.
Michael Teter
2010-01-25 05:48:38
It would be really great if somewhere on your blog page, ideally at the top of the post, there was a datestamp.

You've got great content, but without looking at the URL it's not possible (unless I'm missing it?) to know when this article was published.  Then in addition, I found it amusing that the comments are fuzzy-dated... "about 3 weeks ago".  3 weeks from when? :)

Wait I found it!  It's in tiny text at the bottom of the post.  Still I think it would be great to see that date under the title of the post, near the top.
Lau
2010-01-25 08:09:47
Hi Michael,

I'll see what I can do about integrating a timestamp nicely on the individual posts. Usually I rely on my visitors navigating posts from the <a href="http://www.bestinclass.dk/index.php/blog/" rel="nofollow">main blog page</a>, which contains quite noticeable timestamps with bold white text on a black background :)
Stefan Rohlfing
2010-02-03 15:16:02
Following your screencast I managed to successfully install Clojure and SLIME on emacs but for some reason don't have code highlighting in Clojure.

I am new to both Clojure and emacs so this might be a silly question, but I would really appreciate if you could add some information on how to make Clojure code highlighting work in emacs.
Lau
2010-02-03 16:32:17
Hey Stefan,

If you got everything installed correctly Clojure-mode should activate as soon as you open a .clj file. If not, try manually calling M-x clojure-mode while in that file. If that gives you proper highlighting, everything is installed as it should be, but you will need to add the following hook to .emacs:

<code>(setq auto-mode-alist
      (append '(("\.lisp$" . lisp-mode)
                ("\.lsp$" . lisp-mode)
                ("\\.clj$", clojure-mode) 
                                                    ....) auto-mode-alist))</code>
Stefan Rohlfing
2010-02-04 05:43:13
Thanks a lot your suggestions. You really helped me a lot.
After opening a Clojure (.clj) file and calling  M-x clojure-mode syntax highlighting finally worked. I then added your configuration code to ~/.emacs. Now clojure-mode gets called automatically when I open a Clojure file.

Right now there is only one problem left:  I copied your hello-world example (defn hello-world [ ] (println "Hello"  "World")) to my clj file and tried to run (hello-world) in the slime buffer. Unfortunately all I got was the following error message:

Unable to resolve symbol: hello-world in this context
  [Thrown class java.lang.Exception]

I suspect this was because SLIME could not find the file. So I put it into ~/.emacs.d, added (add-to-list 'load-path "~/.emacs.d/") to ~/.emacs and tried again. However. I still get the exact same error message. Therefore I would be glad if you could show me where I made a mistake here.
Lau
2010-02-04 08:47:33
@Stefan: SLIME doesn't monitor your .clj files, so it doesn't know about symbols like "hello-world" unless you send them to SLIME. In the screencast I do this by hitting s-tab which is bound to M-x slime-eval-defun. That will evaluate  the function in which the cursor is located. My bindings for this are also shown in the .emacs paste:

(add-hook 'clojure-mode-hook
          '(lambda ()
             (define-key clojure-mode-map "\C-c\C-e" 'lisp-eval-last-sexp)
             (define-key clojure-mode-map "\C-x\C-e" 'lisp-eval-last-sexp)
             (local-set-key (kbd "") 'slime-eval-defun)
             (local-set-key (kbd "M-RET") 'dabbrev-expand)))

That hook is executed once clojure-mode is loaded, giving you the bindings you need.
Stefan Rohlfing
2010-02-04 10:20:34
I included your bindings into my configuration file but still get the same error. However, I will keep on trying...
Stefan Rohlfing
2010-02-05 02:35:32
I just wanted to let you know that now code evaluation works perfectly well with my installation as well.

I realized I defined the wrong key bindings in clojure-hook-mode so evaluation did not work right away.

Thank you very much for your help!
Tim McCormack
2010-06-04 07:59:57
I'm curious why you manually download clojure -- there's an Ubuntu package for it.
Lau
2010-06-05 06:05:54
@Tim: Im and old fashioned guy and I like to know what Im getting - Those packages probably arent snapshots and thats usually what Im targeting.