![amsmath-重新定义对齐以支持\abovedisplayshortskip 和 \belowdisplayshortskip?](https://linux22.com/image/359990/amsmath-%E9%87%8D%E6%96%B0%E5%AE%9A%E4%B9%89%E5%AF%B9%E9%BD%90%E4%BB%A5%E6%94%AF%E6%8C%81%5Cabovedisplayshortskip%20%E5%92%8C%20%5Cbelowdisplayshortskip%EF%BC%9F.png)
如果环境前只有一小行文本equation
,则会跳过该小行 (\abovedisplayshortskip
并将\belowdisplayshortskip
使用它。
但对于 amsmath 环境,例如align
它只会插入常规的\abovedisplayskip
and \belowdisplayskip
,即使前面的行很短
我们能否重新定义align
和朋友,使它们的行为类似equation
并在适用的情况下自动插入短跳过?
\documentclass{article}
\usepackage{amsmath}
\begin{document}%
If there is just a short line of text before an \verb|equation| environment, then the short skips (\verb|\abovedisplayshortskip| and \verb|\belowdisplayshortskip|) will be used%
\begin{equation}%
a=b
\end{equation}%
But for amsmath environments such as \verb|align| it will only ever insert the regular \verb|\abovedisplayskip| and \verb|\belowdisplayskip|, even if the preceding line is very short
\begin{align}%
a&=b\\
a&=b
\end{align}%
Can we redefine \verb|align| and friends such that they behave similar to \verb|equation| and automatically insert short skips where applicable?\\[\baselineskip]
\begin{tabular}{ll}%
\verb|\abovedisplayshortskip| & \the\abovedisplayshortskip\\
\verb|\abovedisplayskip| & \the\abovedisplayskip\\
\verb|\belowdisplayshortskip| & \the\belowdisplayshortskip\\
\verb|\belowdisplayskip| & \the\belowdisplayskip
\end{tabular}%
\end{document}%
答案1
好的,我做了一个东西。它似乎可以与align
& co 配合使用。我不知道它还会破坏什么其他东西。有什么想法吗?
\documentclass{article}
\usepackage[tbtags]{mathtools}
\usepackage{regexpatch}
\makeatletter
% a new glue to store the amount we need to modify at the end of the display
\newskip\belowdisplayskip@mod
% a new box to store the left-hand side of the first line inside a split environment
\newbox\split@firstline@LHS
% redefine \start@align to incorporate a call to the check whether the preceding line is short enough
\xpatchcmd{\start@align}{%
\collect@body\next@
}{%
\collect@body\next@
\shortskip@check
}{}{\PackageWarningNoLine{methtools}{Failed to patch \protect\start@align}}
% redefine \endalign to correct the belowskip
\xpatchcmd{\endalign}{%
$$%
}{%
$$%
\vskip\belowdisplayskip@mod
\global\belowdisplayskip@mod\z@
\noindent
}{}{\PackageWarningNoLine{methtools}{Failed to patch \protect\endalign}}
% Redefine \intertext@ to correct the belowskip. How we can patch this depends on whether mathtools has been loaded, hence we defer this action until \begin{document}.
\AtBeginDocument{%
\@ifpackageloaded{mathtools}{\MHInternalSyntaxOn}{\makeatletter}%
\xpatchcmd{\intertext@}{%
\penalty\postdisplaypenalty\vskip\belowdisplayskip
}{%
\penalty\postdisplaypenalty\vskip\belowdisplayskip
\vskip\belowdisplayskip@mod
\global\belowdisplayskip@mod\z@
}{}{\PackageWarningNoLine{methtools}{Failed to patch \protect\intertext@}}
\@ifpackageloaded{mathtools}{\MHInternalSyntaxOff}{\makeatother}%
}
% There is some weird behavior if split is used and the "tbtags" option is active. The first line of the split environment seems to be a dummy line set without any width on the left-hand side. Since shortskips need to be determined depending on the width of the first line, many split environments would erroneously be detected as qualifying for shortskips. To work around this we modify \insplit@ to explicitly measure the width of the left-hand side of the first line and further modify \rendsplit@ to insert an empty box of said width.
\xpatchcmd{\insplit@}{% Patching a command containing ## seems to require regexpatch's xpatchcmd.
\ialign\bgroup
\hfil
\strut@
$\m@th\displaystyle{##}$%
}{%
\setbox\split@firstline@LHS\box\voidb@x
\ialign\bgroup
\hfil
\strut@
\setbox\@tempboxa\hbox{$\m@th\displaystyle{##}$}\unhcopy\@tempboxa
\ifvoid\split@firstline@LHS
\global\setbox\split@firstline@LHS\box\@tempboxa
\fi
}{}{\PackageWarningNoLine{methtools}{Failed to patch \protect\insplit@}}
\xpatchcmd{\rendsplit@}{%
\global\@tempcnta\column@
}{%
\global\@tempcnta\column@
\hbox to\wd\split@firstline@LHS{}%
}{}{\PackageWarningNoLine{methtools}{Failed to patch \protect\rendsplit@}}
% check whether shortskips should be used; if yes, immediately account for the aboveskip and save belowskip for later
\def\shortskip@check{%
\ifmeasuring@\else
\noalign{\shortskip@calc@shift@lc}%
\ifdim\dimexpr\eqnshift@+\@tempdimb\relax > \predisplaysize
\noalign{\vskip\glueexpr\abovedisplayshortskip-\abovedisplayskip\relax}%
\noalign{\global\belowdisplayskip@mod=\glueexpr\belowdisplayshortskip-\belowdisplayskip\relax}%
\fi
\fi
}
% first helper function to calculate how much the first equation row is indented. amsmath documentation:
% \cs{@tempdimb} will be the ``indentation'' of leftmost end of
% text, ignoring the \cs{tabskip} glue, i.e., it will be the sum of
% the maximum widths of any fields to the left of the first
% non-empty field, plus whatever empty space there is at the
% beginning of the first non-empty field.
\def\shortskip@calc@shift@lc{% based on amsmath \x@calc@shift@lc
\row@\@ne
\column@\z@
\@tempdima\z@
\@tempdimb\z@
\edef\@tempb{\fieldlengths@\row@}%
\@for\@tempa:=\@tempb\do{%
\advance\column@\@ne
\shortskip@lcalc@width
}%
}
% second helper function to calculate how much the first equation row is indented. amsmath documentation:
% This macro calculates the ``indentation'' of the current row, as
% defined above under the description of \cs{x@calc@shift@lc}.
% This macro is called for each field of the current line, with
% \cs{@tempa} set to the width of the current field. Ideally, the
% loop enclosing \cs{x@lcalc@width} would terminate as soon as
% \cs{@tempa} is non-zero, but that would be a bit tricky to
% arrange. Instead, we use \cs{@tempdima} as a flag to signal when
% we've encountered the first non-empty field.
\def\shortskip@lcalc@width{% based on amsmath \x@lcalc@width
\ifdim\@tempdima = \z@
\ifdim\@tempa > \z@
\@tempdima\p@
\ifodd\column@
\advance\@tempdimb \maxcol@width\column@
\global\advance\@tempdimb-\@tempa
\fi
\count@\column@
\advance\count@\m@ne
\divide\count@\tw@
\advance\@tempcnta-\count@
\advance\@tempcntb-\count@
\else
\global\advance\@tempdimb \maxcol@width\column@\relax
\fi
\fi
}
\makeatother
\begin{document}%
If there is just a short line of text before an \verb|equation| environment, then the short skips (\verb|\abovedisplayshortskip| and \verb|\belowdisplayshortskip|) will be used%
\begin{equation}%
a=b
\end{equation}%
My modifed \verb|align| will now also insert short skips if the preceding line is short enough, such as in this example%
\begin{align}%
a&=b\\
a&=b
\end{align}%
It should depend only on the first equation; here shortskips are used:\\short%
\begin{align}%
a&=b\\
aaaaaaaaaaaaaaaaaaaaaaa&=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
\end{align}%
but not here, since the first equation is too close to the text (less than 2em):\\regular%
\begin{align}%
a&=b\\
a&=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
\end{align}%
It should also work with multiple columns\\short%
\begin{align}%
a&=b & a&=b & a&=b\\
aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb
\end{align}%
It should also work with multiple columns, now the other way round\\regular%
\begin{align}%
aaaaaa&=bbbbbbb & a&=b & a&=b\\
a&=b & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb
\end{align}%
Let's see what happens if the first entry in the first column is empty\\short%
\begin{align}%
& & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb\\
aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb
\end{align}%
%
\newpage\noindent
%
It has also redefined the friends such has \verb|align*|\\short%
\begin{align*}%
a&=b & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb\\
aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb
\end{align*}%
It has also redefined the friends such has \verb|align*|\\regular%
\begin{align*}%
aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb\\
a&=b & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb
\end{align*}%
What about \verb|alignat|? Seems to work as well\\short%
\begin{alignat}{3}%
aaaaaa&=bbbbbbb &\quad aaaaaa&=bbbbbbb &\quad aaaaaa&=bbbbbbb\\
aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb
\end{alignat}%
What about \verb|alignat|? Seems to work as well\\regular%
\begin{alignat}{3}%
aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb\\
aaaaaa&=bbbbbbb &\qquad aaaaaa&=bbbbbbb &\qquad aaaaaa&=bbbbbbb
\end{alignat}%
There's also \verb|flalign|. Even that one can become short if first entry is missing\\short%
\begin{flalign}%
& & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb\\
aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb & aaaaaa&=bbbbbbb
\end{flalign}%
It works. Yay. What do you think?\\[\baselineskip]
\begin{tabular}{@{}ll}%
\verb|\abovedisplayshortskip| & \the\abovedisplayshortskip\\
\verb|\abovedisplayskip| & \the\abovedisplayskip\\
\verb|\belowdisplayshortskip| & \the\belowdisplayshortskip\\
\verb|\belowdisplayskip| & \the\belowdisplayskip
\end{tabular}%
%
\newpage\noindent
%
Now let's use \verb|split| inside \verb|align|, where the preceding line is\\short%
\begin{align}%
\begin{split}%
aaaaaaaaaaa&=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\\
&=ddddddddddddddddddddddddddddddddddd
\end{split}%
\end{align}%
Now let's use \verb|split| inside \verb|align|, where the preceding line is\\not so short%
\begin{align}%
\begin{split}%
aaaaaaaaaaa&=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\\
&=ddddddddddddddddddddddddddddddddddd
\end{split}%
\end{align}%
Now let's use \verb|split| inside \verb|align|, but switch it around\\still short enough%
\begin{align}%
\begin{split}%
&=ddddddddddddddddddddddddddddddddddd\\
aaaaaaaaaaa&=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
\end{split}%
\end{align}%
It works. Yay. What do you think?
\end{document}%
答案2
据我所知,没有自动解决方案,但您可以使用\useshortskip
中的命令nccmath
。但是,它只会替换\abovedisplayskip
,\abovedisplayshortskip
而不会替换
\belowdisplayskip
。如果您愿意,您可以修补nccmath
,更准确地说是\NCC@ignorepar
命令
当然,人们也可以添加一个对两个跳过都进行操作的nccmath
新\useshortskips
命令并保持原样\useshortskip
,但我不确定这是否值得付出努力。
\documentclass{article}
\usepackage{amsmath, nccmath}
\usepackage{xpatch}
\makeatletter
\xpatchcmd{\NCC@ignorepar}{%
\global}{%
\belowdisplayskip\belowdisplayshortskip
\global}{}{}
\makeatother
\begin{document}%
If there is just a short line of text before an \verb|equation| environment, then the short skips (\verb|\abovedisplayshortskip| and \verb|\belowdisplayshortskip|) will be used%
\begin{equation}%
a=b
\end{equation}%
But for amsmath environments such as \verb|align| it will only ever insert the regular \verb|\abovedisplayskip| and \verb|\belowdisplayskip|, even if the preceding line is very short
\begin{align}%
a&=b\\
a&=b
\end{align}%
Can we redefine \verb|align| and friends such that they behave similar to \verb|equation| and automatically insert short skips where applicable?\\[\baselineskip]
\begin{tabular}{ll}%
\verb|\abovedisplayshortskip| & \the\abovedisplayshortskip\\
\verb|\abovedisplayskip| & \the\abovedisplayskip\\
\verb|\belowdisplayshortskip| & \the\belowdisplayshortskip\\
\verb|\belowdisplayskip| & \the\belowdisplayskip
\end{tabular}%
But for amsmath environments such as \verb|align| it will only ever insert the regular \verb|\abovedisplayskip| and \verb|\belowdisplayskip|, even if the preceding line is very short\useshortskip
\begin{align}%
a&=b\\
a&=b
\end{align}%
Can we redefine \verb|align| and friends such that they behave similar to \verb|equation| and automatically insert short skips where applicable?
\end{document}%