Mostrando entradas con la etiqueta Lenguajes de marcas. Mostrar todas las entradas
Mostrando entradas con la etiqueta Lenguajes de marcas. Mostrar todas las entradas

jueves, 29 de enero de 2015

Pandoc: Plantillas personalizadas de LaTeX para generación de documentos pdf

[Esta entrada es una traducción libre al castellano de la versión original escrita en inglés en este mismo blog.]

Una de las características más interesantes, aunque pocas veces comentada, de Pandoc es la de sus plantillas para LaTeX. Las plantillas de Pandoc nos permiten seguir escribiendo en Markdown, en lugar de volver de nuevo a LaTeX puro, incluso en los casos en que tengamos que producir documentos que no se considerarían "normales". En tales situaciones es posible también aprovecharse de la simplicidad de Markdown y relegar todos los detalles engorrosos a nuestras plantillas, siempre y cuando nuestras plantillas se atengan a la sintaxis y semántica de Pandoc.

Como ejemplo ilustrativo, supongamos que debemos entregar con regularidad actas del día de reuniones en pdf, siguiendo un diseño formal, especializado y con mucho texto repetido de un acta a otra como el que se muestra en la siguiente imagen:

Pandoc no parece ser la mejor herramienta para esta tarea. Trataré de demostrar que, por el contrario, Pandoc es especialmente apropiado para ella.

Plantillas de Pandoc

Como todo usuario de Pandoc sabe, la conversión de Markdown a LaTeX en Pandoc se basa en una plantilla por defecto que viene incluida en la instalación de Pandoc. Si se ejecuta esta orden:
pandoc --standalone --output mi_documento.pdf mi_documento.md

O, con las formas abreviadas de las opciones:

pandoc -s -o mi_documento.pdf mi_documento.md

se está aplicando un plantilla LaTeX por defecto, llamada default.latex, que en mi sistema y versión actual de Pandoc (1.12.2.1) se encuentra en $PANDOC_DIR/data/templates/default.latex. El resultado de aplicar esa plantilla al documento Markdown es un fichero que la máquina LaTeX (actualmente, pdflatex es la máquina por defecto) procesa de forma transparente para producir el pdf final.

Un rápido vistazo a la plantilla por defecto muestra que dicha plantilla no es más que un fichero LaTeX normal y corriente en el que, además, se incluyen, ciertos determinados constructos (variables, condicionales y bucles).

Si queremos usar otra plantilla, en lugar de la plantilla por defecto, ya sea una versión personalizada de dicha plantilla, ya una plantilla que creemos nosotros mismos completamente desde cero, necesitaremos pasar el nombre del fichero que la contiene a la opción --template. Suponiendo que el fichero de entrada y nuestra plantilla están en el mismo directorio, la orden correspondiente sería algo parecido a esto:

pandoc -s --template="mi_plantilla.latex" -o mi_documento.pdf mi_documento.md

Variables en Pandoc

Una variable en Pandoc tiene la siguiente sintaxis:
$nombre-de-variable$

Cuando ejecutamos pandoc cada variable de la plantilla se substituye por su valor. Este valor se puede pasar a Pandoc de distintas formas. Una de ellas, como veremos más adelante, es pasárselo a través de la opción de línea de órdenes -M nombre-de-variable=valor(donde -M es la forma abreviada de --metadata).

