Closed dbitouze closed 1 week ago
Not claiming I understand the issue here yet, but it looks as if it has to do with the way \NewDocumentCommand
is doing the parsing, if you use \newcommand\foo[1][]{x}
instead it does through, so I suspect it has to do with how this tries to be align-safe (and that doesn't quite work if it happens as part of the array preamble code).
@josephwright / @davidcarlisle can you perhaps take a look?
I can look, no promises though, as I said in the original issue it's a tricky area:-)
Technically, it might be enough if we put a \relax
at the end of the preamble tokens so that scanning is stopped, i.e., before the \ignorespaces
but I would like really to understand first what is going on and for now I don't
You can't scan the end template while inside the "safe" group, this works forcing the endtemplate to be seen earlier, but the trailing optional argument can not easily be used even then as there is a lot of backage to lose before the [
at the start of the content is seen.
Given that the optional argument can't easily work, I'm not sure we should try too hard to avoid the error.
\documentclass{article}
\NewDocumentCommand\foo{O{default}}{x with #1}
\usepackage{array}
\begin{document}
%\begin{tabular}{>{\foo}l}
\begin{tabular}{>{\expandafter\foo}l}
Foo\\[0pt]
[option]Foo2
\end{tabular}
\end{document}
What I don't quote comprehend right now is why it hits \endtemplate
during parsing for [
and not the content of the cell and then stop at the F
there. What am I not seeing here?
hmm I tried to make an \halign
example but failed so it's not quite as I thought, will repost something later
It can be fixed using collcell
(I know, not really a solution, but a valid workaround):
\documentclass{article}
\NewDocumentCommand\foo{O{default}}{x with #1}
\NewDocumentCommand\fooAux{m}{\foo#1}
\usepackage{array,collcell}
\begin{document}
\begin{tabular}{>{\collectcell\fooAux}l<{\endcollectcell}}
Foo\\[0pt]
[option]Foo2
\end{tabular}
\end{document}
@Skillmon that moves the execution of \foo
into the cell body where it doesn't hit \endtemplate
. But a far simpler workaround is >{\foo\relax}
.
@FrankMittelbach the difference is that @Skillmon's version actually allows the optional argument (if the cell content starts [option]
whereas \relax
avoids the error but also ensures the option is never taken. ( as would the \ignorespaces
that normally follows the >{...}
tokens actually). So it depends what we think should happen
well I don't think supporting that directly makes much sense (it is not as if we support picking up any data through an argument of a command placed at the end of >{...}
so why doing that for an optional arg? So I'm for putting \relax
in front of \ignorespaces
and be done with it.
OK with me (and it works) but now I'm confused, \ignorespaces
is a non expandable primitive so why doesn't it stop any lookahead in the same way as \relax
OK with me (and it works) but now I'm confused,
\ignorespaces
is a non expandable primitive so why doesn't it stop any lookahead in the same way as\relax
\ignorespaces
is part of the template, and one has to be careful with that.
A couple of notes:
&
at all is that it allows [...&...]
- see https://github.com/latex3/latex3/issues/839siunitx
, where I have to manually pick up \ignorespaces
when looking aheadsiunitx
's S
-column would simply take a mandatory argument - and I suggest that's the better steer here - 'don't use ending optional args in tabular preambles'OK with me (and it works) but now I'm confused,
\ignorespaces
is a non expandable primitive so why doesn't it stop any lookahead in the same way as\relax
\ignorespaces
is part of the template, and one has to be careful with that.
Yes but adding relax to the preamble just before the ignorespaces prevents the lookahead hitting the endtemplate but current I don't see why.
OK with me (and it works) but now I'm confused,
\ignorespaces
is a non expandable primitive so why doesn't it stop any lookahead in the same way as\relax
\ignorespaces
is part of the template, and one has to be careful with that.Yes but adding relax to the preamble just before the ignorespaces prevents the lookahead hitting the endtemplate but current I don't see why.
It stops the look ahead picking up anything from the template, that's the point: if you hit the \ignorespaces
you have to handle differently (again, see inside siunitx
...)
@josephwright I think you are describing >{\foo\relax]
that is the easy case, my question was why adding \relax
to the template stops lookahead when \ignorespaces
does not.
as it is, eventually you end up at
~...\@xarraycr ->\@ifnextchar [\@argarraycr {\ifnum 0=`{}\fi \cr }
but the \cr
triggers the end cell template and you get as next step
~...\@ifnextchar #1#2#3->\let \reserved@d =#1\def \reserved@a {#2}\def \reserve
d@b {#3}\futurelet \@let@token \@ifnch
#1<-[
#2<-\@argarraycr
Runaway argument?
{\ifnum 0=`{}\fi \textonly@unskip \relax \UseTaggingSocket {tbl/cell/\ETC.
! Forbidden control sequence found while scanning use of \@ifnextchar.
<inserted text>
\par
<to be read again>
\endtemplate
but with \relax
you have one extra layer of safe group protection and the \cr
does not fire and the next step is
~...\@ifnextchar #1#2#3->\let \reserved@d =#1\def \reserved@a {#2}\def \reserve
d@b {#3}\futurelet \@let@token \@ifnch
#1<-[
#2<-\@argarraycr
#3<-\ifnum 0=`{}\fi \cr
{\let}
ah, the diff is
$ diff array.sty~ array.sty
99c99
< \the@toks \the \@tempcnta
---
> \the@toks \the \@tempcnta\relax
so I don't think it is \relax
before \ignorespaces
so much as \relax
after \the \@tempcnta
which is reducing the lookahead.
3. and I suggest that's the better steer here - 'don't use ending optional args in tabular preambles'
But what about commands whose final argument is an optional one, used without an optional argument as their final argument one, just as \fontspec{⟨font⟩}[⟨font features⟩]?
See e.g. https://github.com/latex3/tagging-project/issues/707.
- and I suggest that's the better steer here - 'don't use ending optional args in tabular preambles'
But what about commands whose final argument is an optional one, used without an optional argument as their final argument one, just as
\fontspec{⟨font⟩}[⟨font features⟩]?
See e.g. latex3/tagging-project#707.
Doesn't change what I said, really
- and I suggest that's the better steer here - 'don't use ending optional args in tabular preambles'
But what about commands whose final argument is an optional one, used without an optional argument as their final argument one, just as
\fontspec{⟨font⟩}[⟨font features⟩]?
See e.g. latex3/tagging-project#707.
they will work after the change. try adding \relax
on line 99 of array.sty as in the above diff
@dbitouze or rather than modify the package, after loading array do
\makeatletter
\def\insert@column{%
\UseTaggingSocket{tbl/cell/begin}%
\the@toks \the \@tempcnta\relax
\ignorespaces \@sharp \textonly@unskip
\the@toks \the \count@ \relax
\UseTaggingSocket{tbl/cell/end}%
}
\makeatother
@davidcarlisle and probably something similar for \insert@pcolumn
?
@u-fischer ooh probably, yes
I made the PR already last night but didn't upload yet
That change (adding \relax
) breaks collcell
(just pointing it out). Well, breaking is not really correct, collcell
now "just" needs to strip the extra \relax
, still requires a change by collcell
.
@Skillmon hmm
\def\insert@column{%
\UseTaggingSocket{tbl/cell/begin}%
\the@toks \the \@tempcnta
\ignorespaces\space \@sharp \textonly@unskip
\the@toks \the \count@ \relax
\UseTaggingSocket{tbl/cell/end}%
}
?
That change (adding \relax) breaks collcell (just pointing it out)
@Skillmon Do you have an example? For me it still seems to work fine.
@u-fischer just take a look at the contents, it starts with the \relax
that was injected. So it doesn't outright break, but depending on what you intend to do with it, it might break a document.
@Skillmon I need to sort a patch for collcell
to send to Martin - I could cover as part of that
@josephwright yes, I think that would be great (sorry I didn't make it, didn't find the time yesterday evening -- not because I was busy or something just got distracted)
Brief outline of the bug
Commands with optional argument as last argument cannot be used in argument of
array
's>{...}
Minimal example showing the bug
Log file (required) and possibly PDF file