The Problem
There are several packages I would like to write which require me to redefine the \newcommand
(\renewcommand
, etc.) command so I can track or change the commands that authors subsequently define. But I have no idea how to go about it. My naive attempts so far have failed. Probably because I am still very weak at the TeX level.
I'm surprised that I couldn't find more than vague hints towards this concept. It feels like such an obvious thing to do.
Motivation
A simple usecase, and the first package I plan write, is to ensure the following: that using \newcommand
to define a command – say: \cmd
– that has already been defined does not immediately generate an error. \cmd
would simply be in a state of conflict. Subsequently trying to expand \cmd
would then generate an error (since it's ambiguous which of the two definitions you want).
The conflict could be resolved by subsequently redefining \cmd
using \renewcommand
, after which \cmd
can once again safely be expanded. Example:
\newcommand{\cmd}{FIRST} %
\cmd % outputs FIRST
\newcommand{\cmd}{SECOND} % no problem yet
\cmd % error: expanding ambiguous command
\renewcommand{\cmd}{THIRD} %
\cmd % outputs THIRD
This could, for example, be used to mediate conflicts between packages (that use \newcommand
). Of course, this concept is still quite weak (for example, what to do if two packages independently use \renewcommand
on the same command?). But it is enough to serve as a usecase for my question.
After I learn more about this, I plan to exercise more fine-grained control.
Pseudo Code Solution
It feels like I have to do something like this (ignoring the optional argument for now):
\let\old@newcommand\newcommand
\MetaRenewCommand{\newcommand}{
\ifdefined#1
\old@newcommand{#1}{
\PackageError{lazyfail}{Expanding ambiguous command \protect #1}
}
\else
\old@newcommand{#1}{#3}
\fi
}
Of course, there are many things wrong with this code. There is no \MetaRenewCommand
and I still have to handle the optional argument of \newcommand
.
So, how do I start? It feels like it must be possible, as \newcommand
and friends are not primitives of LaTeX, but defined in terms of lower level commands.
Further Motivation
Here's another use-case I have in mind for this. When including a package, I would like to ignore all commands it provides except for a small list which I specify:
\usepackagefor[\Lightning]{marvosym}
Here I am loading the marvosym
package, but only to use \Ligntning
. I choose this example because the marvosym
\CheckedBox
command conflicts with the one in the llncs
class.
I already routinely specify the commands I plan to use a package for with a comment, but it would be nice to actually enforce that.
Best Answer
Tackling the problem as posed is tricky due to the way
\newcommand
works. Heiko's approach is probably more elegant, but one possible method is to usexparse
to deal with the syntax of\newcommand
, andletltxmacro
to deal with the way\newcommand
is set upThe approach here is to grab all of the arguments to the redefined
\newcommand
in one go, then work out whether they are to be 'recycled' or not.Of course, you could set all of this up without
xparse
, but it would be a pain in the next: lots of\@ifstar
and\@ifnextchar
( or slightly better\@testopt
) stuff and several auxiliaries.