Píntame ese código
En este episodio vamos a hablar de resaltado de sintaxis, es decir, vamos a aprender a darle formato al código fuente que hayamos insertado en nuestro documento con la idea de que sea más fácil de leer.
Hay varios paquetes que nos permiten pintar de colorines nuestro
código, está listings
que he usado bastante,
minted
que tenía ganas de aprender a usar y
LGrind
que descubrí al escribir esto. Voy a hablar de los
dos primeros que son los que controlo y sobre LGrind
investigáis si
os gusta, igual hasta hay más por ahí.
Lo fácil: listings
El paquete listings
se utiliza de manera similar al resto de
paquetes que hemos visto hasta ahora: lo cargamos, establecemos sus
opciones y luego utilizamos los comandos que nos proporciona en el
cuerpo del documento.
Para incluir el código hay varias opciones. Por una parte, igual que
ocurría con las ecuaciones y las figuras, podemos escribir código en
la propia línea (inline) o puede flotar. Y también como en el caso
de las figuras y ecuaciones, al código flotante podemos ponerle un
pie de código (caption
) y etiquetarlo (label
) para luego
referenciarlo en el texto (\ref{}
).
Para incluir código inline tenemos el comando \lstinline
, muy útil
él para hacer referencia a órdenes y variables en el texto:
Guardamos el resultado en la variable \lstinline!fib!
Los signos de exclamación delimitan el código y pueden sustituirse por cualquier otro carácter no incluido en el código.
Para escribir código con línea propia está el entorno lstlisting
, al
que le podemos dar como opciones tanto el pie de código y su
posición como la etiqueta del pedacito de código:
% Código con pie en la parte inferior (por defecto en la superior) y etiqueta
\begin{lstlisting}[language=haskell, caption=Código con Listings, captionpos=b, label=lst:fiboHaskell]
-- Fibonacci!
fib = 0 : 1 : zipWith (+) fib (tail fib)
\end{lstlisting}
Por otra parte, se puede escribir el código en el propio documento o importarlo de un archivo externo.
\lstinputlisting[language={[latex]tex}]{Codigo/codigo.tex}
He puesto precisamente un ejemplo de LaTeX porque tiene una característica especial: es un dialecto de TeX, así veis cuál es la sintaxis para indicar dialectos.
Este comando es especialmente interesante con los argumentos
opcionales firstline
y lastline
mediante los cuales le indicamos a
LaTeX el trozo de programa que nos interesa pintar:
\lstinputlisting[language={[latex]tex}, firstline=5, lastline=10]{Codigo/codigo.tex}
Al igual que con el entorno lstlisting
, al código importado mediante
\lstinputlsiting
podemos ponerle un pie de código con el argumento
opcional caption
. Por cierto, si queremos, podemos recopilar todos
los listados de código flotantes en un índice con el comando
\lstlistoflistings
, del mismo modo que hacíamos con las tablas y las
figuras.
Pasemos ahora a personalizarlo. Si no especificamos nada, listings
nos pintará los comentarios en cursiva, las palabras claves en negrita
y demás, pero todo ello en blanco y negro. Si queremos otro tipo de
formato o usar diferentes colores necesitamos indicárselo. Veamos cómo
se hace.
Lo primero es cargar el paquete xcolor
que, como sabemos de entregas
anteriores nos permite usar colores en nuestro documento:
\usepackage[usenames,dvipsnames,svgnames,table]{xcolor}
Luego, en el cuerpo del documento definimos el estilo de nuestro
código con \lstset{OPCIONES}
. Os pongo un ejemplo con diferentes
opciones pero hay muchísimas, lo mejor es mirar en el manual:
\lstset{
tabsize=2, % tab = 2 espacios
backgroundcolor=\color[HTML]{F0F0F0}, % color de fondo
captionpos=b, % posición de pie de código, b=debajo
basicstyle=\ttfamily, % estilo de letra general
columns=fixed, % columnas alineadas
extendedchars=true, % ASCII extendido
breaklines=true, % partir líneas
prebreak = \raisebox{0ex}[0ex][0ex]{\ensuremath{\hookleftarrow}}, % marcar final de línea con flecha
showtabs=false, % no marcar tabulación
showspaces=false, % no marcar espacios
keywordstyle=\bfseries\color[HTML]{007020}, % estilo de palabras clave
commentstyle=\itshape\color[HTML]{60A0B0}, % estilo de comentarios
stringstyle=\color[HTML]{4070A0}, % estilo de strings
}
¿Recordáis que hablamos en su momento de las diferentes familias,
series y formas de las letras? ¿Y de que había dos maneras para
aplicarlas? Aquí se ve clara la utilidad, usamos \bfseries
en lugar
de \textbf
porque ya estamos dentro de un grupo.
También tenemos la opción de definir diferentes estilos mediante el
comando \lstdefinestyle{NOMBRE}{ESTILO}
para luego aplicarlos con la
opción style
. A mí en concreto esta característica me resultó muy
útil en la tesis para poder resaltar mejor el código de Python
específico que se usa en Abaqus (¡programa no libre! ¡Huid!), de esta
manera tenía un estilo general que se aplicaba a todos los listados de
código y luego unas pocas opciones más que solo se aplicaban cuando
eran necesarias:
\lstdefinestyle{abaqusPython}{
language=python,
% Palabras clave extra
morekeywords={CONTINUOUS,NUMBER,MESH,par,name,ParStudy,
template,define,sample,combine, generate},
% Delimitadores extra, s porque hay uno a cada lado
moredelim=[s][\ttfamily\color{magenta}]{<}{>},
}
\lstinputlisting[style=abaqusPython]{calculo.py}
Por último, tenemos que tener en cuenta que listings
no acepta UTF8
por lo que no nos va a escribir los caracteres acentuados
directamente. Para solucionar esto lo más sencillo es crear un
\lstset
con la opción literate
, que sirve para sustituir elementos
en el código. En sí, literate
se usa para que el código pueda
leerse con mayor facilidad, pero a nosotros nos viene bien
para cada vez que vea á
lo sustituya por \'a
y nos queden bien los
acentos. Os copio aquí lo que yo uso, tenéis una versión con más
chirimbolos aquí:
% Listings no acepta UTF8
{original}{sustitución}{tamaño}
\lstset{literate=
{á}{{\'a}}1
{é}{{\'e}}1
{í}{{\'i}}1
{ó}{{\'o}}1
{ú}{{\'u}}1
{Á}{{\'A}}1
{É}{{\'E}}1
{Í}{{\'I}}1
{Ó}{{\'O}}1
{Ú}{{\'U}}1
{ñ}{{\~n}}1
{ü}{{\"u}}1
{Ü}{{\"U}}1
}
La principal debilidad que se le achaca al paquete listings
es la de
no ser un lexer completo, es decir, que no distingue todos los
elementos del lenguaje. Para solucionar este problema tenemos el
paquete minted
.
Lo no tan fácil: minted
El paquete minted
utiliza Pygments, un resaltador de
sintaxis general escrito en Python, para dar formato al código. Está
basado además en el paquete fancyvrb
(Fancy Verbatim),
un paquete para dar formato al texto verbatim, osease, al texto tal
cual, sin interpretar las marcas.
Digo que no es tan fácil porque requiere una etapa de compilación
intermedia y requiere tener Python 2.6 o superior y Pygments
instalados. Para saber si tenemos Pygments instalado podemos buscar el
ejecutable con whereis pygmentize
, que es la
herramienta para el terminal de Pygments. Si no lo
tenemos siempre nos queda pip install pygments
.
Que sea un poco más lío de instalar y usar nos da unas ventajas nada desdeñables:
-
Hay disponibles un mayor número de lenguajes. ¡Hay hasta resaltador de BrainFuck!
-
Es más fácil de personalizar
-
Acepta UTF8, al menos con
xelatex
ypolyglossia
, y hay posibilidad de elegir la codificación a partir de su versión 2.0 -
Está bien mantenido, hay mejoras del 2016.
Evidentemente, también tiene sus desventajas:
-
Hay que compilar con la opción
-shell-escape
para que LaTeX permita la ejecución de un programa externo, lo que implica ciertos problemas de seguridad. -
La versiónPodemos ver la versión del paquete que estamos usando en el archivo .log de los repositorios suele ser antigua, con lo que nos perdemos las últimas funcionalidades como la de elegir la codificación. Además, es un poco de lío actualizarlo porque requiere
fvextra
y en algunos repos no está.
Vayamos a su uso. La opción más básica es usar el entorno minted
junto con el lenguaje del código en cuestión:
\begin{minted}{python}
for n in range(10):
if n%2:
print n
\end{minted}
Que tiene la versión reducida \mint
si el código que queremos añadir
tiene solo una línea. Para delimitar el código podemos usar diferentes
caracteres, los elegimos según los delimitadores que use nuestro
código.
\mint{python}|print [n for n in range(10) if n%2]|
Tanto para el caso del entorno minted
como para el comando \mint
el código tendrá línea propia, pero no se le puede considerar
flotante, para ello debemos rodear cualquiera de las dos opciones con
el entorno listing
, más abajo hay un ejemplo completo en el que se
muestra cómo hacerlo.
Este paquete también nos permite incluir código inline:
Guardamos el resultado en la variable \mintinline{python}{fib}
Y también tenemos la opción de importar el código tal y como hacíamos
con listings
:
\inputminted{python}{fibonacci.py}
Lo más difícil de usar de minted
es llamar al comando que compilará
en documento con la opción -shell-escape
, por ejemplo:
pdflatex -shell-escape documento.tex
Los que compiláis a pelo o con un Makefile no tenéis problema, los que
estáis usando un editor específico para LaTeX seguramente podréis
crear un comando personalizado para compilar. En Kile, que es el
programa que yo uso ahora mismo, tendríamos que ir a Settings >
Configure Kile > Tools > Build y crear una nueva herramienta de
compilación que incluya -shell-escape
siguiendo el ejemplo del resto
de herramientas. Digo una nueva porque no es demasiado recomendable
compilar alegremente cualquier documento con la opción -shell-escape
ya que con TeX se puede programar cualquier cosa, hasta cosas
malignas.
Para personalizar el código tenemos diferentes opciones:
-
Con
\usemintedstyle[LENGUAJE]{ESTILO}
elegimos el estilo de Pygments con el queremos dar formato al código. Como veis el lenguaje es opcional, podemos elegir un estilo para cada lenguaje si nos apetece. Para ver los estilos instalados escribimospygmentize -L styles
en el terminal. También podemos definir nuestro propio estilo siguiendo las directrices de Pygments. -
Los comandos
\setminted[LENGUAJE]{ESTILO}
y\setmintedinline[LENGUAJE]{ESTILO}
, que tiene precedencia, también valen para definir los estilos. El primero afecta al entornominted
y al comando\mint
y el segundo al código inline. -
El comando
\newminted[NOMBRE]{LENGUAJE}{OPCIONES}
nos permite guardar las opciones para un determinado lenguaje para el entornominted
. Es similar a\lstdefinestyle
del paquetelistings
. Si no le ponemos nombre llamaráLENGcode
a nuestro nuevo estilo dondeLENG
es el lenguaje del mismo. Para usarlo no tenemos más que sustituir el nombre del lenguaje por el del estilo que hemos definido en el entornominted
. -
El comando
\newmint[NOMBRE]{LENGUAJE}{OPCIONES}
es el equivalente a\newminted
para el comando\mint
. Funciona exactamente igual excepto por que sustituye\mint
por el nombre que le hemos dado al estilo.
\newmint[py]{python}{bgcolor=black}
\py|print [n for n in range(10) if n%2]|
En cuanto a las opciones, hay montones de ellas, muchas coinciden con
las de listings
, creo que lo mejor es ir al manual y
mirar, se entiende bastante bien y no es demasiado largo.
¡Veamos un ejemplo completo! Tiene las siguientes características:
-
Es un objeto flotante con opción de posición H (here)
-
Crea un índice de codigo con
\listoflistings
, el equivalente a\lstlistoflistings
-
Activa los números de línea con la opción
linenos
-
Nos deja escribir ecuaciones en los comentarios del código gracias a
mathescape
-
Nos permite escribir en LaTeX dentro de los comentarios del código gracias a
texcl
. Esta opción se ha convertido entexcomments
a partir de la versión 2.0. En este caso lo uso para poder enlazar la página web.
% Cambiamos Listing por Listado
\renewcommand{\listingscaption}{Listado}
\listoflistings
\begin{listing}[H]
\begin{minted}[linenos,mathescape,texcl]{clojure}
;; Fibonacci por cortesía de \href{https://pfctelepathy.wordpress.com/}{Ekaitz}
;; $F_n = F_{n-1} + F_{n-2} \,/\, F_0 = 0 \wedge F_1 = 1$
(defn fibo
([] (fibo 0 1))
([one two]
(lazy-seq (cons one (fibo two (+ one two))))))
\end{minted}
\label{lst:fibo}
\caption{Código con Minted}
\end{listing}
Que quedaría así:
Como nota final, listings
no sabe resaltar Clojure y nos obligaría a crear
nuestro propio resaltador.
En resumen
En esta entrega hemos aprendido a resaltar código de dos maneras, una
de ellas usa un paquete de la forma tradicional y la otra llama a un
programa externo. Ambas nos dan una funcionalidad similar siendo tal
vez listings
más fácil de usar y minted
más fácil de
personalizar. Los dos paquetes tienen montones de opciones pero como
ya estamos curtidos, !podemos ir a sus respectivos manuales y leerlos
para saber sacar el máximo partido!
Referencias
Code listings in LaTeX en el FAQ de LaTeX
minted
vs textments
vs verbments
en TeXExchange
Are Text-Only Data Formats Safe? Or, Use This LaTeX Class File to Pwn Your Computer
Anterior: Un documento científico, Siguiente: También podemos presentar [Contenido]