evenmore-paragraphs.tex /size: 15 Kb    last modification: 2021-10-28 13:50
1% language=us runpath=texruns:manuals/evenmore
2
3% End of July 2020 I decided to look into some of the backlog items and paragraphs
4% are on them, as are inserts and so. The usual musical time stamp is buying the
5% excellent Prince Live at the Aladdin Las Vegas DVD which I ran between the
6% moments that I had enough of coding. Some tracks, like Family Name, fit perfectly
7% in mid 2020.
8
9% https://www.youtube.com/watch?v=f8FAJXPBdOg
10
11\environment evenmore-style
12
13\startcomponent evenmore-paragraphs
14
15\enableexperiments[paragraphs.freeze]
16
17\startchapter[title=Paragraphs]
18
19{\em This is mostly a wrapup of some developments, and definitely not a tutorial.
20What is described here is experimental and successive version of \CONTEXT\ \LMTX\
21will explore their potential. As long a users stay away from the low level
22primitives we can try to guarantee consistent behavior (and catch side effect or
23deal with known issues).}
24
25\startsection[title=Freezing]
26
27A well known property of paragraphs is that when the moment is there to split
28into lines, the current state of variables drives it. There are a lot of quite
29some variables involved. The most significant one is the \type {\hsize}. Take
30this:
31
32\startbuffer
33\bgroup
34    {\bf Ward:}
35    \hsize .25\textwidth
36    {\bf Ward:} \samplefile{ward}
37    \hsize .75\textwidth % last value
38\egroup
39\stopbuffer
40
41\typebuffer
42
43This gives:
44
45{\forgetparagraphfreezing \getbuffer}
46
47But wait, why do we get the full text width here? The reason is that by the time
48the paragraph ends, after the \type {\egroup}, the \type {\hsize} is set back to
49what it was before the group started.
50
51\startbuffer
52\bgroup
53    \hsize .25\textwidth
54    {\bf Ward:} \samplefile{ward}
55    \hsize .75\textwidth % last value
56    \par
57\egroup
58\stopbuffer
59
60\typebuffer
61
62This gives:
63
64{\forgetparagraphfreezing \getbuffer}
65
66The last \type {\hsize} specified is used. That is not really a problem, but the
67fact that we need to explicitly end a paragraph before the group ends actually
68is, and in a moment we will see an example where that matters a lot. First a
69general solution to this problem is discussed. In the next example, we do group,
70but inside that group we take a snapshot of the \type {\hsize}:
71
72\startbuffer
73\bgroup
74    \hsize .80\textwidth
75    \dontleavehmode
76    \snapshotpar "000001
77    {\bf Ward:} \samplefile{ward}
78\egroup
79\stopbuffer
80
81\typebuffer
82
83This time we get:
84
85{\forgetparagraphfreezing \getbuffer}
86
87The magic number used in the snapshot relates to the \type {\hsize}.
88
89\startcolumns[n=2]
90\starttabulate[|T||]
91\NC 0x\uchexnumbers{\hsizefrozenparcode        } \NC hsize \NC \NR
92\NC 0x\uchexnumbers{\skipfrozenparcode         } \NC leftskip rightskip \NC \NR
93\NC 0x\uchexnumbers{\hangfrozenparcode         } \NC hangindent hangafter \NC \NR
94\NC 0x\uchexnumbers{\indentfrozenparcode       } \NC parindent \NC \NR
95\NC 0x\uchexnumbers{\parfillfrozenparcode      } \NC parfillskip parfillleftskip \NC \NR
96\NC 0x\uchexnumbers{\adjustfrozenparcode       } \NC adjustspacing adjustspacingstep adjustspacingshrink adjustspacingstretch \NC \NR
97\NC 0x\uchexnumbers{\protrudefrozenparcode     } \NC protrudechars \NC \NR
98\NC 0x\uchexnumbers{\tolerancefrozenparcode    } \NC pretolerance tolerance \NC \NR
99\NC 0x\uchexnumbers{\stretchfrozenparcode      } \NC emergencystretch \NC \NR
100\NC 0x\uchexnumbers{\loosenessfrozenparcode    } \NC looseness \NC \NR
101\NC 0x\uchexnumbers{\lastlinefrozenparcode     } \NC lastlinefit \NC \NR
102\NC 0x\uchexnumbers{\linepenaltyfrozenparcode  } \NC linepenalty interlinepenalty interlinepenalties \NC \NR
103\NC 0x\uchexnumbers{\clubpenaltyfrozenparcode  } \NC clubpenalty clubpenalties \NC \NR
104\NC 0x\uchexnumbers{\widowpenaltyfrozenparcode } \NC widowpenalty widowpenalties displaywidowpenalty displaywidowpenalties \NC \NR
105\NC 0x\uchexnumbers{\brokenpenaltyfrozenparcode} \NC brokenpenalty \NC \NR
106\NC 0x\uchexnumbers{\demeritsfrozenparcode     } \NC adjdemerits doublehyphendemerits finalhyphendemerits \NC \NR
107\NC 0x\uchexnumbers{\shapefrozenparcode        } \NC parshape \NC \NR
108\NC 0x\uchexnumbers{\linefrozenparcode         } \NC baselineskip lineskip lineskiplimit \NC \NR
109\NC                                              \NC \NC \NR
110\NC 0xFFFFFFF                                    \BC all of them \NC \NR
111\stoptabulate
112\stopcolumns
113
114In practice you will set them all on one go, so:
115
116\starttyping
117\snapshotpar "FFFFFFF
118\stoptyping
119
120How often do we need such a feature? Actually more often than one thinks,
121especially when we have an unpredictable situation. For instance, when you
122typeset from an \XML\ source you often don't know what you get, and you can have
123cases that end up like this:
124
125\startbuffer
126\placefigure[left,none]{}{} {Ward: \bf  \dorecurse{3}{\samplefile{ward}} } \par
127\placefigure[left,none]{}{} {\bf Ward:} \dorecurse{3}{\samplefile{ward}}   \par
128\stopbuffer
129
130\typebuffer
131
132This might render as:
133
134{\forgetparagraphfreezing \getbuffer} \forgetsidefloats % needed due to interference
135
136The placement of such a figure is hooked into \type {\everypar} and uses hanging
137indentation. Like \type {\hsize}, \type {\hangafter} and \type {\hangindent} can
138be forgotten before the paragraph ends. In \MKII\ and \MKIV\ the recommended
139solution is to always start a paragraph explicitly, with a strut, forced
140indentation of preferably:
141
142\startbuffer
143\dontleavehmode {Ward: \bf  \dorecurse{3}{\samplefile{ward} } } \par
144\dontleavehmode {\bf Ward:} \dorecurse{3}{\samplefile{ward} }   \par
145\stopbuffer
146
147\typebuffer
148
149In an \XML\ mapping we can hide it but in a regular \TEX\ source this is not
150pretty. With little effort we can do the snapping automatically, so that we get:
151
152\placefigure[left,none]{}{} {Ward: \bf  \dorecurse{3}{\samplefile{ward} } } \par
153\placefigure[left,none]{}{} {\bf Ward:} \dorecurse{3}{\samplefile{ward} }   \par
154
155and this is what \CONTEXT\ \LMTX\ will do once we're sure that the snapshot
156feature behaves well and has no side effects. There is of course some overhead
157involved in taking snapshots, keeping track of the values and accessing them
158later, but it is rewarding.
159
160In addition to the numeric \type {\snapshotpar} primitive there is also another
161way to take s snapshot. As with the numeric variant, it only takes a snapshot when
162in horizontal mode: there has to be a so called local par node at the head of the
163current list. The next code shows some how to play with some of what \CONTEXT\
164offers:
165
166\starttyping
167\setuplayout[alternative=doublesided]
168
169\starttext
170
171\startbuffer
172    \dorecurse{8}{
173        \interlinepenalties 1 \maxcard
174        CASE 1: \samplefile{tufte} \par
175    } \page
176
177    \dorecurse{8}{
178        CASE 2: \samplefile{tufte}
179        \interlinepenalties 1 \maxcard \par
180    } \page
181
182    \dorecurse{8}{
183        CASE 3: \samplefile{tufte}
184        \interlinepenalties 1 \maxcard \freezeparagraphproperties \par
185    } \page
186
187    \dorecurse{8}{
188        CASE 4: \samplefile{tufte}
189        \frozen \interlinepenalties 1 \maxcard \par
190    } \page
191
192    \dorecurse{8}{
193        CASE 5: \samplefile{tufte}
194        \frozen \interlinepenalty \maxcard \par
195    } \page
196\stopbuffer
197
198\typebuffer \page \getbuffer
199
200\stoptext
201\stoptyping
202
203When you process this you will notice that the \type {\frozen} prefix also
204snapshots the parameter that gets set. Now, there is a pitfall here: some for
205these settings are persistent, i.e. they are not reset after a paragraph has been
206typeset. For instance, \type {\tolerance} is a general setting, but \type
207{\hangindent} is a one shot setting: it's value gets reset after the paragraph
208has been dealt with.
209
210Here is another test one can run to see what happens:
211
212\starttyping
213\dontleavehmode
214\defrostparagraphproperties
215\writestatus{state}{after  start            \uchexnumbers{\the\snapshotpar}}%
216\writestatus{state}{before set   hangindent \uchexnumbers{\the\snapshotpar}}%
217\frozen\hangindent10pt
218\writestatus{state}{after  set   hangindent \uchexnumbers{\the\snapshotpar}}%
219\writestatus{state}{before set   looseness  \uchexnumbers{\the\snapshotpar}}%
220\frozen\looseness 1
221\writestatus{state}{after  set   looseness  \uchexnumbers{\the\snapshotpar}}%
222\writestatus{state}{before set   hangafter  \uchexnumbers{\the\snapshotpar}}%
223\frozen\hangafter 2
224\writestatus{state}{after  set   hangafter  \uchexnumbers{\the\snapshotpar}}%
225\begingroup
226\writestatus{state}{before set   rightskip  \uchexnumbers{\the\snapshotpar}}%
227\frozen\rightskip2cm
228\writestatus{state}{after  set   rightskip  \uchexnumbers{\the\snapshotpar}}%
229\endgroup
230\writestatus{state}{before reset hangindent \uchexnumbers{\the\snapshotpar}}%
231\snapshotpar-\frozenhangindentcode
232\writestatus{state}{after  reset hangindent \uchexnumbers{\the\snapshotpar}}%
233\writestatus{state}{before reset hangafter  \uchexnumbers{\the\snapshotpar}}%
234\snapshotpar-\frozenhangaftercode
235\writestatus{state}{after  reset hangafter  \uchexnumbers{\the\snapshotpar}}%
236... content ...
237\stoptyping
238
239You can group an assignment and then take a snapshot. That way the change doesn't
240affect following paragraphs, unless of course to did a global assignment. In
241\CONTEXT\ we have a bunch of constants that can be used instead of the hard to
242remember bit positions. The \type {\frozen} prefix can also be used with for
243instance a \type {\advance} operation. Of course it only has effect for those
244(internal) parameters that relate to a paragraph.
245
246Keep in mind that what is show here will evolve: in \CONTEXT\ \LMTX\ we will
247snapshot by default and the core macros are aware of this fact. Although the way
248\CONTEXT\ is set up makes it relatively easy to make this paradigm shift users
249should anyway be aware of this change when they do their own low level tweaking,
250but in that case they probably already are aware of possible interferences.
251
252\stopsection
253
254\startsection[title=Wrapping up]
255
256Another new (low level) feature is wrapping up a paragraph. Traditional \TEX\
257comes with the powerful \type {\everypar} and in \LUAMETATEX\ we now have \type
258{\wrapuppar}. This primitive collects tokens that will be expanded just before
259the paragraph ends. Here is an example:
260
261\startbuffer
262\dontleavehmode
263\wrapuppar{\hfill {\bf ONE}}%
264\wrapuppar{\crlf\strut\hfill {\bf TWO}\hfill\strut}%
265\wrapuppar{\crlf\strut {\bf THREE}\hfill\strut {\bf FOUR}}%
266\samplefile{ward}
267
268\samplefile{ward}
269\stopbuffer
270
271\typebuffer
272
273We can only wrapup when we are in a paragraph although one can of course use the
274\type {\wrapuppar} command inside an \type {\everypar} if needed.
275
276\getbuffer
277
278An more useful example is the following. We leave it to the reader to check it
279out:
280
281\starttyping
282\dorecurse{10}{
283    \bgroup
284        \advance\hsize by -#1cm\relax
285        \dontleavehmode
286        \wrapuppar{\strut\nobreak\hfill\nobreak QED}%
287        \samplefile{ward}
288    \egroup
289    \par
290}
291\stoptyping
292
293\stopsection
294
295\startsection[title=Insertions]
296
297The concept of inserts is kind of complicated. They are nodes in a list that make
298separate streams. An application of inserts are footnotes. In the text flow a
299symbol is typeset (like a raised number) and the note itself becomes an insert.
300When a paragraph is broken into lines, these inserts end up in to be boxed line,
301but when the line is actually wrapped in a box, these inserts are collected and
302injected after the line. The page builder will then take their dimensions into
303account when it comes to breaking pages. Depending on how strict the rules are
304the inserts will end up on the same page, move, of be broken into lines.
305
306This all works well as long as the inserts are not burried into boxes: they then
307are invisible to the mechanism described before. Take the following example:
308
309\starttyping
310\dontleavehmode
311l\hbox{h\footnote{h1} test}
312l\hbox{h\footnote{h2}} test
313l\hbox{h\footnote{h3}} test
314l\footnote{l4} test
315l\footnote{l5} test
316l\hbox{h\footnote{h6} test}
317l\hbox{\hbox{\hbox{h\footnote{h7} test}}}
318l\footnote{l8} test
319\par
320\stoptyping
321
322% \starttabulate
323% \NC test \NC test \footnote{before} \samplefile{tufte} \footnote{after}\NC \NR
324% ...
325% \NC test \NC test \footnote{before} \samplefile{tufte} \footnote{after}\NC \NR
326% \stoptabulate
327
328In the engines used with \MKII\ only a few footnotes actually show up. In \MKIV\
329the situation is slightly better because there we use some trickery to migrate
330these notes to the outer level. But even there it's not perfect because the order
331changes. We can actually fix that (and do so) but it comes at a performance penalty
332so this is why in \MKIV\ dealing with this is optional.
333
334\start
335    \def\Hi#1{\high{\tx#1}}
336    \dontleavehmode
337    \hbox{lh\H1 test lh\H2 test lh\H3 test l\H4 test l\H5 test lh\H6 test lh\H7 test l\H8 test}
338
339    \starttabulate[|||||||||||]
340    \NC \MKII \NC \PDFTEX\ & \XETEX         \NC \Hi4 l4 \NC \Hi5 l5 \NC \Hi8 l8 \NC         \NC         \NC         \NC         \NC         \NC \NR
341    \NC \MKIV \footnote{In older versions.} \NC \LUATEX             \NC \Hi1 h1 \NC \Hi2 h2 \NC \Hi3 h3 \NC \Hi6 h6 \NC \Hi7 h7 \NC \Hi4 l4 \NC \Hi5 l5 \NC \Hi8 l8 \NC \NR
342    \NC \LMTX \NC \LUAMETATEX               \NC \Hi1 h1 \NC \Hi2 h2 \NC \Hi3 h3 \NC \Hi4 l4 \NC \Hi5 l5 \NC \Hi6 h6 \NC \Hi7 h7 \NC \Hi8 l8 \NC \NR
343    \stoptabulate
344\stop
345
346However, when you look at the results of \LMTX\ you will notice that the
347situation is better. This is because we have some code to \LUAMETATEX\ that can
348better deal with some cases. Combined with some \LUA\ magic (as in \MKIV) we get
349the right order at hardly any runtime overhead. It must be noted that the
350original \TEX\ engine for good reason works as it does because there the actual
351typesetting (read: resolving glyphs, hyphenation, applying ligatures and kerns,
352etc.) is interwoven with the main scanning|/|expanding loops in order to be
353efficient on the machines of those times. In \LUATEX\ we have these stages
354separated but the code dealing with inserts is the same, if only because we have
355to be compatible. In \LUAMETATEX\ we have again a bit simpler code because we use
356the fact that lists are double linked, which also makes it possible to add some
357magic code dealing with nested inserts without obscuring the code. It comes of
358course at a bit performance hit and the nodes related to lists also because
359larger but they are already much larger than in other engines, so we don't care
360too much about that. It is anyway a mechanism that need to be enabled explicitly.
361
362\stopsection
363
364\stopchapter
365
366\stopcomponent
367
368% \starttext
369
370%     \def\TestA  {\registerparwrapper       {A}  {[\ignorespaces}{\removeunwantedspaces]\showparwrapperstate{A}}}
371%     \def\TestB#1{\registerparwrapper       {B#1}{(\ignorespaces}{\removeunwantedspaces)\showparwrapperstate{B#1}}}
372%     \def\TestC  {\registerparwrapper       {C}  {<\ignorespaces}{\removeunwantedspaces>\showparwrapperstate{C}\forgetparwrapper}}
373%     \def\TestR  {\registerparwrapperreverse{R}  {<\ignorespaces}{\removeunwantedspaces>\showparwrapperstate{R}}}
374
375%     \start
376%         \TestA
377%         \dorecurse{3}{1.#1 before \ruledvbox{\hsize2em\raggedcenter\TestB1 !\par} after\par} \blank
378%         \dorecurse{3}{2.#1 before \ruledvbox{\hsize3em\raggedcenter        !\par} after\par} \blank
379%         \dorecurse{3}{3.#1 before \ruledvbox{\hsize4em\raggedcenter\TestB2 !}     after\par} \blank
380%         \forgetparwrapper
381%         \dorecurse{3}{4.#1 before \ruledvbox{\hsize5em\raggedcenter\TestB3 !}     after\par} \blank
382%         \TestC
383%         \dorecurse{3}{5.#1 before \ruledvbox{\hsize2em\raggedcenter\TestA   !}     after\par} \blank
384%     \stop
385
386
387%     \start
388%         \TestA
389%         \dorecurse{3}{6.#1  before after\par} \blank
390%         \TestB4
391%         \dorecurse{3}{7.#1 before after\par} \blank
392%         \TestB5
393%         \TestR
394%         \dorecurse{3}{8.#1 before after\par} \blank
395%     \stop
396
397% \stoptext
398