Ejecutar funciones en la exportación desde Org a otros formatos
Las posibilidades que nos ofrece Org Mode para exportar a otros formatos son de una variedad y un finura exquisitas.
Podemos manejar variables desde la cabecera de nuestro documento, o crear y aplicar filtros de muchas maneras para
contextos concretos, o añadir atributos a bloques para que lleguen con determinadas propiedades al documento meta. De
entre todas esas facilidades, en fin, me resulta especialmente útil el anclaje de funciones denominado
org-export-before-processing-hook
, cuyo nombre es bastante elocuente y nos avisa de que su cometido es ejecutar en el
momento de la exportación las funciones que le añadamos, con la salvedad (y aquí está la gracia) de que lo hará antes de
que se expandan todos los comandos, e incluso de que entre en acción el exportador de Org. Esto supone que podemos
manipular cualquier aspecto de nuestro documento (incluso el meramente textual) en ese lapso en que el proceso de
exportación aún no se ha llevado a efecto. Partamos de un ejemplo muy sencillo para entender cómo funciona.
Imaginemos que nuestro documento de Org lo queremos exportar indistintamente y, muchas veces, a dos formatos, por ejemplo a LaTeX y a HTML. Pero deseamos, además (quién sabe por qué) que las ocurrencias de la cadena de texto «Juan Pérez» en nuestro documento pasen a ser «Sr. Pérez» sólo y únicamente cuando exportamos a HTML. Definimos, primero, una función con un simple búsqueda / reemplazo:
(defun cambiamos-a-juan (backend) "De Juan Pérez a Sr." (when (eq backend 'html) (org-occur "Juan Pérez") (save-excursion (goto-char (point-min)) (replace-regexp "Juan Pérez" "Sr. Pérez" nil))))
Y, por supuesto, añadimos la función al anclaje:
(add-hook 'org-export-before-processing-hook #'cambiamos-a-juan)
Las funciones que anclemos a este hook
admiten un único argumento (backend
). Antes de añadir en nuestra función la
operación de búsqueda / reemplazo necesitamos llamar antes a la función de Org org-occur
para que Juan Pérez se haga
encontradizo en todo el documento. De lo contrario, no se ejecutará su cambio si se esconde entre los sub árboles
plegados.
Todo esto, claro, en nuestro archivo de inicio. Así, cada vez que exportemos un documento Org a HTML, nuestro querido Juan Pérez obtendrá un estatus más respetable. Sin embargo, lo más probable es que queramos que estos cambios no sean globales sino aplicados a documentos en concreto. ¿Cómo hacemos? Fácil. Podemos encerrar este código en un bloque de código al estilo Org, colocarlo al principio del documento a exportar y aplicarle los atributos necesarios para que el código no se exporte sino que se evalue (y, por tanto, se ejecute) en el momento de la exportación. Ya vimos que Org puede hacer estas cosas, a cuento de la evaluación de código LaTeX. En este caso, el código a evaluar es emacs-lisp:
#+begin_src emacs-lisp :exports code :exports results :results none (defun cambiamos-a-juan (backend) "De Juan Pérez a Sr." (when (eq backend 'html) (org-occur "Juan Pérez") (save-excursion (goto-char (point-min)) (replace-regexp "Juan Pérez" "Sr. Pérez" nil)))) (add-hook 'org-export-before-processing-hook #'cambiamos-a-juan) #+end_src
En el anterior ejemplo vimos cómo modificar elementos del contenido. Pero podemos ir más lejos y alterar a conveniencia
los aspectos formales de nuestro documento. Muestro aquí un caso concreto de mi trabajo. En mi traducción de la Odisea
suelo exportar a LaTeX, pero en ocasiones también al formato odt
de LibreOffice, y en ambos casos quiero que se
inserte bajo el título la fecha actual junto a una coletilla. También quiero añadir la opción num:nil
si se exporta a
odt
para evitar que me numere las secciones y salgan cosas como «1. Canto I; 2. Canto II; etc (eso lo evito
directamente en LaTeX definiendo los títulos con titlesec
, en mi clase Org de exportación a LaTeX). El código a
evaluar, que tengo a la cabecera de mi Odisea luce tal que así:
#+BEGIN_SRC emacs-lisp :exports results :results none ;; código a evaluar para exportar a odt (defun mi-filtro-odt (backend) "afina varias cosas para exp. a odt" (when (eq backend 'odt) (save-excursion (goto-char (point-min)) (insert "#+OPTIONS: num:nil") (newline) (insert (format "#+DATE: En algún lugar de vuelta a Ítaca (versión para LibreOffice): %s" (format-time-string "%c"))) (newline)))) (add-hook 'org-export-before-processing-hook #'mi-filtro-odt) ;; código a evaluar para exportar a LaTeX (defun mi-filtro-latex (backend) "añade varias cosas en la exportación a LaTeX" (when (eq backend 'latex) (save-excursion (goto-char (point-min)) (insert "#+DATE: En algún lugar de vuelta a Ítaca (version LaTeX): \\today{}") (newline)))) (add-hook 'org-export-before-processing-hook #'mi-filtro-latex) #+END_SRC
Lo que hacen estas dos funciones no es más que situarse en la cabecera del documento y añadir literalmente lo que deseo,
según se exporte a LaTeX u a odt
. En cuanto a la fecha, en LaTeX nos basta con el comando \today
, cosa que Org
hubiese añadido de oficio, pero también quería incluir mis coletillas1. En cuanto a la salida a odt
, nos puede resultar
útil la función format-time-string
, que nos inserta la fecha en curso con las opciones que indiquemos en su argumento
(en este caso "%c"
, para insertarla según nuestra configuración local). Todo eso lo aplicamos como segundo argumento
de format
. El primero es la cadena de texto donde se recoge el resultado de format-time-string
(comodín %s
), que a
su vez la función insert
imprime como literal.
Y, para terminar, un ejemplo sacado de estas propias Gnutas. Cuando introduzco un bloque example
(como el que encierra
el código del ejemplo anterior) quiero que en la salida a HTML
tenga un determinado color de fondo. Puedo añadir justo
antes del bloque el estilo de exportación como atributo:
#+ATTR_HTML: :style background-color:#fdf6e3;
Pero si automatizo eso, trabajo que me ahorro. Entonces:
#+BEGIN_SRC emacs-lisp :exports results :results none (defun mi-filtro-html (backend) "añade estilo de fondo al bloque example" (when (eq backend 'html) (org-occur "\\#\\+begin_example :exports code") (save-excursion (goto-char (point-min)) (replace-regexp "\\#\\+begin_example :exports code" "#+ATTR_HTML: :style background-color:#fdf6e3\;\n#+begin_example :exports code" nil)))) (add-hook 'org-export-before-processing-hook #'mi-filtro-html) #+END_SRC
∞
Publicado: 22/04/2019
Última actualización: 22/04/2019
Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.
Notas al pie de página:
También nos podemos contentar con la función time-stamp de Emacs.
En cualquier caso, si los filtros que queremos aplicar son generales, es decir, si queremos que se ejecuten las mismas
acciones siempre para cada formato, lo más recomendable sería definir las funciones y anclarlas a
org-export-before-processing-hook
dentro de nuestro archivo de inicio.