[Modification par un non-auteur : cette réponse date de 2010, et le processus a été considérablement simplifié depuis mai 2011. Je vais ajouter un post à cette réponse avec mes notes de configuration à partir de février 2012].
Vous aurez besoin de rassembler quelques pièces : Emacs, SLIME (qui fonctionne parfaitement bien avec Clojure - voir swank-clojure), swank-clojure (l'implémentation Clojure de la contrepartie serveur de SLIME), clojure-mode, Paredit et, bien sûr, le jar Clojure pour commencer, puis peut-être quelques extras parmi lesquels Leiningen serait peut-être le plus remarquable. Une fois que vous aurez tout mis en place, vous disposerez - dans Emacs - de toutes les fonctions de flux de travail et d'édition que vous mentionnez dans la question.
Configuration de base :
Vous trouverez ci-dessous d'excellents didacticiels qui décrivent comment configurer tout cela. Il y en a d'autres sur le Web, mais certains d'entre eux sont assez dépassés, alors que ces deux-là semblent convenir pour le moment :
-
dans lequel on trouve les astuces du métier concernant la paternité de clojure sur le blog de Phil Hagelberg ; Phil maintient swank-clojure et clojure-mode, ainsi qu'un paquet appelé Emacs Starter Kit, auquel tout nouveau venu dans le monde d'Emacs serait bien avisé de jeter un coup d'oeil. Ces instructions semblent avoir été mises à jour avec les récents changements apportés à l'infrastructure ; en cas de doute, cherchez des informations supplémentaires sur le groupe Google de Clojure.
-
Configuration de Clojure, Incanter, Emacs, Slime, Swank et Paredit sur le blog du projet Incanter. Incanter est un paquet fascinant qui fournit un DSL de type R pour les calculs statistiques, intégré directement dans Clojure. Cet article vous sera utile même si vous n'avez pas l'intention d'utiliser - ou même d'installer - Incanter.
Mettre tout cela au travail :
Une fois que vous avez mis en place tous ces éléments, vous pouvez essayer de les utiliser immédiatement, mais je vous conseille vivement de faire ce qui suit :
-
Jetez un coup d'œil au manuel de SLIME - il est inclus dans les sources et est en fait très lisible. De plus, il n'y a absolument aucune raison pour laquelle vous devriez lire le manuel complet du monstre de 50 pages ; jetez simplement un coup d'œil pour voir quelles sont les fonctionnalités disponibles.
Note : la fonctionnalité autodoc de SLIME, telle qu'elle se trouve dans les dernières sources amont, est incompatible avec swank-clojure -- ce problème ne se posera pas si vous suivez la recommandation de Phil Hagelberg d'utiliser la version ELPA (voir son billet de blog mentionné plus haut pour une explication) ou si vous laissez simplement autodoc désactivé (ce qui est l'état par défaut des choses). Cette dernière option présente un intérêt supplémentaire dans la mesure où vous pouvez toujours utiliser la dernière version de SLIME avec Common Lisp, au cas où vous l'utiliseriez également.
-
Jetez un coup d'œil aux documents relatifs à paredit. Il y a deux façons de procéder : (1) regardez la source -- il y a une grande quantité de commentaires en haut du fichier qui contiennent toutes les informations dont vous aurez probablement besoin ; (2) tapez C-h m dans Emacs lorsque paredit-mode est actif -- un tampon apparaîtra avec des informations sur le mode majeur actuel suivi d'informations sur tous les modes mineurs actifs (paredit est l'un d'entre eux).
Mise à jour : Je viens de trouver cet ensemble de notes cool sur Paredit par Phil Hagelberg... Il s'agit d'un lien vers un fichier texte. Je me souviens avoir vu quelque part un bel ensemble de diapositives contenant ces informations, mais je ne parviens pas à le retrouver. Quoi qu'il en soit, c'est un bon résumé de la façon dont cela fonctionne. Je ne peux plus me passer de Paredit maintenant et ce fichier devrait vous permettre de commencer à l'utiliser très facilement, je pense :-).
-
En fait, le C-h m vous renseignera sur toutes les combinaisons de touches actives au niveau de SLIME REPL, en mode clojure (vous voudrez vous souvenir de C-c C-k pour envoyer le tampon courant à la compilation) et en fait dans n'importe quel tampon Emacs.
Pour ce qui est de charger le code à partir d'un fichier et de l'expérimenter ensuite dans le REPL, utilisez la fonction C-c C-k pour compiler le tampon actuel, puis use
ou require
son espace de nom dans le REPL. Ensuite, faites vos expériences.
Notes finales :
Préparez-vous à devoir ajuster les choses pendant un certain temps avant que tout ne se mette en place. Il y a beaucoup d'outils impliqués et leurs interactions sont généralement assez fluides, mais pas au point de ne pas avoir à faire quelques ajustements au début.
Enfin, voici un bout de code que je conserve dans .emacs
que vous ne trouverez pas ailleurs (bien qu'elle soit basée sur une fonction sympa de Phil Hagelberg). J'alterne entre le démarrage de mes instances de luxe avec lein swank
(l'une des caractéristiques les plus agréables de Leiningen) et en utilisant la fonction clojure-project
comme indiqué ci-dessous pour démarrer le tout depuis Emacs. J'ai fait de mon mieux pour que cette dernière produise un environnement correspondant étroitement à celui fourni par la fonction lein swank
. Oh, et si vous voulez juste un REPL dans Emacs pour une expérience rapide et sale, alors avec la configuration correcte vous devriez pouvoir utiliser M-x slime directement.
(setq clojure-project-extra-classpaths
'(
; "deps/"
"src/"
"classes/"
"test/"
))
(setq clojure-project-jar-classpaths
'(
; "deps/"
"lib/"
))
(defun find-clojure-project-jars (path)
(apply #'append
(mapcar (lambda (d)
(loop for jar in (remove-if (lambda (f) (member f '("." "..")))
(directory-files d t))
collect jar into jars
finally return jars))
(remove-if-not #'file-exists-p
clojure-project-jar-classpaths))))
(defun find-clojure-jar (jars)
(let ((candidates
(remove-if-not
(lambda (jar)
(string-match-p "clojure\\([0-9.-]+\\(SNAPSHOT|MASTER\\)?\\)?\\.jar$" jar))
jars)))
(if candidates
(car candidates)
(expand-file-name "~/.clojure/clojure.jar"))))
(defun find-clojure-contrib-jar (jars)
(let ((candidates
(remove-if-not
(lambda (jar)
(string-match-p "clojure-contrib\\([0-9.-]+\\(SNAPSHOT|MASTER\\)?\\)?\\.jar$" jar))
jars)))
(if candidates
(car candidates)
(expand-file-name "~/.clojure/clojure-contrib.jar"))))
;;; original due to Phil Hagelberg
;;; (see `Best practices for Slime with Clojure' thread on Clojure Google Group)
(defun clojure-project (path)
"Sets up classpaths for a clojure project and starts a new SLIME session.
Kills existing SLIME session, if any."
(interactive (list (ido-read-directory-name
"Project root:"
(locate-dominating-file default-directory "pom.xml"))))
(when (get-buffer "*inferior-lisp*")
(kill-buffer "*inferior-lisp*"))
(cd path)
;; I'm not sure if I want to mkdir; doing that would be a problem
;; if I wanted to open e.g. clojure or clojure-contrib as a project
;; (both lack "deps/")
; (mapcar (lambda (d) (mkdir d t)) '("deps" "src" "classes" "test"))
(let* ((jars (find-clojure-project-jars path))
(clojure-jar (find-clojure-jar jars))
(clojure-contrib-jar (find-clojure-contrib-jar jars)))
(setq swank-clojure-binary nil
;; swank-clojure-jar-path (expand-file-name "~/.clojure/clojure.jar")
swank-clojure-jar-path clojure-jar
swank-clojure-extra-classpaths
(cons clojure-contrib-jar
(append (mapcar (lambda (d) (expand-file-name d path))
clojure-project-extra-classpaths)
(find-clojure-project-jars path)))
swank-clojure-extra-vm-args
(list (format "-Dclojure.compile.path=%s"
(expand-file-name "classes/" path)))
slime-lisp-implementations
(cons `(clojure ,(swank-clojure-cmd) :init swank-clojure-init)
(remove-if #'(lambda (x) (eq (car x) 'clojure))
slime-lisp-implementations))))
(slime))