142

I'd like to "add to" an existing command by writing something like

\renewcommand{\somecommand}{\begin{something}\somecommand\end{something}}

but (not surprisingly) I get errors about being "too deeply nested".

Is there a way to take an existing command, add to it (by appending or prepending additional commands or text), and then have that "augmented" command replace the existing command?

1
  • 11
    You may also want to look at the etoolbox package. – mbork Mar 9 '12 at 6:55
131

You can use \let to save a command under another name, and then use that new name in the \renewcommand.

\documentclass{article}

\let\oldemph\emph
\renewcommand{\emph}[1]{\textbf{\oldemph{#1}}}

\begin{document}
\oldemph{Old emph}
\emph{New emph}
\end{document}

(Edit: the TeX FAQ has much more information about "patching" commands. Edit2: egreg's answer below describes some of the gotchas of \let)

100

Important update

The LaTeX kernel from the 2020-10-01 release has \NewCommandCopy that does the same job of \LetLtxMacro and better. It also provides \ShowCommand to obtain the internal definition also of robust commands. So the code below should now be

\NewCommandCopy{\oldemph}{\emph}
\renewcommand{\emph}[1]{\textbf{\oldemph{#1}}}

The analysis below about the problems with \let is still valid.

Original answer

While something such as

\let\oldemph\emph
\renewcommand{\emph}[1]{\textbf{\oldemph{#1}}}

seems to work, it really doesn't, because \emph is defined with \DeclareRobustCommand. Where doesn't it work? suppose you write that code and then use \emph in a caption:

\caption{This is \emph{emphasized}}

what is written in the .aux file is

\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces This is \textbf  {\emph  {emphasized}}}}{1}}

This is because the original expansion of \emph is

\protect\emph§

(where with § I'm denoting a space in the name). So the \emph{emphasized} in the caption gets expanded successively into

\textbf{\oldemph{emphasized}}
\protect\textbf§{\protect\emph§{emphasized}}
\textbf§{\emph§{emphasized}

and written as

\textbf  {\emph  {emphasized}}

(because TeX adds a space after a command name when writing). In this case, when reading the file for building the List of Figures or Tables, TeX will find

\textbf{\textbf{\oldemph{emphasized}}}

which is innocuous. But it's not very difficult to imagine situations where this can lead to infinite loops.

The package letltxmacro prevents this problem:

\usepackage{letltxmacro}
\LetLtxMacro{\oldemph}{\emph}
\renewcommand{\emph}[1]{\textbf{\oldemph{#1}}}

would be a safer way to proceed.

Never use \let on commands defined with \DeclareRobustCommand or commands defined with \newcommand and having an optional argument.

The former can be recognized by the fact that \show\command returns

> \command=macro:
->\protect \command  .

The latter are distinguished by the fact that \show\command returns

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

(where ... is actually the default for the optional argument).

4
  • Haha, I picked a perfect bad example! (Thanks for explaining the mistake!) – huon Mar 9 '12 at 10:34
  • Would be interesting to know why I shouldn't use \let with those commands. – Stefan Braun Jan 26 '16 at 21:00
  • 3
    @StefanBraun Isn't the answer explaining it? – egreg Jan 26 '16 at 21:05
  • This answer is more comprehensive. The first answer without letltxmacro does not work all the time. – Kadir Apr 13 '20 at 11:46
20

Yes, this is possible using \g@addto@macro or some expanded definition (using \expandafter). Here are some examples:

enter image description here

\documentclass{article}
\setlength{\parindent}{0pt}% Just for this example
\begin{document}
\newcommand{\somecmd}{some \textbf{text}}
\somecmd \par
\makeatletter
\g@addto@macro\somecmd{ and some \textit{more} text}
\makeatother
\somecmd

\renewcommand{\somecmd}{some \textbf{text}}
\somecmd \par
\makeatletter
\expandafter\def\expandafter\somecmd\expandafter{\somecmd{} and some \textit{more} text}
\makeatother
\somecmd
\end{document}

The latter example, just like the former, appends contents to a macro. The placement of \somecmd in the latter could be used to prepend something.

However, nothing prevents you from making a new command that includes the old command as part of its expansion, since memory problems tend to be a thing of the past.

You run into problems when the contents of the newly-defined macro does not expand properly. Using your case as an example: although \somecommand may expand as expected, the center environment does not.

1
  • This answer is actually much better than the currently higher voted ones if one needs to add to the same macro more than once, in which case using a temporary variable will not work, unless new temporary variable names are used every time. – Dalker Oct 12 '17 at 10:00
1

Sometimes, you need to use the original name of the command, and you cannot use an environment because of some undesirable side effects. I have the case with \LettrineFontHook which is not directly called in my code. Here, the only solution I have found is to use \let to store and restore the command:

\let\tempLettrineFontHook\LettrineFontHook
\renewcommand{\LettrineFontHook}{\fontseries{bx}}
\lettrine{F}{}
\let\LettrineFontHook\tempLettrineFontHook

If I try to define an environment like this:

\newenvironment{boldLettrine}{%
\renewcommand{\LettrineFontHook}{\fontseries{bx}}%
}{}
% let's use this environment in the document now:
\begin{boldLettrine}
\lettrine{F}{}
\end{boldLettrine}

For reasons I ignore, the indentation of the lettrine is broken.

EDIT: From egreg remark, in your example, this method cannot apply since the new command is defined with the help of the original one, leading to possible infinite loops. So I cancel the application to your use case.

6
  • 1
    not that I follow like a detective all your moves but viz For reasons I ignore, the indentation of the lettrine is broken. : there must be a \par. Because the closing of the environment cleans up the \parshape set up by lettrine package. Please always post complete MWE rather than just a few lines of code. Apart from that this uses your own \Lettrine from some other question but should be with \lettrine. (but then one needs a second, possibly empty, argument {}) – user4686 May 22 '14 at 17:53
  • 1
    In my answer I tell exactly why \let\oldemph\emph is to be avoided. – egreg May 22 '14 at 18:13
  • @egreg, in the case you detail, the copied command is used in the definition of the original one, what can makes infinite loops in the conditions you precise. I think it is not the case in my use case, but I should not have generalized. – lalebarde May 22 '14 at 19:53
  • 1
    @lalebarde Follow \lettrine{F}{} by a \par before closing the environment if you want to get the indentation as expected. Did you notice that the original post dates back to Mar 9 '12 at 5:31? – user4686 May 22 '14 at 20:11
  • 1
    Thanks jfbu. I did notice yes, but as far as I have understood stackexchange, it is also a knowledge & know-how repository. – lalebarde May 22 '14 at 21:06
0

Append to a defined command

If you want to simply append something to a command after it, you can use the LaTeX kernel \g@addto@macro:

\def\authors{}
\def\addauthor#1{%
    \g@addto@macro\authors{
        \begin{tabular}[t]{c}%
            #1
        \end{tabular}%
    }
}

Then in the preamble you can:

\addauthor{Cristiano Ronaldo}
\addauthor{Lionel Messi}

The \authors will contain a printable list of authors that you can use in your maketitle, for example.

Append and Prepend to a defined command

I have not test it, but try:

\def\aroundto#1#2#3{\toks0={#2}\toks1=\expandafter{#1}\toks2={#3}\edef#1{\the\toks0 \the\toks1 \the\toks2}}

References: both solutions were found in The Hacks blog.

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.