Skip to content

suggestion: sign in \belowdisplayskip #809

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
nbeisert opened this issue Mar 5, 2025 · 13 comments
Open

suggestion: sign in \belowdisplayskip #809

nbeisert opened this issue Mar 5, 2025 · 13 comments
Assignees
Labels
area: math enhancement New feature or request or otherwise some possible improvement fixed in release issue is fixed and will be deployed in the next release of package or kernel
Milestone

Comments

@nbeisert
Copy link

nbeisert commented Mar 5, 2025

I would like to modify \belowdisplayskip within a math environment (for example, reduce it upon specifying an optional parameter to some math environment). This change works well in TeX at the level of the $$ group. However, the tagging support changes the meaning of \belowdisplayskip including its short variant by flipping the sign. This breaks the functioning of such a math environment (or requires dedicated handling).

May I propose a change of the sign flip mechanism as follows:

Rather than flipping the sign in \everydisplay:
https://github.com/latex3/latex2e/blob/ad660baa99c8691ce723efe0b9193e2b8f69a33f/required/latex-lab/latex-lab-math.dtx#L2641
perform the flip in \@@_tag_dollardollar_display_end:
https://github.com/latex3/latex2e/blob/ad660baa99c8691ce723efe0b9193e2b8f69a33f/required/latex-lab/latex-lab-math.dtx#L2094

This should have the same effect if \belowdisplayskip is left untouched by the body of $$. But if it is indeed changed in the body of $$, the new processing location would capture the change. That way the sign flip mechanism will not be exposed to the user / package author. It would also reduce side effects such as display within display flipping the sign twice. Same suggestion for \postdisplaypenalty which could be saved and implemented manually after closing $$.

A corresponding sign in amsmath would have to be flipped, too:
https://github.com/latex3/latex2e/blob/63d6757d237d1058883b84395b64479fe8a0fd2c/required/latex-lab/latex-lab-amsmath.dtx#L965
grep shows a few other appearances of \belowdisplayskip within latex-lab, but only within testfiles.

Further suggestion (towards permitting negative values for \belowdisplayskip): Within \@@_tag_dollardollar_display_end: the values of \belowdisplayskip and \belowdisplayshortskip could be globally saved, set to dedicated values like 0pt and -1pt, and after retrieving which of the two skips had been used, the appropriate original skip can be implemented.

Thanks for considering.

@nbeisert
Copy link
Author

nbeisert commented Mar 5, 2025

Ah, I'm sorry, that suggestion was too naive because \aftergroup inserts \@@_tag_dollardollar_display_end: after the $$ group has been closed and the math body has been committed to the (main) vertical list.

Nevertheless, the issue persists. I don't know what is the right behaviour for a contributed package? Set the value of \belowdisplayskip as negative could be done of course, but it does not feel right as the behaviour might still change later? Some interface perhaps? Maybe better to keep the package ignorant of the issue for the time being until a clear solution exists?

@FrankMittelbach
Copy link
Member

The idea is good and yes it would be better if the sign-flipping is hidden. Not that I'm keen on proposing that as a document interface but it was possible in the past so ... A probably better interface is to offer such local parameter settings through a standard first optional key/value argument that should be available anyway (eventually) like with the lists.

Anway, your suggestion has to happen in \@@_grab_dollardollar:w just before the closing $$.

