[texhax] Update: Longtable question (partial) solution.

Uwe Lück uwe.lueck at web.de
Wed Mar 10 22:14:00 CET 2010


At 05:20 08.03.10, Beuthe, Thomas wrote:

>No nibbles to my earlier question, but I have kept on digging...
>
>I have found an answer to my first problem thanks to the efforts of Daniel 
>Lemire at the following link:
>http://www.daniel-lemire.com/blog/archives/2006/01/02/longtable-latex-package-breaks-pages-after-header/
>He states:
>" Here's an annoying longtable bug for those of you using LaTeX for a 
>living. Sometimes, but rarely so,
>  a longtable will break at the oddest places when using horizontal lines 
> (hline), including right after the header.
>  The solution is to define a special kind of hline called "nobreakhline" 
> and use that instead where you don't want any page breaks."
>
>The code is as follows:
>
>\makeatletter
>\def\nobreakhline{%
>\multispan\LT at cols\unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr
>\noalign{\penalty10000}}
>\makeatother
>
>and it does exactly what I want.  Since the document is being mechanically 
>generated,
>replacing all \hline occurrences after the header with \nobreakhline is a 
>snap.
>I tested it and it works as advertised.  No more orphaned longtable headers.
>
>
>On my second problem I am still clueless however, in spite of lots of 
>testing over the weekend. Is there any way of inextricably binding a 
>section break with the longtable that occurs immediately after it so that 
>the section head can never be orphaned at the bottom of the page?  Doing 
>this may cause ugly page breaks (lots of white space at the bottom of a 
>page), but that really doesn't matter in this case. Raising the 
>widow/orphan penalty doesn't help, and messing with the before or after 
>skip parameters didn't seem to help either.
>
>Is there any way of doing this in a general way without manual intervention?
>
>Any thoughts?  I really didn't find anything up to now.
>Section breaks and longtables don't seem to be good bed partners at times.

I once placed another longtable fix on CTAN, http://ctan.org/pkg/ltabptch 
(story inside).

It changes \LT at start. I think another change of it solves the problem. 
Attached is a new, experimental version v2.00a of ltabptch.sty attempting 
at this. Would you like to test it?

I tried to be smart doing something more general. But the essential point 
is that

     \endgraf\penalty\z@\vskip\LTpre

must be replaced by

     \endgraf\if at nobreak\else\penalty\z@\fi\vskip\LTpre

\if at nobreak is exactly the thing for avoiding page breaks after sectioning 
commands (internally set by \@afterheading).

Have you thought of making a LaTeX bug report of it? This would be the 
normal way, as longtable belongs to the tools bundle of the LaTeX distribution.

HTH -- Uwe.

