How to stop macros from processing arguments?

Disclaimer: I don't know how to word this properly so the title might be misleading - edits and comments of advice or correction are very welcome!

I use the minted package to add code to my documents, and since minted supplies mintinline I tend to use the function very often. One of the commands I use to mint python codes inline is:

\NewDocumentCommand \imp { o m } {
\IfNoValueTF{#1} {
\mintinline{python}{#2}
} {
\mintinline[#1]{python}{#2}
}
}


Unfortunately \imp seems to process whatever goes in #2 before passing it on to \mintinline, which produces unwanted results like these:

\imp{'ONE   TWO'} => 'ONE TWO'
\mintinline{python}{'ONE   TWO'} => 'ONE   TWO'


and even errors when backslashes are involved:

\imp{\} => error
\mintinline{python}{\} => \


So is there a way to suppress the processing of inputs when I use these custom-made macros?

My MWE is:

\documentclass[10pt,openany]{book}
\usepackage{xparse,minted}

\NewDocumentCommand \imp { o m } {
\IfNoValueTF{#1} {
\mintinline{python}{#2}
} {
\mintinline[#1]{python}{#2}
}
}

\begin{document}

\imp{'ONE   TWO'} % 'ONE TWO'
\mintinline{python}{'ONE   TWO'} % 'ONE   TWO'

\imp{\} % error
\mintinline{python}{\} % \

\end{document}

• Can't you just leave out the second parameter in the definition of \imp? – siracusa Jun 8 at 6:55
• @DavidCarlisle The difference is the first mandatory argument to \mintinline, namely {python} – siracusa Jun 8 at 7:13
• @DavidCarlisle Funny thing is, I forgot about that as well, I was on my way to fix the code before I saw siracusa's comments as well XD Thank you for your contributions! :-) – Paul Kim Jun 8 at 7:26
• @frougon I only mind if egreg steals the tick, I don't object to them going anywhere else:-) – David Carlisle Jun 8 at 7:46
• @DavidCarlisle You're a real gentleman. :-) – frougon Jun 8 at 7:49

Unless I misunderstood the comments, what you would like is this:

\documentclass{article}
\usepackage{minted}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand \imp { o }
{
\IfValueTF {#1}
{ \mintinline[#1]{python} }
{ \mintinline{python} }
}

\ExplSyntaxOff

\begin{document}

\imp{'ONE   TWO'}
\mintinline{python}{'ONE   TWO'} % 'ONE   TWO'

\imp{\} % no error
\mintinline{python}{\} % \

\end{document}


I added \ExplSyntaxOn and \ExplSyntaxOff, otherwise your formatting would add unwanted spaces.

Note that the following definition would work as well; however, I think it's a bit more difficult to understand for very little gain:

\NewDocumentCommand \imp { o }
{
\IfValueTF {#1}
{ \mintinline[#1] }
{ \mintinline }
{python}
}


The reason why your macro didn't work is that commands that grab verbatim text (here, \mintinline) grab it with a special category code setup (for instance, spaces aren't treated like TeX normally does). But when your macro is called and grabs its #2, TeX assigns each resulting character token a category code according to the current category code setup, which is not the setup \mintinline would have done; and once assigned, the category codes stay firmly attached to their character tokens, unless you use very special commands such as \detokenize.

Note that even \detokenize couldn't help here: if you read a b under TeX's normal category code setup (e.g., if it is grabbed as a macro argument), the result is a token list containing three character tokens:

• a with category code 11 (letter);
• a space token (character code 32, category code 10);
• b with category code 11.

The four spaces from the input have already coalesced into one space token. From the resulting token list, there is no way to recover the original number of spaces. The only way not to lose such information is to set up the category codes differently before the characters from the input file are turned into tokens (this is what \mintinline, \verb and similar commands do).

When characters from the input have been grabbed as part of a macro argument1 under the normal category code regime, it is already too late for verbatim-like handling: the characters from the input have been tokenized, i.e., they have been turned into a list of tokens, each of which is either a control sequence token (e.g., \foobar) or a character token (a pair consisting of a character code and a category code). So, the solution here is not to grab the input characters we want to be treated in a verbatim-like fashion, and let \mintinline do it herself with the proper category code setup for this task.

Footnote

1. This includes environment arguments, since environments are implemented with macros.