How to disable pagebreak on \hline in longtable?
The longtable
package redefines \hline
to allow pagebreaks by introducing penalties like \penaly-\@lowpenalty
in the code. If I understand correctly, what you want is a variant of \hline
which does not introduce any break point. To do this, you can just copy the code used to redefine \hline
in longtable.sty
and use it define a \nobreakhline
variant macro in which the penalties have been changed to 10000
so as to prevent all pagebreaks. This gives the following code:
\documentclass[12pt,a4paper,oneside]{letter}
\usepackage{longtable}
\makeatletter
\def\nobreakhline{%
\noalign{\ifnum0=`}\fi
\penalty\@M
\futurelet\@let@token\LT@@nobreakhline}
\def\LT@@nobreakhline{%
\ifx\@let@token\hline
\global\let\@gtempa\@gobble
\gdef\LT@sep{\penalty\@M\vskip\doublerulesep}% <-- change here
\else
\global\let\@gtempa\@empty
\gdef\LT@sep{\penalty\@M\vskip-\arrayrulewidth}% <-- change here
\fi
\ifnum0=`{\fi}%
\multispan\LT@cols
\unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr
\noalign{\LT@sep}%
\multispan\LT@cols
\unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr
\noalign{\penalty\@M}%
\@gtempa}
\makeatother
\begin{document}
\begin{longtable}{ | p{5cm} | }
\hline
Table header\\*
\nobreakhline
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris pharetra
porttitor turpis, id egestas neque congue in. Nam sed lorem lorem, ac
tristique tellus. Nunc ornare feugiat orci, a blandit turpis facilisis ut.
Aenean pharetra ornare ante. Sed tempus leo in dolor eleifend placerat.
Integer at enim augue. Ut nisl tortor, interdum ac porttitor ac, sagittis
quis libero. Vivamus nibh metus, ornare vel pulvinar nec, fringilla nec
orci. Maecenas mollis nulla a nibh fringilla nec convallis augue varius.
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
cubilia Curae. \\
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris pharetra
porttitor turpis, id egestas neque congue in. Nam sed lorem lorem, ac
tristique tellus. Nunc ornare feugiat orci, a blandit turpis facilisis ut.
Aenean pharetra ornare ante. Sed tempus leo in dolor eleifend placerat.
Integer at enim augue. Ut nisl tortor, interdum ac porttitor ac, sagittis
quis libero. Vivamus nibh metus, ornare vel pulvinar nec, fringilla nec
orci. Maecenas mollis nulla a nibh fringilla nec convallis augue varius.
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
cubilia Curae. \\
\hline
Table header\\*
\nobreakhline
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris pharetra
porttitor turpis, id egestas neque congue in. Nam sed lorem lorem, ac
tristique tellus. Nunc ornare feugiat orci, a blandit turpis facilisis ut.
Aenean pharetra ornare ante. Sed tempus leo in dolor eleifend placerat.
Integer at enim augue. Ut nisl tortor, interdum ac porttitor ac, sagittis
quis libero. Vivamus nibh metus, ornare vel pulvinar nec, fringilla nec
orci. Maecenas mollis nulla a nibh fringilla nec convallis augue varius.
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
cubilia Curae. \\
\hline
\end{longtable}
\end{document}
Here is the detail of how the previous code works. It's between \makeatletter
and \makeatother
because it's internal code containing the @
character. The code is in two parts: it starts by defining the \nobreakhline
which then calls another macro, \LT@@nobreakhline
. The macro begins with
\def\nobreakhline{%
\noalign{\ifnum0=`}\fi
The \ifnum..\fi
is a trick to make TeX
that think that braces are correctly paired when they are not. It it thus equivalent to \noalign{
, the closing brace being in the line beginning by \ifnum
in the second macro. The macro then sets a penalty and calls the second macro thanks to a \futurelet
:
\penalty\@M
\futurelet\@let@token\LT@@nobreakhline}
This \futurelet
is here to look ahead the \nobreakhline
macro; as we will see, the behavior will not be the same if it's followed by another \hline
or not.
We not get to the definition of \LT@@nobreakhline
. It begins by an if
test:
\def\LT@@nobreakhline{%
\ifx\@let@token\hline
\global\let\@gtempa\@gobble
\gdef\LT@sep{\penalty\@M\vskip\doublerulesep}% <-- change here
The test consists at looking if the next token is \hline
or not. If it is, then the macro \@gtempa
is set to \@gobble
. As its name suggest, the \@gobble
macros just gobbles the token following it. The macro \@gtempa
is defined here but used at the end of \LT@@nobreakhline
and so this means that \LT@@nobreakhline
will gobble the \hline
just following it, which avoids \hline
to be typesetted twice. After setting \@gtempa
, the macro \LT@sep
is also set. That's the part which I changed from the original longtable.sty
code: the penalty is changed from -\@medpenalty
(which is something like -151
, depending on the documentclass) to \@M
(which is a shortcut for 10000
); this prevents any break to occur where the penalty is issued.
We now get to the else
part of the conditional:
\else
\global\let\@gtempa\@empty
\gdef\LT@sep{\penalty\@M\vskip-\arrayrulewidth}% <-- change here
\fi
It has the same structure as the then
part, except that it occurs only if our macro \nobreakhline
is not followed by \hline
and sets the ending macro \@gtempa
to be noting (\@empty
) meaning nothing special will be done at the end of \LT@@nobreakhline
; there is also a penalty change to prevent breaking; this time the penalty was -\@lowpenalty
(about -51) and is changed to 10000
as before. The next line is the "closing brace" mentioned before:
\ifnum0=`{\fi}%
The next lines of codes typesets the rule:
\multispan\LT@cols
\unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr
Then the macro \LT@sep
defined earlier is used, and it has the effect of preventing any breaks:
\noalign{\LT@sep}%
Then there's another rule which is typesetted (it could probably be deleted from the code as we don't allow breaks any more, but it's harmless as it overlaps with the previous rule thanks to the negative \vskip
in \LT@sep
):
\multispan\LT@cols
\unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr
Finally, the macro ends with a penalty (to avoid another breaking point) and then the ending macro \@gtempa
defined earlier is issued:
\noalign{\penalty\@M}%
\@gtempa}
The solution of Philippe Goutet does not work well with colortbl
package and setting the color of the horizontal line with \arrayrulecolor
. Here is the solution that should work with colortbl
:
\makeatletter
\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}
\makeatother