4

This is the follow-up - question, respectively the main cause which led to the (yet) unanswered question here: \xpatchcmd defines macros when applied to undefined commands

I tried to patch some command, say, \someothercommand, which is defined locally within another macro, say, \somecommand, outside of the later macro, e.g. in a preamble.

This fails however. The patching jumps to the false branch. I suspect, this is somehow connected to local grouping.

A situation, where this might occur is, when one wants to patch macro definitions which lurk inside of other macros, say in a class or package file.

Consider the case where some bad code should be changed without copying the whole outer macro or editing the .cls or .sty file

Is patching of such locally defined macros possible at all?

I simplified the MWE

\documentclass{article}
\usepackage{xcolor}
\usepackage{xpatch}

\newcommand{\somecommand}[1]{%
  \newcommand{\someothercommand}[1]{\textcolor{blue}{##1}}%
  % This works
  % \xpatchcmd{\someothercommand}{blue}{red}{\typeout{Success!}}{\typeout{Nobody expects the Spanish Inquisition!!!!}}
  Inside usage: \someothercommand{#1}%
}

% Patching fails 
\xpatchcmd{\someothercommand}{blue}{red}{\typeout{Success!}}{\typeout{Nobody expects the Spanish Inquisition!!!!}}


\begin{document}
\somecommand{Outer command}

Outside usage: \someothercommand{Inside} but should be \textcolor{red}{Inside}
\end{document}

enter image description here

  • The colors are just for checking, but there might be more difficult situations, of course – user31729 Apr 20 '15 at 12:28
  • you can't patch \someothercommand before it is defined (how could that work?) don't you just want to patch \somecommand to change blue to red? – David Carlisle Apr 20 '15 at 12:30
  • @DavidCarlisle: Oh, I see... the order is wrong. Changing it works, of course – user31729 Apr 20 '15 at 12:31
  • Side note: you shouldn't use \newcommand inside another command without grouping or you will get an error when you use the outer command more than one. – Ulrike Fischer Apr 20 '15 at 12:35
  • @UlrikeFischer: I know, I omitted it – user31729 Apr 20 '15 at 12:38
2

I would look for a suitable place in \somecommand to place a hook:

\documentclass{article}
\usepackage{xcolor}
\usepackage{xpatch}

\newcommand{\somecommand}[1]{%
  \def\someothercommand##1{\textcolor{blue}{##1}}%
  Inside usage: \someothercommand{#1}%
}


\xpatchcmd{\somecommand}{Inside usage:}{Inside usage: \myspecialsetup}{\typeout{Success!}}{\typeout{Nobody expects the Spanish Inquisition!!!!}}

\newcommand\myspecialsetup{\renewcommand\someothercommand[1]{\textcolor{red}{##1}}}

\begin{document}
\somecommand{Outer command}
\end{document}
|improve this answer|||||
  • Thank you, Ulrike. Actually I had a similar idea in mind, a wrapper replacing the bad code – user31729 Apr 20 '15 at 16:13
4

You can only patch commands that have been defined, so \somecommand here:

\documentclass{article}
\usepackage{xcolor}
\usepackage{xpatch}

\newcommand{\somecommand}[1]{%
  \newcommand{\someothercommand}[1]{\textcolor{blue}{##1}}%
  % This works
  % \xpatchcmd{\someothercommand}{blue}{red}{\typeout{Success!}}{\typeout{Nobody expects the Spanish Inquisition!!!!}}
  Inside usage: \someothercommand{#1}%
}

% Patching works 
\xpatchcmd{\somecommand}{blue}{red}{\typeout{Success!}}{\typeout{Nobody expects the Spanish Inquisition!!!!}}


\begin{document}
\somecommand{Outer command}

Outside usage: \someothercommand{Inside} but should be \textcolor{red}{Inside}
\end{document}
|improve this answer|||||
  • I've tried that already of course. But if there is a really complicated setup inside of \somecommand, with multiple occurences of blue, this might fail if I want to change only the blue inside of \someothercommand. – user31729 Apr 20 '15 at 12:34
  • @ChristianHupfer but that is always true of patch, you need to specify enough of the original tokens to locate the right point, the fact that some earlier tokens happen to include \newcommand isn't relevant to the patch mechanism. – David Carlisle Apr 20 '15 at 12:37
  • Thanks, I just hoped I could bypass the bunch of tokens and patch locally – user31729 Apr 20 '15 at 12:41
  • 1
    @ChristianHupfer You can patch the \someothercommand after it has been defined (after you have run \somecommand) before \somecommand has been run there is nothing to patch. The replacement text of \somecommand has been checked for matching {} but that is all. – David Carlisle Apr 20 '15 at 12:54

Your Answer

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