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
chocolate
1 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:
:
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
Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.
Notas:
Para ver la «paleta de colores» de Emacs, y los nombres de cada color, podemos llamar a la función list-colors-display