Creando un modo menor, sencillo y sin muchas pretensiones
Para seguir con el cursillo de elisp voy a crear un nuevo modo.
Va a ser un minor mode
, es decir, un modo que se puede activar como
secundario a otros modos generales. Lo primero que necesito es un
fichero que guarde el código en él y que se cargue desde la
configuración de Emacs.
Crear el fichero de modo
Tengo la costumbre de ir metiendo todos mis proyectos en un directorio
con ese nombre dentro de mi directorio home
. Es decir, voy a crear
un directorio de proyecto que me sirva para trabajar programando.
Obvio aquí toda la configuración de git
o cualquier otra herramienta
de programación que se utilice de manera externa al propio Emacs.
El resultado final es crear un fichero que se llamará
~/proyectos/datos-mode/datos-mode.el
Para que lo cargue Emacs cuando arranque, debemos definir algunas
cosas en el fichero init.el
:
;; Configuración de prueba de creación de datos-mode (add-to-list 'load-path "~/proyectos/datos-mode") (require 'datos-mode)
He añadido básicamente dos instrucciones: la primera añade a la lista
de paths
el lugar donde guardo el fichero; la segunda solicita
cargar el modo datos-mode
. Bien, muy bonito, pero de momento carga
en vacío. ¿Qué código tengo que meter en el fichero datos-mode
para que funcione?
De momento, cargo el siguiente código, que me sirve como plantilla de modos:
;; Definición del modo menor (define-minor-mode datos-mode "Toggle Datos mode. Interactivamente sin argumento, este comando des/activa el modo." ;; El valor inicial. nil ;; Indicador de modo en la línea. " Datos") ;; Informa que este fichero proporciona el modo datos-mode (provide 'datos-mode)
La primera forma, define-minor-mode
, es la que crea el modo. Sin
entrar en todas las opciones que soporta, de momento vemos que le
decimos que comience desactivado con nil
y que el nombre que
aparecerá en la línea de estado será " Datos"
. Hay que remarcar el
espacio inicial para que no se pegue al modo que se liste antes.
La segunda forma, provide
, es el espejo del require
que hemos
puesto en el init.el
, le informa a Emacs que el modo requerido en
la configuración lo proporciona nuestro fichero o paquete.
Podemos mejorarlo si en lugar de utilizar el modo posicional, utilizamos los nombres de los argumentos:
(define-minor-mode datos-mode "Toggle Datos mode. Interactivamente sin argumento, este comando des/activa el modo." ;; El valor inicial. :init-value nil ;; Indicador de modo en la línea. :lighter " Datos")
Algo de contenido para probar
Vale, muy bonito todo, pero tengo un modo que no hace nada. Eso sí, si
recargo Emacs resulta que puedo llamar hacer M-x datos-mode
y me
aparece el modo en la línea de estado.
Pero aún no hace nada y eso no sirve de mucho, vamos a hacer que tener
instalado nuestro «modo» en el sistema sirva de algo. Algo que suelo
necesitar bastante cuando trasteo con los datos es introducir el día
de la fecha, normalmente en formato ISO. Entre las formas
define-minor-mode
y provide
defino una función que me ayude a
introducir la fecha con un comando:
(defun escribe-dia () "Escribe el día de la fecha en el lugar del punto." (interactive) (insert (format-time-string "%Y-%m-%d")))
Si recargamos Emacs podemos llamar a M-x escribe-dia
y en el lugar
donde esté el cursor escribirá 2019-02-15
, utilizando la forma
insert
después de llamar a format-time-string
con una cadena de
formato concreta, la ISO, se pueden consultar los formatos que vienen
en el manual por si nos viniera mejor otro formato. Todo esto está muy
bien, pero tampoco es una mejora sustancial... ¿qué tendría que hacer
si necesito escribir la fecha en modo largo, o europeo, o americano?
¿Puedo hacer que la función me pregunte cómo quiero la salida en lugar
de una función para cada formato de los que uso? La respuesta es sí,
pongo el código y lo explico más despacio:
(defun escribe-dia (&opcional cadena-formato) "Escribe el día de la fecha en lugar del punto." (interactive "P\nsCadena de formato: ") (if (> (length cadena-formato) 0) (insert (format-time-string cadena-formato)) (insert (format-time-string "%Y-%m-%d"))))
Analizando los cambios entre las dos versiones. Lo primero que puede
llamar la atención es el uso de &opcional
en los argumentos, lo que
hace que cadena-formato
pueda existir o no. Si no existe o es una
cadena vacía ""
, se llama a la función con el formato.
Lo siguiente que llama la atención es cómo está escrita la forma
interactive
donde se añade una cadena que puede parecer un tanto
extraña. Así que ahí va elemento a elemento: P
indica que es
interactivo y admite un argumento que proporcionará el usuario. \n
equivale a pulsar <RET>
cuando interactuamos. s
especifica que el
argumento será una cadena (string
). Y por último una cadena que
funciona como prompt de la función.
A continuación se evalúa si cadena-formato
tiene contenido y si es
así se lo pasará a la función; en caso contrario, se utiliza una
cadena de formato que devuelve la cadena en formato ISO.
Si ahora recargamos Emacs y llamamos a la función escribe-dia
nos
aparecerá el mensaje Cadena de formato: en el buffer y podemos
meter cualquier texto en él. Por ejemplo, si introduces a %d de %B de
%Y
devolverá una cadena como a 15 de febrero de 2019
. Si no
introducimos ninguna cadena, el prompt devolverá una vacía y la
función utilizará la que hemos puesto por defecto.
Conclusión
Un pequeño paso hacia hacer un modo. Hay algunos problemas que nos
podemos encontrar y muchas cosas por hacer aún. No sólo en el modo
sino también en nuestra función de insertar fecha, si hay algo que
puede fallar es la cadena que el usuario introduzca en nuestra
función, aunque en realidad lo que hará insert
será introducir «la
mejor cadena posible.
Comentarios