7

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} 
asdfadf
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?

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

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} 
asdfadf
asdf
asdf
\end{verbatim}
}
\end{document}

enter image description here

  • 4
    you should add a group to avoid that following text is purple too. – Ulrike Fischer May 8 at 10:05
  • @UlrikeFischer Thank you for reminding me of that. – Steven B. Segletes May 8 at 10:08
  • awesome thank you! – Jaebum May 9 at 1:36
  • I also observed weird error without using the verbatim env. I edited a question above. Could you take a look? – Jaebum May 9 at 1:45
  • 2
    @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. – Steven B. Segletes May 9 at 1:51
5

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}

enter image description here

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

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}

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.