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

No hay comentarios:

Publicar un comentario