Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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?

share|improve this question
1  
Issue a number of \unskips: \def\test{1}]\patchcmd\test{1}{2}{}{}\unskip\unskip\unskip[ –  Werner Dec 30 '13 at 0:09

1 Answer 1

up vote 10 down vote accepted

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.

share|improve this answer
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. –  jfbu 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

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.