Cuaderno de GNUtas

Integrando Diogenes con Emacs y Org

Diogenes (lo escribimos así, sin la tilde esdrújula, por respetar el nombre original de la aplicación) es un excelente y utilísimo software libre (licencia GPL v.3) especializado en navegar y rastrear por los textos de los antiguos CD del TLG (Thesaurus Linguae Graecae) y otras fuentes por el estilo1. Viene también con una serie de diccionarios integrados, como el Liddell Scott del Perseus Project, con que podemos buscar palabras incluso en sus variantes flexivas. Se trata de un programa veterano, que hasta hace no mucho era casi imposible de ejecutar correctamente en las versiones más recientes de GNU/Linux. La buena noticia, sin embargo, es que en los dos últimos años (a fecha de esta GNUta) ha recibido una puesta al día por todo lo alto, con no pocas mejoras y añadidos. El responsable de todo es Peter Heslin (aquí puede visitarse el respositorio en GitHub) e incluso podemos descargar paquetes de instalación para Ubuntu/Debian, Fedora y Arch y derivadas desde la web oficial del proyecto. Todo un lujo.

Bien, yo me instalé el paquete para Arch y he estado trasteando un poco. La instalación es muy limpia y sin problemas de dependencias. Basta con correr en terminal:

sudo pacman -U <ruta-a-paquete-descargado>

En general, el programa funciona bien, con algunas características francamente espectaculares. Me gustaron especialmente las funcionalidades de búsquedas por los textos y el análisis morfológico de las palabras. La interfaz de escritorio es (ay) un contenedor de Electron, pero la buena noticia es que podemos usar Diogenes en modo servidor y acceder a él desde un navegador. Y así es como, en principio, recomiendo usarlo, pues aquí a Electron no queremos verlo ni en pintura. De hecho, con EXWM y un navegador orientado al teclado del estilo de qutebrowser hay un amor a primera vista. Pero ya se sabe que los que usamos GNU Emacs aspiramos maniáticamente a hacerlo todo dentro sin salir de Emacs, así que me andaba preguntando estos días cómo y en qué medida podríamos integrar a Diogenes en nuestra querida Lisp Machine. Naturalmente, si uno tiene tiempo, ganas y conocimientos, sería factible desarrollar una interfaz completa de Diogenes escrita en Elisp para traducir los procesos internos en Javascript de aquél. Por desgracia, carecemos de las tres cosas, de modo que aquí nos conentaremos con explotar desde el lado de Emacs la funcionalidad servidor de Diogenes. Y una vez que se logran aislar las URI adecuadas, los resultados son muy satisfactorios. Hagamos un pequeño recorrido por lo que he ido logrando, y aunque he enfocado las triquiñuelas especialmente a mi trabajo en la traducción de la Odisea (work in progress a fecha de esta GNUta), creo que el lector interesado puede aprovechar la información necesaria para adaptarla a su propio flujo de trabajo.

Antes de nada, lo primero: debemos iniciar el servidor de Diogenes, y lo haremos desde Emacs. Para ello definí esta sencilla función (téngase en cuenta que tal vez varíe la ruta del servidor entre distintas distribuciones de GNU/Linux):

(defun inicia-servidor-diogenes ()
  (interactive)
  (start-process-shell-command "diogenes" nil "/usr/local/diogenes/server/diogenes-server.pl"))

Buscar desde Emacs una forma griega en el LSJ integrado en Diogenes

Si conocemos la URI adecuada, la función que necesitamos aquí es bien sencilla. Yo quería que me analizase la palabra donde tengo el cursor, y lo más simple fue reutilizar el código de otra función que había escrito para buscar en el LSJ on line de Perseus. Podemos, incluso, abrir los resultados en el eww-mode de Emacs, sin necesidad de un navegador externo, y así ya todo queda en casa. En la fig. 1 se muestra el siguiente código en acción:

(defun diogenes-perseus (word)
  (interactive (list (current-word t t)))
  (if
      (not (current-word t t))
      (error "Ninguna palabra que analizar...")
    (other-window 1)
    (eww (concat "http://127.0.0.1:8888/Perseus.cgi?do=parse&lang=grk&q=%2A%29/" word))))

perseus-diogenes.png

Figura 1: Buscando en el LSJ de Diogenes desde Emacs (los resultados se muestran en el eww-mode)

Saltar a un verso de la Odisea en Diogenes desde nuestro documento Org

Éste es un uso muy especializado para mi trabajo en la Odisea. El escenario es el siguiente: si tengo el cursor en cualquier verso, tanto de mi traducción como del original en griego (ambos en documentos de Org Mode), cuando evalúo mi función, salto directamente al verso en el texto del TLG abierto por Diogenes. Mi función debe saber de oficio en qué número de verso y número de canto tengo el cursor dentro de Emacs. Para el número de verso definí esta otra función, que devuelve como una cadena de texto el número de verso en la posición del cursor:

