gpoore / minted

minted is a LaTeX package that provides syntax highlighting using the Pygments library. Highlighted source code can be customized using fancyvrb.
1.76k stars 128 forks source link

minted loops in amsmath \text #423

Open davidcarlisle opened 1 week ago

davidcarlisle commented 1 week ago

See https://tex.stackexchange.com/q/730979/1090 The minted call loops in \text which is essentially a \mathchoice so it gets called 4 times with the same arguments. although when I tried to simplify the example calling \mathchoice explicitly it all worked so I'm not sure what else is triggering the loop. Adding \tracingall took me further into minted code than I wanted to go, so just reporting here.

It loops with pdftex or luatex, although hitting a different error in each case (input buffer or pool size)

\documentclass{article}
\usepackage{amsmath}
\usepackage{minted}    % uncomment this line to use minted 3.x
%\usepackage{minted2}  % uncomment this line to use minted 2.9. It requires `-shell-escape`
\begin{document}

\(\textrm{\mintinline{python}{512}}\) units % comment out this line to remove error
\end{document}
muzimuzhi commented 1 week ago

Inside \text, \firstchoice@false used in the last three cases of \mathchoice is the culprit.

Definitions of \text and \text@ in amstest.sty

```shell $ latexdef -p amstext -s \text \text@ ``` ```tex % amstext.sty, line 28: \DeclareRobustCommand{\text}{% \ifmmode\expandafter\text@\else\expandafter\mbox\fi} % amstext.sty, line 31: \def\text@#1{{\mathchoice {\textdef@\displaystyle\f@size{#1}}% {\textdef@\textstyle\f@size{\firstchoice@false #1}}% {\textdef@\textstyle\sf@size{\firstchoice@false #1}}% {\textdef@\textstyle \ssf@size{\firstchoice@false #1}}% \check@mathfonts }% } ```

When \iffirstchoice@ is false, the amstext-redefined \stepcounter and \addtocounter both do nothing, which breaks some of the loops in minted and latex2pydata macros.

Definitions of \stepcounter and \addtocounter redefined by amstest.sty

```shell $ latexdef -p amstext \stepcounter \addtocounter ``` ```tex \stepcounter: macro:#1->\iffirstchoice@ \addtocounter {#1}\@ne \begingroup \let \@elt \@stpelt \csname cl@#1\endcsname \endgroup \fi \addtocounter: macro:#1#2->\iffirstchoice@ \@ifundefined {c@#1}{\@nocounterr {#1}}{\global \advance \csname c@#1\endcsname #2\relax }\fi ```

Replacing \stepcounter with low-level \advance does the trick.

\documentclass{article}
\usepackage{amsmath}
\usepackage{minted}

\makeatletter
% Replace \stepcounter used in loops with low-level \advance, as amstext.sty
% redefines \stepcounter and \addtocounter so that they do nothing when
% \iffirstchoice@ is false, which is the case in the last three cases of
% \mathchoice used by \text{...}.
% The initial intension of amstext/`\text` is to avoid stepping counters
% multiple times.

% patch minted.sty
\patchcmd\minted@highlight
  {\stepcounter{minted@tmpcnt}}
  {\advance\c@minted@tmpcnt 1\relax}
  {}{\ERRORPatchFailed}

\patchcmd\minted@iffasthighlightmode@buffertempfile@v
  {\stepcounter{minted@tmpcnt}}
  {\advance\c@minted@tmpcnt 1\relax}
  {}{\ERRORPatchFailed}

\patchcmd\minted@savecachelist
  {\stepcounter{minted@tmpcnt}}
  {\advance\c@minted@tmpcnt 1\relax}
  {}{\ERRORPatchFailed}

% patch latex2pydata.sty
\patchcmd{\pydatawritebuffer}
  {\stepcounter{pydata@bufferindex}}
  {\advance\c@pydata@bufferindex1\relax}
  {}{\ERRORPatchFailed}

\patchcmd{\pydataclearbuffername}
  {\stepcounter{pydata@bufferindex}}
  {\advance\c@pydata@bufferindex1\relax}
  {}{\ERRORPatchFailed}
\makeatother

\begin{document}

\makeatletter
% simplified example
\firstchoice@false \mintinline{python}{a + 512}
\firstchoice@true
\makeatother

% original example
\(\textrm{\mintinline{python}{512}}\) units
\end{document}
muzimuzhi commented 1 week ago

Should be fixed with minted v3.4.0, fvextra v1.10.0, and latex2pydata v0.4.0, all released on 2024-11-17.