Curso no convencional de LaTeX: 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 y polyglossia, 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ón1 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 escribimos pygmentize -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 entorno minted 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 entorno minted. Es similar a \lstdefinestyle del paquete listings. Si no le ponemos nombre llamará LENGcode a nuestro nuevo estilo donde LENG 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 entorno minted.

  • 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 en texcomments 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í:

Ejemplo de uso de minted

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

Manual de listings

minted en GitHub

Manual de minted

Code listings in LaTeX en el FAQ de LaTeX

Code listing en ShareLaTeX

minted vs textments vs verbments en TeXExchange

Are Text-Only Data Formats Safe? Or, Use This LaTeX Class File to Pwn Your Computer


El título hace referencia a esta canción 😀


  1. Podemos ver la versión del paquete que estamos usando en el archivo .log 
Anuncios

2 pensamientos en “Curso no convencional de LaTeX: píntame ese código

  1. Pingback: En qué ando: abril | Onda Hostil

  2. Pingback: Lo que he aprendido: cuadros de texto de colores en LaTeX | Onda Hostil

¡Opina sin miedo! (Puedes usar Markdown)

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s