I am using the moderncv class provided by TeXLive 2016 and in it the \section command is redefined as follows:

  \phantomsection{}% reset the anchor for hyperrefs
  \par\nobreak\addvspace{1ex}\@afterheading}% to avoid a pagebreak

I want to modify the vertical spacing in the first line, that is 2.5ex to be explicit. If I try to do it with macros from the xpatch package it fails due to unknown reasons.

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

Why is this the case? If I enclose the \RenewDocumentCommand between \makeatletter, \makeatother commands and modify the length 2.5ex to suit my needs everything works fine. Is it a limitation of xpatch commands? I am really curious about this behaviour and want to know why I experience this.

EDIT A MWE is provided below.

\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[scale=0.8]{geometry} % Reduce document margins
\setlength{\hintscolumnwidth}{3cm} % Uncomment to change the width of the dates column

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

    \makecvtitle % Print the CV title

    \section*{Technical Skills}


    \section*{Certificates and Achievements}


    \section*{Schools and Workshops}




  • 1
    Please post a compilable document, not just fragments. Do you have enclosed the \xpatchcmd trial with \makeatletter...\makeatother as well? – user31729 Jul 30 '17 at 23:21
  • 1
    I forgot: xpatch can't be used for macros that have been defined with xparse in general. See the section 5 of the xpatch documentation – user31729 Jul 30 '17 at 23:38
  • 1
    This is by design. The document-level macros created using xparse are not intended to be patchable. Typically, these should only be wrappers for lower level functions. Those functions can be redefined etc. The wrappers can be \Renewed \Declared etc., but they cannot be patched and ought not be. – cfr Jul 30 '17 at 23:38
  • 1
    xpatch only acts on commands defined with\def, \newcommand (and variants thereof) or \DeclareRobusCommand. There are no plans to support the xparse defined commands. – egreg Jul 31 '17 at 8:47
  • 1
    To be more precise: \newcommand and \DeclareRobustCommand inner workings are decades old and aren't bound to change. Within LaTeX3, basing code to inner details is the wrong thing to do, because internals (macros with __ in their names) are not guaranteed to be the same forever. – egreg Jul 31 '17 at 9:51

In the beginning there was patchcmd, by Michael Downes, which allowed to add tokens at the beginning or end of macros defined with \newcommand or \DeclareRobustCommand (but without optional arguments).

Then etoolbox allowed much more freedom, however only doing its work on macros defined with \newcommand or \newrobustcmd, but without optional argument.

An increasing demand for patching led to the release of xpatch, which is able to “guess” whether a command is defined with \newcommand, \newrobustcmd or \DeclareRobustCommand, with or without a leading optional argument.

While xpatch itself is written using expl3, there is no plan to extend it in order to allow patching commands defined with \NewDocumentCommand (from xparse).

One reason is that \newcommand and \DeclareRobustCommand are decades old and they're essentially unchangeable, because several packages depend on their actual implementation. Some words about how xpatch can help in understanding the matter.

Suppose we want to patch the macro \foo, defined with \newcommand\foo[2]{...}. No problem,


directly uses


where \patchcmd is the main macro defined in etoolbox. If \foo is defined with \newcommand{\foo}[2][default]{...} (with an optional argument), the above call of \xpatchcmd actually does


which becomes


in case \foo has been defined with \DeclareRobustCommand{\foo}[2][default]{...}.

The purpose of xpatch is to relieve the user from having to guess what complicated combination of commands to use. It is apparent that xpatch can only work if the indirect definitions done when optional arguments are involved don't change.

On the other hand, the expl3 approach is completely different.

The idea is that there will be an intermediate level between expl3 and the user interface, so in the future \NewDocumentCommand will use this intermediate level and patching should become useless. But there is also another reason: in the LaTeX3 approach, only public interfaces should be relied upon, whereas private ones aren't available.

The implementation of \NewDocumentCommand relies on several private functions and indeed, these have recently changed. Supporting \NewDocumentCommand defined macros is, in principle, feasible: if we do


then \show\foo displays

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

and the actual macro to patch would be \foo code (with a space in the name). But this is internal and not cast into stone.

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.