% -*- mode: Noweb; noweb-code-mode: tex-mode -*- \documentstyle[noweb,twoside]{article} \pagestyle{noweb} \noweboptions{longchunks,smallcode} \title{{\TeX} support for {\tt noweb}} \author{Norman Ramsey} \newcommand{\stylehook}{\marginpar{\raggedright\sl Style hook}} \begin{document} \maketitle \tableofcontents @ This document describes the {\TeX} code that supports {\tt noweave} and {\tt noweb}. Those interested in customizing their output should focus on Section~\ref{section:sty}. Hooks you can easily use (apart from those provided by [[\noweboptions]]) are indicated by marginal notes. This file contains both plain {\TeX} and {\LaTeX} support: <>= % nwmac.tex -- plain TeX support for noweb % DON'T read or edit this file! Use ...noweb-source/tex/support.nw instead. <>= % noweb.sty -- LaTeX support for noweb % DON'T read or edit this file! Use ...noweb-source/tex/support.nw instead. @ \section{Basic {\TeX} support for {\tt noweb}} This basic code is used for both {\TeX} and {\LaTeX}. The first step is to define [[\codehsize]], which is the width in which code is set, and [[\codemargin]], which is the amount by which it is indented.\stylehook <>= % make \hsize in code sufficient for 88 columns \setbox0=\hbox{\tt m} \newdimen\codehsize \codehsize=91\wd0 % 88 columns wasn't enough; I don't know why \newdimen\codemargin \codemargin=0pt @ %def \codehsize \codemargin [[\defspace]] is the space we would like on the right of navigational info that appears on definition lines, so that it lines up with the text above and below. <>= \newdimen\nwdefspace \nwdefspace=\codehsize %% \advance\nwdefspace by -\textwidth\relax \advance\nwdefspace by -\hsize\relax @ Most code is set in an environment in which [[\setupcode]] has been executed. In this environment, only [[\]], [[{]], and [[}]] have their usual categories; every other character represents itself. Appropriate [[\chardef]]s ensure that the special characters can be escaped with a backslash. <>= \chardef\other=12 \def\setupcode{% \chardef\\=`\\ \chardef\{=`\{ \chardef\}=`\} \catcode`\$=\other \catcode`\&=\other \catcode`\#=\other \catcode`\%=\other \catcode`\~=\other \catcode`\_=\other \catcode`\^=\other \catcode`\"=\other % fixes problem with german.sty \obeyspaces\Tt } \let\nwlbrace=\{ \let\nwrbrace=\} @ %def \setupcode [[\eatline]] is used to consume newlines that should be ignored, for example, the newlines at the end of [[@ %def ]]{\em identifiers} lines. I can't remember what [[\startline]] or [[\newlines]] are for; I don't think {\tt noweave} ever emits them. <>= {\catcode`\^^M=\active % make CR an active character \gdef\newlines{\catcode`\^^M=\active % make CR an active character \def^^M{\par\startline}}% \gdef\eatline#1^^M{\relax}% } %%% DON'T \gdef^^M{\par\startline}}% in case ^^M appears in a \write \def\startline{\noindent\hskip\parindent\ignorespaces} \def\nwnewline{\ifvmode\else\hfil\break\fi} @ %def \startline \eatline \nwnewline Within a code environment, it may be necessary to restore the category codes in order to set a module (chunk) name. This hack doesn't properly restore [["]] for use in {\tt german.sty}. <>= {\obeyspaces\global\let =\ } % from texbook, p 381 \def\setupmodname{% \catcode`\$=3 \catcode`\&=4 \catcode`\#=6 \catcode`\%=14 \catcode`\~=13 \catcode`\_=8 \catcode`\^=7 \catcode`\ =10 \catcode`\^^M=5 \let\{\nwlbrace \let\}\nwrbrace % bad news --- don't know what catcode to give " \Rm} @ %def \setupmodname @ \sublabel{ref:fred} {\tt noweave} brackets uses of chunk names with [[\LA]] and [[\RA]], which handle the angle brackets, font, and environment. As it stands, chunk names can be broken across lines (or pages). This could result in unnecessary page breaks in code (c.f.~p.~\pageref{sec:pagebreaking}). [[\let\\maybehbox=\mbox]] to \stylehook avoid breaking them (or to make them work in math mode); this is done in code chunks, but could be done in general. <>= \def\LA{\begingroup\maybehbox\bgroup\setupmodname\It$\langle$} \def\RA{\/$\rangle$\egroup\endgroup} \def\code{\leavevmode\begingroup\setupcode\newlines} \def\edoc{\endgroup} \let\maybehbox\relax @ %def \LA \RA \maybehbox [[\equivbox]] and [[\plusequivbox]] are used to set the ``\unhcopy\equivbox'' and ``\unhcopy\plusequivbox'' that open a chunk definition or its continuation. {\tt noweave} brackets definitions of chunk names with [[\moddef]] and either [[\endmoddef]] or [[\plusendmoddef]]. <>= \newbox\equivbox \setbox\equivbox=\hbox{$\equiv$} \newbox\plusequivbox \setbox\plusequivbox=\hbox{$\mathord{+}\mathord{\equiv}$} % \moddef can't have an argument because there might be \code...\edoc \def\moddef{\leavevmode\kern-\codemargin\LA} \def\endmoddef{\RA\ifmmode\equiv\else\unhcopy\equivbox\fi \nobreak\hfill\nobreak} \def\plusendmoddef{\RA\ifmmode\mathord{+}\mathord{\equiv}\else\unhcopy\plusequivbox\fi \nobreak\hfill\nobreak} @ %def \equivbox \plusequivbox \moddef \endmoddef \plusendmoddef @ Within a code environment, margin tags might be used to mark sub-page numbers in the margins, separated by [[\nwmarginglue]].\stylehook The interaction with [[\moddef]] involves tricky kerning. The tag itself is displayed using [[\nwthemargintag]] <>= \def\nwopt@nomargintag{\let\nwmargintag=\@gobble} \def\nwopt@margintag{% \def\nwmargintag##1{\leavevmode\llap{##1\kern\nwmarginglue\kern\codemargin}}} \def\nwopt@margintag{% \def\nwmargintag##1{\leavevmode\kern-\codemargin\nwthemargintag{##1}\kern\codemargin}} \def\nwthemargintag#1{\llap{#1\kern\nwmarginglue}} \nwopt@margintag \newdimen\nwmarginglue \nwmarginglue=0.3in @ %def \nwmargintag margintag nomargintag \nwmarginglue \iffalse <>= .TP .B margintag Put the sub-page number (tag) of each code-chunk definition in the left margin. (Default) .TP .B nomargintag Don't use margin tags. @ \fi [[\nwtagstyle]] determines the style in which tags are displayed.\stylehook <>= \def\nwtagstyle{\footnotesize\Rm} @ <>= \def\chunklist{% \errhelp{I changed \chunklist to \nowebchunks. I'll try to avoid such incompatible changes in the future.}% \errmessage{Use \string\nowebchunks\space instead of \string\chunklist}} \def\nowebchunks{\message{}} \def\nowebindex{\message{}} @ %def \chunklist \nowebchunks \nowebindex @ We have to be careful with font-changing in the presence of different font-selection schemes. In the \LaTeX{} New Font Selection Scheme something like [[\it\tt]] will attempt to use an italic typewriter font. Thus we define new commands like [[\Tt]] which will work with both the Plain and old and new \LaTeX{} schemes. (Note that NFSS will be standard in the next version of \LaTeX.) A problem with these definitions arises with NFSS: in math mode the won't work unless the {\tt oldlfont} backwards-compatibility option is in effect. For the moment, you can get round this by using [[\mbox]]. If you wanted code set in a different font, you could re-define [[\Tt]].\stylehook{} [\LaTeX2e actually behaves like OFSS, but the extra [[\reset@font]] does no harm.] <>= % here is support for the new-style (capitalized) font-changing commands % thanks to Dave Love \ifx\documentstyle\undefined \let\Rm=\rm \let\It=\it \let\Tt=\tt % plain \else\ifx\selectfont\undefined \let\Rm=\rm \let\It=\it \let\Tt=\tt % LaTeX OFSS \else % LaTeX NFSS \def\Rm{\reset@font\rm} \def\It{\reset@font\it} \def\Tt{\reset@font\tt} \def\Bf{\reset@font\bf} \fi\fi \ifx\reset@font\undefined \let\reset@font=\relax \fi @ %def \Rm \Tt \It \Bf @ \clearpage \section{The {\tt noweb} document-style option for {\LaTeX}} \label{section:sty} {\LaTeX} support begins with the kernel shown above. <>= <> @ \subsection{Support for noweb options} <>= \def\noweboptions#1{% \def\@nwoptionlist{#1}% \@for\@nwoption:=\@nwoptionlist\do{% \@ifundefined{nwopt@\@nwoption}{% \@latexerr{There is no such noweb option as '\@nwoption'}\@eha}{% \csname nwopt@\@nwoption\endcsname}}} @ %def \noweboptions \subsection{Adjusting placement of code on the page} {\LaTeX} requires a larger [[\codehsize]] because code is indented by [[\codemargin]].\stylehook <>= \codemargin=10pt \advance\codehsize by \codemargin % make room for indentation of code \advance\nwdefspace by \codemargin % and fix adjustment for def/use @ [[\noweboptions{shift}]] is used to shift the whole page left to make room for the wide code lines. It may be emitted by {\tt noweave -shift}, or it might be given by a user. <>= \def\nwopt@shift{% \dimen@=-0.8in \if@twoside % Values for two-sided printing: \advance\evensidemargin by \dimen@ \else % Values for one-sided printing: \advance\evensidemargin by \dimen@ \advance\oddsidemargin by \dimen@ \fi % \advance \marginparwidth -\dimen@ } \let\nwopt@noshift\@empty @ %def shift noshift \iffalse <>= .TP .B shift Shift text to the left so that long code lines won't extend off the right-hand side of the page. @ \fi \subsection{Page-breaking strategy}\label{sec:pagebreaking} We want to insert penalties aiming for: \begin{enumerate} \item No page breaks in the middle of a code chunk unless necessary to avoid an overfull vbox; \item Documentation immediately preceding a code chunk should appear on the same page as that code chunk unless doing so would violate rule 1. \end{enumerate} [[\filbreak]] is useful for this sort of thing (see {\em The \TeX book\/}) and is used to encourage breaks at the right places between chunks. Appropriate penalties are inserted elsewhere, between code lines in particular. \subsection{Environments for setting code} [[\nwbegincode]] and [[\nwendcode]] are used by {\tt noweave} to bracket code chunks. The [[webcode]] environment is intended for users who want to paste {\tt noweave} output into papers. The definition of [[\nwbegincode]] is based on the verbatim implementation in {\tt verbatim.sty}, which will, presumably be in the next version of \LaTeX\@. One thing it does differently, apart from the catcode changes is setting [[\linewidth]]; this will avoid some overfull hboxen when the code lines are too long, but the lines won't be broken anyhow (even within chunk names because of the [[\maybehbox]] definition). <>= \def\nwbegincode#1{% \begingroup <<[[\nwbegincode]] separation and penalties>> \@begincode } \def\nwendcode{\endtrivlist \endgroup \filbreak} % keeps code on 1 page \newenvironment{webcode}{% \@begincode }{% \endtrivlist} @ %def \nwbegincode \nwendcode webcode @ This is just common code between [[\nwbegincode]] and [[webcode]]. <>= \def\@begincode{% <<[[\trivlist]] clich\'e (\`a la {\Tt verbatim})>> \linewidth\codehsize <<[[\obeylines]] setup>> <> \nowebsize \setupcode \let\maybehbox\mbox } @ %def \@begincode @ \iffalse <>= .TP .B smallcode Set code in .I LaTeX .B "\\\\small" font instead of .B "\\\\normalsize." @ \fi @ [[\nowebsize]] governs the size at which code is set; users who want to minimize code can [[\let\nowebsize=\small]]. Slitex users should try \begin{quote} [[\def\nowebsize{\normalsize\baselineskip=20pt \parskip=5pt }]] \end{quote} to avoid code lines that are too far apart. [[\nwcodetopsep]] is the glue placed before code chunks.\stylehook <>= \newskip\nwcodetopsep \nwcodetopsep = 3pt plus 1.2pt minus 1pt \let\nowebsize=\normalsize \def\nwopt@smallcode{\let\nowebsize=\small} @ %def \nwcodetopsep \nowebsize smallcode @ Maybe the penalties ought to be parameters\dots <<[[\nwbegincode]] separation and penalties>>= \topsep \nwcodetopsep \@beginparpenalty \@highpenalty \@endparpenalty -\@highpenalty @ The [[\trivlist]] clich\'e isn't quite a clich\'e because we adjust [[\leftskip]] for indentation by [[\codemargin]] and adjust [[\rightskip]] to allow lines up to [[\codehsize]] long without overfull boxen ($\mbox{[[\codehsize]]}=\mbox{[[\hsize]]}+\mbox{[[\rightskip]]}$). Note that [[\hsize]] isn't altered. <<[[\trivlist]] clich\'e (\`a la {\Tt verbatim})>>= \trivlist \item[]% \leftskip\@totalleftmargin \advance\leftskip\codemargin \rightskip\hsize \advance\rightskip -\codehsize \parskip\z@ \parindent\z@ \parfillskip\@flushglue @ The penalty inserted between verbatim lines would normally be [[\interlinepenalty]], but we want to prohibit breaks there. @ Note the bug lurking somewhere in this code, as reported by Steven Ooms: \begin{quote} I have some lay-out problems in the documentation chunks. When using the (La)TeX commands [[\hline]] or [[\vtop]] the right margin is always extended far beyond the page margin after the first code chunk has been typeset. I'm still looking for the exact cause of it, but to me it seems that LaTeX supposes for those commands that the line width for the documentation chunk is as large as that for code chunks, which isn't true in reality. \end{quote} @ <<[[\obeylines]] setup>>= \@@par \def\par{\leavevmode\null \@@par \penalty\nwcodepenalty}% \obeylines @ [[\nwcodepenalty]] is the penalty for breaking between lines in a code chunk. If you set it to 10000, code will never be broken across pages.\stylehook{} I guess this should be settable in [[\noweboptions]]. <>= \newcount\nwcodepenalty \nwcodepenalty=\@highpenalty @ %def \nwcodepenalty The cursing chunk accounts for the addition of a mess of characters to those reset by [[\@noligs]] in \LaTeX2e. <>= \@noligs <> \setupcode \frenchspacing \@vobeyspaces @ We can't make [[`]] ``other,'' because then we'll get ligatures. (Why Don put these ligatures in the [[\tt]] font I wish I knew.) But we'll step on all the others. <>= \ifx\verbatim@nolig@list\undefined\else \let\do=\nw@makeother \verbatim@nolig@list \do@noligs\` \fi <>= \def\nw@makeother#1{\catcode`#1=12 } @ {\tt noweave} uses [[\nwbegindocs{nnn}]] and [[\nwenddocs]] to bracket documentation chunks. If a documentation chunk does not continue the current paragraph, {\tt noweave} inserts [[\nwdocspar]], which uses [[\filbreak]] in an attempt to keep the documentation chunk on the same page as the code chunk that follows it. (The code chunk will have another [[\filbreak]] after it---see [[\nwbegincode]].) [[\nwbegindocs]] doesn't start a new paragraph if the previous chunk didn't end one, i.e.\ didn't enter vmode; if it does start a new one, it's only indented by the use of [[\nwdocspar]]. <>= \def\nwbegindocs#1{\ifvmode\noindent\fi} \let\nwenddocs=\relax \let\nwdocspar=\filbreak @ %def \nwbegindocs \nwdocspar \nwenddocs The page-breaking strategy implies ragged bottom pages, so we should turn it on in general (this is relevant for the {\tt report} style): <>= \raggedbottom <>= \def\nwdocspar{\par\semifilbreak} @ {\tt noweave} doesn't bracket quoted code with [[\code]] and [[\edoc]] any more. It probably should do something nifty, just to make {\TeX} hackers happy, but it doesn't. <>= \def\code{\leavevmode\begingroup\setupcode\@vobeyspaces\obeylines} \let\edoc=\endgroup @ \subsection{The {\tt noweb} page style} Headers contain file name, date, and page number. {\tt noweave} emits [[\nwfilename{]]{\em name}[[}]] for each new file. In the {\tt noweb} page style, new files cause page breaks; otherwise they are ignored. <>= \newdimen\@original@textwidth \def\ps@noweb{% \@original@textwidth=\textwidth \let\@mkboth\@gobbletwo \def\@oddfoot{}\def\@evenfoot{}% No feet. \if@twoside % If two-sided printing. \def\@evenhead{\hbox to \@original@textwidth{% \Rm \thepage\qquad{\Tt\leftmark}\hfil\today}}% Left heading. \def\@oddhead{\hbox to \@original@textwidth{% \Rm \today\hfil{\Tt\leftmark}\qquad\thepage}}% Right heading. \else % If one-sided printing. \def\@oddhead{\hbox to \@original@textwidth{% \Rm \today\hfil{\Tt\leftmark}\qquad\thepage}}% Right heading. \let\@evenhead\@oddhead \fi \let\chaptermark\@gobble \let\sectionmark\@gobble \let\subsectionmark\@gobble \let\subsubsectionmark\@gobble \let\paragraphmark\@gobble \let\subparagraphmark\@gobble \def\nwfilename{\begingroup\let\do\@makeother\dospecials \catcode`\{=1 \catcode`\}=2 \nw@filename} \def\nw@filename##1{\endgroup\markboth{##1}{##1}\let\nw@filename=\nw@laterfilename}% } \def\nw@laterfilename#1{\endgroup\clearpage \markboth{#1}{#1}} \let\nwfilename=\@gobble @ %def \@original@textwidth \ps@noweb \nwfilename @ \subsection{Chunk cross-reference} [[\nwalsodefined]], [[\nwused]], and [[\nwnotused]] are emitted by the {\tt noweb} cross-referencers. (What arguments?) If unused chunks are output chunks, a filter can slip in [[\let\nwnotused\nwoutput]]. The style uses [[\nwcodecomment]] for all annotations that follow code chunks. Fiddling with it can change the appearance of the output. Note that [[\nwcodecomment]] is used after [[\nwbegincode]], with [[\obeylines]] in efect. Since linebreaking can occur here, we need to change the [[\interlinepenalty]]. A little vertical space ([[\nwcodecommentsep]]\stylehook) appears before the first comment. We firkled with [[\rightskip]] in [[\nwbegincode]] above; now we want to reset it so that paragraphs are the normal width ([[\textwidth]], possibly less [[\codemargin]]) and set ragged right. This is done as usuall by making [[\rightskip]] naturally zero but stretchable. <>= \def\nwcodecomment#1{\@@par\penalty\nwcodepenalty <>% \hspace{-\codemargin}{% \rightskip=0pt plus1in \interlinepenalty\nwcodepenalty \let\\\relax\footnotesize\Rm #1\@@par\penalty\nwcodepenalty}} @ %def \nwcodecomment This stuff is used at the end of a chunk. <>= \def\@nwalsodefined#1{\nwcodecomment{This definition is continued \nwpageprep\ \@pagesl{#1}.}} \def\@nwused#1{\nwcodecomment{This code is used \nwpageprep\ \@pagesl{#1}.}} \def\@nwnotused#1{\nwcodecomment{Root chunk (not used in this document).}} \def\nwoutput#1{\nwcodecomment{This code is written to file {\Tt \@stripstar#1*\stripped}.}} \def\@stripstar#1*#2\stripped{#1} @ %def \nwalsodefined \nwused \nwnotused \nwoutput <>= \if@firstnwcodecomment \vskip\nwcodecommentsep\penalty\nwcodepenalty\@firstnwcodecommentfalse \fi @ This stuff on the definition line. Note the hooks\stylehook{} for pointer styles. <>= \newcommand{\nwprevdefptr}[1]{% \mbox{$\mathord{\triangleleft}\,\mathord{\mbox{\subpageref{#1}}}$}} \newcommand{\nwnextdefptr}[1]{% \mbox{$\mathord{\mbox{\subpageref{#1}}}\,\mathord{\triangleright}$}} \newcommand{\@nwprevnextdefs}[2]{% {\nwtagstyle \ifx\relax#1\else ~~\nwprevdefptr{#1}\fi \ifx\relax#2\else ~~\nwnextdefptr{#2}\fi}} \newcommand{\@nwusesondefline}[1]{{\nwtagstyle~~(\@pagenumsl{#1})}} \newcommand{\@nwstartdeflinemarkup}{\nobreak\hskip 1.5em plus 1fill\nobreak} \newcommand{\@nwenddeflinemarkup}{\nobreak\hskip \nwdefspace minus\nwdefspace\nobreak} @ And here are the options we use to choose one or the other. <>= \def\nwopt@longxref{% \let\nwalsodefined\@nwalsodefined \let\nwused\@nwused \let\nwnotused\@nwnotused \let\nwprevnextdefs\@gobbletwo \let\nwusesondefline\@gobble \let\nwstartdeflinemarkup\relax \let\nwenddeflinemarkup\relax } \def\nwopt@shortxref{% \let\nwalsodefined\@gobble \let\nwused\@gobble \let\nwnotused\@gobble \let\nwprevnextdefs\@nwprevnextdefs \let\nwusesondefline\@nwusesondefline \let\nwstartdeflinemarkup\@nwstartdeflinemarkup \let\nwenddeflinemarkup\@nwenddeflinemarkup } \nwopt@shortxref % to hell with backward compatibility! @ \iffalse <>= .TP .B longxref, shortxref Use either long, Knuth-style chunk cross-reference, or short, Hanson-style chunk cross-reference. The former uses small paragraphs after the chunk; the latter uses symbols on the definition line. Defaults to .B shortxref. @ \fi <>= \newskip\nwcodecommentsep \nwcodecommentsep=3pt plus 1pt minus 1pt \newif\if@firstnwcodecomment\@firstnwcodecommenttrue @ \subsection{Page ranges} The goal is to combine sub-page numbers in a way that makes sense. Multiple sub-pages of one page become that page, and individual pages are combined into ranges. (A range may be only one page.) <>= \newcount\@nwlopage\newcount\@nwhipage % range lo..hi-1 \newcount\@nwlosub % subpage of lo \newcount\@nwhisub % subpage of hi \def\@nwfirstpage#1#2{% subpage page \@nwlopage=#2 \@nwlosub=#1 \advance\@nwpagecount by \@ne <<$\mbox{[[\@nwhipage]]} := \mbox{[[\@nwlopage]]}+1$>>} \def\@nwnextpage#1#2{% subpage page \ifnum\@nwhipage=#2 \advance\@nwhipage by \@ne \advance\@nwpagecount by \@ne \@nwhisub=#1 \else \ifnum#2<\@nwlopage <>\else \ifnum#2>\@nwhipage <>\else \@nwlosub=0 \@nwhisub=0 \fi\fi\fi } <>= <>\@nwfirstpage{#1}{#2} <<$\mbox{[[\@nwhipage]]} := \mbox{[[\@nwlopage]]}+1$>>= \@nwhipage=\@nwlopage\advance\@nwhipage by \@ne <>= <>% \edef\@tempa{\noexpand\nwix@cons\noexpand\nw@pages{\@tempa}}\@tempa <>= \advance\@nwhipage by \m@ne \ifnum\@nwhipage=\@nwlopage \edef\@tempa{\noexpand\noexpand\noexpand\\% {\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}}% \else \count@=\@nwhipage \advance\count@ by \m@ne \ifnum\count@=\@nwlopage % consecutive pages \edef\@tempa{\noexpand\noexpand\noexpand\\% {\nwthepagenum{\number\@nwlosub}{\number\@nwlopage}}% \noexpand\noexpand\noexpand\\% {\nwthepagenum{\number\@nwhisub}{\number\@nwhipage}}}% \else <>% \fi \fi <>= \ifnum\@nwlopage<110 <>\else \count@=\@nwlopage \divide\count@ by 100 \multiply\count@ by 100 \ifnum\count@=\@nwlopage <>\else \count@=\@nwlopage \divide\count@ by 100 \@nwpagetemp=\@nwhipage \divide\@nwpagetemp by 100 \ifnum\count@=\@nwpagetemp % lo--least 2 digits of hi \multiply\@nwpagetemp by 100 \advance \@nwhipage by -\@nwpagetemp <>% \else <>% \fi \fi \fi <>= \edef\@tempa{\noexpand\noexpand\noexpand\\{\number\@nwlopage--\number\@nwhipage}} <>= \newcount\@nwpagetemp @ The sequence [[\@pagesl]] makes a range of pages from a list of labels. [[\subpages]] works from a list of [[{{subpage}{page}}]]. <>= \newcount\@nwpagecount \def\@nwfirstpagel#1{% label \@ifundefined{r@#1}{<>}{% \edef\@tempa{\noexpand\@nwfirstpage\subpagepair{#1}}\@tempa}} \def\@nwnextpagel#1{% label \@ifundefined{r@#1}{<>}{% \edef\@tempa{\noexpand\@nwnextpage\subpagepair{#1}}\@tempa}} \def\@pagesl#1{% list of labels \gdef\nw@pages{}\@nwpagecount=0 \def\\##1{\@nwfirstpagel{##1}\let\\=\@nwnextpagel}#1% <>\let\\=\relax \nwpageword\ifnum\@nwpagecount=1 \else s\fi~\commafy{\nw@pages}} \def\@pagenumsl#1{% list of labels -- doesn't include word `pages', commas, or `and' \gdef\nw@pages{}\@nwpagecount=0 \def\\##1{\@nwfirstpagel{##1}\let\\=\@nwnextpagel}#1% <>\def\\{\let\\=~}\nw@pages} \def\subpages#1{% list of {{subpage}{page}} \gdef\nw@pages{}\@nwpagecount=0 \def\\##1{\edef\@tempa{\noexpand\@nwfirstpage##1}\@tempa \def\\####1{\edef\@tempa{\noexpand\@nwnextpage####1}\@tempa}}#1% <>\let\\=\relax \nwpageword\ifnum\@nwpagecount=1 \else s\fi~\commafy{\nw@pages}} \def\@nwaddrange{<>} @ [[\nwpageword]] and [[\nwpageprep]] let you change the wording of the cross-reference information. <>= \def\nwpageword{chunk} % was page \def\nwpageprep{in} % was on <>= <>% \nwix@cons\nw@pages{\\{\bf ??}} @ \subsection{Sub-page references} This is the wonderful code that Dave Love provided to make page references like 7a, 7b, and so on. This code provides a mechanism for defining `page sub-references' using [[\sublabel{foo}]] referenced with [[\subpageref{foo}]]. Sub-references will be numbered like these real examples: \subpageref{ref:foo}, \subpageref{ref:bar}, \subpageref{ref:baz}\sublabel{ref:foo}\sublabel{ref:bar}\sublabel{ref:baz} etc.\ unless there is only one on the page, in which case the letter will be dropped like this: \subpageref{ref:fred}. To be able to use [[\subpageref]] we must define the label with [[\sublabel]], used like label. (Using [[\ref]] with a label defined by [[\sublabel]] will produce the sub-reference number, by the way, and [[\pageref]] works as expected.) Note that [[\subpageref]] is robust and [[\ref]] and [[\pageref]] are redefined to be robust also, as they will be in future \LaTeX{} releases. Incidentally, these expand to the relevant text plus [[\null]]---you might want to strip this off, e.g.\ for sorting lists. There are various ways we could attack this task (which is made non-trivial by the well-known asynchrony of (La)\TeX's output routine), but they all must depend on hacks in the [[.aux]] file or a similar one. Joachim Schrod's [[fnpag.sty]] does the same sort of thing differently to this \LaTeX-specific approach. See [[latex.tex]] for enlightenment on the cross-referencing mechanism and the \LaTeX{} internals used below. [DL: The internals change in \LaTeX2e compared with \LaTeX~2.09. The code here still works, though.] @ The [[\subpageref]] macro first does a normal [[\pageref]]. If the reference is actually defined, it then goes on to check whether the control sequence [[2on]]\LA{}{page referenced}\RA{} is defined and sets the [[\ref]] value to get [[a]] etc.\ if so. The magic, of course, is in defining the [[2on]] bit appropriately. [[\subpageref]] also tries to include the right hyperstuff for xhdvi. <>= \newcommand{\subpageref}[1]{% \nwhyperreference{#1}{% \@ifundefined{r@#1}% {\pageref{#1}}% {\@ifundefined{2on\@pageref{#1}}% {\pageref{#1}}% {\expandafter\expandafter\expandafter\nwthepagenum\csname r@#1\endcsname}}}} @ %def \subpageref [[\subpagepair]] produces a [[{subpage}{page}]] pair. <>= \newcommand{\subpagepair}[1]{% % produces {subpage}{page} \@ifundefined{r@#1}% {{0}{0}}% {\@ifundefined{2on\@pageref{#1}}% {{0}{\expandafter\expandafter\expandafter\@cdr\csname r@#1\endcsname\@nil}}% {\@nameuse{r@#1}}}} @ [[\@pageref]] is like [[\pageref]], but it expands to [[\relax]] without a warning if the reference is undefined. <>= \def\@pageref#1{\expandafter\expandafter\expandafter \@cdr\csname r@#1\endcsname\@nil} @ %def \@pageref @ [[\sublabel]] is like the [[\label]] command, except that it writes [[\newsublabel]] onto the [[.aux]] file rather than [[\newlabel]]. For hyperreferencing, all labels must be hypertext anchors, for which we use [[\nwblindhyperanchor]]. <>= \newcommand{\sublabel}[1]{% \nwblindhyperanchor{#1}% \@bsphack\if@filesw {\let\thepage\relax \def\protect{\noexpand\noexpand\noexpand}% \edef\@tempa{\write\@auxout{\string \newsublabel{#1}{{}{\thepage}}}}% \expandafter}\@tempa \if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack} @ %def \sublabel [[\nosublabel]] creates a label with a sub-page part of~0. <>= \newcommand{\nosublabel}[1]{% \@bsphack\if@filesw {\let\thepage\relax \def\protect{\noexpand\noexpand\noexpand}% \edef\@tempa{\write\@auxout{\string \newlabel{#1}{{0}{\thepage}}}}% \expandafter}\@tempa \if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack} @ %def \sublabel @ [[\newsublabel]] is the macro that does the important work. It is called with the same sort of arguments as [[\newlabel]]: the first argument is the label name and the second is [[{]]\LA ref value[[}{]]page number\RA[[}]]. (Note that the only definition here which needs to be global is the one which is, and that [[\global]] is redefined by [[\enddocument]], which will bite you if you use it\dots) <>= <> @ First we extract the page number into [[\this@page]]. <>= \newcommand{\newsublabel}[2]{% \edef\this@page{\@cdr#2\@nil}% @ %def \newsublabel @ Then we see whether it's changed from the value of [[\last@page]] which was stashed away by the last [[\newsublabel]] (or is [[\relax]] if this is the first one). If the page has changed, we reset the counter [[\sub@page]] telling us how many sub-labels there have been on the page. <>= \ifx\this@page\last@page\else \sub@page=\z@ \fi \edef\last@page{\this@page} \advance\sub@page by \@ne @ If we've had at least two on the page, we define the [[2on]]\LA{}{page no.}\RA{} macro to indicate the fact. <>= \ifnum\sub@page=\tw@ \global\@namedef{2on\this@page}{}% \fi @ Then we write a normal [[\newlabel]] with the sub-reference as the normal reference value in the second argument. <>= \edef\@tempa{\noexpand\newlabel{#1}% {{\number\sub@page}{\this@page}}}% \@tempa} @ We need to define these. <>= \def\last@page{\relax} \newcount\sub@page @ %def \last@page \sub@page @ We use Rainer's new expandable definitions of [[\ref]] and [[\pageref]] to minimise the risk of nasty surprises. <>= % RmS 92/08/14: made \ref and \pageref robust \def\ref#1{\@ifundefined{r@#1}{{\bf ??}<>}% {\expandafter\expandafter\expandafter \@car\csname r@#1\endcsname\@nil\null}} \def\pageref#1{\@ifundefined{r@#1}{{\bf ??}<>}% {\expandafter\expandafter\expandafter \@cdr\csname r@#1\endcsname\@nil\null}} \def\@refpair#1{\@ifundefined{r@#1}{{0}{0}<>}% {\@nameuse{r@#1}}} <>= \@warning{Reference `#1' on page \thepage \space undefined} @ %def \ref \pageref @ Here a a couple of hooks for formatting sub-page numbers, which can be alphbetic, numeric, or omitted.\stylehook <>= \def\@alphasubpagenum#1#2{#2\ifnum#1=0 \else\@alph{#1}\fi} \def\@nosubpagenum#1#2{#2} \def\@numsubpagenum#1#2{#2\ifnum#1=0 \else.\@arabic{#1}\fi} \def\nwopt@nosubpage{\let\nwthepagenum=\@nosubpagenum\nwopt@nomargintag} \def\nwopt@numsubpage{\let\nwthepagenum=\@numsubpagenum} \def\nwopt@alphasubpage{\let\nwthepagenum=\@alphasubpagenum} \nwopt@alphasubpage @ %def \nwthepagenum nosubpage numsubpage alphasubpage \iffalse <>= .TP .B alphasubpage, numsubpage, nosubpage Number chunks by the number of the page on which they appear, followed by an alphabetic (numeric, not used) ``sub-page'' indicator. Defaults to .B alphasubpage. .B nosubpage implies .B nomargintag. @ \fi @ \subsection{{\tt WEB}-like chunk numbering} Here's a righteous hack: we get the effect of WEB-like chunk numbers just by redefining [[\sublabel]] to use a counter instead of the current page number. Since the numbers are all distinct, no sub-page number is ever used. <>= \newcount\nw@chunkcount \nw@chunkcount=\@ne \newcommand{\weblabel}[1]{% \@bsphack\if@filesw {\let\thepage\relax \def\protect{\noexpand\noexpand\noexpand}% \edef\@tempa{\write\@auxout{\string \newsublabel{#1}{{}{\number\nw@chunkcount}}}}% \expandafter}\@tempa \global\advance\nw@chunkcount by \@ne \if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack} \def\nwopt@webnumbering{\let\sublabel=\weblabel\def\nwpageword{chunk}\def\nwpageprep{in}} @ %def \weblabel webnumbering \iffalse <>= .TP .B webnumbering Number chunks consecutively, in .I WEB style, instead of using sub-page numbers. @ \fi @ \subsection{Indexing (identifier cross-reference) support} \subsubsection{Tracking definitions and uses} All index definitions and uses are associated with a label defined with [[\sublabel]] or [[\nosublabel]]. Either the label is the [[\sublabel]] of the code chunk in which the definition or use appears, or it is a [[\nosublabel]] appearing in the middle of a documentation chunk. <>= % \nwindexdefn{printable name}{identifying label}{label of chunk} % \nwindexuse{printable name}{identifying label}{label of chunk} \def\nwindexdefn#1#2#3{\@auxix{\protect\nwixd}{#2}{#3}} \def\nwindexuse#1#2#3{\@auxix{\protect\nwixu}{#2}{#3}} \def\@auxix#1#2#3{% {marker}{id label}{subpage label} \@bsphack\if@filesw {\let\nwixd\relax\let\nwixu\relax \def\protect{\noexpand\noexpand\noexpand}% \edef\@tempa{\write\@auxout{\string\nwixadd{#1}{#2}{#3}}}% \expandafter}\@tempa \if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack} @ %def \nwindexdefn \nwindexuse \@auxix <>= % \nwixadd{marker}{idlabel}{subpage label} \def\nwixadd#1#2#3{% \@ifundefined{nwixl@#2}% {\global\@namedef{nwixl@#2}{#1{#3}}}% {\expandafter\nwix@cons\csname nwixl@#2\endcsname{#1{#3}}}} @ %def \nwixadd @ \subsubsection{Writing lists with commas and ``and''} You get one of \begin{itemize} \item ``$a$'' \item ``$a$ and $b$'' \item ``$a$, $\ldots$, $b$, and $c$'' \end{itemize} Plus [[\\]] is applied to each element of the list. <>= \newcount\@commacount \def\commafy#1{% {\nwix@listcount{#1}\@commacount=\nwix@counter \let\@comma@each=\\% \ifcase\@commacount\let\\=\@comma@each\or\let\\=\@comma@each\or \def\\{\def\\{ and \@comma@each}\@comma@each}\else \def\\{\def\\{, % \advance\@commacount by \m@ne \ifnum\@commacount=1 and~\fi\@comma@each}\@comma@each}\fi #1}} @ %def \@commacount \commafy \subsubsection{New, improved index code} There are two kinds of lists. One kind is a generic list in which elements are preceded by [[\\]]. If the elements are index elements, they are {\em[[{]]printable identifier[[}{]]label[[}]]} pairs. The other kind is a list of sub-page labels, in which each element is preceded by either [[\nwixd]] or [[\nwixu]]. <>= \def\nwix@cons#1#2{% {list}{\marker{element}} {\toks0=\expandafter{#1}\def\@tempa{#2}\toks2=\expandafter{\@tempa}% \xdef#1{\the\toks0 \the\toks2 }}} @ %def \nwix@cons The reference list for an identifier labelled {\em id} is always called [[\nwixl@]]{\em id}. Most applications will work with reference lists by applying [[\\]] either to the defs or to the uses. <>= \def\nwix@uses#1{% {label} \def\nwixu{\\}\let\nwixd\@gobble\@nameuse{nwixl@#1}} \def\nwix@defs#1{% {label} \def\nwixd{\\}\let\nwixu\@gobble\@nameuse{nwixl@#1}} @ %def \nwix@uses \nwix@defs Some applications count uses to see whether there is any need to display information. <>= \newcount\nwix@counter \def\nwix@listcount#1{% {list with \\} {\count@=0 \def\\##1{\advance\count@ by \@ne }% #1\global\nwix@counter=\count@ }} \def\nwix@usecount#1{\nwix@listcount{\nwix@uses{#1}}} \def\nwix@defcount#1{\nwix@listcount{\nwix@defs{#1}}} @ %def \nwix@listcount \nwix@usecount \nwix@defcount @ \subsubsection{Supporting a mini-index at the end of each chunk} When displaying identifiers used, show the identifier and its definitions. <>= \def\nwix@id@defs#1{% index pair {{\Tt \@car#1\@nil}% \def\\##1{~\subpageref{##1}}\nwix@defs{\@cdr#1\@nil}}} \def\nwidentuses#1{% list of index pairs \nwcodecomment{Uses \let\\=\nwix@id@defs\commafy{#1}.}} @ %def \nwidentuses \nwix@id@defs The definitions section is a bit more complex, because it is omitted if none of the identifiers defined is ever used. <>= \def\nwix@totaluses#1{% list of index pairs {\count@=0 \def\\##1{\nwix@usecount{\@cdr##1\@nil}\advance\count@ by\nwix@counter}% #1\global\nwix@counter\count@ }} \def\nwix@id@uses#1#2{% {ident}{label} \nwix@usecount{#2}\ifnum\nwix@counter>0 {\advance\leftskip by \codemargin \nwcodecomment{{\Tt #1}, used \nwpageprep\ \@pagesl{\nwix@uses{#2}}.}}% \else \ifnw@hideunuseddefs\else {\advance\leftskip by \codemargin \nwcodecomment{{\Tt #1}, never used.}}% \fi \fi} \def\nwidentdefs#1{% list of index pairs \ifnw@hideunuseddefs\nwix@totaluses{#1}\else\nwix@listcount{#1}\fi \ifnum\nwix@counter>0 \nwcodecomment{Defines:}% {\def\\##1{\nwix@id@uses ##1}#1}% \fi} <>= \newif\ifnw@hideunuseddefs\nw@hideunuseddefsfalse \def\nwopt@hideunuseddefs{\nw@hideunuseddefstrue} @ \iffalse <>= .TP .B hideunuseddefs Omit defined but unused identifiers from the local identifier cross-reference (Preston Briggs). @ \fi <>= \def\nwopt@noidentxref{% \let\nwidentdefs\@gobble \let\nwidentuses\@gobble} @ \iffalse <>= .TP .B noidentxref Omit the local identifier cross-reference which follows each code chunk. @ \fi \subsubsection{Support for chunk and identifier indices} The index in the back shows absolutely all the pages. <>= \def\nw@underlinedefs{% {list with \nwixd, \nwixu} \let\\=\relax\def\nw@comma{, } \def\nwixd##1{\\\underline{\subpageref{##1}}\let\\\nw@comma}% \def\nwixu##1{\\\subpageref{##1}\let\\\nw@comma}} \def\nw@indexline#1#2{% {\indent {\Tt #1}: \nw@underlinedefs\@nameuse{nwixl@#2}\par}} \newenvironment{thenowebindex}{\parindent=-10pt \parskip=\z@ \advance\leftskip by 10pt \advance\rightskip by 0pt plus1in\par\@afterindenttrue \def\\##1{\nw@indexline##1}}{} @ The information comes from the list [[nwisx@i]]. <>= \def\nowebindex{% \@ifundefined{nwixs@i}% {\@warning{The \string\nowebindex\space is empty}}% {\begin{thenowebindex}\@nameuse{nwixs@i}\end{thenowebindex}}} @ Here's a more efficient version for the external case: <>= \def\nowebindex@external{% {\let\nwixadds@c=\@gobble \def\nwixadds@i##1{\nw@indexline##1}% \def\nwixaddsx##1##2{\@nameuse{nwixadds@##1}{##2}}% \begin{thenowebindex}\@input{\jobname.nwi}\end{thenowebindex}}} @ That list ([[nwisx@i]]) is created by calls to [[\nwixlogsorted{i}]]. <>= \def\nwixlogsorted#1#2{% list data \@bsphack\if@filesw \toks0={#2}\immediate\write\@auxout{\string\nwixadds{#1}{\the\toks0}} \if@nobreak \ifvmode\nobreak\fi\fi\fi\@esphack} @ [[nwixs@c]] and [[nwixs@i]] are sorted lists of chunks and identifiers, respectively. <>= \def\nwixadds#1#2{% \@ifundefined{nwixs@#1}% {\global\@namedef{nwixs@#1}{\\{#2}}}% {\expandafter\nwix@cons\csname nwixs@#1\endcsname{\\{#2}}}} \let\nwixaddsx=\@gobbletwo @ If an external index is used, we need a [[.nwi]] file, [[\nwixadds]] is to be ignored, and we use [[\nwixaddsx]]. <>= \def\nwopt@externalindex{% \ifx\nwixadds\@gobbletwo % already called \else \let\nwixaddsx=\nwixadds \let\nwixadds=\@gobbletwo \let\nowebindex=\nowebindex@external \let\nowebchunks=\nowebchunks@external \fi} @ \iffalse <>= .TP .B externalindex Use an index generated with .I noindex(1) (q.v.). @ \fi @ <>= \def\nowebchunks{% \@ifundefined{nwixs@c}% {\@warning{The are no \string\nowebchunks}}% {\begin{thenowebchunks}\@nameuse{nwixs@c}\end{thenowebchunks}}} \def\nowebchunks@external{% {\let\nwixadds@i=\@gobble \def\nwixadds@c##1{\nw@onechunk##1}% \def\nwixaddsx##1##2{\@nameuse{nwixadds@##1}{##2}}% \begin{thenowebchunks}\@input{\jobname.nwi}\end{thenowebchunks}}} \@namedef{r@nw@notdef}{{0}{(never defined)}} <>= \def\nw@chunkunderlinedefs{% {list of labels with \nwixd, \nwixu} \let\\=\relax\def\nw@comma{, } \def\nwixd##1{\\\underline{\subpageref{##1}}\let\\\nw@comma}% \def\nwixu##1{\\\subpageref{##1}\let\\\nw@comma}} <>= \def\nw@onechunk#1#2#3{% {name}{label of first definition}{list with \nwixd, \nwixu} \@ifundefined{r@#2}{}{% \indent\LA #1~{\nwtagstyle\subpageref{#2}}\RA \if@nwlongchunks{~\nw@chunkunderlinedefs#3}\fi\par}} <>= \newenvironment{thenowebchunks}{\vskip3pt \parskip=\z@\parindent=-10pt \advance\leftskip by 10pt \advance\rightskip by 0pt plus10pt \@afterindenttrue \def\\##1{\nw@onechunk##1}}{} <>= \newif\if@nwlongchunks \@nwlongchunksfalse \let\nwopt@longchunks\@nwlongchunkstrue @ \iffalse <>= .TP .B longchunks When expanding .B "\\\\nowebchunks," show page numbers of definitions and uses of each chunk. @ \fi @ \subsection{support for hypertext with {\tt hyper.sty}} Initial support courtesy of Balasubramanian Narasimhan. <>= \newcommand\nwhyperreference[2]{% \@ifundefined{hyperreference}% {#2\global\let\nwhyperreference\@gobble}% {\hyperreference{#1}{#2}\global\def\nwhyperreference\hyperreference}} \newcommand\nwblindhyperanchor[1]{% \@ifundefined{blindhyperanchor}% {\global\let\nwblindhyperanchor\@gobble}% {\blindhyperanchor{#1}\global\def\nwblindhyperanchor\blindhyperanchor}} @ \subsection{Support for hypertext translation to HTML} <>= \newcommand\nwanchorto{% \begingroup\let\do\@makeother\dospecials \catcode`\{=1 \catcode`\}=2 \nw@anchorto} \newcommand\nw@anchorto[1]{\def\nw@next{#1}\endgroup\nw@anchortofin} \newcommand\nw@anchortofin[1]{#1\footnote{See URL \texttt{\nw@next}.}} \let\nwanchorname\@gobble @ \clearpage \section{The {\tt nwmac} macros for use with plain {\TeX}} First we make [[@]] a letter so that we can use `private' macro names. <>= \catcode`\@=11 <>= % scale cmbx10 instead of using cmbx12 because {\LaTeX} does, so fonts exist \font\twlbf=cmbx10 scaled \magstep1 \font\frtbf=cmbx10 scaled \magstep2 % These fonts don't work with xdvi! \advance\hoffset 0.5 true in \advance\hsize -1.5 true in \newdimen\textsize \textsize=\hsize \def\today{\ifcase\month\or January\or February\or March\or April\or May\or June\or July\or August\or September\or October\or November\or December\fi \space\number\day, \number\year} @ %def \textsize \today <>= \long\def\ifundefined#1#2#3{% \expandafter\ifx\csname#1\endcsname\relax #2% \else#3% \fi} \ifundefined{myheadline} {\headline={\hbox to \textsize{\tentt\firstmark\hfil\tenrm\today\hbox to 4em{\hss\folio}}\hss}} {\expandafter\headline\expandafter{\myheadline}} \ifundefined{myfootline} {\footline={\hfil}} {\expandafter\footline\expandafter{\myfootline}} @ %def \ifundefined <>= \def\semifilbreak{\vskip0pt plus1.5in\penalty-200\vskip0pt plus -1.5in} \raggedbottom @ %def \semifilbreak <>= % % \chapcenter macro to produce nice centered chapter titles % \def\chapcenter{\leftskip=0.5 true in plus 4em minus 0.5 true in \rightskip=\leftskip \parfillskip=0pt \spaceskip=.3333em \xspaceskip=.5em \pretolerance=9999 \tolerance=9999 \hyphenpenalty=9999 \exhyphenpenalty=9999} @ %def \chapcenter <>= % \startsection{LEVEL}{INDENT}{BEFORESKIP}{AFTERSKIP}{STYLE}{HEADING} % #1 #2 #3 #4 #5 #6 % % LEVEL: depth; e.g. part=0 chapter=1 sectino=2... % INDENT: indentation of heading from left margin % BEFORESKIP: skip before header % AFTERSKIP: skip after header % STYLE: style of heading; e.g.\bf % HEADING: heading of the sectino % \def\startsection#1#2#3#4#5#6{\par\vskip#3 plus 2in \penalty-200\vskip 0pt plus -2in \noindent{\leftskip=#2 \rightskip=0.5true in plus 4em minus 0.5 true in \hyphenpenalty=9999 \exhyphenpenalty=9999 #5#6\par}\vskip#4% {\def\code##1{[[}\def\edoc##1{]]}\message{[#6]}} \settocparms{#1} \def\themodtitle{#6} %%%% {\def\code{\string\code}\def\edoc{\string\edoc}% \edef\next{\noexpand\write\cont{\tocskip \tocline{\hskip\tocindent\tocstyle\relax\themodtitle} {\noexpand\the\pageno}}}\next % write to toc %} } @ %def \startsection <>= \def\settocparms#1{ \count@=#1 \ifnum\count@<1 \def\tocskip{\vskip3ptplus1in\penalty-100 \vskip0ptplus-1in}% \def\tocstyle{\bf} \def\tocindent{0pt} \else \def\tocskip{} \def\tocstyle{\rm} \dimen@=2em \advance\count@ by \m@ne \dimen@=\count@\dimen@ \edef\tocindent{\the\dimen@} \fi } @ %def \settocparms <>= \def\tocline#1#2{\line{{\ignorespaces#1}\leaders\hbox to .5em{.\hfil}\hfil \hbox to1.5em{\hss#2}}} @ %def \tocline <>= \def\section#1{\par \vskip3ex\noindent {\bf #1}\par\nobreak\vskip1ex\nobreak} \def\chapter#1{\vfil\eject\startsection{0}{0pt}{6ex}{3ex}{\frtbf\chapcenter}{#1}} \def\section#1{\startsection{1}{0pt}{4ex}{2ex}{\twlbf}{#1}} \def\subsection#1{\startsection{2}{0pt}{2ex}{1ex}{\bf}{#1}} \def\subsubsection#1{\startsection{3}{0pt}{1ex}{0.5ex}{\it}{#1}} \def\paragraph#1{\startsection{4}{0pt}{1.5ex}{0ex}{\it}{#1}} <> \def\nwfilename#1{\vfil\eject\mark{#1}} \def\nwbegindocs#1{\filbreak} \def\nwenddocs{\par} \def\nwbegincode#1{\par\nobreak \begingroup\setupcode\newlines\parindent=0pt\parskip=0pt \let\oendmoddef=\endmoddef \let\oplusendmoddef=\plusendmoddef \def\endmoddef{\oendmoddef\par}\def\plusendmoddef{\oplusendmoddef\par}% \hsize=\codehsize\noindent\bchack} \def\nwendcode{\endgroup} {\catcode`\^^M=\active % make CR an active character \gdef\bchack#1^^M{\relax#1}% } @ %def \section \chapter \section \subsection \subsubsection \paragraph @ %def \nwbegindocs \nwenddocs \nwbegincode \nwendcode \nwfilename <>= \edef\contentsfile{\jobname.toc } % file that gets table of contents info \def\readcontents{\expandafter\input \contentsfile} \newwrite\cont \openout\cont=\contentsfile \write\cont{\string\catcode`\string\@=11}% a hack to make contents @ %def \readcontents \cont <>= % take stuff in plain.tex \def\bye{% \write\cont{}% ensure that the contents file isn't empty \closeout\cont \vfil\eject\pageno=-1 % new page causes contents to be really closed \topofcontents\readcontents\botofcontents \vfil\eject\end} \def\topofcontents{\vfil\mark{{\bf Contents}}} \def\botofcontents{} @ %def \bye \topofcontents \botofcontents <>= \let\em=\it % used to produce an itemized (bulleted) list in plain {\TeX} % such lists can be nested % mostly useful with WEB % Usage: % \itemize % \item First thing % \item second thing % \enditemize \newcount\listlevel \listlevel=0 \newdimen\itemwidth \itemwidth=3em \def\itemize{\begingroup\advance\listlevel by1 \def\item{\par\noindent \raise2pt\llap{$\scriptstyle\bullet$\ }\ignorespaces}% \def\nameditem##1{\par\noindent \llap{\rlap{##1}\hskip\itemwidth}\ignorespaces}% \par\advance\leftskip by\itemwidth\advance\rightskip by0.5\itemwidth} \def\enditemize{\par\endgroup\noindent\ignorespaces} \let\begindocument=\relax @ %def \listlevel \itemwidth \itemize \enditemize Finally we make [[@]] `other' again. <>= \catcode`\@=12 @ \section{Chunks} \nowebchunks \twocolumn[\section{Index}] \nowebindex* @ \end{document}