Cuaderno de GNUtas

Función en Emacs para trabajar con el paquete verse de LaTeX

El paquete verse de Peter Wilson para LaTeX es muy útil a la hora de trabajar con páginas de poesía o, por ser más precisos, con versos, sean o no poesía: dilucidar eso último ya es otro cantar que no compete a TeX ni a la tipografía. Mientras lo dilucidamos, el paquete incluye, entre otras muchas opciones, la posibilidad de alinear automáticamente el poema entre los dos márgenes verticales de la página, tomando como referencia la anchura del verso más largo. Se trata de una norma tipográfica que debe emplearse al menos en la versificación «clásica», y que comento también en esta entrada de mi blog de Apuntes tipográficos. Pero aquí nos ceñiremos a cuestiones de código.

Si seguimos la documentación del paquete, para que un poema quede perfectamente alineado respecto al verso más largo centrado en la página, debemos establecer literalmente ese verso como valor de la longitud \versewidth, a través del comando \settowidth. A continuación encerramos el poema dentro de un entorno verse, que tendrá como argumento opcional el valor \versewidth, que se sobre-escribirá con cada poema1. Así, partiendo de las dos primeras estrofas de la Sonatina de Darío, el esquema sería:

\settowidth{\versewidth}{La princesa está triste... ¿Qué tendrá la princesa?}
\begin{verse}[\versewidth]
La princesa está triste... ¿Qué tendrá la princesa?\\
Los suspiros se escapan de su boca de fresa,\\
que ha perdido la risa, que ha perdido el color.\\
La princesa está pálida en su silla de oro,\\
está mudo el teclado de su clave sonoro,\\
y en un vaso, olvidada, se desmaya una flor.

El jardín puebla el triunfo de los pavos reales.\\
Parlanchina, la dueña dice cosas banales,\\
y vestido de rojo piruetea el bufón.\\
La princesa no ríe, la princesa no siente;\\
la princesa persigue por el cielo de Oriente\\
la libélula vaga de una vaga ilusión.
\end{verse}

Nótese que, dentro del entorno verse cada final de verso ha de marcarse con \\, salvo el último verso de cada estrofa.

Función para Emacs

A pesar de que estos comandos simplifican mucho el proceso, si estamos en Emacs siempre podremos ir un poco más lejos. A la larga puede resultar un poco latoso, sobre todo cuando tenemos que componer un libro con muchos poemas, el ir buscando los versos más largos de cada uno. Nada inasumible, por otra parte; lo que ocurre es que Emacs nos vuelve un poco comodones, pero en lugar de quejarnos nos da por pensar si no se podrá escribir una función. En este caso, que realice lo siguiente:

  1. En un poema señalado (marcado, en la jerga emacsiana) nos busque y copie el verso más largo;
  2. Nos encierre ese poema dentro del entorno antes descrito, con el valor de ese verso añadido a \versewidth.

Pero antes de ponernos a inventar la rueda desde cero, lo recomendable siempre será mirar si no estará ya —como sucede tan a menudo– inventada. Es la salsa del software libre, donde constantemente se reciclan ideas brillantes y no es necesario inventar mil ruedas a un tiempo, pues con una sola que funcione ya basta. Para el caso que nos ocupa, nuestra ansiada rueda era conseguir localizar y —al menos— marcar el verso más largo. Y la teníamos de forma simple y elegante en esta función para buscar y marcar la siguiente línea más larga desde la posición del cursor, que un usuario compartió en la lista de correo de gnu:

(defun goto-longest-line ()
   (interactive)
   (let ((max-line-start 0)
	 (max-line-length 0))
     (goto-char (point-min))
     (while (< (point) (point-max))
       (let ((start (point)))
	 (forward-line)
	 (let ((length (- (point) start)))
	   (if (< max-line-length length)
	      (setf max-line-length length
		    max-line-start  start)))))
     (goto-char max-line-start)
     (set-mark (+ max-line-start max-line-length))))