If you want to do me a favor, write up a test file that exhibits the desired results (or rather doesn't exhibits it if not resolved).

@FrankMittelbach FrankMittelbach self-assigned this Mar 5, 2025
@FrankMittelbach FrankMittelbach added enhancement New feature or request or otherwise some possible improvement area: math labels Mar 5, 2025
@nbeisert
Copy link
Author

nbeisert commented Mar 6, 2025

Ah, very nice! I did not recognise how \@@_grab_dollardollar:w was called. Here's some code that demonstrates a simple patch that hides the sign flip. \iffalse exposes undesired behaviour when testphase is active; works well with \iftrue and lualatex-dev and various possible entries into $$:

\DocumentMetadata{testphase=latest} % use tagging
\documentclass{article}
\usepackage[a4paper,margin=0cm]{geometry}

\ExplSyntaxOn
\iftrue % patch

\tag_if_active:T {

\let\__math_grab_dollardollar:w=\undefined

\cs_new_protected:Npn \__math_grab_dollardollar:w % $$
  #1 $$
  {
    \tl_if_blank:nF {#1}
      {
        \__math_process:nn { equation* } {#1}
        \tag_socket_use:n {math/display/begin}
        \tag_socket_use:nn{math/display/formula/begin}{}{#1}
      }
      \skip_set:Nn \belowdisplayskip      {-\belowdisplayskip}
      \skip_set:Nn \belowdisplayshortskip {-\belowdisplayshortskip}
    $$
  }

% rather remove sign flipping code from \exp_args:No \tex_everymath:D instead
\everydisplay
  {
     \belowdisplayskip-\belowdisplayskip
     \belowdisplayshortskip-\belowdisplayshortskip
  }

}

\fi
\ExplSyntaxOff

\begin{document}

\newdimen\predepth
\def\test#1#2{\newpage
XXXXX before: \the\belowdisplayskip\ \the\belowdisplayshortskip
\par#2\predepth\ifvmode\prevdepth\else\maxdimen\fi
$$\textrm{pre:\ \the\predepth\ \the\predisplaysize}\quad
\textrm{entry:\ \the\belowdisplayskip\ \the\belowdisplayshortskip}\quad
\belowdisplayskip30pt\belowdisplayshortskip20pt
\textrm{exit:\ \the\belowdisplayskip\ \the\belowdisplayshortskip}\quad
$$XXXXX after: \the\belowdisplayskip\ \the\belowdisplayshortskip\par #1}

\parskip150pt
\parindent0pt
\abovedisplayshortskip0pt
\belowdisplayshortskip0pt
\abovedisplayskip50pt
\belowdisplayskip50pt

\test{vmode empty}{\nointerlineskip}
\test{vmode filled}{}
\test{hmode empty}{\noindent}
\test{hmode short}{X}
\test{hmode long}{\hspace{0.5\textwidth}X\noindent}

\end{document}

tagbugsign.pdf

@FrankMittelbach
Copy link
Member

\let__math_grab_dollardollar:w=\undefined

\cs_new_protected:Npn __math_grab_dollardollar:w % $$

Not relevant to the problem at hand but this should be done with \cs_set_protect:Npn then the first line is not necessary (which is not very L3 prog layer anyway :-) that would be \cs_set_eq:NN ...

@FrankMittelbach
Copy link
Member

Second remark:

\newdimen\predepth

that's a very bad idea. This is a primitive and you overwrite this way (plain TeX \newdimen doesn't warn) and so you basically break LaTeX as \prevdepth is needed, even though in this doesn't show in the particular example (probably).

@davidcarlisle
Copy link
Member

Second remark:

\newdimen\predepth

that's a very bad idea. This is a primitive and you overwrite this way (plain TeX \newdimen doesn't warn) and so you basically break LaTeX as \prevdepth is needed, even though in this doesn't show in the particular example (probably).

@FrankMittelbach this is defining predepth not preVdepth

@nbeisert
Copy link
Author

nbeisert commented Mar 6, 2025

@FrankMittelbach Fully agree. This was merely a simple-minded patch to demonstrate that moving the two lines \skip_set:Nn \belowdisplayskip {-\belowdisplayskip} etc in the sketched way will hide the mechanism from the user: quick and dirty paired with my limited writing capabilities in L3. One patch adds the flip to \__math_grab_dollardollar:w and the other doubles the flip in \everydisplay. Of course, in the actual code, I'd just move the two lines from place A to B which would remove the most evident issue. And perhaps extend it by the other mechanisms indicated above (but again, I'm not yet in L3 land). The remainder of the code shows 5 different ways to enter $$ and they all come out fine (that was not the point, but I still wanted to convince myself).

@FrankMittelbach
Copy link
Member

@FrankMittelbach this is defining predepth not preVdepth

so it does. Tomatos on the eyes as we say in German

@FrankMittelbach
Copy link
Member

The situation as such is more complicated, unfortunately. Changing \__math_grab_dollardollar:w only handles the $$...$$ when the formula inside the double dollars is actually grabbed. However, normally the $$ happens in the depth of the math environments (after the grabbing stage) and while the use of \everydisplay applies to those $$s, no sign flipping happens if only the grabber tries to inject something near the end of the math display.

This means that one has to change every place where $$ ends a formula (or ends a speudo formula containing only an \halign). Probably doable but not really pretty.

@nbeisert
Copy link
Author

nbeisert commented Mar 7, 2025

looks dire... so $$ is processed deep down in TeX and it only interacts via \enddisplay (inside the group) and \aftergroup (but after the group)?!
Another related issue seems to be that \endmathdisplay@a changes \postdisplaypenalty (when \displaybreak is issued within equation) which should remain fixed to 10000. That change should be caught before $$ ends (but could be done by altering the behaviour in latex-lab-amsmath to deliver \postdisplaypenalty in some other way to \__math_tag_dollardollar_display_end:).

@nbeisert
Copy link
Author

nbeisert commented Mar 7, 2025

Here's a different approach that captures a display equation in a vbox (edited to remove all traces as far as I can see):

\documentclass{article}
\usepackage[a4paper,margin=1cm]{geometry}
\makeatletter
\begin{document}

\newdimen\para
\newdimen\parb
\newdimen\parc

\def\ddcapture{%
  \ialign{##\cr\noalign{%
    \global\parb\prevdepth
    \prevdepth-\@m\p@
  }}%
  \global\para\predisplaysize
  \abovedisplayskip\z@skip
  \belowdisplayskip\z@skip
  \predisplaypenalty\@M
  \postdisplaypenalty\@M
  $$%
  \par
  \setbox\z@\vbox\bgroup
    \everydisplay{}%
    \prevdepth\parb
    \noindent
    $$%
    \predisplaysize\para
    \aftergroup\after
}

