Formularios y datos con forms-mode de Emacs
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 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:
- El nombre del fichero es
forms-libros.el
. Luego hablaré sobre él más despacio y pondré el código completo. - Aparece el mensaje
Forms 2223/2613
que nos dice que está en modoForms" y los números indican el =registro actual/total registros
. - Cuando está en modo vista o read only aparece la marca
View
al lado del contador de registros.
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 utilizarAv.Pág
. Si estamos en modoView
también podemos utilizarn
, sin más. C-c C-p
- Muestra el registro anterior
forms-prev-record
. También se puede usarRe Pág
. Si estamos en modoView
también podemos utilizarp
, 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 modoView
también podemos utilizarl
, sin más. C-c <
- Va al primer registro con
forms-first-record
. Si estamos en modoView
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 modoView
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 modoView
también podemos utilizars
, 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 modoView
también podemos utilizarr
, 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 deView
y edición. Esto nos permite movernos con libertad sin miedo a cambiar nada accidentalmente, (por ejemplo, con la instintiva pulsación den
en lugar deC-c C-n
) y activar la edición sólo cuando sea necesario. Cuando el formulario está en modoView
, también se puede utilizarq
. 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 modoView
también podemos utilizarx
, 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.
Comentarios