summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/marginfix/marginfix.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2013-09-08 22:07:13 +0000
committerKarl Berry <karl@freefriends.org>2013-09-08 22:07:13 +0000
commitbe662476eb6af4d2ac4265ffdd2c26f9ec0d48ce (patch)
treeb949cd695e0f86d22139a900f34c3f004099fafe /Master/texmf-dist/source/latex/marginfix/marginfix.dtx
parent40706b96168d4f2b191483c54e851e4c46f8de5a (diff)
marginfix (8sep13)
git-svn-id: svn://tug.org/texlive/trunk@31598 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/marginfix/marginfix.dtx')
-rw-r--r--Master/texmf-dist/source/latex/marginfix/marginfix.dtx1194
1 files changed, 929 insertions, 265 deletions
diff --git a/Master/texmf-dist/source/latex/marginfix/marginfix.dtx b/Master/texmf-dist/source/latex/marginfix/marginfix.dtx
index b0686483fd7..1e7b43ea06b 100644
--- a/Master/texmf-dist/source/latex/marginfix/marginfix.dtx
+++ b/Master/texmf-dist/source/latex/marginfix/marginfix.dtx
@@ -12,10 +12,10 @@
%
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\ProvidesPackage{marginfix}%
- [2010/08/28 v0.9.1 Fix Margin Paragraphs]
+ [2013/09/08 v1.1 Fix Margin Paragraphs]
%<*driver>
\documentclass{ltxdoc}
-\CheckSum{546}
+\CheckSum{1197}
%\OnlyDescription % (un)comment this line to show (hide) source code
\RecordChanges
\EnableCrossrefs
@@ -53,6 +53,23 @@
% {(SDH) Initial CTAN version.}
% \changes{v0.9.1}{2010/08/28}
% {(SDH) Fix bug where we alternated sides in article.}
+% \changes{v1.0}{2013/09/01}
+% {(Dario Buttari) Alternate order of \cs{marginpar} arguments to be
+% consistent with the original macro.}
+% \changes{v1.0}{2013/09/01}
+% {(Dario Buttari) Fix bug in deferred note spacing.}
+% \changes{v1.0}{2013/09/01}
+% {(Dario Buttari) Fix issues with \cs{marginheightadjustment} and
+% \cs{extendmargin} not being applied and reset consistently.}
+% \changes{v1.0}{2013/09/01}
+% {(SDH) Stop gobbling vertical stretch on page. Margin notes will
+% not line up properly if page is stretched.}
+% \changes{v1.0}{2013/09/01}
+% {(SDH) Add margin phantoms.}
+% \changes{v1.1}{2013/09/08}
+% {(SDH) Globally calculate margin phantoms over 4 passes.}
+% \changes{v1.1}{2013/09/08}
+% {(SDH) Add \cs{topskip} to notes at the top of the margin.}
%
% \GetFileInfo{marginfix.dtx}
% \title{\Lopt{marginfix} package documentation}
@@ -72,14 +89,16 @@
% unsatisfying for short textual notes, and standard marginpars cannot
% be mixed with sidebars. This package implements a solution to
% make marginpars "just work" by keeping a list of floating inserts and
-% arranging them intelligently in the output routine.
+% arranging them intelligently in the output routine. The credit for the
+% concept behind this algorithm goes to Prof. Andy Ruina, who employed me
+% to work on some of his textbook macros in 2007--9.
%
% \section{Options}
% There are currently no options that do anything yet.
%
% \section{Commands}
-% For the most part, this is a drop-in replacement. Simply add
-% |\usepackage{marginfix}| to the preamble, use \cs{marginpar}
+% For the most part, this is a drop-in replacement. Simply include
+% a call to |\usepackage{marginfix}| to the preamble, use \cs{marginpar}
% normally and hope for the best.
% In the event, however, that it doesn't work exactly as hoped,
% there are a number of tweaks that the user can apply.
@@ -108,9 +127,9 @@
%
% \DescribeMacro{\mparshift}
% To adjust the position of a single note, use \cs{mparshift}\marg{length}
-% before \cs{marginpar}. Positive lengths move it down the page. This
-% essentially shifts the call-out location, so the actual position of the
-% note might not change if the margin is sufficiently crowded.
+% before a call to \cs{marginpar}. Positive lengths move it down the page.
+% This essentially shifts the call-out location, so the actual position of
+% the note might not change if the margin is sufficiently crowded.
% Multiple calls before the same note are cumulative.
%
% \DescribeMacro{\marginheightadjustment}
@@ -122,15 +141,38 @@
% \cs{extendmargin} on every page.
%
% \DescribeMacro{\marginposadjustment}
-% Similarly, if all the margins are in the wrong place, the callout
-% positions can be adjusted by assigning a non-zero value to the dimension
-% register \cs{marginposadjustment}. This is effectively the same as a call
-% to \cs{mparshift} before every note. This is particularly useful at
-% present because the height of the line on which the margin note is called
+% Similarly, if all the margin notes are in the wrong place, the callout
+% positions can be adjusted globally by assigning a non-zero value to the
+% dimension register \cs{marginposadjustment}. This is effectively the same
+% as a call to \cs{mparshift} before every note. This is particularly useful
+% at present because the height of the line on which the margin note is called
% is currently only estimated, and appears to be off by a point or two.
% This may get fixed in the future, but until then, the adjustment is
% possibly the easiest workaround.
%
+% \DescribeMacro{\blockmargin}\DescribeMacro{\unblockmargin}
+% As of version 1.0, we now support ``margin phantoms'': sections of the
+% margin in which no notes will be placed, which can be useful for large
+% figures that jut into the margin (note: margins already move out of the
+% way of floats, regardless of whether or not they extend into the margin;
+% this is mainly for in-place figures or equations). The easiest way to
+% block off part of the margin is to call \cs{blockmargin} before the
+% extended content and \cs{unblockmargin} afterwards. No margin notes
+% will be placed between these two points (though one must be careful:
+% if one of these is called in horizontal mode, the toggle will occur at
+% the \emph{top} of the current line). Each of these commands takes an
+% optional argument: \cs{blockmargin}\oarg{pos} will begin the margin
+% block at a position \emph{pos} below the current position (or above
+% if \emph{pos} is negative), and \cs{unblockmargin}\oarg{pos} will
+% likewise end the block at a position \emph{pos} below the current
+% position.
+%
+% \DescribeMacro{\marginphantom}
+% Margin phantoms may also be called out in place with a known size
+% using \cs{marginphantom}\oarg{pos}\marg{size}, which is essentially
+% equivalent to \cs{blockmargin}\oarg{pos}\cs{unblockmargin}\oarg{pos$+$size}.
+% Either argument may be negative to refer upward rather than downward.
+%
% \section{Interaction with other packages}
% \subsection{memoir}
% There are no known issues with \Lopt{memoir} at present, provided that
@@ -151,10 +193,14 @@
% Here is a list of things to possibly look forward to in a future version.
% If any of them are particularly important, please let me know.
% \begin{itemize}
-% \item Margin phantoms.
% \item Use of pdf\TeX's \cs{pdfsavepos} and \cs{pdflastypos} for more
% accurate margin placement.
% \item \cs{vadjust} to correct inconsistencies with \cs{@pageht}.
+% \item Margin note placement is irrespective of vertical stretch.
+% Previously we gobbled any vertical stretch, but now that we have
+% fixed that bug, there's the possibility of wrong alignment since
+% we don't know where the positions will ultimately end up. This
+% may be fixed by \cs{pdfsavepos} as well.
% \item Better interaction with floats.
% (We can set a default one way
% or the other and then allow a macro to override it (presumably with a
@@ -170,18 +216,11 @@
% \makeatletter
% \part*{Implementation}
% \section{Initial Setup}
-% \begin{macros}{\@ight,\f@ur,\@C}
-% Make the |@|-sign into a letter for use in macro names. We also
-% define a few other (hopefully) obvious and unambiguous macros that
-% other packages won't destructively clobber.
+% Make the |@|-sign into a letter for use in macro names.
% \begin{macrocode}
%<*package>
\makeatletter
-\chardef\@ight=8
-\chardef\f@ur=4
-\chardef\@c=100
% \end{macrocode}
-% \end{macros}
%
% \begin{macros}{\MFX@debug}
% We have some optionally-included code for debugging. \cs{MFX@debug}
@@ -189,15 +228,22 @@
% The newline can be suppressed with a |*|. We'll also ask for more
% error context in the debug mode.
% \begin{macrocode}
-%<debug>\def\MFX@debug{\@ifstar\message{\message{^^JMFX:}\message}}
-%<debug>\errorcontextlines=20
+%<*debug>
+\def\MFX@debug{\message{^^JMFX:}\message}
+\errorcontextlines=20
+\def\MFX@mac#1{\expandafter\MFX@@mac\meaning#1>>>}
+\def\MFX@@mac#1->{<<<}
+\def\MFX@htdp#1{\ht#1=\the\ht#1, \dp#1=\the\dp#1}
+\showboxbreadth=100
+\showboxdepth=10
+%</debug>
% \end{macrocode}
% \end{macros}
%
% The reader might begin to note at this point a convention we
% adopt throughout this package. While we strive to avoid introducing
-% new names as much as possible (using the \pkg{inlinedef} package
-% whenever we can), any new names we do introduce will be prefixed
+% new names as much as possible (with clever usages of \cs{expandafter}),
+% any new names we do introduce will be prefixed
% by |\MFX@|, |\Mfx@|, or |\mfx@|, depending on the type of name.
% The all-capitol |\MFX@| is used for fully-constant macros. The
% initial-caps |\Mfx@| is used for control sequences that are
@@ -208,6 +254,7 @@
%
% \section{Options}
% Here we define the various package options.
+% \iffalse - CURRENTLY UNIMPLEMENTED
% \begin{macros}{\ifmfx@ypos}
% The \Lopt{ypos} option signifies that we should use the pdf{\TeX}
% primitives \cs{pdfsavepos} and \cs{pdflastypos} to improve positioning
@@ -219,6 +266,7 @@
\DeclareOption{ypos}{\mfx@ypostrue}
% \end{macrocode}
% \end{macros}
+% END IFFALSE - \else There are no options yet. \fi
%
% Now we actually process the options.
% \begin{macrocode}
@@ -235,6 +283,21 @@
% \end{macrocode}
% \end{macros}
%
+% \begin{macros}{\mfx@inject,\Mfx@inject@insert}
+% These are used to hijack \cs{marginpar} to inject arbitrary code
+% into the output routine, rather than actually set a note. To
+% inject code, we unshift two copies of this dummy insert onto
+% \cs{@freelist} for \cs{marginpar} to pull off. We append
+% whatever code we want to inject into \cs{mfx@inject} and then
+% call \cs{marginpar}. Then our custom \cs{@addmarginpar} will
+% recognize the dummy inserts and run the code instead of setting
+% a margin note.
+% \begin{macrocode}
+\let\mfx@injected\@empty
+\newinsert\Mfx@inject@insert
+% \end{macrocode}
+% \end{macros}
+%
% \begin{macros}{\Mfx@marginbox}
% While we're building the margin, we need to put it in a box
% before we can attach it to the main columm.
@@ -243,24 +306,52 @@
% \end{macrocode}
% \end{macros}
%
-% \begin{macros}{\Mfx@marginboxspace,\Mfx@marginpos}
-% While we build up the margin box, we need to keep track of both
-% where we are in the margin (\cs{Mfx@marginpos}) and how
-% much of that space is incompressible (\cs{Mfx@marginboxspace}).
+% \begin{macros}{\Mfx@marginpos@min,\Mfx@marginpos@max,\Mfx@marginspace}
+% While we build up the margin piece boxes, we need to keep track of the
+% possible range of positions. The pair \cs{Mfx@marginpos@min} and
+% \cs{Mfx@marginpos@max} are used to accumulate how much material has
+% been added so far, with the difference that \cs{Mfx@marginpos@min} doesn't
+% take into account compressible space, while \cs{Mfx@marginpos@max} does.
+% Finally, \cs{Mfx@marginspace} is the amount of (incompressible) space
+% since the last note, which allows skips to span margin phantoms.
% \begin{macrocode}
-\newdimen\Mfx@marginboxspace
-\newdimen\Mfx@marginpos
+\newdimen\Mfx@marginpos@min
+\newdimen\Mfx@marginpos@max
+\newdimen\Mfx@marginspace
% \end{macrocode}
% \end{macros}
%
% \begin{macros}{\Mfx@marginheight}
% Because the margin height can be altered by, \cs{extendmargin},
% we must maintain a dimension for the height of the current margin.
+% This dimension is reused in several different ways in the shipout-time
+% margin building routines, keeping track of how much much space is left
+% in (for the global passes) and the end position of the end of (for the
+% piecewise passes) the current piece.
% \begin{macrocode}
\newdimen\Mfx@marginheight
% \end{macrocode}
% \end{macros}
%
+% \begin{macros}{\mfx@marginstart,\mfx@marginpieces,
+% \Mfx@piece@content,\Mfx@piece@count,\ifmfx@in@phantom}
+% These control sequences keep track of the margin phantoms. When the
+% margin is unblocked then \cs{mfx@marginstart} is not \cs{relax}. When
+% a phantom begins, the current \cs{mfx@marginstart} and page position
+% are stored as a pair in \cs{mfx@marginpieces}, which is iterated over
+% while building individual pieces of the margin. We also define a box
+% to keep the content of each margin piece, and a counter to keep track
+% of how many pieces we have. Finally, we define a switch for use in
+% the second pass to indicate that we're inside a phantom.
+% \begin{macrocode}
+\def\mfx@marginstart{0pt}
+\let\mfx@marginpieces\@empty
+\newbox\Mfx@piece@content
+\newcount\Mfx@piece@count
+\newif\ifmfx@in@phantom
+% \end{macrocode}
+% \end{macros}
+%
% \begin{macros}{\Mfx@mparshift}
% We store the current shift in a dimension register.
% \begin{macrocode}
@@ -372,7 +463,7 @@
% \@combinefloats
% add \@texttop and \@textbottom to \@outputbox (default no-op)
% \@opcol:
-% \@outputpage (of \@outputdblcol in twocolumn mode)
+% \@outputpage (or \@outputdblcol in twocolumn mode)
% let \@mparbottom := \@textfloatsheight := 0
% \@floatplacement
% \@startcolumn:
@@ -398,22 +489,29 @@
% output routine so that we can get ahold of the current page
% position. Even if we have a better idea of the page position
% (e.g. from pdf\TeX), we still might as well do this in the OR.
+% In addition to actually setting the margin note, we also use this
+% routine to inject arbitrary code into the OR (see \cs{MFX@inject}).
% \begin{macrocode}
\def\@addmarginpar{%
- \@next\@marbox\@currlist{}\MFX@bug
-%<debug>\MFX@debug{addmarginpar (running insert) \@marbox/\@currbox at
-%<debug> \the\c@page:\the\@pageht, marginlist=\meaning\mfx@marginlist}%
+ \@next\@marbox\@currlist{}\MFX@AssertionError
+%<debug>\MFX@debug{addmarginpar (running insert) \@marbox/ \@currbox at
+%<debug> \the\c@page:\the\@pageht, marginlist=\MFX@mac\mfx@marginlist}%
+%<debug>\MFX@debug{addmarginpar outputpenalty=\the\outputpenalty}%
\MFX@getypos
- \MFX@cons\mfx@marginlist{% TODO: later this will be a run@marginlist
- \noexpand\mfx@margin@note\@marbox\@currbox{\mfx@ypos}% (^i.e. for phantoms)
- \noexpand\mfx@margin@skip{\the\marginparpush}%
- }%
-%<debug>\MFX@debug{addmarginpar (exit): marginlist=\meaning\mfx@marginlist}%
+ \expandafter\ifx\@marbox\Mfx@inject@insert
+ \mfx@injected\global\let\mfx@injected\@empty
+ \else
+ \MFX@cons\mfx@marginlist{%
+ \noexpand\mfx@build@note\@currbox\@marbox{\mfx@ypos}%
+ \noexpand\mfx@build@skip{\the\marginparpush}%
+ }%
+ \fi
+%<debug>\MFX@debug{addmarginpar (exit): marginlist=\MFX@mac\mfx@marginlist}%
}
% \end{macrocode}
% \end{macros}
%
-% \begin{macros}{\MFX@cons,\MFX@snoc}
+% \begin{macros}{\MFX@cons,\MFX@snoc,\MFX@run@clear}
% In passing we'll define the cons macro, which fully-expands
% its second argument, but makes sure to only expand the first
% one once, so that any fragile control sequences in it are
@@ -435,11 +533,35 @@
\expandafter\expandafter\expandafter{\expandafter\temp@#1}%
}
% \end{macrocode}
+% Finally, \cs{MFX@run@clear} is a quick trick to expand the
+% contents of a macro and then clear it (to \cs{@empty}) before
+% any of its tokens are consumed.
+% \begin{macrocode}
+\def\MFX@run@clear#1{%
+ \expandafter\global\expandafter\let\expandafter#1\expandafter\@empty#1%
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\MFX@inject}
+% As mentioned earlier, \cs{@addmarginpar} is also a hook for injecting
+% arbitrary code into the output routine, i.e. to get a vertical position
+% for blocking the margin. We define \cs{MFX@inject} to facilitate this.
+% \begin{macrocode}
+\def\MFX@inject#1{
+ \expandafter\def\expandafter\@freelist\expandafter{%
+ \expandafter\@elt\expandafter\Mfx@inject@insert
+ \expandafter\@elt\expandafter\Mfx@inject@insert
+ \@freelist}%
+ \expandafter\def\expandafter\mfx@injected\expandafter{\mfx@injected#1}%
+ \marginpar{}%
+}
+% \end{macrocode}
% \end{macros}
%
% \begin{macros}{\MFX@getypos,\mfx@ypos}
% We now need to settle on a way to determine the vertical position.
-% Ultimately this will be an option, and will depend on a variety
+% Someday this may be an option, and will depend on a variety
% of factors. But for starters, we define the simplest version.
% Note the subtraction of \cs{Mfx@strutheight}. Ideally we would simply
% grab a copy of \cs{@holdpg} from the middle of \cs{@specialoutput}
@@ -450,14 +572,16 @@
% within \cs{@specialoutput}, and it's not worth the risky job of
% performing surgery on it (which is unfortunately brittle if anyone
% else has a similar idea), we instead resort to this approximation.
-% And since this will ultimately be only a fallback for when
-% \cs{pdflastypos} isn't available, it should be good enough.
-% NOTE: we might be able to use a \cs{vadjust} instead here?
+% And since this should ultimately be only a fallback for when
+% \cs{pdflastypos} isn't available, it's good enough.
+% (NOTE: we might be able to use a \cs{vadjust} instead here?)
% \begin{macrocode}
\def\MFX@getypos{%
- \edef\mfx@ypos{%
- \the\dimexpr\@pageht - \Mfx@strutheight
- + \marginposadjustment + \Mfx@mparshift\relax}%
+ \dimen@\dimexpr\@pageht+\@pagedp+\marginposadjustment+\Mfx@mparshift\relax
+ \ifnum\outputpenalty=-10002\relax
+ \advance\dimen@-\Mfx@strutheight
+ \fi
+ \edef\mfx@ypos{\the\dimen@}%
\global\Mfx@mparshift\z@
}
% \end{macrocode}
@@ -490,14 +614,17 @@
%
% \cs{MFX@combinefloats@before} is then responsible for picking the
% needed notes from \cs{mfx@marginlist}, building them into a box, and
-% attaching said box onto the correct side of \cs{@outputbox}. This is
-% also a convenient place to reset \cs{Mfx@marginheight} to zero (since
-% we reuse the register for one-time extensions).
+% attaching that box onto the correct side of \cs{@outputbox}. We also
+% add any global \cs{marginheightadjustment} to \cs{Mfx@marginheight}
+% before building the margin, and then reset it back to zero at the end.
+% This allows any calls to \cs{extendmargin} during the page itself to
+% work as expected.
% \begin{macrocode}
\def\MFX@combinefloats@before{%
+ \advance\Mfx@marginheight\marginheightadjustment
\MFX@buildmargin
\MFX@attachmargin
- \Mfx@marginheight\marginheightadjustment
+ \global\Mfx@marginheight\z@
}
% \end{macrocode}
% \end{macros}
@@ -512,218 +639,312 @@
% First, we need to make sure that the boxes we're combining are the
% same size.
% \begin{macrocode}
- \ifdim\ht\@outputbox<\ht\Mfx@marginbox
- \setbox\@outputbox\vbox to \ht\Mfx@marginbox{%
- \box\@outputbox
- \vfill
- }%
- \else
- \setbox\Mfx@marginbox\vbox to \ht\@outputbox{%
- \unvbox\Mfx@marginbox
- \vfill
- }%
- \fi
+%<debug>\MFX@debug{attachmargin: \MFX@htdp\@outputbox, \MFX@htdp\Mfx@marginbox}%
+ %<debug>\showbox\@outputbox
+ %<debug>\showbox\Mfx@marginbox
+ \setbox\Mfx@marginbox\vtop{%
+ \vskip\z@\unvbox\Mfx@marginbox}%
+ %% \ifdim\ht\@outputbox<\ht\Mfx@marginbox
+ %% \setbox\Mfx@marginbox\vbox to \ht\@outputbox{%
+ %% \unvbox\Mfx@marginbox
+ %% \vskip\z@ shrink 1filll\relax
+ %% }%
+ %% \else
+ %% \setbox\Mfx@marginbox\vbox to \ht\@outputbox{%
+ %% \unvbox\Mfx@marginbox
+ %% \vfill
+ %% }%
+ %% \fi
% \end{macrocode}
% Next we need to figure out which side of \cs{@outputbox} to attach
-% the \cs{Mfx@marginbox} on.
-% \begin{macrocode}
- \setbox\@outputbox\vbox to \ht\@outputbox{%
- \hbox to \wd\@outputbox{%
- \if\MFX@leftmargin
- \llap{\box\Mfx@marginbox\hskip\marginparsep}%
- \box\@outputbox
- \else
- \box\@outputbox
- \rlap{\hskip\marginparsep\box\Mfx@marginbox}%
- \fi
- }}%
+% the \cs{Mfx@marginbox} on. We now use \cs{columnwidth} instead of
+% \cs{wd}\cs{@outputbox} to set the right-hand margins, since tufte-\LaTeX
+% sometimes makes too-wide output boxes. If this becomes a problem,
+% we'll need to consider making this configurable elsewhere. We should
+% also pay attention to whether adding a box at the top of \cs{@outputbox}
+% might have unintended consequences w.r.t. any glue being retained that
+% should have been swallowed. This will require further investigation.
+% \begin{macrocode}
+ \setbox\@outputbox\vbox{% to \ht\@outputbox{%
+ \begingroup
+ \setbox\@tempboxa\vbox{% to \ht\@outputbox{%
+ \hbox{% to \wd\@outputbox{%
+ \if\MFX@leftmargin
+ \llap{\box\Mfx@marginbox\hskip\marginparsep}%
+ \else
+ \hskip\columnwidth
+ \rlap{\hskip\marginparsep\box\Mfx@marginbox}%
+ \fi
+ }}%
+ \ht\@tempboxa\z@
+ \dp\@tempboxa\z@
+ \box\@tempboxa
+ \endgroup
+ \unskip
+ \unvbox\@outputbox
+ }%
+ %<debug>\showbox\@outputbox
}
% \end{macrocode}
% \end{macros}
%
% \begin{macros}{\MFX@buildmargin}
% When \cs{MFX@buildmargin} is called, we have a list of tokens in
-% \cs{mfx@marginlist} that need to be processed. After it's done
-% working, \cs{mfx@marginlist} should have the first $n>0$ of these
-% removed, and leaving only notes that were deferred to the next
-% page. Additionally, \cs{Mfx@marginbox} must contain a
-% box the same height as \cs{@outputbox}. We do this in several
-% steps. We start with a height of \cs{@colroom} rather than
-% \cs{textheight} because \cs{@colroom} has already subtracted
-% off the top/bottom floats that have been set. Eventually we
-% will want to encroach on these floats, particularly if they
-% don't encroach on the margin, but that will be tricky...
+% \cs{mfx@marginlist} that need to be processed: combinations of
+% \cs{mfx@build@note}, \cs{mfx@build@skip}, and \cs{mfx@build@clear},
+% with various parameters to indicate what material still needs to be
+% set in the margin. This macro therefore must pull off the first $n>0$
+% of these commands to set on the current page ($n$ must be positive to
+% prevent infinite loops), and leave the rest to be deferred. We do not
+% currently support taking notes out of order, though that is a possible
+% feature to allow in the future, on an opt-in basis. The typeset
+% material will be left in \cs{Mfx@marginbox}, which must have the same
+% height as \cs{@outputbox} (although because we \cs{unvbox}\cs{@outputbox}
+% in \cs{MFX@attachmargin}, we can't guarantee that this will correctly
+% line up the notes with their callouts). This procedure happens in
+% four passes. But first, we initialize \cs{Mfx@marginheight} to
+% \cs{@colroom}, which is the height of the page minus any floats that
+% have been added to the top of bottom (these floats may extend into the
+% margins: in the future we may look into detecting this and using the
+% whole page, with overwide floats blocked off as phantoms). We add
+% \cs{@colroom} rather than assigning it because any global or per-page
+% adjustments have already been added to \cs{Mfx@marginheight}. We
+% can then close out any still-open margin pieces (this is the typical
+% case, where the margin is not blocked across a page boundary, so that
+% \cs{mfx@marginstart} will hold a position, rather than \cs{relax}).
+% After this, \cs{Mfx@marginheight} is no longer necessary, so we reuse
+% it for keeping track of available space in individual margin pieces.
% \begin{macrocode}
\def\MFX@buildmargin{%
\advance\Mfx@marginheight\@colroom
-%<debug>\MFX@debug{buildmargin: marginheight=\the\Mfx@marginheight}%
- \MFX@buildmargin@down
- \MFX@buildmargin@up
+ \ifx\mfx@marginstart\relax
+ \else
+ \MFX@cons\mfx@marginpieces{%
+ \noexpand\@elt{\mfx@marginstart}{\the\Mfx@marginheight}}%
+ \gdef\mfx@marginstart{0pt}%
+ \global\advance\Mfx@piece@count\@ne
+ \fi
+%<debug>\MFX@debug{buildmargin: marginheight=\the\Mfx@marginheight,
+%<debug> marginlist=\MFX@mac\mfx@marginlist,
+%<debug> marginpieces=\MFX@mac\mfx@marginpieces}%
+% \end{macrocode}
+% We now execute the four passes. First is a global downward pass,
+% whose purpose is to determine the maximum number of notes (and other
+% material) that can fit in the margin, taking any phantoms into
+% consideration. Every note identified by \cs{MFX@buildmargin@down}
+% is guaranteed to show up on this page, so we free its inserts back
+% to \cs{@freelist}. The second pass is the global upward pass, in
+% which we determine the lowest possible margin piece each note may
+% go into without causing lower notes to fall off the bottom. The
+% third pass is the piecewise downward pass. For each piece, we
+% figure out where in the piece each note will go by inserting
+% compressible spaces between the notes. If a note is called out
+% past the end of the piece and does not need to go into the piece
+% (as determined by pass 2), it will be deferred to a later piece.
+% The fourth pass is the piecewise upward pass, in which the compressible
+% spaces are shrunk just enough to fit everything into the piece. The
+% last two (piecewise) passes both occur in each piece before the next
+% piece is addressed. The whole process is bypassed if there are
+% no eligible margin pieces.
+% \begin{macrocode}
+ \ifx\mfx@marginpieces\@empty\else
+ \MFX@buildmargin@down
+ \MFX@buildmargin@up
+ \MFX@buildmargin@pieces
+ \fi
}
% \end{macrocode}
% \end{macros}
%
-% \subsection{First pass}
-% \begin{macros}{\MFX@buildmargin@down}
-% The first step is the ``down'' step, in which we move the notes
-% that will go on the current page into \cs{mfx@marginout} in reverse order,
-% and anything that will be deferred gets put back in
-% \cs{mfx@marginlist}. This behavior is configured by changing
-% the meaning of \cs{mfx@margin@note}, \cs{mfx@margin@skip}, and
-% \cs{mfx@margin@clear}. Note that during the course of processing
-% \cs{mfx@marginlist}, these meanings will continue to change.
+% \subsection{First pass: global downward}
+% \begin{macros}{\MFX@buildmargin@down,\mfx@pieceheights}
+% The first step is the global ``down'' step, in which we move the
+% notes that will fit on the current page into \cs{mfx@marginout} in
+% reverse order (to prepare for the second, upward, pass), and anything
+% that doesn't fit is deferred back into \cs{mfx@marginlist}. We do
+% this by changing the meaning of \cs{mfx@build@note}, \cs{mfx@build@skip},
+% and \cs{mfx@build@clear}, which delimit the different types of material
+% in \cs{mfx@marginlist}. Note that as we continue processing, these
+% macros will change from time to time (i.e. changing \cs{mfx@build@skip}
+% to actually doing something once we find a note, rather than gobbling
+% so as to remove skips at page boundaries; or changing them to save
+% material back onto \cs{mfx@marginlist} once the margin fills up).
+% The first thing we need to do is iterate over the piece positions
+% to get the list of heights.
% \begin{macrocode}
\def\MFX@buildmargin@down{%
-%<debug>\MFX@debug{buildmargin@down: ENTRY}%
-%<debug>\MFX@debug{marginlist=\meaning\mfx@marginlist}%
- \let\mfx@margin@note\MFX@margin@note@down
- \let\mfx@margin@skip\@gobble
- \let\mfx@margin@clear\MFX@margin@clear@down
- \let\mfx@marginout\@empty
+ \let\mfx@pieceheights\@empty
+ \def\@elt##1##2{%
+ \MFX@cons\mfx@pieceheights{\noexpand\@elt{\the\dimexpr##2-##1}}}%
+ \mfx@marginpieces
+ \MFX@popdimen\Mfx@marginheight\mfx@pieceheights
% \end{macrocode}
-% We do a little bit of \cs{expandafter} trickery here to first expand
-% the current meaning of \cs{mfx@marginlist}, then clear it before
-% actually executing anything.
+% Now we run forwards over the \cs{mfx@marginlist} to actually
+% operate on each thing in the margin.
% \begin{macrocode}
- \expandafter\global\expandafter\let
- \expandafter\mfx@marginlist\expandafter\@empty
- \mfx@marginlist
-%<debug>\MFX@debug{buildmargin@down: RETURN}%
-%<debug>\MFX@debug{marginlist=\meaning\mfx@marginlist}%
+ \let\mfx@build@note\MFX@margin@note@down
+ \let\mfx@build@skip\@gobble
+ \let\mfx@build@clear\MFX@build@clear@down
+ \let\mfx@marginout\@empty
+ \MFX@run@clear\mfx@marginlist
+%<debug>\MFX@debug{buildmargin@down: RETURN
+%<debug> marginout=\MFX@mac\mfx@marginout,
+%<debug> marginlist=\MFX@mac\mfx@marginlist}%
}
% \end{macrocode}
% \end{macros}
%
-% We must now define the different meanings for the
-% |\mfx@margin@...| macros.
-% \begin{macros}{\MFX@margin@note@down,\MFX@whichbox,%
-% \MFX@margin@skip@down,\MFX@margin@clear@down}
-% We'll dive right into the notes first. When we see a note in the
-% \cs{marginlist}, we need to do several things.
+% \begin{macros}{\MFX@margin@note@down,\MFX@margin@skip@down,
+% \MFX@margin@clear@down}
+% We now define the various |\MFX@margin@...@down| macros.
+% At this stage in the game, the only difference between notes
+% and skips is that we ignore skips before any notes by setting
+% \cs{mfx@build@note} initially to \cs{@gobble}. Once we've
+% seen the first note, skips are treated exactly the same: as
+% fixed-height material. If there is room in the current piece
+% for the given height, then we prepend it to \cs{mfx@marginout},
+% decrement the remaining height, and arrange for the boxes to
+% be freed. If not, we unshift the next piece height from
+% \cs{mfx@pieceheights} and try again, until \cs{mfx@pieceheights}
+% is empty and we simply defer everything to later pages.
+%
+% Upon seeing a note, we must do several things:
% \begin{enumerate}
-% \item optionally add a \emph{compressible} skip before it, of length
-% $|#3| - \cs{Mfx@marginpos}$, to line it up with the callout
-% location
-% \item figure out which box we need for the current page, not yet freeing
-% the allocated boxes, since we may still end up deferring
-% \item add the height of the correct box to \cs{Mfx@marginboxspace} and
-% \cs{Mfx@marginpos}
-% \item if \cs{Mfx@marginboxspace} exceeds \cs{Mfx@marginheight}, then
-% we defer this note and change the meaning of \cs{mfx@margin@note}
-% to defer all remaining notes
-% \item otherwise, we add tokens to construct the box to \cs{toks@} and
-% free the allocated inserts.
-% \item redefine \cs{mfx@margin@skip} to \cs{MFX@margin@skip@down}, now
-% that we've gotten a real note (it starts out as \cs{@gobble} since
-% we don't want to apply skips at the very beginning).
+% \item determine which box (left or right) is needed for the
+% current page, by calling \cs{MFX@whichbox}
+% \item if the box fits, free both boxes, prepend \cs{mfx@marginout}
+% with a call to \cs{mfx@build@note}, and re-enable skips
+% \item otherwise, defer the current note and all future notes
% \end{enumerate}
+% The latter two steps are taken care of by \cs{MFX@margin@fit},
+% which takes the height and two blocks of material: one to prepend
+% to \cs{mfx@marginout} if it fits, the other to append to
+% \cs{mfx@marginlist} if it doesn't.
% \begin{macrocode}
\def\MFX@margin@note@down#1#2#3{%
-%<debug>\MFX@debug{note@down: ENTRY: #1/#2 at #3}%
- \ifdim#3>\Mfx@marginpos
- \dimen@\dimexpr#3-\Mfx@marginpos\relax
-%<debug>\MFX@debug{note@down: adding compressible \the\dimen@}%
- \MFX@snoc\mfx@marginout{\noexpand\mfx@margin@compressible{\the\dimen@}}%
- \advance\Mfx@marginpos\the\dimen@
- \fi
- \MFX@whichbox#1#2%
- \advance\Mfx@marginboxspace\dimexpr\ht\@marbox+\dp\@marbox\relax
- \ifdim\Mfx@marginboxspace>\Mfx@marginheight
-% \end{macrocode}
-% We've run out of margin space, so we now defer every following box,
-% which means appending them back to \cs{mfx@marginlist}, except with
-% a callout position of zero, since we want them as high up as possible
-% (also, the position should be monotonic).
-% \begin{macrocode}
-%<debug>\MFX@debug{note@down: out of space:
-%<debug> \the\Mfx@marginboxspace>\the\Mfx@marginheight}%
- \advance\Mfx@marginboxspace\dimexpr-\ht\@marbox-\dp\@marbox\relax
- \mfx@margin@clear
- \mfx@margin@note#1#2{#3}%
- \else
-% \end{macrocode}
-% At this point, the box is definitely going onto this page, so we can
-% arrange for the boxes to be freed and then add the correct box to the
-% output list.
-% \begin{macrocode}
-%<debug>\MFX@debug{note@down: adding \@marbox
-%<debug> ht \the\ht\@marbox dp \the\dp\@marbox}%
- \advance\Mfx@marginpos\dimexpr\ht\@marbox+\dp\@marbox\relax
+%<debug>\MFX@debug{margin@note@down: ENTRY: #1/ #2 at #3}%
+ \MFX@whichbox\@marbox#1#2%
+ \if\MFX@check@fit{}{\ht\@marbox+\dp\@marbox}%
\MFX@snoc\mfx@marginout{%
- \noexpand\mfx@margin@note\@marbox
\noexpand\@cons\noexpand\@freelist#1%
\noexpand\@cons\noexpand\@freelist#2%
- }%
+ \noexpand\mfx@build@note\@marbox{#3}}%
+ \let\mfx@build@skip\MFX@margin@skip@down
+ \else
+ \mfx@build@clear
+ \mfx@build@note{#1}{#2}{#3}%
\fi
- \let\mfx@margin@skip\MFX@margin@skip@down
-%<debug>\MFX@debug{note@down: RETURN space=\the\Mfx@marginboxspace,
-%<debug> pos=\the\Mfx@marginpos}%
}
% \end{macrocode}
%
-% We need to figure out which box to set. This macro calls
-% \cs{MFX@leftmargin} and then sets the correct box into
-% \cs{@marbox} for use by \cs{MFX@margin@box@down}.
+% Skips are similar. A skip needs only to save itself back into
+% \cs{mfx@marginout}, provided it fits. If not, there is no need
+% to defer it because it will just get gobbled at the top of the
+% next page anyway.
% \begin{macrocode}
-\def\MFX@whichbox#1#2{%
- \if\MFX@leftmargin
- \def\@marbox{#1}%
+\def\MFX@margin@skip@down#1{%
+%<debug>\MFX@debug{margin@skip@down #1}%
+ \if\MFX@check@fit{}{#1}%
+ \MFX@snoc\mfx@marginout{\noexpand\mfx@build@skip{#1}}%
\else
- \def\@marbox{#2}%
+ \mfx@build@clear
\fi
-%<debug>\MFX@debug{whichbox: \@marbox}%
}
% \end{macrocode}
%
-% The next macro we'll write is the skip. This one just has to save itself
-% onto whichever list we're working on (output or deferred) and in the case
-% of output, update \cs{@Mfx@marginpos}.
+% Finally, \cs{MFX@margin@clear@down} is the only place we actually
+% need to handle full-margin clears, since the downward pass does not
+% ever push \cs{mfx@build@clear} onto \cs{mfx@marginout}. When we
+% see this, we simply redefine all three commands to append themselves
+% back to \cs{mfx@marginlist}.
% \begin{macrocode}
-\def\MFX@margin@skip@down#1{%
-%<debug>\MFX@debug{skip@down #1}%
- \advance\Mfx@marginpos#1\relax
- \advance\Mfx@marginboxspace#1\relax
- \MFX@snoc\mfx@marginout{\noexpand\mfx@margin@skip{#1}}%
+\def\MFX@build@clear@down{%
+%<debug>\MFX@debug{clear@down}%
+ \def\mfx@build@note##1##2##3{%
+ \MFX@cons\mfx@marginlist{\noexpand\mfx@build@note##1##2{\MFX@minus@inf}}}%
+ \def\mfx@build@skip##1{%
+ \MFX@cons\mfx@marginlist{\noexpand\mfx@build@skip{##1}}}%
+ \def\mfx@build@clear{%
+ \MFX@cons\mfx@marginlist{\noexpand\mfx@build@clear}}%
}
% \end{macrocode}
+% \end{macros}
%
-% Finally, \cs{MFX@margin@clear@down} simply signals the end of this
-% margin. All further material will be deferred, so we redefine
-% \cs{mfx@margin@note}, \cs{mfx@margin@skip}, and \cs{mfx@margin@clear}
-% to defer.
+% \begin{macros}{\MFX@check@fit,\MFX@popdimen}
+% We factored out some of the common functionality between the
+% note and skip routines, so that must now be defined. The
+% \cs{MFX@check@fit} macro acts as a conditional and should be
+% used as \cs{if}\cs{MFX@check@fit}\marg{piece-hook}\marg{size}.
+% It takes care of iterating through the list of heights and
+% accumulating the total size of material encountered so far.
+% The \emph{piece-hook} is executed each time a new piece height
+% is popped.
% \begin{macrocode}
-\def\MFX@margin@clear@down{%
-%<debug>\MFX@debug{clear@down}%
- \def\mfx@margin@note##1##2##3{%
- \MFX@cons\mfx@marginlist{\noexpand\mfx@margin@note##1##2{\MFX@minus@inf}}}%
- \def\mfx@margin@skip##1{%
- \MFX@cons\mfx@marginlist{\noexpand\mfx@margin@skip{##1}}}%
- \def\mfx@margin@clear{%
- \MFX@cons\mfx@marginlist{\noexpand\mfx@margin@clear}}%
+\def\MFX@check@fit#1#2{%
+ 00\fi % close out the \if
+%<debug>\MFX@debug{check@fit{\unexpanded{#1}}{#2=\the\dimexpr#2} ENTRY:
+%<debug> marginheight=\the\Mfx@marginheight}%
+ \@tempswafalse
+ \ifdim\dimexpr#2<\Mfx@marginheight % it fits
+ \advance\Mfx@marginheight-\dimexpr#2\relax % deduct the size
+ \@tempswatrue
+ \else % didn't fit: check the next piece
+%<debug>\MFX@debug{check@fit overflow: pieceheights=\MFX@mac\mfx@pieceheights}%
+ \ifx\mfx@pieceheights\@empty\else % make sure there's anything there
+ #1%
+ \MFX@popdimen\Mfx@marginheight\mfx@pieceheights
+ \if\MFX@check@fit{#1}{#2}\fi
+ \fi
+ \fi
+%<debug>\MFX@debug{check@fit RETURN \meaning\if@tempswa:
+%<debug> marginheight=\the\Mfx@marginheight,}%
+ \if@tempswa % start a new \if
+}
+% \end{macrocode}
+% Here is a quick convenience routine. \cs{MFX@popdimen}\marg{dimen}%
+% \marg{list} removes the first dimension from \emph{list} and stores
+% it into \emph{dimen}.
+% \begin{macrocode}
+\def\MFX@popdimen#1#2{%
+ \def\@elt##1{%
+ #1##1\relax
+ \def\@elt####1{%
+ \MFX@cons#2{\noexpand\@elt{####1}}%
+ }%
+ }%
+ \MFX@run@clear#2%
}
% \end{macrocode}
% \end{macros}
%
-% \begin{macros}{\MFX@minus@inf}
-% Note that when we added deferred boxes to the list, we put them
-% at \cs{MFX@minus@inf}. We'll define that to be a large negative
-% dimension.
+% \begin{macros}{\MFX@whichbox,\MFX@leftmargin}
+% We also need to determine which box should be used, since they
+% may have different heights. The macro \cs{MFX@whichbox}%
+% \marg{target-box}\marg{left-box}\marg{right-box} checks which margin
+% we're setting and stores the correct box into \emph{target-box}.
+% Note that \emph{target-box} must be a single control sequence.
% \begin{macrocode}
-\def\MFX@minus@inf{-4000pt}
+\def\MFX@whichbox#1#2#3{%
+ \if\MFX@leftmargin
+ \def#1{#2}%
+ \else
+ \def#1{#3}%
+ \fi
+%<debug>\MFX@debug{whichbox: \@marbox (\the\dimexpr\ht#1+\dp#1)}%
+}
% \end{macrocode}
-% \end{macros}
%
-% \begin{macros}{\MFX@leftmargin}
-% Here we figure out which box to use based on the page number and
-% other flags. This is a conditional that should be used after
-% \cs{if}, as in \cs{if}\cs{MFX@leftmargin}\ldots\cs{else}\ldots\cs{fi}.
+% And here is the logic to figure out which margin were in, based
+% on the page number and other flags. This is another conditional-like
+% macro, and should be used after an \cs{if}, as in
+% \cs{if}\cs{MFX@leftmargin}\ldots\cs{else}\ldots\cs{fi}.
%
% This is different from the corresponding code in the {\LaTeX}
% routines because we don't support double columns. In addition, we
% would ideally allow \cs{if@reversemargin} to work on a per-note
% basis (i.e. at callout time) but we also need something working at
% shipout time so we can figure out which margin to use. Thus, until
-% we figure out how to use multiple margins.
+% we figure out how to use multiple margins, this will have to do.
% \begin{macrocode}
\def\MFX@leftmargin{%
00\fi % close out the \if
@@ -742,84 +963,445 @@
% \end{macrocode}
% \end{macros}
%
-% \subsection{Second pass}
-% \begin{macros}{\MFX@buildmargin@up}
-% Next is the ``up'' step. Here we simply take the reversed
-% list in \cs{mfx@marginout} and prepend each item in turn to
-% \cs{Mfx@marginbox}. We start by automatically discarding any
-% skips, though we can't do this with a simple \cs{@gobble} anymore
-% since we need to deduct them from \cs{Mfx@marginpos}. Once we
-% hit a note, we'll change the skips to be their normal meanings.
-% Note that there are no clears in \cs{mfx@marginout}.
+% \begin{macros}{\MFX@minus@inf}
+% Finally, note that when deferring notes to the next page, we
+% adjust their position to the top of the page, rather than the
+% callout position. This is a large negative dimension (near
+% \TeX's maximum), but we may reconsider making this zero or even
+% a small positive amount, since there seems to be a small amount
+% of space before the first paragraph in normal text, though I'm
+% not sure where that comes from.
+% \begin{macrocode}
+\def\MFX@minus@inf{-4000\p@}
+% \end{macrocode}
+% \end{macros}
+%
+% \subsection{Second pass: global upward}
+% \begin{macros}{\MFX@buildmargin@up,\mfx@phantomheights}
+% The next step is the global ``up'' step, in which we figure out the
+% lowest piece a note can possibly occupy (without pushing later notes
+% off the bottom) and add this information to the \cs{mfx@build@note} in
+% \cs{mfx@marginout}. We start similar to \cs{MFX@buildmargin@down},
+% except we need the list of heights to be backwards. We also need a
+% list of phantom heights, in order to handle skips properly, which we
+% intersperse as negative heights.
% \begin{macrocode}
\def\MFX@buildmargin@up{%
-%<debug>\MFX@debug{buildmargin@up: excess=\the\dimexpr
-%<debug> \Mfx@marginpos-\Mfx@marginheight\relax}%
-%<debug>\MFX@debug{marginout=\meaning\mfx@marginout}
- \let\mfx@margin@note\MFX@margin@note@up
- \let\mfx@margin@compressible\MFX@margin@skip@gobble@up
- \let\mfx@margin@skip\MFX@margin@skip@gobble@up
- \mfx@marginout
+%<debug>\MFX@debug{buildmargin@up: ENTRY
+%<debug> marginpieces=\MFX@mac\mfx@marginpieces,
+%<debug> marginout=\MFX@mac\mfx@marginout}%
+ \let\mfx@pieceheights\@empty
+ \let\mfx@phantomheights\@empty
+ \let\temp@@\relax
+ \def\@elt##1##2{%
+%<debug>\MFX@debug{ -> piece (##1,##2), temp@@=\meaning\temp@@}%
+ \MFX@snoc\mfx@pieceheights{\noexpand\@elt{\the\dimexpr##2-##1}}%
+ \ifx\temp@@\relax\else
+%<debug>\MFX@debug{ -> phantom (\temp@@,##1)}%
+ \MFX@snoc\mfx@phantomheights{\noexpand\@elt{\the\dimexpr##1-\temp@@}}%
+ \fi
+ \def\temp@@{##2}%
+ }%
+ \mfx@in@phantomfalse
+ \mfx@marginpieces
+% \end{macrocode}
+% The piece counter, \cs{Mfx@piece@count} has not been touched yet,
+% so now we will start decrementing it for each piece to keep track
+% of where we are. Note that \cs{mfx@marginout} will never contain
+% \cs{mfx@build@clear} so we don't need to reassign it. Since we
+% don't do any deferrals here, we don't need to empty out a new target
+% list. Instead, we operate ``in-place'' in \cs{mfx@marginout}, after
+% popping off the first height.
+% \begin{macrocode}
+ \MFX@popdimen\Mfx@marginheight\mfx@pieceheights
+ \let\mfx@build@note\MFX@margin@note@up
+ \let\mfx@build@skip\@gobble
+ \MFX@run@clear\mfx@marginout
+%<debug>\MFX@debug{buildmargin@up: RETURN marginout=\MFX@mac\mfx@marginout}%
}
% \end{macrocode}
% \end{macros}
%
-% \begin{macros}{\MFX@margin@skip@gobble@up}
-% In case we have any skips at the beginning of \cs{mfx@marginout},
-% we'll gobble them and deduct their lenghts from \cs{Mfx@marginpos}.
+% \begin{macros}{\MFX@margin@note@up,\MFX@margin@skip@up}
+% We must again define the specific behavior of each build command.
+% These macros simply reuse \cs{MFX@check@fit}, but ask it to
+% decrement the piece counter when a piece runs out of space.
+% Aside from that, the only thing that actually happens here is
+% that we append the current piece to each note, and also end
+% up reversing the contents by again prepending everything.
+% We are guaranteed that \cs{MFX@check@fit} will never fail.
+% Since we cannot put notes in a phantom, we start by ensuring
+% we're not in one.
+% \begin{macrocode}
+\def\MFX@margin@note@up#1#2{%
+%<debug>\MFX@debug{margin@note@up: #1at #2, marginheight=\the\Mfx@marginheight}%
+ \ifmfx@in@phantom
+ \MFX@popdimen\Mfx@marginheight\mfx@pieceheights
+ \advance\Mfx@piece@count\m@ne
+ \mfx@in@phantomfalse
+ \fi
+% \end{macrocode}
+% Now we're guaranteed to be in a piece, rather than a phantom, we
+% look for a piece that can fit this note, making sure to decrement
+% the piece count and pop off a phantom for each new piece we check.
+% Once it's found, we add the note back to \cs{mfx@marginout} with
+% the corect piece.
% \begin{macrocode}
-\def\MFX@margin@skip@gobble@up#1{%
-%<debug>\MFX@debug{skip@gobble@up: #1}%
- \advance\Mfx@marginpos-#1\relax
+ \if\MFX@check@fit{\advance\Mfx@piece@count\m@ne
+ \MFX@popdimen\dimen@\mfx@phantomheights}{\ht#1+\dp#1}%
+ \MFX@snoc\mfx@marginout{%
+ \noexpand\mfx@build@note{#1}{#2}{\the\Mfx@piece@count}}%
+ \let\mfx@build@skip\MFX@margin@skip@up
+ \else\MFX@AssertionError\fi
+}
+% \end{macrocode}
+% Skips are similar, but we have the added complication of handling
+% margin phantoms. When we cross between phantom and piece, we split
+% the skip so that we can use the simplest recursion possible.
+% \begin{macrocode}
+\def\MFX@margin@skip@up#1{%
+%<debug>\MFX@debug{margin@skip@up: #1}%
+ \dimen@#1\relax
+ \advance\Mfx@marginheight-\dimen@
+ \ifdim\Mfx@marginheight<\z@
+% \end{macrocode}
+% This skip was bigger than the piece, so we need to split this skip,
+% adding the overflow back, and try again. Since we're done with this
+% piece, we'll pop the next one and recurse on whatever's left. This
+% looks slightly different depending on whether or not we're in a phantom.
+% \begin{macrocode}
+ \advance\dimen@\Mfx@marginheight
+ \MFX@snoc\mfx@marginout{%
+ \noexpand\mfx@build@skip{\the\dimen@}{\the\Mfx@piece@count}}%
+ \dimen@-\Mfx@marginheight
+ \ifmfx@in@phantom
+ \MFX@popdimen\Mfx@marginheight\mfx@pieceheights
+ \advance\Mfx@piece@count\m@ne
+ \mfx@in@phantomfalse
+ \else
+ \MFX@popdimen\Mfx@marginheight\mfx@phantomheights
+ \mfx@in@phantomtrue
+ \fi
+ \mfx@build@skip\dimen@
+ \else
+% \end{macrocode}
+% This skip fit entirely within the phantom, so we simply emit it.
+% \begin{macrocode}
+ \MFX@snoc\mfx@marginout{%
+ \noexpand\mfx@build@skip{\the\dimen@}{\the\Mfx@piece@count}}%
+ \fi
}
% \end{macrocode}
% \end{macros}
%
-% \begin{macros}{\MFX@margin@note@up}
-% Once we actually do hit a note, we need to set it in \cs{Mfx@marginbox}.
-% We also redefine \cs{mfx@margin@skip} and \cs{mfx@margin@compressible}
-% here. Hopefully any skips aren't being dropped by our \cs{unvbox}ing.
+% \subsection{Margin pieces}
+% \begin{macros}{\MFX@buildmargin@pieces,\MFX@buildmargin@piece}
+% Before we can start the third and fourth passes, we need to set up
+% a loop over the pieces so that each piece can do these passes at
+% one time. In case we didn't use up all the pieces in the second
+% phase, we'll reset \cs{Mfx@piece@count} to zero. We also reset
+% \cs{Mfx@marginspace} and \cs{Mfx@marginbox}.
+% \begin{macrocode}
+\def\MFX@buildmargin@pieces{%
+ \Mfx@piece@count\z@
+ \Mfx@marginspace\z@
+ \setbox\Mfx@marginbox\vbox{\vskip\z@}% TODO - do we need this?
+% \end{macrocode}
+% Now we run over the individual margin pieces, clearing it out as we
+% build up the contents of \cs{Mfx@marginbox}. Once we're done with
+% that, we need to do a bit of clean-up before finishing.
% \begin{macrocode}
-\def\MFX@margin@note@up#1{%
-%<debug>\MFX@debug{note@up: #1}%
- \setbox\Mfx@marginbox\vbox{\box#1\unvbox\Mfx@marginbox}%
- \let\mfx@margin@skip\MFX@margin@skip@up
- \let\mfx@margin@compressible\MFX@margin@compressible@up
+ \let\@elt\MFX@buildmargin@piece
+ \MFX@run@clear\mfx@marginpieces
+ \let\@elt\relax
+ \Mfx@piece@count\z@
+}
+% \end{macrocode}
+%
+% The \cs{MFX@buildmargin@piece} macro is called for each piece of
+% the margin, and is passed the top and bottom positions of the piece.
+% Here we need to do a few things. First, if the output so far is
+% smaller than the top of the piece (this is generally true, except
+% sometimes for the first piece) then we need to insert padding into
+% \cs{Mfx@marginbox} before continuing. We accumulate this padding
+% into \cs{Mfx@marginspace}, which allows skips to do double-duty
+% across phantoms.
+% \begin{macrocode}
+\def\MFX@buildmargin@piece#1#2{%
+%<debug>\MFX@debug{buildmargin@piece: ENTRY (#1, #2)}%
+ \ifdim\ht\Mfx@marginbox<#1\relax
+ \dimen@\dimexpr#1-\ht\Mfx@marginbox\relax
+%<debug>\MFX@debug{buildmargin@piece: padding \the\dimen@}%
+ \setbox\Mfx@marginbox\vbox{%
+ \unvbox\Mfx@marginbox
+ \vskip\dimen@
+ }%
+ \advance\Mfx@marginspace\dimen@
+ \fi
+% \end{macrocode}
+% Now that \cs{Mfx@marginbox} has been padded, we proceed to set
+% things up for our down and up passes, and then run them to build
+% \cs{Mfx@piece@content}.
+% \begin{macrocode}
+ \Mfx@marginpos@min#1\relax
+ \Mfx@marginpos@max#1\relax
+ \Mfx@marginheight#2\relax
+ \advance\Mfx@piece@count\@ne
+ \MFX@buildpiece@down
+ \MFX@buildpiece@up
+% \end{macrocode}
+% Once \cs{Mfx@piece@content} has been built, we append it to the
+% \cs{Mfx@marginbox}.
+% \begin{macrocode}
+ \setbox\Mfx@marginbox\vbox{%
+ \unvbox\Mfx@marginbox
+ \box\Mfx@piece@content
+ \vskip\z@
+ }%
}
% \end{macrocode}
% \end{macros}
%
-% \begin{macros}{\MFX@margin@skip@up}
-% This one is even easier---all we have to do is add a skip to the
-% margin output box. We also need to make sure it's not getting dropped,
-% which might entail adding some \cs{vbox}\lit\{\lit\}s.
+% \subsection{Third pass: piecewise downward}
+% \begin{macros}{\MFX@buildpiece@down,\mfx@pieceout}
+% The next pass is another downward pass. This is very similar
+% to the first (global downward) pass, except we're now moving
+% the first several notes from \cs{mfx@marginout} into
+% \cs{mfx@pieceout} (again, inverting the order) and deferring
+% the rest back into \cs{mfx@marginout}.
% \begin{macrocode}
-\def\MFX@margin@skip@up#1{%
-%<debug>\MFX@debug{skip@up: #1}%
- \setbox\Mfx@marginbox\vbox{\vskip#1\relax\unvbox\Mfx@marginbox}%
+\def\MFX@buildpiece@down{%
+%<debug>\MFX@debug{buildpiece@down: ENTRY piece=\the\Mfx@piece@count,
+%<debug> marginpos=(\the\Mfx@marginpos@min, \the\Mfx@marginpos@max),
+%<debug> marginspace=\the\Mfx@marginspace,
+%<debug> marginout=\MFX@mac\mfx@marginout}%
+ \let\mfx@build@note\MFX@piece@note@down
+ \let\mfx@build@skip\MFX@piece@skip@down
+ \let\mfx@pieceout\@empty
+ \MFX@run@clear\mfx@marginout
+%<debug>\MFX@debug{buildpiece@down: RETURN pieceout=\MFX@mac\mfx@pieceout,
+%<debug> marginout=\MFX@mac\mfx@marginout}%
}
% \end{macrocode}
% \end{macros}
%
-% \begin{macros}{\MFX@margin@compressible@up}
-% This token gets put into \cs{mfx@marginout} during the first pass.
-% When it executes, it inserts a \cs{vskip} depending on how
-% much extra margin space (stored in \cs{Mfx@marginpos})
-% we need to excise. If also updates \cs{Mfx@marginpos}.
+% \begin{macros}{\MFX@piece@note@down,\MFX@piece@skip@down,\MFX@piece@clear}
+% We again define each of our building macros. First, the note builder.
+% When we encounter a note, we first zero out \cs{Mfx@marginspace}. Then
+% we need to decide whether to put it in the current piece, or whether
+% to defer it to the next piece, based on a few signals. A note will only
+% be deferred for one of two reasons. In either case, we store the decision
+% to defer in |@tempswa|, so we'll start by clearing it.
% \begin{macrocode}
-\def\MFX@margin@compressible@up#1{%
-%<debug>\MFX@debug{compressible@up: #1, excess=\the\dimexpr
-%<debug> \Mfx@marginpos-\Mfx@marginheight\relax}%
- \dimen@#1\relax
- \ifdim\Mfx@marginpos>\Mfx@marginheight
- \advance\dimen@\dimexpr\Mfx@marginheight-\Mfx@marginpos\relax
- \ifdim\dimen@<\z@
- \dimen@\z@
+\def\MFX@piece@note@down#1#2#3{%
+%<debug>\MFX@debug{piece@note@down: ENTRY: #1at #2, lowest=#3,
+%<debug> marginpos=(\the\Mfx@marginpos@min,\the\Mfx@marginpos@max,
+%<debug> marginspace=\the\Mfx@marginspace}%
+ \Mfx@marginspace\z@
+ \@tempswafalse
+% \end{macrocode}
+% The first reason to defer is if its callout position (|#2|)
+% is beneath the end of the current piece (\cs{Mfx@marginheight}) \emph{and}
+% if its lowest-possible-piece (|#3|, as computed in the second pass) is
+% \emph{after} the current one (\cs{Mfx@piece@count}).
+% \begin{macrocode}
+ \ifdim#2>\Mfx@marginheight
+ \ifnum#3>\Mfx@piece@count
+ \@tempswatrue
\fi
- \advance\Mfx@marginpos\dimexpr\dimen@-#1\relax
\fi
+% \end{macrocode}
+% The second possibility is that we've run out of room in this piece.
+% In this case, there's no need to check |#3|, since that number was
+% computed assuming everything that fit was as low as possible.
+% \begin{macrocode}
+ \ifdim\dimexpr\ht#1+\dp#1+\Mfx@marginpos@min>\Mfx@marginheight
+ \@tempswatrue
+ \fi
+% \end{macrocode}
+% If a note is deferred, then we push it and everything after it
+% back onto \cs{mfx@marginout}.
+% \begin{macrocode}
+ \if@tempswa
+%<debug>\MFX@debug{piece@note@down: clearing margin}%
+ \MFX@piece@clear
+ \mfx@build@note{#1}{#2}{#3}%
+ \else
+% \end{macrocode}
+% Otherwise, we have decided the note is going into this piece. In this
+% case, we now need to check if any compressible space is needed above it.
+% In order to get better alignment for deferred notes, we check for the
+% case that the current position is zero and the note's callout position
+% is \cs{MFX@minus@inf}. In this case, we change the callout position
+% to instead be the greater of 0 or $\cs{topskip}-\cs{ht}\#1$.
+% \begin{macrocode}
+ \dimen@#2\relax
+ \ifdim\dimen@=\MFX@minus@inf
+ \ifdim\Mfx@marginpos@max=\z@
+ \dimen@\topskip
+ \advance\dimen@-\ht#1\relax
+ \ifdim\dimen@<\z@ \dimen@\z@ \fi
+ \fi
+ \fi
+ \advance\dimen@-\Mfx@marginpos@max
+ \ifdim\dimen@>\z@
+%<debug>\MFX@debug{piece@note@down: adding compressible \the\dimen@}%
+ \MFX@snoc\mfx@pieceout{\noexpand\mfx@build@compressible{\the\dimen@}}%
+ \advance\Mfx@marginpos@max\dimen@
+ \fi
+% \end{macrocode}
+% After (maybe) adding the compressible space, we now add the
+% (incompressible) box itself, and accumulate its height in both position
+% registers. We no longer need the piece index or the position, so we
+% only store the box itself here.
+% \begin{macrocode}
+ \MFX@snoc\mfx@pieceout{\noexpand\mfx@build@note{#1}}%
+ \advance\Mfx@marginpos@min\dimexpr\ht#1+\dp#1\relax
+ \advance\Mfx@marginpos@max\dimexpr\ht#1+\dp#1\relax
+ \fi
+}
+% \end{macrocode}
+%
+% Skips are a bit more complicated now. We no longer gobble the
+% initial skips (since the skips at the top and bottom of the page
+% have already been eaten). Instead, we need to look at
+% \cs{Mfx@marginspace}: if it's nonzero, we substract it from the
+% skip length before adding it incompressibly (if there's any left).
+% While we have piece number information here, we just pass it on
+% to the upward pass, which can choose to ``late-defer'' initial
+% (i.e. the bottom-most) skips in a piece.
+% \begin{macrocode}
+\def\MFX@piece@skip@down#1#2{%
+ \dimen@#1\relax
+ \ifdim\Mfx@marginspace>\z@
+ \advance\dimen@-\Mfx@marginspace
+ \ifdim\dimen@<\z@ \dimen@\z@ \fi
+ \advance\Mfx@marginspace-\dimen@
+ \fi
+% \end{macrocode}
+% At this point, \cs{dimen@} now stores any further incompressible
+% skip we need to add, which is now relative to the top of this piece.
+% In that case (note that \cs{Mfx@marginspace} is now necessarily zero),
+% we need to check that it actually fits in the current piece, and if
+% not, defer it.
+% \begin{macrocode}
\ifdim\dimen@>\z@
- \MFX@margin@skip@up\dimen@
+ \ifdim\dimexpr#1+\Mfx@marginpos@min>\Mfx@marginheight
+ \MFX@piece@clear
+ \mfx@build@skip{\the\dimen@}{#2}%
+ \else
+% \end{macrocode}
+% If the skip \emph{does} fit, we need to add it to \cs{mfx@pieceout}
+% and advance the position registers.
+% \begin{macrocode}
+ \MFX@snoc\mfx@pieceout{\noexpand\mfx@build@skip{\the\dimen@}{#2}}%
+ \advance\Mfx@marginpos@min\dimen@
+ \advance\Mfx@marginpos@max\dimen@
+ \fi
+ \fi
+}
+% \end{macrocode}
+%
+% Finally, we need to handle the case of deferring material. By
+% analogy with the previous two passes, we'll continue to refer to
+% this as clearing. In this case, we need to redefine the note and
+% skip macros to save themselves back to \cs{mfx@marginout}.
+% \begin{macrocode}
+\def\MFX@piece@clear{%
+%<debug>\MFX@debug{piece@clear}%
+ \def\mfx@build@note##1##2##3{%
+ \MFX@cons\mfx@marginout{\noexpand\mfx@build@note##1{##2}{##3}}}%
+ \def\mfx@build@skip##1##2{%
+ \MFX@cons\mfx@marginout{\noexpand\mfx@build@skip{##1}{##2}}}%
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \subsection{Fourth pass: piecewise upward}
+% \begin{macros}{\MFX@buildpiece@up}
+% We are now ready for the final pass, where we take the reversed
+% list of notes for this piece and stack them up, compressing as much
+% compressible space as necessary to make them all fit. Since this
+% is the last pass, we can finally prepend all the boxes into
+% \cs{Mfx@piece@content}. Because it is still possible for pieces
+% to have skips at the bottom, we need to worry about which piece
+% these skips belong in. Since we've passed forward the lowest-piece
+% information from pass 2, we can choose at the last possible moment
+% to defer the bottom-most skips of a piece to the next piece (by
+% prepending it to \cs{mfx@marginout}. Note that compressible spaces
+% will \emph{never} be at the beginning of \cs{mfx@pieceout}. We
+% store the excess space in \cs{Mfx@marginheight}.
+% \begin{macrocode}
+\def\MFX@buildpiece@up{%
+ \Mfx@marginheight\dimexpr\Mfx@marginpos@max-\Mfx@marginheight\relax
+ \ifdim\Mfx@marginheight<\z@\Mfx@marginheight\z@\fi
+%<debug>\MFX@debug{buildpiece@up: excess=\the\Mfx@marginheight}%
+ \let\mfx@build@note\MFX@piece@note@up
+ \let\mfx@build@compressible\MFX@piece@compressible@up
+ \let\mfx@build@skip\MFX@piece@skip@maybedefer
+ \MFX@run@clear\mfx@pieceout\relax
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\MFX@piece@skip@maybedefer}
+% As mentioned earlier, the initial skips in a piece may be deferred
+% to later pieces, provided they can possibly go there. Here we
+% check the |#2| argument against \cs{Mfx@piece@count} and defer if
+% it is larger. Otherwise, we switch back to the standard behavior
+% defined in \cs{MFX@piece@skip@up}. Deferred skips do not need to
+% be subtracted from the excess because they were never compressible
+% in the first place.
+% \begin{macrocode}
+\def\MFX@piece@skip@maybedefer#1#2{%
+ \ifnum#2>\Mfx@piece@count
+%<debug>\MFX@debug{piece@skip deferring: #1, #2 (\the\Mfx@piece@count)}%
+ \MFX@snoc\mfx@marginout{\noexpand\mfx@build@skip{#1}{#2}}%
+ \else
+ \let\mfx@build@skip\MFX@piece@skip@up
+ \mfx@build@skip{#1}{#2}%
+ \fi
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\MFX@piece@note@up,\MFX@piece@skip@up}
+% Now that we've taken care of late deferrals, we can define the
+% standard behavior without worrying as much about that.
+% These macros finally set their contents into \cs{Mfx@piece@content},
+% as well as reset \cs{mfx@build@skip} back to its standard value.
+% \begin{macrocode}
+\def\MFX@piece@note@up#1{%
+%<debug>\MFX@debug{piece@note@up: #1}%
+ \setbox\Mfx@piece@content\vbox{%
+ \box#1%
+ \unvbox\Mfx@piece@content}%
+ \let\mfx@build@skip\MFX@piece@skip@up
+}
+% \end{macrocode}
+% Skips are also straightforward.
+% \begin{macrocode}
+\def\MFX@piece@skip@up#1#2{%
+%<debug>\MFX@debug{skip@up: #1=\the\dimexpr#1\relax (#2)}%
+ \setbox\Mfx@piece@content\vbox{%
+ \vskip#1\relax
+ \unvbox\Mfx@piece@content}%
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\MFX@piece@compressible@up}
+% Finally we come to the compressible space. Here, as long as
+% there's excess space (\cs{Mfx@marginheight}) we drop the
+% compressible space. Once the excess is exhausted, we insert
+% them as normal skips.
+% \begin{macrocode}
+\def\MFX@piece@compressible@up#1{%
+%<debug>\MFX@debug{compressible@up: #1, excess=\the\Mfx@marginheight}%
+ \advance\Mfx@marginheight-#1\relax
+ \ifdim\Mfx@marginheight<\z@
+ \MFX@piece@skip@up{-\Mfx@marginheight}\relax
+ \Mfx@marginheight\z@
\fi
}
% \end{macrocode}
@@ -840,11 +1422,13 @@
%<debug>\MFX@debug{dumpmargins}%
\loop
\unless\ifx\mfx@marginlist\@empty
+%<debug>\MFX@debug{dumpmargins: marginlist=\MFX@mac\mfx@marginlist}%
\let\temp@\mfx@marginlist
\vbox{}\clearpage
\ifx\temp@\mfx@marginlist
\PackageError{marginfix}{lost some margin notes%
-%<debug>: \meaning\mfx@marginlist
+ \ifx\mfx@marginstart\relax\ (missing \noexpand\unblockmargin)\fi
+%<debug>: \MFX@mac\mfx@marginlist
}\@eha
\let\mfx@marginlist\@empty % be nicer by just dropping one?
% TODO: also, set an emergency mode to allow oversized notes
@@ -859,10 +1443,10 @@
%
% \begin{macros}{\marginskip}
% Inserting a skip in the margin list is simple. We need only
-% append \cs{mfx@margin@skip} to \cs{mfx@marginlist}.
+% append \cs{mfx@build@skip} to \cs{mfx@marginlist}.
% \begin{macrocode}
\def\marginskip#1{%
- \MFX@cons\mfx@marginlist{\noexpand\mfx@margin@skip{#1}}%
+ \MFX@cons\mfx@marginlist{\noexpand\mfx@build@skip{#1}}%
}
% \end{macrocode}
% \end{macros}
@@ -871,7 +1455,7 @@
% Likewise, \cs{clearmargin} is easy too.
% \begin{macrocode}
\def\clearmargin{%
- \MFX@cons\mfx@marginlist{\noexpand\mfx@margin@clear}%
+ \MFX@cons\mfx@marginlist{\noexpand\mfx@build@clear}%
}
% \end{macrocode}
% While we call \cs{softclearmargin} a ``clear margin'', it's
@@ -904,6 +1488,86 @@
% \end{macrocode}
% \end{macros}
%
+% \begin{macros}{\blockmargin,\MFX@blockmargin}
+% We need two macros to process the optional bracket argument.
+% Essentially, \cs{blockmargin} just checks that
+% \cs{mfx@marginstart} is defined and then appends a new item to
+% the \cs{mfx@marginpieces} list to indicate a piece that starts
+% at \cs{mfx@marginstart} and ends at the current position, potentially
+% modified by the argument. It then resets \cs{mfx@marginstart} to
+% \cs{relax} and optionally adds a \cs{softclearmargin} if there was no
+% star, to keep margin material separated on either side of the phantom.
+% \begin{macrocode}
+\def\blockmargin{%
+ \@ifnextchar[%]
+ \MFX@blockmargin
+ {\MFX@blockmargin[0\p@]}%
+}
+\def\MFX@blockmargin[#1]{%
+ \MFX@inject{%
+ \ifx\mfx@marginstart\relax
+ \PackageError{marginfix}{two \\blockmargin with no \\unblockmargin}\@eha
+ \else
+ \MFX@cons\mfx@marginpieces{\noexpand
+ \@elt{\mfx@marginstart}{\expandafter\dimexpr\mfx@ypos+#1\relax}}%
+ \global\let\mfx@marginstart\relax
+ \global\advance\Mfx@piece@count\@ne
+ \fi
+ }%
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\unblockmargin,\MFX@unblockmargin}
+% This is the other half of \cs{blockmargin}. It ensures that the
+% margin is currently blocked, and if so, sets \cs{mfx@marginstart}
+% back to a real dimension (the current page position, plus the optional
+% modifier).
+% \begin{macrocode}
+\def\unblockmargin{%
+ \@ifnextchar[%]
+ \MFX@unblockmargin
+ {\MFX@unblockmargin[0\p@]}%
+}
+\def\MFX@unblockmargin[#1]{%
+ \MFX@inject{%
+ \ifx\mfx@marginstart\relax
+ \xdef\mfx@marginstart{\dimexpr\mfx@ypos+#1\relax}%
+ \else
+ \PackageError{marginfix}{\\unblockmargin with no \\blockmargin}\@eha
+ \fi
+ }%
+}
+% \end{macrocode}
+% \end{macros}
+%
+% \begin{macros}{\marginphantom,\MFX@marginphantom}
+% The \cs{marginphantom} command is basically just a concatenation of
+% \cs{blockmargin} and \cs{unblockmargin}. We reimplement it from the
+% ground up mainly so that the error messages make more sense.
+% \begin{macrocode}
+\def\marginphantom{%
+ \@ifnextchar[%]
+ \MFX@marginphantom
+ {\MFX@marginphantom[0\p@]}%
+}
+\def\MFX@marginphantom[#1]#2{%
+ \ifdim#2<\z@\MFX@marginphantom[#1+#2]{-#2}\else
+ \MFX@inject{%
+ \ifx\mfx@marginstart\relax
+ \PackageError{marginfix}{\\marginphantom while margin blocked}\@eha
+ \else
+ \MFX@cons\mfx@marginpieces{\noexpand
+ \@elt{\mfx@marginstart}{\expandafter\dimexpr\mfx@ypos+#1\relax}}%
+ \xdef\mfx@marginstart{\dimexpr\mfx@ypos+#1+#2\relax}%
+ \global\advance\Mfx@piece@count\@ne
+ \fi
+ }%
+ \fi
+}
+% \end{macrocode}
+% \end{macros}
+%
% \section{Random scribbles}
%
% Later we'll get fancier with putting notes next to top/bottom
@@ -917,7 +1581,7 @@
% now that's all we'll do.
%
% \section{Parting words}
-% Finish it up
+% Finish it up.
% \begin{macrocode}
\makeatother
%</package>