\def\after{%
    \par
    \global\parc\prevdepth
  \egroup 
  \unvbox\z@
  \prevdepth\parc
  \vskip-\parskip
  \noindent
}

\def\tsep{\par Ag\hrule Ag\par}

\long\def\test{%
\abovedisplayskip12pt
\belowdisplayskip10.2pt
\abovedisplayshortskip2.4pt
\belowdisplayshortskip9pt
\parskip1pt
\lineskip6.5pt
\lineskiplimit1pt
\relax
\hrule
Ag
$$ \textrm{equation} $$ \tsep
$$ \textrm{AAAA} $$ \tsep
$$ x+z $$ \tsep
$$ \frac{A}{B} $$ \tsep
$$ \halign{##\cr table\cr halign\cr} $$ \tsep
abcg $$ \textrm{equation} $$ \tsep
abcgabcabcabcabc $$ \textrm{equation} $$ \tsep
\noindent $$ \textrm{equation} $$ \tsep
$$ \textrm{equation} $$ \tsep
\nointerlineskip $$ \textrm{equation} $$ \tsep
$$ \textrm{equation} $$ after \tsep
}

\noindent
\parbox[t]{0.5\textwidth}{%
without capture:\par \test\par end}%
\parbox[t]{0.5\textwidth}{%
with capture:\everydisplay{\ddcapture}\par \test\par end}

\end{document}

Now the ending can be adjusted before releasing the contents of the vbox to the encapsulating vmode. I'm not sure whether a boxed display equation is fully equivalent, so you may consider this for your entertainment only. :-)

Alternatively, one could handle $$ manually upon a specific request. E.g. socket calls to be made when entering and leaving display mode. There will not be too many packages which want to change the parameters within a bare $$ structure.

In fact, is a tagged align structure allowed to break pages (cf. \allowdisplaybreaks)? I recall that the sign flip was related to avoiding page breaks while handling the tagging structures.

@github-project-automation github-project-automation bot moved this to Pool (unscheduled issues) in upcoming LaTeX2e releases Mar 9, 2025
@FrankMittelbach FrankMittelbach moved this from Pool (unscheduled issues) to Done in dev in upcoming LaTeX2e releases Mar 9, 2025
@FrankMittelbach FrankMittelbach added this to the 2025 Q2 milestone Mar 9, 2025
@FrankMittelbach FrankMittelbach added fixed in branch fixed in a branch different to develop fixed in release issue is fixed and will be deployed in the next release of package or kernel and removed fixed in branch fixed in a branch different to develop labels Mar 9, 2025
@nbeisert
Copy link
Author

Thanks for the fix, looking forward to it. So to make things work, do I understand correctly that one should use \dollardollar@begin and \dollardollar@end instead of $$ starting from next kernel release?

For completeness, here is some replacement code for \tex_everydisplay:D and \__math_tag_dollardollar_display_end: (based on the old implementation) that avoids flipping the sign of \belowdisplayskip altogether. Of course, several edits would still be needed for proper code; this is intended for demonstration only:

\newdimen\orgprevdepth
\newdimen\orgdisplaywidth
\newdimen\orgdisplayindent
\newdimen\orgpredisplaysize
\newcount\orgprevgraf
\newskip\orgskip
\newcount\orgpenalty

\exp_args:No \tex_everydisplay:D
  {
  \ialign
  {
    #\cr
    \noalign
    {
      \dim_gset:Nn \orgprevdepth \prevdepth
      \nointerlineskip
    }
  }
  \skip_set:Nn \abovedisplayskip {0pt}
  \skip_set:Nn \belowdisplayskip {0pt}
  \int_set:Nn \predisplaypenalty {10000}
  \int_set:Nn \postdisplaypenalty {10000}
  \dim_gset:Nn \orgdisplaywidth \displaywidth
  \dim_gset:Nn \orgdisplayindent \displayindent
  \dim_gset:Nn \orgpredisplaysize \predisplaysize
  \int_gset:Nn \orgprevgraf \prevgraf
  $$
  \par
  \ifinner
    \tex_unskip:D
    \tex_unpenalty:D
    \tex_unskip:D
    \tex_unpenalty:D
  \fi
  \setbox0\vbox\bgroup
    \tex_everydisplay:D{}
    \dim_set:Nn \prevdepth \orgprevdepth
    \tex_noindent:D
    $$
    \dim_set:Nn \displaywidth\orgdisplaywidth
    \dim_set:Nn \displayindent\orgdisplayindent
    \dim_set:Nn \predisplaysize\orgpredisplaysize
    \int_set:Nn \prevgraf\orgprevgraf
    \tex_the:D \tex_everydisplay:D
    \tex_everydisplay:D{ \tex_the:D \tex_everydisplay:D }
    \group_insert_after:N \__math_tag_dollardollar_display_end:
    \bool_if:NF \l__math_collected_bool
      {
        \bool_set_true:N \l__math_collected_bool
        \__math_grab_dollardollar:w
      }
  }

\cs_new_protected:Npn \__math_tag_dollardollar_display_end:
  {
    %  \typeout{== tag dollarldollar display end}
    %  \ShowTagging{struct-stack}
      \para_raw_end:
      \dim_gset:Nn \orgprevdepth \prevdepth
      \int_gset:Nn \orgprevgraf \prevgraf
      \skip_gset:Nn \orgskip \lastskip
      \tex_unskip:D
      \int_gset:Nn \orgpenalty \lastpenalty
      \tex_unpenalty:D
      \tag_socket_use:n{math/display/formula/end}
    \egroup
    \unvbox0\relax
    \penalty \orgpenalty
    \skip_vertical:n { \orgskip }
    \dim_set:Nn \prevdepth \orgprevdepth
%% this would enter horizontal mode properly, but does not work as such:
%    \begingroup
%      \tex_nobreak:D
%      \skip_set:Nn \parskip {0pt}
%      \tex_noindent:D
%      \int_set:Nn \prevgraf \orgprevgraf
%    \endgroup
%    \ignorespaces
%% instead:
    \skip_vertical:n { -\tex_parskip:D }
    \@domathendpetrue
    \@doendpe             % this has no \end{...} to take care of it
}

As far as I can see, this preserves all spacing and avoids a potential error message for display equations ending where a page breaks. It works fine with a few basic examples in amsmath, but may have adverse side-effects that I'm not aware of.

Anyway, thanks for fixing.

@FrankMittelbach
Copy link
Member

Thanks for the fix, looking forward to it. So to make things work, do I understand correctly that one should use \dollardollar@begin and \dollardollar@end instead of $$ starting from next kernel release?

yes, together with \providecommand for them so that the code also works with older kernels that do not contain the commands (if that is necessary/wanted).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: math enhancement New feature or request or otherwise some possible improvement fixed in release issue is fixed and will be deployed in the next release of package or kernel
Projects
Status: Done in dev
Development

No branches or pull requests

3 participants