%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Module: ZzTeX General Text Facilities % % Synopsis: This module contains definitions for blocks that are used to % format text. % % Notes: The tabbing facility was implemented by Richard A. Wells and % integrated into ZzTeX on 8/16/94. % % Authors: Paul C. Anagnostopoulos and Richard A. Wells % Created: 14 March 1990 % % Copyright 1989--2020 by Paul C. Anagnostopoulos % under The MIT License (opensource.org/licenses/MIT) % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Text Block % ---- ----- \defineblock{\text}{\endtext}{\false}{} \resetinvcontext{\text} %~block text Type, Level % \abovepenalty = integer % Penalty above text. % \aboveskip = glue % Space b/b above text. % \def \beginformat {...} % Beginning of text formatter. % \belowpenalty = integer % Penalty below text. % \belowskip = glue % Space b/b below text. % \bodyfont = {font} % Body font. % \def \calloutformat ##1{...} % Callout formatter. % \calloutnumber = integer % Number of first callout. % \def \callouttext {...} % Callout text or \arg. % \defaulttabwidth = dimen % Default repeating tab width. % \setflag \enabletabbing = flag % Enable tabbing commands. % \def \endformat {...} % End of text formatter. % \leftindent = glue % Left indentation. % \parindent = dimen % Paragraph indentation. % \parrag = dimen % Paragraph raggedness. % \parskip = glue % Paragraph skip. % \rightindent = glue % Right indentation. % \textcolor = {...} % Color of text. % \setflag \verbatimlines = flag % Treat line breaks verbatim. % \width = dimen % Line width. %~end \definecount{\calloutnumber}{0} \setflag \enabletabbing = \false \definedimen{\defaulttabwidth}{0pt} \setflag \verbatimlines = \false \def \text #1{% {type} \beginblockscope{text}% \global\increment \textdepth \abovepenalty = \breakgood %~default hard \def \beginformat {}% %~default soft \belowpenalty = \breakgood %~default hard \calloutnumber = 1 %~default with \def \callouttext {\number\calloutnumber}% %~default soft \defaulttabwidth = \mindimen %~default soft \setflag \enabletabbing = \false %~default soft \def \endformat {}% %~default soft \textcolor = {}% %~default soft \setflag \verbatimlines = \false %~default soft \processdesign{\text}{#1\romannumeral\textdepth}% \global\increment \textnumber \textformat \def \zarg {\arg}% \if \tokeqlp{\callouttext}{\zarg}% \defineatsigncommand @##{\ztextcoformat}% \else \defineatsigncommand @##{\ztextcoformat{\callouttext}}% \fi \if \emptytoksp{\textcolor}% \bgroup \else \color{\the\textcolor}% \fi \if \enabletabbing \ztabinittabbing \fi \if \verbatimlines \obeylines \fi \if \enabletabbing \ztabstarttabbing \fi} \def \endtext {% % Must really be \par, not \endgraf, because might be redefined % for tabbing. \if \notp{\verbatimlines}% % In \verbatimlines the line preceding \endtext{...} will put % out a final \par, but if not we have to do it here. \par \fi \if \enabletabbing \ztabfinaltabbing \fi \if \emptytoksp{\textcolor}% \egroup \else \endcolor \fi \futurelet\nexttoken \zendtext} \def \zendtext {% \endtextformat \global\decrement \textdepth \endblockscope{text}% \parnext} \def \textformat {% \endgraf \the\bodyfont \bbskipabove{\abovepenalty}{\aboveskip}% \alterindentation{\leftindent}{\rightindent}% \settextwidth{\width}% \setparrag{\parrag}% \beginformat} \def \endtextformat {% \endformat \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}} \def \ztextcoformat #1{% {text} \calloutformat{#1}% \global\increment \calloutnumber} % Tabbing Commands % ------- -------- % These commands are available in a text block if \enabletabbing is turned on. % \ztabinitalizetabbing % - Redefines \par % - Defines the @ commands for tabbing. (The real work is done in the % in the \ztabcmd* macros, defined below.) % - Initializes variables \def \ztabinittabbing {% % Redefine \par to ship out the tabbed line, \endgraf it and start a % new tabbed line \let \par = \ztabpar % Define tabbing commands \def \adjusttabbing ##1{\ztabadjusttabbing{##1}}% \defineatsigncommand @.{\ztabcmdset}% \defineatsigncommand @>{\ztabcmdforwards}% \defineatsigncommand @+{\ztabcmdindent}% \defineatsigncommand @-{\ztabcmdoutdent}% \defineatsigncommand @D{\ztabcmddiscard}% \defineatsigncommand @C{\ztabcmdclear}% \defineatsigncommand @E##1{\ztabcmdevery{##1}}% % Initialize variables \if \verbatimlines % The line with \text{...} will put out the first \par, so we % want to skip it. \ztabdiscardtrue \else \ztabdiscardfalse \fi \global\ztabindentlevel=0\relax % Clear all tab stops \ztabcmdclear} \def \ztabparfinishpreviousline {% % Set state checked by \ztabendtabcell \ztabatnltrue % End last tab cell with \ztabnltrue \ztabendtabcell \egroup% closes inner group started below in \ztabmaketabbedline \egroup% closes outer group started below in \ztabmaketabbedline % Unless discarding, deposit the line and remove the last box \if \notp{\ztabdiscardp}% \unvbox\zboxa\lastbox \else % Clear discarding flag \ztabdiscardfalse \fi \endgroup% closes outermost group started by \ztabmaketabbedline % We should be back in vertical mode now. % % Reset \ztabsbox. The new value is the set of tbd boxes % followed by the done boxes. If not all of the tbd boxes were % used this should result in the same set of boxes as the % previous value of \ztabsbox. However, if the tbd boxes were used up % then the done boxes may contain additional boxes built on the fly. \setbox\ztabsbox\hbox{\unhbox\ztabstbdbox\unhbox\ztabsdonebox}} \def \ztabparstartnextline {% \ztabmaketabbedline} \def \ztabpar {% macro used instead of \par in tabbing \ztabparfinishpreviousline \endgraf \ztabparstartnextline} \def \ztabstarttabbing {% \ztabparstartnextline} \def \ztabfinaltabbing {% % Discard and finish last tabbed line started by last \ztabpar \ztabdiscardtrue \ztabparfinishpreviousline} % Variables shared by \ztab* macros % Counts and dimens for building tab boxes \definecount{\ztabindentlevel}{0} \definecount{\ztabindentcounter}{0} \definedimen{\ztabcolwidth}{0pt} \definedimen{\ztabtabpos}{0pt} \definedimen{\ztabdimenii}{0pt} % Conditionals % atnlp: are we at a \nl in tab processing? \def \ztabatnlfalse {\global\setflag \ztabatnlp=\false}% \def \ztabatnltrue {\global\setflag \ztabatnlp=\true}% % discardp: are we discarding this line's output? \def \ztabdiscardfalse {\global\setflag \ztabdiscardp=\false}% \def \ztabdiscardtrue {\global\setflag \ztabdiscardp=\true}% % settingp: are we setting? \def \ztabsettingfalse {\global\setflag \ztabsettingp=\false}% \def \ztabsettingtrue {\global\setflag \ztabsettingp=\true}% % tabbingp: are we tabbing? \def \ztabtabbingfalse {\global\setflag \ztabtabbingp=\false}% \def \ztabtabbingtrue {\global\setflag \ztabtabbingp=\true}% % Boxes to hold the tabs \definebox{\ztabsbox}% hbox of hboxes for each tab column \definebox{\ztabstbdbox}% hbox of hbox tab columns still "to be done" \definebox{\ztabsdonebox}% hbox of hbox tab columns already done \definebox{\ztabsindentbox}% hbox of indents % The macros that implement the tabbing commands. \ztabcmd* are the % top-level macros called by the @ commands. Other \ztab* macros are % helpers. \def \ztabcmdset {% % Set state checked by \ztabendtabcell \ztabsettingtrue % End the current cell with \ztabsettingtrue \ztabendtabcell % Start the next cell \ztabbegintabcell\noindent\ignorespaces}% \def \ztabcmdforwards {% % Set state checked by \ztabendtabcell \ztabtabbingtrue % End the current cell with \ztabsettingtrue \ztabendtabcell % Start the next cell \ztabbegintabcell\noindent\ignorespaces}% \def \ztabcmdindent {\global\increment \ztabindentlevel\relax}% \def \ztabcmdoutdent {% \global\decrement \ztabindentlevel\relax \if \negp{\ztabindentlevel}% \zzerror{Attempt to tab dedent (with \string@-) to left of left margin}% \fi} \def \ztabcmddiscard {% \ztabdiscardtrue}% \def \ztabcmdclear {% {boolean: initialization} % First clear all boxes \ztabcleartabboxes % Surprise! Clearing tabs might actually set them, if \defaulttabwidth % has been set in the design \if \neqlp{\defaulttabwidth}{\mindimen}% \ztabcmdevery{\defaulttabwidth}% \else % Must clear indent level since we've cleared all tabs (note that % we intentionally leave indent level alone if there is a % \defaulttabwidth!) \global\ztabindentlevel=0\relax \fi\ignorespaces}% \def \ztabcmdevery #1{% % First clear all tabs \ztabcleartabboxes % Set new tab columns of the specified width into \ztabsbox \ztabsettabs{#1}% % Re-init the boxes used by \ztabmaketabbedline \ztabinittabboxes{\true}% Flag indicates this is a re-init \ignorespaces} % Implementation of the above commands \def \ztabinittabboxes #1{% Init the tab boxes {boolean: re-init} % First copy \ztabsbox into \ztabstbdbox and clear \ztabsdonebox \global\setbox\ztabstbdbox\copy\ztabsbox \global\setbox\ztabsdonebox\null % Put all of the indent boxes that might be built into an hbox % which we will emit later, but just before processing cells \global\setbox\ztabsindentbox\hbox% \bgroup% % Initialize counter for loop \ztabindentcounter=0\relax % Iterate \ztabindentlevel times, moving tabboxes from \ztabstbdbox to % \ztabsdone, maybe emitting hboxes per indent \if \lssp{\ztabindentcounter}{\ztabindentlevel}% \loop \increment \ztabindentcounter\relax% increment loop counter % Pull \lastbox off of \ztabstbdbox \global\setbox\ztabstbdbox\hbox{% \unhbox\ztabstbdbox \global\setbox\zboxb\lastbox}% \ifvoid\zboxb % This is a problem. Not allowed to indent past set tabs. \zzerror{Attempt to tab indent (with \string@+, [\the\ztabindentlevel]) past set tabs}% \else % Nothing wrong with the box: push it on \ztabsdonebox % and maybe emit it \global\setbox\ztabsdonebox\hbox{\copy\zboxb\unhbox\ztabsdonebox}% \if \notp{#1}% Not re-initializing \box\zboxb \fi \fi % Loop test \if \lssp{\ztabindentcounter}{\ztabindentlevel}\repeat \fi % End hbox \egroup} \def \ztabcleartabboxes {% Clear the tab boxes and indent level \setbox\ztabsbox\null \global\setbox\ztabstbdbox\null \global\setbox\ztabsdonebox\null} \def \ztabsettabs #1{% Deposit tab stops of a specified width in \ztabsbox \ztabcolwidth=#1\relax \ztabtabpos=0pt\relax % Loop while \ztabtabpos is less than \hsize, setting another tab \loop \ztabsetanother \if \dimlssp{\ztabtabpos}{\hsize}\repeat} \def \ztabsetanother {% Helper for \ztabsettabs, immediately preceding % Advance the counter \advance \ztabtabpos by \ztabcolwidth % Set another tab by "pushing" another hbox into the \ztabsbox hbox % followed by its old set of hboxes \setbox\ztabsbox\hbox{\hbox to\ztabcolwidth{}\unhbox\ztabsbox}} \def \ztabmaketabbedline {% Build a line of tabbed text % Start outermost group that redefines \nl \begingroup % Inittab boxes (this also builds \ztabsindentbox) \ztabinittabboxes{\false}% Flag indicates NOT a re-init % \nl is a synonym for modified \par \let\nl=\par % \zboxa will contain the entire tabbed line in a vbox. % (It is unvboxed in \nl and may be discarded if a @D is encountered.) \setbox\zboxa\vbox% % start outer group closed by \nl that holds state of \ztabatnlp \bgroup% % don't want to indent a tabbed line \noindent % Init conditionals \ztabatnlfalse \ztabsettingfalse \ztabtabbingfalse % start inner group closed by \nl that surrounds set of tabboxes % and uses \zboxc as an hbox for the current cell. \bgroup% % emit indentation box \box\ztabsindentbox % start the first cell \ztabbegintabcell} % material for a cell will follow here and be ended by % either a @ command or \nl, all of which will deposit % \ztabendtabcell. The @ commands will begin another tab cell and % \nl will also finish all of the groups started by % \ztabmaketabbedline and put out the line. \def \ztabbegintabcell {% % \zboxc contains an hbox as the current cell of tabbed material. % (It is deposited at the end of \ztabendtabcell.) \setbox\zboxc\hbox% \bgroup% opens group closed in \ztabendtabcell \ignorespaces} \def \ztabendtabcell {% \if \ztabatnlp % Processing last cell in this row. Close group opened in % \ztabbegintabcell w/o bothering to re-set tabboxes. \egroup \else % Close this cell's group (opened in \ztabbegintabcell) with \hss, % since this is not the last cell. \hss\egroup % "Pop" current tabbox from \ztabstbdbox, measure it, deposit tabbed % material into properly sized box and then "push" tabbox onto \ztabsdonebox % "Pop" from the end of \ztabstbdbox using \lastbox into \zboxb \global\setbox\ztabstbdbox\hbox{% \unhbox\ztabstbdbox \global\setbox\zboxb\lastbox}% % Process the current tabbox \ifvoid\zboxb \if \ztabtabbingp \zzerror{Attempt to tab (with \string@>) past set tabs}% \else % The current tabbox is void, so we set it to a box that is the % natural width of \zboxc (which contains the cell material). \global\setbox\zboxb\hbox to\wd\zboxc{}% \fi \else \if \ztabsettingp % Re-set previously stored tabbox to natural width of the cell (\zboxc) \global\setbox\zboxb\hbox to\wd\zboxc{}% \fi % Re-deposit the cell material into \zboxc using the width of the % current tabbox. \setbox\zboxc\hbox to\wd\zboxb{\unhbox\zboxc}% \fi % "Push" the current tabbox measure onto the \ztabsdonebox set of boxes. % (Note that this might have come from \ztabstbdbox or been measured from % \zboxc if there were no more tabboxes, so this is where an "on-the-fly" % tab is added to \ztabsdone, which will later be copied back into % \ztabsbox for the next line.) \global\setbox\ztabsdonebox\hbox{\box\zboxb\unhbox\ztabsdonebox}% \fi % Clear conditional variables \ztabsettingfalse \ztabtabbingfalse % emit box for this cell \box\zboxc} \def \ztabadjusttabbing #1{% {vertical-mode material} % Close and discard currently open tabbed line (empty, but started % by end of previous line). \ztabcmddiscard \ztabparfinishpreviousline % Insert vertical material #1\relax % If in verbatimlines must set this line to be discarded by % the newline which ends the \adjusttabbing{...} line, which will also % start the next line. \if \verbatimlines \ztabdiscardtrue \fi % Start next tabbed line \ztabparstartnextline} % Builtin Text Blocks % ------- ---- ------ % The following text block formats text in a completely normal fashion. % It can be used with \with to make small changes to the text format. \def \textnormalidesign {% \calculate \aboveskip = {\enclosingbaselineskip,+,\enclosingparskip}% \belowskip = \aboveskip \bodyfont = {}% \leftindent = \enclosingleftss \parindent = \enclosingparindent \parrag = \enclosingparrag \parskip = \enclosingparskip \rightindent = \enclosingrightss \setflag \verbatimlines = \false \width = \naturalwidth} \def \textnormaliidesign {% \textnormalidesign} \def \textnormaliiidesign {% \textnormalidesign} \def \textnormalivdesign {% \textnormalidesign} \def \setflushingleft {% \leftindent = 0pt \parfillskip = \normalparfillskip \parindent = 0pt \rightindent = 0pt \width = \naturalwidth} % This text block centers text relative to the current left and right % indentation. \def \textcenteridesign {% \textnormalidesign \setcentering} \def \textcenteriidesign {% \textcenteridesign} \def \textcenteriiidesign {% \textcenteridesign} \def \textcenterivdesign {% \textcenteridesign} \def \setcentering {% \leftindent = \centerindent \parfillskip = 0pt \parindent = 0pt \rightindent = \centerindent \width = \naturalwidth} % This text block positions text flush right. \def \textflushrightidesign {% \textnormalidesign \setflushingright} \def \textflushrightiidesign {% \textflushrightidesign} \def \textflushrightiiidesign {% \textflushrightidesign} \def \textflushrightivdesign {% \textflushrightidesign} \def \setflushingright {% \leftindent = \centerindent \parfillskip = 0pt \parindent = 0pt \rightindent = 0pt \width = \naturalwidth} % This text block squares off the last line of paragraphs. \def \textflushendidesign {% \textnormalidesign \parfillskip = 0pt} \def \textflushendiidesign {% \textflushendidesign} \def \textflushendiiidesign {% \textflushendidesign} \def \textflushendivdesign {% \textflushendidesign} \def \flushendpar {% \zskipa = \parfillskip \parfillskip = 0pt \par \parfillskip = \zskipa} % This text block sets text in the full type width. \def \texttypeareaidesign {% \textnormalidesign \leftindent = -\oddlefttextmargin \width = \typeareawidth} \def \texttypeareaiidesign {% \texttypeareaidesign} % This command centers a single line or sets multiple lines in block format. \def \centerorblockpar #1#2{% {width}{text} \measuretextwidth{\tdimena}{#2}% \if \dimlssp{\tdimena}{#1}% \centerline{#2}% \else \noindent #2\par \fi} % Code Block % ---- ----- \defineblock{\code}{\endcode}{\false}{} %~block code Type % \abovepenalty = integer % Penalty above code. % \aboveskip = glue % Space b/b above code. % \setflag \allowbreaks = boolean % Page breaks allowed? % \setflag \allowatsigncommands = boolean % Allow at-sign commands. % \setflag \allowcallouttag = boolean % Allow \tag for callout numbers. % \setflag \allowTeXcommands = boolean % Allow commands with \ { } % \setflag \allowTeXmath = boolean % Allow math with $ _ ^ % \setflag \autocallout = boolean % Automatically number lines? % \def \beginformat {...} % Beginning of code formatter. % \belowpenalty = integer % Penalty below code. % \belowskip = glue % Space b/b below code. % \bodyfont = {...} % Font for text. % \def \calloutformat ##1{...} % Callout formatter. % \calloutnumber = integer % Number of first callout. % \def \callouttext {...} % Callout text or \arg. % \codegapskip = glue % Standard code gap (see \codegap). % \def \endformat {...} % End of code formatter. % \hfuzz = dimen % Amount text can exceed \hsize. % \indentcolumns = integer % Standard indentation amount. % \leftindent = glue % Left indentation. % \metafont = {font} % Font for metasyntactic names. % \rightindent = glue % Right indentation. % \textcolor = {...} % Color of text. % \setflag \verbatimchars = flag % Take all characters verbatim? % \setflag \verbatimspaces = flag % Take all spaces verbatim? % \width = dimen % Width of code. %~end \defineskip{\codegapskip}{0pt} \definecount{\indentcolumns}{0} \definetoks{\metafont} \definecount{\codelinenumber}{0} \definecount{\zcodehyph}{0} % To remember hyphen character. \def \code #1{% {type} \blockcantbein{\code}{\code}% \beginblockscope{code}% \global\increment \codedepth \abovepenalty = \breakgood %~default hard \setflag \allowatsigncommands = \false %~default soft \setflag \allowcallouttag = \false %~default soft \setflag \allowTeXcommands = \true %~default soft \setflag \allowTeXmath = \false %~default soft \setflag \autocallout = \false %~default soft \def \beginformat {}% %~default soft \belowpenalty = \breakbetter %~default hard \calloutnumber = 1 %~default with \def \callouttext {\number\calloutnumber}% %~default soft \codegapskip = \mindimen %~default soft \def \endformat {}% %~default soft \indentcolumns = 3 %~default soft \textcolor = {}% %~default soft \setflag \verbatimchars = \true %~default soft \setflag \verbatimspaces = \true %~default soft \codelinenumber = 1\relax \processdesign{\code}{#1}% \global\increment \codenumber \codeformat \let \par = \zcodepar \obeylines \if \verbatimspaces \obeyspaces \fi \let \zrealincl = \include \let \include = \zcodeincl \let \zrealfn = \footnote \let \footnote = \zcodefn \def \zarg {\arg}% \if \tokeqlp{\callouttext}{\zarg}% \def \!{\zcodecoformat}% \else \def \!{\zcodecoformat{\callouttext}}% \fi \settaginfo{}{}% % No tag information so far. \if \notp{\emptytoksp{\textcolor}}\color{\the\textcolor}\fi \begingroup % So we can undo the following things. \if \autocallout \everyparagraph = {\!}\fi \if \verbatimchars \uncatcode{\allowTeXcommands}{\allowatsigncommands}{\allowTeXmath} \fi \zcodeflushline} {\catcode`\^^M = \catactive \gdef \zcodeflushline #1^^M{}% \gdef \endcode^^M{% %%% \columnbreak{\breakallowed}% % Allow break after last line. \endgroup % Undo the \uncatcode, \if \notp{\emptytoksp{\textcolor}}\endcolor \fi% \futurelet\nexttoken \zendcode}% % and grab onto the next character. } % \catcode \def \zendcode {% \hyphenchar\font = \zcodehyph \setlist \zcodeadjlist = {}% \endformat \forcenextpenalty \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}% \global\decrement \codedepth \endblockscope{code}% \parnext} \def \codeformat {% \endgraf \alterindentation{\leftindent}{\rightindent}% \settextwidth{\width}% \setparrag{0pt}% \the\bodyfont \zcodehyph = \hyphenchar\font \hyphenchar\font = -1 \parskip = 0pt \parindent = 0pt \bbskipabove{\abovepenalty}{\aboveskip} \beginformat} \def \zcodepar {% \increment \codelinenumber \if \hmodep \endgraf \if \notp{\allowbreaks}\nobreak \relax \fi \zchkcodeadj \else \if \notp{\allowbreaks}\nobreak \relax \fi \zchkcodeadj \vskip \baselineskip \fi} % This macro allows the compositor to noninvasively adjust pages between % lines of code. \setlist \zcodeadjlist = {} \long\def \codeadjustment #1#2{% {line-number}{commands} \append{{#1}{#2}}{\zcodeadjlist}} \long\def \zchkcodeadj {% \maplist{\zchkcodeadjb##1}{\zcodeadjlist}} \long\def \zchkcodeadjb #1#2{% {line-number}{commands} \if \eqlp{#1}{\codelinenumber}% #2\relax \fi} \def \zcodecoformat #1{% {text} \ensurepar {\ztoksa = {}% \zcodecocln #1\zmark \calloutformat{\the\ztoksa}}% \if \allowcallouttag \settaginfo{#1}{???}\fi \global\increment \calloutnumber} \def \zcodecocln #1#2\zmark{% \ifx #1\ \else \ztoksa = \expandafter{\the\ztoksa#1}\fi \if \notp{\emptyargp{#2}}\zcodecocln #2\zmark \fi} % Code Tools % ---- ----- %~ This command is used to place a math expression in a %~ code block that doesn't allow dollar signs. \def \codemath {% $math$ %^code $% \catcodemath \let \znext = } % Discard opening $. %~ This command produces a vertical ellipsis in code, %~ with optional text explaining the omission. \def \codeellipsis #1{% {text} %^code \ensurepar {\lower .85\baselineskip \hbox{% \vbox{\baselineskip = .5\baselineskip \lineskiplimit = 0pt \kern \baselineskip \hbox{.}\hbox{.}\hbox{.}\kern \baselineskip}}% \unbreakable\quad {\the\metafont #1}}}% {\catcode`\^^M = \catactive % The \include macro is redefined to use this version, which eats % the newline at the end of the line. \gdef \zcodeincl #1^^M{\zrealincl{#1}}% % The \footnote macro is redefined so that it turns off \obeylines. \gdef \zcodefn {% \bgroup% \let ^^M = \space% \zcodefnb}% \gdef \zcodefnb #1{% \zrealfn{#1}% \egroup}% %~ This command allows a vertical adjustment between two lines %~ of code. A typical use would be %~ \adjustcode{\fullpagebreak} \gdef \adjustcode #1#2^^M{#1}% {command} %^code %~ Blank lines in code should be produced with this command. %~ A regular blank line produces too much space. \gdef \codegap #1^^M{% %^code \if \dimnegp{\codegapskip}% \vspace{\baselineskip}% \else% \vspace{\codegapskip}% \fi}% } % \catcode % Code Fragment % ---- -------- %~ A "code fragment" is a short sequence of program code in the running text. %~ Most books use |\mono|, which is defined in terms of this command. \def \codefragment #1#2#3#4{% {prefix}{suffix}{font}{text} {#1% \measurespacewidth{\tdimena}% #3% \if \monoencodingp \spaceskip = 1.2\tdimena \fi \relax #4% #2}} % Multicolumn Block % ----------- ----- \defineblock{\multicolumn}{\endmulticolumn}{\false}{} %~block multicolumn Type % \abovepenalty = integer % Penalty above block. % \aboveskip = glue % Visual space above block. % \belowpenalty = integer % Penalty below block. % \belowskip = glue % Visual space below block. % \brokenpenalty = penalty % For hyphenation at bottom of column. % \columngutter = dimen % Width of column gutter. % \columnrulecolor = {color} % Color of rule separating columns. % \columnrulewidth = dimen % Width of rule. % \columns = integer % Number of columns. % \setflag \flushbottom = flag % Should bottoms be flush? % \leftindent = glue % Indentation for left edge. % \margins = {left,right,top,bottom} % Four margins. % \parrag = dimen % Paragraph raggedness. % \setflag \preservelistdepth = flag % Preserve list depth? % \siderulecolor = {color} % Color of rules on sides. % \siderulewidth = dimen % Width of rules. % \vshift = dimen % Vertical shift for entire element. % \width = dimen % Width of each column. %~end \definetoks{\columnrulecolor} \definedimen{\columnrulewidth}{0pt} \definecount{\columns}{0} \definetoks{\margins} \definetoks{\siderulecolor} \definedimen{\siderulewidth}{0pt} \definebox{\zmctext} \definecount{\zmccolumn}{0} \definecount{\zentrylistdepth}{0} \definebox{\zmccoli} \definebox{\zmccolii} \definebox{\zmccoliii} \definebox{\zmccoliv} \definebox{\zmccolv} \definebox{\zmccolvi} \definebox{\zmccolvii} \definebox{\zmccolviii} \definedimen{\zmcmaxht}{0pt} \definebox{\zmcbox} \def \multicolumn #1{% {type} \beginblockscope{multicolumn}% \global\increment \multicolumndepth \abovepenalty = \breakgood %~default hard \belowpenalty = \breakgood %~default hard \brokenpenalty = \breaknever %~default soft \setflag \preservelistdepth = \false %~default soft \vshift = 0pt %~default soft \processdesign{\multicolumn}{#1}% \global\increment \multicolumnnumber \expandafter\zmcparse \the\margins\zmark \setbox \zmctext = \vtop\bgroup \zentrylistdepth = \listdepth \zpushvcontext \if \preservelistdepth \global\listdepth = \zentrylistdepth \fi \settextwidth{\width}% \setparrag{\parrag}} \def \endmulticolumn {% \endgraf \zpopvcontext \egroup % \vtop \zbuildmc \global\decrement \multicolumndepth \endblockscope{multicolumn}} \def \zbuildmc {% \splitmaxdepth = \dp\strutbox \vbadness = 10000 % Do we want this? \setbox \zmctext = \vbox{% \vskip \splittopskip \vskip -\ht\zmctext \unvbox \zmctext \unskip \unpenalty \unskip}% \zbuildmca \zbuildmcb \bbskipabove{\abovepenalty}{\aboveskip}% \hfuzz=999pc \hindent{\leftindent} \lower \vshift \box\zmcbox \par \prevdepth = 0pt % Nothing better to do. \bbskipbelowblock{\belowpenalty}{\belowskip}} \def \zbuildmca {% \zmccolumn = \columns \zmcmaxht = 0pt \loop \calculate \tdimena = {\ht\zmctext,-,\splittopskip,/,\zmccolumn,+,\splittopskip}% \setbox \name{\zmccol\romannumeral\zmccolumn} = \if \onep{\zmccolumn}\box\zmctext \else \vsplit \zmctext to \tdimena \fi \tdimena = \ht\name{\zmccol\romannumeral\zmccolumn}% \if \dimgtrp{\tdimena}{\zmcmaxht}\zmcmaxht = \tdimena \fi \decrement \zmccolumn \if \posp{\zmccolumn}\repeat} \def \zbuildmcb {% \setbox \zmcbox = \hbox{% \vrule width \siderulewidth \hskip -\siderulewidth \hskip \zmcleft \zmccolumn = \columns \loop \tdimena = \dp\name{\zmccol\romannumeral\zmccolumn}% \setbox \zboxa = \vbox to \zmcmaxht {% \unvbox \name{\zmccol\romannumeral\zmccolumn}% \if \notp{\flushbottom}\vfil \fi \vskip -\tdimena \vskip \zmcbottom}% \calculate \tdimena = {\ht\zboxa,-,\splittopskip}% \lower \tdimena \hbox{\box\zboxa}% \if \gtrp{\zmccolumn}{1}% \hskip .5\columngutter \hskip -.5\columnrulewidth \vrule width \columnrulewidth \hskip -.5\columnrulewidth \hskip .5\columngutter \fi \decrement \zmccolumn \if \posp{\zmccolumn}\repeat \hskip \zmcright \hskip -\siderulewidth \vrule width \siderulewidth}} \def \zmcparse #1,#2,#3,#4\zmark{% \def \zmcleft {#1\relax}% \def \zmcright {#2\relax}% \splittopskip = #3\relax \def \zmcbottom {#4\relax}}