Juli 12, 2012

Using Emacs for Clojure Development

There are many (confusing) blog posts about using Emacs for Clojure development but I promise you not to make you confuse a bit more (hopefully. :-D). Since I use Clojure for my dissertation and usually Clojurians use Emacs (for obvious reasons), then here I come.

There are some steps to do to prepare Emacs. I use Linux (Arch Linux) here, so, probably it won't be applicable for other OS, but this usually the same with other Linux distros. Some software that needs to be installed properly before are JDK, Clojure, Leiningen (I use version 2), and Emacs (version 24, 23 is okay but you have to prepare package management by yourself and it's quite tricky). Those are already explained properly at each of the website, so I will not repeat it again here. Basically, there are one-time-only setup procedures below:

  1. Setup Emacs package management
  2. Install clojure-mode, swank-clojure, slime and slime-repl
  3. Prepare syntax highlighting
When they are all installed and configured successfully, then the project and source code should be configured  to include swank-clojure.
  1. Prepare project: source code and dependencies.
After all of those steps, then all you have to do is coding. The details follow.

Setup Emacs Package Management
In Linux, usually all of those Emacs file for user will reside in $HOME/.emacs.d/. Inside, there is a file - init.el - which is used to store Lisp script for Emacs configuration. To setup Emacs package management, put this into init.el:


(require 'package)
(setq package-archives '(("ELPA" . "http://tromey.com/elpa/")
    ("gnu" . "http://elpa.gnu.org/packages/")
    ("marmalade" . "http://marmalade-repo.org/packages/")))
(package-initialize)

Those lines are used to let Emacs know about the package archives / repositories (ELPA, gnu, and marmalade) then activate package management. If you edit the init.el file from Emacs, you may activate them by using M-x eval-current-buffer when you are in init.el buffer. If you are confuse, just exit from Emacs (C-x C-c) then fire up Emacs again.

Install clojure-mode, swank-clojure, slime and slime-repl
SLIME (The Superior Lisp Interaction Mode for Emacs) and SLIME-REPL are package to interact with Lisp, especially useful for coding (code evaluation, completion, /etc). In this post, we will install this and make it interact with swank for the benefit of coding in Clojure inside Emacs. Here is how to install them:
  1. M-x package-list-packages, it will access package repositories and show them inside buffer.
  2. Find clojure-mode, swank-clojure, slime, and slime-repl on the list. In each of package, click on the name, then click on "Install" (yes, you can also use your keyboad: put cursor on the name, enter, then "C-x o" to go to the description window below, put cursor on "Install" then RET (or you may call it Enter key).

Prepare Syntax Highlighting
To activate clojure-mode and make all color output, put this into init.el:
;; these for Clojure, activate then turn on 
(require 'clojure-mode)
(defun turn-on-paredit () (paredit-mode 1))
(add-hook 'clojure-mode-hook 'turn-on-paredit)

;; syntax highlighting for swank
(add-hook 'slime-repl-mode-hook
   (defun clojure-mode-slime-font-lock ()
     (require 'clojure-mode)
     (let (font-lock-mode)
       (clojure-mode-font-lock-setup))))
;;
And that's all for setting up Clojure development environment in Emacs. The following detail is only one-time whenever you want to create new project.

Prepare Project Source Code and Dependencies
Using Leiningen, use this command (my Leiningen script name is "lein2", by default, if you follow installation instruction in Leiningen website, this script name should be "lein". I use "lein2" because I have 2 Leiningen alive: "lein" for stable version - 1.x and "lein2" for development version - 2.x):

[bpdp@bpdp-arch clojure]$ lein2 new zax
Generating a project called zax based on the 'default' template.
To see other templates (app, lein plugin, etc), try `lein help new`.
[bpdp@bpdp-arch clojure]$ tree zax/
zax/
|-- README.md
|-- doc
|   `-- intro.md
|-- project.clj
|-- src
|   `-- zax
|       `-- core.clj
|-- target
|   |-- classes
|   `-- stale
|       `-- dependencies
`-- test
    `-- zax
        `-- core_test.clj

8 directories, 6 files
[bpdp@bpdp-arch clojure]$ 
Edit project.clj to include lein-swank plugin:
[bpdp@bpdp-arch zax]$ cat project.clj 
(defproject zax "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"]]
              :plugins [[lein-swank "1.4.4"]])
[bpdp@bpdp-arch zax]$ 
That's all for project and source code preparation. Now, whenever you want to go crazy with Emacs and Clojure, activate swank server and have it connected from inside Emacs. This step below will show you the details:

Activate swank server
Use this command from shell:

[bpdp@bpdp-arch zax]$ lein2 swank 4005 localhost :colors? true 
Listening for transport dt_socket at address: 50069
Connection opened on localhost port 4005.
From inside Emacs, you may connect to this process by using "M-x slime-connect". Emacs will ask you the host and port where swank live: 

Host: 127.0.0.1
Port: 4005

RET to accept the default value. Emacs will activate SLIME:


The statement "Connected. Your hacking starts... NOW!" probably different with yours. It will be displayed randomly (some will make you laugh or at least smile). Whenever we have source code in Clojure, we can evaluate or do many things (see swank-clojure README). Here I just want to give example of evaluating current buffer. Put the source code into the new buffer, here's the example:

(defn relay [x i]
  (when (:next x)
    (send (:next x) relay i))
  (when (and (zero? i) (:report-queue x))
    (.put (:report-queue x) i))
  x)
 
(defn run [m n]
  (let [q (new java.util.concurrent.SynchronousQueue)
        hd (reduce (fn [next _] (agent {:next next}))
                   (agent {:report-queue q}) (range (dec m)))]
    (doseq [i (reverse (range n))]
      (send hd relay i))
    (.take q)))
 
(time (run 1000 1000))

(print "It's the end of the beginning")
To evaluate and run, go to the buffer, then do "C-c C-k". Here's the result:


The result will be showed in REPL:


That's all. happy hacking!



0 comments:

Posting Komentar