9

It seems that \patchcmd from etoolbox adds three unwanted spaces, as shown below:

\documentclass{minimal}
\usepackage{etoolbox}
\begin{document}
\tracingall%                            3 spaces in log file
\def\test{1}]\patchcmd\test{1}{2}{}{}[% 3 spaces between brackets in output
\end{document}

How can I fix this?

  • 1
    Issue a number of \unskips: \def\test{1}]\patchcmd\test{1}{2}{}{}\unskip\unskip\unskip[ – Werner Dec 30 '13 at 0:09
10

Two spaces come from calls of \scantokens, the third from an unprotected end-of-line in the code.

\documentclass{minimal}
\usepackage{etoolbox}

\makeatletter
% Add \ifhmode\unskip\fi
\protected\def\etb@ifscanable#1{%
  \begingroup
  \edef\etb@resrvda{%
    \def\noexpand\etb@resrvda####1\detokenize{macro}:####2->####3&{%
      ####1\def\string\etb@resrvda####2{####3}}%
    \edef\noexpand\etb@resrvda{\noexpand\etb@resrvda\meaning#1&}}%
  \etb@resrvda
  \makeatletter
  \scantokens\expandafter{\etb@resrvda}%
  %%% ADDITION
  \ifhmode\unskip\fi
  %%% END ADDITION
  \expandafter\endgroup\ifx#1\etb@resrvda
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}
\def\etb@patchcmd@scantoks#1{%
  \edef\etb@resrvda{\endgroup
    \unexpanded{\makeatletter\scantokens}{#1}%
    \catcode\number`\@=\the\catcode`\@\relax}%
  \etb@resrvda
  %%% ADDITION
  \ifhmode\unskip\fi
  %%% END ADDITION
}
% Fix a missing `%'
\protected\long\def\etb@ifpattern#1#2{%
  \begingroup
  \edef\etb@resrvda{%
    \def\noexpand\etb@resrvda####1\detokenize{#2}####2&{%
      \endgroup\noexpand\noexpand\noexpand\ifblank{####2}}%
    \edef\noexpand\etb@resrvda{\noexpand\etb@resrvda
      \expandafter\strip@prefix\meaning#1\detokenize{#2}&}%
    \noexpand\etb@resrvda}% <---------- MISSING IN etoolbox.sty
  \etb@resrvda\@secondoftwo\@firstoftwo}

\makeatother


\begin{document}
\def\test{1}]\patchcmd\test{1}{2}{}{}[% brackets for checking

][% for check
\end{document}

enter image description here

However, the best strategy is never using \patchcmd in horizontal mode.

The corresponding command \xpatchcmd from regexpatch is free from this problem.


A different patch could be adding \@empty at the end of the two `\scantokens:

\protected\def\etb@ifscanable#1{%
  \begingroup
  \edef\etb@resrvda{%
    \def\noexpand\etb@resrvda####1\detokenize{macro}:####2->####3&{%
      ####1\def\string\etb@resrvda####2{####3}}%
    \edef\noexpand\etb@resrvda{\noexpand\etb@resrvda\meaning#1&}}%
  \etb@resrvda
  \makeatletter
  \scantokens\expandafter{\etb@resrvda\@empty}% <---- ADDED
  \expandafter\endgroup\ifx#1\etb@resrvda
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}
\def\etb@patchcmd@scantoks#1{%
  \edef\etb@resrvda{\endgroup
    \unexpanded{\makeatletter\scantokens}{#1\noexpand\@empty}% <---- ADDED
    \catcode\number`\@=\the\catcode`\@\relax}%
  \etb@resrvda}

In the second case, \noexpand\@empty is needed, because we're inside an \edef. However this requires more testing than I'm inclined to do.

I'd have liked patching the two commands with \patchcmd itself, but they resist it.

  • 6
    shouldn't you have patched etoolbox with patchcmd for a satisfying virtuous circle? – David Carlisle Dec 30 '13 at 1:31
  • with \endlinechar set to -1 one avoids the spaces coming from \scantokens: \begingroup\endlinechar-1 \patchcmd\test{1}{2}{}{}\global\let\test\test\endgroup. There remains the space you identified in \etb@ifpattern. – user4686 Dec 30 '13 at 8:43
  • 1
    Are you going to contact CTAN about this? The code has the awkward 'author-maintained' status, but presumably a way around that can be found to fix it. – Joseph Wright Dec 30 '13 at 9:13
  • 1
    @JosephWright I'm inclined to avoid proposing the insertion of \ifhmode\unskip\fi. The missing % should be fixed. – egreg Dec 30 '13 at 10:17

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.