Índice de etiquetas para un blog a partir de las etiquetas de Org Mode
Como es bien sabido (como mínimo, sabido por mí), toda mi actividad tocante a lo de los blogs la perpetro, gestiono y
publico íntegramente dentro de GNU Emacs. Las entradas las escribo en Org y las publico mediante la fantástica
biblioteca org-publish
. Luego lo sincronizo con un repositorio público de GitLab y lo entrego a la red mediante el
servicio GitLab Pages, que salvo algún problemilla puntual funciona como un reloj.
Pero estos días de atrás llevaba dándole vueltas a cómo poder crear un sistema de navegación por etiquetas al más puro estilo blogero, con índice de etiquetas y demás aparataje; y ni hace falta mencionar que cada etiqueta debería consistir en un enlace apuntando a las entradas interesadas, pues de no ser así tendría poco sentido usar etiquetas en el blog. La idea, en fin, era poder transformar las etiquetas típicas de los documentos de Org en las no menos típicas etiquetas de un blog al uso. Al final dí en escribir la función que, por si pudiese resultar útil a alguien, comentamos aquí. Aunque antes de meternos en harina, vayan un par de trazos sobre mi rutina a la hora de publicar una entrada.
Cada entrada que publico, en efecto, siempre es un documento de Org independiente. Las etiquetas al estilo Org las
podemos añadir en cualquier encabezado, incluso en uno destinado a no publicarse, ya que en cualquier caso no las hemos
de exportar tal cual (como etiquetas de blog no son útiles y por tanto añado la opción de exportación que ignora las
etiquetas tags:nil
), sino que las vamos a utilizar para generar nuestras etiquetas del blog, que son las que aquí nos
interesan.
Para escribir cada entrada tengo hecha una plantilla, y al final de ésta añadí el siguiente código con el término «Etiquetas:» listo para ser poblado:
#+begin_export html <div style="text-align: right;"> <span style="font-size: x-small;"> #+end_export Etiquetas: #+begin_export html </span></div> <div style="text-align: right;"> <span style="font-size: x-small;"><a href="lista-etiquetas.html">Lista de etiquetas</a></span></div> #+end_export
Por último, este sistema lo he puesto en práctica en mi blog literario Las diosas y las nubes (II). El resultado se puede ver en la fig. 1 (etiquetas y lista de etiquetas al pie de cada entrada: cada etiqueta lleva a un archivo dedicado con todas las entradas que la contienen); en la fig. 2 (el archivo dedicado); y en la fig. 3 (la página con la lista de etiquetas).
Figura 1: Etiquetas y enlace a la lista de etiquetas al pie de la entrada
Y ahora vamos con la función, que debe evaluarse dentro del archivo Org de la entrada que queremos publicar. Se supone
que ya tenemos las etiquetas de Org añadidas en algún lugar de ese archivo. Incluso podemos usar el comando en línea
#+FILETAGS:
:
(defun recoge-etiquetas-diosas () "Genera los enlaces con etiquetas para un archivo Org destinado a publicarse como entrada de blog y puebla los ficheros necesarios" (interactive)
La variable local tit-entrada
almacenará el título de la entrada del blog, que estará (recordemos) en un único documento de Org, en
la línea #+TITLE:
, siempre al principio del documento, para asegurar que la función org-element-at-point
da en el
blanco. Es necesario añadir la expresión let
con asterisco para que las variables se verifiquen por orden:
(let* ((elemento (save-excursion (goto-char (point-min)) (org-element-at-point))) (tit-entrada (org-element-property :value elemento)))
Iniciamos ahora un bucle para que, cada vez que se localice una etiqueta de Org (es decir, cualquier cadena con la estructura :etiqueta:
)…
(save-window-excursion (save-excursion (goto-char (point-min)) (while (re-search-forward ":\\(\\b[a-zA-Záéíóúñ]+\\b\\):" nil t) (forward-char -1)
se defina una variable con el nombre de la etiqueta localizada, literal:
(setq etiqueta-sola (match-string 1))
Y esta otra variable con el nómbre de la etiqueta, pero sin acentos ni caracteres extendidos como la letra eñe.
Necesitaremos esta variante del nombre para poder crear el archivo org dedicado a cada etiqueta. Si normalizamos de NFC
a NFD1 y eliminamos después los diacríticos combinatorios, obtendremos una versión del nombre de la etiqueta apropiada
para poder nombrar un archivo, en caso de que tengamos algún acento o letra no asci rondando. Es decir, que si nuestra
etiqueta es «cuñadísimo» el archivo dedicado a esta etiqueta pasará a llamarse cunadisimo.org
y tras la exportación
cunadisimo.html
:
(setq etiqueta-sola-bis (replace-regexp-in-string "\\([\u0300-\u036F]+\\)" "" (ucs-normalize-NFD-string etiqueta-sola)))
Por último, esta tercera variable almacena el nombre del archivo donde tenemos la entrada del blog a publicar. Y donde nos encontramos.
(setq entrada-diosas (format "%s" (current-buffer)))
A continuación, ya almacenadas las variables, se añadirá el enlace de la etiqueta, tras «Etiquetas:», siempre al final de la línea (recordemos que estamos en un bucle y todo esto se repetirá con cada etiqueta localizada):
(save-excursion (goto-char (point-min)) (re-search-forward "Etiquetas:" nil t) (end-of-line) ;; `etiqueta-sola-bis' siempre en la dirección del enlace para evitar acentos (insert (format " [[file:%s.org][%s]] " etiqueta-sola-bis etiqueta-sola)))
Si no existe ya el archivo dedicado a la etiqueta, lo creamos y lo visitamos. Allí introducimos toda la información de la cabecera que queramos incluir y, justo debajo, añadimos la entrada de lista con el enlace a nuestra entrada y el título de la misma, seguido de la fecha.
(save-window-excursion (if (not (file-exists-p (concat "~/Git/juanmanuelmacias/org/" etiqueta-sola-bis ".org"))) (progn (shell-command (concat "touch " "~/Git/juanmanuelmacias/org/" etiqueta-sola-bis ".org")) (find-file (concat "~/Git/juanmanuelmacias/org/" etiqueta-sola-bis ".org")) (insert (concat "#+TITLE: " "Entradas con la etiqueta: " "\"" etiqueta-sola "\"" "\n\n" "#+SETUPFILE:" " ~/Git/juanmanuelmacias/html-diosas.setup" "\n#+SETUPFILE:" " ~/Git/gnutas/macros-gnutas.setup" "\n#+AUTHOR:" " Juan Manuel Macías" "\n#+OPTIONS:" " num:nil" "\n#+OPTIONS:" " toc:nil" "\n#+OPTIONS:" " tags:nil" "\n#+OPTIONS:" " d:nil" "\n#+OPTIONS:" " ':t" "\n#+OPTIONS:" " todo:nil" "\n#+LANGUAGE:" " es" (concat "\n- " (format " [[file:%s][%s]] " entrada-diosas tit-entrada) " -- " (format-time-string "%d/%m/%y"))))
Ordenamos la lista (aunque en realidad no haría falta, pues sólo tendríamos un enlace, ya que estrenamos fichero dedicado). Salvamos el archivo y (curioso contrasentido emacsiano, por cierto) lo matamos.
(org-sort-list t ?a nil nil nil) (save-buffer) (kill-buffer))
Pero si existe ya el archivo dedicado a la etiqueta, el proceso es más sencillo que en el caso anterior, y no hace falta escribir ni el título ni los elementos de la cabecera. Aquí sí que tiene más sentido ordenar la lista antes de salvar y matar.
(find-file (concat "~/Git/juanmanuelmacias/org/" etiqueta-sola-bis ".org")) (goto-char (point-max)) (insert (concat "\n- " (format " [[file:%s][%s]] " entrada-diosas tit-entrada) " -- " (format-time-string "%d/%m/%y"))) (org-sort-list t ?a nil nil nil) (save-buffer) (kill-buffer)))
Por último, ya sólo queda editar el archivo con la lista de las etiquetas (que tendremos creado). Se añadirá (en caso de
que no esté incluida aún), la etiqueta enlazando a su archivo dedicado. Y después se reordena la lista de enlaces.
Recuérdese que en los enlaces estamos usando en la ruta siempre la variable etiqueta-sola-bis
, para asegurarnos
de que no se nos cuela ningún acento u otros glifos no asci.
(save-window-excursion (find-file "~/Git/juanmanuelmacias/org/lista-etiquetas.org") (unless (re-search-forward etiqueta-sola nil t) (goto-char (point-max)) (insert (concat "\n- " (format " [[file:%s.org][%s]] " etiqueta-sola-bis etiqueta-sola))) (org-sort-list t ?a nil nil nil) (save-buffer) (kill-buffer))))))))
Figura 2: Archivo dedicado a una etiqueta con las entradas que la contienen
Figura 3: Lista de etiquetas
∞
Publicado: 22/06/20
Última actualización: 21/01/22
Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.
Notas al pie de página:
Sobre la normalización NFC y NFD en Unicode con Emacs Lisp ya hablamos en esta pasada entrada.