latex3 / latex2e

The LaTeX2e kernel
https://www.latex-project.org/
LaTeX Project Public License v1.3c
1.82k stars 251 forks source link

longtable : provide a non breakable \hline #1389

Open chrisaga opened 2 weeks ago

chrisaga commented 2 weeks ago

Brief outline of the enhancement

Provide a version of \hline which don't allow page breaks since ending a table row with \\* is useless when followed by \hline. For consistency this new version of \hline could be named \hline*.

Minimal example showing the current behaviour

\RequirePackage{latexbug}       % <--should be always the first line (see CONTRIBUTING)!
\documentclass{article}
\usepackage{longtable}

\begin{document}
  \begin{longtable}{@{*}r||p{1in}@{*}}
    Some & text \\
    Page break not & allowed after this line \\*
    Some & text \\
    Suppose we don't want a break & but need a line \\* % this won't work
    \hline                                              % because \hline allows a page break
    Some & text \\
  \end{longtable}

\end{document}

Minimal example showing the desired new behaviour

\RequirePackage{latexbug}       % <--should be always the first line (see CONTRIBUTING)!
\documentclass{article}
\usepackage{longtable}

\begin{document}
  \begin{longtable}{@{*}r||p{1in}@{*}}
    Some & text \\
    Page break not & allowed after this line \\*
    Some & text \\
    Suppose we don't want a break & but need a line \\
    \hline*                     % the new \hline* does this
    Some & text \\
  \end{longtable}

\end{document}

Working implementation

From tex.stackexchange.com here: https://tex.stackexchange.com/a/107893/211737

\def\nobreakhline{%
\noalign{\ifnum0=`}\fi
 \penalty\@M
\futurelet\@let@token\LT@@nobreakhline}
\def\LT@@nobreakhline{%
\ifx\LT@next\hline
  \global\let\LT@next\@gobble
 \ifx\CT@drsc@\relax
   \gdef\CT@LT@sep{%
     \noalign{\penalty\@M\vskip\doublerulesep}}%
 \else
   \gdef\CT@LT@sep{%
     \multispan\LT@cols{%
       \CT@drsc@\leaders\hrule\@height\doublerulesep\hfill}\cr}%
 \fi
\else
 \global\let\LT@next\empty
 \gdef\CT@LT@sep{%
   \noalign{\penalty\@M\vskip-\arrayrulewidth}}%
\fi
\ifnum0=`{\fi}%
\multispan\LT@cols
 {\CT@arc@\leaders\hrule\@height\arrayrulewidth\hfill}\cr
\CT@LT@sep
\multispan\LT@cols
 {\CT@arc@\leaders\hrule\@height\arrayrulewidth\hfill}\cr
\noalign{\penalty\@M}%
\LT@next}

I think \hline* would be even better than nobreakhline for consistency with \\*

davidcarlisle commented 1 week ago

hmm yes \hline* would be sort of natural but the problem is that \hline is looking ahead for another \hline so the * would complicate the parsing. The extra code needed wouldn't be impossible, there is rather more token memory now than in 1990:-) but would still lead to things like \hline*\hline or \hline\hline* or \hline*\hline* and I'd need to decide if they were all legal, and if they all meant the same thing.

davidcarlisle commented 1 week ago

An alternative would be to not introduce a new \hline option but to directly address the problem in the example, arrange that an \hline or \hline\hline following \\* don't allow a page break. (I don't have code for that immediately available but must be possible in theory and might be a better interface.

FrankMittelbach commented 1 week ago

I agree, the latter would be the more natural interface. Given that \hline is looking for another \hline it would see the following \\and so could look further for * and act depending on what it finds without too much problems.

car222222 commented 1 week ago

@FrankMittelbach But my understanding is that the \\* would be before the lines.

car222222 commented 1 week ago

It is probably safer (more logical?) not to mix up the use of \\* with breaks after hlines -- separation of concerns is usually optimal!

FrankMittelbach commented 1 week ago

yes, my bad to remember the order incorrectly. But that means that somehting like \\* \hline \hline* would make sense with the meaning "if there is a break break between the two lines" as well as \\* \hline* \hline meaning "allow a break only after the double line"

chrisaga commented 1 week ago

An alternative would be to not introduce a new \hline option but to directly address the problem in the example, arrange that an \hline or \hline\hline following \\* don't allow a page break. (I don't have code for that immediately available but must be possible in theory and might be a better interface.

It would be great! It actually wrote

\\*
\hline

in the first place, hoping it would do what I wanted. Then I figured out that \hline re-enabled the page break disabled by \\*. Honestly I suggested \hline* because I thought that it was more "elegant" than \nobreakhline but I am perfectly happy with the later.