Highlighting parts of lines in minted

To repeat, I prefer to use the minted package for typesetting syntax-highlighted code in LaTeX. For example:

\begin{minted}[linenos]{c}
for (int i = 0; i < 100; i++) {
    printf("i = %d\n", i);
}
\end{minted}

This is rendered as:

No highlight

For completeness, here’s the preamble used for examples throughout this post:

\usepackage{minted}
\setminted{style=tango}
\usepackage[svgnames]{xcolor}
\usepackage{inconsolata}

Full line highlight

Occasionally it is useful to highlight a particular line of code. Conveniently, minted provides the highlightlines option to do so by line number:

\begin{minted}[linenos,highlightlines=1]{c}
for (int i = 0; i < 100; i++) {
    printf("i = %d\n", i);
}
\end{minted}

The following image comparison illustrates the change in rendering compared to no highlight (hover/swipe across the image):1

No highlight
Full line highlight

Partial line highlight

Occasionally it would be useful to not highlight the entire line of code but only a part of it. Unfortunately, minted does not provide a straightforward way to do so. So let’s try to come up with a custom solution!

Attempt 1

The obvious way is to use a \colorbox within minted’s escapeinside:

\newcommand{\codehighlight}[1]{\colorbox{LightCyan}{#1}}
\begin{minted}[linenos,escapeinside=||]{c}
for (int i = 0; |\codehighlight{i < 100}|; i++) {
    printf("i = %d\n", i);
}
\end{minted}

The color LightCyan is just what minted has as default for highlightcolor.

The following image comparison illustrates the change in rendering compared to full line highlight:

Full line highlight
Partial line highlight (attempt 1)

This has multiple issues. For one, the characters in the \colorbox don’t align with the rest of the columns of monospaced text.

Attempt 2

This is caused by the default value of \fboxsep, which is used to pad the contents of the \colorbox on all sides. To avoid the padding causing misalignment, it can be set to 0pt:

\newcommand{\codehighlight}[1]{{\setlength{\fboxsep}{0pt}\colorbox{LightCyan}{#1}}}
\begin{minted}[linenos,escapeinside=||]{c}
for (int i = 0; |\codehighlight{i < 100}|; i++) {
    printf("i = %d\n", i);
}
\end{minted}

The following image comparison illustrates the change in rendering compared to the first attempt:

Partial line highlight (attempt 1)
Partial line highlight (attempt 2)

The columns of monospaced characters now align, but the highlighting is very tight, also vertically (unlike highlightlines).

Attempt 3

We could do some trickery to effectively get different horizontal and vertical \fboxsep. However, it’s much easier to just insert a \strut, which is an invisible zero-width box that (more-or-less) accounts for the line height:

\newcommand{\codehighlight}[1]{{\setlength{\fboxsep}{0pt}\colorbox{LightCyan}{\strut #1}}}
\begin{minted}[linenos,escapeinside=||]{c}
for (int i = 0; |\codehighlight{i < 100}|; i++) {
    printf("i = %d\n", i);
}
\end{minted}

The following image comparison illustrates the change in rendering compared to the second attempt:

Partial line highlight (attempt 2)
Partial line highlight (attempt 3)

This fixes the alignment and padding issues,2 but there’s still a noticeable problem: the text, which we have highlighted for the user using the background color, is not being code highlighted by minted at all.

Attempt 4 (solution)

As far as I know, it’s not really possible to put \mintinline inside the minted environment to somehow try to fix this. Instead, we can do something strange with how our \codehighlight macro is used:

\newcommand{\codehighlight}[1]{{\setlength{\fboxsep}{0pt}\colorbox{LightCyan}{\strut #1}}}
\begin{minted}[linenos,escapeinside=||]{c}
for (int i = 0; |\codehighlight{{|i < 100|}}|; i++) {
    printf("i = %d\n", i);
}
\end{minted}

Previously, we had a single escapeinside that contained the macro applied to its contents. Now, there are two escapeinsides: one before the contents and one after:

  1. The one before only calls the macro and starts its argument. Importantly, this needs double { because minted puts the escapeinside contents into a group (i.e. between braces like {\codehighlight{{}). The first brace starts the macro argument, the second is only there to cancel out the group-closing brace. Without the latter, \codehighlight would just be given an empty argument.
  2. The one after only ends the macro argument. Analogously, this needs double }} (i.e. grouped like like {}}}). The first brace is only there to cancel out the group-opening brace and the second ends the macro argument.

The following image comparison illustrates the change in rendering compared to the third attempt:

Partial line highlight (attempt 3)
Partial line highlight (attempt 4)

The strange amalgamation fixes the code highlighting “within” \codehighlight.

Finally, this image comparison illustrates the change in rendering compared to no highlight:

No highlight
Partial line highlight (attempt 4)

  1. Only now, when producing the comparison images for this post, I noticed that highlightlines seems to slightly reduce line spacing. I’m not sure why, seems like a bug. 

  2. Although our \colorbox now also seems to slightly reduce line spacing. I’m not sure why, but this will be irrelevant in the end.