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?

fishfin
  • 301

2 Answers2

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}
egreg
  • 1,121,712
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}
user691586
  • 1,988
  • Oh, no! That's the wrong approach. – egreg May 20 '23 at 08:14
  • @egreg I do not disagree and edited. Please feel free to edit further to add modern way. – user691586 May 20 '23 at 08: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 May 20 '23 at 08:37
  • additionally, the [#1] should be [{#1}] in case #1 may contain itself some ]. – user691586 May 20 '23 at 08: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 May 21 '23 at 03:03
  • @fishfin the 1st approach is the most economical one of all; the reason it is "not the right way" is that it sort of makes sense only if user actually understands what is going on. What is done in 1st approach ends up being done internally in one way or another by all other approaches... except that the higher level interface means less cluttering of your LaTeX file with incomprehensible low-level things, and are safer in the sense that if LaTeX evolves internally they should follow-up. (to be cont.) – user691586 May 21 '23 at 12:07
  • @fishfin It is very improbable LaTeX will suddenly change completely the details of internal implementation of \newcommand for a command with an option, as this would easily breaks dozens if not hundreds of packages potentially; however it is much more possible that the 1st method may break additions modern LaTeX does, via its cmd/<name>/before and cmd/<name>/after hooks, and I did not check that. (to be cont.) – user691586 May 21 '23 at 12:10
  • @fishfin as per the difficulties with \expandafter the background of the 1st method is explained in egreg's answer which details the internals. The 1st method is simply implementing the knowledge of the internals as explained in egreg's answer. All other methods ultimately will do something very similar to the 1st method! – user691586 May 21 '23 at 12:11
  • in comment above substitute "details of internally created support macros" as replacement of "details of internal implementation" which may be misconstrued to refer to how these internal auxiliary macros are created. The way they are created can change, what these created things are less likely so for backwards compatibility because many packages have been using LaTeX internals. – user691586 May 21 '23 at 12:18
  • @user691586 Understood, thank you. – fishfin May 22 '23 at 13:52