如何通过将带有参数的宏应用于命令来修补 \xpretocmd 和 \xapptocmd 命令?

如何通过将带有参数的宏应用于命令来修补 \xpretocmd 和 \xapptocmd 命令?

假设我想修补一个非常复杂的宏,比如\autocite。为此,xpatch包是我的好朋友。如果修补包括应用不带参数的模态命令,例如\bfseries\xpretocmd也是我的朋友:

\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}

现在,假设补丁包括应用一个确实带有参数的宏,例如\textbf:我想要\autocite...成为\textf{\autocite...},无论中的星号/可选/强制参数是什么...。为此,我不能将\textf{}用作⟨prepend⟩⟨append⟩

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

因为括号不平衡。如果将{}替换为\bgroup\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}

它也不起作用,因为\egroup它被视为\autocite论点。

因此我的问题是:如何通过将带有参数的宏应用于命令来修补命令\xpretocmd\xapptocmd

编辑。我对下面的技巧寄予厚望,依靠包\BODY中的命令environ,但它也失败了……

\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}

答案1

让我们看一下的定义\autocite

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

这意味着宏会查找*并将控制权传递给另一个宏。仅通过修补根本不可能实现您想要的效果\autocite

对不起。

您可以重新定义\autocite使用xparse,以便传递完整的参数集和*-变量,并添加\textbf整个内容。

用户级语法\autocite

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

因此重新实现xparse如下

\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}}}%
   }%
 }%
}

您应该对 做类似的事情\Autocite

当然,对于来说,这种情况是不可能的\autocites,因为参数的数量是可变的。

更可能的情况是,你应该在实际排版的地方添加\begingroup\bfseries和匹配\endgroup。这当然需要深入分析的工作原理biblatex

答案2

总的来说,这确实取决于很多因素……

例如,你可以做一些简单的事情

在此处输入图片描述

\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}

在上面,可能已知 some\specialcmd只接受一个参数。因此,在大多数情况下,复制和重新定义方法就足够了。但是,如果\specialcmd构成某些宏链的一部分,并且这些宏可能具有后缀*或可选参数,则可能必须使用以下方法搜索要修补的链尾宏\apptocmd

在此处输入图片描述

\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}

请注意,上述补丁还依赖于这样一个事实,即更改基于可以在范围内定义的某些内容 - \bfseries- 但它也有一个宏类型对应部分 - \textbf

虽然上述补丁是使用etoolbox,同样的原则也适用于使用xpatch

因此,最终,修补的选择取决于什么补丁是否是和/或宏构造是否是基本的。

对于\autocite,它取决于您是否使用\autocite\autocite*,并在稍后阶段获取其参数,使其“非基本”。如果您从未使用条件\autocite*,那么您可以使用如下简单方法

\let\oldautocite\autocite
\renewcommand{\autocite}[1]{\textbf{\oldautocite{#1}}}

相关内容