1if not modules then modules = { } end modules ['node-ali'] = {
2 version = 1.001,
3 comment = "companion to node-ini.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11local aligncharacter_code = 0x1
12local mathalign_code = 0x2
13local mathmatrix_code = 0x4
14local alignskip_code = 0x8
15
16local setmetatableindex = table.setmetatableindex
17
18local nuts = nodes.nuts
19local tonut = nuts.tonut
20local tonode = nuts.tonode
21local getwidth = nuts.getwidth
22local setwidth = nuts.setwidth
23local getid = nuts.getid
24
25local getattr = nuts.getattr
26local setnext = nuts.setnext
27local getnext = nuts.getnext
28local getprev = nuts.getprev
29local getboth = nuts.getboth
30local getglue = nuts.getglue
31local setglue = nuts.setglue
32local getwhd = nuts.getwhd
33local gettotal = nuts.gettotal
34local setpenalty = nuts.setpenalty
35local getlist = nuts.getlist
36local setlist = nuts.setlist
37local getleader = nuts.getleader
38local setattrlist = nuts.setattrlist
39local setprop = nuts.setprop
40local getprop = nuts.getprop
41local getfont = nuts.getfont
42local getchar = nuts.getchar
43local addmargins = nuts.addmargins
44local findtail = nuts.tail
45local hasglyph = nuts.hasglyph
46local getwordrange = nuts.getwordrange
47local dimensions = nuts.rangedimensions
48local flushnode = nuts.flush
49local hpack = nuts.hpack
50local repack = nuts.repack
51local insertbefore = nuts.insertbefore
52local insertafter = nuts.insertafter
53local replacenode = nuts.replace
54local effectiveglue = nuts.effectiveglue
55
56local newkern = nuts.pool.kern
57local newrule = nuts.pool.rule
58local newglue = nuts.pool.glue
59
60local traversers = nuts.traversers
61local nextrecord = traversers.alignrecord
62local nextunset = traversers.unset
63local nextglyph = traversers.glyph
64local nextglue = traversers.glue
65local nextpenalty = traversers.penalty
66local nextboundary = traversers.boundary
67local nextnode = traversers.node
68local nextlist = traversers.list
69local nextrule = traversers.rule
70
71local nodecodes = nodes.nodecodes
72local hlist_code <const> = nodecodes.hlist
73local glyph_code <const> = nodecodes.glyph
74local glue_code <const> = nodecodes.glue
75local kern_code <const> = nodecodes.kern
76local disc_code <const> = nodecodes.disc
77local unset_code <const> = nodecodes.unset
78local alignrecord_code <const> = nodecodes.alignrecord
79local rule_code <const> = nodecodes.rule
80local temp_code <const> = nodecodes.temp
81
82local spaceskip_code <const> = nodes.gluecodes.spaceskip
83local xspaceskip_code <const> = nodes.gluecodes.xspaceskip
84local intermathskip_code <const> = nodes.gluecodes.intermathskip
85local fontkern_code <const> = nodes.kerncodes.fontkern
86local row_code <const> = nodes.listcodes.alignment
87local cell_code <const> = nodes.listcodes.cell
88local line_code <const> = nodes.listcodes.line
89local linepenalty_code <const> = nodes.penaltycodes.linepenalty
90local linebreakpenalty_code <const> = nodes.penaltycodes.linebreakpenalty
91
92
93
94
95
96
97
98do
99
100
101 local a_alignchar <const> = attributes.private("aligncharacter")
102
103 local method = 2
104 local unislots = fonts.hashes.unislots
105 local chardata = fonts.hashes.characters
106
107 function nodes.handlers.aligncharacter(head,where,callback,attr,preamble)
108 if (callback & aligncharacter_code == 0) then
109
110 elseif where == "preroll" then
111 local attr = getattr(attr,a_alignchar)
112 if attr then
113 local widths = { }
114 local data = { }
115 local rows = 0
116 local cols = 0
117 for col in nextrecord, preamble do
118 cols = cols + 1
119 local w, s = getwidth(col,true)
120 widths[cols] = { col, w, s }
121 end
122
123 for row in nextunset, head do
124 rows = rows + 1
125 local c = 0
126 local d = { }
127 data[rows] = d
128 for col in nextunset, getlist(row) do
129 c = c + 1
130 if widths[c][2] then
131 local list = getlist(col)
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 local middle = nil
148
149 for g, char, font in nextglyph, list do
150 local unicode = getattr(g,a_alignchar)
151 if unicode then
152 if char == unicode then
153 middle = g
154 elseif unislots[font][char] == unicode then
155 middle = g
156 end
157 end
158 end
159 if middle then
160 local left, right = getwordrange(middle)
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181 d[c] = { col, left, middle, right, 0, 0, getwidth(middle) }
182 else
183 d[c] = false
184 end
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 else
207 d[c] = false
208 end
209 end
210 end
211
212 for col=1,cols do
213 local maxl = 0
214 local maxr = 0
215 local minm = 0
216 local maxm = 0
217 local colw = widths[col]
218 for row=1,rows do
219 local d = data[row][col]
220 if d then
221 local p = d[1]
222 local l = d[2]
223 local m = d[3]
224 local r = d[4]
225 if m then
226 local lw = l == m and 0 or dimensions(p,l,m)
227 local rw = m == r and 0 or dimensions(p,getnext(m),getnext(r))
228 d[5] = lw
229 d[6] = rw
230 if lw > maxl then
231 maxl = lw
232 end
233 if rw > maxr then
234 maxr = rw
235 end
236 local mw = d[7]
237 if maxm == 0 then
238 minm = mw
239 maxm = mw
240 else
241 if mw > maxm then
242 maxm = mw
243 end
244 if mw < minm then
245 minm = mw
246 end
247 end
248 end
249 end
250 end
251
252 local fixedwidth = colw[3] ~= 0
253
254 local old = colw[2]
255 local new = old
256 for row=1,rows do
257 local d = data[row][col]
258 if d then
259 local p = d[1]
260 local l = d[2]
261 local m = d[3]
262 local r = d[4]
263 if l and m and r then
264 local lw = d[5]
265 local rw = d[6]
266 local mw = d[7]
267 dl = maxl - lw
268 dr = maxr - rw
269 if dl ~= 0 or dr ~= 0 or mw ~= maxm then
270 local lst = getlist(p)
271 local wid = getwidth(p)
272 if dl ~= 0 then
273 local k = newkern(dl)
274 lst = insertbefore(lst,l,k)
275 setattrlist(k,m)
276 setlist(p,lst)
277 wid = wid + dl
278 end
279 if dr ~= 0 then
280 local k = newkern(dr)
281 insertafter(lst,r,k)
282 setattrlist(k,m)
283 wid = wid + dr
284 end
285 if mw ~= maxm then
286 local dw = (maxm - mw)
287 local dx = dw / 2
288 addmargins(m,-dx,-dx)
289 wid = wid + dw
290 end
291 setwidth(p,wid)
292 if wid > new then
293 new = wid
294 end
295 setlist(p,lst)
296
297 if fixedwidth then
298 local l = hpack(h,getwidth(p),"exactly")
299 setglue(p,getglue(l))
300 setlist(l)
301 flushnode(l)
302 else
303 setglue(p)
304 end
305
306 end
307 end
308 end
309 end
310 if new > old then
311 if fixedwidth then
312
313 else
314 setwidth(colw[1],new)
315 end
316 end
317 end
318 end
319 end
320 end
321
322 local enabled = false
323
324 interfaces.implement {
325 name = "enablealignmentcharacter",
326
327 public = true,
328 protected = true,
329 actions = function()
330 if not enabled then
331 nodes.tasks.enableaction("alignments","nodes.handlers.aligncharacter")
332 enabled = true
333 end
334 end,
335 }
336
337end
338
339
340
341do
342
343 local getdata = nuts.getdata
344 local removenode = nuts.remove
345
346 local getheight = nuts.getheight
347 local getdepth = nuts.getdepth
348 local setheight = nuts.setheight
349 local setdepth = nuts.setdepth
350 local getglue = nuts.getglue
351 local setoffsets = nuts.setoffsets
352 local setsubtype = nuts.setsubtype
353
354 local baselineskip_code <const> = nodes.gluecodes.baselineskip
355 local lineskip_code <const> = nodes.gluecodes.lineskip
356
357 local alignrecord_code <const> = nodecodes.alignrecord
358 local hlist_code <const> = nodecodes.hlist
359 local unset_code <const> = nodecodes.unset
360
361
362 local nextnode = nuts.traversers.node
363
364 local texgetdimen = tex.getdimen
365 local texsetdimen = tex.setdimen
366 local texgetglue = tex.getglue
367 local texget = tex.get
368
369 local leftmarker <const> = tex.boundaries.system("c_math_align_l_marker")
370 local rightmarker <const> = tex.boundaries.system("c_math_align_r_marker")
371
372 local a_location <const> = attributes.system("mathnumberlocation")
373 local a_threshold <const> = attributes.system("mathnumberthreshold")
374
375 local v_first <const> = interfaces.variables.first
376 local v_last <const> = interfaces.variables.last
377 local v_both <const> = interfaces.variables.both
378
379
380
381 local function openup(specification,head)
382 local inbetween = specification.inbetween or 0
383 local height = specification.height or 0
384 local depth = specification.depth or 0
385 local lines = { }
386 for n, id, subtype, list in nextlist, head do
387 lines[#lines+1] = { n, subtype, getwhd(n) }
388 end
389 local noflines = #lines
390 if noflines > 0 then
391 local currentline = 1
392 for n, subtype in nextglue, head do
393
394
395
396 if subtype == baselineskip_code or subtype == lineskip_code then
397 local nextline = currentline + 1
398 local amount, stretch, shrink = getglue(n)
399
400 local prevdp = lines[currentline][5]
401 local nextht = lines[nextline][4]
402
403 local delta = 0
404 if prevdp < depth then
405 setdepth(lines[currentline][1],depth)
406 delta = delta + (depth - prevdp)
407
408 end
409 if nextht < height then
410 setheight(lines[nextline][1],height)
411
412 delta = delta + (height - nextht)
413 end
414
415
416 setsubtype(n,baselineskip_code)
417
418 setglue(n,amount+inbetween-delta,stretch,shrink)
419
420 currentline = nextline
421
422
423
424 end
425 end
426 local firstht = lines[1][4]
427 local lastdp = lines[noflines][5]
428 if firstht < height then
429 setheight(lines[1],height)
430 end
431 if lastdp < depth then
432 setdepth(lines[noflines],depth)
433 end
434 end
435 end
436
437 nuts.openup = openup
438
439
440
441
442
443
444
445
446
447
448
449
450
451 local totals = { }
452 local widths = { }
453 local records = { }
454 local deltas = { }
455 local cellwidths = { }
456
457 local a_flushleft <const> = 1
458 local a_centered <const> = 2
459 local a_flushright <const> = 3
460
461 local a_numberright <const> = 1
462 local a_numberleft <const> = 2
463
464 local function first_pass(head,callback,attr,preamble,signal)
465
466 local width = 0
467 local hsize = texget("hsize")
468 local count = 0
469 local overflow = false
470 totals = { }
471 widths = { }
472 records = { }
473 deltas = { }
474 for n in nextrecord, preamble do
475 local wd = getwidth(n)
476 count = count + 1
477 width = width + wd
478 totals [count] = width
479 widths [count] = wd
480 records[count] = n
481 deltas [count] = 0
482 end
483
484 local lindex = 0
485 local rindex = 0
486 local lwidth = 0
487 local rwidth = 0
488 local centered = false
489
490 for row in nextunset, head do
491 local count = 0
492 local anchor = nil
493 local rochan = nil
494
495 for cell in nextunset, getlist(row) do
496 local list = getlist(cell)
497 count = count + 1
498 cellwidths[count] = getwidth(cell)
499 for bound in nextboundary, list do
500 local marker = getdata(bound)
501 if marker == leftmarker then
502 lindex = count
503 anchor = bound
504 rochan = list
505 elseif marker == rightmarker then
506 local n = getnext(bound)
507 if n and getid(n) == hlist_code then
508 local wd, ht, dp = getwhd(n)
509 local lc = getattr(n,a_location)
510 if lc then
511
512
513
514 local packed = (lc >> 8) & 0xF
515 local align = (lc >> 4) & 0xF
516 local location = (lc ) & 0xF
517 local threshold = getattr(n,a_threshold)
518 if location == a_numberright then
519
520 local m = 1
521 local s = align == a_centered and 2 or 1
522 if align == a_flushleft then
523 rwidth = wd
524 elseif align == a_flushright then
525 rwidth = wd
526 elseif wd > lwidth then
527 lwidth = wd
528 rwidth = wd
529 centered = true
530 end
531 if packed > 0 then
532 setprop(n,"mathalignshift","right")
533 if packed == 2 then
534 lwidth = 0
535 else
536 lwidth = 0
537 rwidth = 0
538 end
539 end
540 if totals[count-2] + cellwidths[count-1] + s*wd - s*threshold > hsize then
541 local total = ht + dp
542 setdepth(row,getdepth(row) + total)
543 setoffsets(n,0,-total)
544 local pr = records[count-1]
545 local cw = getwidth(pr)
546 if cw - wd > deltas[count-1] then
547 deltas[count-1] = cw - wd
548 end
549 overflow = true
550 end
551 elseif location == a_numberleft then
552 if align == a_flushleft then
553 lwidth = wd
554 elseif align == a_flushright then
555 lwidth = wd
556 end
557 if signal == 0x80 then
558 lwidth = wd
559 end
560 if packed > 0 then
561 setprop(n,"mathalignshift","left")
562 if packed == 2 then
563 rwidth = 0
564 else
565 lwidth = 0
566 rwidth = 0
567 end
568 end
569 end
570 if location == a_numberleft and anchor then
571 local l, l, n = removenode(list,n)
572 if l ~= list then
573 setlist(cell,l)
574
575 end
576 if signal == 0x80 then
577 setwidth(cell,lwidth)
578 end
579 insertafter(rochan,anchor,n)
580 end
581 end
582 end
583 rindex = count
584 end
585 end
586 end
587 end
588
589 if overflow then
590 if deltas[rindex-1] ~= 0 then
591 setwidth(records[rindex-1],deltas[rindex-1])
592 end
593 end
594
595 for count=1,#records do
596 if count == lindex then
597 if centered and overflow then
598 lwidth = lwidth - texgetdimen("d_math_eqalign_number_distance")
599 end
600 setwidth(records[count],lwidth)
601 elseif count == rindex then
602 setwidth(records[count],rwidth)
603 end
604 end
605 end
606
607 local function second_pass(head,callback,attr,preamble,signal)
608 local done = setmetatableindex("table")
609 local glues = { }
610 local okay = false
611 for row, id, subtype in nextlist, head do
612 if id == hlist_code and subtype == row_code then
613 for cell, id, subtype in nextlist, getlist(row) do
614 if id == hlist_code and subtype == cell_code then
615 for n, s in nextglue, getlist(cell) do
616 if s == intermathskip_code then
617 local e = effectiveglue(n,cell)
618 local g = getglue(n)
619 local f = getfont(n)
620 local a = done[f]
621 local d = a[g]
622 glues[n] = g
623 if not d then
624 a[g] = e
625 elseif d > e then
626 a[g] = e
627 okay = true
628 end
629 end
630 end
631 end
632 end
633 end
634 end
635 if okay then
636 for k, v in next, glues do
637 local g = done[getfont(k)][v]
638 if g then
639 setglue(k,g)
640 setprop(k,"fixedmathalign",true)
641 end
642 end
643 for row, id, subtype in nextlist, head do
644 if id == hlist_code and subtype == row_code then
645 for cell, id, subtype, list in nextlist, getlist(row) do
646 if list and id == hlist_code and subtype == cell_code then
647 local wd = getwidth(cell)
648 repack(cell,wd,"exactly")
649 end
650 end
651 end
652 end
653 end
654 end
655
656 local function third_pass(head,callback,attr,preamble,signal)
657 local inbetween, stretch, shrink = texgetglue("s_strc_math_alignment_inbetween")
658 openup({ inbetween = inbetween }, head)
659 end
660
661
662
663
664
665 function nodes.handlers.mathalignrelocate(head,where,callback,attr,preamble)
666 if (callback & mathalign_code == 0) then
667
668 elseif where == "preroll" then
669 local signal = getattr(attr,a_location)
670 if signal == 0x20 or signal == 0x40 or signal == 0x80 then
671 first_pass(head,callback,attr,preamble,signal)
672 end
673 elseif where == "wrapup" then
674 local signal = getattr(attr,a_location)
675 if signal == 0x40 or signal == 0x80 then
676 second_pass(head,callback,attr,preamble,signal)
677 end
678 if signal then
679 third_pass(head,callback,attr,preamble,signal)
680 end
681 end
682 end
683
684do
685
686 local a_mathalignmentvrule <const> = attributes.private("mathalignmentvrule")
687 local a_mathalignmenthrule <const> = attributes.private("mathalignmenthrule")
688 local a_mathalignmenttop <const> = attributes.private("mathalignmenttop")
689 local a_mathalignmentmid <const> = attributes.private("mathalignmentmid")
690 local a_mathalignmentbot <const> = attributes.private("mathalignmentbot")
691
692 local function hrule_pass(head,attr,preamble)
693 local i = 0
694 for row, id, subtype, list in nextlist, head do
695 if id == hlist_code and subtype == row_code then
696 local height = 0
697 local depth = 0
698 local done = false
699 for cell, id, subtype, list in nextlist, list do
700 if list then
701
702 for n, id, subtype in nextglue, list do
703
704
705 local rule = getleader(n)
706 if rule then
707 local signal = getattr(rule,a_mathalignmenthrule)
708 if signal then
709 local w, h, d = getwhd(n)
710 if h and d then
711 if h > height then
712 height = h
713 end
714 if d > depth then
715 depth = d
716 end
717 done = true
718 end
719 end
720 end
721 end
722 end
723 end
724 if done then
725 setheight(row,height)
726 setdepth(row,depth)
727 end
728 end
729 end
730 end
731
732
733
734
735
736 local force_height <const> = 2
737
738 local force_depth <const> = 4
739
740 local function vrule_pass(head,attr,preamble)
741 for row, id, subtype, list in nextlist, head do
742 if id == hlist_code and subtype == row_code then
743 local prv, nxt = getboth(row)
744 for cell, id, subtype, list in nextlist, list do
745 if list then
746
747 local d = false
748 local h = false
749 for n, id, subtype in nextrule, list do
750 local signal = getattr(n,a_mathalignmentvrule)
751 if signal then
752
753 if not d then
754 if prv then
755 local a = getattr(prv,a_mathalignmentvrule)
756
757 if a == force_depth then
758 local p = prv
759 while p do
760 a = getattr(p,a_mathalignmentvrule)
761 if not a then
762 break
763 elseif a == force_height then
764 if not getprev(p) or getid(getprev(p)) == temp_code then
765 local h = getattr(p,a_mathalignmenttop) or 0
766 nuts.setheight(p,h)
767 end
768 break
769 else
770 p = getprev(p)
771 end
772 end
773 else
774 prv = nil
775 end
776
777
778
779 end
780 if nxt then
781 local a = getattr(nxt,a_mathalignmentvrule)
782
783 if a == force_height then
784 local p = nxt
785 while p do
786 a = getattr(p,a_mathalignmentvrule)
787 if not a then
788 break
789 elseif a == force_depth then
790 if not getnext(p) then
791 local d = getattr(p,a_mathalignmentbot) or 0
792 nuts.setdepth(p,d)
793 end
794 break
795 else
796 p = getnext(p)
797 end
798 end
799 else
800 nxt = nil
801 end
802
803
804
805 end
806 d = prv and -getdepth (prv) or 0
807 h = nxt and -getheight(nxt) or 0
808 d = d - (getattr(prv,a_mathalignmentmid) or 0)
809 end
810 setoffsets(n,nil,nil,d,h)
811 end
812 end
813 end
814 end
815 end
816 end
817 end
818
819 function nodes.handlers.mathmatrixrules(head,where,callback,attr,preamble)
820 if (callback & mathmatrix_code == 0) then
821
822 elseif where == "wrapup" then
823 hrule_pass(head,attr,preamble)
824 vrule_pass(head,attr,preamble)
825 end
826 end
827
828 local enabled = false
829
830 interfaces.implement {
831 name = "enablematrixrules",
832
833 public = true,
834 protected = true,
835 actions = function()
836 if not enabled then
837 nodes.tasks.enableaction("alignments","nodes.handlers.mathmatrixrules")
838 enabled = true
839 end
840 end,
841 }
842
843end
844
845
846
847 local a_ornament <const> = attributes.system("mathmatrixornament")
848
849 local leftornament <const> = tex.boundaries.system("c_math_matrix_ornament_l")
850 local rightornament <const> = tex.boundaries.system("c_math_matrix_ornament_r")
851 local topornament <const> = tex.boundaries.system("c_math_matrix_ornament_t")
852 local bottomornament <const> = tex.boundaries.system("c_math_matrix_ornament_b")
853
854 local verticalline <const> = tex.boundaries.system("c_math_matrix_vl_boundary")
855
856 local left = 0
857 local right = 0
858 local nofcells = 0
859 local found = false
860
861 local lefts = false
862 local rights = false
863 local tops = false
864 local bottoms = false
865
866 local function first_pass(head,callback,attr,preamble,signal)
867 nofcells = 0
868 left = 0
869 right = 0
870 found = false
871 lefts = { }
872 rights = { }
873 tops = { }
874 bottoms = { }
875 for n in nextrecord, preamble do
876 nofcells = nofcells + 1
877 end
878 local cells = { }
879 for row in nextunset, head do
880 local c = 0
881 for cell in nextunset, getlist(row) do
882 local list = getlist(cell)
883 c = c + 1
884 for bound in nextboundary, list do
885 local ornament = getdata(bound)
886
887
888
889
890
891 if ornament == leftornament then
892 if c == 1 then
893 local w = getwidth(cell)
894 if w > left then
895 left = w
896 end
897 setwidth(cell,0)
898 cells[c+1] = true
899 cells[c] = true
900 found = true
901 lefts[#lefts+1] = cell
902 end
903 elseif ornament == rightornament then
904 if c == nofcells then
905 local w = getwidth(cell)
906 if w > right then
907 right = w
908 end
909 setwidth(cell,0)
910 cells[c-1] = true
911 cells[c] = true
912 found = true
913 rights[#rights+1] = cell
914 end
915 elseif ornament == topornament then
916 setheight(row,0)
917 setdepth(row,0)
918 found = true
919 tops[#tops+1] = cell
920 elseif ornament == bottomornament then
921 setheight(row,0)
922 setdepth(row,0)
923 found = true
924 bottoms[#bottoms+1] = cell
925 end
926 end
927 end
928 end
929 if next(cells) then
930 local c = 0
931 for n in nextrecord, preamble do
932 c = c + 1
933 if cells[c] then
934 setwidth(n)
935 end
936 end
937 end
938 end
939
940 local function second_pass(box,callback,attr,preamble,signal)
941 if found then
942 local head = getlist(nuts.getbox(box))
943 local leftmargin = texgetdimen("d_math_matrix_margin_l")
944 local rightmargin = texgetdimen("d_math_matrix_margin_r")
945 local topmargin = texgetdimen("d_math_matrix_margin_t")
946 local bottommargin = texgetdimen("d_math_matrix_margin_b")
947 for i=1,#lefts do
948 setoffsets(lefts[i],-(left+leftmargin),0)
949 end
950 for i=1,#rights do
951 setoffsets(rights[i],rightmargin,0)
952 end
953 for i=1,#tops do
954 setoffsets(tops[i],0,topmargin)
955 end
956 for i=1,#bottoms do
957 setoffsets(bottoms[i],0,-bottommargin)
958 end
959 found = false
960 lefts = false
961 rights = false
962 tops = false
963 bottoms = false
964 texsetdimen("global","d_math_matrix_max_left", left)
965 texsetdimen("global","d_math_matrix_max_right",right)
966 end
967 end
968
969 function nodes.handlers.mathmatrixornaments(head,where,callback,attr,preamble)
970 if (callback & mathmatrix_code == 0) then
971
972 elseif where == "preroll" then
973 first_pass(head,callback,attr,preamble,signal)
974
975
976 end
977 end
978
979 interfaces.implement {
980 name = "shiftmatrixornaments",
981 actions = second_pass,
982 arguments = "integer",
983 }
984
985 local enabled = false
986
987 interfaces.implement {
988 name = "enablemathalignrelocate",
989
990 public = true,
991 protected = true,
992 actions = function()
993 if not enabled then
994 nodes.tasks.enableaction("alignments","nodes.handlers.mathalignrelocate")
995 enabled = true
996 end
997 end,
998 }
999
1000 local enabled = false
1001
1002 interfaces.implement {
1003 name = "enablematrixornaments",
1004
1005 public = true,
1006 protected = true,
1007 actions = function()
1008 if not enabled then
1009 nodes.tasks.enableaction("alignments","nodes.handlers.mathmatrixornaments")
1010 enabled = true
1011 end
1012 end,
1013 }
1014
1015end
1016
1017
1018
1019local report = logs.reporter("alignment","preamble")
1020local trace trackers.register("alignments.showstates",function(v) trace = v end)
1021
1022function nodes.handlers.showpreamble(head,where,callback,attr,preamble)
1023 if trace then
1024 local c = 0
1025 for n, id in nextnode, preamble do
1026 if id == unset_code or id == alignrecord_code then
1027 c = c + 1
1028 report("stage %a, cell %i, width %p",where,c,getwidth(n))
1029 elseif id == glue_code then
1030 report("stage %a, tabskip %s",where,node.direct.gluetostring(n))
1031 else
1032 report("stage %a, node %a",where,nodecodes[id])
1033 end
1034 end
1035 end
1036end
1037
1038
1039
1040do
1041
1042 local a_alignskip <const> = attributes.private("alignskip")
1043
1044 local findattribute = nuts.findattribute
1045
1046 function nodes.handlers.tabulateskip(head,where,callback,attr,preamble)
1047 if callback & alignskip_code ~= 0 then
1048
1049 if where == "wrapup" and findattribute(head,a_alignskip,hlist_code) then
1050 local previous = false
1051 for row, id, subtype, list in nextlist, head do
1052 if id == hlist_code and subtype == row_code then
1053 if previous and previous ~= head and getattr(row,a_alignskip) == 1 then
1054 local glue = newglue(gettotal(previous))
1055 setattrlist(glue,previous)
1056 replacenode(head,previous,glue)
1057 previous = false
1058 else
1059 previous = row
1060 end
1061 end
1062 end
1063 end
1064 end
1065 end
1066
1067 local enabled = false
1068
1069 interfaces.implement {
1070 name = "enablealignskips",
1071
1072 public = true,
1073 protected = true,
1074 actions = function()
1075 if not enabled then
1076 nodes.tasks.enableaction("alignments","nodes.handlers.tabulateskip")
1077 enabled = true
1078 end
1079 end,
1080 }
1081
1082end
1083 |