Cuaderno de GNUtas

Revoltijo Elisp (IV)

Resaltar y/o plegar notas al pie en Org

Como ya he dicho más de una vez, uso Org Mode para escribir (entre otras cosas) y también para intentar poner un orden (esa gran utopía) en lo que escribo. Sobre este último extremo, uno de los frentes que se me iba resistiendo algo más era el de organizar las notas al pie. Veamos. Por un lado no soy muy dado a abusar de notas al pie, una de las grandes plagas del academicismo. Creo que lo que se debe decir debe decirse en el texto, y no escribir dos textos que discurran en paralelo, uno arriba y otro abajo. Pero alguna que otra no me queda más remedio que escribir, me temo1. Por otra parte, Org Mode gestiona razonablemente bien todo lo referente a las notas, pero mi problema es que tiendo a usar muy a menudo la opción fnlocal, que sitúa las notas por grupos lo más cerca posible del párrafo que voy escribiendo, en lugar de hacerlo todas juntas bajo un encabezado al final del documento. Me resulta mucho mantener las notas así, ya que muevo mucho los encabezados y sub-árboles entre documentos, y si las notas no están «pegadas» al párrafo o rondando por ahí cerca (ergo, dentro del sub-árbol que muevo), se me acaban quedando por el camino. Dicho lo cual, echaba de menos una forma de resaltar los cuerpos de notas al igual que los bloques de código. Y, como éstos, también la posibilidad de plegarlos para que no estorben. Así pues, me decidí a escribir una serie de funciones como apaño. Estas funciones hacen uso de los overlays de Emacs, o capas temporales con propiedades de texto y gráficos. Los overlays vienen a ser, mutatis mutandis como las máscaras de capa de los programas para editar imágenes.

Pasamos a explicar rápidamente las funciones, por si le fuesen de utilidad a alguien o las quisiese mejorar. Y, por contradecir el título de esta entrada, empezamos por las que pliegan / despliegan el texto de la nota.

Para plegar y desplegar el texto de las notas en un documento

Primero, la función que pliega las notas, donde nos viene de perlas la función nativa de Org org-narrow-to-element. Nuestro overlay para sustituir al texto de la nota, en este caso, es la palabra «nota», en rojo y encerrada en un recuadro.

(defun pliega-notas-org ()
      (interactive)
      (save-excursion
	(goto-char (point-min))
	(while
	    (re-search-forward "^\\[fn:[[:digit:]]" nil t)
	  (save-restriction
	    (org-narrow-to-element)
	    (let
		((ov (make-overlay (point-min) (point-max)))
		 (nota-plegada (propertize "nota" 'font-lock-face '(:foreground "red" :weight bold :box t))))
	      (overlay-put ov 'overlay-nota-plegada t)
	      (overlay-put ov 'display nota-plegada))))))

Y para volver a mostrar las notas, simplemente eliminamos el overlay:

(defun muestra-notas-org ()
       (interactive)
       (remove-overlays nil nil 'overlay-nota-plegada t))

resaltado%20notas2.png

Para resaltar el texto de las notas de un documento

Aquí son necesarias algunas triquiñuelas. Primero definimos una función que aplica un par de propiedades de texto entre los argumentos x e y. Los colores que he ecogido, por supuesto, son personales e intransferibles, pero al menos cuadran bien con los dos temas que suelo usar en Emacs, el claro para el día y el oscuro para los trabajos nictálopes.

(defun propiedades-resaltado-nota (x y)
    (put-text-property x y 'font-lock-face '(:background "NavajoWhite" :foreground "DarkMagenta"))
    (put-text-property x y 'front-sticky t))

A continuación, la función que resalta las notas en todo el documento, aplicando las propiedades antes mencionadas como overlay:

(defun resaltado-notas-local ()
    (interactive)
    (save-excursion
      (goto-char (point-min))
      (while
	  (re-search-forward "^\\[fn:[[:digit:]]" nil t)
	(save-restriction
	  (org-narrow-to-element)
	  (let
	      ((ov (make-overlay (point-min) (point-max)))
	       (resaltado-nota (propiedades-resaltado-nota (point-min) (point-max))))
	    (overlay-put ov 'overlay-nota-resaltada t)
	    (overlay-put ov 'display resaltado-nota))))))

Ahora, lo complicamos algo más. Esta otra función añade la anterior como variable local al documento. Sólo si no está ya añadida (expresión unless). Así, cada vez que abramos el documento, se conservará nuestro resaltado, ya que los overlays son siempre temporales.

(defun var-local-resaltado-nota ()
    (save-excursion
      (goto-char (point-min))
      (unless (re-search-forward "eval: (resaltado-notas-local)" nil t)
	(add-file-local-variable 'eval '(resaltado-notas-local))
	(save-excursion
	  (goto-char (point-max))
	  (re-search-backward "# Local Variables:" nil t)
	  (newline 5)))))

Y, por último, una función que añade una nota ya resaltada. Por cierto, aquí he tenido que hacer una pequeña triquiñuela no demasiado elegante. Una nota que vamos a escribir es una nota vacía, así que la función org-narrow-to-element no tiene ningún elemento que «aislar». Así que, de forma provisional, se inserta y se elimina un pequeño texto de «bulto», para que el resaltado tenga efecto desde el momento en que empezamos a escribir la nota.

(defun mi-notapie-org ()
    (interactive)
    (org-footnote-action)
    (save-excursion
      (insert "nota"))
    (resaltado-notas-local)
    (var-local-resaltado-nota)
    (save-restriction
      (org-narrow-to-element)
      (goto-char (point-min))
      (replace-regexp "nota" "" nil)))

resaltado%20notas1.png

Estrambotes

Uno. La última función tiene un pequeño problema. Si pegamos texto en nuestra nota resaltada (yank), el texto pegado viene con las propiedades de origen, que se sobreescribirán a las del overlay. Por tanto, no aparecerá resaltado hasta que no recarguemos el búfer (revert-buffer). Para prevenir ese comportamiento, podemos definir esta función:

(defun resaltado-yank-notas ()
  (if (org-footnote-at-definition-p)
	 (resaltado-notas-local)))

Y hacer que se ejecute justo después de llamar a la función yank. Así:

(advice-add 'yank :after 'resaltado-yank-notas)

Dos. Con esto de los overlays, que da mucho juego, escribí también unas funciones para mostrar las imágenes dentro de un documento de LaTeX o el resultado compilado (y aproximado, ojo) de algunos entornos. El código está en este repo de GitLab.

Publicado: 18/10/2019

Última actualización: 18/10/2019


Índice general

Acerca de...

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

Notas:

1

Un autor que abusa de este recurso, por cierto, recuerda mucho al que en el cine te está explicando la película y no te deja verla.

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