Cuaderno de GNUtas

Resaltando cosas en Emacs (con hi-lock y demás)

A veces podemos desear que ciertas palabras o pasajes de texto se resalten con un color determinado en Emacs, siguiendo patrones definidos. Nuestro polifacético editor ofrece para ello muchos y variados recursos. Describiré aquí un poco los que yo más suelo usar en mi trabajo.

Un resaltado permanente con la función ’font-lock-add-keywords’

La función font-lock-add-keywords nos permite anclar a un modo determinado una lista de expresiones regulares, con objeto de que se resalten según las escribamos dentro de ese modo. Por ejemplo: imaginemos que queremos resaltar en el color que Emacs denomina chocolate1 pequeños pasajes de texto (unas pocas palabras que, por norma general, no abarquen más de dos líneas) entre estos signos <<...>>. Primero, debemos definir una variable y asignarle un valor de face, y a su vez aplicarle a éste un color de letra:

(defvar anotacion (make-face 'anotacion))
(set-face-foreground 'anotacion "chocolate")

Y, acto seguido, incluimos esta variable en font-lock-add-keywords, anclada a (por ejemplo) el Org Mode, y asociada a nuestra expresión regular.

(font-lock-add-keywords
   'org-mode
   '(("<<\\(.+\\)>>" 0 anotacion)))

Debemos, por último, reiniciar Emacs para que los cambios surtan efecto. Así, cuando en lo sucesivo estemos dentro de Org Mode y escribamos algo entre <<...>>, ese pasaje se resaltará de manera instantánea.

Resaltar cosas de manera local

Con ’highlight-regexp’

Si queremos que los pasajes a resaltar se limiten sólo a ciertos documentos, y de forma provisional, lo más fácil es recurrir a la función del hi-lock-mode llamada highlight-regexp. Basta con que llamemos a la función de manera interactiva y se nos pedirá insertar el regexp a resaltar así como el color del resaltado, que debemos escoger entre una pequeña lista. El resaltado lo podemos eliminar desactivando hi-lock-mode aunque, en cualquier caso, no se conservará cuando cerremos el documento. Y si pretendemos exactamente lo contrario, es decir, que el resaltado sea permanente, pero sólo en ese documento, bastaría con añadir una variable local. Nuevo ejemplo: imaginemos que queremos resaltar en un documento LATEX todos los pasajes escritos en griego, ya sea mono o politónico. Insertaremos al principio del documento una variable local que evalúe highlight-regexp así:

% -*- eval: (highlight-regexp "\\([\u1F00-\u1FFE\u0370-\u03FF]+\\)" 'hi-red-b) -*-

Es decir, indicamos que cualquier carácter en el documento que pertenezca a los rangos unicode «griego básico» y «griego extendido» ha de resaltarse en el color que hi-lock-mode tiene definido como hi-red-b. Incluso podemos complicar las cosas más, y antojársenos otro resaltado distinto para los pasajes en cirilico. De modo que a nuestra variable local le sumamos otra con el rango Unicode correspondiente. Ambas variables, pues, nos quedarían así:

% -*- eval: (highlight-regexp "\\([\u1F00-\u1FFE\u0370-\u03FF]+\\)" 'hi-red-b); eval: (highlight-regexp "\\([\u0400-\u04FF]+\\)" 'hi-pink); -*-

Con overlays

Me gusta utilizar a menudo el recurso de los overlays (capas superpuestas al texto «real» del búfer, siempre transitorias, con propiedades gráficas y textuales). Siguiendo con el ejemplo del griego, escribí esta simple función que colorea en rojo (mediante overlays) los pasajes que estén en ese sistema de escritura:

(defun resalta-griego ()
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while
        (re-search-forward "\\([··\u1F00-\u1FFE\u0370-\u03FF]+\\)" nil t)
      (let
          ((x (match-string 1))
           (ov (make-overlay (match-beginning 0) (match-end 0))))
        (overlay-put ov 'griego t)
        (overlay-put ov 'display (propertize (format "%s" x) 'font-lock-face '(:foreground "red" :weight bold)))))))

Y para eliminar el resaltado, esta otra función que «mata» el overlay:

(defun desresalta-griego ()
  (interactive)
  (remove-overlays nil nil 'griego t))

La desventaja que tiene este método respecto al anterior es que el texto resaltado no es editable mientras el overlay permanezca encima, así que mejor reservarla para textos de sólo lectura. La ventaja, por contra, está en que podemos crear el resaltado de muchas más formas y colores, con otra fuente o familia de fuentes, con subrayado, entre recuadros, etc. Todos los atributos textuales, en fin, que nos permite definir font-lock-face. Como se ve en mi función, el resaltado es en rojo y en negrita.

Resaltado anclado a un sub-árbol de Org Mode

Nuestro resaltado también puede ceñirse no a todo el documento sino a un sólo subárbol de Org. ¿Cómo? Fácil: sólo tenemos que crear una etiqueta personalizada mediante org-map-entries. Por seguir en el caso del griego y de la función anterior de los overlays, podemos evaluar este código en un bloque de Org:

(org-map-entries
     (lambda ()
       (save-restriction
         (save-excursion
           (org-narrow-to-subtree)
           (resalta-griego))))
     "griego")

Y probar que el resaltado sólo se lleva a cabo en el encabezado que incluye la etiqueta :griego::

org-map-entries1.gif

Como vemos que la cosa funciona, ya sólo nos queda definir una función y anclarla al Org Mode:

(defun org-resalta-griego ()
    (interactive)
    (org-map-entries
     (lambda ()
       (save-restriction
         (save-excursion
           (org-narrow-to-subtree)
           (resalta-griego))))
     "griego"))

 (add-hook 'org-mode-hook 'org-resalta-griego)

Publicado: 06/12/2019

Última actualización: 16/08/23


Índice general

Acerca de...

Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.

Notas:

1

Para ver la «paleta de colores» de Emacs, y los nombres de cada color, podemos llamar a la función list-colors-display

© Juan Manuel Macías
Creado con esmero en
GNU Emacs