Reference lines with less boilerplate
I have been annotating a lot of code in a LaTeX document recently using the method outlined in this Tex Stack Exchange post. But when working with this method it is a bit cumbersome to work with - adding the reference to a list of highlighted lines manually. Could I suggest some different syntax for achieving this?
\begin{document}
\begin{minted}[
linenos=true,
escapeinside=!!,
highlightlabels,
]{c++}
i = i + 1 ;
j = j + 1 ; !\label{myline}!
k = k + 1 ;
l = l + 1 ; !\label{yourline}!
\end{minted}
The important lines are line~\ref{myline} and line\ref{yourline}.
The minted package should be able to figure out what lines need highlighting purely based off the lines inside the code block - without requiring them to be defined separately.
I have been annotating a lot of code in a LaTeX document recently using the method outlined in this Tex Stack Exchange post.
Being the author of the linked TeX-SX answer, I doubt my patch for highlightlines option still worked for minted v3.x.
Your example is not compilable. It has no preamble and no \end{document}, and lacks the definition of non-built-in highlightlabels option.
The
mintedpackage should be able to figure out what lines need highlighting purely based off the lines inside the code block - without requiring them to be defined separately.
Auto-labelling highlighted lines may be feasible with customized fvextra commands \FancyVerbFormatLine/\FancyVerbFormatText and \FancyVerbHighlightLine/\FancyVerbHighlightLine(First|Middle|Last|Single). (fvextra is one of the dependencies of minted.) But how would you like to name the labels?
Being the author of the linked TeX-SX answer, I doubt my patch for highlightlines option still worked for minted v3.x.
Odd, I must be using an outdated version. I use \usepackage{minted} in my preamble without a version so that could be why.
Your example is not compilable. It has no preamble and no \end{document}, and lacks the definition of non-built-in highlightlabels option.
That's my bad, I thought the preamble would be self-evident. Regarding the highlightlabels option, I included that as "pseudocode" for an idea of how the syntax might work - keeping the option of labelling lines without them being highlighted open to users.
Auto-labelling highlighted lines may be feasible with customized fvextra commands \FancyVerbFormatLine/\FancyVerbFormatText and \FancyVerbHighlightLine/\FancyVerbHighlightLine(First|Middle|Last|Single). (fvextra is one of the dependencies of minted.) But how would you like to name the labels?
That sounds great that it could be feasible! I'm not sure what you mean by how to name the labels though, I was thinking that a user could type the names of the labels inline with the code as shown in my example and then minted can search the code for any instance of a \label{} and highlight it with the methods you mentioned.
Regarding the
highlightlabelsoption, I included that as "pseudocode" for an idea of how the syntax might work - keeping the option of labelling lines without them being highlighted open to users.
Oh I didn't realize that it acted as "pseudocode".
Try the example below. It adds
- three new commands
\FVLabel{<label>},\FVLabelBegin{<label>}, and\FVLabelEnd{<label>}which wrap\labeland also marks a line or line range to be highlighted, in addition to those lines specified by thehighlightlinesoption. A second compilation is needed. - a new option
highlightlabelswhich makes\labelthe same as\FVLabel, when used inVerbatim-derived environments.
The patches mostly happen in the fvextra package, and the inheritance in minted are tested with both v2.x and v3.x.
\documentclass{article}
\usepackage{minted}
\usepackage{fvextra}
\usepackage{xcolor}
%\usepackage{hyperref}
% for the "tcblisting" env
\usepackage{tcolorbox}
\tcbuselibrary{minted}
\ExplSyntaxOn
\makeatletter
% count the number of \Verb and \begin{Verbatim}
\newcounter{FancyVerb}
\tl_new:N \l__fv_tmp_tl
\tl_new:N \g__fv_lines_labeled_begin_tl
\seq_new:N \g__fv_lines_labeled_seq
% \FVLabel, \FVLabelBegin, and \FVLabelEnd add extra highlighting lines,
% in addition to those specified by the "hightlightlines" option.
\NewDocumentCommand{\FVLabel}{}{
\__fv_highlight_curr_line:
\__fv_label:
}
\NewDocumentCommand{\FVLabelBegin}{}{
\__fv_highlight_range_begin:
\__fv_label:
}
\NewDocumentCommand{\FVLabelEnd}{}{
\__fv_highlight_range_end:
\__fv_label:
}
\cs_new_protected:Npn \__fv_highlight_curr_line:
{
\seq_gpush:Ne \g__fv_lines_labeled_seq { \arabic{FancyVerbLine} }
}
\cs_new_protected:Npn \__fv_highlight_range_begin:
{
\tl_gset:Ne \g__fv_lines_labeled_begin_tl { \arabic{FancyVerbLine} }
}
\cs_new_protected:Npn \__fv_highlight_range_end:
{
\tl_if_empty:NTF \g__fv_lines_labeled_begin_tl
{ \PackageError{fvextra}{Missing paired \string\FVLabelBegin}{} }
{
\seq_gpush:Ne \g__fv_lines_labeled_seq
{ \g__fv_lines_labeled_begin_tl - \arabic{FancyVerbLine} }
}
\tl_gclear:N \g__fv_lines_labeled_begin_tl
}
\cs_new_protected:Npn \__fv_label: { \label }
% Init setting for labeled lines
% add labeled lines to
\FV@AddToHook\FV@FormattingPrep@PreHook
{
\refstepcounter{FancyVerb}
\tl_set_eq:Nc \l__fv_tmp_tl
{ FV@highlightlines@smuggle@ \arabic{FancyVerb} }
\cs_if_exist:NT \l__fv_tmp_tl
{
\exp_args:Ne \fvset{highlightlines={ \l__fv_tmp_tl }}
% at this point the env-level "highlightlines" is already processed,
% so we trigger the processer again, manually.
\FV@HighlightLinesPrep
}
% just in case
\seq_gclear:N \g__fv_lines_labeled_seq
}
% new hook \FV@Endlist@Hook
\def\FV@Endlist@Hook{}
\def\FV@EndList{%
\FV@ListProcessLastLine
\FV@EndListFrame
\FV@Endlist@Hook
\@endparenv
\endgroup
\@endpetrue}
\FV@AddToHook\FV@Endlist@Hook
{
\seq_if_empty:NF \g__fv_lines_labeled_seq
{
% example: write "\FV@highlightlines@smuggle{1}{4,2}" to .aux
\immediate\write\@auxout
{
\string\FV@highlightlines@smuggle
{ \arabic{FancyVerb} }
{ \seq_use:Nn \g__fv_lines_labeled_seq {,} }
}
}
\seq_gclear:N \g__fv_lines_labeled_seq
}
% helper, used in .aux file
\cs_new_protected:Npn \FV@highlightlines@smuggle #1#2
{
\cs_gset:cpn { FV@highlightlines@smuggle@#1 } {#2}
}
% new boolean option "highlightlabels", for both fvextra and minted
%
% It makes \label the same as \FVLabel inside Verbatim-derived envs.
\define@booleankey{FV}{highlightlabels}
{\FV@AddToHook\FV@FormattingPrep@PreHook
{\let\__fv_label:=\label \let\label=\FVLabel}}
{}
% one-day newer than the date in minted2.sty
\IfPackageAtLeastTF{minted}{2024-05-10}{
% for minted v3.x
\mintedpgfkeyscreate{fv}{
highlightlabels
}
}{
% for minted v2.x
\minted@def@optfv@switch{highlightlabels}
}
\makeatother
\ExplSyntaxOff
\begin{document}
\fvset{numbersep=5pt}
\subsection*{\texttt{fvextra} example(s)}
\begin{tcblisting}{minted language=latex}
\begin{Verbatim}[linenos, gobble=4, commandchars=\\\{\}]
i = i + 1 ;
j = j + 1 ; \FVLabel{myline}
k = k + 1 ;
l = l + 1 ; \FVLabel{yourline}
\end{Verbatim}
\end{tcblisting}
The important lines are line~\ref{myline} and line~\ref{yourline}.
\begin{tcblisting}{minted language=latex}
\begin{Verbatim}[linenos, firstnumber=11, gobble=4, commandchars=\\\{\}]
i = i + 1 ;
j = j + 1 ; \FVLabelBegin{myline2}
k = k + 1 ;
l = l + 1 ; \FVLabelEnd{yourline2}
\end{Verbatim}
\end{tcblisting}
The important lines are lines~\ref{myline2}--\ref{yourline2}.
\subsection*{\Verb|minted| example(s)}
\begin{tcblisting}{minted language=latex}
\begin{minted}[
autogobble,
linenos=true,
firstnumber=21,
escapeinside=!!,
highlightlabels,
highlightlines={27-29},
]{c++}
i = i + 1 ;
j = j + 1 ; !\label{myline3}!
k = k + 1 ;
l = l + 1 ; !\label{yourline3}!
i -= 1 ;
j -= 1 ;
k -= 1 ;
l -= 1 ;
\end{minted}
\end{tcblisting}
The important lines are line~\ref{myline3}, line~\ref{yourline3}, and the
following highlighted range.
\end{document}
Thank you so much for taking the time to look into this! I'm not well versed in the world of writing LaTeX packages - how would I use this patch in my document? Do I make some kind of fvextra.tex file where I copy that preamble, or is it more involved than that?
@zax71 In general the patch (lines from \ExplSyntaxOn to \ExplSyntaxOff in https://github.com/gpoore/minted/issues/459#issuecomment-3314721381 example, inclusive) only needs to appear in your preamble (so the patch takes effect before any fvextra/minted commands are used), possibly in a separate file (which consists of various kinds of patches) \input by the main tex file.
That seems to work perfectly! I guess this can be PR'd in now, or is this out of scope for the Minted package?
Hmm, it seems to work perfectly on my desktop that is running NixOS. Although, on my laptop that is running Debian with the texlive-full package it can't build the project. My GitHub Actions CI can also build it perfectly fine.
The build errors on \g__fv_lines_labeled_seq with the full error of:
./_minted-main/43EE9E6F2074F7B02419542E4824B6E41B35B9996CB1364E8424D6B13D48A010.pygtex:8: Undefined control sequence.
\__fv_highlight_curr_line: ->\seq_gpush:Ne
\g__fv_lines_labeled_seq {\arabic...
l.8 ...\PYG{+w}{ }\PYG{esc}{\label{calculateMove}}
I can't find any reference of this control sequence or error anywhere else on the internet so I'm stumped as to how to fix my TexLive install so that it builds.
Adding
\cs_generate_variant:Nn \seq_gpush:Nn { Ne }
to the very beginning of the patch (but after \ExplSyntaxOn) should do the trick. This line of code defines \seq_gpush:Ne as the variant of expl3 function \seq_gpush:Nn (see texdoc l3 for more info).
The \seq_gpush:Ne is added to the l3kernel since 2023-10-10, so your laptop may be using a TeX Live 2023.
The version of l3kernel can be read from the beginning of every log file, on the 7th or 8th line, which looks like
L3 programming layer <2025-09-02>
I guess this can be PR'd in now, or is this out of scope for the Minted package?
Yes, as the highlightlines option in minted is inherited from fvextra package (https://github.com/gpoore/fvextra, created and maintained by the same author), extension to it should be contributed to fvextra too.
Also my patch uses expl3 functions (control sequences having _ and/or : in their names, and surrounded by \ExplSyntaxOn...\ExplSyntaxOff), which is not used by fvextra code base (yet). It's just a matter of style, or choices of utility functions.
Adding
\cs_generate_variant:Nn \seq_gpush:Nn { Ne }
to the very beginning of the patch (but after
\ExplSyntaxOn) should do the trick. This line of code defines\seq_gpush:Neas the variant of expl3 function\seq_gpush:Nn(seetexdoc l3for more info).
Thanks! That seems to fix it.
I guess this can be PR'd in now, or is this out of scope for the Minted package?
Yes, as the
highlightlinesoption inmintedis inherited fromfvextrapackage (https://github.com/gpoore/fvextra, created and maintained by the same author), extension to it should be contributed tofvextratoo.Also my patch uses
expl3functions (control sequences having_and/or:in their names, and surrounded by\ExplSyntaxOn...\ExplSyntaxOff), which is not used byfvextracode base (yet). It's just a matter of style, or choices of utility functions.
Ah, should this issue be transitioned to the fvextra repo?
@muzimuzhi If you want to convert this into an fvextra pull request, I'd be happy to add highlightlabels. Using expl3 is fine. I may be slow in working through and accepting a pull request...I have several deadlines and a backlog of projects over the next month or two.