Notxor tiene un blog

Defenestrando la vida

Preparando Emacs para trabajar con Clojure

2022-01-08

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.

Captura-emacs-cider.png

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.

Captura-emacs-cider-ivy.png

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.

Captura-cider-evaluacion-codigo.png

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.

Captura-emacs-procesos.png

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.

Categoría: emacs clojure

Comentarios

Debido a algunos ataques mailintencionados a través de la herramienta de comentarios, he decidido no proporcionar dicha opción en el Blog. Si alguien quiere comentar algo, me puede encontrar en Mastodon y en Diaspora con el nick de Notxor.

También se ha abierto un grupo en Telegram, para usuarios de esa red.

Disculpen las molestias.