>Thomas
>
>
>
>=======================================
>Hello all,
>
>I'm overseeing the production of some large documents that are almost 
>entirely mechanically generated.
>Large portions consist of sections that contain only longtables and no 
>other text or features.
>Example:
>
>\subsection{A}
>longtable here
>\subsection{B}
>another longtable here
>and so on
>
>This can cause funny pagebreaks sometimes where a section heading is orphaned
>at the bottom of the page because the only thing following it is a 
>longtable before the next
>section break occurs.
>
>It can also cause situations where the section break occurs at the bottom 
>of the page
>and the only thing that follows it is the header of the longtable and an 
>\hline below it
>at the very bottom of the page, and the table continues on next page.  For 
>example:
>
>2.0 Section Heading for a Section
>
>------------------
>| longtable head |
>----------------------------------------------------------------------------------
>
>[page breaks here]
>
>------------------
>| longtable head |
>----------------------------------------------------------------------------------
>| First table 
>entry...                                                           |
>----------------------------------------------------------------------------------
>| Second table 
>entry...                                                          |
>----------------------------------------------------------------------------------
>...and so on
>
>So my question is:
>
>...aside from manually entering a \newpage before the section break, which 
>is not a good option
>because the document source is being produced by a large perl script, and 
>would mean I would
>have to do the manual correction every time I re-produce the document 
>source via the perl script...
>(which happens far too often...)
>
>1) Is there any way of glueing the \subsection to the top of the longtable 
>somehow?
>
>2) Is there any way to force longtable NOT to allow the orphaning of one 
>of its heads at the end of a page?
>    (From what I read in the documentation, this isn't really supposed to 
> happen.)
>
>I've tried readin through all of the documentation again and done a search 
>to see if anyone
>else had this problem before me, but no luck?
>
>Does David Carlisle or David Kastrup read this list?
>I tried contacting them at some of their old email addresses, but got only 
>a bounce.
>Does anyone happen to have their up to date email addresses handy?
>
>Thanks in advance for any advice.
>Even a pointer to a previous discussion or FAQ would be great!
>
>Thomas
-------------- next part --------------
%% LTabPtch.sty---Uwe L"uck---patch for Longtable. 
\def\filedate{2010/03/10} \def\fileversion{2.00a}
%% For David Carlisle's longtable.sty, version 4.11 
%% Fixes tools/3180 (Sebastian Rahtz) and tools/3485: 
%% missing/wrong interline glues above/below table. 
%% 
%% Copyright (C) 2002--2005, 2010 Uwe L"uck, 
%% http://www.contact-ednotes.sty.de.vu 
%% --author-maintained. 
%%
%% Usage, no warranty, distribution as in lppl.txt on CTAN 
%% (macros/latex/base/lppl.txt). 
%% 
%% Loading Longtable.sty with options must be done earlier! 
%% 
\NeedsTeXFormat{LaTeX2e}[1994/05/20] % \CheckCommand 
\ProvidesPackage{ltabptch}[\filedate\space v\fileversion\space
   Longtable patch for tools/3180, 3485 (ul)]
% 
% The problem(s): [Thomas Beuthe 2010 not recognized]
% Sebastian Rahtz (tools/3180) observed 2000/03/05 that there be 
% a "spurios blank line" below the longtable. This impression 
% may have been due to two spacing problems: 
% (1) There is \parskip and some interline glue below longtable, 
% while there is no \parskip and no interline glue above 
% (without head as specified by \endhead or \firstendhead) 
% or just \lineskip 0.0pt (with head---\endhead, \endfirsthead). 
% (2) After longtable, \prevdepth is the depth of the last line 
% before the longtable (if there is no head) or the depth of the 
% head (otherwise). So \prevdepth may be 0pt. By contrast, the 
% last table row has depth of at least \dp\@arstrutbox--which 
% should rather matter, and this is 3.6pt or more. 
% --I have reported something like this as tools/3485, not 
% entirely correctly. Details are presented below \endinput. 
% 
% Solution presented: 
% (1) I think there should be \parskip and usual interline glue 
% above, since the same would happen with a table in a center 
% environment (e.g.). 
% \noindent seems to work fatally; moreover, \LT at start's decision 
% whether to enter a new page would ignore \parskip and interline 
% glue still needed. 
% So emulate interline glue calculation according to TeXbook p. 80 
% and add it by \vskip, along with \parskip. 
% (This is rather a hack---a proper correction should perhaps not 
% "emulate" but place the interlineglue changes of \LT at array inside 
% the \vbox \LT at bchunk starts and treat glue between chunks in a 
% new way.) 
% (2) Set \prevdepth to depth of box 0 before the latter is 
% \unvbox'ed (which leaves \prevdepth untouched, TeXbook p. 282) 
% in \endlongtable. 
% 
% I thought David Carlisle would change Longtable according to my 
% suggestions. By e-mail from 2003/04/07 however, he finds it 
% better not to change Longtable, in order not to change layouts 
% of works that have been made using Longtable so far 
% (e-Mail 2003/04/08). 
% 
%% <- TODO: change this when David has changed his mind! 
% By the way: 
% 1.) There are two successive lines in the Longtable code (v4.11) 
%     together saying: 
%         \prevdepth\z@\global 
%         \global\let\LT at setprevdepth\relax 
%     Isn't the first \global just a typo? 
%     --Yes--this is David Carlisle's answer in his e-mail 
%     dating from 2004/05/14. 
% 2.) Couldn't the one-column restriction easily be removed 
%     by using \columnwidth instead of \hsize? 
% 
% Patching is to override Longtable.sty: 
\RequirePackage{longtable}[2004/02/01] 
%% TODO: Cf. \CheckCommand below. 
% Load earlier on your own for choosing Longtable options! 
% 
% For (1), we are patching \LT at start, assumed to have been defined 
% as follows (Longtable v4.11; sorry we can no longer handle v3.16 
% through 4.10): 

