lowlevel-paragraphs.tex /size: 51 Kb    last modification: 2023-12-21 09:43
1% language=us runpath=texruns:manuals/lowlevel
2
3\environment lowlevel-style
4
5\startdocument
6  [title=paragraphs,
7   color=middlecyan]
8
9\startsectionlevel[title=Introduction]
10
11This manual is mostly discussing a few low level wrappers around low level \TEX\
12features. Its writing is triggered by an update to the \METAFUN\ and \LUAMETAFUN\
13manuals where we mess a bit with shapes. It gave a good reason to also cover some
14more paragraph related topics but it might take a while to complete. Remind me if
15you feel that takes too much time.
16
17Because paragraphs and their construction are rather central to \TEX, you can
18imagine that the engine exposes dealing with them. This happens via commands
19(primitives) but only when it's robust. Then there are callbacks, and some
20provide detailed information about what we're dealing with. However, intercepting
21node lists can already be hairy and we do that a lot in \CONTEXT. Intercepting
22and tweaking paragraph properties is even more tricky, which is why we try to
23avoid that in the core. But \unknown\ in the following sections you will see that
24there are actually a couple of mechanism that do so. Often new features like this
25are built in stepwise and enabled locally for a while and when they seem okay
26they get enabled by default. \footnote {For this we have \type
27{\enableexperiments} which one can use in \type {cont-loc.mkxl} or \type
28{cont-exp.mkxl}, files that are loaded runtime when on the system. When you use
29them, make sure they don't interfere; they are not part of the updates, contrary
30to \type {cont-new.mkxl}.}
31
32\stopsectionlevel
33
34\startsectionlevel[title=Paragraphs]
35
36Before we demonstrate some trickery, let's see what a paragraph is. Normally a
37document source is formatted like this:
38
39\starttyping[option=TEX]
40some text (line 1)
41some text (line 2)
42
43some more test (line 1)
44some more test (line 2)
45\stoptyping
46
47There are two blocks of text here separated by an empty line and they become two
48paragraphs. Unless configured otherwise an empty line is an indication that we
49end a paragraph. You can also explicitly do that:
50
51\starttyping[option=TEX]
52some text (line 1)
53some text (line 2)
54\par
55some more test (line 1)
56some more test (line 2)
57\stoptyping
58
59When \TEX\ starts a paragraph, it actually also does something think of:
60
61\starttyping[option=TEX]
62[\the\everypar]some text      (line 1) some text      (line 2) \par
63[\the\everypar]some more test (line 1) some more test (line 2) \par
64\stoptyping
65
66or more accurate:
67
68\starttyping[option=TEX]
69[\the\everypar]some text      some text      \par
70[\the\everypar]some more test some more test \par
71\stoptyping
72
73because the end|-|of|-|line character has become a space. As mentioned,
74an empty line is actually the end of a paragraph. But in \LUAMETATEX\
75we can cheat a bit. If we have this:
76
77\startbuffer
78line 1
79
80line 2
81\stopbuffer
82
83\typebuffer[option=TEX]
84
85We can do this (watch how we need to permit overloading a primitive when we have
86enabled \type {\overloadmode}):
87
88\startbuffer
89\pushoverloadmode
90\def\linepar{\removeunwantedspaces !\ignorespaces}
91\popoverloadmode
92line 1
93
94line 2
95\stopbuffer
96
97\typebuffer[option=TEX]
98
99This comes out as:
100
101\start \getbuffer \stop
102
103I admit that since it got added (as part of some cleanup halfway the overhaul of
104the engine) I never saw a reason to use it, but it is a cheap feature. The \type
105{\linepar} primitive is undefined (\type {\undefined}) by default so no user sees
106it anyway. Just don't use it unless maybe for some pseudo database trickery (I
107considered using it for the database module but it is not needed). In a similar
108fashion, just don't redefine \type {\par}: it's asking for troubles and \quote
109{not done} in \CONTEXT\ anyway.
110
111Back to reality. In \LUATEX\ we get a node list that starts with a so called
112\type {localpar} node and ends with a \type {\parfillskip}. The first node is
113prepended automatically. That list travels through the system: hyphenation,
114applying font properties, break the effectively one line into lines, wrap them
115and add them to a vertical list, etc. Each stage can be intercepted via
116callbacks.
117
118When the paragraph is broken into lines hanging indentation or a so called par
119shape can be applied, and we will see more of that later, here we talk \type
120{\par} and show another \LUAMETATEX\ trick:
121
122\startbuffer
123\def\foo{{\bf test:} \ignorepars}
124
125\foo
126
127line
128\stopbuffer
129
130\typebuffer[option=TEX]
131
132The macro typesets some text and then skips to the next paragraph:
133
134\start \getbuffer \stop
135
136Think of this primitive as being a more powerful variant of \type
137{\ignorespaces}. This leaves one aspect: how do we start a paragraph. Technically
138we need to force \TEX\ into so called horizontal mode. When you look at plain
139\TEX\ documents you will notice commands like \type {\noindent} and \type
140{\indent}. In \CONTEXT\ we have more high level variants, for instance we have
141\type {\noindentation}.
142
143A robust way to make sure that you get in horizontal mode is using \type
144{\dontleavehmode} which is a wink to \type {\leavevmode}, a command that you
145should never use in \CONTEXT, so when you come from plain or \LATEX, it's one of
146the commands you should wipe from your memory.
147
148When \TEX\ starts with a paragraph the \type {\everypar} token list is expanded
149and again this is a primitive you should not mess with yourself unless in very
150controlled situations. If you change its content, you're on your own with respect
151to interferences and side effects.
152
153One of the things that \TEX\ does in injecting the indentation. Even when there
154is none, it gets added, not as skip but as an empty horizontal box of a certain
155width. This is easier on the engine when it constructs the paragraph from the one
156liner: starting with a skip demands a bit more testing in the process (a nice
157trick so to say). However, in \CONTEXT\ we enable the \LUAMETATEX\ feature that
158does use a skip instead of a box. It's part of the normalization that is
159discussed later. Instead of checking for a box with property indent, we check for
160a skip with such property. This is often easier and cleaner.
161
162A bit off topic is the fact that in traditional \TEX\ empty lines or \type {\par}
163primitives can trigger an error. This has to do with the fact that the program
164evolved in a time where paper terminals were used and runtime could be excessive.
165So, in order to catch a possible missing brace, a concept of \type {\long}
166macros, permitting \type {\par} or equivalents in arguments, was introduced as
167well as not permitting them in for instance display math. In \CONTEXT\ \MKII\
168most macros that could be sensitive for this were defined as \type {\long} so
169that users never had to bother about it and probably were not even aware of it.
170Right from the start in \LUATEX\ these error|-|triggers could be disabled which
171of course we enable in \CONTEXT\ and in \LUAMETATEX\ these features have been
172removed altogether. I don't think users will complain about this.
173
174If you want to enforce a newline but not a new paragraph you can use the \type
175{\crlf} command. When used on its own it will produce an empty line. Don't use
176this to create whitespace between lines.
177
178If you want to do something after so called par tokens are seen you can do this:
179
180\startbuffer
181\def\foo{{\bf >>>> }}
182\expandafterpars\foo
183
184this is a new paragraph ...
185
186\expandafterpars\foo
187\par\par\par\par
188this is a new paragraph ...
189\stopbuffer
190
191\typebuffer[option=TEX]
192
193This not to be confused with \type {\everypar} which is a token list that \TEX\
194itself injects before each paragraph (also nested ones).
195
196\getbuffer
197
198This is typically a primitive that will only be used in macros. You can actually
199program it using macros: pickup a token, check and push it back when it's not a
200par equivalent token. The primitive is is just nicer (and easier on the log when
201tracing is enabled).
202
203\stopsectionlevel
204
205\startsectionlevel[title=Properties]
206
207A paragraph is just a collection of lines that result from one input line that
208got broken. This process of breaking into lines is influenced by quite some
209parameters. In traditional \TEX\ and also in \LUAMETATEX\ by default the values
210that are in effect when the end of the paragraph is met are used. So, when you
211change them in a group and then ends the paragraph after the group, the values
212you've set in the group are not used.
213
214However, in \LUAMETATEX\ we can optionally store them with the paragraph. When
215that happens the values current at the start are frozen. You can still overload
216them but that has to be done explicitly then. The advantage is that grouping no
217longer interferes with the line break algorithm. The magic primitive is \type
218{\snapshotpar} which takes a number made from categories mentioned below:
219
220\starttabulate[|l|l|r|]
221\BC variable                       \BC category        \BC code                                        \NC \NR
222\NC \type {\hsize}                 \NC hsize           \NC 0x\uchexnumbers\hsizefrozenparcode          \NC \NR
223\NC \type {\leftskip}              \NC skip            \NC 0x\uchexnumbers\skipfrozenparcode           \NC \NR
224\NC \type {\rightskip}             \NC skip            \NC 0x\uchexnumbers\skipfrozenparcode           \NC \NR
225\NC \type {\hangindent}            \NC hang            \NC 0x\uchexnumbers\hangfrozenparcode           \NC \NR
226\NC \type {\hangafter}             \NC hang            \NC 0x\uchexnumbers\hangfrozenparcode           \NC \NR
227\NC \type {\parindent}             \NC indent          \NC 0x\uchexnumbers\indentfrozenparcode         \NC \NR
228\NC \type {\parfillleftskip}       \NC par fill        \NC 0x\uchexnumbers\parfillfrozenparcode        \NC \NR
229\NC \type {\parfillrightskip}      \NC par fill        \NC 0x\uchexnumbers\parfillfrozenparcode        \NC \NR
230\NC \type {\adjustspacing}         \NC adjust          \NC 0x\uchexnumbers\adjustfrozenparcode         \NC \NR
231\NC \type {\adjustspacingstep}     \NC adjust          \NC 0x\uchexnumbers\adjustfrozenparcode         \NC \NR
232\NC \type {\adjustspacingshrink}   \NC adjust          \NC 0x\uchexnumbers\adjustfrozenparcode         \NC \NR
233\NC \type {\adjustspacingstretch}  \NC adjust          \NC 0x\uchexnumbers\adjustfrozenparcode         \NC \NR
234\NC \type {\protrudechars}         \NC protrude        \NC 0x\uchexnumbers\protrudefrozenparcode       \NC \NR
235\NC \type {\pretolerance}          \NC tolerance       \NC 0x\uchexnumbers\tolerancefrozenparcode      \NC \NR
236\NC \type {\tolerance}             \NC tolerance       \NC 0x\uchexnumbers\tolerancefrozenparcode      \NC \NR
237\NC \type {\emergencystretch}      \NC stretch         \NC 0x\uchexnumbers\stretchfrozenparcode        \NC \NR
238\NC \type {\looseness}             \NC looseness       \NC 0x\uchexnumbers\loosenessfrozenparcode      \NC \NR
239\NC \type {\lastlinefit}           \NC last line       \NC 0x\uchexnumbers\lastlinefrozenparcode       \NC \NR
240\NC \type {\linepenalty}           \NC line penalty    \NC 0x\uchexnumbers\linepenaltyfrozenparcode    \NC \NR
241\NC \type {\interlinepenalty}      \NC line penalty    \NC 0x\uchexnumbers\linepenaltyfrozenparcode    \NC \NR
242\NC \type {\interlinepenalties}    \NC line penalty    \NC 0x\uchexnumbers\linepenaltyfrozenparcode    \NC \NR
243\NC \type {\clubpenalty}           \NC club penalty    \NC 0x\uchexnumbers\clubpenaltyfrozenparcode    \NC \NR
244\NC \type {\clubpenalties}         \NC club penalty    \NC 0x\uchexnumbers\clubpenaltyfrozenparcode    \NC \NR
245\NC \type {\widowpenalty}          \NC widow penalty   \NC 0x\uchexnumbers\widowpenaltyfrozenparcode   \NC \NR
246\NC \type {\widowpenalties}        \NC widow penalty   \NC 0x\uchexnumbers\widowpenaltyfrozenparcode   \NC \NR
247\NC \type {\displaywidowpenalty}   \NC display penalty \NC 0x\uchexnumbers\displaypenaltyfrozenparcode \NC \NR
248\NC \type {\displaywidowpenalties} \NC display penalty \NC 0x\uchexnumbers\displaypenaltyfrozenparcode \NC \NR
249\NC \type {\brokenpenalty}         \NC broken penalty  \NC 0x\uchexnumbers\brokenpenaltyfrozenparcode  \NC \NR
250\NC \type {\adjdemerits}           \NC demerits        \NC 0x\uchexnumbers\demeritsfrozenparcode       \NC \NR
251\NC \type {\doublehyphendemerits}  \NC demerits        \NC 0x\uchexnumbers\demeritsfrozenparcode       \NC \NR
252\NC \type {\finalhyphendemerits}   \NC demerits        \NC 0x\uchexnumbers\demeritsfrozenparcode       \NC \NR
253\NC \type {\parshape}              \NC shape           \NC 0x\uchexnumbers\shapefrozenparcode          \NC \NR
254\NC \type {\baselineskip}          \NC line            \NC 0x\uchexnumbers\linefrozenparcode           \NC \NR
255\NC \type {\lineskip}              \NC line            \NC 0x\uchexnumbers\linefrozenparcode           \NC \NR
256\NC \type {\lineskiplimit}         \NC line            \NC 0x\uchexnumbers\linefrozenparcode           \NC \NR
257\NC \type {\hyphenationmode}       \NC hyphenation     \NC 0x\uchexnumbers\hyphenationfrozenparcode    \NC \NR
258\stoptabulate
259
260As you can see here, there are more paragraph related parameters than in for
261instance \PDFTEX\ and \LUATEX\ and these are (to be) explained in the
262\LUAMETATEX\ manual. You can imagine that keeping this around with the paragraph
263adds some extra overhead to the machinery but most users won't notice that
264because is is compensated by gains elsewhere.
265
266This is pretty low level and there are a bunch of helpers that support this but
267these are not really user level macros. As with everything \TEX\ you can mess
268around as much as you like, and the code gives plenty of examples but when you do
269this, you're on your own because it can interfere with \CONTEXT\ core
270functionality.
271
272In \LMTX\ taking these snapshots is turned on by default and because it thereby
273fundamentally influences the par builder, users can run into compatibility issues
274but in practice there has been no complaints (and this feature has been in use
275quite a while before this document was written). One reason for users not
276noticing is that one of the big benefits is probably handled by tricks mentioned
277on the mailing list. Imagine that you have this:
278
279\starttyping[option=TEX]
280{\bf watch out:} here is some text
281\stoptyping
282
283In this small example the result will be as expected. But what if something magic
284with the start of a paragraph is done? Like this:
285
286\starttyping[option=TEX]
287\placefigure[left]{A cow!}{\externalfigure[cow.pdf]}
288
289{\bf watch out:} here is some text ... of course much more is needed to
290    get a flow around the figure!
291\stoptyping
292
293The figure will hang at the left side of the paragraph but it is put there when
294the text starts and that happens inside the bold group. It means that the
295properties we set in order to get the shape around the figure are lost as soon as
296we're at \quote{\type {here is some text}} and definitely is wrong when the
297paragraph ends and the par builder has to use them to get the shape right. We get
298text overlapping the figure. A trick to overcome this is:
299
300\starttyping[option=TEX]
301\dontleavehmode {\bf watch out:} here is some text ... of course much
302    more is needed to get a flow around the figure!
303\stoptyping
304
305where the first macro makes sure we already start a paragraph before the group is
306entered (using a \type {\strut} also works). It's not nice and I bet users have
307been bitten by this and by now know the tricks. But, with snapshots such fuzzy
308hacks are not needed any more! The same is true with this:
309
310\starttyping[option=TEX]
311{\leftskip 1em some text \par}
312\stoptyping
313
314where we had to explicitly end the paragraph inside the group in order to retain
315the skip. I suppose that users normally use the high level environments so they
316never had to worry about this. It's also why users probably won't notice that
317this new mechanism has been active for a while. Actually, when you now change a
318parameter inside the paragraph its new value will not be applied (unless you
319prefix it with \type {\frozen} or snapshot it) but no one did that anyway.
320
321\stopsectionlevel
322
323\startsectionlevel[title=Wrapping up]
324
325In \CONTEXT\ \LMTX\ we have a mechanism to exercise macros (or content) before a
326paragraph ends. This is implemented using the \type {\wrapuppar} primitive. The
327to be wrapped up material is bound to the current paragraph which in order to
328get this done has to be started when this primitive is used.
329
330Although the high level interface has been around for a while it still needs a
331bit more testing (read: use cases are needed). In the few cases where we already
332use it application can be different because again it relates to snapshots. This
333because in the past we had to use tricks that also influenced the user interface
334of some macros (which made them less natural as one would expect). So the
335question is: where do we apply it in old mechanisms and where not.
336
337{\em todo: accumulation, interference, where applied, limitations}
338
339% \vbox   {vbox    : \wrapuppar{1}test\par x\wrapuppar{2}test}\blank
340% \vtop   {vtop    : \wrapuppar{1}test\par x\wrapuppar{2}test}\blank
341% \vcenter{vcenter : \wrapuppar{1}test\par x\wrapuppar{2}test}\blank
342% $$x = \vcenter{vcenter : \wrapuppar{1}test\par x\wrapuppar{2}test}$$\blank
343% x\vadjust{vadjust : \wrapuppar{1}test\par x\wrapuppar{2}test}x\blank
344
345% \starttext
346% \starttabulate[|||]
347%     \NC test \NC test \NC \NR
348%     \NC test \NC \hbox{\hbox{\hbox{\vadjust pre {\kern-12pt}}}}test \NC \NR
349%     \NC test \NC \hbox{\hbox{\hbox{\vadjust     {\kern-12pt}}}}test \NC \NR
350%     \NC test \NC test \NC \NR
351% \stoptabulate
352% \starttabulate[||p|]
353%     \NC test \NC test \NC \NR
354%     \NC test \NC \hbox{\vadjust{\kern-22pt}}test \NC \NR
355%     \NC test \NC test \NC \NR
356% \stoptabulate
357% \stoptext
358
359\stopsectionlevel
360
361\startsectionlevel[title=Hanging]
362
363There are two mechanisms for getting a specific paragraph shape: rectangular
364hanging and arbitrary shapes. Both mechanisms work top|-|down. The first
365mechanism uses a combination of \type {\hangafter} and \type {\hangindent}, and
366the second one depends on \type {\parshape}. In this section we discuss the
367rectangular one.
368
369\startbuffer[demo-5]
370\hangafter  4 \hangindent  4cm \samplefile{tufte} \page
371\hangafter -4 \hangindent  4cm \samplefile{tufte} \page
372\hangafter  4 \hangindent -4cm \samplefile{tufte} \page
373\hangafter -4 \hangindent -4cm \samplefile{tufte} \page
374\stopbuffer
375
376\typebuffer[demo-5][option=TEX]
377
378As you can see in \in {figure} [fig:hang], the four cases are driven by the sign
379of the values. If you want to hang into the margin you need to use different
380tricks, like messing with the \type {\leftskip}, \type {\rightskip} or \type
381{\parindent} parameters (which then of course can interfere with other mechanisms
382uses at the same time).
383
384\startplacefigure[title=Hanging indentation,reference=fig:hang]
385\startcombination[nx=2,ny=2]
386    {\typesetbuffer[demo-5][page=1,width=.4\textwidth,frame=on]} {\type{\hangafter +4 \hangindent +4cm}}
387    {\typesetbuffer[demo-5][page=2,width=.4\textwidth,frame=on]} {\type{\hangafter -4 \hangindent +4cm}}
388    {\typesetbuffer[demo-5][page=3,width=.4\textwidth,frame=on]} {\type{\hangafter +4 \hangindent -4cm}}
389    {\typesetbuffer[demo-5][page=4,width=.4\textwidth,frame=on]} {\type{\hangafter -4 \hangindent -4cm}}
390\stopcombination
391\stopplacefigure
392
393\stopsectionlevel
394
395\startsectionlevel[title=Shapes]
396
397In \CONTEXT\ we don't use \type {\parshape} a lot. It is used in for instance
398side floats but even there not in all cases. It's more meant for special
399applications. This means that in \MKII\ and \MKIV\ we don't have some high level
400interface. However, when \METAFUN\ got upgraded to \LUAMETAFUN, and the manual
401also needed an update, one of the examples in that manual that used shapes also
402got done differently (read: nicer). And that triggered the arrival of a new low
403level shape mechanism.
404
405One important property of the \type {\parshape} mechanism is that it works per
406paragraph. You define a shape in terms of a left margin and width of a line. The
407shape has a fixed number of such pairs and when there is more content, the last
408one is used for the rest of the lines. When the paragraph is finished, the shape
409is forgotten. \footnote {Not discussed here is a variant that might end up in
410\LUAMETATEX\ that works with the progression, i.e.\ takes the height of the
411content so far into account. This is somewhat tricky because for that to work
412vertical skips need to be frozen, which is no real big deal but has to be done
413careful in the code.}
414
415The high level interface is a follow up on the example in the \METAFUN\ manual and
416uses shapes that carry over to the next paragraph. In addition we can cycle over
417a shape. In this interface shapes are defined using keyword. Here are some
418examples:
419
420\starttyping[option=TEX]
421\startparagraphshape[test]
422    left 1mm right 1mm
423    left 5mm right 5mm
424\stopparagraphshape
425\stoptyping
426
427This shape has only two entries so the first line will have a 1mm margin while
428later lines will get 5mm margins. This translates into a \type {\parshape} like:
429
430\starttyping[option=TEX]
431\parshape 2
432    1mm \dimexpr\hsize-1mm\relax
433    5mm \dimexpr\hsize-5mm\relax
434\stoptyping
435
436Watch the number \type {2}: it tells how many specification lines follow. As you
437see, we need to calculate the width.
438
439\starttyping[option=TEX]
440\startparagraphshape[test]
441    left 1mm right 1mm
442    left 5mm right 5mm
443    repeat
444\stopparagraphshape
445\stoptyping
446
447This variant will alternate between 1mm and 5mm margins. The repeating feature is
448translated as follows. Maybe at some point I will introduce a few more options.
449
450\starttyping[option=TEX]
451\parshape 2 options 1
452    1mm \dimexpr\hsize-1mm\relax
453    5mm \dimexpr\hsize-5mm\relax
454\stoptyping
455
456A shape can have some repetition, and we can save keystrokes by copying the last
457entry. The resulting \type {\parshape} becomes rather long.
458
459\starttyping[option=TEX]
460\startparagraphshape[test]
461    left 1mm right 1mm
462    left 2mm right 2mm
463    left 3mm right 3mm
464    copy 8
465    left 4mm right 4mm
466    left 5mm right 5mm
467    left 5mm hsize 10cm
468\stopparagraphshape
469\stoptyping
470
471Also watch the \type {hsize} keyword: we don't calculate the hsize from the \type
472{left} and \type {right} values but explicitly set it.
473
474\starttyping[option=TEX]
475\startparagraphshape[test]
476    left 1mm right 1mm
477    right 3mm
478    left 5mm right 5mm
479    repeat
480\stopparagraphshape
481\stoptyping
482
483When a \type {right} keywords comes first the \type {left} is assumed to be zero.
484In the examples that follow we will use a couple of definitions:
485
486\startbuffer[setup-0]
487\startparagraphshape[test]
488    both 1mm both 2mm both 3mm both 4mm both 5mm both 6mm
489    both 7mm both 6mm both 5mm both 4mm both 3mm both 2mm
490\stopparagraphshape
491\stopbuffer
492
493\startbuffer[setup-0-repeat]
494\startparagraphshape[test-repeat]
495    both 1mm both 2mm both 3mm both 4mm both 5mm both 6mm
496    both 7mm both 6mm both 5mm both 4mm both 3mm both 2mm
497    repeat
498\stopparagraphshape
499\stopbuffer
500
501\typebuffer[setup-0,setup-0-repeat][option=TEX]
502
503The last one could also be defines as:
504
505\starttyping[option=TEX]
506\startparagraphshape[test-repeat]
507    \rawparagraphshape{test} repeat
508\stopparagraphshape
509\stoptyping
510
511In the previous code we already introduced the \type {repeat} option. This will
512make the shape repeat at the engine level when the shape runs out of specified
513lines. In the application of a shape definition we can specify a \type {method}
514to be used and that determine if the next paragraph will start where we left off
515and discard afterwards (\type {shift}) or that we move the discarded lines up
516front so that we never run out of lines (\type {cycle}). It sounds complicated
517but just keep in mind that \type {repeat} is part of the \type {\parshape} and
518act within a paragraph while \type {shift} and \type {cycle} are applied when a
519new paragraph is started.
520
521\startbuffer[demo-1]
522\startshapedparagraph[list=test]
523    \dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
524\stopshapedparagraph
525\stopbuffer
526
527\startbuffer[demo-1-repeat]
528\startshapedparagraph[list=test-repeat]
529    \dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
530\stopshapedparagraph
531\stopbuffer
532
533In \in {figure} [fig:shape:discard] you see the following applied:
534
535\typebuffer[demo-1,demo-1-repeat][option=TEX]
536
537\startplacefigure[title=Discarded shaping,reference=fig:shape:discard]
538\startcombination[nx=2,ny=2]
539    {\typesetbuffer[setup-0,demo-1]       [page=1,width=.4\textwidth,frame=on]} {discard, finite shape,    page 1}
540    {\typesetbuffer[setup-0,demo-1]       [page=2,width=.4\textwidth,frame=on]} {discard, finite shape,    page 2}
541    {\typesetbuffer[setup-0,demo-1-repeat][page=1,width=.4\textwidth,frame=on]} {discard, repeat in shape, page 1}
542    {\typesetbuffer[setup-0,demo-1-repeat][page=2,width=.4\textwidth,frame=on]} {discard, repeat in shape, page 2}
543\stopcombination
544\stopplacefigure
545
546In \in {figure} [fig:shape:shift] we use this instead:
547
548\startbuffer[demo-2]
549\startshapedparagraph[list=test,method=shift]
550    \dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
551\stopshapedparagraph
552\stopbuffer
553
554\startbuffer[demo-2-shift]
555\startshapedparagraph[list=test-repeat,method=shift]
556    \dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
557\stopshapedparagraph
558\stopbuffer
559
560\typebuffer[demo-2,demo-2-repeat][option=TEX]
561
562\startplacefigure[title=Shifted shaping,reference=fig:shape:shift]
563\startcombination[nx=2,ny=2]
564    {\typesetbuffer[setup-0,demo-2][page=1,width=.4\textwidth,frame=on]}              {shift, finite shape,    page 1}
565    {\typesetbuffer[setup-0,demo-2][page=2,width=.4\textwidth,frame=on]}              {shift, finite shape,    page 2}
566    {\typesetbuffer[setup-0-repeat,demo-2-shift][page=1,width=.4\textwidth,frame=on]} {shift, repeat in shape, page 1}
567    {\typesetbuffer[setup-0-repeat,demo-2-shift][page=2,width=.4\textwidth,frame=on]} {shift, repeat in shape, page 2}
568\stopcombination
569\stopplacefigure
570
571Finally, in \in {figure} [fig:shape:cycle] we use:
572
573\startbuffer[demo-3]
574\startshapedparagraph[list=test,method=cycle]
575    \dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
576\stopshapedparagraph
577\stopbuffer
578
579\startbuffer[demo-3-cycle]
580\startshapedparagraph[list=test-repeat,method=cycle]
581    \dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
582\stopshapedparagraph
583\stopbuffer
584
585\typebuffer[demo-3,demo-3-repeat][option=TEX]
586
587\startplacefigure[title=Cycled shaping,reference=fig:shape:cycle]
588\startcombination[nx=2,ny=2]
589    {\typesetbuffer[setup-0,demo-3][page=1,width=.4\textwidth,frame=on]}              {cycle, finite shape,    page 1}
590    {\typesetbuffer[setup-0,demo-3][page=2,width=.4\textwidth,frame=on]}              {cycle, finite shape,    page 2}
591    {\typesetbuffer[setup-0-repeat,demo-3-cycle][page=1,width=.4\textwidth,frame=on]} {cycle, repeat in shape, page 1}
592    {\typesetbuffer[setup-0-repeat,demo-3-cycle][page=2,width=.4\textwidth,frame=on]} {cycle, repeat in shape, page 2}
593\stopcombination
594\stopplacefigure
595
596These examples are probably too small to see the details but you can run them
597yourself or zoom in on the details. In the margin we show the values used. Here
598is a simple example of (non) poetry. There are other environments that can be
599used instead but this makes a good example anyway.
600
601\startbuffer
602\startparagraphshape[test]
603    left 0em right 0em
604    left 1em right 0em
605    repeat
606\stopparagraphshape
607
608\startshapedparagraph[list=test,method=cycle]
609    verse line 1.1\crlf verse line 2.1\crlf
610    verse line 3.1\crlf verse line 4.1\par
611    verse line 1.2\crlf verse line 2.2\crlf
612    verse line 3.2\crlf verse line 4.2\crlf
613    verse line 5.2\crlf verse line 6.2\par
614\stopshapedparagraph
615\stopbuffer
616
617\typebuffer[option=TEX]
618
619\start \getbuffer \stop
620
621Because the idea for this feature originates in \METAFUN, we will now kick in
622some \METAPOST. The following code creates a shape for a circle. We use a
6232mm offset here:
624
625\startbuffer
626\startuseMPgraphic{circle}
627    path p ; p := fullcircle scaled TextWidth ;
628    build_parshape(p,
629        2mm, 0, 0,
630        LineHeight, StrutHeight, StrutDepth, StrutHeight
631    ) ;
632\stopuseMPgraphic
633\stopbuffer
634
635\typebuffer[option=TEX]
636
637\start \getbuffer \stop
638
639We plug this into the already described macros:
640
641\startbuffer
642\startshapedparagraph[mp=circle]%
643    \setupalign[verytolerant,stretch,last]%
644    \samplefile{tufte}
645    \samplefile{tufte}
646\stopshapedparagraph
647\stopbuffer
648
649\typebuffer[option=TEX]
650
651And get ourself a circular shape. Watch out, at this moment the shape environment
652does not add grouping so when as in this case you change the alignment it can
653influence the document.
654
655\start \getbuffer \stop
656
657\startbuffer[framed]
658\framed[align=normal,width=\textwidth,offset=2mm,strut=no]\bgroup
659    \getbuffer
660\egroup
661\stopbuffer
662
663Assuming that the shape definition above is in a buffer we can do this:
664
665\typebuffer[option=TEX]
666
667The result is shown in \in {figure} [fig:shape:circle]. Because all action
668happens in the framed environment, we can also use this definition:
669
670\starttyping[option=TEX]
671\startuseMPgraphic{circle}
672    path p ; p := fullcircle scaled \the\dimexpr\framedwidth+\framedoffset*2\relax ;
673    build_parshape(p,
674        \framedoffset, 0, 0,
675        LineHeight, StrutHeight, StrutDepth, StrutHeight
676    ) ;
677    draw p ;
678\stopuseMPgraphic
679\stoptyping
680
681\startplacefigure[title=A framed circular shape,reference=fig:shape:circle]
682    \getbuffer[framed]
683\stopplacefigure
684
685A mechanism like this is often never completely automatic in the sense that you
686need to keep an eye on the results. Depending on user demands more features can
687be added. With weird shapes you might want to set up the alignment to be \type
688{tolerant} and have some \type {stretch}.
689
690The interface described in the \METAFUN\ manual is pretty old, the time stamp of
691the original code is mid 2000, but the principles didn't change. The examples in
692\type {meta-imp-txt.mkxl} can now be written as:
693
694\startuseMPgraphic{test 1}
695  begingroup ;
696    save p ; path p ; p := fullcircle scaled 6cm ;
697    lmt_parshape [
698        path        = p,
699        offset      = BodyFontSize/2,
700        dx          = 0,           % default
701        dy          = 0,           % default
702        lineheight  = LineHeight,  % default
703        strutheight = StrutHeight, % default
704        strutdepth  = StrutDepth,  % default
705        topskip     = StrutHeight, % default
706    ] ;
707    draw p withpen pencircle scaled 1pt ;
708  endgroup ;
709\stopuseMPgraphic
710
711\startuseMPgraphic{test 2}
712  begingroup ;
713    save p ; path p ; p := fullsquare rotated 45 scaled 5cm ;
714    lmt_parshape [
715        path   = p,
716        offset = BodyFontSize/2,
717        trace  = true,
718    ] ;
719    draw p withpen pencircle scaled 1pt ;
720  endgroup ;
721\stopuseMPgraphic
722
723\startuseMPgraphic{test 3}
724  begingroup ;
725    save w, h, p ; path p ; w := h := 6cm ;
726    p := (.5w,h) -- (   0,  h) -- (0,0) -- (w,0) &
727         (  w,0) .. (.75w,.5h) .. (w,h) &  (w,h) -- cycle ;
728    lmt_parshape [
729        path   = p,
730        offset = BodyFontSize/2,
731    ] ;
732    draw p withpen pencircle scaled 1pt ;
733  endgroup ;
734\stopuseMPgraphic
735
736\startuseMPgraphic{test 4}
737  begingroup ;
738    save d, p, q ; path p, q ; d := BodyFontSize/2;
739    vardef shape(expr w, h, o) =
740        (o,o) -- (w-o,o) & (w-o,o) .. (.75w-o,.5h) ..
741        (w-2o,h-o) & (w-2o,h-o) -- (o,h-o) -- cycle
742    enddef ;
743    p := shape(6cm, 6cm, d) ; q := shape(6cm, 6cm, 0) ;
744    lmt_parshape [
745        path       = p,
746        offsetpath = q,
747        dx         = d,
748        dy         = d,
749        trace      = true,
750    ] ;
751    draw q withpen pencircle scaled 1pt ;
752  endgroup ;
753\stopuseMPgraphic
754
755\defineoverlay[test 1][\useMPgraphic{test 1}]
756\defineoverlay[test 2][\useMPgraphic{test 2}]
757\defineoverlay[test 3][\useMPgraphic{test 3}]
758\defineoverlay[test 4][\useMPgraphic{test 4}]
759
760\startbuffer
761  \startshapetext[test 1,test 2,test 3,test 4]
762    \setupalign[verytolerant,stretch,normal]%
763    \samplefile{douglas} % Douglas R. Hofstadter
764  \stopshapetext
765  \startcombination[2*2]
766    {\framed[offset=overlay,frame=off,background=test 1]{\getshapetext}}
767        {test 1}
768    {\framed[offset=overlay,frame=off,background=test 2]{\getshapetext}}
769        {test 2}
770    {\framed[offset=overlay,frame=off,background=test 3]{\getshapetext}}
771        {test 3}
772    {\framed[offset=overlay,frame=off,background=test 4]{\getshapetext}}
773        {test 4}
774  \stopcombination
775\stopbuffer
776
777\typebuffer[option=TEX]
778
779In \in {figure} [fig:shapes:chain] we see the result. Watch how for two shapes
780we have enabled tracing. Of course you need to tweak till all fits well but we're
781talking of special situations anyway.
782
783\startplacefigure[Title=Multiple shapes,reference=fig:shapes:chain]
784    \getbuffer
785\stopplacefigure
786
787Here is a bit more extreme example. Again we use a circle:
788
789\startbuffer
790\startuseMPgraphic{circle}
791    lmt_parshape [
792        path       = fullcircle scaled 136mm,
793        offset     = 2mm,
794        bottomskip = - 1.5LineHeight,
795    ] ;
796\stopuseMPgraphic
797\stopbuffer
798
799\typebuffer[option=TEX]
800
801But we output a longer text:
802
803\startbuffer
804\startshapedparagraph[mp=circle,repeat=yes,method=cycle]%
805    \setupalign[verytolerant,stretch,last]\dontcomplain
806    {\darkred     \samplefile{tufte}}\par
807    {\darkgreen   \samplefile{tufte}}\par
808    {\darkblue    \samplefile{tufte}}\par
809    {\darkcyan    \samplefile{tufte}}\par
810    {\darkmagenta \samplefile{tufte}}\par
811\stopshapedparagraph
812\stopbuffer
813
814\typebuffer[option=TEX]
815
816We get a multi|-|page shape:
817
818\start \getbuffer \stop
819
820Compare this with:
821
822\startbuffer
823\startshapedparagraph[mp=circle,repeat=yes,method=cycle]%
824    \setupalign[verytolerant,stretch,last]\dontcomplain
825    {\darkred     \samplefile{tufte}}
826    {\darkgreen   \samplefile{tufte}}
827    {\darkblue    \samplefile{tufte}}
828    {\darkcyan    \samplefile{tufte}}
829    {\darkmagenta \samplefile{tufte}}
830\stopshapedparagraph
831\stopbuffer
832
833\typebuffer[option=TEX]
834
835Which gives:
836
837\start \getbuffer \stop
838
839Here the \type {bottomskip} takes care of subtle rounding issues as well as
840discarding the last line in the shape so that we get nicer continuation. There is
841no full automated solution for all you can come up with.
842
843Mixing a \METAPOST\ specification into a regular one is also possible. The next
844example demonstrates this as well as the option to remove some lines from a
845specification:
846
847\starttyping[option=TEX]
848\startparagraphshape[test]
849    left 0em right 0em
850    left 1em right 0em
851    metapost {circle}
852    delete 3
853    metapost {circle,circle,circle}
854    delete 7
855    metapost {circle}
856    repeat
857\stopparagraphshape
858\stoptyping
859
860You can combine a shape with narrowing a paragraph. Watch the \type {absolute}
861keyword in the next code. The result is shown in \in {figure} [fig:shape:skips].
862
863\startbuffer[demo-4]
864\startuseMPgraphic{circle}
865    lmt_parshape [
866        path       = fullcircle scaled TextWidth,
867        bottomskip = - 1.5LineHeight,
868    ] ;
869\stopuseMPgraphic
870
871\startparagraphshape[test-1]
872    metapost {circle} repeat
873\stopparagraphshape
874
875\startparagraphshape[test-2]
876    absolute left metapost {circle} repeat
877\stopparagraphshape
878
879\startparagraphshape[test-3]
880    absolute right metapost {circle} repeat
881\stopparagraphshape
882
883\startparagraphshape[test-4]
884    absolute both metapost {circle} repeat
885\stopparagraphshape
886
887\showframe
888
889\startnarrower[4*left,2*right]
890    \startshapedparagraph[list=test-1,repeat=yes,method=repeat]%
891        \setupalign[verytolerant,stretch,last]\dontcomplain
892        \dorecurse{3}{\samplefile{thuan}}
893    \stopshapedparagraph
894    \page
895    \startshapedparagraph[list=test-2,repeat=yes,method=repeat]%
896        \setupalign[verytolerant,stretch,last]\dontcomplain
897        \dorecurse{3}{\samplefile{thuan}}
898    \stopshapedparagraph
899    \page
900    \startshapedparagraph[list=test-3,repeat=yes,method=repeat]%
901        \setupalign[verytolerant,stretch,last]\dontcomplain
902        \dorecurse{3}{\samplefile{thuan}}
903    \stopshapedparagraph
904    \page
905    \startshapedparagraph[list=test-4,repeat=yes,method=repeat]%
906        \setupalign[verytolerant,stretch,last]\dontcomplain
907        \dorecurse{3}{\samplefile{thuan}}
908    \stopshapedparagraph
909\stopnarrower
910\stopbuffer
911
912\typebuffer[demo-4][option=TEX]
913
914\startplacefigure[title=Skip compensation,reference=fig:shape:skips]
915\startcombination[nx=2,ny=2]
916    {\typesetbuffer[demo-4][page=1,width=.4\textwidth,frame=on]} {test 1}
917    {\typesetbuffer[demo-4][page=2,width=.4\textwidth,frame=on]} {test 2, left}
918    {\typesetbuffer[demo-4][page=3,width=.4\textwidth,frame=on]} {test 3, right}
919    {\typesetbuffer[demo-4][page=4,width=.4\textwidth,frame=on]} {test 4, both}
920\stopcombination
921\stopplacefigure
922
923The shape mechanism has a few more tricks but these are really meant for usage
924in specific situations, where one knows what one deals with. The following
925examples are visualized in \in {figure} [fig:flow].
926
927\startbuffer[jano]
928\useMPlibrary[dum]
929\usemodule[article-basics]
930
931\startbuffer
932    \externalfigure[dummy][width=6cm]
933\stopbuffer
934
935\startshapedparagraph[text=\getbuffer]
936    \dorecurse{3}{\samplefile{ward}\par}
937\stopshapedparagraph
938
939\page
940
941\startshapedparagraph[text=\getbuffer,distance=1em]
942    \dorecurse{3}{\samplefile{ward}\par}
943\stopshapedparagraph
944
945\page
946
947\startshapedparagraph[text=\getbuffer,distance=1em,
948        hoffset=-2em]
949    \dorecurse{3}{\samplefile{ward}\par}
950\stopshapedparagraph
951
952\page
953
954\startshapedparagraph[text=\getbuffer,distance=1em,
955        voffset=-2ex,hoffset=-2em]
956    \dorecurse{3}{\samplefile{ward}\par}
957\stopshapedparagraph
958
959\page
960
961\startshapedparagraph[text=\getbuffer,distance=1em,
962        voffset=-2ex,hoffset=-2em,lines=1]
963    \dorecurse{3}{\samplefile{ward}\par}
964\stopshapedparagraph
965
966\page
967
968\startshapedparagraph[width=4cm,lines=4]
969    \dorecurse{3}{\samplefile{ward}\par}
970\stopshapedparagraph
971\stopbuffer
972
973\typebuffer[jano]
974
975\startplacefigure[title={Flow around something},reference=fig:flow]
976    \startcombination[nx=3,ny=2]
977        {\typesetbuffer[jano][page=1,frame=on,width=\measure{combination}]}{}
978        {\typesetbuffer[jano][page=2,frame=on,width=\measure{combination}]}{}
979        {\typesetbuffer[jano][page=3,frame=on,width=\measure{combination}]}{}
980        {\typesetbuffer[jano][page=4,frame=on,width=\measure{combination}]}{}
981        {\typesetbuffer[jano][page=5,frame=on,width=\measure{combination}]}{}
982        {\typesetbuffer[jano][page=6,frame=on,width=\measure{combination}]}{}
983    \stopcombination
984\stopplacefigure
985
986\stopsectionlevel
987
988\startsectionlevel[title=Modes]
989
990% \ruledvbox{1\ifhmode\writestatus{!}{HMODE 1}\fi}                               % hsize
991% \ruledvbox{\hbox{\strut 2}\ifhmode\writestatus{!}{HMODE 2}\fi}                 % fit
992% \ruledvbox{\hbox{\strut 3}\hbox{\strut 3}\ifhmode\writestatus{!}{HMODE 3}\fi}  % fit
993% \ruledvbox{\hbox{\strut 4}4\ifhmode\writestatus{!}{HMODE 4}\fi}                % hsize
994% \ruledvbox{\hbox{\strut 5}5\hbox{\strut 5}\ifhmode\writestatus{!}{HMODE 5}\fi} % hsize
995% \ruledvbox{6\hbox{\strut 6}\ifhmode\writestatus{!}{HMODE 6}\fi}                % hsize
996
997{\em todo: some of the side effects of so called modes}
998
999\stopsectionlevel
1000
1001\startsectionlevel[title=Leaders]
1002
1003Leaders are a basic feature that users probably never run into directly. They
1004repeat content till it fits the specified width which can be stretched out. The
1005content is typeset once and it is the backend that does the real work of
1006repetition.
1007
1008\startbuffer
1009\strut\leaders \hbox{!}\hfill\strut
1010\strut\xleaders\hbox{!}\hfill\strut
1011\strut\cleaders\hbox{!}\hfill\strut
1012\strut\gleaders\hbox{!}\hfill\strut
1013\stopbuffer
1014
1015\typebuffer
1016
1017Here \type {\leaders} starts at the left edge and are repeats the box as long as
1018it fits, \type {\xleaders} spreads till the edges and \type {\cleaders} centers
1019the lot. The \type {\gleaders} primitive (which is not in orginal \TEX) takes the
1020outer box as reference and further behaves like \type {\cleaders}.
1021
1022\startlines \showmakeup[line] \getbuffer \stoplines
1023
1024The leader primitives take box or rule but in \LUAMETATEX\ a glyph can also be
1025specified, which saves wrapping in a box.
1026
1027\startbuffer
1028\ruledvbox \bgroup \hsize 10cm
1029    \strut\cleaders\hbox{!}\hfill\strut
1030\egroup
1031
1032\ruledvbox \bgroup \hsize 10cm
1033    \strut\cleaders\hrule\hfill\strut
1034\egroup
1035
1036\ruledvbox \bgroup \hsize 10cm
1037    \strut\cleaders\glyph`!\hfill\strut
1038\egroup
1039\stopbuffer
1040
1041\typebuffer
1042
1043\getbuffer
1044
1045The \LUAMETATEX\ engine also introduced \type {\uleaders}
1046
1047\definecolor[tred]  [r=.6,a=1,t=.5]
1048\definecolor[tgreen][g=.6,a=1,t=.5]
1049\definecolor[tblue] [b=.6,a=1,t=.5]
1050
1051\startbuffer[one]
1052    x xx xxx xxxx
1053    \ruledhbox{L\hss R}\space
1054    x xx xxx xxxx
1055\stopbuffer
1056
1057\startbuffer[two]
1058    x xx xxx xxxx
1059    \uleaders\backgroundhbox[gray]{L\hss R}\hskip\zeropoint plus 100pt\relax\space
1060    x xx xxx xxxx
1061\stopbuffer
1062
1063\startbuffer[three]
1064    x xx xxx xxxx
1065    \uleaders\ruledhbox{L\hss R}\hskip\zeropoint plus 100pt\relax\space
1066    x xx xxx xxxx
1067\stopbuffer
1068
1069We show three boxes, a regular one first (red):
1070
1071\typebuffer[one]
1072
1073The second one (blue) is also a box but one that stretches upto 100pt and is in a
1074later stage, when the paragraph has been built, is repackaged to the effective
1075width. The third example (green) leaves out the background.
1076
1077\startlinecorrection
1078\startoverlay
1079    {\vbox{\color[tgreen]{\small\dorecurse {20} {\getbuffer[three]}}}}
1080    {\vbox{\color[tblue] {\small\dorecurse {20} {\getbuffer  [two]}}}}
1081    {\vbox{\color[tred]  {\small\dorecurse {20} {\getbuffer  [one]}}}}
1082\stopoverlay
1083\stoplinecorrection
1084
1085In \CONTEXT\ we have wrapped this feature in the adaptive box mechanism, so here
1086a few a few examples:
1087
1088\setupexternalfigures[location={default,local,global}]
1089
1090\startbuffer
1091\startsetups adaptive:test:a
1092    \setbox\usedadaptivebox\vbox to \usedadaptivetotal \bgroup
1093        \externalfigure
1094          [cow.pdf]
1095          [width=\framedmaxwidth,
1096           frame=on,
1097           height=\usedadaptivetotal]%
1098   \egroup
1099\stopsetups
1100
1101\startsetups adaptive:test:b
1102    \setbox\usedadaptivebox\vbox to \usedadaptivetotal \bgroup
1103        \externalfigure
1104          [cow.pdf]
1105          [width=\usedadaptivewidth,
1106           frame=on,
1107           height=\usedadaptivetotal]%
1108   \egroup
1109\stopsetups
1110\stopbuffer
1111
1112\typebuffer \getbuffer
1113
1114We use this as follows (see \in {figure} [fig:adaptive] for the result):
1115
1116\startbuffer
1117\framed[height=18cm,align=middle,adaptive=yes,top=,bottom=] {%
1118    \begstrut \samplefile{tufte} \endstrut
1119    \par
1120    \adaptivevbox
1121      [strut=yes,setups=adaptive:test:a]
1122      {\showstruts\strut\hsize5cm\hss}%
1123    \par
1124    \adaptivevbox
1125      [strut=yes,setups=adaptive:test:b]
1126      {\showstruts\strut\hsize5cm\hss}%
1127    \par
1128    \begstrut \samplefile{tufte} \endstrut
1129}
1130\stopbuffer
1131
1132\typebuffer
1133
1134\startplacefigure[reference=fig:adaptive]
1135    \getbuffer
1136\stopplacefigure
1137
1138Here is one that you can test yourself:
1139
1140\starttyping
1141\startsetups adaptive:test
1142    \setbox\usedadaptivebox\vbox to \usedadaptivetotal \bgroup
1143        \externalfigure
1144          [cow.pdf]
1145          [width=\usedadaptivewidth,
1146           height=\usedadaptivetotal]%
1147   \egroup
1148\stopsetups
1149
1150\ruledvbox to \textheight {
1151    \par \begstrut \samplefile{tufte} \endstrut \par
1152    \adaptivevbox[strut=yes,setups=adaptive:test]{\hsize\textwidth\hss}
1153    \par \begstrut \samplefile{tufte} \endstrut
1154}
1155\stoptyping
1156
1157The next example comes from the test suite (where it runs over many pages in
1158order to illustrate the idea):
1159
1160\startbuffer
1161\startMPdefinitions
1162    def TickTock =
1163        interim linecap := squared;
1164        save p ; path p ;
1165        p := fullsquare xysized(AdaptiveWidth,.9(AdaptiveHeight+AdaptiveDepth)) ;
1166        fill p withcolor AdaptiveColor ;
1167        draw bottomboundary (p enlarged (-AdaptiveThickness) )
1168            withdashes (3*AdaptiveThickness)
1169            withpen pencircle scaled AdaptiveThickness
1170            withcolor white ;
1171    enddef ;
1172\stopMPdefinitions
1173
1174\startsetups adaptive:test
1175    \setbox\usedadaptivebox\hbox
1176        to         \usedadaptivewidth
1177        yoffset -.9\usedadaptivedepth
1178    \bgroup
1179        \hss
1180        \startMPcode
1181            TickTock ;
1182        \stopMPcode
1183        \hss
1184   \egroup
1185\stopsetups
1186
1187\definecolor[adaptive:tick][.25(blue,green)]
1188\definecolor[adaptive:tock][.75(blue,green)]
1189
1190\defineadaptive
1191  [tick]
1192  [setups=adaptive:test,
1193   color=adaptive:tick,
1194   foregroundcolor=white,
1195   foregroundstyle=\infofont,
1196   strut=yes]
1197
1198\defineadaptive
1199  [tock]
1200  [tick]
1201  [color=adaptive:tock]
1202
1203\dostepwiserecurse{8}{12}{1}{%
1204    \dostepwiserecurse{5}{15}{1}{%
1205        this~#1.##1 is~#1.##1 test~#1.##1
1206        \ifodd##1\relax
1207            \adaptivebox[tick]{\hss tick #1.##1\hss}
1208        \else
1209            \adaptivebox[tock]{\hss tock #1.##1\hss}
1210        \fi
1211    }
1212}
1213\stopbuffer
1214
1215\typebuffer \getbuffer
1216
1217In the next example the graphics adapt to the available space:
1218
1219\startbuffer
1220\startsetups adaptive:test
1221    \setbox\usedadaptivebox\hbox
1222        to       \usedadaptivewidth
1223        yoffset -\usedadaptivedepth
1224    \bgroup
1225        \externalfigure
1226          [cow.pdf]
1227          [width=\usedadaptivewidth,
1228           height=\dimexpr\usedadaptivetotal\relax]%
1229    \egroup
1230\stopsetups
1231
1232\dostepwiserecurse{1}{50}{1}{%
1233    this~#1 is~#1 test~#1
1234    {\adaptivebox[strut=yes,setups=adaptive:test]{}}
1235}
1236\stopbuffer
1237
1238\typebuffer \getbuffer
1239
1240\stopsectionlevel
1241
1242\startsectionlevel[title=Prevdepth]
1243
1244The depth of a box is normally positive but rules can have a negative depth in
1245order to get a rule above the baseline. When \TEX\ was written the assumption was
1246that a negative depth of more than 1000 point made no sense at all. The last
1247depth on a vertical list is registered in the \type {\prevdepth} variable. This
1248is basically a reference into the current list. In order to illustrate some
1249interesting side effects of setting this \type {\prevdepth} and especially when
1250we set it to $\tf -1000pt$. In order to illustrate this this special value can be set
1251to a different value in \LUAMETATEX. However, as dealing with the property is
1252somewhat special in the engine you should not set it unless you know that the
1253macro package is ware of it.
1254
1255\startbuffer
1256line 1\par line 2 \par \nointerlineskip line 3 \par
1257\stopbuffer
1258
1259\typebuffer
1260
1261Assuming that we haven't set any inter paragraph spacing this gives:
1262
1263\startlinecorrection
1264\ruledvbox{\setupwhitespace[none]\showmakeup[line]\getbuffer}
1265\stoplinecorrection
1266
1267Here \type {\nointerlineskip} is (normally) defined as:
1268
1269\starttyping
1270\prevdepth-1000pt
1271\stoptyping
1272
1273although in \CONTEXT\ we use \type {\ignoredepthcriterium} instead of the hard
1274coded dimension. We now give a more extensive example:
1275
1276\startbuffer[definition-1]
1277\def\PrevTest#1%
1278  {\setbox0\ruledhbox{\strut$\tf#1$}%
1279   \dp0=#1
1280   \vbox\bgroup\hsize4em
1281     FIRST\par
1282     \unhbox0\par
1283     LAST\par
1284   \egroup}
1285\stopbuffer
1286
1287\startbuffer[definition-2]
1288\def\PrevTest#1%
1289  {\setbox0\ruledhbox{\strut$\tf#1$}%
1290   \dp0=#1
1291   \vbox\bgroup
1292     \ruledhbox{FIRST}\par
1293     \box0\par
1294     \ruledhbox{LAST}\par
1295   \egroup}
1296\stopbuffer
1297
1298\startbuffer[example]
1299\ruledhbox \bgroup
1300    \PrevTest{-10.0pt}\quad
1301    \PrevTest{-20.0pt}\quad
1302    \PrevTest{-49.9pt}\quad
1303    \PrevTest{-50.0pt}\quad
1304    \PrevTest{-50.1pt}\quad
1305    \PrevTest{-60.0pt}\quad
1306    \PrevTest{-80.0pt}%
1307\egroup
1308\stopbuffer
1309
1310\typebuffer[example][option=TEX]
1311
1312In this example we set \type {\ignoredepthcriterium} to $\tf -50.0pt$ instead of the
1313normal $\tf -1000pt$. The helper is defined as:
1314
1315\typebuffer[definition-1][option=TEX]
1316
1317or
1318
1319\typebuffer[definition-2][option=TEX]
1320
1321The result is shown in \in {figures} [fig:prevdepth-1] \in {and}
1322[fig:prevdepth-2]. The first case is what we normally have in text and we haven't
1323set \type {prevdepth} explicitly between lines so \TEX\ will just look at the
1324depth of the lines. In the second case the depth is ignored when less than the
1325criterium which is why, when we set the depth of the box to a negative value we
1326get somewhat interesting skips.
1327
1328\startplacefigure[reference=fig:prevdepth-1]
1329    \showmakeup[line]
1330    \ignoredepthcriterium-50pt
1331    \setupwhitespace[none]
1332    \getbuffer[definition-1,example]
1333\stopplacefigure
1334
1335\startplacefigure[reference=fig:prevdepth-2]
1336    \showmakeup[line]
1337    \ignoredepthcriterium-50pt
1338    \setupwhitespace[none]
1339    \getbuffer[definition-2,example]
1340    \blank[5*line]
1341\stopplacefigure
1342
1343I'm sure one can use this effect otherwise than intended but I doubt is any user
1344is willing to do this but the fact that we can lower the criterium makes for nice
1345experiments. Just for the record, in \in {figure} [fig:prevdepth-3] you see what
1346we get with positive values:
1347
1348\startbuffer[example]
1349\ruledhbox \bgroup
1350    \PrevTest{10.0pt}\quad
1351    \PrevTest{20.0pt}\quad
1352    \PrevTest{49.9pt}\quad
1353    \PrevTest{50.0pt}\quad
1354    \PrevTest{50.1pt}\quad
1355    \PrevTest{60.0pt}\quad
1356    \PrevTest{80.0pt}%
1357\egroup
1358\stopbuffer
1359
1360\typebuffer[example][option=TEX]
1361
1362\startplacefigure[reference=fig:prevdepth-3]
1363    \showmakeup[line]
1364    \ignoredepthcriterium50pt
1365    \setupwhitespace[none]
1366    \getbuffer[definition-2,example]
1367\stopplacefigure
1368
1369Watch the interline skip kicking in when we make the depth larger than in
1370\type {\ignoredepthcriterium} being $\tf 50pt$.
1371
1372\stopsectionlevel
1373
1374\startsectionlevel[title=Normalization]
1375
1376{\em todo: users don't need to bother about this but it might be interesting anyway}
1377
1378\stopsectionlevel
1379
1380\startsectionlevel[title=Dirty tricks]
1381
1382{\em todo: explain example for combining paragraphs}
1383
1384% test\wrapuppar{\crlf\ignorepars}
1385%
1386% test
1387%
1388% test\wrapuppar{\ignorepars}
1389%
1390% test
1391%
1392% test\wrapuppar{\removeunwantedspaces\ignorepars}
1393%
1394% test
1395
1396\stopsectionlevel
1397
1398\stopdocument
1399
1400% I rewarded myself after writing a section by watching the video "Final Thing On
1401% My Mind", The Pineapple This, Live, 2020, the usual perfect GH performance,
1402% wondering if live would turn to normal so that we could go to such concerts once
1403% again given successive covids. Writing manuals can do with a distraction.
1404%
1405% Gavin Harrison: Soundcheck, Drummerworld Jan 27, 2021 ... I wish I could make
1406% something called a check into pefect solo. Okay, another section and I'll check
1407% out the latest Simon Phillips and other favourite dummer uploads.
1408
1409% todo:
1410
1411% \everyhbox \everyvbox : useless unless one resets
1412% \parattr
1413% \snapshotpar
1414% \wrapuppar
1415
1416% \normalizelinemode0
1417% x\ruledhbox{\parindent 1cm\indent x \indent x}
1418% \normalizelinemode \parindentskipnormalizecode
1419% x\ruledhbox{\parindent 1cm\indent x \indent x}
1420
1421% \starttext
1422%     \tracingoutput1 \tracingonline1
1423%     \pretolerance9000 test \pretolerance 8000 test \par
1424%     \pretolerance9000 test \pretolerance 7000 \updateparagraphproperties test \par
1425%     \pretolerance9000 test \pretolerance 6000 \snapshotpar\tolerancefrozenparcode test \par
1426%     \pretolerance9000 test {\pretolerance5000 \snapshotpar\ntolerancefrozenparcode}test \par
1427% \stoptext
1428
1429% \par[newgraf][16=1,17=1], .... pretolerance 9000, ....
1430% \par[newgraf][16=1,17=1], .... pretolerance 7000, ....
1431% \par[newgraf][16=1,17=1], .... pretolerance 6000, ....
1432
1433% \parfillleftskip
1434
1435% todo:
1436
1437% \starttext
1438%
1439% \showframe
1440%
1441% % this is the current default behaviour; we have a topskip with quite some stretch
1442% % and that stretch is taken into account when tex calculates the badness; watch
1443% % the next page
1444%
1445% \dorecurse{4}{
1446%     \bgroup
1447%         \shapingpenaltiesmode\zerocount
1448%         \showmakeup[penalty]
1449%         \placefigure[left]{}{}
1450%         \input tufte \par
1451%     \egroup
1452% }
1453%
1454% \page EMPTY \page
1455%
1456% % the ntop is new and when >= 0 it is a multiplier for the number of lines
1457% % stretch, here we have one line; watch the next page
1458%
1459% \dorecurse{4}{
1460%     \bgroup
1461%         \shapingpenaltiesmode\zerocount
1462%         \setupinterlinespace[ntop=1]
1463%         \showmakeup[penalty]
1464%         \placefigure[left]{}{}
1465%         \input tufte \par
1466%     \egroup
1467% }
1468%
1469% \page EMPTY \page
1470%
1471% % these shaping parameters will discourage a linebreak within a shape;
1472% % the placement macro checked available space but that doesn't mean that
1473% % there can be no linebreak
1474%
1475% \dorecurse{4}{
1476%     \bgroup
1477%         \showmakeup[penalty]
1478%         \shapingpenalty\plushundred
1479%         \shapingpenaltiesmode"FF\relax
1480%         \placefigure[left]{}{}
1481%         \input tufte \par
1482%     \egroup
1483% }
1484%
1485% \page EMPTY \page
1486%
1487% % the next pages show the effect of changed topskip on page breaks with
1488% % footnotes
1489%
1490% \dorecurse{10}{
1491%     [#1] \input tufte \footnote{\input{tufte}} \par
1492% }
1493%
1494% \page EMPTY \page
1495%
1496% \setupinterlinespace[ntop=2]
1497%
1498% \dorecurse{10}{
1499%     [#1] \input tufte \footnote{\input{tufte}} \par
1500% }
1501%
1502% \page EMPTY \page
1503%
1504% \setupinterlinespace[ntop=0]
1505%
1506% \dorecurse{10}{
1507%     [#1] \input tufte \footnote{\input{tufte}} \par
1508% }
1509%
1510% \stoptext
1511
1512