[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