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
  • 1
    Issue a number of \unskips: \def\test{1}]\patchcmd\test{1}{2}{}{}\unskip\unskip\unskip[
    – Werner
    Dec 30, 2013 at 0:09

1 Answer 1

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.

4
  • 6
    shouldn't you have patched etoolbox with patchcmd for a satisfying virtuous circle? Dec 30, 2013 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, 2013 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, 2013 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, 2013 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.