(defun numero-verso-actual ()
  "Devuelve el número de verso en que está el cursor"
  (save-excursion
    (end-of-line)
    (save-restriction
      (org-narrow-to-block)
      (narrow-to-region (point-min) (point))
      (goto-char (point-min))
      (end-of-line)
      (let
	  ((numverso 0))
	(save-excursion
	  (while
	      (re-search-forward "^." nil t)
	    (setf numverso (+ numverso 1)))
	  (setq verso-actual numverso)))))
  verso-actual)

Para el número de canto, mi función que ha de saltar a Diogenes tiene dos opciones: si el cursor está en la traducción, lo obtiene de una propiedad :Canto:; si está en el texto original, del nombre del archivo individual, ya que todos los nombro siguiendo un mismo esquema. Así que tiraremos aquí de un condicional. Y aquí tenemos la función resultante, la cual, insisto, está especializada en hacer una única cosa: buscar en un verso en la Odisea:

(defun diogenes-odisea-verso ()
  (interactive)
  (let* ((canto (if (string-match "\\([[:digit:]]+\\)gr" (buffer-name))
		    (match-string 1 (buffer-name))
		  (org-entry-get nil "Canto")))
	 (verso (number-to-string (numero-verso-actual)))
	 (url "http://127.0.0.1:8888/Diogenes.cgi?JumpTo=&JumpFromQuery=&JumpFromLang=&JumpFromAction=&level_1=canto&level_0=verso&submit=Show+me+this+passage&greek_output_formatXXstate=UTF-8&levelsXXstate=1&JumpFromQueryXXstate=&typeXXstate=TLG+Texts&corpusXXstate=TLG+Texts&export-pathXXstate=&current_pageXXstate=browser_passage&authorXXstate=0012&JumpFromLangXXstate=&queryXXstate=Homerus&splashXXstate=true&actionXXstate=browse&workXXstate=002&JumpToXXstate=&submitXXstate=Find+a+passage+in+this+work&short_typeXXstate=tlg&JumpFromActionXXstate=")
	 (url-form (replace-regexp-in-string "canto" canto
					     (replace-regexp-in-string "verso" verso url))))
    (browse-url url-form)))

Nótese que, en este caso y los que siguen, no usamos el eww-mode de Emacs sino el navegador externo por defecto, que en mi caso es qutebrowser.

Buscar un término griego en Homero o en cualquier otro autor griego

Como en el caso anterior, el escenario de uso vuelve a estar bastante acotado. Aquí la idea es lanzar la pesquisa adecuada en Diogenes desde el pasaje griego seleccionado o marcado en Emacs. La estructura de ambas funciones es muy parecida a la de la anterior. De hecho, esto es más bien Elisp de parvulario. La gracia y la dificultad estriba en poner la correcta cadena en la URI con la que tenemos que abrir Diogenes.

Aquí tenemos la función para buscar las ocurrencias de un pasaje en Homero:

(defun busca-diogenes-pasaje-homero (desde hasta)
  (interactive "r")
  (let* ((pas (buffer-substring-no-properties desde hasta))
	 (url "http://127.0.0.1:8888/Diogenes.cgi?JumpTo=&JumpFromQuery=&JumpFromLang=&JumpFromAction=&action=author&splash=true&export-path=&corpus=TLG+Texts&author=Homerus&query=pasaje&current_pageXXstate=splash&greek_output_formatXXstate=UTF-8")
	 (url-form (replace-regexp-in-string "pasaje" pas url)))
    (browse-url url-form)))

Y aquí su hermana gemela, para buscar un pasaje (griego, insistimos) en cualquier autor:

(defun busca-diogenes-pasaje-simple (desde hasta)
  (interactive "r")
  (let* ((pas (buffer-substring-no-properties desde hasta))
	 (url "http://127.0.0.1:8888/Diogenes.cgi?JumpTo=&JumpFromQuery=&JumpFromLang=&JumpFromAction=&action=search&splash=true&export-path=&corpus=TLG+Texts&query=pasaje&greek_output_formatXXstate=UTF-8&current_pageXXstate=splash")
	 (url-form (replace-regexp-in-string "pasaje" pas url)))
    (browse-url url-form)))

Y éste es un breve vídeo de muestra donde se ve todo el proceso en acción:

Publicado: 15/08/21

Última actualización: 15/08/21


Índice general

Acerca de...

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

Notas:

1

Es importante señalar que las fuentes no vienen incluidas en el programa por cuestiones obvias de licencias, y es el usuario quien debe aportarlas.

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