summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/magaz/magaz.sty
blob: b6ba7f74ca8d5325944db5169c27ba708c4bafd3 (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
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
% magaz.sty  Ver 0.4   24-Nov-2011  "Magazine style"
% Copyright 1999-2011, Donald Arseneau,   asnd@triumf.ca,  Vancouver, Canada
% This software may be freely used, transmitted, reproduced, or modified
% provided that the copyright notice and this permission is retained.
%
% This version is just a single tool from a larger body of tools I am 
% unlikely to implement.  I wrote this in 1999 in response to a request
% on comp.text.tex.
%
% Features:
% Yes Special formatting for first line of text in a paragraph
% Not Special formatting for for first n lines (allow each different)
% Not Also for first character (drop caps) (working together)
% No  "Continued on"/"continued from" markers (like varioref marks)
% No  wrapfig spanning columns
% No  wrapfig placed at fixed location on page
% No Piecing together fragments of gallies to fit page (maybe flowfram)
%
% Instructions:
%
% \FirstLine{<text>}
%
% The "\FirstLine" command takes one argument: Some text.
% 
% The "\FirstLine" command is placed at the beginning of a paragraph, 
% and takes one argument: Some text. The first line of this text will 
% be formatted according to "\FirstLineFont"; but if the text occupies 
% less than a full line of the paragraph, all that text (and no more) 
% will be affected by "\FirstLineFont".
% 
% You should define "\FirstLineFont" appropriately as either a switch 
% or a text-command; as in "\renewcommand\FirstLineFont{\MakeUppercase}".
% The defult definition performed in \pkg{magaz.sty} is 
% "\providecommand\FirstLineFont{\scshape}".
% 
% The parameter for "\FirstLine" should be ordinary text, not containing
% lists or displayed equations -- such things will give you a ``Bad text''
% error. If the parameter text ends with a space, that space will be 
% removed. A line break may sometimes be permitted after the parameter 
% text even if the ensuing text prohibits one (using "~"). Furthermore, 
% the text should be constant, or else the successive measurements made 
% internally will not be consistent, and the output may be corrupted
% (with words missing or duplicated). Some subtle sources of inconstant 
% text are:
%  -  Incrementing a counter (and printing the value).              
%  -  "\everypar" that executes once and is cleared. (This occurs after
%     section heads and inside list/quotation/center/etc. environments,
%     but those cases are handled, somewhat.)
%  -  A "\FirstLineFont" that affects hyphenation (as "\texttt" or a
%     language setting will).
%  -  Changing paragraph-layout parameters in "\FirstLineFont".
% 
% Other deviations from simple text can give poor formatting. Here are some
% `advanced' tips:
%  -  Using "\FirstLine" in the middle of a paragraph will make a mess.
%     (It should be used to start a paragraph, or placed at the beginning
%     of one started with "\noindent".  Using it after "\\" should also
%     work.)
%  -  Multiple "\vspace" or "\\*" or "\\[]" will cause failure;
%     a single "\vspace" will be ignored.
%  -  Although there is no corruption if used immediately after a
%     "\section" command (or similar) that suppresses indentation,
%     the paragraph will likely be indented anyway.  The fix for
%     this (and similar problems) is to begin the paragraph with
%     "\noindent" before "\FirstLine".
%  -  Using an inflexible "\parfillskip" might cause some highlighted
%     first-line text to be dragged down to the second line. (Providing
%     more text in the argument will usually solve this.) (If you 
%     don't know about "\parfillskip" you probably don't have to worry.)
%  -  A large font for "\FirstLineFont" may be too crowded with the
%     second line, and inserting "\vspace" will not help (this should
%     be improved) so you may need to resort to a "\strut", as with
%     "\renewcommand\FirstLineFont{\large\strut\MakeUppercase}"
%
% The "\FirstLine" system is intended to be used in a replacement for 
% a normal sectioning command in a document class; "\paragraph" would be 
% appropriate.  In particular, this "\paragraph" (or whatever) should 
% insert vertical space and penalties etc., and probably "\noindent"
% at the start of the argument.  The document class should also define 
% "\FirstLineFont" appropriately as either a switch or a text-command; 
% as in "\renewcommand\FirstLineFont{\scshape\textcolor{blue}}".  The 
% defult definition is "\providecommand\FirstLineFont{\scshape}".

\ProvidesPackage{magaz}[2011/11/24 v0.4]

\newcommand\FirstLine[1]{%
 \relax\if@inlabel\noindent\fi % produce any pending list item label
 \begingroup
 % typeset text 3 times: 1) using all breaks to count segments; 2) with
 % a full first line and \FirstLineFont to get first line and remaining
 % segments; 3) Using current font, keeping only `remaining segments'
 % on a single line. 
 \setbox\z@\box\mz@firstbox \setbox\z@\box\mz@remains % void the global boxes
 \setbox\@tempboxa\vbox{% 1) use all breaks
   \hbadness\maxdimen \hfuzz\maxdimen
   \hsize\z@ \leftskip\z@skip \rightskip\z@skip \parfillskip\fill
   \parshape\z@ \pretolerance\m@ne \tolerance\@ne 
   \doublehyphendemerits\z@ \finalhyphendemerits\z@
   #1\global\mathchardef\mz@spf\spacefactor\@@par
   \global\mathchardef\mz@numl\prevgraf
   %{\message{^^J^^J^^JText has \number\mz@numl\space segments:}\showhyphens{#1\unskip\unskip}}%
 }% end vbox "1)"
 \setbox\@tempboxa\vbox{% 2) first line, plus other segments
   \parshape \tw@ \z@\linewidth \z@\maxdimen 
   \doublehyphendemerits\z@ \finalhyphendemerits\z@
   %\linepenalty\z@
   % note no \hbadness\maxdimen \hfuzz\maxdimen at this stage
   \pretolerance\m@ne \parfillskip\fill
   {\FirstLineFont{#1}\@@par}%
   \ifnum\prevgraf>\tw@ % Bad argument: not simple text or too much text
     \mz@handlebad{#1}%
   \else
     \unskip\unkern\unskip\unpenalty \unskip\unkern\unskip\unpenalty
     \ifnum\prevgraf<\tw@ % All text fits on first line
       \global\setbox\mz@firstbox\lastbox % Grab that line
       %{\message{Entire text fits: }\showhyphens{\unhcopy\mz@firstbox\unskip\unskip\unpenalty}}%
       \setbox\z@\hbox{\unhcopy\mz@firstbox}%
       \begingroup
       \advance\linewidth-0.4em\relax
       \expandafter\endgroup
       \ifdim\wd\z@>0.97\linewidth
         %\message{^^JHandle wide first line: \the\wd\z@\space vs \the\linewidth. }%
         \global\setbox\mz@firstbox\hbox to\wd\mz@firstbox{%
             \unhcopy\mz@firstbox\unskip\unskip\unpenalty}% remove \parfillskip
         \global\setbox\mz@remains\hbox{}% Trigger keeping of full wide line
       \fi        % else \mz@remains remains void
     \else % 2 lines: text fills first line with some left over
       \setbox\z@\lastbox % remainders to \z@
       \ifvoid\z@ % could not grab last line 
         \mz@handlebad{#1}%
       \else 
         \unskip\unkern\unskip\unpenalty \unskip\unkern\unskip\unpenalty
         \global\setbox\mz@firstbox\lastbox % grab first line
         % Note: counting segments in this first line will be wrong if the line
         % ended with a hyphenation.  It could be possible to detect and adjust
         % for the resulting extra segment if it is deemed desirable to count the
         % first line directly.
         %{\message{First line is: }\showhyphens{\unhcopy\mz@firstbox\unskip}}%
         %{\message{Remaining segments are: }\showhyphens{\unhcopy\z@\unskip\unskip}}%
         %
         % 2a) break up "remaining segments":
         \hsize\z@ \hbadness\maxdimen \hfuzz\maxdimen
         \leftskip\z@skip \rightskip\z@skip \parfillskip\fill
         \parshape\z@ \pretolerance\m@ne \tolerance\@ne 
         {\everypar{}\noindent}% mid-par so no \everypar or \parindent
         \nobreak % \nobreak because leftskip adds breakpoint
         \unhbox\z@\unskip\unskip\unpenalty\@@par % gives number of "extra segments"
         %\message{There are \number\mz@numl\space segments in total and \the\prevgraf\space "remaining segments". }%
         \@tempcnta\mz@numl \advance\@tempcnta-\prevgraf 
         %\message{Number of segs in 1st line: \the\@tempcnta. }%
         \advance\@tempcnta\@ne % number of segs in 1st line plus 1
         \edef\@tempa{\the\@tempcnta\space}% 3) Collect "other segments"
         \@whilenum \@tempcnta>\@ne\do{% build \parshape lines
           \edef\@tempa{\@tempa \z@\z@}%
           \advance\@tempcnta\m@ne
         }%
         %\message{Parshape: \@tempa \z@\maxdimen}%
         \parshape \@tempa \z@\maxdimen
         #1\@@par
         \unskip\unkern\unskip\unpenalty \unskip\unkern\unskip\unpenalty
         \global\setbox\mz@remains\lastbox 
       \fi
     \fi
   \fi
 }% end vbox "2)"
 \endgroup
 \ifvoid\mz@firstbox
   #1% Error case: just output the text
 \else
   {\everypar{}\noindent}\nobreak % everypar was captured in firstbox
   \ifvoid\mz@remains % partial line only
     % Unbox the partial line. This allows equal stretching of spaces across
     % the line, but admits a slight chance that some \FirstLineFont may
     % carry over to the second line.
     \unhbox\mz@firstbox 
     \unskip\unskip\unpenalty % remove \rightskip \parfillskip \nobreak
     \allowbreak % allow a break rather than get dragged to next line (??)
   \else % full first line 
     % Output whole box to prevent unexpected linebreaks, especially for
     % an overfull line and at the bogus discretionary that TeX leaves before
     % a final (used) hyphen.
     \box\mz@firstbox\break 
     \unhbox\mz@remains
     \unskip\unskip\unpenalty % remove \rightskip \parfillskip \nobreak
     % (or remove forced \break for empty remains)
   \fi
   \spacefactor\mz@spf
 \fi
}

\newbox\mz@firstbox
\newbox\mz@remains

\providecommand\FirstLineFont{\scshape}

% In the future, I might allow some non-text material by using \vsplit
% as a fallback method of grabbing lines, and I might allow more or
% unusual text in the `remainders' by skipping the step of setting two
% lines (instead setting one first line plus many tiny lines all together).
% The following macro would then handle those cases with a secondary
% algorithm as an error recovery mechanism.  Right now it just gives an 
% error message and dumps out the text.

\def\mz@handlebad{\mz@error}
\def\mz@error#1{%
 \PackageError{magaz}{Bad text for \string\FirstLine\space ending\on@line}{}%
 \global\setbox\mz@remains\box\mz@firstbox % void first box
}
 
\endinput

Test file integrity:  ASCII 32-57, 58-126:  !"#$%&'()*+,-./0123456789
:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~