[tex-eplain] column and page breaks in index.

Oleg Katsitadze olegkat at gmail.com
Fri Feb 27 07:17:30 CET 2009

On Thu, Feb 26, 2009 at 01:38:52PM -0500, John Culleton wrote:
> 1. Will eplain make column or page breaks based on a command 
> in the .ind file like \goodbreak?

Eplain typesets the index under the \doublecolumns settings, so the
usual multi-column commands are applicable.  That said, it is very
difficult to control multi-column environments, at least in my
experience.  Sometimes the commands just don't work, for no apparent

> 2. Has anyone addressed the problem of automating the 
> replication of the major heading when a column or page 
> break occurs in the middle of a long list of subheads? I 
> use pdftex. 

I did this a long time ago.  I didn't use Eplain's \doublecolumns, had
to design special-purpose macros based on some TeXbook wizardry.  The
macros below are taken out from a macro file, so in case I omitted
something, the original source is at


(the relevant file is epdf/epdfidx.tex).  But be warned there's a lot
of cruft in there to create hyperlinks, as it was written when Eplain
didn't have any hyperlink support.


%% We need custom double-column macros for the index which support `continued'
%% index entries (reminders on top of the page when an index entry did not fit
%% on the previous page).  Adapted from The TeXbook, p.~417.
\newbox\epdf at partialpage % will contain material preceding double-column mode
\newdimen\epdf at pagewidth  % real page width
\newdimen\epdf at pageheight % real page height
\epdf at pagewidth=\hsize
\epdf at pageheight=\vsize
% Start double column output
\def\epdf at begindoublecolumns{%
  % Output what's already on the page in single column mode
  \output={\global\setbox\epdf at partialpage=\vbox{\unvbox255\vskip\abovecolumnskip}}%
  % Start typesetting in two columns
  \output={\epdf at doublecolumnout}%
  \hsize=.5\epdf at pagewidth
  \advance\hsize by -.5\gutter
  \vsize=2\epdf at pageheight
% End double column output
\def\epdf at enddoublecolumns{%
  % Balance last material between two columns
  \output={\epdf at balancecolumns}%
  % Return to whatever mode was before double-column
% Main output routine for double column output
\def\epdf at doublecolumnout{%
  \splitmaxdepth=\maxdimen % make sure \vsplit produces boxes with true depth of
                           % the last box
  % Split \box255.  The height is \epdf at pageheight - \ht\epdf at partialpage.
  \dimen@=\epdf at pageheight
  \advance\dimen@ by-\ht\epdf at partialpage
  \setbox0=\vsplit255 to\dimen@
  \setbox2=\vsplit255 to\dimen@
  \dimen@=\dp2 % depth of last box in second column---will be use in \inxcheck
  % Output the two columns using previous output routine.  Preserve \hsize,
  % \vsize, and \dimen at .
    \setbox255=\expandafter\vbox\expandafter{\epdf at pagesofar}%
    \hsize=\epdf at pagewidth
    \vsize=\epdf at pageheight
    \the\epdf at previousoutput
  % Check \splitbotmark and put in `continued' lines, if necessary
  \expandafter\epdf at inxcheck\splitbotmark \cr\cr\end
  % Add what's left after splitting \box255
% Output \epdf at partialpage followed by a two-column box of \box0 and \box2
\def\epdf at pagesofar{%
  \unvbox\epdf at partialpage
  % Make sure width of the columns is \hsize (might be less than that)
  \hbox to\epdf at pagewidth{\box0\hfil\box2}%
% Auxiliary double-column output routine to balance final double-column material
% into two columns
\def\epdf at balancecolumns{%
  % \box0 now contains \baselineskip at the top, but after \vsplit it will
  % contain \splittopskip (equal to \topskip) at the top of both columns, so
  % adjust \ht0 to the \splittopskip
  \advance\dimen@ by\topskip
  \advance\dimen@ by-\baselineskip
  % Have of this adjusted half-height is initial \vsplit goal
  \divide\dimen@ by2
    \vbadness=10000 % do not report underfull boxes while we are trying to split
      \global\setbox1=\vsplit3 to\dimen@
    \ifdim\ht3>\dimen@ \global\advance\dimen@ by1pt \repeat
  \setbox0=\vbox to\dimen@{\unvbox1}%
  \setbox2=\vbox to\dimen@{\unvbox3}%
  \epdf at pagesofar
%% Macros to produce actual index.  We want to support `continued' index
%% entries.  The macros are adapted from The TeXbook, pp.~261--263.
\newtoks\epdf at previousoutput % will hold original output routine
% We set up our index in a hook to \@beginindex of eplain.
  \singlecolumn % we use our own double column mode
  \nobreak\vskip-\abovecolumnskip % remove extra vskips added by \singlecolumn
  \epdf at previousoutput=\expandafter{\the\output}% save original output routine
  \epdf at begindoublecolumns
  \epdf at indextrue % tell \headline not to expand \botmark
  \def\par{\endgraf \futurelet\next\epdf at inxentry}% sets \next to the first token of the next line
  \everypar={\hangindent 2\parindent}%
  \raggedright \tolerance=\@M
    \let\par=\endgraf % restore \par before calling \enddoublecolumns because it
                      % calls \eject, which in turn says \par
    \epdf at enddoublecolumns
% This is equivalent of \bigbreak, but \par was replaced with \endgraph and an
% empty \mark was added to make sure `continued' entry for a finished index
% entry will not migrate to the top of the next page
      \penalty -200
% See what's coming up on the next line.  \next was set to the first token of
% the next line in the redefined \par.
\def\epdf at inxentry{%
  % Ordered by (my guess of) frequency of use
  \ifx \next\item
    \ifx \next\subitem
      \ifx \next\par
        \let\next=\relax % ignore blank lines
        \ifx \next\indexspace
          \ifx \next\subsubitem
            \ifx \next\end
              \errmessage{Unknown index command}%
% These have to be differentiable by \ifx in \inxcheck, they only act as
% delimiters.  Actual typesetting is done by \{main,sub,subsub}entry macros.
% Registers to store name of current entries
% All entries are delimited by `\enditem', so they should not use it.
  \mark{}% empty \botmark if page break occurs before main entry
  \mark{\the\maintoks}% avoid expansion of tokens
  \printmainitem{#1}\separmainitem % print entry
  \mark{\the\maintoks}% main entry in \botmark if page break occurs before subentry
  \mark{\the\maintoks \cr \the\subtoks}% avoid expansion of tokens; \cr not
                                % expanded because it is a primitive cs
  \mark{\the\maintoks \cr \the\subtoks}% main + sub entries in \botmark if page
                                    % break occurs before subsubentry
  \mark{\the\maintoks \cr \the\subtoks \cr \the\subsubtoks}% avoid expansion of
                                % tokens; \cr not expanded because it is a
                                % primitive cs
% Produce lines with entries followed by \continued, when necessary
\def\epdf at inxcheck#1\cr#2\cr#3\end{%
  \ifx \next\empty % do nothing if \botmark is null
    \ifx \next\empty % nothing more if \botmark has no \subitem
      \ifx \next\temp % nothing more if \botmark has no \subsubitem
        \def\temp##1\cr\cr{##1}% remove trailing \cr\cr
    % Insert compensating glue.  \dimen@ must contain depth of the last box in
    % last column on the previous page.  We have two possibilities here:
    %   1) \vsplit in \doublecolumnout used up all of \box255 to produce the
    %      two columns, so \box255 is now void.  This case is similar to the
    %      one described in The TeXbook, p.~263;
    %   2) \box255 is not empty, i.e., \vsplit in \doublecolumnout left
    %      something there to go on the next page.  In this case \vsplit ate up
    %      all discardable items on top of what remained in \box255 and
    %      inserted \splittopskip reduced by the height of the first \hbox at
    %      the top (see The TeXbook, p.~124).  So in this case we need a more
    %      complex compensating glue, because the contents of \box255 will be
    %      unboxed in \doublecolumnout AFTER the new material we inserted above
    %      in this macro.  First, TeX will not add \parskip before the first
    %      \hbox in \box255, because \hbox in vertical mode does not start new
    %      paragraph, so we need \vskip\parskip.  Next, we want an adjusted
    %      \baselineskip instead of the adjusted \splittopskip before the first
    %      \hbox in \box255, so compensate the \splittopskip's glue at the top
    %      of \box255 by \baselineskip - \splittopskip.  Note that this will
    %      only work when depths of the boxes are not too big (i.e., when
    %      interline glue does not need to use \lineskip instead of
    %      \baselineskip).
      \advance\dimen@ by\baselineskip
    \advance\dimen@ by-\prevdepth

More information about the tex-eplain mailing list