[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
reason.

> 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

    http://geolsoft.freeshell.org/elsgolts.diff.ur.var.is/elsgolts_diff_ur_var_is.tar.gz

(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.

HTH,
Oleg

%
%% 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{%
  \begingroup
  % Output what's already on the page in single column mode
  \output={\global\setbox\epdf at partialpage=\vbox{\unvbox255\vskip\abovecolumnskip}}%
  \eject
  % 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}%
  \eject
  % Return to whatever mode was before double-column
  \endgroup
  \pagegoal=\vsize
}%
% Main output routine for double column output
\def\epdf at doublecolumnout{%
  \splittopskip=\topskip
  \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
  \unvbox255
  \penalty\outputpenalty
}%
% 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)
  \wd0=\hsize
  \wd2=\hsize
  \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{%
  \setbox0=\vbox{\unvbox255}%
  % \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
  \dimen@=\ht0
  \advance\dimen@ by\topskip
  \advance\dimen@ by-\baselineskip
  % Have of this adjusted half-height is initial \vsplit goal
  \divide\dimen@ by2
  \splittopskip=\topskip
  {%
    \vbadness=10000 % do not report underfull boxes while we are trying to split
    \loop
      \global\setbox3=\copy0
      \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.
\hookaction{beginindex}{%
  \singlecolumn % we use our own double column mode
  \nobreak\vskip-\abovecolumnskip % remove extra vskips added by \singlecolumn
  \nobreak\vskip-\belowcolumnskip
  \epdf at previousoutput=\expandafter{\the\output}% save original output routine
  \gutter=.5cm
  \epdf at begindoublecolumns
  \let\linkBorderType=\linkBorderNone
  \parindent=1em
  \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
  \let\enditem\
  \obeylines
  \everypar={\hangindent 2\parindent}%
  \exhyphenpenalty=10000
  \raggedright \tolerance=\@M
  \def\end#1{%
    \mark{}%
    \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
\def\indexspace{%
  \mark{}%
  \endgraf
  \ifdim
    \lastskip<\bigskipamount
      \removelastskip
      \penalty -200
      \bigskip
  \fi
}%
% 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
    \let\next=\mainentry
  \else
    \ifx \next\subitem
      \let\next=\subentry
    \else
      \ifx \next\par
        \let\next=\relax % ignore blank lines
      \else
        \ifx \next\indexspace
          \let\next=\relax
        \else
          \ifx \next\subsubitem
            \let\next=\subsubentry
          \else
            \ifx \next\end
              \let\next=\relax
            \else
              \errmessage{Unknown index command}%
            \fi
          \fi
        \fi
      \fi
    \fi
  \fi
  \next
}%
%
% These have to be differentiable by \ifx in \inxcheck, they only act as
% delimiters.  Actual typesetting is done by \{main,sub,subsub}entry macros.
\let\item1
\let\subitem2
\let\subsubitem3
% Registers to store name of current entries
\newtoks\maintoks
\newtoks\subtoks
\newtoks\subsubtoks
% All entries are delimited by `\enditem', so they should not use it.
\def\mainentry\item#1\enditem{%
  \mark{}% empty \botmark if page break occurs before main entry
  \noindent
  \maintoks={#1}%
  \mark{\the\maintoks}% avoid expansion of tokens
  \printmainitem{#1}\separmainitem % print entry
}%
%
\def\subentry\subitem#1\enditem{%
  \mark{\the\maintoks}% main entry in \botmark if page break occurs before subentry
  \noindent
  \subtoks={#1}%
  \mark{\the\maintoks \cr \the\subtoks}% avoid expansion of tokens; \cr not
                                % expanded because it is a primitive cs
  \printsubitem{#1}\separsubitem
}%
%
\def\subsubentry\subsubitem#1\enditem{%
  \mark{\the\maintoks \cr \the\subtoks}% main + sub entries in \botmark if page
                                    % break occurs before subsubentry
  \noindent
  \subsubtoks={#1}%
  \mark{\the\maintoks \cr \the\subtoks \cr \the\subsubtoks}% avoid expansion of
                                % tokens; \cr not expanded because it is a
                                % primitive cs
  \printsubsubitem{#1}\separsubsubitem
}%
%
% Produce lines with entries followed by \continued, when necessary
\def\epdf at inxcheck#1\cr#2\cr#3\end{%
  \def\next{#1}%
  \ifx \next\empty % do nothing if \botmark is null
  \else
    \noindent
    \printmainitem{#1}\continuedmainitem
    \def\next{#2}%
    \ifx \next\empty % nothing more if \botmark has no \subitem
    \else
      \noindent
      \printsubitem{#2}\continuedsubitem
      \def\next{#3}%
      \def\temp{\cr}%
      \ifx \next\temp % nothing more if \botmark has no \subsubitem
      \else
        \def\temp##1\cr\cr{##1}% remove trailing \cr\cr
        \noindent
        \expandafter\printsubsubitem\expandafter{\temp#3}\continuedsubitem
      \fi
    \fi
    % 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).
    \ifvoid255
    \else
      \vskip\parskip
      \dimen@=-\splittopskip
      \advance\dimen@ by\baselineskip
    \fi
    \advance\dimen@ by-\prevdepth
    \kern\dimen@
  \fi
}%
%
%
%
\endinput


More information about the tex-eplain mailing list