summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/fwlw/fwlw.sty
blob: 10a4ee04a5c46066d9357c01c7c88a900df398ba (plain)
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
%  F W L W . S T Y  ( First Word, Last Word )
%
%  Donald Arseneau  (1993, 1995)
%
%  The fwlw package provides a mechanism to determine the first and
%  last words on the current page, plus the first word on the *next*
%  page.  These can be used in head-lines or foot-lines.  The `words'
%  you see may not be real words, but any unbreakable object.
%
%  Two pagestyles are defined to print these words: \pagestyle{NextWordFoot}
%  which helps you read ahead to the word on the next page; and \pagestyle
%  {fwlwhead} which is like the headers in a lexicon.  Or you can use the
%  words in your own page-style. The words are made available in the box
%  registers:
%       \FirstWordBox   -  first word on this page
%       \NextWordBox    -  first word on next page
%       \LastWordBox    -  last word on this page
%  Use them in your header lines like: \usebox\LastWordBox.
%
%  Such labelling does not make much sense when \chapter generates a page
%  break, so the last page before a \chapter (or any \clearpage) gets 
%  a blank "next word", and the first page of the chapter gets a blank
%  "first word". 
%
%  Note that `words' may unfortunately be things like:
%    - two~words
%    - [ ]Word  ( [ ] represents a parindent box)
%    - a whole displayed equation
%    - the first column of an aligned equation
%    - anomalously blank, if there are \writes or split footnotes etc.
%    - partial words like  par-  or  -tial due to hyphenation.
%
%  (Major digression...)
%  An entirely different approach is possible using \mark and \obeyspaces,
%  and would have different problems.  The problems with catcode changes
%  may be more or less serious for your particular application.  (You are
%  invited to write a package using that method!)  The best solution would 
%  involve \mark and an input filter program to 
%  `\w{tag} \w{each} \w{word}, \w{in} \w{some} \w{way}.'
%  TeX has no \everyword hook to insert such tagging.
%
%     Copyright (C) 1993,1995 by Donald Arseneau
%     Vancouver, Canada, email asnd@triumf.ca
%     This software package may be freely used, transmitted, reproduced,
%     or modified provided that this notice is left intact.
%
% Declare a "unique" penalty value as flag
\mathchardef\LW@pen 12345

% allocate box registers
\newbox\FirstWordBox     \global\setbox\FirstWordBox\hbox{}
\newbox\NextWordBox      \global\setbox\NextWordBox\hbox{}
\newbox\LastWordBox      \global\setbox\LastWordBox\hbox{}
\newbox\LW@box           \global\setbox\LW@box\hbox{}
\newbox\LW@saved

% pagestyle fwlwhead: header line hsa first word and last word
\def\ps@fwlwhead{\let\@mkboth\@gobbletwo
 \def\@oddhead{\if@fcolmade\else % no word-heads on float pages.
   \usebox\FirstWordBox\hfil\usebox\LastWordBox\fi}%
 \let\@evenhead\@oddhead 
 \let\@oddfoot\@empty\let\@evenfoot\@oddfoot
 \let\chaptermark\@gobble\let\sectionmark\@gobble\let\subsectionmark\@gobble
 }

% pagestyle NextWordFoot: foot line has page number and next-page first word,
% but only on odd pages
\def\ps@NextWordFoot{\let\@mkboth\@gobbletwo
 \let\@oddhead\@empty\let\@evenhead\@oddhead
 \def\@oddfoot{\hfil\thepage\hfil\llap{\usebox\NextWordBox}}%
 \let\@evenfoot\@empty
 \let\chaptermark\@gobble\let\sectionmark\@gobble\let\subsectionmark\@gobble
 }

%  Shell around old output routine.  Gets first word from next page by
%  letting TeX continue with \vsize=0 to get a look at the next line.
%  Values of \outputpenalty for \specialoutput ( -10001 to -19999 ) are
%  simply run through the output routine.
%  \supereject and \clearpage give a blank "next word".
%  When called after making a stub-page the stub is returned to the
%  vertical list, the previous page is restored and shipped out normally,
%  but knowing what the next word will be.

\edef\FWLWnorm@L@output{\the\output}

\output{\@tempswafalse
\ifnum \outputpenalty>-\@MM \ifnum\outputpenalty<-\@M \@tempswatrue\fi\fi
\if@tempswa % special (float) output
%  \message{Float handler: penalty=\the\outputpenalty}%
   \FWLWnorm@L@output
\else
  \ifvoid\LW@saved % end of real page
%    \message{End of real page}%
     \global\setbox\LW@saved\copy\@cclv % save page
     \setbox\@tempboxa\vbox{\unvbox\@cclv \unskip\unkern\unpenalty
       \unskip\unkern\unpenalty \unskip\unkern\unpenalty
       \setbox\@tempboxa\lastbox
       \LW@getlast@word\@tempboxa\LastWordBox
     }\ifnum\outputpenalty>-\@MM % not \supereject
       \xdef\LW@vsize{\global\vsize\the\vsize 
          \global\holdinginserts\the\holdinginserts}%
       \global\vsize\z@ \global\holdinginserts\@ne 
     \else % \supereject, just output, don't look for word on next page
%      \message{caused by super-eject.}
       \global\setbox\@cclv\box\LW@saved
       \global\setbox\NextWordBox\hbox{}%
       \FWLWnorm@L@output
       \global\setbox\FirstWordBox\box\NextWordBox
     \fi
  \else % saved page => just did tiny page to get next word
%    \message{Just got next line:}{\tracingall\showboxdepth2 \showbox\@cclv}%
     \setbox\@tempboxa\vbox{\penalty\LW@pen\unvcopy\@cclv \LW@getall@boxes
       \ifvbox\LW@box \penalty\LW@pen\unvbox\LW@box \LW@getall@boxes\fi
       \ifvbox\LW@box \global\setbox\NextWordBox\hbox{}\else
         \LW@getfirst@word\LW@box\NextWordBox
       \fi}%  Return tiny page to page list:
     \unvbox\@cclv \ifnum\outputpenalty<\@M \penalty\outputpenalty\fi
     \LW@vsize\relax
     \global\setbox\@cclv\box\LW@saved
     \FWLWnorm@L@output
     \global\setbox\FirstWordBox\box\NextWordBox
\fi\fi}

% globally get last "word" from a box (#1) into another box (#2)
\def\LW@getlast@word#1#2{\setbox\@tempboxa\vbox{\hsize\maxdimen \@parboxrestore
  \hyphenpenalty\@M \exhyphenpenalty\@M 
  \rightskip\fill \looseness\@M \linepenalty\z@
  \noindent\unhbox#1\endgraf
  \unskip\unkern\unpenalty \global\setbox\LW@box\lastbox
  }\LW@repack{#2}}

% globally get first "word" from a box (#1) into another box (#2)
\def\LW@getfirst@word#1#2{\setbox\@tempboxa\vbox{\@parboxrestore
  \parshape\thr@@ \z@\z@ \z@\z@ \z@\maxdimen \parfillskip\fill
  \hyphenpenalty\@M \exhyphenpenalty\@M 
  \hbadness\@MM \overfullrule\z@ \hfuzz\maxdimen
  \ifhbox#1\noindent
   \vadjust{\penalty\LW@pen}\penalty-\@M\unhbox#1% eliminate previous \leftskip
  \else\ifvbox#1\penalty\LW@pen\unvbox#1\fi\fi
  \endgraf
  \@tempcnta\z@  \LW@getall@boxes}\LW@repack{#2}}

% Go through a vertical list that starts with special penalty
\def\LW@getall@boxes{\global\setbox\LW@box\lastbox \unskip\unkern \unskip\unkern
  \let\@tempa\relax
  \ifvoid \LW@box \advance\@tempcnta\@ne \else \@tempcnta\z@ \fi
  \ifnum\lastpenalty=\LW@pen \else \unpenalty\fi
  \ifnum\lastpenalty=\LW@pen \else \unpenalty\fi
  \ifnum\lastpenalty=\LW@pen \else \ifnum\@tempcnta<5
    \let\@tempa\LW@getall@boxes \fi \fi \unpenalty \@tempa}

% Put contents of \LW@box into hbox #1
\def\LW@repack#1{\global\setbox#1\hbox{\ifhbox\LW@box
   \unhbox\LW@box\unskip\unskip\unpenalty\unskip
  \else\ifvbox\LW@box\box\LW@box\fi\fi}}