Ya teníamos la rueda. Lo que yo he añadido no es más que la decoración de la rueda, es decir, adaptar esta función para usarla en el entorno verse de LaTeX. Y ésta es mi función resultante (más bien dos funciones, una para generar el entorno verse y otra para encerrar el poema dentro, con los valores del verso más largo:

 1: (defun verso-latex ()
 2:   "Envuelve una región marcada en un entorno verse y añade marcas
 3: de verso y separación de 1.2em entre estrofas"
 4:         (interactive)
 5:        (if (region-active-p)
 6:        (progn
 7:          (save-excursion
 8:            (goto-char (region-end))
 9:            (newline 2)
10:            (insert "\\end{verse}"))
11:          (save-excursion
12:            (replace-regexp "$" "\\\\\\\\" nil (region-beginning) (region-end)))
13:          (save-excursion
14:          (replace-regexp "\\\\\\\\\n\\\\\\\\" "\n" nil (region-beginning) (region-end)))
15:          (save-excursion
16:            (goto-char (region-beginning))
17:            (insert "\\begin{verse}")
18:            (newline 2)))
19:         (nil)))
20: 
21: ;; Definir el verso más largo en LaTeX
22: 
23: (defun verso-largo-latex ()
24:   "Envuelve una región marcada en un entorno verse y añade marcas
25: de verso y separación entre estrofas. Extrae el verso más largo
26: de un entorno verse y lo coloca antes de \begin{verse}. Por
27: último, añade el argumento opcional [\versewidth] con el valor
28: del verso más largo"
29:   (interactive)
30:   (narrow-to-region (region-beginning) (region-end))
31:     (deactivate-mark)
32:       (whitespace-cleanup)
33:       (goto-longest-line)
34:       (copy-region-as-kill (region-beginning) (region-end))
35:                 (beginning-of-buffer)
36:                 (set-mark-command nil)
37:                 (end-of-buffer)
38:                 (verso-latex)
39:       (deactivate-mark)
40:    (widen)
41:    (LaTeX-find-matching-begin)
42:    (previous-line)
43:    (save-excursion
44:   (insert "\\settowidth{\\versewidth}{")
45:   (yank))
46:     (set-mark-command nil)
47:     (end-of-line)
48:     (insert "}")
49:     (save-excursion
50:     (next-line 3)
51:     (LaTeX-mark-environment)
52:     (replace-string "begin{verse}" "begin{verse}[\\versewidth]" nil (region-beginning) (region-end))))

Naturalmente, debemos incluir antes la función que mencionamos goto-longest-line, así como requerir AUCTeX, ya que echamos mano de algunas funciones de este paquete. Para que la función goto-longest-line actúe sólo en el poema y no en todo el documento desde el cursor hasta el final (algo que no deseamos que suceda), aislamos nuestro poema marcado, temporalmente, con un narrow-to-region. Por otra parte, whitespace-cleanup (lín. 32) nos resultará muy útil por si se nos va la mano marcando el poema y nos pasamos algunas líneas blancas. No afecta al resultado final, pero le añade desaliño. En este vídeo se muestra un poco cómo funciona nuestra nueva y flamante rueda:

Cómo colocar correctamente un poema en la página from Juan Manuel Macías Chaín on Vimeo.

Un bonus para Org Mode

¿Y si queremos exportar un bloque VERSE desde Org Mode a LaTeX? Pues da la casualidad de que aquí también teníamos nuestra rueda (o parte de ella) inventada, con una función que sitúa el cursor al principio de un bloque. En el caso de la función original se trata de un bloque de código. Para que sea un bloque VERSE, nos basta con modificarla en la línea 9:

 1: ;; Ir a inicio bloque (fuente:
 2: ;; https://github.com/kshenoy/dotfiles/blob/master/emacs.org#jump-to-headtail-of-any-block-not-just-src-blocks)
 3: 
 4: (defun my-org-babel-goto-block-corner (p)
 5:   "Go to the beginning of the current block.
 6:   If called with a prefix, go to the end of the block"
 7:   (interactive "P")
 8:   (let* ((element (org-element-at-point)))
 9:     (when (or (eq (org-element-type element) 'verse-block) ;; añadimos el bloque verse
10:               (eq (org-element-type element) 'src-block) )
11:       (let ((begin (org-element-property :begin element))
12:             (end (org-element-property :end element)))
13:         ;; Ensure point is not on a blank line after the block.
14:         (beginning-of-line)
15:         (skip-chars-forward " \r\t\n" end)
16:         (when (< (point) end)
17:           (goto-char (if p end begin))
18:           (when p
19:             (skip-chars-backward " \r\t\n")
20:             (beginning-of-line)))))))

Entonces, partiendo de esa función, no nos es difícil escribir esta otra para exportar desde Org:

(defun verso-largo-org ()
  "extrae el verso más largo de un bloque VERSE y lo coloca para exportar a LaTeX"
  (interactive)
  (my-org-babel-goto-block-corner nil)
  (org-narrow-to-block)
  (goto-longest-line)
   (region-active-p)
   (copy-region-as-kill (region-beginning) (region-end))
   (widen)
   (my-org-babel-goto-block-corner nil)
   (previous-line)
   (insert "#+begin_export latex")
     (newline)
    (save-excursion
   (insert "\\settowidth{\\versewidth}{")
   (yank))
    (save-excursion
   (end-of-line)
   (insert "}")
	 (newline)
	 (insert "#+end_export")))

Nuestro bloque VERSE acabaría luciendo entonces tal que así:

#+begin_export latex
\settowidth{\versewidth}{La princesa está triste... ¿Qué tendrá la princesa?}
#+end_export

#+begin_verse
La princesa está triste... ¿Qué tendrá la princesa?
Los suspiros se escapan de su boca de fresa,
que ha perdido la risa, que ha perdido el color.
La princesa está pálida en su silla de oro,
está mudo el teclado de su clave sonoro,
y en un vaso, olvidada, se desmaya una flor.

El jardín puebla el triunfo de los pavos reales.
Parlanchina, la dueña dice cosas banales,
y vestido de rojo piruetea el bufón.
La princesa no ríe, la princesa no siente;
la princesa persigue por el cielo de Oriente
la libélula vaga de una vaga ilusión.
#+end_verse

Estrambote: una consideración final

Téngase en cuenta, dicho todo lo anterior, que estamos en Emacs y que (muy probablemente) usaremos allí una fuente mono-espaciada, en mi caso la DejaVu Sans Mono, de la que soy devoto. Esto quiere decir que, en unos (por fortuna) pocos casos), el verso más largo en la fuente de Emacs no será el mismo que el verso más largo en la fuente de anchura variable de nuestra salida tipográfica tras la compilación con LaTeX. Habrá que estar al tanto y, si es necesario, hacer una enmienda manual de versos.

Publicado: 22/05/2019

Última actualización: 22/05/2019


Índice general

Acerca de...

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

Notas:

1

En este argumento opcional podemos incluir otras longitudes que se nos antojen, no sólamente \versewidth. Si el poema, por ejemplo, contiene versos que ocupan varias líneas, no tendría sentido declarar el valor del verso más largo, ya que éste equivaldría al ancho de la caja de texto. En tal caso, la longitud elegida ha de ser \textwidth. El paquete verse compondrá esos versos como un párrafo normal y corriente, sólo que dejará sangrada la última línea.

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