3

Suppose I'd like to patch a very complicated macro, say \autocite. For this, xpatch package is my friend. If the patch consists in applying a modal command which doesn't take arguments, such as \bfseries, \xpretocmd is also my friend:

\documentclass{article}
\usepackage{xpatch}
\usepackage[backend=biber]{biblatex}%
%
\addbibresource{biblatex-examples.bib}
%
% \autocite's patch
\xpretocmd{\autocite}%
{\bfseries}%
{\message{^^Jxpretocmd OK^^J^^J}}%
{\message{^^Jxpretocmd not OK^^J^^J}}
%
\begin{document}
\autocite{cicero}
\printbibliography
\end{document}

Now, suppose the patch consists in applying a macro which does take an argument, such as \textbf: I want \autocite... to become \textf{\autocite...}, whatever are the star/optional/mandatory arguments in .... For this, I can't use \textf{ and } as ⟨prepend⟩ and ⟨append⟩ in:

\xpretocmd{⟨command⟩}{⟨prepend⟩}{⟨success⟩}{⟨failure⟩}
\xapptocmd{⟨command⟩}{⟨append⟩}{⟨success⟩}{⟨failure⟩}

because of unbalanced braces. If { and } are replaced by \bgroup and \egroup:

\documentclass{article}
\usepackage{xpatch}
\usepackage[backend=biber]{biblatex}%
%
\addbibresource{biblatex-examples.bib}
%
% \autocite's patch
\xpretocmd{\autocite}%
{\textbf\bgroup}%
{\message{^^Jxpretocmd OK^^J^^J}}%
{\message{^^Jxpretocmd not OK^^J^^J}}
\xapptocmd{\autocite}
{\egroup}%
{\message{^^Jxapptocmd OK^^J^^J}}%
{\message{^^Jxapptocmd not OK^^J^^J}}
%
\begin{document}
\autocite{cicero}
\printbibliography
\end{document}

it doesn't work neither as \egroup is considered as the \autocite's argument.

Hence my question: how to patch with \xpretocmd and \xapptocmd a command by applying to it a macro with argument?

Edit. I placed a great deal of hope in the following trick, relying on \BODY command from environ package, but it fails as well...

\documentclass{article}
\usepackage{xpatch}
\usepackage{environ}
\usepackage[backend=biber]{biblatex}%
%
\addbibresource{biblatex-examples.bib}
%
\NewEnviron{boldify}{%
  \textbf{\BODY}%
}
% \autocite's patch
\xpretocmd{\autocite}%
{\boldify}%
{\message{^^Jxpretocmd OK^^J^^J}}%
{\message{^^Jxpretocmd not OK^^J^^J}}
\xapptocmd{\autocite}
{\endboldify}%
{\message{^^Jxapptocmd OK^^J^^J}}%
{\message{^^Jxapptocmd not OK^^J^^J}}
%
\begin{document}
\autocite{cicero}
\printbibliography
\end{document}
  • I don't think that appending to a macro with several arguments such as \autocite is easily possible… \renewcommand\citesetup{\bfseries} does not suffice for your needs? – clemens Nov 6 '15 at 11:18
  • @clemens \textbf is just an example. In the real life, the macro with argument is not so simple: namely, it is e.g. \switchocg{⟨refocgs⟩}{⟨complicated command such as \autocite with possibly several optional/mandatory arguments⟩}. – Denis Bitouzé Nov 6 '15 at 11:23
  • Sorry, but you can't do it like that, because \autocite ends with a macro looking for its arguments. – egreg Nov 6 '15 at 11:23
  • @DenisBitouzé then you probably need a wrapper macro for \autocite with the same argument structure which passes its arguments to \autocite and wraps the whole thing in the macro you need – clemens Nov 6 '15 at 11:26
  • 1
    Imho you are misusing patching. You should better make a biblatex feature request that is adds a wrapper which allows to surround the complete cite (similar to e.g. \mkbibparens in \parencite), or adds some hook \AtEveryCiteEnd which would allow you to enter the starting code of your ocg-command in \AtEveryCite and the \pdfendlink at the end. – Ulrike Fischer Nov 6 '15 at 14:03
4

Let's look at the definition of \autocite:

> \autocite=\protected macro:
->\blx@citecmdinit \@ifstar {\blx@citepunct {\blx@acitei@inline *}} {\blx@citepunct {\blx@acitei@inline {}}}.

This means that the macro looks for * and then passes control to another macro. It's simply not possible to make what you want by just patching \autocite.

Sorry.

You may instead redefine \autocite using xparse so that you pass the full set of arguments and *-variants, adding \textbf around the whole thing.

The user level syntax of \autocite is

\autocite*[<prenote>][<postnote>]{<key>}

so a reimplementation with xparse could be

\usepackage{xparse}

