summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/lowlevel/lowlevel-alignments.tex
blob: 1b8bc65522731097ccc9080e6d60c19351a53abe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
% language=us runpath=texruns:manuals/lowlevel

\startcomponent lowlevel-alignments

\environment lowlevel-style

\startdocument
  [title=alignments,
   color=middlegreen]

\startsectionlevel[title=Introduction]

\TEX\ has a couple of subsystems and alignments is one of them. This mechanism is
used to construct tables or alike. Because alignments use low level primitives to
set up and construct a table, and because such a setup can be rather extensive, in
most cases users will rely on macros that hide this.

\startbuffer
\halign {
        \alignmark\hss \aligntab
    \hss\alignmark\hss \aligntab
    \hss\alignmark     \cr
    1.1     \aligntab 2,2     \aligntab 3=3     \cr
    11.11   \aligntab 22,22   \aligntab 33=33   \cr
    111.111 \aligntab 222,222 \aligntab 333=333 \cr
}
\stopbuffer

\typebuffer[option=TEX]

That one doesn't look too complex and comes out as:

\blank\getbuffer\blank

This is how the previous code comes out when we use one of the \CONTEXT\ table
mechanism.

\startbuffer
\starttabulate[|l|c|r|]
  \NC 1.1     \NC 2,2     \NC 3=3     \NC \NR
  \NC 11.11   \NC 22,22   \NC 33=33   \NC \NR
  \NC 111.111 \NC 222,222 \NC 333=333 \NC \NR
\stoptabulate
\stopbuffer

\typebuffer[option=TEX]

\blank\getbuffer\blank

That one looks a bit different with respect to spaces, so let's go back to the
low level variant:

\startbuffer
\halign {
        \alignmark\hss \aligntab
    \hss\alignmark\hss \aligntab
    \hss\alignmark     \cr
  1.1\aligntab     2,2\aligntab     3=3\cr
  11.11\aligntab   22,22\aligntab   33=33\cr
  111.111\aligntab 222,222\aligntab 333=333\cr
}
\stopbuffer

\typebuffer[option=TEX]

Here we don't have spaces in the content part and therefore also no spaces in the
result:

\blank\getbuffer\blank

You can automate dealing with unwanted spacing:

\startbuffer
\halign {
      \ignorespaces\alignmark\unskip\hss \aligntab
  \hss\ignorespaces\alignmark\unskip\hss \aligntab
  \hss\ignorespaces\alignmark\unskip     \cr
  1.1     \aligntab 2,2     \aligntab 3=3     \cr
  11.11   \aligntab 22,22   \aligntab 33=33   \cr
  111.111 \aligntab 222,222 \aligntab 333=333 \cr
}
\stopbuffer

\typebuffer[option=TEX]

We get:

\blank\getbuffer\blank

By moving the space skipping and cleanup to the so called preamble we don't need
to deal with it in the content part. We can also deal with inter|-|column spacing
there:

\startbuffer
\halign {
      \ignorespaces\alignmark\unskip\hss \tabskip 1em \aligntab
  \hss\ignorespaces\alignmark\unskip\hss \tabskip 1em \aligntab
  \hss\ignorespaces\alignmark\unskip     \tabskip 0pt \cr
  1.1     \aligntab 2,2     \aligntab 3=3     \cr
  11.11   \aligntab 22,22   \aligntab 33=33   \cr
  111.111 \aligntab 222,222 \aligntab 333=333 \cr
}
\stopbuffer

\typebuffer[option=TEX]

\blank\getbuffer\blank

