spac-par.mkxl /size: 18 Kb    last modification: 2023-12-21 09:44
1%D \module
2%D   [       file=spac-par,
3%D        version=2009.10.16, % 1997.03.31, was core-spa.tex
4%D          title=\CONTEXT\ Spacing Macros,
5%D       subtitle=Paragraphs,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Spacing Macros / Paragraphs}
15
16\registerctxluafile{spac-par}{autosuffix}
17
18\unprotect
19
20% TODO: \appendtoks \strut \wrapuppar{\strut}\to \everypar
21
22%D New experimental stuff:
23
24% this might move to syst-ini.mkxl
25
26\setnewconstant\paragraphupdatecodes\numexpr
27    \tolerancefrozenparcode
28  + \loosenessfrozenparcode
29  + \linepenaltyfrozenparcode
30  + \widowpenaltyfrozenparcode
31  + \clubpenaltyfrozenparcode
32  + \brokenpenaltyfrozenparcode
33  + \demeritsfrozenparcode
34  + \orphanpenaltyfrozenparcode
35  + \singlelinepenaltyfrozenparcode
36\relax
37
38\setnewconstant\paragraphpenaltycodes\numexpr
39    \linepenaltyfrozenparcode
40  + \widowpenaltyfrozenparcode
41  + \clubpenaltyfrozenparcode
42  + \brokenpenaltyfrozenparcode
43  + \shapingpenaltyfrozenparcode
44  + \orphanpenaltyfrozenparcode
45  + \singlelinepenaltyfrozenparcode
46\relax
47
48\setnewconstant\paragraphdemeritcodes\numexpr
49    \demeritsfrozenparcode
50\relax
51
52\setnewconstant\paragraphshapecodes\numexpr
53   \hangfrozenparcode
54 + \skipfrozenparcode
55 + \parfillfrozenparcode
56 + \shapefrozenparcode
57\relax
58
59\setnewconstant\paragraphlinecodes\numexpr
60    \linefrozenparcode
61\relax
62
63\setnewconstant\paragraphhyphenationcodes\numexpr
64    \hyphenationfrozenparcode
65\relax
66
67\setnewconstant\paragraphpassescodes\numexpr
68    \parpassesfrozenparcode
69\relax
70
71% \linefrozenparcode % lineskip
72
73\setnewconstant\frozenparagraphdefault\numexpr
74   \hsizefrozenparcode            % \hsize
75 + \skipfrozenparcode             % \leftskip \rightskip
76 + \hangfrozenparcode             % \hangindent \hangafter
77 + \indentfrozenparcode           % \parindent
78 + \parfillfrozenparcode          % \parfillskip \parfillleftskip
79 + \adjustfrozenparcode           % \adjustspacing
80 + \protrudefrozenparcode         % \protrudechars
81 + \tolerancefrozenparcode        % \tolerance \pretolerance
82 + \stretchfrozenparcode          % \emergcystretch
83 + \loosenessfrozenparcode        % \looseness
84 + \lastlinefrozenparcode         % \lastlinefit
85 + \linepenaltyfrozenparcode      % \linepenalty \interlinepenalty \interlinepenalties
86 + \clubpenaltyfrozenparcode      % \clubpenalty \clubpenalties
87 + \widowpenaltyfrozenparcode     % \widowpenalty \widowpenalties
88 + \displaypenaltyfrozenparcode   % \displaypenalty \displaypenalties
89 + \brokenpenaltyfrozenparcode    % \brokenpenalty
90 + \demeritsfrozenparcode         % \doublehyphendemerits \finalhyphendemerits \adjdemerits
91 + \shapefrozenparcode            % \parshape
92 % \linefrozenparcode             % \baselineskip \lineskip \lineskiplimit
93 + \hyphenationfrozenparcode      % \hyphenationmode
94 + \shapingpenaltyfrozenparcode   % \shapingpenaltymode
95 + \orphanpenaltyfrozenparcode
96 % \mathpenaltyfrozenparcode
97 + \emergencyfrozenparcode
98 + \parpassesfrozenparcode
99 + \singlelinepenaltyfrozenparcode
100\relax
101
102\permanent\protected\def\freezeparagraphproperties {\snapshotpar\frozenparagraphdefault}
103\permanent\protected\def\defrostparagraphproperties{\snapshotpar\zerocount}
104
105\permanent\protected\def\updateparagraphproperties{\ifhmode\snapshotpar\paragraphupdatecodes \fi}
106\permanent\protected\def\updateparagraphpenalties {\ifhmode\snapshotpar\paragraphpenaltycodes\fi}
107\permanent\protected\def\updateparagraphdemerits  {\ifhmode\snapshotpar\paragraphdemeritcodes\fi}
108\permanent\protected\def\updateparagraphshapes    {\ifhmode\snapshotpar\paragraphshapecodes  \fi}
109\permanent\protected\def\updateparagraphlines     {\ifhmode\snapshotpar\paragraphlinecodes   \fi}
110\permanent\protected\def\updateparagraphpasses    {\ifhmode\snapshotpar\paragraphpassescodes \fi}
111
112% so far
113
114\let\spac_paragraph_freeze\relax
115
116\permanent\protected\def\setparagraphfreezing   {\enforced\let\spac_paragraph_freeze\freezeparagraphproperties}
117\permanent\protected\def\forgetparagraphfreezing{\enforced\let\spac_paragraph_freeze\relax}
118
119\installcorenamespace {bparwrap}
120\installcorenamespace {eparwrap}
121\installcorenamespace {parwrapbefore}
122\installcorenamespace {parwrapafter}
123\installcorenamespace {parwrapcount}
124
125\lettonothing\spac_paragraph_wrap
126
127\newinteger\c_spac_paragraph_group_level
128
129\protected\def\spac_paragraph_update
130  {\c_spac_paragraph_group_level\currentgrouplevel\relax
131   \ifcsname\??bparwrap\the\c_spac_paragraph_group_level\endcsname
132     \the\lastnamedcs
133     \relax
134     \dontleavehmode % just in case
135     \wrapuppar{\the\csname\??eparwrap\the\c_spac_paragraph_group_level\endcsname\relax}%
136   \fi}
137
138\permanent\protected\def\registerparwrapper       {\spac_register_par_wrapper\toksapp\tokspre}
139\permanent\protected\def\registerparwrapperreverse{\spac_register_par_wrapper\tokspre\toksapp}
140
141\protected\def\spac_paragraph_install
142  {\expandafter\newtoks\csname\??bparwrap\the\currentgrouplevel\endcsname
143   \expandafter\newtoks\csname\??eparwrap\the\currentgrouplevel\endcsname}
144
145\def\spac_paragraph_install_count#1%
146  {\expandafter\newinteger\csname\??parwrapcount#1\endcsname}
147
148\def\spac_paragraph_install_pair#1#2#3%
149  {\expandafter\newtoks\csname\??parwrapbefore#3\endcsname
150   \expandafter\newtoks\csname\??parwrapafter #3\endcsname
151   #1\csname\??bparwrap\the\currentgrouplevel\endcsname{\the\csname\??parwrapbefore#3\endcsname}%
152   #2\csname\??eparwrap\the\currentgrouplevel\endcsname{\the\csname\??parwrapafter #3\endcsname}}
153
154\def\spac_register_par_wrapper_yes#1#2#3#4#5%
155  {\ifcsname\??bparwrap\the\currentgrouplevel\endcsname \else
156     \spac_paragraph_install
157   \fi
158   \ifcsname\??parwrapcount#3\endcsname \else
159     \spac_paragraph_install_count{#3}%
160   \fi
161   \ifcsname\??parwrapbefore#3\endcsname \else
162     \spac_paragraph_install_pair#1#2{#3}%
163   \fi
164   #1\csname\??parwrapbefore#3\endcsname{\global\advanceby\csname\??parwrapcount#3\endcsname\plusone\relax % global, see (!)
165                                         \clf_setparwrapper{#3}#4}%
166   #2\csname\??parwrapafter #3\endcsname{#5}%
167   \clf_newparwrapper{#3}%
168   \let\spac_paragraph_wrap\spac_paragraph_update}
169
170\def\spac_register_par_wrapper_nop#1#2#3#4#5%
171  {\ifcsname\??parwrapcount#3\endcsname \else
172     \spac_paragraph_install_count{#3}%
173   \fi
174   \global\csname\??parwrapcount#3\endcsname\plusone % global, see (!)
175   #4\wrapuppar{#5}}
176
177\protected\def\spac_register_par_wrapper
178  {\ifhmode
179     \expandafter\spac_register_par_wrapper_nop
180   \else
181     \expandafter\spac_register_par_wrapper_yes
182   \fi}
183
184\permanent\protected\def\forgetparwrapper
185  {\csname\??bparwrap\the\currentgrouplevel\endcsname\emptytoks
186   \csname\??eparwrap\the\currentgrouplevel\endcsname\emptytoks}
187
188\permanent\protected\def\unregisterparwrapper#1%
189  {\global\csname\??parwrapcount#1\endcsname\zerocount % global, see (!)
190   \ifcsname\??parwrapbefore#1\endcsname
191     \lastnamedcs\emptytoks
192     \csname\??parwrapafter#1\endcsname\emptytoks
193   \fi}
194
195\permanent\def\directparwrapper#1#2%
196  {#1\wrapuppar{#2}}
197
198\permanent\protected\def\doifelseparwrapper#1%
199  {\unless\ifcsname\??parwrapcount#1\endcsname
200     \expandafter\secondoftwoarguments
201   \orelse\ifcase\lastnamedcs
202     \expandafter\secondoftwoarguments
203   \else
204     \expandafter\firstoftwoarguments
205   \fi}
206
207% \getparwrapper  % defined in lua
208% \lastparwrapper % defined in lua
209
210\permanent\protected\def\showparwrapperstate#1%
211  {\begingroup
212   \infofont ΒΆ#1\hilo
213     {\smallinfofont\getparwrapper {#1}}%
214     {\smallinfofont\lastparwrapper{#1}}%
215   \endgroup}
216
217%appendtoks\updateparwrapperindeed\to\everypar
218%appendtoks\spac_paragraph_wrap   \to\everypar
219%appendtoks\spac_paragraph_freeze \to\everypar
220
221% (!) testcase for global setting of count
222%
223% \starttext
224%     \hsize3cm
225%     Aaa\wordright{Aaa}\par
226%     \sc{Bbb\wordright{Bbb}}\par
227%     {\sc Ccc\wordright{Ccc}}\par
228%     \sc{Ddd}\wordright{\sc{Ddd}}\par
229% \stoptext
230
231\setparagraphfreezing
232
233\appendtoks\lettonothing\spac_paragraph_wrap\to\everyforgetall
234
235%D In due time, the code below will be upgraded using the above mechanisms.
236
237%D The dreadful sequence \type {\bgroup} \unknown\ \type {\carryoverpar} \unknown\
238%D \type {\egroup} is needed when for instance sidefloats are used in combination
239%D with something that starts with a group. This is because otherwise the
240%D indentation as set (by the output routine) inside the group are forgotten
241%D afterwards. (I must not forget its existence).
242
243\mutable\lettonothing\currentparagraphproperties % visible for tracing
244
245\permanent\def\carryoverpar#1% #1 can be \endgroup or \egroup or ... expandable !
246  {\normalexpanded
247     {\noexpand#1%
248      \hangindent\the\hangindent
249      \hangafter \the\hangafter
250      \parskip   \the\parskip
251      \leftskip  \the\leftskip
252      \rightskip \the\rightskip
253      \relax}}
254
255\permanent\protected\def\pushparagraphproperties
256  {\edef\currentparagraphproperties{\carryoverpar\relax}%
257   \pushmacro\currentparagraphproperties}
258
259\permanent\protected\def\popparagraphproperties
260  {\popmacro\currentparagraphproperties
261   \currentparagraphproperties}
262
263\permanent\protected\def\flushparagraphproperties
264  {\popmacro\currentparagraphproperties}
265
266%D Beware, changing this will break some code (like pos/backgrounds) but it has been
267%D changed anyway so let's see where things go wrong.
268
269\installcorenamespace{paragraphintro}
270
271\newtoks\t_spac_paragraphs_intro_first
272\newtoks\t_spac_paragraphs_intro_next
273\newtoks\t_spac_paragraphs_intro_each
274
275\newconditional\c_spac_paragraphs_intro_first
276\newconditional\c_spac_paragraphs_intro_next
277\newconditional\c_spac_paragraphs_intro_each
278
279\lettonothing\spac_paragraphs_flush_intro
280\lettonothing\spac_paragraphs_intro_step
281
282\permanent\protected\tolerant\def\setupparagraphintro[#1]#*[#2]%
283  {\def\spac_paragraphs_intro_step##1%
284     {\csname\??paragraphintro\ifcsname\??paragraphintro##1\endcsname##1\fi\endcsname{#2}}%
285   \processcommacommand[#1]\spac_paragraphs_intro_step}
286
287\letcsname\??paragraphintro\empty\endcsname\gobbleoneargument
288
289\defcsname\??paragraphintro\v!reset\endcsname#1%
290  {\global\c_spac_paragraphs_intro_first\conditionalfalse
291   \global\c_spac_paragraphs_intro_next\conditionalfalse
292   \global\c_spac_paragraphs_intro_each\conditionalfalse
293   \global\t_spac_paragraphs_intro_first\emptytoks
294   \global\t_spac_paragraphs_intro_next \emptytoks
295   \global\t_spac_paragraphs_intro_each \emptytoks
296   \glettonothing\spac_paragraphs_flush_intro}
297
298\defcsname\??paragraphintro\v!first\endcsname#1%
299  {\global\c_spac_paragraphs_intro_first\conditionaltrue
300   \gtoksapp\t_spac_paragraphs_intro_first{#1}%
301   \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_indeed}
302
303\defcsname\??paragraphintro\v!next\endcsname#1%
304  {\global\c_spac_paragraphs_intro_next\conditionaltrue
305   \gtoksapp\t_spac_paragraphs_intro_next{#1}%
306   \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_indeed}
307
308\defcsname\??paragraphintro\v!each\endcsname#1%
309  {\global\c_spac_paragraphs_intro_each\conditionaltrue
310   \gtoksapp\t_spac_paragraphs_intro_each{#1}%
311   \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_indeed}
312
313%D We can say:
314%D
315%D \starttyping
316%D \setupparagraphintro[first][\index{Knuth}]
317%D \stoptyping
318%D
319%D Maybe more convenient is:
320%D
321%D \starttyping
322%D \flushatparagraph{\index{Zapf}}
323%D \stoptyping
324%D
325%D \starttyping
326%D \setupparagraphintro[first][\hbox to 3.5em{\tt FIRST \hss}]
327%D \setupparagraphintro[first][\hbox to 3.5em{\tt TSRIF \hss}]
328%D \setupparagraphintro[next] [\hbox to 3.5em{\tt NEXT  \hss}]
329%D \setupparagraphintro[next] [\hbox to 3.5em{\tt TXEN  \hss}]
330%D \setupparagraphintro[each] [\hbox to 3.0em{\tt EACH  \hss}]
331%D \setupparagraphintro[each] [\hbox to 3.0em{\tt HCEA  \hss}]
332%D
333%D some paragraph \par
334%D some paragraph \par
335%D some paragraph \par
336%D some paragraph \par
337%D
338%D \setupparagraphintro[first][\hbox to 3.5em{\tt FIRST \hss}]
339%D \setupparagraphintro[first][\hbox to 3.5em{\tt TSRIF \hss}]
340%D
341%D some paragraph \par
342%D some paragraph \par
343%D
344%D \setupparagraphintro[reset]
345%D
346%D some paragraph \par
347%D \stoptyping
348
349\permanent\protected\def\flushatparagraph#1%
350  {\global\c_spac_paragraphs_intro_first\plusone
351   \gtoksapp\t_spac_paragraphs_intro_first{#1}%
352   \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_indeed}
353
354%D Here comes the flusher (we misuse the one level expansion of token registers to
355%D feed a nice stream into the paragraph.)
356
357\protected\def\spac_paragraphs_flush_intro_indeed % we make sure that the token lists expand directly
358  {\normalexpanded{%                              % after another so the first code is there twice
359     \ifconditional\c_spac_paragraphs_intro_each
360       \ifconditional\c_spac_paragraphs_intro_next
361         \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_next
362       \else
363         \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_each
364       \fi
365       \ifconditional\c_spac_paragraphs_intro_first
366         \global\c_spac_paragraphs_intro_first\conditionalfalse
367         \global\t_spac_paragraphs_intro_first\emptytoks
368         \expand\t_spac_paragraphs_intro_first
369       \fi
370       \expand\t_spac_paragraphs_intro_each
371     \else
372       \ifconditional\c_spac_paragraphs_intro_next
373         \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_next
374       \fi
375       \ifconditional\c_spac_paragraphs_intro_first
376         \global\c_spac_paragraphs_intro_first\conditionalfalse
377         \global\t_spac_paragraphs_intro_first\emptytoks
378         \expand\t_spac_paragraphs_intro_first
379       \fi
380     \fi}}
381
382\protected\def\spac_paragraphs_flush_intro_next
383  {\normalexpanded{%
384     \global\c_spac_paragraphs_intro_next\conditionalfalse
385     \global\t_spac_paragraphs_intro_next\emptytoks
386     \ifconditional\c_spac_paragraphs_intro_each
387       \glet\spac_paragraphs_flush_intro\spac_paragraphs_flush_intro_each
388       \expand\t_spac_paragraphs_intro_next
389       \expand\t_spac_paragraphs_intro_each
390     \else
391       \glettonothing\spac_paragraphs_flush_intro
392       \expand\t_spac_paragraphs_intro_next
393     \fi}}
394
395\protected\def\spac_paragraphs_flush_intro_each
396  {\expand\t_spac_paragraphs_intro_each}
397
398%D \macros
399%D   {flushatnextpar}
400%D
401%D This macro collects data that will be flushed at the next paragraph. By using
402%D this macro you can avoid interfering nodes (writes, etc).
403
404\lettonothing\flushpostponednodedata % hook into everypar
405
406\newbox    \b_spac_postponed_data
407%newinteger\c_spac_postponed_data
408
409% \installcorenamespace {postponednodesstack}
410%
411% \initializeboxstack\??postponednodesstack
412%
413% \protected\def\pushpostponednodedata
414%   {\global\advanceby\c_spac_postponed_data\plusone
415%    \savebox\??postponednodesstack{\the\c_spac_postponed_data}{\box\b_spac_postponed_data}}
416%
417% \protected\def\poppostponednodedata
418%   {\global\setbox\b_spac_postponed_data\hbox{\foundbox\??postponednodesstack{\the\c_spac_postponed_data}}%
419%    \global\advanceby\c_spac_postponed_data\minusone
420%    \ifvoid\b_spac_postponed_data\else
421%      \enforced\glet\flushpostponednodedata\spac_postponed_data_flush
422%    \fi}
423
424\newtoks\everyflushatnextpar
425
426\permanent\protected\def\pushpostponednodedata
427  {\globalpushbox\b_spac_postponed_data}
428
429\permanent\protected\def\poppostponednodedata
430  {\globalpopbox\b_spac_postponed_data
431   \ifvoid\b_spac_postponed_data\else
432     \enforced\glet\flushpostponednodedata\spac_postponed_data_flush
433   \fi}
434
435\permanent\protected\def\flushatnextpar
436  {\begingroup
437   \expand\everyflushatnextpar
438   \enforced\glet\flushpostponednodedata\spac_postponed_data_flush
439   \dowithnextboxcs\spac_postponed_data_finish\hpack}
440
441% \def\spac_postponed_data_finish
442%   {\global\setbox\b_spac_postponed_data\hpack % to\zeropoint
443%      {\box\b_spac_postponed_data\box\nextbox}%
444%    \endgroup}
445%
446% This is better when used with protrusion which does not like too deeply nested
447% boxes:
448%
449% \def\spac_postponed_data_finish
450%   {\dontcomplain
451%    \global\setbox\b_spac_postponed_data\hpack to \zeropoint
452%      {\unhbox\b_spac_postponed_data\unhbox\nextbox}%
453%    \endgroup}
454%
455% We could do this if there is content with widths ... not that is should be used
456% that way, but this way we don't overflow:
457
458\def\spac_postponed_data_finish
459  {\dontcomplain
460   \global\setbox\b_spac_postponed_data\hpack % to \zeropoint
461     {\unhbox\b_spac_postponed_data
462      \scratchdimen\wd\nextbox
463      \unhbox\nextbox
464      \ifcase\scratchdimen\else\kern-\scratchdimen\fi}%
465   \endgroup}
466
467\def\spac_postponed_data_flush
468  {%\iftrialtypesetting \else
469     \ifvoid\b_spac_postponed_data\else
470       \hpack{\smashedbox\b_spac_postponed_data}% \box\b_spac_postponed_data
471     \fi
472     \enforced\glettonothing\flushpostponednodedata
473   }%\fi}
474
475\permanent\protected\def\doflushatpar % might be renamed
476  {\ifvmode
477     \expandafter\flushatnextpar
478   \else
479     \expandafter\firstofoneargument
480   \fi}
481
482%D Experiment:
483%D
484%D \starttyping
485%D \startcombination[4*1]
486%D     {\vtop{           \hsize #1 \setupalign[tolerant]                             \samplefile{ward}}} {tolerant}
487%D     {\vtop{\darkblue  \hsize #1 \setupalign[tolerant,stretch]                     \samplefile{ward}}} {tolerant,stretch}
488%D     {\vtop{\darkgreen \hsize #1 \setupalign[tolerant]        \optimize[flushleft] \samplefile{ward}}} {tolerant,fuzzy}
489%D     {\vtop{\darkred   \hsize #1 \setupalign[tolerant]        \optimize[normal]    \samplefile{ward}}} {tolerant,lessfuzzy}
490%D \stopcombination
491%D \stoptyping
492
493\installcorenamespace {optimize}
494
495\installcommandhandler \??optimize {optimize} \??optimize
496
497\setupoptimize
498  [\c!lines=\zerocount,
499   \c!left=\zeropoint,
500   \c!right=\zeropoint,
501   \c!distance=\zeropoint]
502
503\permanent\protected\def\optimize[#S#1]%
504  {\begingroup
505   \ifhastok={#1}%
506     \setupcurrentoptimize[#1]%
507   \else
508     \cdef\currentoptimize{#1}%
509   \fi
510   \scratchdimenone  \optimizeparameter\c!left \relax
511   \scratchdimentwo  \optimizeparameter\c!right\relax
512   \scratchcounterone\optimizeparameter\c!lines\relax
513   \scratchdistance  \optimizeparameter\c!distance\relax
514   \normalexpanded
515     {\endgroup
516      \looseness\the\scratchcounterone\relax
517      \emergencyextrastretch\the\scratchdistance\relax
518      \ifzerodim\scratchdimenone\else
519        \emergencyleftskip \zeropoint \s!plus \the\scratchdimenone\relax
520      \fi
521      \ifzerodim\scratchdimentwo\else
522        \emergencyrightskip\zeropoint \s!plus \the\scratchdimentwo\relax
523      \fi}%
524   \ignorespaces}
525
526\defineoptimize[+\v!line][\c!lines=\plusone]
527\defineoptimize[-\v!line][\c!lines=\minusone]
528
529\defineoptimize[\v!flushleft ][\c!right=2\bodyfontsize]
530\defineoptimize[\v!flushright][\c!left=2\bodyfontsize]
531\defineoptimize[\v!normal    ][\c!right=2\bodyfontsize,\c!distance=\bodyfontsize]
532
533\protect \endinput
534