\let\BLautocite\autocite
\RenewDocumentCommand{\autocite}{soom}{%
 \textbf{%
  \IfNoValueTF{#2}% no notes
   {\IfBooleanTF{#1}{\BLautocite*{#4}}{\BLautocite{#4}}
   {% else
    \IFNoValue{#3}% only optional argument is postnote
     {\IfBooleanTF{#1}{\BLautocite*[#2]{#4}}{\BLautocite[#2]{#4}}}
     {\IfBooleanTF{#1}{\BLautocite*[#2][#3]{#4}}{\BLautocite[#2][#3]{#4}}}%
   }%
 }%
}

You should do similarly for \Autocite.

Of course, something like this would be impossible for \autocites, where the number of arguments is variable.

More likely, you should add \begingroup\bfseries and a matching \endgroup where the actual typesetting takes place. This of course requires going deep in analyzing the working of biblatex.

  • With xparse? But anyway, too bad: as said in comment @clemens, having to deal with the exact argument structure of these macros is a pain, especially if numerous of them have to be patched. – Denis Bitouzé Nov 6 '15 at 11:33
  • @DenisBitouzé with xparse it is a lot easier to redefine with the exact argument structure. (What actually really might be a problem is the scanning ahead for trailing punctuation that biblatex's cite commands do…) – clemens Nov 6 '15 at 11:48
  • @clemens Okay but, as shown by egreg, this requires to deal with this exact argument structure, a pain I'd like to avoid :) – Denis Bitouzé Nov 6 '15 at 12:37
  • @DenisBitouzé of course it does but not using xparse would even increase the pain ;) – clemens Nov 6 '15 at 12:39
  • @egreg Okay but I'd like to avoid tricks such as \let\origautocite\autocite and \renewcommand{\autocite}[...]{...} (LaTeX's way) or \RenewDocumentCommand{\autocite} (LaTeX3's way) because, in reimplementations, you have to take care of the exact argument structure. – Denis Bitouzé Nov 6 '15 at 12:41
3

In general, this really depends on a number of things...

For example, you can do something as simple as

enter image description here

\documentclass{article}

% Special command that is already defined
\newcommand{\specialcmd}[1]{\textit{#1}}

\begin{document}

\specialcmd{abc}

\let\oldspecialcmd\specialcmd% Copy definition
\renewcommand{\specialcmd}[1]{\textbf{\oldspecialcmd{#1}}}

\specialcmd{abc}

\end{document}

In the above, it may be known that some \specialcmd takes only a single argument. Therefore, a copy-and-redefinition approach is sufficient in most cases. However, if \specialcmd forms part of some chain of macros that conditions on possibly having a * suffix, or optional arguments, you may have to search for the end-of-chain macro to patch using \apptocmd:

enter image description here

\documentclass{article}

\usepackage{etoolbox}

\begin{document}

\section{abc}
\section*{def}

\makeatletter
\pretocmd{\section}{\bgroup\let\bfseries\mdseries}{}{}
\apptocmd{\@xsect}{\egroup}{}{}
\makeatother

\section{abc}
\section*{def}

\end{document}

Note that the above patch also relies on the fact that the change is based on something that can be defined within a scope - \bfseries - yet it also has a macro-type counterpart - \textbf.

While the above patch is implemented using etoolbox, the same principle holds for using xpatch.

So, ultimately, ones choice of patching depends on what the patch is and/or whether the macro construction is elementary or not.

In the case of \autocite, it conditions on whether you use \autocite or \autocite*, grabbing its arguments at a later stage, making it "not elementary". If you're never using the conditional \autocite*, you can get away with something as simple as

\let\oldautocite\autocite
\renewcommand{\autocite}[1]{\textbf{\oldautocite{#1}}}
  • 2
    The above suggestion ignores the fact that biblatex provides \citesetup. As such, the discussion is only used for illustrative purposes. – Werner Nov 6 '15 at 11:46
  • The point is the macro (with mandatory argument) I have to apply to the command to be patched hasn't any counterpart that can be defined within a scope: it is e.g. \switchocg{⟨refocgs⟩}{⟨complicated command such as \autocite with possibly several optional/mandatory arguments⟩} (from ocgx package). – Denis Bitouzé Nov 6 '15 at 11:46
  • 1
    @DenisBitouzé: There remains a number of ways to complete the patch. A copy-and-redefinition approach may suffice where, instead of \switchocg{..}{...} you redefine \switchocg to always be \switchocg{..}{\specialcmd{...}}. – Werner Nov 6 '15 at 11:53
  • Redefining \switchocg is not be an option because \switchocg{...}{⟨complicated command such as \autocite with possibly several optional/mandatory arguments⟩} is supposed to apply to several complicated commands, such as \autocite, \parencite, \cite, \textcite, etc. (and these, only in biblatex's area but there are other areas). – Denis Bitouzé Nov 6 '15 at 12:35

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.