假设我想修补一个非常复杂的宏,比如\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}}}