lowlevel-alignments.tex /size: 28 Kb    last modification: 2023-12-21 09:43
1% language=us runpath=texruns:manuals/lowlevel
2
3\startcomponent lowlevel-alignments
4
5\environment lowlevel-style
6
7\startdocument
8  [title=alignments,
9   color=middlegreen]
10
11\startsectionlevel[title=Introduction]
12
13\TEX\ has a couple of subsystems and alignments is one of them. This mechanism is
14used to construct tables or alike. Because alignments use low level primitives to
15set up and construct a table, and because such a setup can be rather extensive, in
16most cases users will rely on macros that hide this.
17
18\startbuffer
19\halign {
20        \alignmark\hss \aligntab
21    \hss\alignmark\hss \aligntab
22    \hss\alignmark     \cr
23    1.1     \aligntab 2,2     \aligntab 3=3     \cr
24    11.11   \aligntab 22,22   \aligntab 33=33   \cr
25    111.111 \aligntab 222,222 \aligntab 333=333 \cr
26}
27\stopbuffer
28
29\typebuffer[option=TEX]
30
31That one doesn't look too complex and comes out as:
32
33\blank\getbuffer\blank
34
35This is how the previous code comes out when we use one of the \CONTEXT\ table
36mechanism.
37
38\startbuffer
39\starttabulate[|l|c|r|]
40  \NC 1.1     \NC 2,2     \NC 3=3     \NC \NR
41  \NC 11.11   \NC 22,22   \NC 33=33   \NC \NR
42  \NC 111.111 \NC 222,222 \NC 333=333 \NC \NR
43\stoptabulate
44\stopbuffer
45
46\typebuffer[option=TEX]
47
48\blank\getbuffer\blank
49
50That one looks a bit different with respect to spaces, so let's go back to the
51low level variant:
52
53\startbuffer
54\halign {
55        \alignmark\hss \aligntab
56    \hss\alignmark\hss \aligntab
57    \hss\alignmark     \cr
58  1.1\aligntab     2,2\aligntab     3=3\cr
59  11.11\aligntab   22,22\aligntab   33=33\cr
60  111.111\aligntab 222,222\aligntab 333=333\cr
61}
62\stopbuffer
63
64\typebuffer[option=TEX]
65
66Here we don't have spaces in the content part and therefore also no spaces in the
67result:
68
69\blank\getbuffer\blank
70
71You can automate dealing with unwanted spacing:
72
73\startbuffer
74\halign {
75      \ignorespaces\alignmark\unskip\hss \aligntab
76  \hss\ignorespaces\alignmark\unskip\hss \aligntab
77  \hss\ignorespaces\alignmark\unskip     \cr
78  1.1     \aligntab 2,2     \aligntab 3=3     \cr
79  11.11   \aligntab 22,22   \aligntab 33=33   \cr
80  111.111 \aligntab 222,222 \aligntab 333=333 \cr
81}
82\stopbuffer
83
84\typebuffer[option=TEX]
85
86We get:
87
88\blank\getbuffer\blank
89
90By moving the space skipping and cleanup to the so called preamble we don't need
91to deal with it in the content part. We can also deal with inter|-|column spacing
92there:
93
94\startbuffer
95\halign {
96      \ignorespaces\alignmark\unskip\hss \tabskip 1em \aligntab
97  \hss\ignorespaces\alignmark\unskip\hss \tabskip 1em \aligntab
98  \hss\ignorespaces\alignmark\unskip     \tabskip 0pt \cr
99  1.1     \aligntab 2,2     \aligntab 3=3     \cr
100  11.11   \aligntab 22,22   \aligntab 33=33   \cr
101  111.111 \aligntab 222,222 \aligntab 333=333 \cr
102}
103\stopbuffer
104
105\typebuffer[option=TEX]
106
107\blank\getbuffer\blank
108
109If for the moment we forget about spanning columns (\type {\span}) and locally
110ignoring preamble entries (\type {\omit}) these basic commands are not that
111complex to deal with. Here we use \type {\alignmark} but that is just a primitive
112that we use instead of \type {#} while \type {\aligntab} is the same as \type
113{&}, but using the characters instead also assumes that they have the catcode
114that relates to a parameter and alignment tab (and in \CONTEXT\ that is not the
115case). The \TEX book has plenty alignment examples so if you really want to learn
116about them, consult that must|-|have|-|book.
117
118\stopsectionlevel
119
120\startsectionlevel[title=Between the lines]
121
122The individual rows of a horizontal alignment are treated as lines. This means that,
123as we see in the previous section, the interline spacing is okay. However, that also
124means that when we mix the lines with rules, the normal \TEX\ habits kick in. Take
125this:
126
127\startbuffer
128\halign {
129      \ignorespaces\alignmark\unskip\hss \tabskip 1em \aligntab
130  \hss\ignorespaces\alignmark\unskip\hss \tabskip 1em \aligntab
131  \hss\ignorespaces\alignmark\unskip     \tabskip 0pt \cr
132  \noalign{\hrule}
133  1.1     \aligntab 2,2     \aligntab 3=3     \cr
134  \noalign{\hrule}
135  11.11   \aligntab 22,22   \aligntab 33=33   \cr
136  \noalign{\hrule}
137  111.111 \aligntab 222,222 \aligntab 333=333 \cr
138  \noalign{\hrule}
139}
140\stopbuffer
141
142\typebuffer[option=TEX]
143
144The result doesn't look pretty and actually, when you see documents produced by
145\TEX\ using alignments you should not be surprised to notice rather ugly spacing.
146The user (or the macropackage) should deal with that explicitly, and this is not
147always the case.
148
149\startlinecorrection
150\getbuffer
151\stoplinecorrection
152
153The solution is often easy:
154
155\startbuffer
156\halign {
157      \ignorespaces\strut\alignmark\unskip\hss \tabskip 1em \aligntab
158  \hss\ignorespaces\strut\alignmark\unskip\hss \tabskip 1em \aligntab
159  \hss\ignorespaces\strut\alignmark\unskip     \tabskip 0pt \cr
160  \noalign{\hrule}
161  1.1     \aligntab 2,2     \aligntab 3=3     \cr
162  \noalign{\hrule}
163  11.11   \aligntab 22,22   \aligntab 33=33   \cr
164  \noalign{\hrule}
165  111.111 \aligntab 222,222 \aligntab 333=333 \cr
166  \noalign{\hrule}
167}
168\stopbuffer
169
170\typebuffer[option=TEX]
171
172\startlinecorrection
173\getbuffer
174\stoplinecorrection
175
176The user will not notice it but alignments put some pressure on the general \TEX\
177scanner. Actually, the scanner is either scanning an alignment or it expects
178regular text (including math). When you look at the previous example you see
179\type {\noalign}. When the preamble is read, \TEX\ will pick up rows till it
180finds the final brace. Each row is added to a temporary list and the \type
181{\noalign} will enter a mode where other stuff gets added to that list. It all
182involves subtle look ahead but with minimal overhead. When the whole alignment is
183collected a final pass over that list will package the cells and rows (lines) in
184the appropriate way using information collected (like the maximum width of a cell
185and width of the current cell. It will also deal with spanning cells then.
186
187So let's summarize what happens:
188
189\startitemize[n,packed]
190\startitem
191    scan the preamble that defines the cells (where the last one is repeated
192    when needed)
193\stopitem
194\startitem
195    check for \type {\cr}, \type {\noalign} or a right brace; when a row is
196    entered scan for cells in parallel the preamble so that cell specifications
197    can be applied (then start again)
198\stopitem
199\startitem
200    package the preamble based on information with regards to the cells in
201    a column
202\stopitem
203\startitem
204    apply the preamble packaging information to the columns and also deal with
205    pending cell spans
206\stopitem
207\startitem
208    flush the result to the current list, unless packages in a box a \type
209    {\halign} is seen as paragraph and rows as lines (such a table can split)
210\stopitem
211\stopitemize
212
213The second (repeated) step is complicated by the fact that the scanner has to
214look ahead for a \type {\noalign}, \type {\cr}, \type {\omit} or \type {\span}
215and when doing that it has to expand what comes. This can give side effects and
216often results in obscure error messages. When for instance an \type {\if} is seen
217and expanded, the wrong branch can be entered. And when you use protected macros
218embedded alignment commands are not seen at all; of course they still need to
219produce valid operations in the current context.
220
221All these side effects are to be handled in a macro package when it wraps
222alignments in a high level interface and \CONTEXT\ does that for you. But because
223the code doesn't always look pretty then, in \LUAMETATEX\ the alignment mechanism
224has been extended a bit over time.
225
226Nesting \type {\noalign} is normally not permitted (but one can redefine this
227primitive such that a macro package nevertheless handles it). The first extension
228permits nested usage of \type {\noalign}. This has resulted of a little
229reorganization of the code. A next extension showed up when overload protection
230was introduced and extra prefixes were added. We can signal the scanner that a
231macro is actually a \type {\noalign} variant: \footnote {One can argue for using
232the name \type {\peekaligned} because in the meantime other alignment primitives
233also can use this property.}
234
235\starttyping[option=TEX]
236\noaligned\protected\def\InBetween{\noalign{...}}
237\stoptyping
238
239Here the \type {\InBetween} macro will get the same treatment as \type {\noalign}
240and it will not trigger an error. This extension resulted in a second bit of
241reorganization (think of internal command codes and such) but still the original
242processing of alignments was there.
243
244A third overhaul of the code actually did lead to some adaptations in the way
245alignments are constructed so let's move on to that.
246
247\stopsectionlevel
248
249\startsectionlevel[title={Pre-, inter- and post-tab skips}]
250
251The basic structure of a preamble and row is actually not that complex: it is
252a mix of tab skip glue and cells (that are just boxes):
253
254\startbuffer
255\tabskip 10pt
256\halign {
257  \strut\alignmark\tabskip 12pt\aligntab
258  \strut\alignmark\tabskip 14pt\aligntab
259  \strut\alignmark\tabskip 16pt\cr
260  \noalign{\hrule}
261  cell 1.1\aligntab cell 1.2\aligntab cell 1.3\cr
262  \noalign{\hrule}
263  cell 2.1\aligntab cell 2.2\aligntab cell 2.3\cr
264  \noalign{\hrule}
265}
266\stopbuffer
267
268\typebuffer[option=TEX]
269
270The tab skips are set in advance and apply to the next cell (or after the last
271one).
272
273\startbuffer[blownup-1]
274\startlinecorrection
275{\showmakeup[glue]\scale[width=\textwidth]{\vbox{\getbuffer}}}
276\stoplinecorrection
277\stopbuffer
278
279\getbuffer[blownup-1]
280
281% \normalizelinemode \zerocount % \discardzerotabskipsnormalizecode
282
283In the \CONTEXT\ table mechanisms the value of \type {\tabskip} is zero
284in most cases. As in:
285
286\startbuffer
287\tabskip 0pt
288\halign {
289  \strut\alignmark\aligntab
290  \strut\alignmark\aligntab
291  \strut\alignmark\cr
292  \noalign{\hrule}
293  cell 1.1\aligntab cell 1.2\aligntab cell 1.3\cr
294  \noalign{\hrule}
295  cell 2.1\aligntab cell 2.2\aligntab cell 2.3\cr
296  \noalign{\hrule}
297}
298\stopbuffer
299
300\typebuffer[option=TEX]
301
302When these ships are zero, they still show up in the end:
303
304\getbuffer[blownup-1]
305
306Normally, in order to achieve certain effects there will be more align entries in
307the preamble than cells in the table, for instance because you want vertical
308lines between cells. When these are not used, you can get quite a bit of empty
309boxes and zero skips. Now, of course this is seldom a problem, but when you have
310a test document where you want to show font properties in a table and that font
311supports a script with some ten thousand glyphs, you can imagine that it
312accumulates and in \LUATEX\ (and \LUAMETATEX) nodes are larger so it is one of
313these cases where in \CONTEXT\ we get messages on the console that node memory is
314bumped. \footnote {I suppose it was a coincidence that a few weeks after these
315features came available a user consulted the mailing list about a few thousand
316page table that made the engine run out of memory, something that could be cured
317by enabling these new features.}
318
319After playing a bit with stripping zero tab skips I found that the code would not
320really benefit from such a feature: lots of extra tests made it quite ugly. As a
321result a first alternative was to just strip zero skips before an alignment got
322flushed. At least we're then a bit leaner in the processes that come after it.
323This feature is now available as one of the normalizer bits.
324
325But, as we moved on, a more natural approach was to keep the skips in the
326preamble, because that is where a guaranteed alternating skip|/|box is assumed.
327It also makes that the original documentation is still valid. However, in the
328rows construction we can be lean. This is driven by a keyword to \type {\halign}:
329
330\startbuffer
331\tabskip 0pt
332\halign noskips {
333  \strut\alignmark\aligntab
334  \strut\alignmark\aligntab
335  \strut\alignmark\cr
336  \noalign{\hrule}
337  cell 1.1\aligntab cell 1.2\aligntab cell 1.3\cr
338  \noalign{\hrule}
339  cell 2.1\aligntab cell 2.2\aligntab cell 2.3\cr
340  \noalign{\hrule}
341}
342\stopbuffer
343
344\typebuffer[option=TEX]
345
346No zero tab skips show up here:
347
348\getbuffer[blownup-1]
349
350When playing with all this the \LUAMETATEX\ engine also got a tracing option for
351alignments. We already had one that showed some of the \type{\noalign} side
352effects, but showing the preamble was not yet there. This is what \typ
353{\tracingalignments = 2} results in:
354
355% {\tracingalignments2 \setbox0\vbox{\getbuffer}}
356
357\starttyping[option=TEX]
358<preamble>
359\glue[ignored][...] 0.0pt
360\alignrecord
361..{\strut }
362..<content>
363..{\endtemplate }
364\glue[ignored][...] 0.0pt
365\alignrecord
366..{\strut }
367..<content>
368..{\endtemplate }
369\glue[ignored][...] 0.0pt
370\alignrecord
371..{\strut }
372..<content>
373..{\endtemplate }
374\glue[ignored][...] 0.0pt
375\stoptyping
376
377The \type {ignored} subtype is (currently) only used for these alignment tab
378skips and it triggers a check later on when the rows are constructed. The \type
379{<content>} is what get injected in the cell (represented by \type {\alignmark}).
380The pseudo primitives are internal and not public.
381
382\stopsectionlevel
383
384\startsectionlevel[title={Cell widths}]
385
386Imagine this:
387
388\startbuffer
389\halign {
390  x\hbox to 3cm{\strut    \alignmark\hss}\aligntab
391  x\hbox to 3cm{\strut\hss\alignmark\hss}\aligntab
392  x\hbox to 3cm{\strut\hss\alignmark    }\cr
393  cell 1.1\aligntab cell 1.2\aligntab cell 1.3\cr
394  cell 2.1\aligntab cell 2.2\aligntab cell 2.3\cr
395}
396\stopbuffer
397
398\typebuffer[option=TEX]
399
400which renders as:
401
402\startbuffer[blownup-2]
403\startlinecorrection
404{\showboxes\scale[width=\textwidth]{\vbox{\getbuffer}}}
405\stoplinecorrection
406\stopbuffer
407
408{\showboxes\getbuffer[blownup-2]}
409
410A reason to have boxes here is that it enforces a cell width but that is done at
411the cost of an extra wrapper. In \LUAMETATEX\ the \type {hlist} nodes are rather
412large because we have more options than in original \TEX, for instance offsets
413and orientation. In a table with 10K rows of 4 cells yet get 40K extra \type
414{hlist} nodes allocated. Now, one can argue that we have plenty of memory but
415being lazy is not really a sign of proper programming.
416
417\startbuffer
418\halign {
419  x\tabsize 3cm\strut    \alignmark\hss\aligntab
420  x\tabsize 3cm\strut\hss\alignmark\aligntab
421  x\tabsize 3cm\strut\hss\alignmark\hss\cr
422  cell 1.1\aligntab cell 1.2\aligntab cell 1.3\cr
423  cell 2.1\aligntab cell 2.2\aligntab cell 2.3\cr
424}
425\stopbuffer
426
427\typebuffer[option=TEX]
428
429If you look carefully you will see that this time we don't have the embedded
430boxes:
431
432{\showboxes\getbuffer[blownup-2]}
433
434So, both the sparse skip and new \type {\tabsize} feature help to make these
435extreme tables (spanning hundreds of pages) not consume irrelevant memory and
436also make that later on we don't have to consult useless nodes.
437
438\stopsectionlevel
439
440\startsectionlevel[title=Plugins]
441
442Yet another \LUAMETATEX\ extension is a callback that kicks in between the
443preamble preroll and finalizing the alignment. Initially as test and
444demonstration a basic character alignment feature was written but that works so
445well that in some places it can replace (or compliment) the already existing
446features in the \CONTEXT\ table mechanisms.
447
448\startbuffer
449\starttabulate[|lG{.}|cG{,}|rG{=}|cG{x}|]
450\NC 1.1     \NC 2,2     \NC 3=3     \NC a 0xFF   \NC \NR
451\NC 11.11   \NC 22,22   \NC 33=33   \NC b 0xFFF  \NC \NR
452\NC 111.111 \NC 222,222 \NC 333=333 \NC c 0xFFFF \NC \NR
453\stoptabulate
454\stopbuffer
455
456\typebuffer[option=TEX]
457
458The tabulate mechanism in \CONTEXT\ is rather old and stable and it is the
459preferred way to deal with tabular content in the text flow. However, adding the
460\type {G} specifier (as variant of the \type {g} one) could be done without
461interference or drop in performance. This new \type {G} specifier tells the
462tabulate mechanism that in that column the given character is used to vertically
463align the content that has this character.
464
465\blank\getbuffer\blank
466
467Let's make clear that this is {\em not} an engine feature but a \CONTEXT\ one. It
468is however made easy by this callback mechanism. We can of course use this feature
469with the low level alignment primitives, assuming that you tell the machinery that
470the plugin is to be kicked in.
471
472\startbuffer
473\halign noskips \alignmentcharactertrigger \bgroup
474    \tabskip2em
475        \setalignmentcharacter.\ignorespaces\alignmark\unskip\hss \aligntab
476    \hss\setalignmentcharacter,\ignorespaces\alignmark\unskip\hss \aligntab
477    \hss\setalignmentcharacter=\ignorespaces\alignmark\unskip     \aligntab
478    \hss                       \ignorespaces\alignmark\unskip\hss \cr
479      1.1   \aligntab   2,2   \aligntab   3=3   \aligntab \setalignmentcharacter{.}\relax 4.4\cr
480     11.11  \aligntab  22,22  \aligntab  33=33  \aligntab \setalignmentcharacter{,}\relax 44,44\cr
481    111.111 \aligntab 222,222 \aligntab 333=333 \aligntab \setalignmentcharacter{!}\relax 444!444\cr
482        x   \aligntab     x   \aligntab     x   \aligntab \setalignmentcharacter{/}\relax /\cr
483       .1   \aligntab    ,2   \aligntab    =3   \aligntab \setalignmentcharacter{?}\relax ?4\cr
484       .111 \aligntab    ,222 \aligntab    =333 \aligntab \setalignmentcharacter{=}\relax 44=444\cr
485\egroup
486\stopbuffer
487
488{\switchtobodyfont[8pt] \typebuffer[option=TEX]}
489
490This rather verbose setup renders as:
491
492\blank\getbuffer\blank
493
494Using a high level interface makes sense but local control over such alignment too, so
495here follow some more examples. Here we use different alignment characters:
496
497\startbuffer
498\starttabulate[|lG{.}|cG{,}|rG{=}|cG{x}|]
499\NC 1.1     \NC 2,2     \NC 3=3     \NC a 0xFF   \NC \NR
500\NC 11.11   \NC 22,22   \NC 33=33   \NC b 0xFFF  \NC \NR
501\NC 111.111 \NC 222,222 \NC 333=333 \NC c 0xFFFF \NC \NR
502\stoptabulate
503\stopbuffer
504
505\typebuffer[option=TEX] \getbuffer
506
507In this example we specify the characters in the cells. We still need to add a
508specifier in the preamble definition because that will trigger the plugin.
509
510\startbuffer
511\starttabulate[|lG{}|rG{}|]
512\NC left                                         \NC right                            \NC\NR
513\NC \showglyphs \setalignmentcharacter{.}1.1     \NC \setalignmentcharacter{.}1.1     \NC\NR
514\NC \showglyphs \setalignmentcharacter{,}11,11   \NC \setalignmentcharacter{,}11,11   \NC\NR
515\NC \showglyphs \setalignmentcharacter{=}111=111 \NC \setalignmentcharacter{=}111=111 \NC\NR
516\stoptabulate
517\stopbuffer
518
519{\switchtobodyfont[8pt] \typebuffer[option=TEX]} \getbuffer
520
521You can mix these approaches:
522
523\startbuffer
524\starttabulate[|lG{.}|rG{}|]
525\NC left    \NC right                            \NC\NR
526\NC 1.1     \NC \setalignmentcharacter{.}1.1     \NC\NR
527\NC 11.11   \NC \setalignmentcharacter{.}11.11   \NC\NR
528\NC 111.111 \NC \setalignmentcharacter{.}111.111 \NC\NR
529\stoptabulate
530\stopbuffer
531
532\typebuffer[option=TEX] \getbuffer
533
534Here the already present alignment feature, that at some point in tabulate might
535use this new feature, is meant for numbers, but here we can go wild with words,
536although of course you need to keep in mind that we deal with typeset text, so
537there may be no match.
538
539\startbuffer
540\starttabulate[|lG{.}|rG{.}|]
541\NC foo.bar \NC foo.bar \NC \NR
542\NC  oo.ba  \NC  oo.ba  \NC \NR
543\NC   o.b   \NC   o.b   \NC \NR
544\stoptabulate
545\stopbuffer
546
547\typebuffer[option=TEX] \getbuffer
548
549This feature will only be used in know situations and those seldom involve advanced
550typesetting. However, the following does work: \footnote {Should this be an option
551instead?}
552
553\startbuffer
554\starttabulate[|cG{d}|]
555\NC \smallcaps abcdefgh \NC \NR
556\NC              xdy    \NC \NR
557\NC \sl          xdy    \NC \NR
558\NC \tttf        xdy    \NC \NR
559\NC \tfd          d     \NC \NR
560\stoptabulate
561\stopbuffer
562
563\typebuffer[option=TEX] \getbuffer
564
565As always with such mechanisms, the question is \quotation {Where to stop?} But it
566makes for nice demos and as long as little code is needed it doesn't hurt.
567
568\stopsectionlevel
569
570\startsectionlevel[title=Pitfalls and tricks]
571
572The next example mixes bidirectional typesetting. It might look weird at first
573sight but the result conforms to what we discussed in previous paragraphs.
574
575\startbuffer
576\starttabulate[|lG{.}|lG{}|]
577\NC \righttoleft 1.1   \NC \righttoleft \setalignmentcharacter{.}1.1   \NC\NR
578\NC              1.1   \NC              \setalignmentcharacter{.}1.1   \NC\NR
579\NC \righttoleft 1.11  \NC \righttoleft \setalignmentcharacter{.}1.11  \NC\NR
580\NC              1.11  \NC              \setalignmentcharacter{.}1.11  \NC\NR
581\NC \righttoleft 1.111 \NC \righttoleft \setalignmentcharacter{.}1.111 \NC\NR
582\NC              1.111 \NC              \setalignmentcharacter{.}1.111 \NC\NR
583\stoptabulate
584\stopbuffer
585
586{\switchtobodyfont[8pt] \typebuffer[option=TEX]} \getbuffer
587
588In case of doubt, look at this:
589
590\startbuffer
591\starttabulate[|lG{.}|lG{}|lG{.}|lG{}|]
592\NC \righttoleft 1.1   \NC \righttoleft \setalignmentcharacter{.}1.1   \NC
593                 1.1   \NC              \setalignmentcharacter{.}1.1   \NC\NR
594\NC \righttoleft 1.11  \NC \righttoleft \setalignmentcharacter{.}1.11  \NC
595                 1.11  \NC              \setalignmentcharacter{.}1.11  \NC\NR
596\NC \righttoleft 1.111 \NC \righttoleft \setalignmentcharacter{.}1.111 \NC
597                 1.111 \NC              \setalignmentcharacter{.}1.111 \NC\NR
598\stoptabulate
599\stopbuffer
600
601{\switchtobodyfont[8pt] \typebuffer[option=TEX]} \getbuffer
602
603The next example shows the effect of \type {\omit} and \type {\span}. The first one
604makes that in this cell the preamble template is ignored.
605
606\startbuffer
607\halign \bgroup
608    \tabsize 2cm\relax     [\alignmark]\hss \aligntab
609    \tabsize 2cm\relax \hss[\alignmark]\hss \aligntab
610    \tabsize 2cm\relax \hss[\alignmark]\cr
611           1\aligntab       2\aligntab       3\cr
612     \omit 1\aligntab \omit 2\aligntab \omit 3\cr
613           1\aligntab       2\span           3\cr
614           1\span           2\aligntab       3\cr
615           1\span           2\span           3\cr
616           1\span \omit     2\span \omit     3\cr
617     \omit 1\span \omit     2\span \omit     3\cr
618\egroup
619\stopbuffer
620
621\typebuffer[option=TEX]
622
623Spans are applied at the end so you see a mix of templates applied.
624
625{\showboxes\getbuffer[blownup-2]}
626
627When you define an alignment inside a macro, you need to duplicate the \type {\alignmark}
628signals. This is similar to embedded macro definitions. But in \LUAMETATEX\ we can get
629around that by using \type {\aligncontent}. Keep in mind that when the preamble is scanned there
630is no doesn't expand with the exception of the token after \type {\span}.
631
632\startbuffer
633\halign \bgroup
634    \tabsize 2cm\relax     \aligncontent\hss \aligntab
635    \tabsize 2cm\relax \hss\aligncontent\hss \aligntab
636    \tabsize 2cm\relax \hss\aligncontent\cr
637    1\aligntab 2\aligntab 3\cr
638    A\aligntab B\aligntab C\cr
639\egroup
640\stopbuffer
641
642\typebuffer[option=TEX]
643
644\blank\getbuffer\blank
645
646In this example we still have to be verbose in the way we align but we can do this:
647
648\startbuffer
649\halign \bgroup
650    \tabsize 2cm\relax \aligncontentleft  \aligntab
651    \tabsize 2cm\relax \aligncontentmiddle\aligntab
652    \tabsize 2cm\relax \aligncontentright \cr
653    1\aligntab 2\aligntab 3\cr
654    A\aligntab B\aligntab C\cr
655\egroup
656\stopbuffer
657
658\typebuffer[option=TEX]
659
660Where the helpers are defined as:
661
662\starttyping[option=TEX]
663\noaligned\protected\def\aligncontentleft
664  {\ignorespaces\aligncontent\unskip\hss}
665
666\noaligned\protected\def\aligncontentmiddle
667  {\hss\ignorespaces\aligncontent\unskip\hss}
668
669\noaligned\protected\def\aligncontentright
670  {\hss\ignorespaces\aligncontent\unskip}
671\stoptyping
672
673The preamble scanner see such macros as candidates for a single level expansion
674so it will inject the meaning and see the \type {\aligncontent} eventually.
675
676\blank\getbuffer\blank
677
678The same effect could be achieved by using the \type {\span} prefix:
679
680\starttyping[option=TEX]
681\def\aligncontentleft{\ignorespaces\aligncontent\unskip\hss}
682
683\halign { ... \span\aligncontentleft ...}
684\stoptyping
685
686One of the reasons for not directly using the low level \type {\halign} command is
687that it's a lot of work but by providing a set of helpers like here might change
688that a bit. Keep in mind that much of the above is not new in the sense that we
689could not achieve the same already, it's just a bit programmer friendly.
690
691\stopsectionlevel
692
693\startsectionlevel[title=Rows]
694
695Alignment support is what the documented source calls \quote {interwoven}. When
696the engine scans for input it processing text, math or alignment content. While
697doing alignments it collects rows, and inside these cells but also deals with
698material that ends up in between. In \LUAMETATEX\ I tried to isolate the bits and
699pieces as good as possible but it remains \ complicated (for all good reasons).
700Cells as well as rows are finalized after the whole alignment has been collected
701and processed. In the end cells and rows are boxes but till we're done they are
702in an \quote {unset} state.
703
704Scanning starts with interpreting the preamble, and then grabbing rows. There is
705some nasty lookahead involved for \type {\noalign}, \type {\span}, \type {\omit},
706\type {\cr} and \type {\crcr} and that is not code one wants to tweak too much
707(although we did in \LUAMETATEX). This means for instance that adding \quote
708{let's start a row here} primitive is sort of tricky (but it might happen some
709day) which in turn means that it is not really possible to set row properties. As
710an experiment we can set some properties now by hijacking \type {\noalign} and
711storing them on the alignment stack (indeed: at the cost of some extra overhead
712and memory). This permits the following:
713
714% \theorientation{down} "002
715
716\startbuffer
717\halign {
718    \hss
719    \ignorespaces \alignmark \removeunwantedspaces
720    \hss
721    \quad \aligntab \quad
722    \hss
723    \ignorespaces \alignmark \removeunwantedspaces
724    \hss
725    \cr
726    \noalign xoffset 40pt {}
727    {\darkred   cell one}   \aligntab {\darkgray cell one}   \cr
728    \noalign orientation "002 {}
729    {\darkgreen cell one}   \aligntab {\darkblue cell one}   \cr
730    \noalign xoffset 40pt {}
731    {\darkred   cell two}   \aligntab {\darkgray cell two}   \cr
732    \noalign orientation "002 {}
733    {\darkgreen cell two}   \aligntab {\darkblue cell two}   \cr
734    \noalign xoffset 40pt {}
735    {\darkred   cell three} \aligntab {\darkgray cell three} \cr
736    \noalign orientation "002 {}
737    {\darkgreen cell three} \aligntab {\darkblue cell three} \cr
738    \noalign xoffset 40pt {}
739    {\darkred   cell four}  \aligntab {\darkgray cell four}  \cr
740    \noalign orientation "002 {}
741    {\darkgreen cell four}  \aligntab {\darkblue cell four}  \cr
742}
743\stopbuffer
744
745\typebuffer[option=TEX]
746
747\startlinecorrection
748\showmakeup[line]
749\ruledvbox{\getbuffer}
750\stoplinecorrection
751
752The supported keywords are similar to those for boxes: \type {source}, \type
753{target}, \type {anchor}, \type {orientation}, \type {shift}, \type {xoffset},
754\type {yoffset}, \type {xmove} and \type {ymove}. The dimensions can be prefixed
755by \type {add} and \type {reset} wipes all. Here is another example:
756
757\startbuffer
758\halign {
759    \hss
760    \ignorespaces \alignmark \removeunwantedspaces
761    \hss
762    \quad \aligntab \quad
763    \hss
764    \ignorespaces \alignmark \removeunwantedspaces
765    \hss
766    \cr
767    \noalign xmove 40pt {}
768    {\darkred   cell one}   \aligntab {\darkgray cell one}   \cr
769    {\darkgreen cell one}   \aligntab {\darkblue cell one}   \cr
770    \noalign xmove 20pt {}
771    {\darkred   cell two}   \aligntab {\darkgray cell two}   \cr
772    {\darkgreen cell two}   \aligntab {\darkblue cell two}   \cr
773    \noalign xmove 40pt {}
774    {\darkred   cell three} \aligntab {\darkgray cell three} \cr
775    {\darkgreen cell three} \aligntab {\darkblue cell three} \cr
776    \noalign xmove 20pt {}
777    {\darkred   cell four}  \aligntab {\darkgray cell four}  \cr
778    {\darkgreen cell four}  \aligntab {\darkblue cell four}  \cr
779}
780\stopbuffer
781
782\typebuffer[option=TEX]
783
784\startlinecorrection
785\showmakeup[line]
786\ruledvbox{\getbuffer}
787\stoplinecorrection
788
789Some more features might be added in the future as is it an interesting
790playground. It is to be seen how this ends up in \CONTEXT\ high level interfaces
791like tabulate.
792
793\stopsectionlevel
794
795\startsectionlevel[title=Remark]
796
797It can be that the way alignments are interfaced with respect to attributes is a bit
798different between \LUATEX\ and \LUAMETATEX\ but because the former is frozen (in
799order not to interfere with current usage patterns) this is something that we will
800deal with deep down in \CONTEXT\ \LMTX.
801
802In principle we can have hooks into the rows for pre and post material but it
803doesn't really pay of as grouping will still interfere. So for now I decided not
804to add these.
805
806\stopsectionlevel
807
808\stopdocument
809
810% \hbox \bgroup
811%     \vbox \bgroup \halign \bgroup
812%         \hss\aligncontent\hss\aligntab
813%         \hss\aligncontent\hss\cr
814%         aaaa\aligntab bbbb\cr
815%         aaa\aligntab bbb\cr
816%         aa\aligntab bb\cr
817%         a\aligntab b\cr
818%         \omit\span \hss ccc\hss\cr
819%     \egroup \egroup
820%     \quad
821%     \vbox \bgroup \halign noskips \bgroup
822%         \hss\aligncontent\hss\aligntab
823%         \hss\aligncontent\hss\cr
824%         aaaa\aligntab bbbb\cr
825%         aaa\aligntab bbb\cr
826%         aa\aligntab bb\cr
827%         a\aligntab b\cr
828%         \omit\span \hss ccc\hss\cr
829%     \egroup \egroup
830% \egroup
831