Configurar Emacs usando emacs-lisp (0x0005)
§Introducción
Hoy vamos a agregar algunas configuraciones a nuestro emacs de ejemplo.
Agregaremos un par de paquetes que a mi parecer son bastante útiles:
vertico
orderless
Y lo haremos de dos maneras distintas, aunque muy similares.
§¿Qué es todo esto?
Hay varias formas de configurar paquetes en emacs, desde copiar los archivos de código fuente directo a un directorio y agregar ese directoria a la load-path
, hasta utilizar otros paquetes para instalar paquetes (sí, suena redundante, pero funciona).
En este video veremos un par de opciones para instalar paquetes con package.el
y configurarlos utilizando únicamente emacs-lisp
(nada de use-package
, leaf
, et. al.).
Básicamente hay dos maneras de instalar tus paquetes: lo que llamo el modo «tradicional», en donde encapsulas la instalacón y configuración de tu paquete en un bloque/archivo de código; y una manera que llamo «global», en que en distintas partes de tu código instalas los paquetes y en otra los configuras (ya sea distintos bloques o distintos archivos).
§Vamos al código fuente
Quien quiera acceder a esta sección sin toda la demás explicación y discusión (previa y posterior), puden acceder a él en la siguiente dirección: https://codeberg.org/barocio/emacs-config-examples/src/branch/0x0005/0x0005.
§Configurar y activar package.el
§Encabezado de init-pkg.el
;;; init-pkg.el -- Configuración de package.el -*- lexical-binding:t -*-
§Configuración
Esto es importante para poder instalar paquetes en emacs. Por supuesto, no es la única manera de instalarlos, pero es la que viene por default en emacs y es la que voy a estar recomendando, sin menospreciar otros poderosos métodos que pudieran existir (straight.el
, elpaca.el
, etc.).
- Repositorios
Primero que nada tenemos que ver de dónde obtenemos los paquetes, es decir, los repositorios de paquetes de emacs.
;;; Package (require 'package) ;; Agregamos algunos repositorios de paquetes (unless (and (boundp 'package-archives) (version< emacs-version "28")) ;; Argegamos este repositorio sólo si no está ya agregado. Algunas ;; versiones de emacs traen ya por sí mismas este repositorio (creo ;; que apartir de la versión 28 de emacs). (add-to-list 'package-archives '("nongnu" . "https://elpa.nongnu.org/nongnu/"))) (add-to-list 'package-archives '("stable" . "https://stable.melpa.org/packages/")) (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
- Precedencia
Ahora, configuraremos de dónde tomará los paquetes, en caso de que estén presentes en más de un repositorio.
;; Customizamos la prioridad de los repositorios de paquetes ;; (setopt package-archive-priorities ; Esta macro está disponible a ; partir de emacs 29 (customize-set-variable 'package-archive-priorities '(("gnu" . 99) ; Preferimos los paquetes de GNU elpa; ("nongnu" . 80) ; Usemos paquetes de non-gnu ; packages si no los podemos ; encontrar en GNU elpa; ("stable" . 70) ; Preferimos versiones "liberadas" de melpa; ("melpa" . 0))) ; Si todo lo demás falla, ; tratamos de obtener ; versiones "no liberadas" ; de melpa.
- Inicialización
Finalmente preparamos todo para que funcione sin problemas.
;; Preparamos todo para instalar paquetes. (package-initialize) ; Inicializamos el repositorio de paquetes. (unless package-archive-contents ; Verificamos si la lista de paquetes está vacía. (package-refresh-contents)) ; Actualizamos la lista de paquetes ; (sólo si está vacía).
Una nota final: Es importante recordar que
package-refresh-contents
es un comando (se puede ejecutar desdeM-x
) y debe actualizarse con cierta frecuencia. ¿Con qué tanta frecuencia? Yo lo hago cada vez que trato de instalar un paquete nuevo y me dice que no existe, o cuando al intentarpackage-upgrade-all
me da errores similares. Otros actualizan cada semana, cada mes… no hay una relga al respecto.
§Cierre de init-pkg.el
;;; init-pkg.el ends here
§Modo «tradicional»
§Encabezado del archivo init-trad.el
Esto no es absolutamente necesario, pero es muy recomendable incluirlo al inicio de cualquier archivo código fuente de emacs-lisp
. Aquí indicamos el nombre del archivo, una muy, muy, muy breve descripción y activamos los lexical-bindings
, que son una forma de decirle al intérprete de emacs-lisp
cómo ejecutar este código, en particular que ligue los nombres de variables y funciones a su contexto léxico.
;;; init-trad.el --- Archivo de configuración de emacs -*- lexical-binding:t -*- ;;; 0x0004 (package-install 'beacon) (beacon-mode +1) (package-install 'evil) (evil-mode +1) (package-install '0x0) (package-install 'doom-themes) (load-theme 'doom-monokai-pro t) (disable-theme 'wombat)
§Configurar y activar vertico
He elegido vértico precisamente porque es muy sencillo de configurar: sólo basta instalarlo y activar el modo.
;;; Vertico ;; Instalamos el paquete. (package-install 'vertico) ;; Activamos el modo. (vertico-mode +1)
Eso es todo.
§Configurar y activar orderless
Orderless es un paquete que se puede configurar de manera avanzada.
Comencemos por instalarlo:
;;; Orderless ;; Instalamos el paquete. (package-install 'orderless)
Ahora configuraremos algunas variables que modifican su funcionamiento:
;; Con esta opción activamos el uso del paquete (customize-set-variable 'completion-styles '(orderless)) ;; (setopt completion-styles '(orderless)) ;; Elegimos algunas opciones para la búsqueda, selección y filtrado de opciones. (customize-set-variable 'orderless-matching-styles '(orderless-regexp)) ;; (setopt orderless-matching-styles '(orderless-regexp))
Ahora podemos extender su funcionalidad:
;; Completa con las letras iniciales de la función/variable/objeto/símbolo. (defun first-initialism (pattern index total) "Completes with the first letter of the function/variable/object/symbol." (if (= index 0) 'orderless-initialism)) ;; Esto nunca lo entendí (defun flex-if-twiddle (pattern index total) "Removes the pattern folowing a literal `~' from completions." (when (string-suffix-p "~" pattern) `(orderless-flex . ,(substring pattern 0 -1)))) ;; Elimina de las complesiones las opciones que coincidan con lo que siga de la exclamación. (defun without-if-bang (pattern index total) "Removes the pattern folowing a literal `!' from completions." (cond ((equal "!" pattern) '(orderless-literal . "")) ((string-prefix-p "!" pattern) `(orderless-without-literal . ,(substring pattern 1))))) ;; Activamos las opciones extra para `orderless'. (customize-set-variable 'orderless-style-dispatchers '(first-initialism flex-if-twiddle without-if-bang))
Para una expliación más completa, puedes ver el video de Andrew Tropin «Emacs Completion Explained».
§Finalización del archivo init-trad.el
Esta parte tampoco es necesaria, pero es una buena práctica indicar dónde termina el código del archivo. No tiene ningún efecto sobre el intérprete, pero es una manera de mantener un poco de órden mental. Aún más, cuando comencemos a extraer código de nuestro init.el
y lo coloquemos en otros archivos, esta pieza de código, este comentario y el primero que pusimos en el archivo serán muy útiles.
;;; init-trad.el ends here
§Configuración directa, todos los paquetes a la vez.
Hay una manera de seleccionar los paquetes que se utilizarán e instalarlos de una sola vez. Por supuesto, esto requiere que se configure package.el
.
§Encabezado del archivo init-alt.el
Esto no es absolutamente necesario, pero es muy recomendable incluirlo al inicio de cualquier archivo código fuente de emacs-lisp
. Aquí indicamos el nombre del archivo, una muy, muy, muy breve descripción y activamos los lexical-bindings
, que son una forma de decirle al intérprete de emacs-lisp
cómo ejecutar este código, en particular que ligue los nombres de variables y funciones a su contexto léxico.
;;; init-alt.el --- Archivo de configuración de emacs -*- lexical-binding:t -*-
§Seleccionar paquetes
;;; Selección e instalación de paquetes
Para seleccionar paquetes símplemente los agregamos a una lista especial.
;; Selección de paquetes ;;; 0x0004 (add-to-list 'package-selected-packages 'beacon) (add-to-list 'package-selected-packages 'evil) (add-to-list 'package-selected-packages '0x0) (add-to-list 'package-selected-packages 'doom-themes) ;;; 0x0005 (add-to-list 'package-selected-packages 'vertico) (add-to-list 'package-selected-packages 'orderless)
§Instalar los paquetes seleccionados
;; Instalación de paquetes (package-install-selected-packages :noconfirm)
§Configurar paquetes
;;; Configurar paquetes ;;; 0x0004 (beacon-mode +1) (evil-mode +1) (load-theme 'doom-monokai-pro t) (disable-theme 'wombat)
- Vertico
;; Vertico (vertico-mode +1)
- Orderless
orderless
Orderless es un paquete que se puede configurar de manera avanzada.
;; Orderless
Ahora configuraremos algunas variables que modifican su funcionamiento:
;; Con esta opción activamos el uso del paquete (customize-set-variable 'completion-styles '(orderless)) ;; (setopt completion-styles '(orderless)) ;; Elegimos algunas opciones para la búsqueda, selección y filtrado de opciones. (customize-set-variable 'orderless-matching-styles '(orderless-regexp)) ;; (setopt orderless-matching-styles '(orderless-regexp))
Ahora podemos extender su funcionalidad:
;; Completa con las letras iniciales de la función/variable/objeto/símbolo. (defun first-initialism (pattern index total) "Completes with the first letter of the function/variable/object/symbol." (if (= index 0) 'orderless-initialism)) ;; Elimina de las complesiones las opciones que coincidan con lo que siga de la exclamación. (defun without-if-bang (pattern index total) "Removes the pattern folowing a literal `!' from completions." (cond ((equal "!" pattern) '(orderless-literal . "")) ((string-prefix-p "!" pattern) `(orderless-without-literal . ,(substring pattern 1))))) ;; Activamos las opciones extra para `orderless'. (setq orderless-style-dispatchers '(first-initialism without-if-bang))
§Finalización del archivo init-alt.el
Esta parte tampoco es necesaria, pero es una buena práctica indicar dónde termina el código del archivo. No tiene ningún efecto sobre el intérprete, pero es una manera de mantener un poco de órden mental. Aún más, cuando comencemos a extraer código de nuestro init.el
y lo coloquemos en otros archivos, esta pieza de código, este comentario y el primero que pusimos en el archivo serán muy útiles.
;;; init-alt.el ends here
§Archivo principal
Este sería el archivo de configuración init.el
.
;;; init.el --- Archivo de configuración de emacs -*- lexical-binding:t -*- ;;; 0x0003 -- Una configuración minimalista -- algo para comenzar (load-theme 'wombat t) (set-face-attribute 'default nil :height 160) ;; Pasamos un valor negativo a la función `menu-bar-mode'. (menu-bar-mode -1) ;; Pasamos un valor negativo a la función `tool-bar-mode'. (tool-bar-mode -1) ;; Pasamos un valor negativo a la función `scroll-bar-mode' (scroll-bar-mode -1) (setq inhibit-splash-screen t user-full-name "Alex Barocio") (setq visible-bell t) ;;; 0x0004 -- Instalar paquetes en Emacs ;; Cambiar donde se guardan las customizaciones (setq custom-file (expand-file-name "custom.el" user-emacs-directory)) (add-hook 'emacs-startup-hook (lambda () (when (file-exists-p custom-file) (load-file custom-file)))) ;; Modificado en 0x0005: se extrajo y ampiló la configuración de ;; `package' en su propio archivo. (load-file (expand-file-name "init-pkg.el" user-emacs-directory)) ;;; 0x0005 -- Configurar Emacs usando emacs-lisp ;; (load-file (expand-file-name "init-trad.el" user-emacs-directory)) (load-file (expand-file-name "init-alt.el" user-emacs-directory)) ;;; init.el ends here
§Comentarios
Al no utilizar use-package
(ni ninguna otra macro) tenemos algunas ventajas y otras desventajas, como en (casi) todo.
§Ventajas
- La mayoría de las configuraciones no necesitan de la macro
use-package
. - Promueve un conocimiento más claro de lo que se puede hacer con
emacs-lisp
. - No agrega paquetes extra (bloated software).
- Para configuraciones pequeñas es sencillo y rápido.
§Desventajas
- Las dependencias de configuración entre paquetes puede ser difícil de lograr.
- No todos los usuarios de emacs les gusta programar.
- Muchos desarrolladores de paquetes sugieren el uso de la macro
use-package
para configurar sus paquetes. - Para configuraciones grandes, es fácil perderse entre todo el código si no se tiene cuidado de mantenerlo ordenado.
- Con configuraciones grandes es fácil que el arranque se vuelva lento.
§Conclusión
En realidad depende del tipo de configuración que tengas y el tipo de usuario que seas.
Te recomiendo que experimentes con distintos estilos de configuración (sí, incluyendo la interfaz customize
), y elijas la que más te agrade o te convenga.
En emacs hay más de una forma de hacer las cosas, si es la adecuada o correcta dependerá de tu caso particular, tus habilidades y modo de trabajo.
§¿Y ahora qué?
En el próximo video veremos otra forma de configurar un paquete por medio de use-package
.
Puedes acceder a mis notas en mi repositorio: https://git.sr.ht/~abarocio80/videos/tree/master/item/content/0x0005--configurar-emacs-usando-emacs-lisp.org
O en mi página: https://barocio.cc/videos/0x0005--configurar-emacs-usando-emacs-lisp.html
Si te interesa este tipo de contenido, suscríbete al canal y activa las notificaciones para que (tarde o temprano) te enteres de los nuevos videos que vaya subiendo.
Nos vemos luego.