Por lo respecta a las variables pre-definidas por Pandoc y que están incluidas en la plantilla por defecto, más información sobre la mayoría de ellas se encuentra en la documentación oficial (http://johnmacfarlane.net/pandoc/README.html#templates).

Para saber en concreto qué variables hay en la plantilla por defecto podemos también utilizar un filtro Unix como el siguiente:

grep -o '\$.*\$' /usr/share/pandoc/data/templates/default.latex \
| grep -v '\$endif\$\|\$else\$\|\$endfor\$'

Es especialmente importante destacar que hay una variable crítica pre-definida, la variable $body$, que toda plantilla debería incluir, puesto que el contenido propiamente tal de nuestro documento de entrada será introducido en su lugar.

Comprobemos esto último. Creemos una platilla LaTeX simple.latex con este contenido:

\documentclass{minimal}
\begin{document}
$body$
\end{document}

y ejecutemos pandoc para que reciba el input de la entrada estándar desde terminal. El resultado de nuestra sesión de prueba es el siguiente:

$ pandoc -s --template="simple.latex" --to latex
Hola
Ctrl+D
\documentclass{minimal}
\begin{document}
Hola
\end{document}

La primera línea es el comando ejecutado. Estoy pidiendo a Pandoc que aplique nuestra plantilla, simple.latex a la entrada que le vamos a pasar y que la convierta a formato LaTeX. Las dos siguientes líneas reproducen lo que he tecleado para que Pandoc lo consuma. Ctrl+D señala EOF (fin de fichero) y cierra la entrada estándar. El resto es la salida que Pandoc produce. Nótese que lo que he tecleado, "Hola", aparece tras el procesamiento, como esperábamos, en el lugar en que estaba $body$ en la plantilla.

Intentemos algo un poco más complicado. Añadamos una variable de nuestra cosecha, que llamaremos $saludo$, a la plantilla:

\documentclass{minimal}
\begin{document}
$saludo$
$body$
\end{document}
y comprobemos qué pasa:
$ pandoc -s -M saludo="Hola gente" --template="simple.latex" --to latex
Esto es Pandoc
Ctrl+D
\documentclass{minimal}
\begin{document}
Hola gente
Esto es Pandoc
\end{document}

La orden es casi idéntica a la de antes. El añadido clave es la opción -M comentada previamente. A diferencia de la variable predefinida $body$, tenemos ahora que pasar los valores de nuestras propias variables a pandoc a través de la opción -M. Como vemos, en la salida, la variable en la plantilla es sustituida por el que valor que hemos dado.

Condicionales

Los condicionales tienen esta sintaxis:
$if(variable)$
X
$else$
Y
$endif$ 

donde la cláusula $else$ es opcional.

Supongamos que nos interesa poder elegir, cuando sea necesario, entre diferentes clases de documentos para el mismo documento de entrada. En concreto, supongamos que queremos crear un documento minimal por defecto, a no ser que pidamos expresamente que el documento sea de otra determinada clase. Podemos conseguirlo a través de este condicional:

$if(mi-clase-doc)$
$mi-clase-doc$
$else$
minimal
$endif$

Hay que tener cuidado con la sintaxis. Cada cláusula (if(), else, endif) va rodeada por el signo $. Las variables que serán remplazadas por sus valores también van entre $. Los valores literales, así como las referencias a la variable en la cláusula if van sin ese signo.

Naturalmente, nuestro condicional debe colocarse en el lugar adecuado en la plantilla, a saber, la instrucción \documentclass:

\documentclass{$if(mi-clase-doc)$
               $mi-clase-doc$
               $else$
               minimal
               $endif$}
Escribir lo anterior en una sola línea quizá sea menos legible, pero también más característico del estilo LaTeX. Pongámosla, pues, así:
\documentclass{$if(mi-clase-doc)$$mi-clase-doc$$else$minimal$endif$}
\begin{document}
$saludo$
$body$
\end{document}

Toca poner a prueba la plantilla:

$ pandoc -s -M saludo="Hola gente" --template="simple.latex" --to latex
Esto debería ser minimal
Ctrl+D
\documentclass{minimal}
\begin{document}
Hola gente
Esto debería ser minimal
\end{document}

¡Funciona!

Probemos ahora la otra posibilidad:

$ pandoc -s -M saludo="Hola gente" -M mi-clase-doc="book" --template="simple.latex" --to latex
Y esto, book
Ctrl+D
\documentclass{book}
\begin{document}
Hola gente
Y esto, book
\end{document}

¡También funciona! Nótese que en esta ocasión hemos establecido el valor de la variable mi-clase-doc a "book" a través de la opción -M, tal como hicimos anteriormente con $saludo$.

Bucles

Los bucles funcionan de una manera semejante. La sintaxis básica de un bucle es la siguiente:
$for(variable)$
X
$sep$separador
$endfor$

La línea $sep$separador es opcional. Sirve para definir un separador entre elementos consecutivos.

Digamos que queremos anotar los participantes a una reunión en la primera línea de nuestro documento. Podemos definir una variable $partipante$ en nuestra plantilla y dejar que Pandoc rellene su contenido. Queremos además que los nombres de los participantes aparezcan separados por una coma. Podríamos hacer todo esto añadiendo lo siguiente a nuestra plantilla:

$for(participante)$
$participante$
$sep$, 
$endfor$

O en una sola línea y en el lugar de la plantilla que corresponde:

\documentclass{$if(mi-clase-doc$$mi-clase-doc$$else$minimal$endif$}

\begin{document}
Participantes: $for(participante)$$participante$$sep$, $endfor$

$saludo$
$body$
\end{document}

Hagamos de nuevo una prueba. Ahora añadiremos a la orden pandoc tantos -M participante=... como participantes queremos incluir.

$ pandoc -s -M saludo="Hola gente" -M participante="W. Shakespeare" -M participante="Edgar A. Poe" --template="simple.latex" --to latex
Menudo plantel
Ctrl+D
\documentclass{minimal}
\begin{document}
Participantes: W. Shakespeare, Edgar A. Poe

Hola gente
Menudo plantel
\end{document}

¡Estupendo! Todo funciona perfecto.

Bloques de meta-datos

Es, como poco, engorroso tener que pasar todas estas cosas a la línea de órdenes. No es obligatorio, por supuesto. Pandoc proporciona para esta tarea los así llamados bloques de meta-datos. Un bloque de meta-datos para nuestro experimento anterior tendría este aspecto:
---
mi-clase-doc: minimal
saludo: Hola gente
participante:
- William Shakespeare
- Edgar A. Poe
---

Este bloque no es más que un fragmento de texto que sigue las especificación YAML (http://yaml.org/spec). Aparte de esto, los bloques YAML que se incluyen en un documento para que Pandoc lo procese deben empezar con una línea de tres guiones y terminar con una línea de tres puntos o tres guiones como se ve en el ejemplo.

Un bloque de meta-datos consta de campos. Cada campo tiene un nombre y un valor asociado a ese nombre, separado del nombre por dos puntos. Algunos campos pueden contener varios valores, los cuales van precedidos por un guion, tal y como aparecen para el campo 'participante' en el ejemplo.

Estos bloques nos permiten pasar a pandoc toda la información requerida sin tener que complicarnos la vida con las opciones en la línea de órdenes. La forma habitual de usar estos bloques es añadirlos al principio de nuestro documento de entrada. Otra forma, en mi opinión mejor, es crear un fichero yaml que pasamos a la vez que el fichero de entrada.

Por ejemplo, si guardamos la entrada de nuestro último experimento (la cadena "Menudo plantel") en un fichero con nombre mi_documento.md y el bloque de meta-datos en un fichero con nombre variables.yaml, podemos llamar a pandoc como sigue para conseguir exactamente la misma salida que obtuvimos antes:

pandoc -s --template="simple.latex" --to latex mi_documento.md variables.yaml

El documento final de la reunión

Nuestra tarea inicial se vuelve realizable gracias a la flexibilidad de Pandoc, que acabamos de explicar. Es cuestión sencillamente de crear un documento LaTeX normal y corriente (nuestra plantilla) con unas pocas variables y un bucle. Todos los detalles complicados y el texto repetitivo se desplaza a la plantilla, mientras que el contenido relevante y propiamente tal puede escribirse como de costumbre y muy convenientemente en Markdown puro.

Como referencia reproduzco todos los ficheros implicados en la creación del documento que mostré al principio de esta entrada. No voy a añadir nada más acerca del LaTeX que he usado, que es, dicho sea de paso, un poco chapucero ;-) En cualquier caso, asumo que los lectores conocen LaTeX lo suficiente.

mi_documento.md

1.  Lorem ipsum dolor sit amet,

    Lorem ipsum dolor sit amet consectetur adipiscing elit,
    sed do eiusmod tempor incididunt ut labore et dolore
    magna aliqua.

2.  Ut enim ad minim veniam,

    Ut enim ad minim veniam, quis nostrud exercitation ullamco
    laboris nisi ut aliquip ex ea commodo consequat.

3.  Duis aute irure dolor

    Duis aute irure dolor in reprehenderit in voluptate velit
    esse cillum dolore eu fugiat nulla pariatur.

4.  Excepteur sint occaecat

    Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum

mi_plantilla.latex

\documentclass[a4paper]{extreport}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[spanish]{babel}
\usepackage{marginnote}
\usepackage{background}

\setlength{\parindent}{0pt}

\SetBgScale{1}
\SetBgColor{black}
\SetBgAngle{0}
\SetBgHshift{-0.52\textwidth}
\SetBgVshift{-1mm}
\SetBgContents{\rule{0.4pt}{\textheight}}

\setlength{\marginparwidth}{32mm}
\renewcommand*{\raggedleftmarginnote}{}
\reversemarginpar

\begin{document}
\textbf{Informe}\marginnote{$for(asistente)$$asistente$$sep$\\ $endfor$}

$body$

\section{}
Freedonia, $dia$ de $mes$ de $ano$ 

\section{}
Jefe del Departamento

\vspace{2cm}
\emph{Firma: átopos}
\end{document}

variables.yaml

---
dia: 25
mes: Enero
ano: 2015
asistente:
- William Shakespeare
- Edgar A. Poe
- Miguel de Cervantes
---

La orden de Pandoc que genera el pdf

pandoc -s --template="mi_plantilla.latex" -o mi_documento.pdf mi_documento.md variables.yaml

domingo, 25 de enero de 2015

Pandoc: Customized LaTeX templates for PDF generation

One of the most interesting, however rarely commented, features of Pandoc is its support for LaTeX templates. Pandoc templates allows us to keep writing mostly in Markdown, instead of falling back to LaTeX, even if we have to produce documents that wouldn't be considered as "normal". In those cases we can still take advantage of Markdown simplicity by delegating all the gory-details to our own templates as long as they stick to the Pandoc syntax and semantics.

As an illustration, let us suppose we have to regularly deliver very formalized (with a lot of boilerplate text) but at the same time really specialized (as for design) pdfs of meeting minutes such as the following:

It would seem that Pandoc is not the best option for this task. I'll try to prove that Pandoc might be, on the contrary, particularly suitable.

Pandoc templates

As every Pandoc user knows converting to LaTeX from markdown relies on a default template included in the Pandoc installation. Issuing this command
pandoc --standalone --output my_document.pdf my_document.md

Or, using short options, for brevity

pandoc -s -o my_document.pdf my_document.md

applies a default LaTeX template named default.latex that, on my system and current version (1.12.2.1), can be found at $PANDOC_DIR/data/templates/default.latex. The result of applying the template to the markdown document is a file processed transparently by a LaTeX engine (currently, pdflatex by default) that produces the final pdf output.

A quick inspection into the default template reveals that a Pandoc template is just a normal LaTeX file in which certain specific constructs (variables, conditionals and loops) are included.

To use another template, either a customized version of the default template, or our own template written from scratch, we need to pass its filename to the option --template. Assuming that the template file is in the same directory as the input file the pandoc command would be as follows:

pandoc -s --template="my_template.latex" -o my_document.pdf my_document.md

Pandoc Variables

A variable in Pandoc has the following syntax.
$variable-name$

Every variable in the template will be replaced with its actual value. This value can be passed in different ways. One of them is to pass it via the -M variable-name=value (--metadata is the long name switch) Pandoc command line option, as we will see later.

As for pre-defined variables contained in the default template, you can see more information about most of them in the Pandoc documentation (http://johnmacfarlane.net/pandoc/README.html#templates).

Another useful way to know what variables are actually present in the default template is to extract them with a Unix filter:

grep -o '\$.*\$' /usr/share/pandoc/data/templates/default.latex \
| grep -v '\$endif\$\|\$else\$\|\$endfor\$'

A very important thing to point out is that there is a critical variable, $body$ that should be present in every template. This variable is implicitly replaced with the actual content of our input.

Let's check the latter by creating a minimal LaTeX template simple.latex

\documentclass{minimal}
\begin{document}
$body$
\end{document}

and issuing pandoc to take our input from the terminal [Below is a reproduction of the test]

$ pandoc -s --template="simple.latex" --to latex
Hi
Ctrl+D
\documentclass{minimal}
\begin{document}
Hi
\end{document}

The first line is the command issued. I'm telling Pandoc to apply our own template over whatever input is going to be passed, and convert it to LaTeX. The following lines are what I've actually typed in to be consumed by pandoc, hitting Ctrl+D (in Linux and other Unixes) signals EOF and closes the standard input. The rest is the output produced by pandoc. Note that what I've typed in, "Hi", is now in place of the $body$ variable, as expected.

Let's try something a bit more complicated, adding our own variable, say $greeting$, to our template:

\documentclass{minimal}
\begin{document}
$greeting$
$body$
\end{document}

and test it as before

$ pandoc -s -M greeting="Hi, World" --template="simple.latex" --to latex
This is Pandoc!
Ctrl+D
\documentclass{minimal}
\begin{document}
Hi, World
This is Pandoc!
\end{document}

The command is almost the same. The critical add-on is the -M option referred above. Unlike the variable $body$, the values for our variables need to be passed to pandoc explicitly via the -M option. Again, the variable in the template is replaced with the given value to produce the output.

Conditionals

Conditionals have this syntax:
$if(variable)$
X
$else$
Y
$endif$ 

where the $else$ part is optional.

Let's suppose that we want to be able to choose between different document classes for the same document as needed. In particular, we want to create a minimal document by default, or another document class on demand. We can do this by creating this conditional:

$if(my-doc-class)$
$my-doc-class$
$else$
minimal
$endif$

Be careful about the syntax. Each syntactic part (if(), else, endif) is enclosed in dollar signs. Variables to be replaced by their values are also surrounded by that sign. Literal values, as well as the variable reference in the if section go without them, though. Of course, we have to put this conditional in the suitable place, the LaTeX \documentclass macro:

\documentclass{$if(my-doc-class)$
               $my-doc-class$
               $else$
               minimal
               $endif$}

One-liners maybe less readable but more LaTeX-style aware. So put the corresponding one-liner into the template:

\documentclass{$if(my-doc-class)$$my-doc-class$$else$minimal$endif$}
\begin{document}
$greeting$
$body$
\end{document}
Now, Let's check:
$ pandoc -s -M greeting="Hi, World" --template="simple.latex" --to latex
This should be a minimal
Ctrl+D
\documentclass{minimal}
\begin{document}
Hi, World
This should be a minimal
\end{document}

It works!

Let's try the second use case:

$ pandoc -s -M greeting="Hi, World" -M my-doc-class="book" --template="simple.latex" --to latex
And this one, a book
Ctrl+D
\documentclass{book}
\begin{document}
Hi, World
And this one, a book
\end{document}

It also works! Note that this time the previously defined variable my-doc-class is set to the value "book" by means of the option -M as we did before with $greeting$

Loops

Loops behave in a similar manner. The basic syntax is as follows:
$for(variable)$
X
$sep$separator
$endfor$

The $sep$separator line (for defining a separator between consecutive items) is optional.

Let's say we want to take note of participants in a meeting as the very first line in our document. We can define a variable participant in our template and leave Pandoc to fill its content. We want to separate by commas the names of participants. So we can add this to the template:

$for(participant)$
$participant$
$sep$, 
$endfor$
Or just a one-liner in the corresponding place:
\documentclass{$if(my-doc-class)$$my-doc-class$$else$minimal$endif$}

\begin{document}
Participants: $for(participant)$$participant$$sep$, $endfor$

$greeting$
$body$
\end{document}

Testing again ... Now we add as many -M participant=... options as participants we wish to set.

$ pandoc -s -M greeting="Hi, World" -M participant="W. Shakespeare" -M participant="Edgar A. Poe" --template="simple.latex" --to latex
Good staff!
Ctrl+D
\documentclass{minimal}
\begin{document}
Participants: W. Shakespeare, Edgar A. Poe

Hi, World
Good staff!
\end{document}
Nice. Everything works fine!

Metadata blocks

It's cumbersome, to say the least, being forced to pass all those things to the command line. You aren't, of course. Pandoc provides the so-called metadata blocks for this task. A metadata block for our previous experiments would look like as follows:
---
my-doc-class: minimal
greeting: Hi, World
participant:
- William Shakespeare
- Edgar A. Poe
---

This is just a chunk of text following the YAML specification (http://yaml.org/spec). YAML blocks included in a document to be consumed by pandoc must begin with three hyphens and end with three points or three hyphens.

A metadata block consists of fields. Each field has a name and its associated value separated by semicolon. Some fields can contain multiple values preceded by a hyphen like the participant field in the previous example.

These blocks allow us to pass to pandoc all the required information without bothering with the command line switches. The customary way is to add the block at the beginning of our input document. Another way, even better in my opinion, is to create a yaml file that we pass to pandoc along with our input file.

For instance, if we save the input of our last experiment (the "Good staff!" string) in a file named my_document.md and the metadata block above in a file named variables.yaml, pandoc can be called to produce exactly the same output as the one we obtained before (try it!) as follows:

pandoc -s --template="simple.latex" --to latex my_document.md variables.yaml

The final meeting document

Our initial task becomes feasible due to the explained Pandoc flexibility. It's just a matter of creating a normal LaTeX document (our template) with a bit of variables and loops. All of the gory-details and boilerplate text will be shifted to the template while the actual and relevant content could be written, as usual and conveniently, in pure Markdown.

For reference I reproduce all the files involved in the creation of the document shown at the beginning of this entry. No further comments about LaTeX here, that is a bit quick&dirty, BTW ;-) I'm assuming readers already know LaTeX, anyway.

my_document.md

1.  Lorem ipsum dolor sit amet,

    Lorem ipsum dolor sit amet consectetur adipiscing elit,
    sed do eiusmod tempor incididunt ut labore et dolore
    magna aliqua.

2.  Ut enim ad minim veniam,

    Ut enim ad minim veniam, quis nostrud exercitation ullamco
    laboris nisi ut aliquip ex ea commodo consequat.

3.  Duis aute irure dolor

    Duis aute irure dolor in reprehenderit in voluptate velit
    esse cillum dolore eu fugiat nulla pariatur.

4.  Excepteur sint occaecat

    Excepteur sint occaecat cupidatat non proident, sunt in
    culpa qui officia deserunt mollit anim id est laborum

my_template.latex

\documentclass[a4paper]{extreport}
\usepackage[T1]{fontenc}
\usepackage{marginnote}
\usepackage{background}

\setlength{\parindent}{0pt}

\SetBgScale{1}
\SetBgColor{black}
\SetBgAngle{0}
\SetBgHshift{-0.52\textwidth}
\SetBgVshift{-1mm}
\SetBgContents{\rule{0.4pt}{\textheight}}

\setlength{\marginparwidth}{32mm}
\renewcommand*{\raggedleftmarginnote}{}
\reversemarginpar

\begin{document}
\textbf{Report}\marginnote{$for(attendee)$$attendee$$sep$\\ $endfor$}

$body$

\section{}
Freedonia, $month$ $day$, $year$ 

\section{}
Chief of Departament

\vspace{2cm}
\emph{Signature: atopos}
\end{document}

variables.yaml

---
day: 25
month: January
year: 2015
attendee:
- William Shakespeare
- Edgar A. Poe
- Miguel de Cervantes
---

The Pandoc command to generate the pdf

pandoc -s --template="my_template.latex" -o my_document.pdf my_document.md variables.yaml

[Spanish translation on the way...]

domingo, 11 de enero de 2015

Typesetting code with latex and minted. A real-world example.

More than 4 years without writing a word in this blog :(

What if I blend the trend right now? What about something on (what else!) LaTeX?

I was trying to reread some pages from the K&R's C book taking notes along the way for my own use, and I wondered what LaTeX has to offer nowadays beyond the venerable listings package.

And I've found out minted

listings and minted user interfaces are similar. So the transition from one to the other is most of the time seamless. Anyway, both interfaces are clean and easy to use. Though listings may be more flexible, minted has an advantage for lazy users like me: no need to create custom syntax highlighting styles since, thanks to the Python Pygments library integration provided by minted, we can get state of the art and wonderful highlighting niceties automatically!

The only requirement (of course) is to have Python installed as well as the Pygments library. That's probably the case if you are using a modern Linux (MacOSX?) distro. For Windows users you may need to consult minted package documentation (particularly, section 2.4).

If Pygments is not already installed (I assume Python is installed, it will be on almost all modern Unixes):

pip install Pygments

should do the job.

This is what I get (just a draft):

Nice, isn't it? The LaTeX I've used is as follows.

The preamble is self-explanatory:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{minted}  % The expected way to load minted macros
The C code for this file comes from the same single file strlen2.c. It's natural to search for a way to input text from files directly instead of writing it over and over. The \inputminted command provides the desirable support:
\begin{document}
...
\inputminted[linenos]{c}{strlen2.c}
In general, the \inputminted macro expects an optional set of key-value pairs (some options will be explained later) and two mandatory arguments: the programming language in which the code is written, C in my case, and the name of the file containing the actual code.
\inputminted[<options>]{<language>}{<filename>}
Interestingly, there is no need to rewrite code fragments, a really boring and error-prone task. We can select lines in the file on demand. For listings users this is a piece of cake, both packages provide practically the same keywords for options related to inputting code fragments. For the text at hand:
  • firstline=<number>
  • lastline=<number>
These options are self-explanatory. They select lines of interest from the first one to the last one, both included. To display line numbers we have the option:
  • linenos=true
Or, simpler, as every LaTeX user knows:
  • linenos
I want to print the actual C code line numbers as they appear in the source. By default the line-number counter is reset to 1 for any code fragment, though. Therefore, I also have to provide the actual initial line number for each chunk:
  • firstnumber=<number>
Finally, a colored frame background might make things more readable and beautiful:
  • background=<color>
I've defined a color for this purpose in the preamble:
\definecolor{bg}{rgb}{0.95,0.95,0.95}
and refer to it as the value for background to obtain the final macro. Thus, the LaTeX code for the third C code fragment above would look like this:
\inputminted[background=bg,linenos,firstnumber=6,firstline=6,lastline=7]{c}{strlen2.c}
Copy&pasting such a huge macro is awful. As usual, laziness can be our best friend. This is a suitable place for putting a familiar macro shorthand in the preamble:
\newcommand{\Cfrag}[3]{%
\inputminted[%
  bgcolor=bg,
  linenos,
  firstnumber=#1,
  firstline=#1,
  lastline=#2
]{c}{#3}}
This way each chunk of code can be included with a more friendly macro. For instance:
\Cfrag{6}{7}{strlen2.c}
All in all, the final LaTeX file looks as follows:
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{minted}

\definecolor{bg}{rgb}{0.95,0.95,0.95}
\newcommand{\Code}[1]{\texttt{#1}}
\renewcommand{\labelitemi}{\color{red!50!black}\guilsinglright}

\newcommand{\Cfrag}[3]{%
\inputminted[%
  bgcolor=bg,
  linenos,
  firstnumber=#1,
  firstline=#1,
  lastline=#2
]{c}{#3}}

\begin{document}
\section{The \Code{strlen} function}
\inputminted[linenos]{c}{strlen2.c}

\section{Commentary}
\Cfrag{1}{2}{strlen2.c}

\begin{itemize}
...
\end{itemize}

\Cfrag{4}{4}{strlen2.c}

\begin{itemize}
...
\end{itemize}

\Cfrag{6}{7}{strlen2.c}

\begin{itemize}
...
\end{itemize}

\Cfrag{8}{8}{strlen2.c}

\begin{itemize}
...
\end{itemize}
\end{document}
And a last one important thing. You need to pass the option -shell-escape to pdflatex in order to get a pdf from a latex file containing minted macros. Something like this:
pdflatex -shell-escape strlen_commentary.tex

martes, 24 de marzo de 2009

HAL y las marcas (Markdown y Pandoc)

No es improbable que el lector impaciente se canse de tanta marca y decida seguir trabajando con los medios que ya conoce, que no son otros que los omnipresentes procesadores de textos. Dirá que ya le costó lo suyo desenvolverse en los complejos menús del procesador como para ponerse ahora a cambiar toda su forma de escritura por unos enigmáticos "códigos" más que difíciles de teclear y peores de aprender. Insistirá en que para la Web le bastan los formularios de su plataforma de blogging, con sus perfectas barras de herramientas, tan estupendamente semejantes a las de los procesadores de texto. Concederá, finalmente, con inconfesada ironía, que el resultado con LaTeX es sorprendentemente bonito, pero total, para la cuatro cosas que va a escribir...

Estos son los argumentos habituales que esgrimen los usuarios que podríamos calificar propiamente y sin intención ofensiva alguna como usuarios "esclavos", pues es esclavo quien permanece completamente atado a la tecnología que, de un modo un otro, le es impuesta, ya porque constituye la corriente dominante, ya porque es la primera que aprendió o, tal vez con mayor probabilidad, por ambas cosas juntas. Tales argumentos no son, en el fondo, más que racionalizaciones pergeñadas con el único fin de continuar encastillado en una posición inamovible.

Ni HTML ni LaTeX son más difíciles de aprender que las innumerables opciones de menú de los procesadores de textos. En realidad, es mucho más natural plantear la tarea de escribir un documento electrónico cuando se establece de antemano una separación clara entre la estructura de su contenido y su forma de presentación.

Podríamos llegar a aceptar que la introducción de las marcas, particularmente en el caso de HTML, mucho más prolijo en esto que LaTeX, puede llegar a ser bastante pesada, si no se dispone de las herramientas que para esta tarea proporcionan editores como Vim o Emacs. Pero, como vamos a ver hoy, hasta este último baluarte de la recalcitrante defensa del procesador de textos, cae ante la presencia de los lenguajes de marcas "ligeros" como Markdown, que es el representante que hemos escogido de entre los muchos existentes.

No hay forma de sostener racionalmente la indiferencia displicente ante los lenguajes de marcas cuando nos hallamos ante caso tan natural como el siguiente:

% Un ejemplo de Markdown
% átopos
% 25 de Marzo de 2009

# Navegación gráfica
Si hubiésemos estado visitando la página con un buen navegador gráfico que disponga de la opción de guardar las páginas web como texto, tendríamos que realizar al menos dos acciones, ambas independientes:

1. Ir al menú "Archivo" del navegador y guardar como texto la página web. (Lo que además implica seleccionar un nombre de fichero y un directorio).
2. Crear en _Vim_ una nueva ventana para editar en ella el documento que acabamos de guardar, mediante la orden `:new ruta_fichero`.

# Navegación desde consola
Si navegamos con _w3m_, y gracias a la interacción entre las aplicaciones de consola, bastaría ejecutar una única acción desde el propio _Vim_, que, además, podríamos abreviar para reproducirla en situaciones semejantes. Veamos cómo.

Con _w3m_ el proceso de convertir una página web en texto es absolutamente elemental: añadir la opción `-dump`. Por ejemplo:

    w3m -dump http://www.w3.org/TR/html401/struct/lists.html

nos devuelve la página dada como argumento, tal cual se presenta en el navegador, pero como puro texto.

Esto ya parece dar gato por libre. ¿Dónde están las marcas? ¿No es éste el texto tal cual lo hubiéramos escrito, de no existir el maravilloso procesador de textos? ¡Menudo avance! ¡Un regreso a las cavernas!

Fíjese bien el lector incrédulo, porque las marcas siguen estando, pero reducidas a su más mínima expresión [El signo indica un espacio]:

% Un ejemplo de Markdown
% átopos
% 25 de Marzo de 2009

# Navegación gráfica
Si hubiésemos estado visitando la página con un buen navegador gráfico que disponga de la opción de guardar las páginas web como texto, tendríamos que realizar al menos dos acciones, ambas independientes:

1.¶Ir al menú "Archivo" del navegador y guardar como texto la página web. (Lo que además implica seleccionar un nombre de fichero y un directorio).
2.¶Crear en _Vim_ una nueva ventana para editar en ella el documento que acabamos de guardar, mediante la orden `:new ruta_fichero`.

# Navegación desde consola
Si navegamos con _w3m_, y gracias a la interacción entre las aplicaciones de consola, bastaría ejecutar una única acción desde el propio _Vim_, que, además, podríamos abreviar para reproducirla en situaciones semejantes. Veamos cómo.

Con _w3m_ el proceso de convertir una página web en texto es absolutamente elemental: añadir la opción `-dump`. Por ejemplo:

¶¶¶¶w3m -dump http://www.w3.org/TR/html401/struct/lists.html

nos devuelve la página dada como argumento, tal cual se presenta en el navegador, pero como puro texto.

Las equivalencias con nuestras marcas informales, (incluidos los añadidos de los últimos días), que frente a tal simplicidad resultan terriblemente embarazosas, son transparentes como la luz de un día radiante. Hagásmolas explícitas, por si alguien sigue todavía encerrado entre cuatro paredes:

TÍTULO, AUTOR y FECHA:
%

INICIO TÍTULO SECCIÓN:
#

FIN TÍTULO SECCIÓN
[No necesario]

INICIO SECCIÓN
[No necesario]

FIN SECCIÓN
[No necesario]

INICIO PÁRRAFO
Línea en blanco

FIN PÁRRAFO
[No necesario]

INICIO LISTA NUMERADA
[No necesario]

FIN LISTA NUMERADA
[No necesario]

INICIO ELEMENTO LISTA
1.¶ [y 2. , etc, para los siguientes elementos]

FIN ELEMENTO LISTA
[No necesario]

INICIO NOMBRE PROGRAMA
_ [guión bajo]

FIN NOMBRE PROGRAMA
_

INICIO OPCIÓN
` [acento grave]

FIN OPCIÓN
`

INICIO ORDEN
`

FIN ORDEN
`

INICIO BLOQUE ORDEN
¶¶¶¶

FIN BLOQUE ORDEN
[No necesario]


Estas marcas, excepto la primera, pertenecen al lenguaje de marcas ligero conocido como Markdown. Su sintaxis completa se explica aquí. La única precaución que hay que tomar es, como cabe esperar, la de escapar las marcas de Markdown cuando se van a introducir como caracteres literales en el texto corriente. Por ejemplo, para introducir literalmente un asterisco (*) tendremos que escribir \*. Quedan excluidos los casos en que esos signos aparecen dentro de un fragmento de código (entre acentos graves) o en los bloques de código (que se identifican, como hemos visto, por su sangría de cuatro espacios). A las marcas de Markdown se pueden añadir algunas otras, por ejemplo, la barra (|) para señalar una celda de una tabla. Este conjunto de extensiones se conoce como Markdown Extra.

Bien, las marcas fáciles, facilísimas, están ahí. ¿Qué podemos hacer con ellas? Los enterados saben que son la base, por ejemplo, de muchos sistemas de wikis. Pero nosotros no tenemos un wiki, todavía. No hace falta pensar, sin embargo, en aplicaciones especializadas. Los lenguajes de marcas ligeros pueden servir para escribir nuestros documentos y para que ayudantes especiales de HAL nos los devuelvan en un formato apto para su presentación, ya sea en la web o, incluso, en bella versión imprimible.

Pandoc es uno de estos eficientes colaboradores de HAL. Se trata de un conversor universal de un lenguaje de marcas a otro. Emplea las mismas marcas de Markdown y Markdown Extra con algunas extensiones y mejoras, como la marca % para elementos del encabezado. Las variantes de Pandoc en relación con Markdown / Markdown Extra se pueden consultar aquí.

Pandoc está disponible en Debian y se puede instalar como cualquier paquete:

aptitude install pandoc

Con Pandoc la conversión de nuestro texto a HTML, LaTeX y otros muchos lenguajes de marcas es cosa de niños, basta con pedírselo a HAL.

Supongamos que el texto anterior lo guardamos en el fichero texto_etiquetado-pandoc.mdml (la extensión mdml, que es opcional, es una abreviatura de MarkDown Markup Language). En tal caso, podríamos solicitar a HAL lo siguiente:

HAL, llama a tu ayudante en conversión de marcas para que convierta 'texto_etiquetado-pandoc.mdml' de [from] Markdown a [to] HTML.

Que se puede expresar así:

pandoc -f markdown -t html texto_etiquetado-pandoc.mdml

HAL nos devolverá el texto marcado con HTML, un HTML muy parecido al que obtuvimos hace unos días, aunque con un formato distinto, que en ningún caso afecta a la interpretación que un navegador hará de él. De hecho, la salida de pandoc se puede enviar directamente a w3m mediante una tubería:

pandoc -f markdown -t html texto_etiquetado-pandoc.mdml | w3m -T text/html

Se advertirá que en el HTML resultante no hay rastro de lo marcado con %, esto es, título, autor y fecha. Esta información se debería integrar en la cabecera de HTML (la etiqueta HEAD), pero pandoc la descarta por defecto, a menos que le indiquemos lo contrario con la opción --standalone (= autónomo), o -s, en versión abreviada. Con esta opción activada, pandoc crea un documento autónomo, un HTML completo con su declaración de documento y su oportuna cabecera. Podemos volver a ejecutar la orden, redirigir el resultado a w3m y, por medio de la orden v de w3m, inspeccionar el HTML.

pandoc -s -f markdown -t html texto_etiquetado-pandoc.mdml | w3m -T text/html

La conversión a LaTeX sigue los mismos derroteros:

pandoc -f markdown -t latex texto_etiquetado-pandoc.mdml

Y la versión autónoma se obtiene mediante el mismo procedimiento:

pandoc -s -f markdown -t latex texto_etiquetado-pandoc.mdml

El resultado es prácticamente idéntico a uno de los nuestros. La única diferencia reseñable está en el preámbulo del documento, una diferencia que sí afectaría al resultado final del procesamiento con pdflatex. La razón es que pandoc no tiene en cuenta, porque no puede saberlo de antemano, que nuestro texto está escrito en castellano. Tenemos que decírselo explícitamente. La forma de hacerlo es bien simple. Creamos, para empezar, un fichero, llamémoslo preambulo-latex, que contenga nuestro preámbulo, por ejemplo, éste:

\documentclass[a4paper]{article}
\usepackage[spanish]{babel}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{bera}

Después, se informa a pandoc de nuestro preámbulo para que lo aplique en lugar del que él utliza por defecto. Para ello recurrimos a la opción --custom-header (= cabecera personalizada) o, su versión abreviada, -C:

pandoc -s -C preamulo_latex -f markdown -t latex texto_etiquetado-pandoc.mdml

El resultado se podría redirigir a un fichero para procesarlo más tarde con pdflatex.

Con el fin de evitarnos los pasos intermedios en la generación del PDF, Pandoc proporciona como alternativa rápida el guión markdown2pdf, que generaría un fichero con extensión pdf y el mismo nombre de nuestro fichero original:

markdown2pdf -C preambulo_latex texto_etiquetado-pandoc.mdml

Pandoc, aparte de su facultad para convertir a otros muchos formatos, permite usos más sofisticados, como, por ejemplo, introducir directamente marcas LaTeX en el documento marcado con Markdown que se mantendrán literalmente en el documento resultante, lo que facilita la construcción de documentos LaTeX más elaborados. Todo esta documentado en la página web citada y en el fichero README, que se encuentra en la documentación del paquete Debian: /usr/share/doc/pandoc/README.gz.

Con Markdown y Pandoc finalizamos, de momento, este primer contacto con los lenguajes de marcas. Mucho queda en el tintero. Es casi vergonzoso no haber presentado, en particular, el metalenguaje XML y algunos de los lenguajes de marcas construidos a partir de él. Otra vez será.


Resumen

  • Los lenguajes de marcas ligeros facilitan el tecleado de las marcas y pueden aprenderse en pocos minutos.

  • Markdown es un lenguaje ligero de marcas.

  • Pandoc es un sistema de conversión de lenguajes de marcas, especialmente apropiado para producir documentos LaTeX sencillos a partir de lenguajes de marcas ligeros. Ofrece una interfaz de línea de comandos a través de la orden pandoc y de algún guión, como markdown2pdf, para facilitar la generación de documentos típicos.

lunes, 23 de marzo de 2009

HAL y las marcas (LaTeX - anexo)

Recurrir al paquete listing para un tarea tan elemental como la que requiere nuestro simplísimo texto de ejemplo es como hablar con HAL únicamente para preguntarle su nombre. No es de recibo dejar ese fleco abierto. Un texto más complejo permitirá apreciar por qué listing es un paquete ampliamente recomendado para la presentación de código.

Vamos a producir un documento que incluya directamente el código de una orden de las primerísimas que vimos en estas conversaciones con HAL. Se trata del código, escrito en C, de la orden hostname. El código mismo no puede distribuirse sino mediante la licencia GPL, como se especifica en su primer comentario. Aquí sólo mostramos el fichero LaTeX para producir el documento y la primera página que resulta de su procesamiento. Las marcas que no se han explicado se señalan en rojo. El lector interesado puede encontrar ayuda completa sobre estas marcas y sobre listings en /usr/share/doc/texlive-doc/latex/listings/listings.pdf, si su distribución está basada en Debian.

El breve fichero LaTeX a partir del que generaremos la versión coloreada del código es éste:

\documentclass[a4paper]{article}
\usepackage{bera}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{xcolor}
\usepackage{listings}
\lstset{%
numbers=left,
basicstyle=\footnotesize\ttfamily,
commentstyle=\color{violet},
stringstyle=\color{magenta},
keywordstyle=\color{purple},
identifierstyle=\color{teal},

}

\begin{document}
\lstinputlisting[language=C]{hostname.c}
\end{document}

Y ésta es una imagen con la primera página del documento generado:



¡Happy Latexing!

HAL y las marcas (LaTeX - VI)

El día pasado acudimos excepcionalmente a una orden de estilo para poder integrar los resultados habituales del paquete listings en nuestro texto. Ya puestos, y como la veda se ha levantado parcialmente, vamos a tolerar otra excepción y sustituir la marca que establecimos para nombres de programas.

Es una convención frecuente presentar estos nombres con una familia de fuente diferente. Puesto que la familia por defecto en LaTeX es Serif y, puesto que la familia Typewritter (Monospace) es la elegida para el código, la opción recomendable es reservar la familia restante de la típica triada, Sans Serif, para nuestros nombres de programas.

Podríamos etiquetarlos directamente con la marca que define justo esa familia:

\textsf{nombre_programa}

Pero, dado que esta marca no dice nada sobre la función estructural del texto marcado y ante la posibilidad, además, de que cambiemos en el futuro de idea al definir las características de presentación de los nombres de programas, es mucho mejor crear una marca propia, llamémosla \Prog, que permita envolver la citada definición de fuente u otras definiciones futuras.

Para crear marcas propias, lo que en terminología de LaTeX se llamarían órdenes propias, se usa la orden de LaTeX \newcommand. Esta orden tendría, en el caso que nos ocupa el siguiente aspecto:

\newcommand{\Prog}[1]{\textsf{#1}}

La sintaxis indica que, en el lugar en el que nosotros pongamos la marca \Prog{texto}, donde texto es el argumento único (argumento 1 de \Prog), el sistema de procesamiento del documento pondrá \textsf{texto}. El texto en \textsf es el mismo texto de \Prog, que se pasa como valor al primer y único contenedor, #1, que nuestra orden \newcommand ha establecido para \textsf.

Lo único que hay que tener en cuenta a la hora de crear estas marcas propias es que el nombre de la marca elegida no exista ya entre las marcas de LaTeX o entre las de sus paquetes. Si albergamos dudas al respecto, podemos utilizar, en lugar de \newcommand, la orden \providecommand, que tendrá el mismo resultado que \newcommand cuando \Prog no sea una marca de LaTeX o sus paquetes y que no producirá efecto alguno, cuando la marca ya exista:

\providecommand{\Prog}[1]{\textsf{#1}}

Finalmente, para que las órdenes \newcommand o \providecommand sean tenidas en cuenta, se deben incluir en el preámbulo del documento después de las solicitudes de carga de paquetes.

Con este último refinamiento podríamos considerar acabado nuestro trabajo con las marcas de LaTeX, pero aún podemos introducir unas pocas mejoras más.

En primer lugar, vamos a utilizar un tipo de fuente distinta de la que por defecto utiliza LaTeX. La razón es que, aunque la fuente por defecto de LaTeX (Computer Modern) es estupenda para texto impreso, cabe la posibilidad de que nuestro documento se visualice más frecuentemente en pantalla. Una fuente más legible en pantalla puede ser beneficiosa. Seleccionaremos la fuente Bera, que viene incluida en TeX Live y que se activa mediante la carga de un paquete:

\usepackage{bera}

Y ya que asumimos que nuestro documento se verá en pantalla, podríamos también beneficiarnos del uso de colores, especialmente para resaltar los fragmentos de código.

Para disponer de soporte de colores en un documento LaTeX podemos usar el paquete xcolor.

\usepackage{xcolor}

El color para todo el código se puede establecer con la etiqueta \color{nombre_color} en la configuración inicial de listings:

\lstset{basicstyle=\color{teal}\small\ttfamily}

También añadiremos una sección previa con el título del documento, el autor y la fecha (la fecha la introduce por defecto LaTeX). Se debe solicitar explícitamente la generación del título mediante la orden \maketitle. El grupo de marcas adecuadas puede ir todo él justo después de \begin{document}, aunque hay quien prefiere situar \title y \author en el preámbulo.

\title{Un ejemplo juguete de \LaTeX}
\author{átopos}
\maketitle

(Cuando la palabra 'LaTeX' aparece precedida por la barra invertida, tal como acabamos de hacer, el tipógrafo producirá un versión embellecida de esa palabra. Es el ejemplo típico que se espeta a los usuarios de sistemas de preparación de documentos no profesionales: "¡Aficionados, a ver cómo os las apañáis para producir estos nuestros hermosos tipos!".)

Finalmente, estableceremos el tamaño de la página a A4, que es el modelo de página habitual en Europa. Basta para ello una opción en la declaración inicial de la clase de documento:

\documentclass[a4paper]{article}

Hemos terminado de etiquetar con LaTeX nuestro documento. Proponemos como ejercicio para el lector la modificación de los ficheros txt2latex.sed y generar_latex que corresponda a las transformaciones y añadidos que hemos introducido en estos dos últimos capítulos. El fichero txt2latex.tex resultante debería ser el siguiente:

\documentclass[a4paper]{article}
\usepackage[spanish]{babel}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{bera}
\usepackage{xcolor}
\usepackage{listings}
\lstset{basicstyle=\color{teal}\small\ttfamily}

\newcommand{\Prog}[1]{\textsf{#1}}

\title{Un ejemplo juguete de \LaTeX}
\author{átopos}

\begin{document}
\maketitle


\section{Navegación gráfica}
Si hubiésemos estado visitando la página con un buen navegador gráfico que disponga de la opción de guardar las páginas web como texto, tendríamos que realizar al menos dos acciones, ambas independientes:

\begin{enumerate}
\item Ir al menú <<Archivo>> del navegador y guardar como texto la página web. (Lo que además implica seleccionar un nombre de fichero y un directorio).
\item Crear en \Prog{Vim} una nueva ventana para editar en ella el documento que acabamos de guardar, mediante la orden \lstinline!:new ruta_fichero!.
\end{enumerate}

\section{Navegación desde consola}
Si navegamos con \Prog{w3m}, y gracias a la interacción entre las aplicaciones de consola, bastaría ejecutar una única acción desde el propio \Prog{Vim}, que, además, podríamos abreviar para reproducirla en situaciones semejantes. Veamos cómo.

Con \Prog{w3m} el proceso de convertir una página web en texto es absolutamente elemental: añadir la opción \lstinline!-dump!. Por ejemplo:
\begin{lstlisting}
w3m -dump http://www.w3.org/TR/html401/struct/lists.html
\end{lstlisting}
nos devuelve la página dada como argumento, tal cual se presenta en el navegador, pero como puro texto.
\end{document}

Tras procesar este fichero con pdflatex, se obtiene texto_etiquetado.pdf, que podrá verse con cualquier lector de PDFs:



Resumen

  • LaTeX permite crear marcas personalizadas con la orden \newcommand o con la orden \providecommand

  • El paquete xcolor proporciona soporte de colores en documentos LaTeX.

  • La creación de una sección previa con el título del documento y de su autor o fecha de escritura es trivial con LaTeX.

HAL y las marcas (LaTeX - V)

Nuestro fichero marcado con LaTeX no es una traducción perfecta de nuestro fichero marcado con marcas informales. Ante el desconocimiento de marcas LaTeX apropiadas para los elementos peculiares y, en principio, exclusivos de nuestro texto original (nombre de programa, opción y orden), llegamos al compromiso provisional de suprimir tales marcas.

No hay nada en LaTeX que obligue a una concesión tan poco justa. De hecho, LaTeX proporciona dos marcas, equivalentes al <EM> y al <CODE> de HMTL, que pueden desempeñar perfectamente el mismo papel:

\emph{texto}
Marca el texto como texto enfatizado.

\verb CAR texto CAR
Marca el texto como código de computador. CAR funciona aquí como delimitador y puede ser cualquier carácter que no forme parte del texto que marca. (Los espacios no deben incluirse y se han escrito sólo para facilitar su comprensión). Así, por ejemplo, el fragmento de texto '-dump' se podría marcar de esta forma: \verb!-dump!.


Por si fuera poco, LaTeX dispone también de un entorno semejante a \verb para marcar bloques independientes de código, como el que constituye la penúltima línea de nuestro texto original. Lo que implica que deberíamos haber utilizado una marca diferente para el bloque de código que constituye esa línea. Por ejemplo:

INICIO BLOQUE ORDEN
w3m -dump http://www.w3.org/TR/html401/struct/lists.html
FIN BLOQUE ORDEN


Si, además, concebimos dicha línea como un bloque de código, resulta innecesario situarla ahora como un párrafo aparte y pensar la línea subsiguiente como otro párrafo más. En realidad, esa forma de escribir no sería estructuralmente correcta, si es que tenemos en cuenta el sentido mismo del texto. La multiplicación de párrafos es una consecuencia indeseable de no haber comprendido que la línea en cuestión debe formar parte del mismo párrafo, lo que en ningún caso significa que no pueda tener un valor estructuralmente especial dentro de él, como bloque de código lógicamente independiente. Es notable como LaTeX nos fuerza, pues, a ser más finos a la hora de estructurar nuestra escritura, gracias a la disponibilidad de marcas distintas para unidades lógicas diferentes.

En consecuencia, la parte afectada de nuestro texto con marcas informales se puede reescribir ahora de una forma más precisa:

INICIO PÁRRAFO
Con INICIO NOMBRE PROGRAMAw3mFIN NOMBRE PROGRAMA el proceso de convertir una página web en texto es absolutamente elemental: añadir la opción INICIO OPCIÓN-dumpFIN OPCIÓN. Por ejemplo:
INICIO BLOQUE ORDEN
w3m -dump http://www.w3.org/TR/html401/struct/lists.html
FIN BLOQUE ORDEN
nos devuelve la página dada como argumento, tal cual se presenta en el navegador, pero como puro texto.
FIN PÁRRAFO

Con estas nuevas marcas de LaTeX es casi trivial modificar el fichero txt2latex.sed para que procese estas tres líneas como debe:

s/INICIO NOMBRE FICHERO/\\emph{/g
s/FIN NOMBRE FICHERO/}/g
s/INICIO ORDEN/\\verb!/g
s/FIN ORDEN/\!/g
s/INICIO BLOQUE ORDEN/\n\\begin{verbatim}\n/g
s/FIN BLOQUE ORDEN/\n\\end{verbatim}\n/g

Por otra parte, habría que suprimir, además, la línea de txt2latex.sed que añadía el carácter de escape al guión bajo, puesto que ya no es necesaria: en un fragmento de texto con las marcas LaTeX mentadas los caracteres especiales de LaTeX se interpretan literalmente sin que haya necesidad de escaparlos.

Tras ejecutar el guión generar_latex fichero_etiquetado.txt ---fichero_etiquetado.txt se ha de modificar previamente como acabamos de explicar---, el fichero resultante, fichero_etiquetado.tex tendría el siguiente aspecto:

\documentclass{article}
\usepackage[spanish]{babel}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\begin{document}

\section{Navegación gráfica}
Si hubiésemos estado visitando la página con un buen navegador gráfico que disponga de la opción de guardar las páginas web como texto, tendríamos que realizar al menos dos acciones, ambas independientes:

\begin{enumerate}
\item Ir al menú <<Archivo>> del navegador y guardar como texto la página web. (Lo que además implica seleccionar un nombre de fichero y un directorio).
\item Crear en \emph{Vim} una nueva ventana para editar en ella el documento que acabamos de guardar, mediante la orden \verb!:new ruta_fichero!.
\end{enumerate}

\section{Navegación desde consola}
Si navegamos con \emph{w3m}, y gracias a la interacción entre las aplicaciones de consola, bastaría ejecutar una única acción desde el propio \emph{Vim}, que, además, podríamos abreviar para reproducirla en situaciones semejantes. Veamos cómo.

Con \emph{w3m} el proceso de convertir una página web en texto es absolutamente elemental: añadir la opción \verb!-dump!. Por ejemplo:
\begin{verbatim}
w3m -dump http://www.w3.org/TR/html401/struct/lists.html
\end{verbatim}
nos devuelve la página dada como argumento, tal cual se presenta en el navegador, pero como puro texto.
\end{document}

Si el LaTeX básico dispone de marcas suficientes para etiquetar todo nuestro texto original, ¿por que no las comentamos a su debido tiempo? ¿Por qué hemos diferido su explicación hasta ahora?

La razón es que no vamos a utilizar las marcas descritas, sino otras, más elaboradas, que obligan a recurrir a algún paquete que extienda las funcionalidades básicas de LaTeX. Y no las vamos a utilizar, porque, aunque son perfectamente válidas para un texto tan simple como el de nuestro ejemplo, conviene tener noticia de mecanismos más sofisticados y aptos para situaciones más complejas. De paso, veremos tomaremos contacto con el tipo de mecanismos habituales en el uso de paquetes.

Un paquete especialmente indicado para casos en los que hay que introducir código es el paquete listings, que vendrá instalado en cualquier distribución de LaTeX y, por supuesto, en TeX Live. El paquete listings suministra dos marcas parejas al \verb y al entorno verbatim comentados anteriormente. Son las siguientes:

\lstlisting CAR código CAR
Permite marcar fragmentos de código.

\begin{lstlisting}código\end{lstlisting}
Permite marcar bloques de código.


listings, como cualquier paquete, debe cargarse en el preámbulo del documento con la orden:

\usepackage{listings}

Tras ella suele aparecer una orden de configuración de las opciones del paquete. En nuestro caso, es imprescindible, al menos, una opción, la que defina la fuente básica con que se mostrará el código para que se diferencie del texto corriente. \verb y verbatim lo hacían por nosotros, establecían la fuente como perteneciente a la familia Typewriter, pero listings no lo hace por defecto, y no lo hace, porque no presupone por adelantado que nuestro documento pueda contener algo más que código. Debemos pues, excepcionalmente, tocar este aspecto del estilo. La orden que permite refinar la configuración de listings es \lstset{opciones_configuración} y la opción para modificar la familia de la fuente básica de forma que utilice la familia Typewriter es basicstyle=\ttfamily. Por otra parte, listings suele requerir de una disminución del tamaño de la fuente básica cuando las líneas de código son más largas de lo acostumbrado, como la penúltima línea de nuestro texto original. Ahí podemos utilizar la orden \small de LaTeX, que utiliza una fuente más pequeña de la habitual. En nuestro caso concreto, la opción podría aparecer también como parte de la configuración básica, es decir, dentro de \lstset, o bien como opción que matiza un entorno lstlisting en particular. Nosotros vamos a quedarnos con la primera posibilidad, aunque pueda ser discutible desde el punto de vista estético.

Por tanto, y teniendo en cuenta las anteriores explicaciones, deberíamos añadir estas dos líneas al preámbulo de nuestro documento:

\usepackage{listings}
\lstset{basicstyle=\small\ttfamily}


Finalmente sólo falta sustituir los \verb y \verbatim de antes por las marcas equivalentes de listings [Las modificaciones se muestran en azul]:

\documentclass{article}
\usepackage[spanish]{babel}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{listings}
\lstset{basicstyle=\small\ttfamily}


\begin{document}
\section{Navegación gráfica}
Si hubiésemos estado visitando la página con un buen navegador gráfico que disponga de la opción de guardar las páginas web como texto, tendríamos que realizar al menos dos acciones, ambas independientes:

\begin{enumerate}
\item Ir al menú <<Archivo>> del navegador y guardar como texto la página web. (Lo que además implica seleccionar un nombre de fichero y un directorio).
\item Crear en \emph{Vim} una nueva ventana para editar en ella el documento que acabamos de guardar, mediante la orden \lstinline!:new ruta_fichero!.
\end{enumerate}

\section{Navegación desde consola}
Si navegamos con \emph{w3m}, y gracias a la interacción entre las aplicaciones de consola, bastaría ejecutar una única acción desde el propio \emph{Vim}, que, además, podríamos abreviar para reproducirla en situaciones semejantes. Veamos cómo.

Con \emph{w3m} el proceso de convertir una página web en texto es absolutamente elemental: añadir la opción \lstinline!-dump!. Por ejemplo:
\begin{lstlisting}
w3m -dump http://www.w3.org/TR/html401/struct/lists.html
\end{lstlisting}
nos devuelve la página dada como argumento, tal cual se presenta en el navegador, pero como puro texto.
\end{document}



Resumen

  • LaTeX suele favorecer e, incluso, forzar, al escritor a tomar conciencia plena de la estructura lógica de sus escritos.

  • El paquete listings extiende las funcionalidades básicas de LaTeX para la edición de documentos que contengan cualquier clase de código.

  • La mayoría de los paquetes, como listings, proporcionan marcas u órdenes especializadas que el usuario puede utilizar de acuerdo con sus fines concretos.

  • Las paquetes más versátiles, como listings, proporcionan al usuario la posibilidad de configurar muchos detalles que afectan al resultado final.

sábado, 21 de marzo de 2009

HAL y las marcas (LaTeX - IV)

Vale. Hemos marcado nuestro texto como LaTeX prescribe. Pero ¿cómo podemos ver el resultado?

Para un texto marcado con marcas HTML el navegador hace las veces del experto que lo procesa y del soporte para su visualización. Para un texto marcado con LaTeX, las dos acciones, la de procesar el documento y la de visualizarlo, son, sin embargo, competencia de dos agentes diferentes: el tipógrafo y el "lector" o "visualizador" del documento resultante, normalmente, en nuestros días, un fichero PDF.

El tipógrafo más recomendable en la actualidad para documentos LaTeX se llama pdfTeX, un descendiente del original TeX, que todavía se sigue usando, y mucho. LuaTeX, nieto de TeX e hijo de pdfTeX, podría consolidarse como el noble heredero de ambos en los próximos años.

pdfTeX y todo lo que se requiere para procesar un documento LaTeX viene incluido en todas las distribuciones modernas de GNU/Linux. En Debian, por ejemplo, se empaqueta dentro de los paquetes que incluyen el prefijo texlive-. TeX Live, que es la distribución más completa que existe para procesar documentos con LaTeX, es realmente grande y por eso Debian ofrece la posibilidad de instalar todo TeX Live, mediante el paquete texlive-full, o sólo una parte básica, mediante el paquete texlive y otros posibles añadidos.

Si el lector dispone de una gran cantidad de disco duro puede proceder a instalar texlive-full:

aptitude install texlive-full

En caso de que quiera ahorrar espacio, bastará con que instale, por lo pronto, tres paquetes (de los cuales sólo los dos primeros son imprescindibles):

aptitude install texlive texlive-lang-spanish texlive-doc-es

Tenemos ya a nuestros expertos ahí disponibles para todo lo que les ordenemos. No perdamos más tiempo y hagamos que pongan su imprenta en marcha sobre nuestro documento. Llamaremos a pdflatex que es el ayudante de pdfTeX encargado de procesar los documentos LaTeX:

pdflatex texto_etiquetado.tex

Si no hay ningún error sintáctico en nuestras marcas LaTeX, pdflatex terminará su trabajo rápidamente tras expulsar algunos mensajes sobre el procesamiento. El resultado quedará guardado en el fichero texto_etiquetado.pdf. Cualquier lector de PDF nos mostrará el resultado:



Pero, ¿y si hemos cometido un error sintáctico en las marcas? Lo que sucederá es que pdflatex se detendrá y nos mostrará un mensaje de error. Los mensajes de error de pdflatex pueden ser difícilmente comprensibles; lo peor, sin embargo, es que tendremos que aprender algunos atajos de teclado para salir del procesamiento detenido y, sobre todo, nos veremos obligados a volver a ejecutar pdflatex cuantas veces sea necesario hasta corregir todos los errores. Una opción para evitar, al menos, esto último, es utilizar un corrector de la sintaxis de LaTeX antes de procesar el documento con pdflatex. Podemos recurrir a lacheck, que viene incluido en TeX Live.

Imaginemos, por ejemplo, que nos comimos ---un hambre descuidada produce estos males--- la llave de cierre en la primera sección y el \end{enumerate} al final de la lista. O sea:

...
6 \begin{document}
7 \section{Navegación gráfica <== Falta llave de cierre
8 Si hubiésemos estado visitando la página con un buen navegador gráfico que disponga de la opción de guardar las páginas web como texto, tendríamos que realizar al menos dos acciones, ambas independientes:
9
10 \begin{enumerate}
11 \item Ir al menú <<Archivo>> del navegador y guardar como texto la página web. (Lo que además implica seleccionar un nombre de fichero y un directorio).
12 \item Crear en Vim una nueva ventana para editar en ella el documento que acabamos de guardar, mediante la orden :new ruta\_fichero.
13 <== Falta \end{enumerate}
14
15 \section{Navegación desde consola}
16 Si navegamos con w3m, y gracias a la interacción entre las aplicaciones de consola, bastaría ejecutar una única acción desde el propio Vim, que, además, podríamos abreviar para reproducirla en situaciones semejantes. Veamos cómo.
17
18 Con w3m el proceso de convertir una página web entexto es absolutamente elemental: añadir la opción -dump. Por ejemplo:
19
20 w3m -dump http://www.w3.org/TR/html401/struct/lists.html
21
22 nos devuelve la página dada como argumento, tal cual se presenta en el navegador, pero como puro texto.
23
24 \end{document}

Sobre este texto, que guardamos como el nombre texto_erroneo.tex, ejecutamos ahora lacheck:

lacheck texto_erroneo.tex

Aparecerán los siguientes mensajes:

"texto_erroneo.tex", line 24: <- unmatched "\end{document}"
"texto_erroneo.tex", line 10: -> unmatched "\begin{enumerate}"
"texto_erroneo.tex", line 25: <- unmatched "end of file texto_erroneo.tex"
"texto_erroneo.tex", line 7: -> unmatched "{"
"texto_erroneo.tex", line 25: <- unmatched "end of file texto_erroneo.tex"
"texto_erroneo.tex", line 6: -> unmatched "\begin{document}"

El analizador sintáctico, aunque emite mensajes que no son absolutamente claros, ayuda a localizar rápida y exactamente la línea o líneas que contiene los errores cometidos. Nótese que se muestran mensajes de error para las últimas líneas del fichero, la 24 y la 25, así como para la primera del fragmento, la línea 6. Estos mensajes de error son provocados por nuestros verdaderos errores, los que afectan a las líneas 7 y 13, que, como un efecto en cadena, disparan los mensajes relativos al resto de líneas. Una vez corregidas las líneas defectuosas (la 7 y la 13), el resto de mensajes de error desaparecerá.

La moraleja es que hay que ser cuidadoso a la hora de marcar textos (los buenos editores como Vim o Emacs suelen ayudar ya de entrada en esta tarea) y que conviene utilizar un analizador sintáctico como lacheck antes de procesar el documento con pdflatex.


Resumen:

  • pdflatex es el tipógrafo de documentos LaTeX recomendado en la actualidad. pdflatex forma parte de la máquina tipográfica pdfTeX.

  • pdfTeX es heredero de TeX. LuaTeX, por su parte, es heredero de pdfTeX y se perfila como su futuro sucesor.

  • La distribución actualmente más completa para procesar documentos LaTeX es TeX Live. TeX Live viene empaquetada por Debian en el paquete texlive (que contiene lo básico) y otros paquetes con el prefijo texlive-.

  • lacheck es un analizador de la sintaxis de marcas LaTeX. Es recomendable analizar la corrección de nuestra sintaxis antes de procesar nuestro documento con pdflatex.

HAL y las marcas (LaTeX - III)

Como sucede con HTML, también LaTeX requiere de cierto protocolo para definir aspectos básicos del documento marcado según sus convenciones y para que el experto o expertos que procesen estas marcas sepan cómo hacerlo exactamente. Por fortuna, este formulismo inicial es bastante más fácil de entender y de explicar que el de HTML. Nos limitaremos, no obstante, a comentar los aspectos más importantes de él y a confiar en que lector sabrá encontrar información más detallada en los enlaces propuestos en los primeros párrafos de este otro artículo.

La estructura de un documento LaTeX listo para su procesamiento es básicamente la siguiente:

PREÁMBULO

\begin{document}
[Nuestro texto con las marcas LaTeX]
\end{docuemnt}

Así pues, si retomamos la metáfora aplicada en la exposición de HTML, vemos que también el gabinete de LaTeX precisa que nuestro texto marcado se envíe en un sobre document y que a ese sobre le peguemos una etiqueta que contenga descripciones precisas de lo que va en él (el PREÁMBULO). Un preámbulo típico para documentos en castellano consta de los siguientes enunciados:

\documentclass{article}
\usepackage[spanish]{babel}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

Veamos qué significa cada uno de ellos:

\documentclass{article}
Define el tipo de documento que creamos. En nuestro caso un artículo.

\usepackage[spanish]{babel}
Define la lengua en la que está escrito nuestro documento.

\usepackage[T1]{fontenc}
Define el tipo de codificación de la fuente empleada por defecto. Es recomendable para lenguas que contienen, como la nuestra, caracteres acentuados.

\usepackage[utf8]{inputenc}
Define el tipo de codificación empleada al escribir el texto. En cualquier máquina moderna será UTF-8.


Más allá de los tecnicismos ---por los que hemos pasado rozando---, lo que salta a la vista en las tres últimas líneas del preámbulo es la marca \usepackage{...}. Se trata de un tipo de orden que le indica a los expertos que procesarán nuestro documento que use un determinado tipo de paquetes LaTeX y que active, en caso necesario, tales o cuales opciones de ese paquete, donde las opciones solicitadas se indican entre corchetes de acuerdo con la sintaxis \usepackage[opciones]{paquete}.

¿Pero qué es un paquete de LaTeX? Un paquete no es sino una extensión para determinados propósitos de las posibilidades básicas de LaTeX. Algunas de estas extensiones actúan sobre los engranajes de las máquinas que procesarán LaTeX y sólo deberemos ser conscientes de ellos a la hora de incluirlos en el preámbulo. Otras pueden poner a disposición del usuario nuevas marcas especializadas a las que éste puede recurrir si lo desea. Así, por citar sólo un caso particular, el paquete babel permite escribir documentos en varias lenguas (las que se indican como opciones suyas) y seleccionar una u otra lengua cuando convenga mediante, por ejemplo, la orden o marca \selectlanguage{lengua}. En el caso de nuestro ejemplo sólo utilizamos una lengua, spanish, y podemos prescindir de estas sofisticaciones. Por lo demás, el recurso a paquetes es especialmente recomendable cuando nuestro texto va a contener elementos característicos propios que requerirán de un tratamiento específico. Veremos un caso de ello en un artículo posterior.

Bien. Nos queda sólo incluir el preámbulo comentado y el envoltorio document en nuestro texto marcado con LaTeX para obtener un documento LaTeX completo listo para su procesamiento. Si seguimos la misma estrategia empleada en la generación del documento HTML a partir de nuestro texto con marcas informales, bastaría con modificar ligeramente el guión generar_html de este modo:

## --* generar_latex - 21/03/09 - átopos *--
## Genera documento LaTeX canónico a partir de un documento de texto
## marcado con mis marcas informales
SED_F=txt2latex.sed # Fichero sed: convierte mis marcas
# informales en marcas LaTeX
ORIG_F=$1 # Fichero de entrada
DEST_F=$(basename $ORIG_F .txt).tex # Fichero LaTeX de salida

tr -d '\n'< $ORIG_F \
| sed -f $SED_F
\
| awk 'BEGIN {
print "\\documentclass{article}";
print "\\usepackage[spanish]{babel}";
print "\\usepackage[T1]{fontenc}";
print "\\usepackage[utf8]{inputenc}\n";
print "\\begin{document}";

}
{ print $0; }
END {
print "\\end{document}";
}' \
> $DEST_F

Las modificaciones, aparte de las que afectan a los comentarios, son las lógicas: cambia el fichero de órdenes para sed, que ahora será el txt2latex.sed que creamos el día pasado; se añade la orden tr, y se modifica el subsiguiente sed como corresponde (también lo comentamos ayer); se modifican mutatis mutandis las líneas que imprimirá awk al principio y al final (nótese que en awk, como en sed, el literal '\' debe escaparse).

El nuevo guión, que llamaremos generar_latex recibe como argumento el fichero con nuestras etiquetas informales y produce el fichero texto_etiquetado.tex. Tras cambiarlo de modo, podemos ejecutarlo:

./generar_latex texto_etiquetado.txt

El resultado, texto_etiquetado.tex, es el esperado:

\documentclass{article}
\usepackage[spanish]{babel}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\begin{document}
\section{Navegación gráfica}
Si hubiésemos estado visitando la página con un buen navegador gráfico que disponga de la opción de guardar las páginas web como texto, tendríamos que realizar al menos dos acciones, ambas independientes:

\begin{enumerate}
\item Ir al menú <<Archivo>> del navegador y guardar como texto la página web. (Lo que además implica seleccionar un nombre de fichero y un directorio).
\item Crear en Vim una nueva ventana para editar en ella el documento que acabamos de guardar, mediante la orden :new ruta\_fichero.
\end{enumerate}

\section{Navegación desde consola}
Si navegamos con w3m, y gracias a la interacción entre las aplicaciones de consola, bastaría ejecutar una única acción desde el propio Vim, que, además, podríamos abreviar para reproducirla en situaciones semejantes. Veamos cómo.

Con w3m el proceso de convertir una página web en texto es absolutamente elemental: añadir la opción -dump. Por ejemplo:

w3m -dump http://www.w3.org/TR/html401/struct/lists.html

nos devuelve la página dada como argumento, tal cual se presenta en el navegador, pero como puro texto.

\end{document}

Si queremos ver coloreada la sintaxis de LaTeX nada mejor que echar mano del propio Vim. Se puede llamar a Vim para ver ficheros, sin intención de editarlos, con la orden view, que es un atajo de vim -R:

view texto_etiquetado.tex

La imagen siguiente muestra el resultado:




Resumen:

  • Un documento LaTeX consta de un preámbulo y un entorno document. El preámbulo incluye, como mínimo, la definición de la clase de documento (artículo, libro, carta, etc.) y, normalmente, también la solicitud de uso de paquetes. El entorno document engloba todo el texto marcado con marcas LaTeX.

  • Un paquete de LaTeX es una extensión de las posibilidades básicas de LaTeX. La inclusión de paquetes se solicita en el preámbulo del documento con la etiqueta u orden \usepackage[opciones]{paquete}, donde cada opción activa un conjunto determinado de las extensiones que el paquete proporciona. Por ejemplo, \usepackage[spanish]{babel} permite usar el paquete para el uso de múltiples lenguas babel y beneficiarse de sus extensiones para el castellano.

viernes, 20 de marzo de 2009

HAL y las marcas (LaTeX - II)

Si quisiéramos acudir a un procedimiento automático para traducir nuestras marcas informales a marcas LaTeX, como hicimos para obtener nuestro documento HTML, deberíamos tener en cuenta la forma típica que adoptan los textos etiquetados con LaTeX, de lo que ayer se dio un brevísimo ejemplo, así como algunas de sus peculiaridades, tales como la manera de entrecomillar en español o la introducción literal de caracteres especiales.

¿Qué queremos decir con esto? La mejor manera de verlo es elaborar un fichero txt2latex.sed semejante al txt2html.sed de entonces. El fichero tendría por lo pronto este aspecto:

# Conversión de caracteres especiales
s/"\([[:alnum:]]\+\)"/<<\1>>/g
s/_/\\_/g

# Conversión de etiquetas
s/INICIO SECCIÓN//g
s/FIN SECCIÓN//g
s/INICIO TÍTULO SECCIÓN/\\section{/g
s/FIN TÍTULO SECCIÓN/}\n/g
s/INICIO PÁRRAFO//g
s/FIN PÁRRAFO/\n\n/g
s/INICIO LISTA NUMERADA/\\begin{enumerate}\n/g
s/FIN LISTA NUMERADA/\\end{enumerate}\n\n/g
s/INICIO ELEMENTO LISTA/\\item /g
s/FIN ELEMENTO LISTA/\n/g
s/INICIO NOMBRE PROGRAMA//g
s/FIN NOMBRE PROGRAMA//g
s/INICIO ORDEN//g
s/FIN ORDEN//g
s/INICIO OPCIÓN//g
s/FIN OPCIÓN//g

Buena parte de este fichero se entiende por sí mismo. Las etiquetas informales que no tienen traducción se sustituyen por nada, es decir, se eliminan. También hemos eliminado provisionalmente las etiquetas para nombre de programa, opción y orden, porque todavía no sabemos sus equivalencias en LaTeX. Allí donde queremos un salto de párrafo sustituimos la marca informal por la marca LaTeX equivalente más dos saltos de línea ---recuérdese que el salto de línea se expresa con '\n'. Estos dos saltos crean precisamente una línea en blanco. Nótese, en particular, que el carácter '\' de LaTeX debe escaparse con otro '\' (el carácter de escape de sed, y de casi todo en HAL), puesto que es un carácter especial de sed, justamente el que sirve para escapar un carácter cualquiera.

En cuanto a la primera sección del fichero, la relativa a la conversión de las comillas rectas por comillas angulares y la secuencia de escape para el carácter '_' explicada ayer, sólo nos puede extrañar la primera orden:

s/"\([[:alnum:]]\+\)"/<<\1>>/g

Entender lo que esta orden de sed significa implica conocer una nueva posibilidad de sed todavía no explicada: las referencias hacia atrás (backreferences). Miremos la expresión minuciosamente, porque casi todo nos debería resultar familiar.

s/RE/remplazo/g

es evidentemente una orden de sustitución de sed. Lo sustituido es todo lo que encaja con la expresión regular (RE) que hay a la izquierda. Analicemos primero esa expresión regular:

"\([[:alnum:]]\+\)"

Se trata de un molde para un texto entrecomillado ("texto"). Lo entrecomillado es un conjunto de caracteres alfanuméricos [[:alnum:]]. Este conjunto contiene uno o más miembros (el signo +), que en sed, frente a lo que ocurre con expresiones regulares extendidas, tiene que escaparse (\+). Además, este conjunto aparece agrupado (los paréntesis (...), que en sed deben también escaparse). Por tanto, la expresión regular designa todo fragmento de texto constituido por uno o más de un carácter alfanuméricos que esté entrecomillado por comillas rectas. En definitiva, esta expresión regular no contiene nada que no sepamos ya, salvo la necesidad de escapar algunos de sus caracteres.

Lo nuevo está en la expresión que se propone como remplazo:

<<\1>>

Las comillas angulares de inicio y cierre son justamente aquellas por las que queremos sustituir las comillas rectas del texto que encaje con la expresión regular. Lo que aparece entre estas comillas angulares es la enigmática expresión \1. Esta expresión simplemente recupera el contenido de lo registrado por sed cuando descubrió una agrupación en la expresión regular, es decir, todo lo que hay entre los paréntesis. (Como sólo se ha registrado una agrupación, la referencia hacia atrás es \1; si en la expresión regular apareciese una segunda agrupación, la referencia de esta segunda agrupación sería \2, etc.). Por tanto, el fragmento de texto constituido por los caracteres alfanuméricos va a aparecer intacto en el remplazo. Esta es la técnica habitual que se utiliza cuando una parte interna del texto que encaja con la expresión (en nuestro caso, lo entrecomillado) se quiere preservar y sólo otra parte (en nuestro caso, las comillas rectas) se quiere modificar.

Diseccionado el sentido de nuestro fichero txt2latex.sed, podemos utilizarlo para efectuar la sustitución de nuestras marcas informales ---que, recuérdese, aparecen en el fichero texto_etiquetado.txt--- por las de LaTeX y guardar el resultado en un fichero con la extensión .tex, que es la forma canónica de identificar ficheros LaTeX:

sed -f txt2latex.sed texto_etiquetado.txt >texto_etiquetado.tex

El resultado deja mucho que desear:

\section{
Navegación gráfica
}



Si hubiésemos estado visitando la página con un buen navegador gráfico que disponga de la opción de guardar las páginas web como texto, tendríamos que realizar al menos dos acciones, ambas independientes:
...

Los espacios en blanco están por doquier y se han generado saltos de línea donde no debía haberlos.

La causa del problema está en que sed, tras realizar cada sustitución, incluye el salto de línea en las líneas modificadas. Este comportamiento es conveniente en la mayoría de los casos ---nadie esperaría que sed se comiese el salto de línea, cuando de lo que se trata es de cambiar sólo una parte de una línea. Sin embargo, este educada manera de obrar es fatal para el caso que nos ocupa.

Hay varias formas de resolver el problema, que pasan por utilizar otro ayudante que no sea sed. Pero quizá la más sencilla para nuestro caso particular, y que no nos obliga a renunciar a sed, sea darle como entrada el mismo fichero pero transformado previamente en una única línea. Las marcas seguirán allí intactas y nada provocará saltos de línea innecesarios, más allá de los que nosotros hemos decidido producir en nuestras sustituciones, puesto que sed trabajará sobre una línea única.

Hacer que las múltiples líneas de un fichero se unan y constituyan una única línea se puede conseguir con distintas órdenes de HAL. Una de las más simples es la orden tr (de translate). Esta orden dispone de una opción adecuada a nuestros fines, la opción -d, que elimina (delete) de la entrada el carácter que demos como argumento a esa opción. Por ejemplo:

tr -d 'a'

eliminaría todas las aes de nuestra entrada.

Para convertir múltiples líneas en una única línea, el carácter que deberemos eliminar es justamente el salto de línea. Por tanto:

tr -d '\n'

es la orden apropiada para lograr nuestro propósito.

Hemos dicho que tr afecta a la "entrada" y no simplemente al "fichero" dado como argumento. ¿Por qué? La razón es que tr es una de esas pocas órdenes que no permite ficheros como argumentos. Dicho de otra forma, tr actúa sólo y directamente sobre el flujo de entrada del que se nutre. Esta característica la hace especialmente apta para integrarse en tuberías. Pero en nuestro caso, sigue siendo un fichero el que queremos darle como alimento.

Existe una forma de dar un fichero de alimento a una orden que trabaja únicamente sobre el flujo de entrada. Es una herramienta más de fontanería, el reverso del famoso embudo (>) que aplicamos para redirigir la salida de una orden a un fichero. Existe otro embudo, <, que realiza la función contraria: redirige un fichero hacia la entrada estándar. Si en el otro lado (el izquierdo) hay una orden que puede alimentarse directamente desde la entrada estándar (cualquiera de los filtros que hemos visto en anteriores artículos: sed, grep, etc.) o que sólo se alimenta de ella, como tr, el fichero redirigido se convertirá en la entrada de la orden.

En consecuencia, para que nuestra anterior orden de supresión de saltos de línea haga su efecto sobre el fichero texto_etiquetado.txt, deberíamos decirle a HAL lo siguiente:

tr -d '\n'< texto_etiquetado.txt

Con este paso previo se puede ya construir la orden completa, puesto que el resultado de la acción de tr se puede enviar sin problemas a sed mediante una tubería y redirigir lo que produce sed al fichero texto_etiquetado.tex:

tr -d '\n'< texto_etiquetado.txt | sed -f txt2latex.sed >texto_etiquetado.tex

Lo cual produce el documento con todas las transformaciones propias de LaTeX que hemos solicitado:

\section{Navegación gráfica}
Si hubiésemos estado visitando la página con un buen navegador gráfico que disponga de la opción de guardar las páginas web como texto, tendríamos que realizar al menos dos acciones, ambas independientes:

\begin{enumerate}
\item Ir al menú <<Archivo>> del navegador y guardar como texto la página web. (Lo que además implica seleccionar un nombre de fichero y un directorio).
\item Crear en Vim una nueva ventana para editar en ella el documento que acabamos de guardar, mediante la orden :new ruta\_fichero.
\end{enumerate}

\section{Navegación desde consola}
Si navegamos con w3m, y gracias a la interacción entre las aplicaciones de consola, bastaría ejecutar una única acción desde el propio Vim, que, además, podríamos abreviar para reproducirla en situaciones semejantes. Veamos cómo.

Con w3m el proceso de convertir una página web en texto es absolutamente elemental: añadir la opción -dump. Por ejemplo:

w3m -dump http://www.w3.org/TR/html401/struct/lists.html

nos devuelve la página dada como argumento, tal cual se presenta en el navegador, pero como puro texto.



Resumen:

  • Las expresiones regulares para sed no son idénticas a las expresiones regulares extendidas. Ello implica que muchos caracteres típicos de las EREs tengan que escaparse en sed.

  • sed registra las agrupaciones que en los patrones de expresiones regulares aparecen entre paréntesis \(...\) y los guarda para su uso posterior. Para recuperar lo contenido en esos registros se utilizan los signos de referencias hacia atrás (\1, \2, ..., \9), cada uno de los cuales remite a la primera, segunda, ..., novena agrupación de la expresión regular del caso.

  • La orden tr traduce o elimina (con la opción -d) caracteres de la entrada estándar. Por ejemplo tr -d '\n' elimina los saltos de línea del flujo de entrada.

  • Existen órdenes de HAL que se nutren únicamente de la entrada estándar, como tr y no pueden recibir un fichero como argumento.

  • El embudo < permite redirigir un fichero a la entrada estándar y, por extensión, a una orden que se alimente de la entrada estándar. Por ejemplo, tr -d '\n'< mi_fichero, hace que el fichero mi_fichero sea la entrada de la orden tr.