Miskatonic University Press

Exporting Org source code blocks to LaTeX with minted

code4lib emacs latex

Recently I spent much longer than expected generating data about library holdings for an insurance spreadsheet needed by CURIE. We don’t have to do it often, and this was the first time I’d had to figure out the numbers they want about total books on the shelf (by LCC class letter) and years of print journal holdings (by subject groupings based on LCC). Cleaning the messy bibliographic metadata—all bibliographic metadata is messy—took a number of steps, and naturally I did it with R in Org, documenting everything in a reproducible way so that next time it will just take me an afternoon, not days and days.

Interesting fact: the Scott Library has about 250,000 years of print journals on the shelves.

So that others can see what data cleaning and munging was done, I exported the Org file to LaTeX and then turned it into a PDF. I included the R source code and wanted to make that look nice, not just plain verbatim text. This got me looking at the LaTeX package minted for the first time. Here I document how I now have things set up.

In my Emacs config I set up a function to turn minted on or off. Originally I added minted to the default list of packages in every LaTeX export and defined that every source code listing should be formatted with minted, like so:

(add-to-list 'org-latex-packages-alist '("" "minted" nil))
(setq org-latex-src-block-backend 'minted)

About the first line, a lot of documentation says the variable to set is org-latex-listings but as of Org 9.6 that is obsolete. As to the second, with that back end variable set, every block will be inside \begin{minted} and \end{minted} instead of \begin{verbatim} and \end{verbatim}.

But when minted is one of the included packages it’s always necessary to run pdflatex -shell-escape to compile the PDF, even if there are no source blocks. I can’t be having that.

Instead, I use this function (based on a tip from Xah Lee) to toggle those settings on or off. When I’m working on a file that I want to export using minted, I run M-x wtd/org-toggle-minted to turn things on. When I’m done, I run it again to turn things off.

(defun wtd/org-toggle-minted ()
  "Toggle whether or not Org should use minted for LaTeX."
  (interactive)
  (if (get 'wtd-org-minted-on-or-off 'state)
      (progn
	(setq org-latex-packages-alist (delete '("" "minted" nil) org-latex-packages-alist))
	(setq org-latex-src-block-backend 'verbatim)
	(put 'wtd-org-minted-on-or-off 'state nil)
	(message "Minted is off")
	)
    (progn
      (add-to-list 'org-latex-packages-alist '("" "minted" nil))
      (setq org-latex-src-block-backend 'minted)
      (put 'wtd-org-minted-on-or-off 'state t)
      (message "Minted is on; use pdflatex -shell-escape -interaction=nonstopmode")
      )
    )
  )

(My arrangement of parentheses probably offends many people, but I don’t do much Lisp and I find it helpful here.)

Now, minted has all sorts of options. They can be set in an association list that will be passed to every source block, like so.

(setq org-latex-minted-options
      '(("frame" "leftline")
))

However, this seems inelegant to me. It puts the same text on every code block, over and over, and I would rather specify the options once in LaTeX. Also, I don’t think I’ll want the same look on everything I do; I want to be able to control document-specific options right in the Org file. Therefore I prefer to define options with \setminted{} in a latex_header at the top of the Org file.

Here’s an example. The file starts with minted settings (I don’t need usepackage because it’s already done, thanks to the above). This says that I want to use one of the Solarized colour schemes (see the listing of Pygments styles) and put a line on the left of every block. For R code, I want line numbers.

#+latex_header: \setminted{style=solarized-light,frame=leftline}
#+latex_header: \setminted[r]{linenos=true}

Here’s an R block. I throw in an option for this block specifically, to change the frame setting so there’s a line around the whole block.

#+attr_latex: :options frame=single
#+begin_src R
library(purrr)
fruits <- c("apple", "pear", "grape", "blueberry")
map(fruits, \(f) nchar(f))
#+end_src

(I know that nchar(fruits) is the proper way, but I was using purrr seriously for the first time in the CURIE work and thought what the hell.)

In my Emacs (where I use the dark Solarized theme), this looks like so:

Formatted R code in Org
Formatted R code in Org

When turned into a PDF, I get:

Nicely formatted code from the PDF
Nicely formatted code from the PDF

That looks good!

It’s in a box because I overrode the frame setting, it has line numbers because I set that for R, and it uses the Solarized light theme because that is the document setting.

Next, here’s a Ruby block.

#+attr_latex: :options style=default,fontsize=\footnotesize
#+begin_src ruby
fruits = %w[apple pear grape blueberry]
fruits.each do |f|
  puts f.length
end
#+end_src

In my Emacs:

Formatted Ruby code in Org
Formatted Ruby code in Org

In the PDF:

Nicely formatted code from the PDF
Nicely formatted code from the PDF

That also looks good!

It has the left line by the document setting, but the style is overridden in just this block to be the Pygments default, and for fun the font size is a bit smaller.

To make all this work I need Pygments installed, because that’s how minted does the formatting. That’s a simple external requirement (well, as simple as Python packages are; I use them so rarely I always get confused by whether I should use pip or pip3 and if it needs to be run as root, but the error messages are helpful and I get it right soon enough). But because it’s external, pdflatex needs to be run specially to allow an outside call:

pdflatex -shell-escape filename.tex

Or better yet this, to plough through problems:

pdflatex -shell-escape -interaction=nonstopmode filename.tex

I could configure Org to handle that but I’d rather do it by hand when needed and I know it’s safe.

Lastly, to show off the LaTeX fragment previews in Org, here’s some math almost plain (some of the raw LaTeX is prettified in the buffer) and then previewed. This is Org showing me in Emacs what the PDF output will look like.

Formula for pi in mostly raw LaTeX
Formula for pi in mostly raw LaTeX
Formula for pi looking spiffy
Formula for pi looking spiffy

I’m happy to have found one more way for Org and LaTeX to work together to make more beautiful documents.

UPDATE (22 November 2023): I rewrote this to use the toggle function instead of accidentally leaving the minted settings permanently on.