修补命令不适用于 /RenewDocumentCommands

修补命令不适用于 /RenewDocumentCommands

我正在使用moderncvTeXLive 2016 提供的类,其中\section命令重新定义如下:

\RenewDocumentCommand{\section}{sm}{%
  \par\addvspace{2.5ex}%
  \phantomsection{}% reset the anchor for hyperrefs
  \addcontentsline{toc}{section}{#2}%
  \cvitem[0ex]{\strut\raggedleft\raisebox{\baseletterheight}{\color{color1}\rule{\hintscolumnwidth}{0.95ex}}}{\strut\sectionstyle{#2}}%
  \par\nobreak\addvspace{1ex}\@afterheading}% to avoid a pagebreak

我想修改第一行的垂直间距,即2.5ex如果我尝试使用xpatch包中的宏来执行此操作,则会由于未知原因而失败。

\xpatchcmd{\section}{2.5ex}{15ex}{\typeout{----Section command patched----}}{\typeout{----Section command cannot be patched----}}

为什么会这样?如果我将\RenewDocumentCommand,\makeatletter命令括起来\makeatother并修改长度2.5ex满足我的需求,一切都很好。这是xpatch命令的限制吗?我对这种行为非常好奇,想知道为什么我会遇到这种情况。

编辑下面提供了 MWE。

\documentclass[10pt,a4paper,sans]{moderncv} % Font sizes: 10, 11, or 12; paper sizes: a4paper, letterpaper, a5paper, legalpaper, executivepaper or landscape; font families: sans or roman

\moderncvstyle{casual} % CV theme - options include: 'casual' (default), 'classic', 'oldstyle' and 'banking'
\moderncvcolor{red} % CV color - options include: 'blue' (default), 'orange', 'green', 'red', 'purple', 'grey' and 'black'
%\usepackage{lipsum} % Used for inserting dummy 'Lorem ipsum' text into the template
\usepackage[utf8]{inputenc}
\usepackage[scale=0.8]{geometry} % Reduce document margins
%\usepackage{amsfonts,color}
%\usepackage{graphicx,calc}
\usepackage{footmisc}
\usepackage{xpatch}
%\usepackage{mathpazo}
%\renewcommand{\sfdefault}{ppl}
\setlength{\hintscolumnwidth}{3cm} % Uncomment to change the width of the dates column
\setlength{\footskip}{36pt}

\firstname{John} % Your first name
\familyname{Doe} % Your last name

\xpatchcmd{\cvitem}{#2}{\bfseries #2}{}{}
\xpatchcmd{\section}{2.5ex}{15ex}{\typeout{----Section command patched----}}{\typeout{----Section command cannot be patched----}}
%\xpatchcmd{\section}{\rule{\hintscolumnwidth}{0.95ex}}{\rule{\hintscolumnwidth}{1.95ex}}{\typeout{----Section command patched----}}{\typeout{----Section command cannot be patched----}}

%%% If you UNCOMMMENT this everything works 
%\makeatletter
%\RenewDocumentCommand{\section}{sm}{%
%  \par\addvspace{5.5ex}%originally 2.5ex
%  \phantomsection{}% reset the anchor for hyperrefs
%  \addcontentsline{toc}{section}{#2}%
%  \parbox[t]{\hintscolumnwidth}{\strut\raggedleft\raisebox{\baseletterheight}{\color{color1}\rule{\hintscolumnwidth}{0.95ex}}}%
%  \hspace{\separatorcolumnwidth}%
%  \parbox[t]{\maincolumnwidth}{\strut\sectionstyle{#2}}%
%  \par\nobreak\addvspace{1ex}\@afterheading}% to avoid a pagebreak after the heading
%\makeatother

%%%%
\begin{document}
    \makecvtitle % Print the CV title
    \section*{Education}

    \section*{Technical Skills}

    \section*{Experience}

    \section*{Certificates and Achievements}

    \section*{Projects}

    \section*{Schools and Workshops}

    \section*{Languages}

    \section*{Associations}

    \section*{Interests}


\end{document}

答案1

一开始patchcmd,Michael Downes 开发了,它允许在使用\newcommand或定义的宏的开头或结尾添加标记\DeclareRobustCommand(但没有可选参数)。

然后允许更多的自由,但是只对用或etoolbox定义的宏进行工作,但没有可选参数。\newcommand\newrobustcmd

修补需求的不断增长导致了 的发布xpatch,它能够“猜测”一个命令是用\newcommand\newrobustcmd或定义的\DeclareRobustCommand,带有或不带有前导可选参数。

虽然xpatch它本身是使用 编写的expl3,但是没有计划扩展它以允许修补用\NewDocumentCommand(来自xparse)定义的命令。

其中一个原因是\newcommand\DeclareRobustCommand已经有几十年的历史了,而且基本上是不可改变的,因为几个包依赖于它们的实际实现。关于如何的一些话xpatch可以帮助理解这个问题。

假设我们要修补\foo用 定义的宏\newcommand\foo[2]{...}。没问题,

\xpatchcmd\foo{<search>}{<replace>}{<success>}{<failure>}

直接使用

\patchcmd\foo{<search>}{<replace>}{<success>}{<failure>}

其中\patchcmd,主宏定义在 中etoolbox。如果\foo用 定义\newcommand{\foo}[2][default]{...}(带有可选参数),则上述调用\xpatchcmd实际上会

\expandafter\patchcmd\csname\string\foo\endcsname{<search>}{<replace>}{<success>}{<failure>}

变成

\expandafter\patchcmd\csname\string\foo\space\endcsname{<search>}{<replace>}{<success>}{<failure>}

如果\foo已经用 定义了\DeclareRobustCommand{\foo}[2][default]{...}

的目的xpatch是让用户不必猜测要使用什么复杂的命令组合。显然,xpatch只有在涉及可选参数时进行的间接定义不变的情况下,才能发挥作用。

另一方面,expl3方法却完全不同。

我们的想法是,在用户界面之间会有一个中间层expl3,所以将来\NewDocumentCommand会使用这个中间层,修补应该变得毫无用处。但还有另一个原因:在 LaTeX3 方法中,只有民众接口应该被依赖,而私有接口则不可用。

的实现\NewDocumentCommand依赖于几个私有函数,事实上,这些函数最近已经发生了变化。\NewDocumentCommand原则上,支持定义的宏是可行的:如果我们这样做

\NewDocumentCommand{\foo}{O{default}m}{...}

然后\show\foo显示

> \foo=\protected macro:
->\__xparse_start:nNNnnn {O{default}m}\foo  \foo code {\__xparse_grab_D:w []\__
xparse_grab_m_1:w }{{\prg_do_nothing: default}\c_novalue_tl }{}.

而实际要修补的宏将是\foo code(名称中有一个空格)。但这是内部的,并不是一成不变的。

相关内容