TeX - LaTeX Asked by Lawrence Wong on April 24, 2021
Here is a minimal example of what I want to do.
documentclass{article}
usepackage{amsmath}
makeatletter
newcommand{mylinebreak}{@ifstar@mylinebreak@@mylinebreak}
newcommand{@mylinebreak}{&}
newcommand{@@mylinebreak}{&&}
%letmylinebreak@@mylinebreak
makeatother
begin{document}
begin{align*}
a&=bmylinebreak
&=c.
end{align*}
end{document}
This gives the error message
! Misplaced alignment tab character &.
@@mylinebreak ->&
&
l.16 end{align*}
What is wrong? How can I get this to work?
Curiously, I get no error message if I remove the %
or if I use mylinebreak*
instead.
I am guessing that the problem can be solved using the tricks involving master/balance counters, but I could not make this work.
You are defining
to look ahead for a *
(incidentally the standard command already looks ahead for a *
) but in doing this it "sees" the &
and the next cell starts before the previous row is ended by inserting the original
The definition in amsmath
is
defmath@cr{relaxiffalse{fiifnum0=`}fi
@ifstar{global@eqpen@Mmath@cr@}%
{global@eqpen
ifnumdspbrk@lvl <z@ interdisplaylinepenalty
else -@getpendspbrk@lvl fi
math@cr@}}
defmath@cr@{new@ifnextchar[math@cr@@{math@cr@@[z@]}}
defmath@cr@@[#1]{ifnum0=`{fi iffalse}fimath@cr@@@
noalign{vskip#1relax}}
The special relaxiffalse{fiifnum0=`}fi
is designed to avoid this issue by preventing the halign template ending a cell at this point.
Note that it is already using @ifstar
to define *
to prevent a page break at this point.
It is not clear what is the intention of using &
as the behaviour of that construct is the same as
as the empty cells do not do anything in almost all circumstances.
Correct answer by David Carlisle on April 24, 2021
Simple solution: use a more robust check for the *-variant.
documentclass{article}
usepackage{amsmath}
NewDocumentCommand{mylinebreak}{s}{%
IfBooleanTF{#1}{&x}{&x&=y}%
}
begin{document}
begin{align*}
a&=bmylinebreak
&=c.
a&=bmylinebreak*
&=c.
end{align*}
end{document}
I added something in order to better see that the choices are made correctly.
If you're running a version of LaTeX prior to the 2020-10-01 release, you also need usepackage{xparse}
.
Let's see what happens: mylinebreak
becomes
@ifstar@mylinebreak@@mylinebreak
According to the definition of @ifstar
by amsmath
def@ifstar#1#2{new@ifnextchar *{defreserved@a*{#1}reserved@a}{#2}}
the above becomes
new@ifnextchar*{defreserved@a{@mylinebreak}reserved@a}{@@mylinebreak}
Let's see what new@ifnextchar
does:
longdefnew@ifnextchar#1#2#3{%
letreserved@d= #1%
defreserved@a{#2}defreserved@b{#3}%
futurelet@let@tokennew@ifnch
}
so the expansions continues as (newlines just for reading convenience)
letreserved@d= *
defreserved@a{defreserved@a*{@mylinebreak}reserved@a}
defreserved@b{@@mylinebreak}
futurelet@let@tokennew@ifnch &
The trailing &
comes from the fact that the newline after mylinebreak
is ignored during tokenization. Unfortunately, we're in an alignment, so as soon as TeX scans &
, it inserts the v part of the template. And, indeed, the error message with a high value of errorcontextlines
reads
! Misplaced alignment tab character &.
@@mylinebreak ->&
&
<to be read again>
}
<template> }
$}ifmeasuring@ savefieldlength@ fi set@field hfil endtempl...
<argument> a&=bmylinebreak &
=c.
and @let@token
is set to }
. This is confirmed by injecting show@let@token
at the beginning of new@ifnch
:
@let@token=end-group character }
OK, let's go a step forward: the expansion of new@ifnch
yields
ifx@let@tokenreserved@dletreserved@breserved@afireserved@b
In our case, the ifx
test returns false, so we remain with
reserved@b}&
and this breaks, because reserved@b
becomes @@mylinebreak
.
Answered by egreg on April 24, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP