Notxor tiene un blog

Defenestrando la vida

Formularios y datos con forms-mode de Emacs

2020-06-23

A veces echaba de menos la forma sencilla y eficiente que tenía el dbase para proporcionar formularios que facilitaban la edición de datos. Apenas cuatro comandos que disponían en la pantalla de texto los campos de los registros y uno podía ponerse a introducir, modificar y borrar datos de una base de datos.

En estos días me he visto en la tesitura de gestionar datos que me han llegado en hojas de cálculo ─la navaja suiza de quien no conoce Emacs─. Tenía que revisar y en su caso modificar algunos datos en una tabla casi infinita, llena de columnas, que se perdían por los lados, haciendo muy difícil saber dónde estabas. Me acordé de los formularios de Emacs y decidí probarlos.

Para el ejemplo del artículo, muestro la gestión de una tabla grande (con muchos registros), pero con muchas menos columnas, o campos, para no liar las explicaciones. Ese ejemplo funciona sobre la biblioteca de libros de la Frateco de Zaragoza.

Captura-forms-libroj.png

Captura de pantalla de cómo funciona el forms-mode de Emacs. En la ventana se puede apreciar que hay cuatro campos (en amarillo) que nos permiten modificar los contenidos. En este caso está modo edición, si estamos en modo vista o read only, los campos no se destacan. Además, si vemos lo que nos cuenta la línea de estado vemos varios datos que nos pueden llamar la atención:

Estructura de los datos

Los datos para forms-mode tienen una estructura muy básica: son ficheros de texto, conde cada registro se encuentra en una línea y cada campo está separado por un carácter especial. Si no se especifica cual, forms-mode entiende que es \t (un tabulador). Los campos pueden mostrarse también en varias líneas. Esas líneas se separan dentro del campo utilizando un carácter "\^k" (C-k), por defecto, aunque se puede definir el que queramos con la variable forms-multi-line. Si se establece ese valor a nil deshabilita los campos en varias líneas.

Los campos son posicionales de izquierda a derecha y cuando definamos la estructura del formulario en pantalla, los podemos insertar mediante su número de orden en el fichero de datos. Sin embargo, veremos que hay una forma más cómoda de hacerlo y dotar de nombre a cada campo.

En el caso del ejemplo, se hizo un volcado de datos desde una hoja de cálculo a CSV, pero utilizando como separador de campos el carácter |, porque si se hubiera utilizado la prosaica , hubiera cortado los títulos que contienen comas, aunque estén delimitados por comillas, forms ignora esas estructuras y se fija sólo en el separador establecido.

Fichero de control

El fichero de control que gestiona el formulario es el siguiente:

;; forms-mode por Frateca Biblioteko

(setq forms-read-only t)

(setq forms-field-sep "|")

(setq forms-file "./FratecoBiblioteko.csv")

(setq forms-number-of-fields
      (forms-enumerate
       '(kodo         ; 1
         numero       ; 2
         aŭtoro       ; 3
         titolo       ; 4
         )))

(setq forms-format-list
      (list
       "====== Biblioteko de Frateco el Zaragozo =======\n\n"
       "Kodo: " kodo " -- " "Numero: " numero "\n\n"
       "Aŭtoro: " aŭtoro "\n"
       "Titolo: " titolo "\n\n"
       "=============== Klarigo de kodoj ===============\n\n"
       "F = Biblioteko Frateco -- O = Biblioteko Olavide\n\n"
       "ESE = Eseoj, filozofio, religio, politiko\n"
       "LER = Lernolibroj, legolibroj\n"
       "LIN = Lingvo, Interlingvistiko\n"
       "MOV = Movado, historio, esperantologio\n"
       "POE = Poezio\n"
       "ROM = Romanoj, noveloj, rakontoj\n"
       "SCI = Scienco\n"
       "TEA = Teatro\n"
       "VOJ = Vojagxoj,Geografio\n"
       "VOR = Vortaroj, Terminaroj\n"
       "KD = Kompakt-disko\n"
       "DVD = VideoDisko\n"
       "================================================\n\n"
       ))

Aunque es un código corto y suficientemente autoexplicativo lo cuento más despacio. Con la variable forms-read-only establecemos que inicie los datos en modo de sólo lectura ─luego veremos que podemos cambiar ese estado con una simple combinación de teclas─. La variable forms-field-sep se establece al carácter que hemos utilizado para exportar el fichero CSV: |. La variable forms-file establece el nombre del fichero donde se guardan los datos, en este caso ./FratecoBiblioteko.csv. En caso de no existir el fichero, forms lo crea. La variable forms-number-of-fields estable el número de columnas o campos que tiene cada línea. En este caso 4, pero se ha utilizado la función forms-enumerate para establecer ese número de columnas. Dicha función lo que hace es proveer de nombres, emparejando cada nombre con su número de posición y devolviendo el número más alto asignado. De esa manera, cuando en la definición de forms-format-list, que establece la estructura del formulario, podemos utilizar los nombres anteriores en lugar de su número correspondiente ─como se puede apreciar en el código─, porque a veces el orden de las columnas no es el que interesa mostrar. El truco de los nombres además nos ahorra muchos quebraderos de cabeza en caso de que los campos no sigan el mismo orden que en el fichero de datos. En la variable form-format-list se especifica el formato de los datos en el fichero de datos.

En la lista de formato se pueden proporcionar una serie de valores para especificar lo que se mostrará:

  • Cadena: Una cadena se mostrará tal cual está escrita.
  • Número: Indica el número de campo del registro. En nuestro ejemplo, los hemos sustituido con forms-enumerate por atoms con el nombre.
  • Lista: O mejor dicho, una forma. Especifica una llamada a una función. La función se la llama cada vez que se muestra un registro y su resultado ─que debe ser una cadena─ se muestra en pantalla.

Si no se especifica una lista de formato, forms genera una simple lista, cada campo en una línea con la etiqueta del número correspondiente delante de cada campo.

Iniciar forms-mode

La manera directa de iniciar el modo es llamar a M-x forms-find-file con el nombre de fichero de control, en el ejemplo form-libros.el. Hacerlo de ese modo en lugar del habitual find-file con C-x C-f inicia forms-mode de manera automática al cargarlo. Si lo abrimos con C-x C-f nos lo abrirá como cualquier fichero de código elisp. Si una vez abierto queremos iniciar el modo tendremos que lanzar M-x forms-mode. Es decir, iniciamos el modo en dos pasos, en lugar de en uno.

Podríamos saltarnos ese segundo paso colocando -*- forms -*- en la primera línea del fichero, sin embargo, si quisiéramos modificar el contenido del código del fichero, tendríamos problemas, porque automáticamente entrará en modo forms y no en modo elisp. Como es un fichero elisp, se le puede meter toda la magia elisp que necesitemos y dotar a los datos de algo más de vida.

Movernos y trabajar con los datos

Una vez situados en nuestro formulario podemos movernos por los diferentes campos y registros:

  • Movimientos entre los campos:
    <TAB>
    Mover el cursor al siguiente campo dentro del formulario. También se puede utilizar C-c <TAB>.
    S-<TAB>
    Hace el movimiento contrario al anterior, con mayúsculas+tabulador se va al campo anterior en el formulario.
  • Movimientos entre registros:
    C-c C-n
    Muestra el siguiente registro forms-next-record. También podemos utilizar Av.Pág. Si estamos en modo View también podemos utilizar n, sin más.
    C-c C-p
    Muestra el registro anterior forms-prev-record. También se puede usar Re Pág. Si estamos en modo View también podemos utilizar p, sin más.
    C-c C-l
    Nos preguntará a qué registro debe saltar (en formato numérico) con el comando forms-jump-record. Si estamos en modo View también podemos utilizar l, sin más.
    C-c <
    Va al primer registro con forms-first-record. Si estamos en modo View también podemos utilizar <, sin más.
    C-c >
    Salta al último registro de la base de datos con el comando forms-last-record. Si estamos en modo View también podemos utilizar >, sin más.
    C-c C-s
    Busca una expresión hacia adelante en la base de datos con el comando forms-search-forward. Funciona como el comando de búsqueda habitual. Si estamos en modo View también podemos utilizar s, sin más.
    C-c C-r
    Busca una expresión hacia atrás en la base de datos con el comando forms-search-backward. Funciona como el comando de búsqueda hacia atrás. Si estamos en modo View también podemos utilizar r, sin más.
  • Modificación de datos:
    C-c C-q
    Intercambia el modo de sólo lectura con el comando forms-toggle-read-only, es decir entre los modos de View y edición. Esto nos permite movernos con libertad sin miedo a cambiar nada accidentalmente, (por ejemplo, con la instintiva pulsación de n en lugar de C-c C-n) y activar la edición sólo cuando sea necesario. Cuando el formulario está en modo View, también se puede utilizar q.
    C-c C-o
    Crea un nuevo registro y lo inserta justo antes del registro actual con el comando forms-insert-record. Comienza con los campos en blanco.
    C-c C-k
    Borra el registro actual con el comando forms-delete-record. Pregunta para confirmar si realmente se quiere borrar dicho registro. Si se utiliza con un parámetro numérico, no preguntará.
    C-x C-s
    Guarda los cambios en los datos que se hayan realizado.
  • Otras funciones
    M-x forms-print
    Genera una impresión de la base de datos en un buffer de nombre *forms-print* y lo intenta enviar a la impresora asociada con el comando del sistema /usr/bin/lpr. Cuidado con esto si tienes una impresora conectada y un fichero de datos con 3.000 registros, porque imprimirá uno en cada página.
    C-c C-x
    Sale del modo con el comando forms-exit. Si estamos en modo View también podemos utilizar x, sin más.

Conclusiones

Este modo es bastante sencillo de configurar y de utilizar. ¿Es útil? ... pues eso depende. En mi caso me ha venido muy bien cuando he tenido que trastear con una más que incómoda tabla hecha en una hoja de cálculo. El poder distribuir los campos en toda la pantalla, con etiquetas claras y la posibilidad de editar los datos, buscarlos sin perder la noción de lo que rodea a «esa cadena que buscas» teniendo toda la información de un vistazo. En fin, algo más amable que una hoja de cálculo, en la que muchas veces el contenido de las celdas no se veía de forma completa para evitar que el margen derecho de la tabla se perdiera en el infinito.

Además, aunque no lo he mencionado antes, se puede especificar un fichero gpg como fuente de los datos. Y esto es todo. Espero que os sea útil.

Categoría: emacs

Comentarios

Debido a algunos ataques mailintencionados a través de la herramienta de comentarios, he decidido no proporcionar dicha opción en el Blog. Si alguien quiere comentar algo, me puede encontrar en Mastodon y en Diaspora con el nick de Notxor.

También se ha abierto un grupo en Telegram, para usuarios de esa red.

Disculpen las molestias.