\CheckCommand*{\LT at start}{%
  \let\LT at start\endgraf
  \endgraf\penalty\z@\vskip\LTpre
  \dimen@\pagetotal
  \advance\dimen@ \ht\ifvoid\LT at firsthead\LT at head\else\LT at firsthead\fi
  \advance\dimen@ \dp\ifvoid\LT at firsthead\LT at head\else\LT at firsthead\fi
  \advance\dimen@ \ht\LT at foot
  \dimen at ii\vfuzz
  \vfuzz\maxdimen
    \setbox\tw@\copy\z@
    \setbox\tw@\vsplit\tw@ to \ht\@arstrutbox
    \setbox\tw@\vbox{\unvbox\tw@}%
  \vfuzz\dimen at ii
  \advance\dimen@ \ht
        \ifdim\ht\@arstrutbox>\ht\tw@\@arstrutbox\else\tw@\fi
  \advance\dimen@\dp
        \ifdim\dp\@arstrutbox>\dp\tw@\@arstrutbox\else\tw@\fi
  \advance\dimen@ -\pagegoal
  \ifdim \dimen@>\z@\vfil\break\fi
      \global\@colroom\@colht
  \ifvoid\LT at foot\else
    \advance\vsize-\ht\LT at foot
    \global\advance\@colroom-\ht\LT at foot
    \dimen@\pagegoal\advance\dimen at -\ht\LT at foot\pagegoal\dimen@
    \maxdepth\z@
  \fi
  \ifvoid\LT at firsthead\copy\LT at head\else\box\LT at firsthead\fi\nobreak 
%% \nobreak new with Longtable v4.11. 
  \output{\LT at output}}
