我正在使用moderncv
TeXLive 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
(名称中有一个空格)。但这是内部的,并不是一成不变的。