# Macro that takes any latex code as an argument

So I am thinking of creating a macro that takes any latex code as an argument. For example,

\newcommand\purp[1]{\color{purple} #1}

I hoped that this macro would make any latex code inside of \purp to be colored as purple. I realized, however, is that if I pass some environment (\begin.. \end) to the argument, some weird latex error occurs. For example.

\purp{
\begin{verbatim}
asdf
asdf
\end{verbatim}
}

breaks the verbatim output and generates bunch of latex errors. Is there any safe way to make a function that takes arbitrary latex code as an argument?

Edit

Besides a verbatim, I also observed that following produces very weird error.

\purp{
$x= \begin{cases*} y & if x_1 \text{ is } 1\\ z & if x_2 \text{ is } 2 \end{cases*}$
}

This gives a weird error Missing \$ is inserted. Any idea why?

• The problem is not the environment, but the verbatim. Verbatim can not be in the argument of other commands. May 8, 2019 at 9:56

The near universal rule is that verbatim material cannot be an argument to a command. With the cprotect package, there is sometimes a workaround as shown in the MWE, but even that is not a universal fix.

EDIT: group added to prevent spillage of purple into subsequent material (thanks Ulrike).

\documentclass{article}
\usepackage{cprotect,xcolor}
\newcommand\purp[1]{{\color{purple} #1}}
\begin{document}
\cprotect\purp{
\begin{verbatim}
asdf
asdf
\end{verbatim}
}
\end{document}

• you should add a group to avoid that following text is purple too. May 8, 2019 at 10:05
• @UlrikeFischer Thank you for reminding me of that. May 8, 2019 at 10:08
• awesome thank you! May 9, 2019 at 1:36
• I also observed weird error without using the verbatim env. I edited a question above. Could you take a look? May 9, 2019 at 1:45
• @Jaebum Your syntax is in error: \purp{ $x= \begin{cases*} y & if x_1 is 1\\ z & if x_2 is 2 \end{cases*}$ } Nothing at all to do with \purp. May 9, 2019 at 1:51

If it's just about colours, you could fake a \textcolor command, which seems to take an argument, but does support verbatim material. Note that this is no general solution, but just provides an argument taking syntax to \color which is not really an argument.

(This way one could use any formatting switches not only colours, e.g. \bfseries could be used this way, too)

EDIT: created a \switchhack that allows arbitrary formatting switches not only colours, and \colorhack calls \switchhack now.

\documentclass[]{article}

\usepackage{xcolor}

\makeatletter
\begingroup\def\:#1{\endgroup\let\switchhack@sptoken= #1}\:{ }
\newcommand\switchhack[1]
{%
\def\switchhack@switch{#1}%
\switchhack@a
}
\newcommand\switchhack@a
{%
\futurelet\switchhack@gobbled\switchhack@b
}
\newcommand\switchhack@b
{%
\ifx\switchhack@gobbled\switchhack@sptoken
\switchhack@eatspace
\fi
\@firstofone
{%
\ifx\bgroup\switchhack@gobbled
\else
\GenericWarning
{}{Warning: Argument of \string\switchhack\space not delimited}%
\switchhack@undelimeted
\fi
\switchhack@delimited
}%
}
\long\def\switchhack@eatspace\fi#1#2%
{%
\fi
\afterassignment\switchhack@a
\let\switchhack@gobbled=
}
\long\def\switchhack@undelimeted\fi#1#2%
{%
\fi
{\switchhack@switch#2}%
}
\newcommand\switchhack@delimited
{%
\afterassignment\switchhack@do
\let\switchhack@gobbled
}
\newcommand\switchhack@do
{%
\bgroup\switchhack@switch
}
\long\def\colorhack#1#{\colorhack@{#1}}
\newcommand\colorhack@[2]
{%
\switchhack{\color#1{#2}}%
}
\makeatother

\newcommand\purp{\colorhack{purple}}
\newcommand\bfhack{\switchhack{\bfseries}}

\begin{document}
\colorhack[rgb]{.5 .4 .8}{foo}
\purp{\verb|this is blue|}
following text
\bfhack{this is bold}

\colorhack{red} Undelimeted

\purp{
\begin{verbatim}
This is
verbatim
purple (I lied up there, it never was blue)
\end{verbatim}
}
\end{document}

• I also observed weird error without using the verbatim env. I edited a question above. Could you take a look? May 9, 2019 at 1:45

Another possibility to get macros which take verbatim material as arguments is to grab the arguments as boxes instead. Again this is no universal solution and you can't do arbitrary stuff with it (most importantly you can't change the appearance of the boxed material after it is boxed, that's what the optional arguments of grabbox are for, to make some formatting possible).

The following defines \purp to take its argument inside of a \hbox and \purp* to take it inside of a \vbox (of course the macro name in both cases is \purp, the second one is just followed by a star).

\documentclass[]{article}

\usepackage{grabbox}
\usepackage{xcolor}

\makeatletter
\newsavebox\purp@box
\newcommand\purp
{%
\begingroup
\@ifstar
{%
\grabbox\purp@box[\color{purple}]\vbox{\unvbox\purp@box\endgroup}%
}
{%
\grabbox\purp@box[\color{purple}]\hbox{\unhbox\purp@box\endgroup}%
}%
}
\makeatother

\begin{document}
\purp{\verb|this is blue|}

other text

\purp*{
\begin{verbatim}
This is
verbatim
purple (I lied up there, it never was blue)
\end{verbatim}
}
\end{document}