Cuaderno de GNUtas

Í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).

etiquetas-detalle.png

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))))))))

etiquetas-detalle2.png

Figura 2: Archivo dedicado a una etiqueta con las entradas que la contienen

etiquetas-detalle3.png

Figura 3: Lista de etiquetas

Publicado: 22/06/20

Ú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 al pie de página:

1

Sobre la normalización NFC y NFD en Unicode con Emacs Lisp ya hablamos en esta pasada entrada.

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