4

So this is my example, closely related to Remove extra curly braces. Apart from my application, trying to line-break the labels in the margin even if they do not have spaces in them, I am trying to understand what's going on.

\documentclass{article}
\usepackage{showlabels}
\usepackage{seqsplit}
\usepackage{xpatch}
\makeatletter

% line-break annotations, http://tex.stackexchange.com/a/148613/30810
\patchcmd{\showlabelsetlabel}{#1}{\parbox[t]{\marginparwidth}{\myseqsplit{#1}}}{}{err}

% remove extra curly braces, http://tex.stackexchange.com/a/300871/30810
\newcommand{\myseqsplit}[1]{\expandafter\seqsplit\expandafter{\@firstofone#1}}

% remove curly braces from text
\patchcmd{\SL@margintext}{\{\SL@prlabelname{#1}\}}{#1}{}{err}

% testing patch: overwrite *definition* of \SL@prlabelname (twice because two code paths) - no effect
% \patchcmd{\SL@margtext}{\xdef\SL@labelname{\SL@prlabelname{#1}}}{\xdef\SL@labelname{kooooooooooooooooooooooooooooooong}}{}{err}
% \patchcmd{\SL@margtext}{\xdef\SL@labelname{\SL@prlabelname{#1}}}{\xdef\SL@labelname{kooooooooooooooooooooooooooooooong}}{}{err}

% testing patch: overwrite *use* of \SL@prlabelname - has an effect
% \patchcmd{\@eqnnum}{\SL@eqntext{\SL@labelname}}{\SL@eqntext{pooooooooooooooooooooooooooooooong}}{}{err}

% down the road, show the argument being passed. no change with either patch!
\pretocmd{\SL@eqnlrtext}{\edef\test{#1}\meaning\test}{}{err}

\begin{document}
    \begin{equation}
        \label{looooooooooooooooooooooooooooooong}
    \end{equation}
\end{document}

The first line should be fairly obvious, defining the parbox to put the label in. The second is related to my aforementioned question, because I assumed extra curly brackets may be the culprits here (I don't think they are any more). The third simplifies the text in the parbox to make it one single-group argument, see above.

Now, while this whole thing does work outside of an equation environment (different code paths), it does not work within, and I was trying to investigate why. (This is why this MWE is pretty much boiled down to this single case.)

My two optional patches overwrite the definition and the use of \SL@labelname. Interestingly, while overwriting the definition does not work (it works, but has no effect on line breaks), overwriting the use DOES work. Even more interestingly, the last patch further down the road is there to show the value of the argument, and this value does not seem to change between the different patches (at least not in a way that I can see a difference).

5

And. it. worked. Amazing.

\seqsplit iterates through a list of tokens inserting at each step except the last.

so if given looooong then the effective behaviour ignoring expansion order and assignments while constructing the loop is

l\seqinsert o\seqinsert o\seqinsert o\seqinsert o\seqinsert o\seqinsert n\seqinsert g

If the supplied sequence is the single token \kong then \seqsplit does nothing useful as the sequence has length one.

The standard way to solve this problem would be to expand \kong before calling \seqsplit that is

\expandafter\seqsplit\expandafter{\kong}

which if \kong was defined to be looooong would expand in one step to

\seqsplit{looooong}

so produce the same result as the original.

The suggested use of

\seqsplit{\expandafter\kong}

works more or less by chance and is heavily dependent on the specific implementation of the loop.

Simplifying slightly \seqsplit works by looking at the first token, checking it isn't a guard token that marks the end of the input and if it is not it outputs the first token followed by a command \SQSPL@insert that recursively starts looking at the next token.

So in

\seqsplit{\expandafter\kong}

the first token is \expandafter so the first step is

\expandafter\SQSPL@insert\kong

but now this first token instead of just being a character like l expands, so expands the \kong token before the loop recurses so the next step is

\SQSPL@insert looooong

and from this point the iteration proceeds as if the string had been explicit in the input argument.

So the {\expandafter\kong} form only works because the \seqsplit iteration only ever places a single token between the tokens so that the \expandafter expanded \kong, also as it causes \seqinsert to be inserted after the first \expandafter token this means that the end result is not equivalent to the explicit input but rather it is equivalent to

    \seqinsert l\seqinsert o\seqinsert o\seqinsert o\seqinsert o\seqinsert o\seqinsert n\seqinsert g

with an additional \seqinsert at the start. (You can see this by defining \seqinsert to be something visible such as

\def\seqinsert{!}

The default definition is just an \hspace of natural size 0 so this spurious space is not so noticeable but if you did

\def\seqinsert{\ifmmode\allowbreak\else\hspace{20pt plus 0.02em}\fi}

You would see the {\expandafter\kong} version had 10pt spurious indentation.

So to expand an argument before the macro call, the

\expandafter\seqsplit\expandafter{\kong}

form is preferred.

  • 1
    "So to expand ... the \expandafter ... form is preferred." This must be what they call British understatement ... – gernot says Reinstate Monica Feb 17 '17 at 11:37
0

After reducing my MWE to this

\documentclass{article}
\usepackage{seqsplit}
\makeatletter
\newcommand{\myseqsplit}[1]{\expandafter\seqsplit\expandafter{\@firstofone#1}}
\begin{document}
    \seqsplit{loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong}

    \def\kong{loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong}
    \seqsplit{\kong}
\end{document}

I tried \seqsplit{\expandafter\kong}.

And. it. worked. Amazing.

So in my original MWE, this is it:

\patchcmd{\@eqnnum}{\SL@eqntext{\SL@labelname}}{\SL@eqntext{\expandafter\SL@labelname}}{}{err}

If you use amsmath, this may be more complete:

\ifSL@AMS
    \patchcmd{\maketag@@@}{{\df@label}}{{\expandafter\df@label}}{}{err}
    \patchcmd{\maketag@@@}{{\SL@labelname}}{{\expandafter\SL@labelname}}{}{err}
\else
    \patchcmd{\@eqnnum}{{\SL@labelname}}{{\expandafter\SL@labelname}}{}{err}
\fi
  • 3
    Redefining \long is asking to break LaTeX. For example, \newcommand (non-star form) is using it. – Heiko Oberdiek Mar 28 '16 at 18:56
  • Thanks for spotting this. \kong works just as well. – bers Mar 28 '16 at 18:59

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.