% 
% Change it: 
\def\LT at start{%
  \let\LT at start\endgraf
%<v2.00> for Thomas Beuthe texhax March 2010
% most simply surround `\penalty\z@' with `\if at nobreak\else...\fi'
%   \endgraf\penalty\z@\vskip\LTpre
 \endgraf
 \@tempskipa\LTpre
%  \vskip\parskip %% U.L. v1.73 or earlier
 \if at nobreak \else
   \addpenalty\z@
   \advance\@tempskipa\parskip
 \fi
 \addvspace\@tempskipa
%</v2.00>
% I want to add the interline glue before \pagetotal goes to \dimen at . 
% So I move \LT at start's \vsplit here. 
 %% U.L. start: 
 \dimen at ii\vfuzz 
 \vfuzz\maxdimen
   \setbox\tw@\copy\z@
   \setbox\tw@\vsplit\tw@ to \ht\@arstrutbox
   \setbox\tw@\vbox{\unvbox\tw@}%
 \vfuzz\dimen at ii
 \ifdim\prevdepth>-\@m\p@ 
% First we need the maximum of the heights of \tw@ and head row. 
% A little flaw might be here: I am ignoring \Lt at start's 
% \@arstrutbox concern below, cf. remark there. 
   \@tempskipa % \normalbaselineskip going to enter. 
     \ht\ifvoid\LT at firsthead\LT at head\else\LT at firsthead\fi 
%  \typeout{\@tempskipa=\the\@tempskipa}% TEST 
   \@tempskipa-\ifdim\@tempskipa<\ht\tw@\ht\tw@\else\@tempskipa\fi 
%  \typeout{\@tempskipa=\the\@tempskipa}% TEST 
   \advance\@tempskipa-\prevdepth 
%  \typeout{\string\prevdepth=\prevdepth}% TEST 
%  \typeout{\@tempskipa=\the\@tempskipa}% TEST 
   \advance\@tempskipa\normalbaselineskip 
%  \typeout{\normallineskiplimit=\the\normallineskiplimit}% TEST 
%  \typeout{\@tempskipa=\the\@tempskipa}% TEST 
   \vskip \ifdim\@tempskipa<\normallineskiplimit 
            \normallineskip 
          \else 
            \@tempskipa 
          \fi 
 \fi 
 \nointerlineskip % v1.4 prevent head from adding more 
%                 % (if only negative) glue. 
%  \prevdepth -1000\p@ % Prevent head from adding more glue (v1.3). 
 %% U.L. end. 
  \dimen@\pagetotal
  \advance\dimen@ \ht\ifvoid\LT at firsthead\LT at head\else\LT at firsthead\fi
  \advance\dimen@ \dp\ifvoid\LT at firsthead\LT at head\else\LT at firsthead\fi
  \advance\dimen@ \ht\LT at foot
%   \dimen at ii\vfuzz
%   \vfuzz\maxdimen
%     \setbox\tw@\copy\z@
%     \setbox\tw@\vsplit\tw@ to \ht\@arstrutbox
%     \setbox\tw@\vbox{\unvbox\tw@}%
%   \vfuzz\dimen at ii
% 
% Remark U.L.: The following four code lines seem strange to me: 
% after all, \tw@ contains \@arstrutbox, doesn't it? 
% And even if not: why should we need room for another \@arstrutbox? 
  \advance\dimen@ \ht
        \ifdim\ht\@arstrutbox>\ht\tw@\@arstrutbox\else\tw@\fi
  \advance\dimen@\dp
        \ifdim\dp\@arstrutbox>\dp\tw@\@arstrutbox\else\tw@\fi
  \advance\dimen@ -\pagegoal
  \ifdim \dimen@>\z@\vfil\break\fi
      \global\@colroom\@colht
  \ifvoid\LT at foot\else
    \advance\vsize-\ht\LT at foot
    \global\advance\@colroom-\ht\LT at foot
    \dimen@\pagegoal\advance\dimen at -\ht\LT at foot\pagegoal\dimen@
    \maxdepth\z@
  \fi
  \ifvoid\LT at firsthead\copy\LT at head\else\box\LT at firsthead\fi\nobreak 
%% \nobreak new with Longtable 4.11. 
  \output{\LT at output}}
% 
% 
% For (2), we are patching \endlongtable: 
% The patch should not change essentials of \endlongtable 
% which may have changed when this patch meets longtable. 
% We just assume that the final contribution to the main vertical 
% list is done by \unvbox0 which is preceded by \LT at start. 
% \prevdepth\dp0 can be put in between, it will then 
% last till the end (TeXbook pp. 282, 277f.). 
\def\@tempa#1\LT at start{#1\LT at start \prevdepth\dp\z@} 
\expandafter\expandafter\expandafter \def 
 \expandafter\expandafter\expandafter \endlongtable 
  \expandafter\expandafter\expandafter 
   {\expandafter\@tempa\endlongtable} 
% 
\endinput 

DETAILED DIAGNOSIS: 

Concerning the question of "bugs" vs. "features", you might 
reason what features should be aimed at. 

%% TODO: This can be shortened when David agrees. 

    (A) If there is \parskip below a longtable, there should 
be \parskip above as well--shouldn't it? 
    (B) Interline glue above should (in general) depend on the 
same values of \baselineskip and \lineskip as below---OK? 
    (C) Interline glue below a longtable should depend on the 
depth of the last row, not on the depth of the head or of the 
last line above the longtable--OK? 

