1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
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}
%</driver>
%
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\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}
%</driver>
% \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}
%<debug>\def\MFX@debug{\@ifstar\message{\message{^^JMFX:}\message}}
%<debug>\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
%<debug>\MFX@debug{addmarginpar (running insert) \@marbox/\@currbox at
%<debug> \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}%
}%
%<debug>\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{%
%<debug>\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
%<debug>\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{%
%<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
% \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
%<debug>\MFX@debug{buildmargin@down: RETURN}%
%<debug>\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{%
%<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
\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
%<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}.
% \begin{macrocode}
\def\MFX@whichbox#1#2{%
\if\MFX@leftmargin
\def\@marbox{#1}%
\else
\def\@marbox{#2}%
\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}.
% \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}}%
}
% \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{%
%<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}}%
}
% \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
%<debug>\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{%
%<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
}
% \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{%
%<debug>\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{%
%<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
}
% \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{%
%<debug>\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{%
%<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@
\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{%
%<debug>\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%
%<debug>: \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
%</package>
% \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 \~}
%%
|