Cuaderno de GNUtas

Notas en Org no exportables

Una funcionalidad muy interesante que echo en falta en Org Mode es la de poder ignorar de manera arbitraria algunas notas al pie durante el proceso de exportación. Podemos, por supuesto, ignorarlas o activarlas todas en bloque, si añadimos a nuestra cabecera las opciones #+OPTIONS: fn:nil / #+OPTIONS: fn:t, respectivamente. Pero lo que yo quiero es ser capaz de dejar algunas en concreto de lado, mientras que el resto sean exportadas de manera normal. Creo que es una forma más y muy efectiva de gestionar un corpus marginal para mi consumo privado. Bien es cierto que en Org tenemos para ese fin opciones muy útiles, como los meros comentarios o los drawers («cajones») desplegables que sirven para un roto como para un descosido. Pero hay contextos donde una nota al pie con carácter secreto se vuelve indispensable, entre otras cosas por la gran agilidad de navegación correlativa entre marca de nota y referencia. O porque no queremos alterar una determinada sucesión de líneas al insertar un bloque de comentario o un cajón. Un ejemplo que me viene muy a mano es el de un poema largo, como en mi traducción de la Odisea (work in progress).

Así las cosas, ¿qué podemos hacer? Se imponen tres posibles soluciones:

  1. Esperar a que los desarrolladores de Org implementen la funcionalidad, cosa poco probable, pues no parece que sea algo muy demandado.
  2. Echarse al monte y ponerse a hacer código duro, como San Ignucio manda, e implementarla nosotros mismos.
  3. No echarse al monte sino salir a pasear por el solar de la esquina, y probar un remiendo chapucero pero que, sin embargo (y ante nuestra sorpresa), funcione.

Naturalmente, yo he seguido la tercera vía, y aquí resumo un poco por encima los pormenores. Se basa en dos cosas que tienen Emacs y Org, tremendamente útiles: su potente sistema (aunque también doloroso y muchas veces arcano) de expresiones regulares y la posibilidad de ejecutar funciones de elisp en la exportación desde Org, y hacerlo en los momentos tempranos, antes de que se expandan los comandos, y sólo si el formato de salida es uno determinado. Sobre esto último ya hablamos aquí.

Empezamos, primero, por definir una sencilla función que nos inserte una nota al pie con unas marcas especiales, tanto en la llamada de la nota como en su referencia. Será, pues, reconocida como una nota no exportable.

(defun nota-org-no-exportable ()
    (interactive)
    (insert "!@!")
    (org-footnote-action)
    (insert "⁜no-exp⁜:")
    (newline 1)
    (save-excursion
      (newline 1)
      (insert "@@")))

Como se ve, la marca de esta nota comenzará por los caracteres !@!, y el cuerpo de la nota estará delimitado por las cadenas ⁜no-exp⁜: y @@, ambos encerrados entre sendos símbolos que Unicode denomina DOTTED CROSS. En la fig. 1 se muestra el aspecto que tendría nuestra nueva nota. Dado que ya tenemos todo convenientemente delimitado y marcado, no es difícil definir una función que efectúe las correspondientes sustituciones mediante expresiones regulares, a fin de «anularnos» las notas así marcadas, y anclar nuestra función al pre-proceso de exportación. Coser y cantar. El cuerpo de la nota es fácil de eliminar. Basta con incluirlo en un snippet de exportación con un backend inexistente, que aquí por conveniencia llamamos «null», aunque valdría cualquier palabra que no sea la de los backends conocidos.

nota_no_exp.png

Figura 1: Ejemplo de nuestra nota «no exportable»

Nuestra función, entonces, luciría tal que así para ignorar las notas no exportables en cualquier salida. Definimos antes una función para simplificar el proceso de reemplazo:

(defun reemplaza (antes despues)
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward antes nil t)
      (replace-match despues t nil))))

Y luego la función propiamente dicha. Nótese que evitamos el proceso de reemplazo en los bloques de ejemplo, de código y en los segmentos literales (véase la línea lin):

;; no exportar ciertas notas
(defun no-exportar-notas-org (backend)
  "evita exportar las notas marcadas a html o LaTeX"
  (when backend
    (org-show-all)
    (let ((el (car (org-element-context)))) (lin)
      (unless (or (eq 'example-block el)
                  (eq 'src-block el)
                  (eq 'verbatim el))
        (reemplaza (concat "!@!" org-footnote-re) "")
        (reemplaza (concat org-footnote-definition-re "\s*⁜no-exp⁜:") "@@null:")
        (reemplaza "@@" "@@")))))

Y para anclarla al pre-proceso de exportación, añadimos también lo siguiente a nuestro /.emacs1:

(add-hook 'org-export-before-processing-hook #'no-exportar-notas-org)

Así, cada vez que exportemos a esos dos formatos, nuestras notas no exportables quedarán en la más absoluta ignorancia. Para reconocer bien en nuestro texto las marcas que añadimos a dichas notas, podemos también definir un resaltado por color:

(defvar nota-muda (make-face 'nota-muda))
(set-face-foreground 'nota-muda "chocolate")

(font-lock-add-keywords
 'org-mode
 '(("⁜\\(.+\\)⁜" 0 nota-muda) ; esto para el cuerpo de la nota
   ("!@!\\[fn:[[:digit:]]+\\]" 0 nota-muda) ; y esto para la marca de la nota
 ))

Publicado: 11/07/2019

Última actualización: 21/01/22


Índice general

Acerca de...

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

Notas:

1

Si vamos a introducir las notas no exportables en subdocumentos, que luego se incluirán a un documento «maestro» mediante la directiva #+INCLUDE:, nos interesará mejor anclar esa función a org-export-before-parsing-hook.

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