The recent versions of longtable.sty have not satisfied any 
of these three demands. 
Concerning (A), \parskip appears below the longtable, but not 
above. 
Concerning (B), (i) no interline glue appears above if there 
is no head, (ii) otherwise, only zero interline glue appears.
Concerning (C), the interline glue below the longtable is 
calculated using the depth of (i) the last line above the 
longtable as \prevdepth when there is no head or of (ii) the 
head otherwise. (Thus I was wrong earlier when I claimed that 
\prevdepth were 0pt after longtable. This only holds in the 
previous case (i) when the last line above the longtable has 
zero depth.)

You can observe this by playing with the demonstration file 
ltabptch.tex in CTAN folder macros/latex/contrib/ltabptch. 

Reasons: For contributing a head to the main vertical list, 
longtable uses \copy or \box, which yields a <box> according 
to TeXbook p. 278. Rows are contributed by \unvbox. Now, 
violation of (A) is due to the fact that neither \copy or 
\box of the head nor the \unvbox for table rows leads to 
execution of an \indent or \noindent (TeXbook pp. 282f., see 
also <horizontal command>). 
Violation of (B) is due either to (i) the fact that \unvbox 
is no <box> (TeXbook p. 282/278) or to (ii) the fact that at 
\copy or \box \baselineskip and \lineskip are 0pt. 
Violation of (C) is due to the fact that \unvbox does not 
change \prevdepth (TeXbook p. 282). 

As to recognizable effects: 
    Violation of (A), of course, has very little effect in 
general since \parskip is 0pt plus 1pt usually. This is hardly 
recognizable in the presence of the \bigskipamount above and 
below a longtable. 
    Violation of (B) results in missing appropriate interline 
glue above, which often should be 3.6pt or more. This may 
rather be recognizable and may contribute to the impression 
that there even is a spurious blank line below the longtable 
(this is what Sebastion Rahtz reported in tools/3180). 
    For the previous as well as for the details and the 
effects of violation of (C), consider the algorithm for 
calculating interline glue on p. 80 of the TeXbook. If there 
is no head, and the depth of the last line before the 
longtable is 0pt, the interline glue below the longtable is 
\baselineskip minus the height of the first line after the 
longtable. The interline glue *should be* \baselineskip minus 
height of following line *minus* depth of last table row--if 
this depth is not too large (depending on \lineskiplimit). 
This depth is at least 3.6pt. So the interline glue is often 
by 3.6pt or more greater than is appropriate. Considering the 
missing interline glue above the longtable and the \parskip 
below, the glue after the longtable is by 6.2pt (or more) plus 
1pt larger than the glue before. Due to the shrink component 
of the surrounding \bigskipamount, the glue following the 
longtable may be nearly twice as large as the glue before.
---Usually, violation of (C) has no effect at all. Namely, 
there is a head usually, and its depth is usually the same as 
the depth of the last row, namely \dp\@arstrutbox. 


%% VERSION HISTORY: 
v1.7   2003/01/07 Sent around 2003/01/13 with first release of 
                  ednotes.sty. Sent to David Carlisle. Earlier versions 
                  were sent to Frank Mittelbach and the team. 
v1.71  2003/01/22 Added version history. 
v1.72  2003/01/27 Changed copyright notice. 
v1.73  2004/05/13 Adapted to Longtable v4.11; new copyright; 
                  longtable -> Longtable (selectively). 
                  Added `I have ... 3485'. 
v1.74  2004/08/05 Added `---Yes---...'. 
       2004/08/21 Typo fix for `problem'; added report on 2003/04/08. 
       2004/08/23 Corrected and extended diagnosis, sent to CTAN. 
v1.74b  .../08/23 `---' -> `--'; added that (C) usually doesn't 
                 matter. 
v1.74c  .../08/31 `author-maintained'. 
v1.74d 2005/01/10 Contact via http. 
v2.00  2010/03/10 Attempt for Thomas Beuthe
v2.00a 2010/03/10 Updated copyright



More information about the texhax mailing list