2

I am following this QnA to create a renewed \inputminted command.

\documentclass{article}

\usepackage{minted}                 % code highlighting, uses python pygments
\usepackage{mdframed}
\usepackage{xcolor}
\definecolor{codebg}{rgb}{0.95,0.95,0.95}

\let\inputmintedorig\inputminted    % copy original command [pack:minted]\inputminted to \inputmintedorig
\renewcommand{\inputminted}[3][]{%  % change original \inputminted
    \begin{mdframed}%
        \inputmintedorig[#1]{#2}{#3}%
    \end{mdframed}%
}

\begin{document}
\inputminted[bgcolor=codebg,mathescape,linenos,numbersep=5pt,gobble=2,frame=none,framesep=2mm,label=Some Code]{py}{pycode.py}
\end{document}

where pycode.py contains some arbitray Python code:

  import numpy as np    # importing library
  ls = np.arange(0, 100, 1)

But I am getting error "Too deeply nested. ...framesep=2mm,label=Some Code]{py}{pycode.py}" when using the renewed command. What am I doing wrong?

3
  • 1
    Try using \NewCommandCopy to copy the command instead. macros - Can I redefine a command to contain itself? - TeX - LaTeX Stack Exchange
    – user202729
    Commented May 20, 2023 at 7:09
  • do not show only a snippet, always make a small but complete example that demonstrates you problem and can be use in a test. Generally I would suggest that you use tcolorbox instead of mdframed. It offers various options for listings and supports also minted. Commented May 20, 2023 at 8:01
  • @UlrikeFischer, modifed to MWE instead of snippet. I will try out tcolorbox too. Thank you.
    – fishfin
    Commented May 21, 2023 at 2:36

2 Answers 2

6

This is a well-known problem with \let.

When you ask for \show\inputminted you'll be told that

> \inputminted=macro:
->\@protected@testopt \inputminted \\inputminted {}.

The macro doing the real job is \\inputminted (where the second backslash is part of the name. In general, when you have something like

\newcommand{\foo}[2][default]{something with #1 and #2}

LaTeX will internally do something like

\def\foo{\protected@testopt\foo\\foo{default}}
\def\\foo[#1]#2{something with #1 and #2}

but you're not supposed to know it as a user. (Note: I know that the code above isn't what actually LaTeX does, but the details are completely unimportant.)

But you're trying to access internals in order to redefine \inputminted. I believe it's not a good idea, actually. Anyway, when you want to do this you must be aware of the subtleties involved.

With your \let, you're not accessing the real macro that does the job. Worse, the subsequent \renewcommand will clobber the meaning of \\inputminted, so you enter an infinite loop as soon as you use \inputmintedorig.

Until 2021, the correct way to proceed was to load \usepackage{letltxmacro} and say

\LetLtxMacro{\inputmintedorig}{\inputminted}

but now there's a method from the LaTeX kernel itself:

\NewCommandCopy{\inputmintedorig}{\inputminted}
2
  • \NewCommandCopy worked. And thank you for the explanation!
    – fishfin
    Commented May 21, 2023 at 2:47
  • @user691586 Thanks, fixed.
    – egreg
    Commented May 21, 2023 at 13:13
2

do-it-yourself-way (may be broken if LaTeX kernel change)

\documentclass{article}

\usepackage{minted}
\usepackage{mdframed}

\makeatletter
\expandafter\let\expandafter\inputmintedorig@internal
             \csname\string\inputminted\endcsname
\renewcommand{\inputminted}[3][]{%
\begin{mdframed}%
\inputmintedorig@internal[#1]{#2}{#3}%
\end{mdframed}%
}
\makeatother
\begin{document}
\inputminted{py}{test.py}
\end{document}

But not to be advised, as this may be broken if LaTeX kernel internals change.

By the way doesn't minted documentation explain how to use a "framing" package of one's choice (untested).

use-devoted-package-way

\documentclass{article}

\usepackage{minted}
\usepackage{mdframed}

\usepackage{letltxmacro}

\LetLtxMacro{\inputmintedorig}{\inputminted}

\renewcommand{\inputminted}[3][]{%
\begin{mdframed}%
\inputmintedorig[#1]{#2}{#3}%
\end{mdframed}%
}

\begin{document}
\inputminted{py}{test.py}
\end{document}

The package letltxmacro was created for such tasks.

use-modern-LaTeX-way

copied from egreg answer:

\NewCommandCopy{\inputmintedorig}{\inputminted}
10
  • Oh, no! That's the wrong approach.
    – egreg
    Commented May 20, 2023 at 8:14
  • @egreg I do not disagree and edited. Please feel free to edit further to add modern way.
    – user691586
    Commented May 20, 2023 at 8:23
  • The main reason why the first method is wrong it works only for classic LaTeX commands with an optional argument defined by \newcommand. A priori you are not supposed to make hypothesis on how the command was defined, so basically this method implies you are able to check the package source code and see how are things are done there and adapt if necessary. Besides as LaTeX kernel evolve it may modify internals so this is in theory a bit fragile in the (very) long term.
    – user691586
    Commented May 20, 2023 at 8:37
  • additionally, the [#1] should be [{#1}] in case #1 may contain itself some ].
    – user691586
    Commented May 20, 2023 at 8:40
  • I understand the 1st approach is not the right way, but I was still trying to understand the \expandafter... code. I am not an advanced LaTeX user, so didn't quite understand it (tried the AI bot too, still didn't - goes on to show there's a lot still for me to learn). But thank you!
    – fishfin
    Commented May 21, 2023 at 3:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .