From 114a4d955c87445db34af4882ede0351ccb0e74c Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 8 Sep 2010 00:24:22 +0000 Subject: new package marginfix (29aug10) git-svn-id: svn://tug.org/texlive/trunk@19602 c570f23f-e606-0410-a88d-b1316a301751 --- .../source/latex/marginfix/marginfix.dtx | 951 +++++++++++++++++++++ .../source/latex/marginfix/marginfix.ins | 5 + 2 files changed, 956 insertions(+) create mode 100644 Master/texmf-dist/source/latex/marginfix/marginfix.dtx create mode 100644 Master/texmf-dist/source/latex/marginfix/marginfix.ins (limited to 'Master/texmf-dist/source/latex/marginfix') diff --git a/Master/texmf-dist/source/latex/marginfix/marginfix.dtx b/Master/texmf-dist/source/latex/marginfix/marginfix.dtx new file mode 100644 index 00000000000..b0686483fd7 --- /dev/null +++ b/Master/texmf-dist/source/latex/marginfix/marginfix.dtx @@ -0,0 +1,951 @@ +% \iffalse +% +% Copyright 2010 Stephen Hicks, All rights reserved. +% marginfix.dtx - 29 Jul 2010 +% originally floatprobsbegone, created 21 Mar 2008 +% +% Run LaTeX on this document to produce documentation. +% Run LaTeX on marginfix.ins to produce the package. +%<*driver> +\ProvidesFile{marginfix.dtx} +% +% +%\NeedsTeXFormat{LaTeX2e} +%\ProvidesPackage{marginfix}% + [2010/08/28 v0.9.1 Fix Margin Paragraphs] +%<*driver> +\documentclass{ltxdoc} +\CheckSum{546} +%\OnlyDescription % (un)comment this line to show (hide) source code +\RecordChanges +\EnableCrossrefs +\CodelineIndex % (un)comment this line to index source by page (line) +\begin{document} + \newcommand*\Lopt[1]{\textsf {#1}} + \newcommand*\lit[1]{\texttt{\char`#1}} %% literal character (funny catcodes) + \parindent0pt + \def\*#1{\texttt{\string#1}} %% sdh - |...| doesn't work in headings + \makeatletter + % + \let\pkg\textsf + \newcount\mac@depth\mac@depth\z@ + \newcommand\@macros{}\newcommand\@endmacros{} + \catcode`&3 %% we use a funny catcode to ensure never used. + \def\@macros#1,{\macro{#1}\global\advance\mac@depth\@ne\relax + \@ifnextchar&\@gobble\@macros} + \def\@endmacros{\let\mac@next\relax\ifnum\mac@depth>\z@ + \endmacro\let\mac@next\@endmacros + \global\advance\mac@depth\m@ne\fi\mac@next} + \newenvironment{macros}[1]{\@macros#1,&}{\@endmacros} + \catcode`&4 %% put it back + \makeatother %% must be balanced for character table to work properly + % + \DocInput{marginfix.dtx} + \setcounter{IndexColumns}{2} + \PrintIndex + \PrintChanges +\end{document} +% +% \fi +% \changes{v0.0}{2008/03/21} +% {(SDH) Initial version of floatprobsbegone.} +% \changes{v0.9}{2010/08/18} +% {(SDH) Initial CTAN version.} +% \changes{v0.9.1}{2010/08/28} +% {(SDH) Fix bug where we alternated sides in article.} +% +% \GetFileInfo{marginfix.dtx} +% \title{\Lopt{marginfix} package documentation} +% \author{Stephen Hicks\\% +% \texttt{sdh33@cornell.edu}\\% +% \texttt{http://shicks.github.com/marginfix}} +% \date{\fileversion{} -- \filedate} +% \maketitle +% +% \part*{Usage} +% \section{Overview} +% Authors using \LaTeX\ to typeset books with significant margin material +% often run into the problem of long notes running off the bottom of the +% page. A typical workaround is to insert \cs{vshift}s by hand, but +% this is a tedious process that is invalidated when pagination changes. +% Another workaround is \pkg{memoir}'s \cs{sidebar} function, but this can be +% 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. +% +% \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} +% 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. +% +% \DescribeMacro{\marginskip} +% Calling \cs{marginskip}\marg{length} will insert an incompressible +% skip in the margin. These skips will force neighboring notes on +% the same page to be separated, but will disappear at the top or +% bottom of a margin. +% +% \DescribeMacro{\clearmargin}\DescribeMacro{\softclearmargin} +% In an analog to \cs{clearpage}, \cs{clearmargin} prevents any further +% material from being added to the current margin. These calls are +% cumulative, so that two \cs{clearmargin}s in a row will produce a +% completely empty margin on the next page as well. If this is not +% the desired effect, use \cs{softclearmargin}, which is effectively +% idempotent: multiple calls have the same effect as one call to +% end the current margin. +% +% \DescribeMacro{\extendmargin} +% If a page has too much margin material to fit and an important note +% is floating to the next page, \cs{extendmargin}\marg{length} will +% extend the margin (for the current page only) by the given length. +% If the length is negative, the margin will shrink. Multiple calls +% on the same page are cumulative. +% +% \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. +% Multiple calls before the same note are cumulative. +% +% \DescribeMacro{\marginheightadjustment} +% If all the margins are the wrong size, the height of the margin on every +% page can be adjusted by assigning a non-zero value to the dimension +% register \cs{marginheightadjustment} (as in +% \cs{marginheightadjustment}\texttt{=}$\langle$\emph{length}$\rangle$). +% This is effectively the same as a call to +% \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 +% 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. +% +% \section{Interaction with other packages} +% \subsection{memoir} +% There are no known issues with \Lopt{memoir} at present, provided that +% \cs{sidebar} is not used. +% +% \subsection{mparhack} +% \Lopt{mparhack} was designed to deal with the problem of margin notes +% showing up in the wrong margin because the left/right was decided before +% it was known exactly which page the note would be on. Because we defer +% this decision to shipout time in this package, we are not susceptible +% to this problem, so \Lopt{mparhack} is no longer needed and should not +% be included (though I'm unaware whether it causes any actual problems). +% +% \subsection{Multiple columns} +% There is currently no support for multiple columns. +% +% \section{Coming attractions and known issues} +% 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 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 +% CS defined in terms of the box name/meaning, so as not to get in the +% way of \LaTeX's use of the insert registers). We would then add or +% not add phantoms in the right spots. We'd also need to shift all the +% callout points by the size of the top figures (unless we're using +% \cs{pdfsavepos}).) +% \end{itemize} +% +% \StopEventually{} +% +% \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. +% \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} +% prints a new line followed by ``|MFX: |'' and then the message. +% The newline can be suppressed with a |*|. We'll also ask for more +% error context in the debug mode. +% \begin{macrocode} +%\def\MFX@debug{\@ifstar\message{\message{^^JMFX:}\message}} +%\errorcontextlines=20 +% \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 +% 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 +% technically constant, but that refer to things that change, such +% as counters, token lists, dimension registers, etc. Finally, +% the lowercase |\mfx@| is used for control sequences whose meaning +% changes dynamically (i.e. variable macros). +% +% \section{Options} +% Here we define the various package options. +% \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 +% of margin notes relative to their callouts. This requires two +% passes to work, and the first time through, the margin notes +% will be positioned very na\"ively. +% \begin{macrocode} +\newif\ifmfx@ypos +\DeclareOption{ypos}{\mfx@ypostrue} +% \end{macrocode} +% \end{macros} +% +% Now we actually process the options. +% \begin{macrocode} +\ProcessOptions\relax +% \end{macrocode} +% +% \section{Variables} +% \begin{macros}{\mfx@marginlist} +% We need a place to store our list of marginal material. We +% store material in this variable using insert registers and +% a variety of macros, to be explained later. +% \begin{macrocode} +\let\mfx@marginlist\@empty +% \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. +% \begin{macrocode} +\newbox\Mfx@marginbox +% \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{macrocode} +\newdimen\Mfx@marginboxspace +\newdimen\Mfx@marginpos +% \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. +% \begin{macrocode} +\newdimen\Mfx@marginheight +% \end{macrocode} +% \end{macros} +% +% \begin{macros}{\Mfx@mparshift} +% We store the current shift in a dimension register. +% \begin{macrocode} +\newdimen\Mfx@mparshift +% \end{macrocode} +% \end{macros} +% +% \section{User-configurable dimensions} +% We export a few dimensions that the user can redefine to tweak behavior. +% \begin{macros}{\marginheightadjustment} +% This length will be added to the total margin height of each page +% (the default is zero). +% \begin{macrocode} +\newdimen\marginheightadjustment +% \end{macrocode} +% \end{macros} +% +% \begin{macros}{\marginposadjustment} +% We will offset each margin note from its callout location by this length +% (the default is zero). +% \begin{macrocode} +\newdimen\marginposadjustment +% \end{macrocode} +% \end{macros} +% +% \section{Plan of attack} +% \subsection{\cs{marginpar}} +% The default sequence of events for a \cs{marginpar} is roughly the following +% (assuming no errors): +% \begin{verbatim} +% \marginpar: +% let \@floatpenalty := (horizontal ? -10002 : -10003) +% allocate inserts \@currbox and \@marbox from \@freelist +% let \count\@marbox := -1 % signifies marginpar (not float) +% if optional argument then \@xmpar else \@ympar +% \@xmpar: +% \@savemarbox \@currbox := required argument +% \@savemarbox \@marbox := optional argument +% \@xympar +% \@ympar: +% \@savemarbox \@currbox := required argument +% copy \@marbox := \@currbox +% \@xympar +% \@xympar: +% append \@marbox to \@currlist +% \end@float +% \end@float: +% append \@currbox to \@currlist +% if horizontal then following two lines are in \vadjust: +% \penalty -10004 +% \penalty \@floatpenalty +% \end{verbatim} +% +% To get the rest of the picture, we need to peek into the +% output routine. The pertinent parts are as follows (in +% vanilla \LaTeX): +% \begin{verbatim} +% \output: +% if \outputpenalty < -10000 then +% \@specialoutput +% else +% do regular output... +% details for dealing with footnotes... +% \@specialoutput: +% switch \outputpenalty: +% case -10001: \@doclearpage +% case -10004: set box \@holdpg := \vbox{\unvbox255} +% case -10002 or -10003: +% set box \@holdpg := \vbox{\unvbox\@holdpg \unvbox255} +% let \@pageht := \ht\@holdpg, \@pagedp := \dp\@holdpg +% \unvbox\@holdpg +% pop \@currbox off of \@currlist +% \@addmarginpar (assuming \count\@currbox <= 0) +% \@addmarginpar: +% pop \@marbox off of \@currlist +% free \@currbox and \@marbox back to \@freelist +% if left-hand margin then let \@marbox := \@currbox +% let \@tempdima := \@mparbottom - \@pageht + \ht\@marbox +% if \@tempdima < 0 then let \@tempdima := 0 +% let \@mparbottom := \@pageht + \@tempdima + \dp\@marbox + \marginparpush +% decrement \@tempdima := \@tempdima - \ht\@marbox +% prepend \vskip\@tempdima to \@marbox +% let \ht\@marbox := \dp\@marbox := 0 +% \kern -\@pagedp, \nointerlineskip +% set an \hbox to \columnwidth (zero height/depth): +% attach \@marbox to correct margin +% set a \vbox with height 0 and depth \@pagedp +% \end{verbatim} +% +% We see from here that \cs{@addmarginpar} is the place where {\LaTeX} +% does the work of calculating the current page position and where the +% next note should go, and then actually puts it there. We will need +% to completely replace this routine, but can leave everything else +% as is. +% +% \subsection{\cs{output}} +% While \LaTeX's margin routines end with \cs{@addmarginpar}, we must +% dig even deeper to apply our patch, since we need to insert some +% code to run during the \emph{main} output routine that ships out +% each page. Thus, we'll expand ``\texttt{do regular output...}'' +% from the previous \cs{output} listing. +% \begin{verbatim} +% do regular output...: +% \@makecol +% do { \@opcol \@startcolumn } while @fcolmade +% \@makecol: +% set box \@outputbox := box255 (plus any footnotes) +% let \@freelist := \@freelist + \@midlist, \@midlist := \@empty +% \@combinefloats +% add \@texttop and \@textbottom to \@outputbox (default no-op) +% \@opcol: +% \@outputpage (of \@outputdblcol in twocolumn mode) +% let \@mparbottom := \@textfloatsheight := 0 +% \@floatplacement +% \@startcolumn: +% try to make a float column from \@deferlist, setting @fcolmade +% if !@fcolmade then add floats from \@deferlist to next column +% \@combinefloats: +% aggregate \@toplist floats into a box and prepend to \@outputbox +% aggregate \@botlist floats into a box and append to \@coutputbox +% free inserts from \@toplist and \@botlist +% \@outputpage: +% ship out the page +% reset a bunch of stuff +% let \@colht := \textheight (in \@outputpage) +% \end{verbatim} +% +% We've seen two main times when action occurs: callout time and +% shipout time. We proceed chronologically with our patches. +% +% \section{Callout-time patches} +% \begin{macros}{\@addmarginpar} +% The first thing we must modify is that at callout time, we need to +% get the inserts into \cs{mfx@marginlist}. This should happen in the +% 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. +% \begin{macrocode} +\def\@addmarginpar{% + \@next\@marbox\@currlist{}\MFX@bug +%\MFX@debug{addmarginpar (running insert) \@marbox/\@currbox at +% \the\c@page:\the\@pageht, marginlist=\meaning\mfx@marginlist}% + \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}% + }% +%\MFX@debug{addmarginpar (exit): marginlist=\meaning\mfx@marginlist}% +} +% \end{macrocode} +% \end{macros} +% +% \begin{macros}{\MFX@cons,\MFX@snoc} +% 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 +% corectly protected. We also define snoc, which prepends. +% Note that we could put the \cs{temp@} definition into a group +% if it was really gonna matter\ldots +% \begin{macrocode} +\def\MFX@cons#1#2{% + \edef\temp@{#2}% + \expandafter\expandafter\expandafter\gdef + \expandafter\expandafter\expandafter#1% + \expandafter\expandafter\expandafter{\expandafter#1\temp@}% +} + +\def\MFX@snoc#1#2{% + \edef\temp@{#2}% + \expandafter\expandafter\expandafter\gdef + \expandafter\expandafter\expandafter#1% + \expandafter\expandafter\expandafter{\expandafter\temp@#1}% +} +% \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 +% 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} +% and then discard the last box to figure out what height we're really +% at, since \cs{@holdpg} includes the box from the line we're currently +% on, and we want to be level with the \emph{top} of that box, rather +% than the baseline. But since \cs{@holdpg} is accessible only deep +% 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? +% \begin{macrocode} +\def\MFX@getypos{% + \edef\mfx@ypos{% + \the\dimexpr\@pageht - \Mfx@strutheight + + \marginposadjustment + \Mfx@mparshift\relax}% + \global\Mfx@mparshift\z@ +} +% \end{macrocode} +% \end{macros} +% +% \begin{macros}{\marginpar,\Mfx@strutheight} +% We need to make sure \cs{Mfx@strutheight} gets defined somewhere, +% and the best time is probably right before the \cs{marginpar} does +% its work, since that will most likely ensure we're using the right +% font for the line. +% \begin{macrocode} +\newdimen\Mfx@strutheight +\edef\marginpar{% + \unexpanded{\setbox\@tempboxa\hbox{\strut}\Mfx@strutheight\ht\@tempboxa}% + \expandafter\unexpanded\expandafter{\marginpar}% +} +% \end{macrocode} +% \end{macros} +% +% \section{Shipout-time patches} +% \begin{macros}{\@combinefloats,\MFX@combinefloats@before} +% We need to patch in somewhere before \cs{@combinefloats} at the latest, +% so that any heights calculated from \cs{@pageht} are correct---otherwise +% the top figures will confuse us. So we'll start by simply adding our +% own \cs{MFX@combinefloats@before} at the very beginning of \cs{@combinefloats} +% \begin{macrocode} +\expandafter\def\expandafter\@combinefloats\expandafter{\expandafter + \MFX@combinefloats@before\@combinefloats} +% \end{macrocode} +% +% \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). +% \begin{macrocode} +\def\MFX@combinefloats@before{% + \MFX@buildmargin + \MFX@attachmargin + \Mfx@marginheight\marginheightadjustment +} +% \end{macrocode} +% \end{macros} +% +% \begin{macros}{\MFX@attachmargin} +% We'll start with the second half of \cs{MFX@combinefloats@before}, +% since it's simpler. We need to do several things here. +% \begin{macrocode} +\def\MFX@attachmargin{% +%\MFX@debug{attachmargin}% +% \end{macrocode} +% 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 +% \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 + }}% +} +% \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... +% \begin{macrocode} +\def\MFX@buildmargin{% + \advance\Mfx@marginheight\@colroom +%\MFX@debug{buildmargin: marginheight=\the\Mfx@marginheight}% + \MFX@buildmargin@down + \MFX@buildmargin@up +} +% \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. +% \begin{macrocode} +\def\MFX@buildmargin@down{% +%\MFX@debug{buildmargin@down: ENTRY}% +%\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 +% \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. +% \begin{macrocode} + \expandafter\global\expandafter\let + \expandafter\mfx@marginlist\expandafter\@empty + \mfx@marginlist +%\MFX@debug{buildmargin@down: RETURN}% +%\MFX@debug{marginlist=\meaning\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{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). +% \end{enumerate} +% \begin{macrocode} +\def\MFX@margin@note@down#1#2#3{% +%\MFX@debug{note@down: ENTRY: #1/#2 at #3}% + \ifdim#3>\Mfx@marginpos + \dimen@\dimexpr#3-\Mfx@marginpos\relax +%\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} +%\MFX@debug{note@down: out of space: +% \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} +%\MFX@debug{note@down: adding \@marbox +% ht \the\ht\@marbox dp \the\dp\@marbox}% + \advance\Mfx@marginpos\dimexpr\ht\@marbox+\dp\@marbox\relax + \MFX@snoc\mfx@marginout{% + \noexpand\mfx@margin@note\@marbox + \noexpand\@cons\noexpand\@freelist#1% + \noexpand\@cons\noexpand\@freelist#2% + }% + \fi + \let\mfx@margin@skip\MFX@margin@skip@down +%\MFX@debug{note@down: RETURN space=\the\Mfx@marginboxspace, +% 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}. +% \begin{macrocode} +\def\MFX@whichbox#1#2{% + \if\MFX@leftmargin + \def\@marbox{#1}% + \else + \def\@marbox{#2}% + \fi +%\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}. +% \begin{macrocode} +\def\MFX@margin@skip@down#1{% +%\MFX@debug{skip@down #1}% + \advance\Mfx@marginpos#1\relax + \advance\Mfx@marginboxspace#1\relax + \MFX@snoc\mfx@marginout{\noexpand\mfx@margin@skip{#1}}% +} +% \end{macrocode} +% +% 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{macrocode} +\def\MFX@margin@clear@down{% +%\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}}% +} +% \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{macrocode} +\def\MFX@minus@inf{-4000pt} +% \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}. +% +% 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. +% \begin{macrocode} +\def\MFX@leftmargin{% + 00\fi % close out the \if + \@tempcnta\@ne + \if@mparswitch + \unless\ifodd\c@page + \@tempcnta\m@ne + \fi + \fi + \if@reversemargin + \@tempcnta-\@tempcnta + \fi +%\MFX@debug{margin on \ifnum\@tempcnta<\z@ left\else right\fi}% + \ifnum\@tempcnta<\z@ % start a new \if +} +% \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{macrocode} +\def\MFX@buildmargin@up{% +%\MFX@debug{buildmargin@up: excess=\the\dimexpr +% \Mfx@marginpos-\Mfx@marginheight\relax}% +%\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 +} +% \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{macrocode} +\def\MFX@margin@skip@gobble@up#1{% +%\MFX@debug{skip@gobble@up: #1}% + \advance\Mfx@marginpos-#1\relax +} +% \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. +% \begin{macrocode} +\def\MFX@margin@note@up#1{% +%\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 +} +% \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. +% \begin{macrocode} +\def\MFX@margin@skip@up#1{% +%\MFX@debug{skip@up: #1}% + \setbox\Mfx@marginbox\vbox{\vskip#1\relax\unvbox\Mfx@marginbox}% +} +% \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{macrocode} +\def\MFX@margin@compressible@up#1{% +%\MFX@debug{compressible@up: #1, excess=\the\dimexpr +% \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@ + \fi + \advance\Mfx@marginpos\dimexpr\dimen@-#1\relax + \fi + \ifdim\dimen@>\z@ + \MFX@margin@skip@up\dimen@ + \fi +} +% \end{macrocode} +% \end{macros} +% +% \section{Cleaning up} +% We need to worry about a few more things. First, what happens +% if we reach the end of the document and there are still deferred +% margin notes? We need to be able to dump all the margin notes +% whenever the user wants (i.e. before a new chapter), so we'll +% make a macro \cs{dumpmargins} to do this, and then make sure it +% gets called \cs{AtEndDocument}. Since we're looping to do this, +% we need to make darned sure that every \cs{newpage} shrinks the +% marginlist. +% \begin{macros}{\dumpmargins} +% \begin{macrocode} +\def\dumpmargins{% +%\MFX@debug{dumpmargins}% + \loop + \unless\ifx\mfx@marginlist\@empty + \let\temp@\mfx@marginlist + \vbox{}\clearpage + \ifx\temp@\mfx@marginlist + \PackageError{marginfix}{lost some margin notes% +%: \meaning\mfx@marginlist + }\@eha + \let\mfx@marginlist\@empty % be nicer by just dropping one? + % TODO: also, set an emergency mode to allow oversized notes + \fi + \repeat +} +\AtEndDocument{\dumpmargins} +% \end{macrocode} +% \end{macros} +% +% \section{User macros} +% +% \begin{macros}{\marginskip} +% Inserting a skip in the margin list is simple. We need only +% append \cs{mfx@margin@skip} to \cs{mfx@marginlist}. +% \begin{macrocode} +\def\marginskip#1{% + \MFX@cons\mfx@marginlist{\noexpand\mfx@margin@skip{#1}}% +} +% \end{macrocode} +% \end{macros} +% +% \begin{macros}{\clearmargin,\softclearmargin} +% Likewise, \cs{clearmargin} is easy too. +% \begin{macrocode} +\def\clearmargin{% + \MFX@cons\mfx@marginlist{\noexpand\mfx@margin@clear}% +} +% \end{macrocode} +% While we call \cs{softclearmargin} a ``clear margin'', it's +% actually just a big \cs{marginskip}. This allows us to stack +% multiple copies without backing them all up. +% \begin{macrocode} +\def\softclearmargin{% + \marginskip{\the\textheight}% +} +% \end{macrocode} +% \end{macros} +% +% \begin{macros}{\extendmargin} +% We overload \cs{Mfx@marginheight} to be the amount of extension +% at all times except shipout-time. +% \begin{macrocode} +\def\extendmargin#1{% + \advance\Mfx@marginheight#1\relax +} +% \end{macrocode} +% \end{macros} +% +% \begin{macros}{\mparshift} +% This is as simple as setting the dimen register. We advance so that +% the shifts are cumulative, but there's not really any point either way. +% \begin{macrocode} +\def\mparshift#1{% + \advance\Mfx@mparshift#1\relax +} +% \end{macrocode} +% \end{macros} +% +% \section{Random scribbles} +% +% Later we'll get fancier with putting notes next to top/bottom +% figures but for now, not so much. +% +% In the future we will support the use of \cs{pdfsavepos} and +% \cs{pdflastypos} for more accurately determining where the callouts +% actually were, which will end up going right around here. But in +% order to work with older versions of \LaTeX, we still need to +% support the old style of using \cs{@pageht} to figure that out, so for +% now that's all we'll do. +% +% \section{Parting words} +% Finish it up +% \begin{macrocode} +\makeatother +% +% \end{macrocode} +% \makeatother +% \Finale +% +% +% \iffalse +% +% The next line of code prevents DocStrip from adding the +% character table to the generated files(s). +\endinput +% \fi +% +%% \CharacterTable +%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +%% Digits \0\1\2\3\4\5\6\7\8\9 +%% Exclamation \! Double quote \" Hash (number) \# +%% Dollar \$ Percent \% Ampersand \& +%% Acute accent \' Left paren \( Right paren \) +%% Asterisk \* Plus \+ Comma \, +%% Minus \- Point \. Solidus \/ +%% Colon \: Semicolon \; Less than \< +%% Equals \= Greater than \> Question mark \? +%% Commercial at \@ Left bracket \[ Backslash \\ +%% Right bracket \] Circumflex \^ Underscore \_ +%% Grave accent \` Left brace \{ Vertical bar \| +%% Right brace \} Tilde \~} +%% diff --git a/Master/texmf-dist/source/latex/marginfix/marginfix.ins b/Master/texmf-dist/source/latex/marginfix/marginfix.ins new file mode 100644 index 00000000000..f63a96be807 --- /dev/null +++ b/Master/texmf-dist/source/latex/marginfix/marginfix.ins @@ -0,0 +1,5 @@ +\input docstrip.tex +\keepsilent +\askonceonly +\generate{\file{marginfix.sty}{\from{marginfix.dtx}{package,debug}}} +\endbatchfile -- cgit v1.2.3