If for the moment we forget about spanning columns (\type {\span}) and locally
ignoring preamble entries (\type {\omit}) these basic commands are not that
complex to deal with. Here we use \type {\alignmark} but that is just a primitive
that we use instead of \type {#} while \type {\aligntab} is the same as \type
{&}, but using the characters instead also assumes that they have the catcode
that relates to a parameter and alignment tab (and in \CONTEXT\ that is not the
case). The \TEX book has plenty alignment examples so if you really want to learn
about them, consult that must|-|have|-|book.

\stopsectionlevel

\startsectionlevel[title=Between the lines]

The individual rows of a horizontal alignment are treated as lines. This means that,
as we see in the previous section, the interline spacing is okay. However, that also
means that when we mix the lines with rules, the normal \TEX\ habits kick in. Take
this:

\startbuffer
\halign {
      \ignorespaces\alignmark\unskip\hss \tabskip 1em \aligntab
  \hss\ignorespaces\alignmark\unskip\hss \tabskip 1em \aligntab
  \hss\ignorespaces\alignmark\unskip     \tabskip 0pt \cr
  \noalign{\hrule}
  1.1     \aligntab 2,2     \aligntab 3=3     \cr
  \noalign{\hrule}
  11.11   \aligntab 22,22   \aligntab 33=33   \cr
  \noalign{\hrule}
  111.111 \aligntab 222,222 \aligntab 333=333 \cr
  \noalign{\hrule}
}
\stopbuffer

\typebuffer[option=TEX]

The result doesn't look pretty and actually, when you see documents produced by
\TEX\ using alignments you should not be surprised to notice rather ugly spacing.
The user (or the macropackage) should deal with that explicitly, and this is not
always the case.

\startlinecorrection
\getbuffer
\stoplinecorrection

The solution is often easy:

\startbuffer
\halign {
      \ignorespaces\strut\alignmark\unskip\hss \tabskip 1em \aligntab
  \hss\ignorespaces\strut\alignmark\unskip\hss \tabskip 1em \aligntab
  \hss\ignorespaces\strut\alignmark\unskip     \tabskip 0pt \cr
  \noalign{\hrule}
  1.1     \aligntab 2,2     \aligntab 3=3     \cr
  \noalign{\hrule}
  11.11   \aligntab 22,22   \aligntab 33=33   \cr
  \noalign{\hrule}
  111.111 \aligntab 222,222 \aligntab 333=333 \cr
  \noalign{\hrule}
}
\stopbuffer

\typebuffer[option=TEX]

\startlinecorrection
\getbuffer
\stoplinecorrection

The user will not notice it but alignments put some pressure on the general \TEX\
scanner. Actually, the scanner is either scanning an alignment or it expects
regular text (including math). When you look at the previous example you see
\type {\noalign}. When the preamble is read, \TEX\ will pick up rows till it
finds the final brace. Each row is added to a temporary list and the \type
{\noalign} will enter a mode where other stuff gets added to that list. It all
involves subtle look ahead but with minimal overhead. When the whole alignment is
collected a final pass over that list will package the cells and rows (lines) in
the appropriate way using information collected (like the maximum width of a cell
and width of the current cell. It will also deal with spanning cells then.

So let's summarize what happens:

\startitemize[n,packed]
\startitem
    scan the preamble that defines the cells (where the last one is repeated
    when needed)
\stopitem
\startitem
    check for \type {\cr}, \type {\noalign} or a right brace; when a row is
    entered scan for cells in parallel the preamble so that cell specifications
    can be applied (then start again)
\stopitem
\startitem
    package the preamble based on information with regards to the cells in
    a column
\stopitem
\startitem
    apply the preamble packaging information to the columns and also deal with
    pending cell spans
\stopitem
\startitem
    flush the result to the current list, unless packages in a box a \type
    {\halign} is seen as paragraph and rows as lines (such a table can split)
\stopitem
\stopitemize

The second (repeated) step is complicated by the fact that the scanner has to
look ahead for a \type {\noalign}, \type {\cr}, \type {\omit} or \type {\span}
and when doing that it has to expand what comes. This can give side effects and
often results in obscure error messages. When for instance an \type {\if} is seen
and expanded, the wrong branch can be entered. And when you use protected macros
embedded alignment commands are not seen at all; of course they still need to
produce valid operations in the current context.

All these side effects are to be handled in a macro package when it wraps
alignments in a high level interface and \CONTEXT\ does that for you. But because
the code doesn't always look pretty then, in \LUAMETATEX\ the alignment mechanism
has been extended a bit over time.

Nesting \type {\noalign} is normally not permitted (but one can redefine this
primitive such that a macro package nevertheless handles it). The first extension
permits nested usage of \type {\noalign}. This has resulted of a little
reorganization of the code. A next extension showed up when overload protection
was introduced and extra prefixes were added. We can signal the scanner that a
macro is actually a \type {\noalign} variant: \footnote {One can argue for using
the name \type {\peekaligned} because in the meantime other alignment primitives
also can use this property.}

\starttyping[option=TEX]
\noaligned\protected\def\InBetween{\noalign{...}}
\stoptyping

Here the \type {\InBetween} macro will get the same treatment as \type {\noalign}
and it will not trigger an error. This extension resulted in a second bit of
reorganization (think of internal command codes and such) but still the original
processing of alignments was there.

A third overhaul of the code actually did lead to some adaptations in the way
alignments are constructed so let's move on to that.

\stopsectionlevel

\startsectionlevel[title={Pre-, inter- and post-tab skips}]

The basic structure of a preamble and row is actually not that complex: it is
a mix of tab skip glue and cells (that are just boxes):

\startbuffer
\tabskip 10pt
\halign {
  \strut\alignmark\tabskip 12pt\aligntab
  \strut\alignmark\tabskip 14pt\aligntab
  \strut\alignmark\tabskip 16pt\cr
  \noalign{\hrule}
  cell 1.1\aligntab cell 1.2\aligntab cell 1.3\cr
  \noalign{\hrule}
  cell 2.1\aligntab cell 2.2\aligntab cell 2.3\cr
  \noalign{\hrule}
}
\stopbuffer

\typebuffer[option=TEX]

The tab skips are set in advance and apply to the next cell (or after the last
one).

\startbuffer[blownup-1]
\startlinecorrection
{\showmakeup[glue]\scale[width=\textwidth]{\vbox{\getbuffer}}}
\stoplinecorrection
\stopbuffer

\getbuffer[blownup-1]

% \normalizelinemode \zerocount % \discardzerotabskipsnormalizecode

In the \CONTEXT\ table mechanisms the value of \type {\tabskip} is zero
in most cases. As in:

\startbuffer
\tabskip 0pt
\halign {
  \strut\alignmark\aligntab
  \strut\alignmark\aligntab
  \strut\alignmark\cr
  \noalign{\hrule}
  cell 1.1\aligntab cell 1.2\aligntab cell 1.3\cr
  \noalign{\hrule}
  cell 2.1\aligntab cell 2.2\aligntab cell 2.3\cr
  \noalign{\hrule}
}
\stopbuffer

\typebuffer[option=TEX]

When these ships are zero, they still show up in the end:

\getbuffer[blownup-1]

Normally, in order to achieve certain effects there will be more align entries in
the preamble than cells in the table, for instance because you want vertical
lines between cells. When these are not used, you can get quite a bit of empty
boxes and zero skips. Now, of course this is seldom a problem, but when you have
a test document where you want to show font properties in a table and that font
supports a script with some ten thousand glyphs, you can imagine that it
accumulates and in \LUATEX\ (and \LUAMETATEX) nodes are larger so it is one of
these cases where in \CONTEXT\ we get messages on the console that node memory is
bumped. \footnote {I suppose it was a coincidence that a few weeks after these
features came available a user consulted the mailing list about a few thousand
page table that made the engine run out of memory, something that could be cured
by enabling these new features.}

After playing a bit with stripping zero tab skips I found that the code would not
really benefit from such a feature: lots of extra tests made it quite ugly. As a
result a first alternative was to just strip zero skips before an alignment got
flushed. At least we're then a bit leaner in the processes that come after it.
This feature is now available as one of the normalizer bits.

But, as we moved on, a more natural approach was to keep the skips in the
preamble, because that is where a guaranteed alternating skip|/|box is assumed.
It also makes that the original documentation is still valid. However, in the
rows construction we can be lean. This is driven by a keyword to \type {\halign}:

\startbuffer
\tabskip 0pt
\halign noskips {
  \strut\alignmark\aligntab
  \strut\alignmark\aligntab
  \strut\alignmark\cr
  \noalign{\hrule}
  cell 1.1\aligntab cell 1.2\aligntab cell 1.3\cr
  \noalign{\hrule}
  cell 2.1\aligntab cell 2.2\aligntab cell 2.3\cr
  \noalign{\hrule}
}
\stopbuffer

\typebuffer[option=TEX]

No zero tab skips show up here:

\getbuffer[blownup-1]

When playing with all this the \LUAMETATEX\ engine also got a tracing option for
alignments. We already had one that showed some of the \type{\noalign} side
effects, but showing the preamble was not yet there. This is what \typ
{\tracingalignments = 2} results in:

% {\tracingalignments2 \setbox0\vbox{\getbuffer}}

\starttyping[option=TEX]
<preamble>
\glue[ignored][...] 0.0pt
\alignrecord
..{\strut }
..<content>
..{\endtemplate }
\glue[ignored][...] 0.0pt
\alignrecord
..{\strut }
..<content>
..{\endtemplate }
\glue[ignored][...] 0.0pt
\alignrecord
..{\strut }
..<content>
..{\endtemplate }
\glue[ignored][...] 0.0pt
\stoptyping

The \type {ignored} subtype is (currently) only used for these alignment tab
skips and it triggers a check later on when the rows are constructed. The \type
{<content>} is what get injected in the cell (represented by \type {\alignmark}).
The pseudo primitives are internal and not public.

\stopsectionlevel

\startsectionlevel[title={Cell widths}]

Imagine this:

\startbuffer
\halign {
  x\hbox to 3cm{\strut    \alignmark\hss}\aligntab
  x\hbox to 3cm{\strut\hss\alignmark\hss}\aligntab
  x\hbox to 3cm{\strut\hss\alignmark    }\cr
  cell 1.1\aligntab cell 1.2\aligntab cell 1.3\cr
  cell 2.1\aligntab cell 2.2\aligntab cell 2.3\cr
}
\stopbuffer

\typebuffer[option=TEX]

which renders as:

\startbuffer[blownup-2]
\startlinecorrection
{\showboxes\scale[width=\textwidth]{\vbox{\getbuffer}}}
\stoplinecorrection
\stopbuffer

{\showboxes\getbuffer[blownup-2]}

A reason to have boxes here is that it enforces a cell width but that is done at
the cost of an extra wrapper. In \LUAMETATEX\ the \type {hlist} nodes are rather
large because we have more options than in original \TEX, for instance offsets
and orientation. In a table with 10K rows of 4 cells yet get 40K extra \type
{hlist} nodes allocated. Now, one can argue that we have plenty of memory but
being lazy is not really a sign of proper programming.

\startbuffer
\halign {
  x\tabsize 3cm\strut    \alignmark\hss\aligntab
  x\tabsize 3cm\strut\hss\alignmark\aligntab
  x\tabsize 3cm\strut\hss\alignmark\hss\cr
  cell 1.1\aligntab cell 1.2\aligntab cell 1.3\cr
  cell 2.1\aligntab cell 2.2\aligntab cell 2.3\cr
}
\stopbuffer

\typebuffer[option=TEX]

If you look carefully you will see that this time we don't have the embedded
boxes:

{\showboxes\getbuffer[blownup-2]}

So, both the sparse skip and new \type {\tabsize} feature help to make these
extreme tables (spanning hundreds of pages) not consume irrelevant memory and
also make that later on we don't have to consult useless nodes.

\stopsectionlevel

\startsectionlevel[title=Plugins]

Yet another \LUAMETATEX\ extension is a callback that kicks in between the
preamble preroll and finalizing the alignment. Initially as test and
demonstration a basic character alignment feature was written but that works so
well that in some places it can replace (or compliment) the already existing
features in the \CONTEXT\ table mechanisms.

\startbuffer
\starttabulate[|lG{.}|cG{,}|rG{=}|cG{x}|]
\NC 1.1     \NC 2,2     \NC 3=3     \NC a 0xFF   \NC \NR
\NC 11.11   \NC 22,22   \NC 33=33   \NC b 0xFFF  \NC \NR
\NC 111.111 \NC 222,222 \NC 333=333 \NC c 0xFFFF \NC \NR
\stoptabulate
\stopbuffer

\typebuffer[option=TEX]

The tabulate mechanism in \CONTEXT\ is rather old and stable and it is the
preferred way to deal with tabular content in the text flow. However, adding the
\type {G} specifier (as variant of the \type {g} one) could be done without
interference or drop in performance. This new \type {G} specifier tells the
tabulate mechanism that in that column the given character is used to vertically
align the content that has this character.

\blank\getbuffer\blank

Let's make clear that this is {\em not} an engine feature but a \CONTEXT\ one. It
is however made easy by this callback mechanism. We can of course use this feature
with the low level alignment primitives, assuming that you tell the machinery that
the plugin is to be kicked in.

\startbuffer
\halign noskips \alignmentcharactertrigger \bgroup
    \tabskip2em
        \setalignmentcharacter.\ignorespaces\alignmark\unskip\hss \aligntab
    \hss\setalignmentcharacter,\ignorespaces\alignmark\unskip\hss \aligntab
    \hss\setalignmentcharacter=\ignorespaces\alignmark\unskip     \aligntab
    \hss                       \ignorespaces\alignmark\unskip\hss \cr
      1.1   \aligntab   2,2   \aligntab   3=3   \aligntab \setalignmentcharacter{.}\relax 4.4\cr
     11.11  \aligntab  22,22  \aligntab  33=33  \aligntab \setalignmentcharacter{,}\relax 44,44\cr
    111.111 \aligntab 222,222 \aligntab 333=333 \aligntab \setalignmentcharacter{!}\relax 444!444\cr
        x   \aligntab     x   \aligntab     x   \aligntab \setalignmentcharacter{/}\relax /\cr
       .1   \aligntab    ,2   \aligntab    =3   \aligntab \setalignmentcharacter{?}\relax ?4\cr
       .111 \aligntab    ,222 \aligntab    =333 \aligntab \setalignmentcharacter{=}\relax 44=444\cr
\egroup
\stopbuffer

{\switchtobodyfont[8pt] \typebuffer[option=TEX]}

This rather verbose setup renders as:

\blank\getbuffer\blank

Using a high level interface makes sense but local control over such alignment too, so
here follow some more examples. Here we use different alignment characters:

\startbuffer
\starttabulate[|lG{.}|cG{,}|rG{=}|cG{x}|]
\NC 1.1     \NC 2,2     \NC 3=3     \NC a 0xFF   \NC \NR
\NC 11.11   \NC 22,22   \NC 33=33   \NC b 0xFFF  \NC \NR
\NC 111.111 \NC 222,222 \NC 333=333 \NC c 0xFFFF \NC \NR
\stoptabulate
\stopbuffer

\typebuffer[option=TEX] \getbuffer

In this example we specify the characters in the cells. We still need to add a
specifier in the preamble definition because that will trigger the plugin.

\startbuffer
\starttabulate[|lG{}|rG{}|]
\NC left                                         \NC right                            \NC\NR
\NC \showglyphs \setalignmentcharacter{.}1.1     \NC \setalignmentcharacter{.}1.1     \NC\NR
\NC \showglyphs \setalignmentcharacter{,}11,11   \NC \setalignmentcharacter{,}11,11   \NC\NR
\NC \showglyphs \setalignmentcharacter{=}111=111 \NC \setalignmentcharacter{=}111=111 \NC\NR
\stoptabulate
\stopbuffer

{\switchtobodyfont[8pt] \typebuffer[option=TEX]} \getbuffer

You can mix these approaches:

\startbuffer
\starttabulate[|lG{.}|rG{}|]
\NC left    \NC right                            \NC\NR
\NC 1.1     \NC \setalignmentcharacter{.}1.1     \NC\NR
\NC 11.11   \NC \setalignmentcharacter{.}11.11   \NC\NR
\NC 111.111 \NC \setalignmentcharacter{.}111.111 \NC\NR
\stoptabulate
\stopbuffer

\typebuffer[option=TEX] \getbuffer

Here the already present alignment feature, that at some point in tabulate might
use this new feature, is meant for numbers, but here we can go wild with words,
although of course you need to keep in mind that we deal with typeset text, so
there may be no match.

\startbuffer
\starttabulate[|lG{.}|rG{.}|]
\NC foo.bar \NC foo.bar \NC \NR
\NC  oo.ba  \NC  oo.ba  \NC \NR
\NC   o.b   \NC   o.b   \NC \NR
\stoptabulate
\stopbuffer

\typebuffer[option=TEX] \getbuffer

This feature will only be used in know situations and those seldom involve advanced
typesetting. However, the following does work: \footnote {Should this be an option
instead?}

\startbuffer
\starttabulate[|cG{d}|]
\NC \smallcaps abcdefgh \NC \NR
\NC              xdy    \NC \NR
\NC \sl          xdy    \NC \NR
\NC \tttf        xdy    \NC \NR
\NC \tfd          d     \NC \NR
\stoptabulate
\stopbuffer

\typebuffer[option=TEX] \getbuffer

As always with such mechanisms, the question is \quotation {Where to stop?} But it
makes for nice demos and as long as little code is needed it doesn't hurt.

\stopsectionlevel

\startsectionlevel[title=Pitfalls and tricks]

The next example mixes bidirectional typesetting. It might look weird at first
sight but the result conforms to what we discussed in previous paragraphs.

\startbuffer
\starttabulate[|lG{.}|lG{}|]
\NC \righttoleft 1.1   \NC \righttoleft \setalignmentcharacter{.}1.1   \NC\NR
\NC              1.1   \NC              \setalignmentcharacter{.}1.1   \NC\NR
\NC \righttoleft 1.11  \NC \righttoleft \setalignmentcharacter{.}1.11  \NC\NR
\NC              1.11  \NC              \setalignmentcharacter{.}1.11  \NC\NR
\NC \righttoleft 1.111 \NC \righttoleft \setalignmentcharacter{.}1.111 \NC\NR
\NC              1.111 \NC              \setalignmentcharacter{.}1.111 \NC\NR
\stoptabulate
\stopbuffer

{\switchtobodyfont[8pt] \typebuffer[option=TEX]} \getbuffer

In case of doubt, look at this:

\startbuffer
\starttabulate[|lG{.}|lG{}|lG{.}|lG{}|]
\NC \righttoleft 1.1   \NC \righttoleft \setalignmentcharacter{.}1.1   \NC
                 1.1   \NC              \setalignmentcharacter{.}1.1   \NC\NR
\NC \righttoleft 1.11  \NC \righttoleft \setalignmentcharacter{.}1.11  \NC
                 1.11  \NC              \setalignmentcharacter{.}1.11  \NC\NR
\NC \righttoleft 1.111 \NC \righttoleft \setalignmentcharacter{.}1.111 \NC
                 1.111 \NC              \setalignmentcharacter{.}1.111 \NC\NR
\stoptabulate
\stopbuffer

{\switchtobodyfont[8pt] \typebuffer[option=TEX]} \getbuffer

The next example shows the effect of \type {\omit} and \type {\span}. The first one
makes that in this cell the preamble template is ignored.

\startbuffer
\halign \bgroup
    \tabsize 2cm\relax     [\alignmark]\hss \aligntab
    \tabsize 2cm\relax \hss[\alignmark]\hss \aligntab
    \tabsize 2cm\relax \hss[\alignmark]\cr
           1\aligntab       2\aligntab       3\cr
     \omit 1\aligntab \omit 2\aligntab \omit 3\cr
           1\aligntab       2\span           3\cr
           1\span           2\aligntab       3\cr
           1\span           2\span           3\cr
           1\span \omit     2\span \omit     3\cr
     \omit 1\span \omit     2\span \omit     3\cr
\egroup
\stopbuffer

\typebuffer[option=TEX]

Spans are applied at the end so you see a mix of templates applied.

{\showboxes\getbuffer[blownup-2]}

When you define an alignment inside a macro, you need to duplicate the \type {\alignmark}
signals. This is similar to embedded macro definitions. But in \LUAMETATEX\ we can get
around that by using \type {\aligncontent}. Keep in mind that when the preamble is scanned there
is no doesn't expand with the exception of the token after \type {\span}.

\startbuffer
\halign \bgroup
    \tabsize 2cm\relax     \aligncontent\hss \aligntab
    \tabsize 2cm\relax \hss\aligncontent\hss \aligntab
    \tabsize 2cm\relax \hss\aligncontent\cr
    1\aligntab 2\aligntab 3\cr
    A\aligntab B\aligntab C\cr
\egroup
\stopbuffer

\typebuffer[option=TEX]

\blank\getbuffer\blank

In this example we still have to be verbose in the way we align but we can do this:

\startbuffer
\halign \bgroup
    \tabsize 2cm\relax \aligncontentleft  \aligntab
    \tabsize 2cm\relax \aligncontentmiddle\aligntab
    \tabsize 2cm\relax \aligncontentright \cr
    1\aligntab 2\aligntab 3\cr
    A\aligntab B\aligntab C\cr
\egroup
\stopbuffer

\typebuffer[option=TEX]

Where the helpers are defined as:

\starttyping[option=TEX]
\noaligned\protected\def\aligncontentleft
  {\ignorespaces\aligncontent\unskip\hss}

\noaligned\protected\def\aligncontentmiddle
  {\hss\ignorespaces\aligncontent\unskip\hss}

\noaligned\protected\def\aligncontentright
  {\hss\ignorespaces\aligncontent\unskip}
\stoptyping

The preamble scanner see such macros as candidates for a single level expansion
so it will inject the meaning and see the \type {\aligncontent} eventually.

\blank\getbuffer\blank

The same effect could be achieved by using the \type {\span} prefix:

\starttyping[option=TEX]
\def\aligncontentleft{\ignorespaces\aligncontent\unskip\hss}

\halign { ... \span\aligncontentleft ...}
\stoptyping

One of the reasons for not directly using the low level \type {\halign} command is
that it's a lot of work but by providing a set of helpers like here might change
that a bit. Keep in mind that much of the above is not new in the sense that we
could not achieve the same already, it's just a bit programmer friendly.

\stopsectionlevel

\startsectionlevel[title=Remark]

It can be that the way alignments are interfaced with respect to attributes is a bit
different between \LUATEX\ and \LUAMETATEX\ but because the former is frozen (in
order not to interfere with current usage patterns) this is something that we will
deal with deep down in \CONTEXT\ \LMTX.

In principle we can have hooks into the rows for pre and post material but it
doesn't really pay of as grouping will still interfere. So for now I decided not
to add these.

\stopsectionlevel

\stopdocument

% \hbox \bgroup
%     \vbox \bgroup \halign \bgroup
%         \hss\aligncontent\hss\aligntab
%         \hss\aligncontent\hss\cr
%         aaaa\aligntab bbbb\cr
%         aaa\aligntab bbb\cr
%         aa\aligntab bb\cr
%         a\aligntab b\cr
%         \omit\span \hss ccc\hss\cr
%     \egroup \egroup
%     \quad
%     \vbox \bgroup \halign noskips \bgroup
%         \hss\aligncontent\hss\aligntab
%         \hss\aligncontent\hss\cr
%         aaaa\aligntab bbbb\cr
%         aaa\aligntab bbb\cr
%         aa\aligntab bb\cr
%         a\aligntab b\cr
%         \omit\span \hss ccc\hss\cr
%     \egroup \egroup
% \egroup