Notxor tiene un blog

Defenestrando la vida


Comandos, módulos, marca, punto y otras zarandajas

Hasta ahora hemos venido trabajando directamente en el buffer *scratch* y todo ha ido funcionando bien, aunque nuestras funciones y llamadas eran más bien efímeras. En este artículo vamos a guardar el código, por primera vez, en un módulo, librería, fichero, o como lo queráis llamar.

Tradicionalmente los ficheros que nos sirven de librerías o módulos, para marcarlos como elisp, llevan una extensión .el. Cargar uno de esos módulos o librerías se puede hacer de muchas maneras. Por ejemplo, Emacs cuando se inicia busca el código en el fichero especial init.el. Si queremos que nuestro código esté siempre accesible, ese es el lugar apropiado para configurarlo. No voy a entrar ahora a detallar cómo hacer un módulo para establecer un modo de Emacs, me quedaré en algo más básico: crear un par de funciones interactivas o comandos que nos permitan llamarlas desde el minibuffer con M-x.

Un poco de código en un fichero

Voy a poner un ejemplo sencillo, y por tanto inútil, de lo que puede representar un módulo o librería. Supongamos que quiero solucionar un problema, acelerando la inserción de etiquetas en mis ficheros html. Concretamente las etiquetas de negrita, que es muy cansado escribir <b></b> cada vez que toca. Lo suyo además es que me deje el cursor, lo que en emacs se llama punto, situado entre las etiquetas para escribir cómodamente lo que sea. Veamos el siguiente código:

(defun insertar-etiqueta-negrita ()
  "Inserta un par de etiquetas <b></b> en el punto del cursor."
  (interactive)
  (insert "<b></b>")
  (backward-char 4))

Definimos una función llamada insertar-etiqueta-negrita que hace justo lo que dice su cadena de documentación. Es una función sencilla y no necesitará que se le introduzcan datos a través de parámetros, por eso su lista de parámetros está vacía. Lo primero que vemos en el cuerpo de la función es interactive, una forma especial que hace que nuestra función se convierta en un comando al que se le puede llamar desde M-x. La siguiente forma insert insertará la cadena que queremos, en nuestro caso, la cadena contiene las etiquetas de apertura y cierre de negrita en html. Por último le decimos que retrase el punto cuatro caracteres para que se quede entre ambas. Bien, ese código lo vamos a guardar en un fichero que podemos llamar, por ejemplo, negrita.el.

Una vez guardado, sin haber evaluado el código si pulsamos M-x y llamamos a insertar-etiqueta-negrita nos dará un error. El sistema no encontrará dicha función. ¿Cómo puedo cargarla desde el fichero? Podríamos por ejemplo, abrir el fichero y evaluar el código, pero lo que nos facilita el proceso es que con load-file emacs hace las dos cosas sobre la marcha. Así si utilizamos M-x load-file y le decimos que cargue el fichero negrita.el, automágicamente tendremos disponible nuestra función.

Vamos a seguir con el ejemplo un poco... Vamos a suponer que se da el siguiente caso: ya he escrito todo el texto que debería ir en negrita y no he escrito las etiquetas, porque soy así de torpe. Lo puedo solucionar de dos maneras. La primera sería escribirlas manualmente al principio y al final. La segunda escribir las dos etiquetas juntas en un extremo y corto-pegar la otra en el otro... o una tercera, teniendo como tenemos el poder en la punta de los dedos, escribir una función que lo haga por mí. La forma debería escribir en el inicio la etiqueta <b> y en el final la etiqueta </b>. Veamos el siguiente código:

(defun marcar-negrita-region (inicio fin)
  "Inserta una marca <b></b> en torno a una región."
  (interactive "r")
  (save-excursion
    (goto-char fin)   (insert "</b>")
    (goto-char inicio) (insert "<b>")))

Vemos una función marcada como interactive, aunque es un poco distinta a la anterior, lleva aparejada una "r" para marcar que es de una clase especial. La forma interactive tiene varios códigos según lo que se quiera hacer con ella. Si miramos qué es lo que significa esa r en el enlace anterior nos dirá que se utilizarán el punto y la marca como parámetros para la función.

El punto he dicho ya que es la posición del cursor dentro del buffer, pero ¿qué es la marca? La marca es otro valor que está en el buffer, lo activamos con el comando set-mark-command, normalmente asociada a la combinación C-<SPC>, para marcar el texto que se sitúe entre los dos valores.

Bien, la siguiente forma que nos encontramos es save-excursion. Básicamente lo que hace es guardar los valores de posición del cursor ─o punto─ para poder recuperarlo y dejarlo como estaba aunque en su cuerpo se mueva el mismo, como hacemos con las llamadas a goto-char. En esta función, lo que se hace es saltar al final, proporcionado por el argumento fin para introducir la etiqueta de cierre de negrita y luego al inicio para introducir la etiqueta de comienzo de negrita. Cuanto save-excursion termina, tanto el punto como la marca están en el sitio que tenían antes de llamar a nuestra función.

Si hemos guardado el código en nuestro fichero, lo podemos recargar de nuevo llamando al comando load-file y nuestra nueva función estará disponible.

Alguien dirá que no hemos avanzado mucho: en lugar de escribir <p></p> tenemos que escribir M-x nombre-de-la-función, que es bastante más largo, así que no hemos ganado nada. Se olvidan que podemos establecer en nuestro código los atajos que queramos. Es habitual que en emacs se dejen las combinaciones de C-c para este tipo de cosas. Cada modo utiliza los suyos, y vemos que según el tipo de archivo que estemos editando C-c C-c, la combinación de teclas superocupada hace cosas distintas. En nuestro caso, podemos por ejemplo establecer los siguientes atajos en el código:

;; Asignación de combinaciones de teclas globales
(global-set-key (kbd "C-c b") 'insertar-etiqueta-negrita)
(global-set-key (kbd "C-c B") 'marcar-negrita-region)

Conclusión

Ha sido un repaso muy rápido a las funciones que vamos a emplear como comandos de nuestros programas. Pero los conceptos, ─dados así a grandes rasgos─, son sencillos de entender.


Comentarios