Preparando Emacs para trabajar con Clojure
Entre los propósitos del nuevo año está el aprender Clojure, incluso
tengo pensado un proyecto en el que emplearlo para aprender. Si las
cosas van bien, y no me falta tiempo, os lo iré poniendo por aquí para
enseñar mis vergüenzas como corresponde. Al empezar con el tema de
la programación con ese lenguaje, como con cualquier otro, lo primero
que he tenido que hacer es configurar mi editor favorito para ello. En
este artículo hablaré de los paquetes que he instalado y la
configuración que he hecho, todo muy sencillo. Hablaré un poco sobre:
clojure-lsp
, cider
y los primeros pasos con ellos.
clojure-lsp
sólo es necesario si utilizas el modo lsp
de Emacs,
si no quieres utilizarlo, con cider
es suficiente para convertir tu
Emacs en un IDE para Clojure. Voy a hablar de las dos
posibilidades pero empezaré por la básica.
cider
El primer paquete que encontré relacionado con Clojure fue cider
.
La instalación no puede ser más sencilla:
M-x package-install RET cider RET
Este paquete proporciona un modo menor de Emacs que nos permite la
programación interactiva, como hacemos en emacs-lisp
, o en commond
lisp
con SLIME
, o en scheme
con Geiser
, o en Smalltalk. Es
por tanto, un complemento a clojure-mode
y le dota de interacción
con una consola REPL
de Clojure donde poder probar nuestro código,
lanzar nuestra aplicación o depurarla. No se limita a establecer una
conexión a una consola y ya, sino que proporciona unas características
adicionales que nos dulcifica el trabajo con ella:
- Autocompletado
- Integración de tests
- Mensajes de error más claros
- Acceso a documentación
- Depurador interactivo
Con este modo y el clojure-mode
es suficiente para convertir Emacs
en un IDE
para Clojure.
Se puede apreciar en la imagen anterior cómo funciona: abres un
buffer de cualquier archivo Clojure y pulsando C-c C-x j j
se
lanza una consola interactiva. Se integra con projectile
y si
detecta que el fichero editado pertenece a un proyecto lo carga en la
consola completo. Si pulsamos ,
nos aparecerá la lista de comandos
en ivy
.
Además podemos evaluar cualquier código directamente. Por ejemplo, en un fichero de código he añadido la forma:
(println "El número es" (+ 1 2 3))
Tras pulsar la combinación de teclas C-c C-e
estando el cursor al
final de esa línea el resultado aparecerá en el buffer cider
, algo
parecido a cuando lo hacemos en un buffer scratch
de Emacs, o
cuando lo hacemos en SLIME
o en Geiser
.
Si estás acostumbrado a trabajar con lisp
o scheme
en Emacs, la
integración es tan similar que no necesitas adaptarte, más allá de las
idiosincrasias sintácticas de Clojure, se entiende.
La cantidad de opciones y características que trae cider
es tan
amplia que se sale del espacio de un artículo. En su página web podéis
encontrar toda la información necesaria. Me ha parecido muy
interesante el que traiga de fábrica un depurador. He mirado por
encima cómo funciona y la sorpresa ha sido que funciona exactamente
igual que el depurador que emacs-lisp
trae de fábrica... otra
funcionalidad que me suena y no debo aprender de cero.
En resumen: podemos lanzar una consola cargada con el proyecto que tengamos entre manos. Igual que la lanzamos la podemos parar. Podemos evaluar código de forma interactiva, no sólo ejecutar nuestro proyecto y ya. Además también nos permite depurar el código interactivamente. Si no es suficiente, también nos permite acceder a la documentación del lenguaje sobre la marcha. En fin, todo lo que se le puede pedir a una herramienta de desarrollo específica, pero con la integración en Emacs con todas las facilidades que da para la edición de código.
Si necesitas algo más, te lo proporcionará lsp-mode
, pero con un
gasto extra de memoria y ciclos de proceso.
lsp-mode
Ya hablé de lsp-mode
, así que sólo añadiré algún detalle a lo que ya
conté en la otra ocasión. Como sabéis, lsp
necesita para funcionar
un servidor de lenguaje externo, que suele estar hecho en el mismo
lenguaje que quieres trabajar, pues cada lenguaje suele requerir el
suyo específico. Para Clojure no hay excepción y debemos instalar el
suyo. Para no enmarañar más con detalles, sólo vamos a trabajar dos
cosas:
- Instalación de
clojure-lsp
(el servidor de lenguaje de Clojure) - Configuración de Emacs para activar
lsp-mode
. (Aunque lo haremos de dos maneras diferentes para que no dependa de instalaciones)
Servidor clojure-lsp
Como he dicho antes, este servidor es necesario para que funcione el
modo lsp
con Clojure. Es una herramienta externa y, en mi caso, he
descargado el código de su repositorio para instalarlo. No estaría de
más consultar toda la información en su página web.
Descarga del código e instalación del servidor:
cd ~/proyectos git clone https://github.com/clojure-lsp/clojure-lsp.git cd clojure-lsp ./install --dir /home/notxor/opt/bin/
Los cuatro pasos los he puesto juntos en una especie de script. En realidad me llevó algo más de tiempo: buscarlo en Internet, mirar la documentación y explicaciones de cómo instalarlo y decidir, una vez descargado, dónde instalarlo, etc. Así que, te recomiendo, si estás leyendo ésto, que en lugar de copiar el código anterior a ciegas, teniéndolo como guía. deberías consultar también las opciones para ajustarlo a tus necesidades. Pero como resumen, esas cuatro líneas, esos cuatro pasos son suficientes.
Si todo ha ido bien, tras unos instantes de espera, mientras se descarga el código, se compila y se instala ya tendremos nuestro servidor funcional. Sólo hay que tener en cuenta, que lo he instalado en un directorio local para mi usuario. Para que funcione, tengo que decirle a Emacs dónde está y cómo lanzarlo para que lo arranque cuando sea necesario.
(setq lsp-clojure-custom-server-command '("bash" "-c" "/home/notxor/opt/bin/clojure-lsp"))
Esto es importante, porque si no el modo lsp
lanzará un error que
dice que no encuentra el servidor y no puede conectarse al mismo.
Para comprobar que está funcionando, podemos solicitar la lista de
procesos de Emacs con M-x list-processes
.
En la imagen, entre los procesos con PID
que son los externos
utilizados por Emacs, nos aparecerá clojure-lsp
y también la
conexión del editor. Podemos comprobar que efectivamente, el comando
que lanza nuestro servidor es el que le proporcionamos en la variable
anterior.
Es un servidor un poco pesado para máquinas de pocos recursos. Está
hecho en Clojure y su ejecución necesita también cargar la máquina
virtual de java. Es recomendable eliminarlo si no lo estamos
usando. Recuerda cuando cierres Emacs que, según como cierres o si
estás utilizando emacsclient
, que el servidor puede permanecer
funcionando esperando conexiones. Si no lo vas a usar más, es
recomendable matar el proceso.
Para configurarlo, pongo dos versiones. Desde vanilla se necesitarán
sólo algunos hooks para iniciar el proceso para los modos
necesarios. En este caso para los modos de clojure
, clojurescript
y clojurec
. Y también el comando que lanza el servidor que vimos
antes. Debería quedar algo así:
(add-hook 'clojure-mode-hook 'lsp) (add-hook 'clojurescript-mode-hook 'lsp) (add-hook 'clojurec-mode-hook 'lsp) (setq lsp-clojure-custom-server-command '("bash" "-c" "/home/notxor/opt/bin/clojure-lsp"))
Si estamos utilizando, como en mi caso, use-package
, la
configuración es distinta. En otras distribuciones
de Emacs como doom-emacs
, por ejemplo, vienen por defecto
configuradas con use-package
. Yo utilizo GNU Emacs, pero entiendo
que sería igual para esos otros entornos:
;;; Configuración de lsp-mode (use-package lsp-mode :ensure t :defer t :init (add-hook 'clojure-mode-hook #'lsp) (add-hook 'clojurescript-mode-hook #'lsp) (add-hook 'clojurec-mode-hook #'lsp) (setq lsp-clojure-custom-server-command '("bash" "-c" "/home/notxor/opt/bin/clojure-lsp")) (add-hook 'python-mode-hook #'lsp) (add-hook 'c++-mode-hook #'lsp))
Ese bloque de código lo he copiado directamente de mi init.el
. He
dejado al final los ganchos para otros lenguajes de programación con
los que utilizo lsp-mode
, sólo para remarcar, que cada modo
necesitará su gancho, para conectarse a lsp-mode
.
Conclusión
Pues no hay mucho que concluir, de momento no he avanzado mucho más
allá. De momento no he pasado de crear un incipiente proyecto de
pruebas con la herramienta lain
, para comprobar que toda la
maquinaria funciona. Entiendo que este tipo de herramientas tienen sus
ventajas, pero te obliga a aprender una herramienta externa al
lenguaje y distinta para cada uno de ellos. La estructura de proyecto
que genera puede ser aceptable, o incluso óptima para el mayor número
de casos, pero te acostumbra a un esquema de pensamiento uniforme y te
dificulta salirte del redil cuando sea necesario. No sé, habría que
investigarlo más y no es el tema del artículo, ya siento la
disgresión de pensamiento.
Si me tropiezo con algo interesante que contar sobre el tema ya lo iré escribiendo. Con interesante me refiero, no sólo a cosas nuevas y frikis de esas que me gustan, sino también a esas más «sórdidas» que provocan las dificultades que se encuentran por el camino y cómo las superamos.
Comentarios