math-ali.mkxl /size: 105 Kb    last modification: 2024-01-16 09:02
1%D \module
2%D   [       file=math-ali,
3%D        version=2008.10.20,
4%D          title=\CONTEXT\ Math Macros,
5%D       subtitle=Math Alignments,
6%D         author={Hans Hagen, Taco Hoekwater \& Aditya Mahajan},
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Math Macros / Math Alignments}
15
16\unprotect
17
18\registerctxluafile{math-ali}{autosuffix}
19
20%D The code here has been moved from other files. Beware: the \MKII\ and \MKIV\ code
21%D is not gathered in files with the same name. In the meantime this code has been
22%D adapted to \MKIV\ but more is possible. The code is somewhat complicated by the
23%D fact that alignments are tricky with rspect to tagging.
24
25% export:
26%
27% alignment : ok
28% cases     :
29% matrix    : ok
30% substack  :
31
32% Alignment overhaul timestamp: around watching GhostNote Live in Utrecht 2022
33% (energizing funky professionalism).
34
35%D The following macros are moved to this module because here we deal mostly with
36%D alignment issues. In principle one should see strc-mat, math-ini and math-ali as
37%D a close operation. The \type {\displaywidth} is only known inside a display
38%D formula, so we need to catch it when still zero.
39
40\permanent\def\checkeddisplaywidth % hsize if zero
41  {\dimexpr
42     \ifzeropt\displaywidth
43       \hsize
44     \else
45       \displaywidth
46     \fi
47      -\leftskip
48      -\rightskip
49   \relax}
50
51\permanent\def\maximizeddisplaywidth % larger than zero but within hsize
52  {\dimexpr
53     \ifzeropt\displaywidth
54       \hsize
55     \orelse\ifdim\displaywidth>\hsize
56       \hsize
57     \else
58       \displaywidth
59     \fi
60      -\leftskip
61      -\rightskip
62   \relax}
63
64%D \macros
65%D   {definemathalignment, setupmathalignment, startmathalignment}
66%D
67%D Modules may provide additional alignment features. The following kind of plain
68%D mechanisms are provided by the core.
69
70% \startformula
71%     \startalign[m=3, n=2, align={1:right,2:left},distance=2em]
72%         \NC 1.1 \NC = 1.2 \NC 2.1 \NC = 2.2 \NC 3.1 \NC = 3.2 \NR
73%         \NC 1   \NC = 1   \NC 2   \NC = 2   \NC 3   \NC = 3   \NR
74%         \NC 1.1 \NC = 1.2 \NC 2.1 \NC = 2.2 \NC 3.1 \NC = 3.2 \NR
75%     \stopalign
76% \stopformula
77
78\newtoks     \mathdisplayaligntweaks
79
80\newtoks     \t_math_align_a
81\newtoks     \t_math_align_b
82\newtoks     \t_math_align_c
83\newgluespec \d_math_eqalign_distance
84\newgluespec \d_math_eqalign_rulethickness
85\newdimension\d_math_eqalign_number_distance
86\newinteger  \c_math_eqalign_repeat
87
88\mutable\def\displayopenupvalue{.25\bodyfontsize}
89
90\installcorenamespace{mathalignendclass}   % maybe {complexmathendclass}
91
92\global\expandafter\integerdef\csname\??mathalignendclass\the\zerocount\endcsname\mathendcode
93
94\protected\def\math_eqalign_distance
95  {\global\expandafter\integerdef\csname\??mathalignendclass\the\c_math_eqalign_column\endcsname\mathendcode
96   \mathalignmentparameter\c!separator
97   \relax}
98
99% \def\math_build_eqalign
100%   {\scratchtoks\emptytoks
101%    \d_math_eqalign_distance\mathalignmentparameter\c!distance\relax
102%    \ifcstok{\mathalignmentparameter\c!align}\v!auto
103%      \d_math_eqalign_number_distance\mathalignmentparameter\c!numberdistance\relax
104%      \letmathalignmentparameter\c!align\v!middle
105%    \else
106%      \d_math_eqalign_number_distance\zeropoint
107%    \fi
108%    \scratchcounterone\mathalignmentparameter\c!m
109%    \scratchcountertwo\mathalignmentparameter\c!n
110%    \toksapp\scratchtoks\t_math_align_a
111%    \toksapp\scratchtoks{\global\c_math_eqalign_repeat\zerocount}%
112%    \scratchcounter\plusone
113%    \localcontrolledrepeat \numexpr\scratchcounterone*\scratchcountertwo-\plusone\relax
114%      {\ifnum\scratchcounter=\scratchcountertwo
115%         \scratchcounter\plusone
116%         % preamble expansion hell ...
117%         \toksapp\scratchtoks {\tabskip\d_math_eqalign_distance}%
118%         % so ...
119%         \toksapp\scratchtoks {\relax\math_eqalign_distance}%
120%         \etoksapp\scratchtoks{\global\advanceby\c_math_eqalign_repeat\the\scratchcountertwo\relax}%
121%       \else
122%         \advanceby\scratchcounter\plusone
123%       \fi
124%       \toksapp\scratchtoks\t_math_align_b}%
125%    \toksapp\scratchtoks\t_math_align_c
126%    \toksapp\scratchtoks{\global\c_math_eqalign_repeat\zerocount}}
127
128%D For compatibility we have this location stuff. It is kind of messy and uses
129%D tabskip magick plus signal 0x08 for an exception. Contrary to normal left
130%D aligned formulas we keep the number inline.
131%
132% \startbuffer
133%     \startformula
134%       A = B
135%     \stopformula
136%
137%     \startplaceformula \startformula
138%       A = B
139%     \stopformula \stopplaceformula
140%
141%     \startformula \startalign
142%       \NC A \EQ B \NR
143%       \NC A \EQ B \NR
144%     \stopalign \stopformula
145%
146%     \startplaceformula \startformula \startalign
147%       \NC A \EQ B \NR[+]
148%       \NC A \EQ B \NR[+]
149%     \stopalign \stopformula \stopplaceformula
150% \stopbuffer
151%
152% \startbuffer[all]
153%     \section[title=middle] \setupmathalignment[location={center,middle}] \getbuffer
154%     \section[title=left]   \setupmathalignment[location={center,left}]   \getbuffer
155%     \section[title=right]  \setupmathalignment[location={center,right}]  \getbuffer
156% \stopbuffer
157%
158% {\setupformula[location=right] \getbuffer[all] \page}
159% {\setupformula[location=left]  \getbuffer[all] \page}
160
161\def\math_build_eqalign
162  {\scratchtoks\emptytoks
163   \d_math_eqalign_distance\mathalignmentparameter\c!distance\relax
164   \ifcstok{\mathalignmentparameter\c!align}\v!auto
165     \d_math_eqalign_number_distance\mathalignmentparameter\c!numberdistance\relax
166     \letmathalignmentparameter\c!align\v!middle
167   \else
168     \d_math_eqalign_number_distance\zeropoint
169   \fi
170   \scratchcounterone\mathalignmentparameter\c!m
171   \scratchcountertwo\mathalignmentparameter\c!n
172   \etoksapp\scratchtoks\t_math_align_a
173   \toksapp\scratchtoks{\global\c_math_eqalign_repeat\zerocount}%
174   \scratchcounter\plusone
175   \localcontrolledrepeat \numexpr\scratchcounterone*\scratchcountertwo-\plusone\relax
176     {\ifnum\scratchcounter=\scratchcountertwo
177        \scratchcounter\plusone
178        % preamble expansion hell ...
179        \toksapp\scratchtoks {\tabskip\d_math_eqalign_distance}%
180        % so ...
181        \toksapp\scratchtoks {\relax\math_eqalign_distance}%
182        \etoksapp\scratchtoks{\global\advanceby\c_math_eqalign_repeat\the\scratchcountertwo\relax}%
183      \else
184        \advanceby\scratchcounter\plusone
185      \fi
186      \etoksapp\scratchtoks\t_math_align_b}%
187   \etoksapp\scratchtoks\t_math_align_c
188   \toksapp\scratchtoks{\global\c_math_eqalign_repeat\zerocount}}
189
190\def\math_eqalign_set_defaults
191  {%\normalbaselines % per januari 2024 commented
192   \mathsurround\zeropoint
193   \mathsurroundskip\zeroskip
194   \tabskip\zeroskip
195   \everycr\emptytoks}
196
197\protected\def\math_math_in_eqalign#1%
198  {\mathbeginclass
199     \ifcase\c_math_eqalign_column\or
200       \mathunsetcode
201     \orelse\ifcsname\??mathalignendclass\the\numexpr\c_math_eqalign_column-\plusone\relax\endcsname
202       \lastnamedcs
203     \else
204       \mathunsetcode
205     \fi
206   \startforceddisplaymath
207   \usemathstyleparameter\mathalignmentparameter\c!mathstyle
208   \tabskip\zeroskip
209   \everycr\emptytoks
210   #1%
211   \stopforceddisplaymath
212   \ifnum\lastrightclass<\mathunsetcode
213     \global\expandafter\integerdef\csname\??mathalignendclass\the\c_math_eqalign_column\endcsname\lastrightclass
214   \fi}
215
216\noaligned\protected\def\math_text_in_eqalign#1%
217  {\mathbeginclass\mathordcode
218   \mathendclass  \mathordcode
219   \startimath
220   \tabskip\zeroskip
221   \everycr\emptytoks
222   #1%
223   \stopimath}
224
225% the preamble is scanned for tabskips so we need the span to prevent an error
226% message but we can probably do without that hack now .. best not change this
227% now .. what works now keeps working
228
229\setnewconstant\c_strc_formulas_check_width\plusone
230
231\newboundary\c_math_align_l_marker
232\newboundary\c_math_align_r_marker
233
234% formula   : numbermethod        down : default
235% formula   : numberlocation   overlay : option
236% mathalign : align           ..| auto :
237% mathalign : adaptive             yes : synchronize glue
238
239% \startplaceformula
240% \startformula[numbermethod=down,numberlocation=normal]
241% \medmuskip 4mu plus 2mu minus 2mu \showmakeup[mathglue]\showglyphs\showboxes
242% \startalign[adaptive=yes,align=auto]
243% \NC aaa+x+xxxxxxxx+x+xxxx \EQ x+xxx                   \NR[eq:two:zz]
244% \NC x+x                   \EQ x+x+x+xxx+x+x+xxx+xx+xx \NR[eq:two:xx]
245% \stopalign
246% \stopformula
247% \stopplaceformula
248%
249% \startplaceformula
250% \startformula[numbermethod=normal,numberlocation=normal]
251% \medmuskip 4mu plus 2mu minus 2mu \showmakeup[mathglue]\showglyphs\showboxes
252% \startalign[adaptive=no,align=middle]
253% \NC aaa+x+xxxxxxxx+x+xxxx \EQ x+xxx                   \NR[eq:two:zz]
254% \NC x+x                   \EQ x+x+x+xxx+x+x+xxx+xx+xx \NR[eq:two:xx]
255% \stopalign
256% \stopformula
257% \stopplaceformula
258
259\newconditional\c_math_align_overflow_mode     \c_math_align_overflow_mode\conditionaltrue
260\newconditional\c_math_align_reformat_mode     \c_math_align_reformat_mode\conditionaltrue
261\newconditional\c_strc_formulas_overlay_number \c_strc_formulas_overlay_number\conditionaltrue
262
263\protected\def\math_text_in_align
264  {\scratchcounter\numexpr\c_math_eqalign_row+\plusone\relax
265   \usemathalignmentstyleandcolor\c!textstyle\c!textcolor
266   \usemathalignmentstyleandcolor{\c!textstyle:\the\scratchcounter}{\c!textcolor:\the\scratchcounter}%
267   \mathalignmentparameter\c!text
268   \mathalignmentparameter{\c!text:\the\scratchcounter}}
269
270\def\math_align_initialize_class_states
271  {}
272
273\protected\def\math_align_reset_class_states
274  {\lastleftclass \mathbegincode
275   \lastrightclass\mathendcode}
276
277% the fill skips are somewhat hackery here ...
278
279% left
280
281\def\math_prepare_l_eqalign_no_a
282  {\relax
283   \strut
284   \math_text_in_align
285   \aligncontent % for picking up the number
286   \ifcase\c_strc_formulas_align_alignment
287     \ifnum\c_strc_math_ragged_status=\plusthree
288       \tabskip\zeroskip
289     \else
290       \tabskip\centeringskip
291     \fi
292   \or
293     \ifnum\c_strc_math_ragged_status=\plusthree
294       \tabskip\zeroskip
295     \else
296       \tabskip\centeringskip
297     \fi
298   \or
299     \tabskip\stretchingfillskip
300   \fi
301   \boundary\c_math_align_l_marker
302   \math_align_reset_class_states
303   \aligntab
304   \math_first_in_eqalign
305   \hfil
306   \math_left_of_eqalign
307   \span
308   \math_math_in_eqalign{\aligncontent}%
309   \math_right_of_eqalign
310   \tabskip\zeroskip}
311
312\def\math_prepare_l_eqalign_no_b
313  {\aligntab
314   \math_next_in_eqalign
315   \math_left_of_eqalign
316   \span
317   \math_math_in_eqalign{\aligncontent}%
318   \math_right_of_eqalign
319   \tabskip\zeroskip
320   }
321
322\def\math_prepare_l_eqalign_no_c_three
323  {\hfil
324   \tabskip\zeroskip
325   \aligntab
326   \span
327   \boundary\c_math_align_r_marker
328   \math_alignment_rbox{\aligncontent}%
329   \tabskip\zeroskip}
330
331\def\math_prepare_l_eqalign_no_c_one
332  {\hfil
333   \tabskip\stretchingfillskip
334   \aligntab
335   \span
336   \boundary\c_math_align_r_marker
337   \math_alignment_rbox{\aligncontent}%
338   \tabskip\zeroskip}
339
340\def\math_prepare_l_eqalign_no_c_other
341  {\hfil
342   \tabskip\centeringskip
343   \aligntab
344   \span
345   \boundary\c_math_align_r_marker
346   \math_alignment_rbox{\aligncontent}%
347   \ifcase\c_strc_formulas_align_alignment
348     \tabskip\zeroskip
349   \or
350     \ifconditional\c_strc_formulas_handle_number
351       \tabskip\zeroskip
352\tabskip\stretchingfillskip
353     \or
354       \tabskip\stretchingfillskip
355     \fi
356   \or
357     \tabskip\zeroskip
358   \fi
359  }
360
361\def\math_prepare_l_eqalign_no  % \checkeddisplaymath
362  {\math_align_initialize_class_states
363   \t_math_align_a{\math_prepare_l_eqalign_no_a}%
364   \t_math_align_b{\math_prepare_l_eqalign_no_b}%
365   \ifnum\c_strc_math_ragged_status=\plusthree
366     \t_math_align_c{\math_prepare_l_eqalign_no_c_three}%
367   \orelse\ifnum\c_strc_math_ragged_status=\plusone
368     \t_math_align_c{\math_prepare_l_eqalign_no_c_one}%
369   \else
370     \t_math_align_c{\math_prepare_l_eqalign_no_c_other}%
371   \fi
372   \math_build_eqalign
373   \the\mathdisplayaligntweaks\relax
374   \ifnum\c_strc_math_ragged_status=\plusthree
375     \tabskip\stretchingfillskip
376   \else
377     \tabskip\zeroskip
378   \fi}
379
380% right
381
382\def\math_prepare_r_eqalign_no_a
383  {\relax
384    \strut
385    \math_text_in_align
386    \tabskip\centeringskip
387    \aligncontent % for picking up the number
388    \ifcase\c_strc_formulas_align_alignment
389      % middle
390      \boundary\c_math_align_l_marker% This is flush left when number
391      \tabskip\centeringskip
392    \or
393      % left
394      \tabskip\zeroskip
395    \or
396      % right
397      \tabskip\stretchingfilllskip
398    \fi
399    \math_align_reset_class_states
400    \aligntab
401    \math_first_in_eqalign
402    \hfil
403    \math_left_of_eqalign
404    \span
405    \math_math_in_eqalign{\aligncontent}%
406    \math_right_of_eqalign
407    \tabskip\zeroskip}
408
409\def\math_prepare_r_eqalign_no_b
410  {\aligntab
411   \math_next_in_eqalign
412   \math_left_of_eqalign
413   \span
414   \math_math_in_eqalign{\aligncontent}%
415   \math_right_of_eqalign
416   \tabskip\zeroskip}
417
418\def\math_prepare_r_eqalign_no_c_three
419  {\hfil
420   \aligntab
421   \hfill % the only one !
422   \span
423   \boundary\c_math_align_r_marker
424   \math_alignment_lbox{\aligncontent}%
425   \tabskip\zeroskip}
426
427\def\math_prepare_r_eqalign_no_c_one_one
428  {\hfil
429   \tabskip\stretchingfillskip
430   \aligntab
431   \span
432   \boundary\c_math_align_r_marker
433   \math_alignment_lbox{\aligncontent}%
434   \tabskip\zeroskip}
435
436\def\math_prepare_r_eqalign_no_c_one_other
437  {\hfil
438   \tabskip\zeroskip
439   \aligntab
440   \span
441   \boundary\c_math_align_r_marker
442   \math_alignment_lbox{\aligncontent}%
443   \tabskip\stretchingfillskip}
444
445\def\math_prepare_r_eqalign_no_c_other
446  {\hfil
447   \ifcase\c_strc_formulas_align_alignment
448     % middle
449     \tabskip\centeringskip % fails in some cases
450   \or
451     % left
452     \ifconditional\c_strc_formulas_handle_number
453       \tabskip\stretchingfillskip
454     \else
455       \tabskip\zeroskip
456     \fi
457   \or
458     % right
459     \ifconditional\c_strc_formulas_handle_number
460       \tabskip\stretchingfillskip
461     \else
462       \tabskip\zeroskip
463     \fi
464   \fi
465   \aligntab
466   \span
467   \hss % for MS to test this
468   \boundary\c_math_align_r_marker
469   \math_alignment_lbox{\aligncontent}%
470   \ifcase\c_strc_formulas_align_alignment
471     % middle
472     \tabskip\zeroskip
473   \or
474     % left
475     \ifconditional\c_strc_formulas_handle_number
476       \tabskip\zeroskip
477     \else
478       \tabskip\stretchingfillskip
479     \fi
480   \or
481     % right
482     \ifconditional\c_strc_formulas_handle_number
483       \tabskip\stretchingfillskip
484     \else
485       \tabskip\zeroskip
486     \fi
487   \fi}
488
489\def\math_prepare_r_eqalign_no
490  {\math_align_initialize_class_states
491   \t_math_align_a{\math_prepare_r_eqalign_no_a}%
492   \t_math_align_b{\math_prepare_r_eqalign_no_b}%
493   \ifnum\c_strc_math_ragged_status=\plusthree
494     \t_math_align_c{\math_prepare_r_eqalign_no_c_three}%
495   \orelse\ifnum\c_strc_math_ragged_status=\plusone
496     \ifnum\c_strc_math_number_variant=\plusone
497       \t_math_align_c{\math_prepare_r_eqalign_no_c_one_one}%
498     \else
499       \t_math_align_c{\math_prepare_r_eqalign_no_c_one_other}%
500     \fi
501   \else
502     \t_math_align_c{\math_prepare_r_eqalign_no_c_other}%
503   \fi
504   \math_build_eqalign
505   \the\mathdisplayaligntweaks
506   \tabskip\zeroskip}
507
508% done
509
510\def\math_halign_checked
511  {\enablemathalignrelocate
512   \halign
513     \ifconditional\c_math_align_overflow_mode
514       \s!callback
515         \align_callback_mathalign
516       \s!attr
517         \mathnumberlocationattribute \numexpr % on whole, different on l/rbox
518            \unless\ifcase\c_strc_formulas_align_alignment
519              \plustwo
520            \orelse\ifconditional\c_math_align_reformat_mode
521              \plusfour
522            \orelse\ifnum\c_strc_formulas_align_alignment=\plusone
523              \ifcstok{\formulaparameter\c!location}\v!left
524                \pluseight
525              \else
526                \plustwo
527              \fi
528            \else
529              \plustwo
530            \fi
531          * \plussixteen % just a signal
532       \relax
533     \fi
534     \ifcase\c_strc_formulas_check_width\else
535        to \checkeddisplaywidth
536     \fi}
537
538\installcorenamespace {mathalignlocation}
539
540\setnewconstant\c_strc_formulas_align_alignment\zerocount % 1=left 2=right
541\setnewconstant\c_strc_formulas_align_packed   \zerocount
542
543\defcsname\??mathalignlocation\v!top   \endcsname{\let\math_alignment_location_box\tpack}
544\defcsname\??mathalignlocation\v!bottom\endcsname{\let\math_alignment_location_box\vpack}
545\defcsname\??mathalignlocation\v!center\endcsname{\let\math_alignment_location_box\vcenter}
546
547\defcsname\??mathalignlocation\v!middle\endcsname{\c_strc_formulas_align_alignment\zerocount}
548\defcsname\??mathalignlocation\v!left  \endcsname{\c_strc_formulas_align_alignment\plusone}
549\defcsname\??mathalignlocation\v!right \endcsname{\c_strc_formulas_align_alignment\plustwo}
550
551\defcsname\??mathalignlocation\v!packed\endcsname
552  {\c_strc_formulas_align_packed\plusone}
553
554\defcsname\??mathalignlocation\v!formula\endcsname
555  {\c_strc_formulas_align_alignment
556     \ifcstok{\formulaparameter\c!align}\v!flushleft
557       \plusone
558   % \orelse\expandafter\ifx\lastnamedcs\v!flushright
559     \orelse\ifcstok{\lastnamedcs}\v!flushright
560       \plustwo
561     \else
562       \zerocount
563     \fi}
564
565\def\math_alignment_location_box_set#1{\begincsname\??mathalignlocation#1\endcsname}
566
567\def\math_alignment_location_check#1%
568  {\c_strc_formulas_align_alignment\zerocount
569   \c_strc_formulas_align_packed\zerocount
570   \let\math_alignment_location_box\vcenter
571   \processcommacommand[#1]\math_alignment_location_box_set}
572
573%D Here we implement the user interface part. We start with basic math alignments:
574
575\newinteger    \c_math_eqalign_column
576\newinteger    \c_math_eqalign_row
577\newconditional\c_math_eqalign_first
578
579\newtoks       \everymathalignment
580\newtoks       \everymathalignmentdone
581
582\newdimension  \d_math_eqalign_number_threshold
583
584\definesystemattribute[mathnumberlocation] [public]
585\definesystemattribute[mathnumberthreshold][public]
586
587\protected\def\math_alignment_lbox#1%
588  {\begingroup
589   \setbox\scratchbox\hbox{\resetformulaparameter\c!location#1}%
590   \ifzeropt\wd\scratchbox\else
591     \hpack
592       \s!attr \mathnumberlocationattribute \numexpr
593         \c_math_alignment_packed_signal +
594         \c_strc_math_ragged_status * \plussixteen + \plusone
595       \relax
596       \s!attr \mathnumberthresholdattribute \numexpr
597         \d_math_eqalign_number_threshold
598       \relax
599       {\strc_formulas_add_distance \plustwo\v!left\mathalignmentparameter
600        \box\scratchbox
601        \hskip\d_math_alignment_packed_margin
602        }%
603   \fi
604   \global\d_math_eqalign_number_threshold\zeropoint % move to begin of row
605   \endgroup}
606
607\protected\def\math_alignment_rbox#1%
608  {\begingroup
609   \setbox\scratchbox\hbox{\resetformulaparameter\c!location#1}%
610   \ifzeropt\wd\scratchbox\else
611     \hpack
612       \s!attr \mathnumberlocationattribute \numexpr
613         \c_math_alignment_packed_signal +
614         \c_strc_math_ragged_status * \plussixteen + \plustwo
615       \relax
616       \s!attr \mathnumberthresholdattribute \numexpr
617         \d_math_eqalign_number_threshold
618       \relax
619       {\hskip\d_math_alignment_packed_margin
620        \box\scratchbox
621        \strc_formulas_add_distance \plustwo\v!right\mathalignmentparameter}%
622   \fi
623   \global\d_math_eqalign_number_threshold\zeropoint % move to begin of row
624   \endgroup}
625
626\permanent\tolerant\protected\def\math_alignment_NN[#1]#*[#2]%
627  {\aligntab
628   \strc_formulas_place_number_nested{#1}{#2}}
629
630\permanent\tolerant\protected\def\math_alignment_NR[#1]#*[#2]%
631  {\aligntab
632   \dostoptagged % finish cell
633   \strc_formulas_place_number_nested{#1}{#2}%
634   \math_number_right_of_eqalign
635   \global\c_math_eqalign_first\conditionaltrue
636   \crcr
637   \noalign{\dostoptagged}} % finish row
638
639\permanent\protected\def\math_alignment_NC
640  {\relax
641   \ifconditional\c_math_eqalign_first
642     \ifx\p_math_alignment_number\v!auto
643       \strc_formulas_place_number_nested{+}{}%
644     \fi
645     \global\c_math_eqalign_first\conditionalfalse
646   \fi
647   \math_number_left_of_eqalign
648   \aligntab}
649
650\permanent\protected\def\math_alignment_EQ
651  {\NC=}
652
653\noaligned\tolerant\protected\def\math_common_TB[#1]%
654  {\noalign{\blank[#1]}}
655
656\installmacrostack\NC % maybe more to shared table definitions
657\installmacrostack\NN % maybe more to shared table definitions
658\installmacrostack\EQ % maybe more to shared table definitions
659\installmacrostack\NR % maybe more to shared table definitions
660\installmacrostack\BC % maybe more to shared table definitions
661\installmacrostack\EC % maybe more to shared table definitions
662\installmacrostack\TB % maybe more to shared table definitions
663
664\appendtoks
665    \push_macro_NC
666    \push_macro_NN
667    \push_macro_EQ
668    \push_macro_NR
669    \push_macro_TB
670    \enforced\let\NC\math_alignment_NC
671    \enforced\let\NN\math_alignment_NN
672    \enforced\let\EQ\math_alignment_EQ
673    \enforced\let\NR\math_alignment_NR
674    \enforced\let\TB\math_common_TB
675    \global\c_math_eqalign_first\conditionaltrue
676    \global\s_strc_math_alignment_inbetween\zeroskip
677\to \everymathalignment
678
679\appendtoks
680    \pop_macro_TB
681    \pop_macro_NR
682    \pop_macro_EQ
683    \pop_macro_NN
684    \pop_macro_NC
685    \global\s_strc_math_alignment_inbetween\zeroskip
686\to \everymathalignmentdone
687
688% % experimental:
689%
690% \def\math_alignment_snap_start
691%   {\ifgridsnapping
692%      \edef\p_math_alignment_grid{\mathalignmentparameter\c!grid}%
693%      \ifx\p_math_alignment_grid\v!no\else
694%        \snaptogrid[\p_math_alignment_grid]\vbox\bgroup
695%      \fi
696%    \fi}
697%
698% \def\math_alignment_snap_stop
699%   {\ifgridsnapping
700%      \ifx\p_math_alignment_grid\v!no\else
701%        \egroup
702%      \fi
703%    \fi}
704%
705% % doesn't work well, so:
706
707\let\math_alignment_snap_start\relax
708\let\math_alignment_snap_stop \relax
709
710% end of experimental
711
712\newconditional\c_math_alignment_auto_number
713
714% \begingroup not permitted ($$...assignments...\halign... ).. check in luametatex
715
716% \definemathmatrix
717%   [pmatrix]
718%   [matrix:parentheses]
719% % [align=1:right]
720%   [align=all:right]
721% % [align=2:right]
722% % [align={1:left,2:middle,3:right}]
723
724\newgluespec\s_strc_math_alignment_inbetween
725
726\def\strc_math_setup_spacing_aligned#1%
727  {\begingroup
728   % here we abuse the whitespace setter
729   \edef\v_spac_whitespace_current{#1\c!spaceinbetween}%
730   \ifempty\v_spac_whitespace_current
731     \global\s_strc_math_alignment_inbetween\zeroskip
732   \else
733     \spac_whitespace_setup
734     \global\s_strc_math_alignment_inbetween\parskip
735   \fi
736   \endgroup}
737
738\newinteger  \c_math_alignment_packed_signal
739\newdimension\d_math_alignment_packed_margin
740
741\def\math_alignment_packed_start
742  {\c_strc_formulas_check_width\zerocount
743   \c_math_alignment_packed_signal"100\relax
744   \d_math_alignment_packed_margin\rightskip
745   \mathatom
746     \s!class \mathwrappedcode
747     \s!attr \mathnumberlocationattribute \c_math_alignment_packed_signal
748   \bgroup
749%     \scratchdimen\mathalignmentparameter\c!leftmargin\relax
750%     \ifzeropt\scratchdimen\else\kern\scratchdimen\fi
751%     \mathalignmentparameter\c!left\relax
752   \math_fenced_start_wrap{\mathalignmentparameter\c!fences}%
753   \mathatom
754     \s!class \mathconstructcode
755%    \bgroup
756   \bgroup}
757
758\def\math_alignment_packed_stop
759  {\egroup
760%    \egroup
761   \math_fenced_stop_wrap
762% \mathalignmentparameter\c!right\relax
763% \scratchdimen\mathalignmentparameter\c!rightmargin\relax
764% \ifzeropt\scratchdimen\else\kern\scratchdimen\fi
765% \setbox\scratchbox\hbox{\mathalignmentparameter\c!text}%
766% \ifvoid\scratchbox\else
767%   \kern\mathalignmentparameter\c!textdistance
768%   \vcenter{\box\scratchbox}%
769% \fi
770   \egroup
771   \d_math_alignment_packed_margin\zeropoint
772   \c_math_alignment_packed_signal\zerocount}
773
774\permanent\tolerant\protected\def\math_alignment_start[#1]#*[#S#2]%
775  {\begingroup
776   \cdef\currentmathalignment{#1}%
777   \ifarguments\or\or
778     \setupmathalignment[#1][#2]%
779   \fi
780   \ifcstok{\mathalignmentparameter\c!adaptive}\v!yes
781     \c_math_align_reformat_mode\conditionaltrue
782   \else
783     \c_math_align_reformat_mode\conditionalfalse
784   \fi
785   \math_alignment_location_check{\mathalignmentparameter\c!location}% vcenter etc
786   \ifcase\c_strc_formulas_align_packed\or
787     \math_alignment_packed_start
788   \fi
789   \math_alignment_snap_start
790   \expand\everymathalignment
791   \c_math_eqalign_row   \zerocount
792   \c_math_eqalign_column\zerocount
793   \edef\p_math_alignment_number{\mathalignmentparameter\c!number}%
794   \processcommacommand
795     [\mathalignmentparameter\c!align]%
796     {\advanceby\c_math_eqalign_column\plusone\math_eqalign_set_column}% takes argument
797   \global\c_math_eqalign_column\plusone
798   \strc_math_setup_spacing_aligned\mathalignmentparameter
799   \dostarttagged\t!math\empty
800   \dostarttagged\t!mtable\currentmathalignment
801   % is this check still valid?
802   \ifmmode
803     % we're always in mathmode
804     \the\mathdisplayaligntweaks
805     \math_alignment_location_box
806   \fi
807   \bgroup
808   \ifcstok{\formulaparameter\c!location}\v!left
809     \math_prepare_l_eqalign_no
810   \else
811     \math_prepare_r_eqalign_no
812   \fi
813   \math_halign_checked\expandafter\bgroup\the\scratchtoks\crcr}
814
815\def\math_alignment_stop % can be protected
816  {\crcr
817   \egroup
818   \egroup
819   \dostoptagged
820   \dostoptagged
821   \expand\everymathalignmentdone
822   \math_alignment_snap_stop
823   \ifcase\c_strc_formulas_align_packed\or
824     \math_alignment_packed_stop
825   \fi
826   \endgroup}
827
828\installcorenamespace{mathalignment}
829\installcorenamespace{mathalignmentvariant}
830
831\installcommandhandler \??mathalignment {mathalignment} \??mathalignment
832
833\appendtoks
834              \frozen\protected\instance\edefcsname\e!start\currentmathalignment\endcsname{\math_alignment_start[\currentmathalignment]}%
835    \noaligned\frozen\protected\instance \defcsname\e!stop \currentmathalignment\endcsname{\math_alignment_stop}%
836\to \everydefinemathalignment
837
838% to be tested
839%
840% \appendtoks
841%               \frozen\instance\protected\defcsname\e!start\currentmathalignment\endcsname{\math_alignment_start[\currentmathalignment]}%
842%     \noaligned\frozen\instance\protected\defcsname\e!stop \currentmathalignment\endcsname{\math_alignment_stop}%
843% \to \everydefinemathalignment
844
845\setupmathalignment
846  [\c!n=2,
847   \c!m=1,
848\c!leftmargin=\zeropoint,
849\c!rightmargin=\zeropoint,
850\c!fences=,
851\c!left=,
852\c!right=,
853   \c!distance=\emwidth,
854   \c!location=\v!formula,
855   \c!spaceinbetween=\formulaparameter\c!spaceinbetween,
856   \c!numberthreshold=\zeropoint,
857   \c!grid=\v!math]
858
859\definemathalignment[align]            % default case (this is what amstex users expect)
860\definemathalignment[\v!mathalignment] % prefered case (this is cleaner, less clashing)
861
862% this needs some consideration, it might be obsolete now:
863
864\protected\def\math_display_align_hack
865  {\everycr{\noalign{\penalty\interdisplaylinepenalty}}}
866
867\appendtoks
868    \math_display_align_hack
869\to \mathdisplayaligntweaks
870
871% special case.. in case one mistypes ..
872
873\ifdefined \startalignment
874
875    \pushoverloadmode
876
877    \aliased\let\align_math_normal_start\startalign
878    \aliased\let\align_math_normal_stop \stopalign
879
880    \aliased\let\align_text_normal_start\startalignment
881    \aliased\let\align_text_normal_stop \stopalignment
882
883    \permanent\overloaded\protected\def\startalign
884      {\ifmmode
885         \enforced\let\stopalign\align_math_normal_stop % cannot be a protected def ... lookahead in align
886         \expandafter\align_math_normal_start
887       \orelse\ifinformula
888         \enforced\let\stopalign\align_math_normal_stop
889         \expandafter\align_math_normal_start
890       \else
891         \enforced\let\stopalign\align_text_normal_stop
892         \expandafter\align_text_normal_start
893       \fi}
894
895    \aliased\let\stopalign\relax
896
897    \permanent\overloaded\protected\def\startalignment
898      {\ifmmode
899         \enforced\let\stopalignment\align_math_normal_stop % cannot be a protected def ... lookahead in align
900         \expandafter\align_math_normal_start
901       \orelse\ifinformula
902         \enforced\let\stopalignment\align_math_normal_stop % cannot be a protected def ... lookahead in align
903         \expandafter\align_math_normal_start
904       \else
905         \enforced\let\stopalignment\align_text_normal_stop
906         \expandafter\align_text_normal_start
907       \fi}
908
909    \aliased\let\stopalignment\relax
910
911    \pushoverloadmode
912
913\fi
914
915%
916
917\protected\def\math_first_in_eqalign % protection prevents tagging expansion
918  {\global\c_math_eqalign_column\plusone
919   \global\advanceby\c_math_eqalign_row\plusone
920   \dostarttagged\t!mtablerow \empty
921   \dostarttagged\t!mtablecell\empty}
922
923\protected\def\math_next_in_eqalign % protection prevents tagging expansion
924  {\global\advanceby\c_math_eqalign_column\plusone
925   \dostoptagged % finish cell
926   \dostarttagged\t!mtablecell\empty}
927
928\protected\def\math_left_of_eqalign
929  {\ifcsname\??mathalignmentvariant\the\c_math_eqalign_column\endcsname
930     \ifcase\lastnamedcs \or \relax \or \hfill \or \hfill \fi
931   \orelse\ifcsname\??mathalignmentvariant\the\zerocount\endcsname
932     \ifcase\lastnamedcs \or \relax \or \hfill \or \hfill \fi
933   \orelse\ifcsname\??mathalignmentvariant\the\numexpr\c_math_eqalign_column-\c_math_eqalign_repeat\relax\endcsname
934     \ifcase\lastnamedcs \or \relax \or \hfill \or \hfill \fi
935   \fi}
936
937\protected\def\math_right_of_eqalign
938  {\ifcsname\??mathalignmentvariant\the\c_math_eqalign_column\endcsname
939     \ifcase\lastnamedcs \or \hfill \or \relax \or \hfill \fi
940   \orelse\ifcsname\??mathalignmentvariant\the\zerocount\endcsname
941     \ifcase\lastnamedcs \or \hfill \or \relax \or \hfill \fi
942   \orelse\ifcsname\??mathalignmentvariant\the\numexpr\c_math_eqalign_column-\c_math_eqalign_repeat\relax\endcsname
943     \ifcase\lastnamedcs \or \hfill \or \relax \or \hfill \fi
944   \fi}
945
946\newconditional\c_math_alignment_local_number % not used but when true puts in front (todo)
947
948\def\math_number_right_of_eqalign
949  {\ifcase\d_strc_formulas_number\else
950     \ifconditional\c_math_alignment_local_number
951       \ifcase\c_strc_math_number_location\or\or
952         \strc_math_flush_number_box
953       \fi
954     \else
955       \strc_math_flush_number_box
956     \fi
957   \fi}
958
959\def\math_number_left_of_eqalign
960  {\ifcase\d_strc_formulas_number\else
961     \ifconditional\c_math_alignment_local_number
962       \ifcase\c_strc_math_number_location\or
963         \strc_math_flush_number_box
964       \fi
965     \fi
966   \fi}
967
968\protected\def\math_eqalign_set_column_indeed[#1:#2:#3]% we don't really check for all (so * will do too) ... yet
969  {\ifempty{#2}%
970     % current counter
971   \orelse\ifchknumber#1\or
972     \c_math_eqalign_column\lastchknumber
973   \else
974     \c_math_eqalign_column\zerocount
975   \fi
976   \expandafter\integerdef\csname\??mathalignmentvariant\the\c_math_eqalign_column\endcsname
977     \ifcsname\??mathalignmentvariant#2\endcsname\lastnamedcs\else\zerocount\fi\relax}
978
979\def\math_eqalign_set_column#1%
980  {\normalexpanded{\math_eqalign_set_column_indeed[#1::]}}
981
982\def\math_eqalign_set_columns_step
983  {\advanceby\c_math_eqalign_column\plusone
984  %\c_math_matrix_columns\c_math_eqalign_column
985   \math_eqalign_set_column}
986
987\def\math_eqalign_set_columns#1%
988  {\c_math_eqalign_column\zerocount
989   \rawprocesscommacommand[#1]\math_eqalign_set_columns_step}
990
991% can't we reuse these numbers ?
992
993\letcsname\??mathalignmentvariant\v!normal    \endcsname\zerocount
994\letcsname\??mathalignmentvariant\v!flushright\endcsname\plusone
995\letcsname\??mathalignmentvariant\v!left      \endcsname\plusone
996\letcsname\??mathalignmentvariant\v!right     \endcsname\plustwo
997\letcsname\??mathalignmentvariant\v!flushleft \endcsname\plustwo
998\letcsname\??mathalignmentvariant\v!middle    \endcsname\plusthree
999
1000%D \starttyping
1001%D \placeformula[eqn0]\startformula \startalign[n=1] a\NR       \stopalign \stopformula See \in[eqn0]
1002%D \placeformula[eqn1]\startformula \startalign[n=1] a\NR       \stopalign \stopformula See \in[eqn1]
1003%D \placeformula      \startformula \startalign[n=1] a\NR[eqn2] \stopalign \stopformula See \in[eqn2]
1004%D \placeformula[eqn3]\startformula \startalign[n=1] a\NR[+]    \stopalign \stopformula See \in[eqn3]
1005%D \stoptyping
1006
1007%D \startbuffer
1008%D \placeformula \startformula \startalign
1009%D \NC  a \EQ b \NR[+]
1010%D \NC  c \EQ d \NR
1011%D \NC    \EQ f \NR[for:demo-a-1]
1012%D \NC    \EQ g \NR[for:demo-a-2][a]
1013%D \NC    \EQ h \NR[for:demo-a-3][b]
1014%D \NC    \EQ i \NR
1015%D \stopalign \stopformula
1016%D \stopbuffer
1017%D
1018%D \typebuffer \getbuffer
1019%D
1020%D \startbuffer
1021%D \placeformula \startformula \startalign
1022%D \NC a \EQ b \NR[+]
1023%D \NC c \EQ d \NR
1024%D \NC   \EQ f \NR
1025%D \NC   \EQ g \NR
1026%D \NC   \EQ h \NR
1027%D \NC   \EQ i \NR[+]
1028%D \stopalign \stopformula
1029%D \stopbuffer
1030%D
1031%D \typebuffer \getbuffer
1032%D
1033%D \startbuffer
1034%D \placeformula \startformula \startalign
1035%D \NC  a \NC \eq  b \NR[+]
1036%D \NC  c \NC \neq d \NR
1037%D \NC    \NC \neq f \NR[for:demo-b-1]
1038%D \NC    \NC \geq g \NR[for:demo-b-2][a]
1039%D \NC    \NC \leq h \NR[for:demo-b-3][b]
1040%D \NC    \NC \neq i \NR
1041%D \stopalign \stopformula
1042%D \stopbuffer
1043%D
1044%D \typebuffer \getbuffer
1045%D
1046%D \startbuffer
1047%D \placeformula \startformula \startalign[n=3,align={left,middle,right}]
1048%D \NC       l \NC = \NC r     \NR
1049%D \NC    left \NC = \NC right \NR
1050%D \stopalign \stopformula
1051%D \stopbuffer
1052%D
1053%D \typebuffer \getbuffer
1054%D
1055%D \startbuffer
1056%D \placeformula \startformula \startalign[n=3,align={right,middle,left}]
1057%D \NC       l \NC = \NC r     \NR
1058%D \NC    left \NC = \NC right \NR
1059%D \stopalign \stopformula
1060%D \stopbuffer
1061%D
1062%D \typebuffer \getbuffer
1063%D
1064%D \startbuffer
1065%D \placeformula \startformula \startalign[n=3,align={middle,middle,middle}]
1066%D \NC       l \NC = \NC r     \NR
1067%D \NC    left \NC = \NC right \NR
1068%D \stopalign \stopformula
1069%D \stopbuffer
1070%D
1071%D \typebuffer \getbuffer
1072%D
1073%D \startbuffer
1074%D \placeformula
1075%D \startformula
1076%D     \startalign[n=3,align={middle,middle,middle}]
1077%D         \NC a  \NC = \NC b  \NR[+]
1078%D         \NC 2a \NC = \NC 2b \NR
1079%D     \stopalign
1080%D \stopformula
1081%D \stopbuffer
1082%D
1083%D \typebuffer \getbuffer
1084%D
1085%D \startbuffer
1086%D \placeformula
1087%D \startformulas
1088%D     \setupmathalignment[n=3,align={middle,middle,middle}]%
1089%D     \startformula
1090%D         \startalign
1091%D             \NC a  \NC = \NC b  \NR[+]
1092%D             \NC 2a \NC = \NC 2b \NR
1093%D         \stopalign
1094%D     \stopformula
1095%D     \startformula
1096%D         \startalign
1097%D             \NC a  \NC = \NC b  \NR[+]
1098%D             \NC 2a \NC = \NC 2b \NR
1099%D         \stopalign
1100%D     \stopformula
1101%D \stopformulas
1102%D \stopbuffer
1103%D
1104%D \typebuffer \getbuffer
1105%D
1106%D \startbuffer
1107%D \placeformula
1108%D \startformulas
1109%D     \dorecurse{5}{\startformula
1110%D         \startalign[n=3,align={middle,middle,middle}]
1111%D             \NC a  \NC = \NC b  \NR[+]
1112%D             \NC 2a \NC = \NC 2b \NR
1113%D         \stopalign
1114%D     \stopformula}
1115%D \stopformulas
1116%D \stopbuffer
1117%D
1118%D \typebuffer \getbuffer
1119
1120%D \macros
1121%D   {definemathcases, setupmathcases, startmathcases}
1122%D
1123%D Another wish \unknown
1124
1125\installcorenamespace{mathcases}
1126
1127\installcommandhandler \??mathcases {mathcases} \??mathcases
1128
1129\setupmathcases
1130  [\c!distance=\emwidth,
1131   \c!strut=\v!yes, % new
1132   \c!spaceinbetween=\mathalignmentparameter\c!spaceinbetween,
1133  %\c!numberdistance=2.5\emwidth,
1134   \c!numberdistance=\zeropoint]
1135
1136\appendtoks
1137    \frozen\instance\protected\edefcsname\e!start\currentmathcases\endcsname{\math_cases_start[\currentmathcases]}%
1138    \frozen\instance          \defcsname \e!stop \currentmathcases\endcsname{\math_cases_stop}%
1139\to \everydefinemathcases
1140
1141%D Why not \unknown:
1142%D
1143%D \starttyping
1144%D \definemathcases[mycases][simplecommand=mycases]
1145%D
1146%D \startformula
1147%D \startmycases
1148%D \NC 1  \NC x>0 \NR
1149%D \NC -1 \NC x<0 \NR
1150%D \stopmycases
1151%D \stopformula
1152%D
1153%D \startformula
1154%D     \mycases{1,x>0;-1,x<0}
1155%D \stopformula
1156%D \stoptyping
1157
1158\permanent\tolerant\protected\def\math_cases_simple[#1]#*[#2]#:#3%
1159  {\begingroup
1160   \cdef\currentmathcases{#1}%
1161   \setupcurrentmathcases[#2]%
1162   \math_cases_start[\currentmathcases]%
1163   \clf_simplecases{\mathcasesparameter\c!action}{#3}%
1164   \math_cases_stop
1165   \endgroup}
1166
1167\appendtoks
1168    \edef\p_simplecommand{\mathcasesparameter\c!simplecommand}%
1169    \ifempty\p_simplecommand\else
1170        \frozen\protected\instance\edefcsname\p_simplecommand\endcsname{\math_cases_simple[\currentmathcases]}%
1171    \fi
1172\to \everydefinemathcases
1173
1174\let\math_cases_strut\relax
1175
1176\newinteger\c_math_cases_nc
1177
1178\def\math_cases_NC_zero
1179  {\ifmmode\else\startimath\fi}
1180
1181\def\math_cases_NC_one
1182  {\ifmmode\stopimath\fi
1183   \aligntab
1184   \ifmmode\else\startimath\fi}
1185
1186\def\math_cases_NC_two
1187  {\ifmmode\stopimath\fi}
1188
1189\def\math_cases_TC_zero % needs checking
1190 %{\ifmmode\else\startimath\fi}
1191  {}
1192
1193\def\math_cases_TC_one
1194  {\ifmmode\stopimath\fi
1195   \aligntab}
1196
1197\def\math_cases_TC_two
1198 %{\ifmmode\stopimath\fi} % needs checking
1199  {}
1200
1201\permanent\protected\def\math_cases_NC
1202  {\ifcase\c_math_cases_nc
1203     \expandafter\math_cases_NC_zero
1204   \or
1205     \expandafter\math_cases_NC_one
1206   \or
1207     \expandafter\math_cases_NC_zero
1208   \else
1209     % error
1210   \fi
1211   \global\advanceby\c_math_cases_nc\plusone}
1212
1213\permanent\protected\def\math_cases_TC
1214  {\ifcase\c_math_cases_nc
1215     \expandafter\math_cases_TC_zero
1216   \or
1217     \expandafter\math_cases_TC_one
1218   \or
1219     \expandafter\math_cases_TC_two
1220   \else
1221     % error
1222   \fi
1223   \global\advanceby\c_math_cases_nc\plusone}
1224
1225\noaligned\tolerant\permanent\protected\def\math_cases_NR[#1]#*[#2]%
1226  {\unskip
1227   \ifmmode\stopimath\fi
1228   \aligntab
1229   \global\c_math_cases_nc\zerocount
1230   \strc_formulas_place_number_nested{#1}{#2}%
1231   \math_number_right_of_eqalign
1232   \box\b_strc_formulas_number
1233   \crcr}
1234
1235\installglobalmacrostack\c_math_cases_nc
1236
1237\permanent\tolerant\protected\def\math_cases_start[#1]#*[#S#2]%
1238  {\begingroup
1239   \cdef\currentmathcases{#1}%
1240   \ifarguments\or\or
1241     \setupcurrentmathcases[#2]%
1242   \fi
1243   \edef\p_strut{\mathcasesparameter\c!strut}%
1244   \ifx\p_strut\v!yes
1245     \enforced\let\math_cases_strut\strut
1246   \else
1247     \enforced\let\math_cases_strut\relax
1248   \fi
1249   \push_macro_c_math_cases_nc
1250   \mathatom \s!class \mathwrappedcode \bgroup
1251   \scratchdimen\mathcasesparameter\c!leftmargin\relax
1252   \ifzeropt\scratchdimen\else\kern\scratchdimen\fi
1253   \mathcasesparameter\c!left
1254   \math_fenced_start_wrap{\mathcasesparameter\c!fences}%
1255   \mathatom \s!class \mathconstructcode \bgroup
1256   \vcenter\bgroup
1257   \enforced\let\MC\math_cases_NC
1258   \enforced\let\NC\math_cases_NC
1259   \enforced\let\NR\math_cases_NR
1260   \enforced\let\TC\math_cases_TC
1261   \enforced\let\TB\math_common_TB
1262   \math_eqalign_set_defaults
1263   \global\c_math_eqalign_column\plusone
1264   \global\c_math_eqalign_row\plusone
1265   \global\c_math_cases_nc\zerocount
1266   \strc_math_setup_spacing_aligned\mathcasesparameter
1267   \enablemathalignrelocate
1268   \halign
1269     \s!callback
1270       \align_callback_mathalign
1271     \s!attr
1272       \mathnumberlocationattribute \zerocount
1273     \bgroup % use \indexofregister here
1274     \ifmmode\else\startimath\fi
1275     \mathcasesparameter\c!style
1276     \aligncontent
1277     \ifmmode\stopimath\fi
1278     \hfil
1279     \aligntab
1280     \kern\mathcasesparameter\c!distance\relax
1281     \math_cases_strut % looks better
1282     \aligncontent
1283     \hfil
1284     \aligntab
1285     \kern\mathcasesparameter\c!numberdistance\relax
1286     \span\math_text_in_eqalign{\aligncontent}%
1287     \crcr} % todo: number
1288
1289\noaligned\permanent\protected\def\math_cases_stop
1290  {\crcr
1291   \egroup
1292   \egroup
1293   \egroup
1294   \math_fenced_stop_wrap
1295   \mathcasesparameter\c!right\relax
1296   \scratchdimen\mathcasesparameter\c!rightmargin\relax
1297   \ifzeropt\scratchdimen\else\kern\scratchdimen\fi
1298   \egroup
1299   \pop_macro_c_math_cases_nc
1300   \endgroup}
1301
1302% \definemathfence [cases] [\c!left="007B,\c!right=\v!none]
1303% \definemathfence [sesac] [\c!left=\v!none,\c!right="007D]
1304
1305\definemathcases[cases]
1306\definemathcases[\v!mathcases]
1307
1308% This might become key=cases in the end:
1309
1310\setupmathcases
1311% [cases]
1312  [\c!leftmargin=\zeropoint,
1313   \c!rightmargin=\zeropoint,
1314   \c!left=,
1315   \c!right=,
1316   \c!fences=cases]
1317
1318\definemathcases
1319  [sesac]
1320  [\c!fences=sesac]
1321
1322%D \startbuffer
1323%D \placeformula \startformula \startcases
1324%D \NC 2 \NC y > 0     \NR
1325%D \NC 7 \NC x = 7     \NR[+]
1326%D \NC 4 \TC otherwise \NR
1327%D \stopcases \stopformula
1328%D \stopbuffer
1329%D
1330%D \typebuffer \getbuffer
1331%D
1332%D \startbuffer
1333%D \placeformula \startformula x \startcases
1334%D \NC 2 \NC y > 0     \NR[+]
1335%D \NC 7 \NC x = 7     \NR
1336%D \NC 4 \TC otherwise \NR
1337%D \stopcases \stopformula
1338%D \stopbuffer
1339%D
1340%D \typebuffer \getbuffer
1341%D
1342%D \startbuffer
1343%D \placeformula \startformula \startcases
1344%D \NC 2 \NC y > 0     \NR
1345%D \NC 7 \NC x = 7     \NR
1346%D \NC 4 \TC otherwise \NR
1347%D \stopcases \stopformula
1348%D \stopbuffer
1349%D
1350%D \typebuffer \getbuffer
1351%D
1352%D \startbuffer
1353%D \placeformula \startformula x \startcases
1354%D \NC 2 \NC y > 0     \NR
1355%D \NC 7 \NC x = 7     \NR
1356%D \NC 4 \TC otherwise \NR
1357%D \stopcases \stopformula
1358%D \stopbuffer
1359%D
1360%D \typebuffer \getbuffer
1361
1362%D \macros
1363%D   {definemathmatrix, setupmathmatrix, startmathmatrix}
1364%D
1365%D Yet another one \unknown. This time we implement the lot a bit
1366%D different which is a side effect of getting the tagging right. In
1367%D retrospect the main alignment could be done this way but \unknown
1368
1369%D In the end is is way easier to not use alignments and just paste boxes together
1370%D but let's be a bit texie.
1371
1372\installcorenamespace{mathmatrix}
1373
1374\installcommandhandler \??mathmatrix {mathmatrix} \??mathmatrix
1375
1376\setupmathmatrix
1377  [\c!distance=\emwidth,
1378   \c!fences=,
1379   \c!left=,
1380   \c!right=,
1381   \c!align=\v!middle,
1382   \c!leftmargin=\zeropoint,
1383   \c!rightmargin=\zeropoint,
1384   \c!rulecolor=,
1385   \c!rulethickness=\linewidth]
1386
1387\appendtoks
1388    \frozen\instance\protected\edefcsname\e!start\currentmathmatrix\endcsname{\math_matrix_start[\currentmathmatrix]}%
1389    % \noaligned\protected should work here:
1390    \frozen\instance          \defcsname \e!stop \currentmathmatrix\endcsname{\math_matrix_stop}% no u else lookahead problem
1391\to \everydefinemathmatrix
1392
1393\newinteger\c_math_matrix_columns
1394
1395\def\math_matrix_start_table
1396  {\global\c_math_eqalign_column\zerocount
1397   \global\c_math_eqalign_row\zerocount
1398   \global\c_math_matrix_columns\zerocount
1399   \dostarttagged\t!math\empty
1400   \dostarttagged\t!mtable\empty}
1401
1402\def\math_matrix_stop_table
1403  {\dostoptagged
1404   \dostoptagged}
1405
1406\def\math_matrix_start_row
1407  {\beginlocalcontrol
1408   \global\c_math_matrix_columns\c_math_eqalign_column
1409   \global\c_math_eqalign_column\zerocount
1410   \global\advanceby\c_math_eqalign_row\plusone
1411   \dostarttagged\t!mtablerow\empty
1412   \endlocalcontrol}
1413
1414\def\math_matrix_stop_row
1415  {\beginlocalcontrol
1416   \dostoptagged
1417   \endlocalcontrol}
1418
1419\protected\def\math_matrix_start_cell
1420  {\dostarttagged\t!mtablecell\empty
1421   \hss
1422   \math_left_of_eqalign
1423   \startimath
1424   \math_matrix_set_style
1425   \everycr\emptytoks}
1426
1427\protected\def\math_matrix_stop_cell
1428  {\stopimath
1429   \math_right_of_eqalign
1430   \hss
1431   \dostoptagged}
1432
1433% \dorecurse{10}{test }
1434%
1435% \startformula
1436%     \startmatrix[left=\left(,right=\right)]
1437%       \NC x \NC       \NC yy \NC       \NC zzz \NR
1438%       \NC x \NC \dots \NC yy \NC \dots \NC zzz \NR
1439%       \HF[2]                                   \NR
1440%       \NC x \NC \dots \NC yy \NC \dots \NC zzz \NR
1441%       \HF                                      \NR
1442%       \NC x \NC \dots \NC yy \NC \dots \NC zzz \NR
1443%       \NC \HF[2]                               \NR
1444%       \NC x \NC \dots \NC yy \NC \dots \NC zzz \NR
1445%       \NC \NC \HF[2][rule]                     \NR
1446%       \NC x \NC \dots \NC yy \NC \dots \NC zzz \NR
1447%       \HL
1448%       \NC x \VL \dots \VL yy \NC \dots \VL zzz \NR
1449%       \NC x \VL \dots \VL yy \NC \dots \VL zzz \NR
1450%       \HL
1451%     \stopmatrix
1452% \stopformula
1453%
1454% \dorecurse{10}{test }
1455%
1456% \startformula
1457%     \startmatrix[left=\left(,right=\right)]
1458%       \NC        \TT \ttx 1 \NC       \TT \ttx 2 \NC       \TT \ttx 3 \NC        \NR
1459%       \LT \ttx 1 \NC a      \NC \dots \NC aa     \NC \dots \NC aaa    \RT \ttx 1 \NR
1460%       \LT \ttx 2 \NC b      \NC \dots \NC bb     \NC \dots \NC bbb    \RT \ttx 2 \NR
1461%       \LT \ttx 3 \NC c      \NC \dots \NC cc     \NC \dots \NC ccc    \RT \ttx 3 \NR
1462%       \NC        \BT \ttx 1 \NC       \BT \ttx 2 \NC       \BT \ttx 3 \NC        \NR
1463%     \stopmatrix
1464% \stopformula
1465%
1466% \dorecurse{10}{test }
1467%
1468% \startformula
1469%     \startmatrix[left=\left(,right=\right)]
1470%       \NC        \TT \ttx 1 \NC       \TT \ttx 2 \NC       \TT \ttx 3 \NR
1471%       \LT \ttx 1 \NC a      \NC \dots \NC aa     \NC \dots \NC aaa    \NR
1472%       \LT \ttx 2 \NC b      \NC \dots \NC bb     \NC \dots \NC bbb    \NR
1473%       \LT \ttx 3 \NC c      \NC \dots \NC cc     \NC \dots \NC ccc    \NR
1474%       \NC        \BT \ttx 1 \NC       \BT \ttx 2 \NC       \BT \ttx 3 \NR
1475%     \stopmatrix
1476% \stopformula
1477%
1478% \dorecurse{10}{test }
1479
1480\newtoks\everymathmatrix
1481
1482\tolerant\permanent\def\math_matrix_HF[#1]#*[#2]% [n] [name] | [name] | [n]
1483  {\expandedloop
1484     \plusone
1485     \numexpr\ifchknumber#1\or\lastchknumber\else(\c_math_matrix_columns+\minusone)\fi*\plustwo\relax
1486     \plusone
1487   {\omit\span}%
1488   \normalexpanded{\filler[%
1489     \ifcsname\??filleralternative matrix:#1\endcsname matrix:#1\orelse
1490     \ifcsname\??filleralternative matrix:#2\endcsname matrix:#2\orelse
1491     \ifcsname\??filleralternative        #1\endcsname        #1\orelse
1492     \ifcsname\??filleralternative        #2\endcsname        #2\else
1493                                                matrix:\v!normal\fi
1494   ]}}
1495
1496\appendtoks
1497   \enforced\let\HF\math_matrix_HF
1498\to \everymathmatrix
1499
1500\definefiller
1501  [matrix:\v!normal]
1502  [\c!symbol=\textperiod,
1503   \c!style=\v!normal,
1504   \c!method=\v!broad,
1505   \c!width=\emwidth,
1506   \c!leftmargin=-.1\emwidth,
1507   \c!rightmargin=-.1\emwidth]
1508
1509\definefiller
1510  [matrix:\v!middle]
1511  [\c!symbol=\textperiod,
1512   \c!style=\v!normal,
1513   \c!method=\v!middle,
1514   \c!width=\emwidth,
1515   \c!leftmargin=.5\emwidth,
1516   \c!rightmargin=.5\emwidth]
1517
1518\definefiller
1519  [matrix:ldots]
1520  [matrix:\v!normal]
1521
1522\definefiller
1523  [matrix:cdots]
1524  [matrix:\v!normal]
1525  [\c!symbol=\cdot]
1526
1527% We could construct a preamble with alignment and such embedded but the number
1528% of matrices with many rows is normally so low that it doesn't pay of at all.
1529
1530\newconditional\c_math_matrix_first
1531\newconstant   \c_math_matrix_anchor_mode
1532\newconditional\c_math_matrix_sl_seen
1533
1534% enabled    : 1
1535% left/both  : 2
1536% right/both : 4
1537
1538\permanent\protected\def\setmathmatrixanchoring[#1]%
1539  {\c_math_matrix_anchor_mode\zerocount
1540   \processaction
1541     [#1]%
1542     [\v!both=>\c_math_matrix_anchor_mode\plusone,%
1543       \v!yes=>\c_math_matrix_anchor_mode\plusone]}
1544
1545\def\math_matrix_anchor
1546  {\ifcase\c_math_matrix_anchor_mode\else
1547     \markanchor{matrix}{\numexpr\c_math_eqalign_column+\plusone\relax}\c_math_eqalign_row
1548   \fi}
1549
1550\protected\def\math_matrix_anchor_first
1551  {\relax
1552   \ifcase\c_math_matrix_anchor_mode\else
1553     \math_matrix_anchor
1554   % \ifdim\d_math_eqalign_distance>\zeropoint
1555   %   \ifbitwiseand\c_math_matrix_anchor_mode\plustwo
1556   %      \kern.5\d_math_eqalign_distance
1557   %   \fi
1558   % \fi
1559   \fi}
1560
1561\protected\def\math_matrix_anchor_last
1562  {\relax
1563   \ifcase\c_math_matrix_anchor_mode\else
1564   % \ifdim\d_math_eqalign_distance>\zeropoint
1565   %   \ifbitwiseand\c_math_matrix_anchor_mode\plusfour
1566   %     \kern.5\d_math_eqalign_distance
1567   %   \fi
1568   % \fi
1569     \math_matrix_anchor
1570   \fi}
1571
1572\def\math_matrix_preamble
1573  {\math_matrix_strut
1574   \math_matrix_anchor_first
1575   \global\advanceby\c_math_eqalign_column\plusone
1576   \math_matrix_start_cell
1577     \aligncontent
1578   \math_matrix_stop_cell
1579   \aligntab
1580   \aligntab
1581   \math_matrix_anchor
1582   \kern.5\d_math_eqalign_distance
1583   \aligncontent
1584   \aligntab
1585   \global\advanceby\c_math_eqalign_column\plusone
1586   \math_matrix_start_cell
1587     \aligncontent
1588   \math_matrix_stop_cell}
1589
1590\permanent\protected\def\math_matrix_NR
1591  {\math_matrix_anchor_last
1592   \math_matrix_stop_row
1593   \math_matrix_pickup
1594   \crcr
1595   \math_matrix_start_row}
1596
1597\permanent\protected\def\math_matrix_NC
1598  {\ifconditional\c_math_matrix_first
1599     \expandafter\math_matrix_NC_yes
1600   \else
1601     \expandafter\math_matrix_NC_nop
1602   \fi}
1603
1604\permanent\protected\def\math_matrix_pickup{\global\c_math_matrix_first\conditionaltrue}
1605\permanent\protected\def\math_matrix_NC_yes{\global\c_math_matrix_first\conditionalfalse}
1606\permanent\protected\def\math_matrix_NC_nop{\aligntab\aligntab} % avoids lookahead
1607
1608\def\math_matrix_check_rule_step#1%
1609  {\ifchkdim#1\or
1610     \scratchdimen#1\relax
1611   \orelse\ifchknum#1\or
1612     \scratchdimen#1\d_math_eqalign_rulethickness
1613   \else
1614     \edef\p_rulecolor{#1}
1615   \fi}
1616
1617\def\math_matrix_check_rule[#1]%
1618  {\d_math_eqalign_rulethickness\mathmatrixparameter\c!rulethickness\relax
1619   \scratchdimen\d_math_eqalign_rulethickness
1620   \edef\p_rulecolor{\mathmatrixparameter\c!rulecolor}%
1621   \ifempty{#1}\else
1622     \rawprocesscommalist[#1]\math_matrix_check_rule_step
1623   \fi
1624   \ifempty\p_rulecolor\else
1625     \dousecolorparameter\p_rulecolor
1626   \fi}
1627
1628% These offset are an experiment so we abuse some existing keys or we have to
1629% cook up new ones. Maybe we then should provide small medium big halfline etc.
1630% but all depends on actual demand for this feature.
1631
1632% Musical timestamp VL, NL, SL: Bad Hombre II by Antonio Sanches
1633%
1634% \startformula
1635% \startmatrix[left=\left(,right=\right)]
1636% \NC 0  \NL 0  \NC 0  \NC 2x \NC 1  \NC 0  \NC 0  \NL \NR
1637% \NC 0  \VL 0  \NC 0  \NC 0  \NC 2x \NC 0  \NC 0  \NL \NR
1638% \NC 0  \VL 0  \NC 0  \NC 0  \NC 0  \NC 3x \NC 0  \NL \NR
1639% \NC 0  \NL 0  \NC 0  \NC 0  \NC 0  \NC 0  \NC 4x \VL \NR
1640% \stopmatrix
1641% \stopformula
1642%
1643% \startformula
1644% \startmatrix[left=\left(,right=\right)]
1645% \SL[3]               \NL    \NL    \NL    \NL    \NL \NR
1646% \VL 2x \NL 1  \NL 0  \VL 0  \NL 0  \NL 0  \NL 0  \NL \NR
1647% \VL 0  \NL 2x \NL 1  \VL 0  \NL 0  \NL 0  \NL 0  \NL \NR
1648% \VL 0  \NL 0  \NL 2x \VL 0  \NL 0  \NL 0  \NL 0  \NL \NR
1649% \SL[5]                             \NL    \NL    \NL \NR
1650% \NL 0  \NL 0  \NL 0  \VL 2x \NL 1  \VL 0  \NL 0  \NL \NR
1651% \NL 0  \NL 0  \NL 0  \VL 0  \NL 2x \VL 0  \NL 0  \NL \NR
1652% \NL    \NL    \NL    \SL[3]               \NL    \NL \NR
1653% \NL 0  \NL 0  \NL 0  \NL 0  \NL 0  \VL 3x \VL 0  \NL \NR
1654% \NL    \NL    \NL    \NL    \NL    \SL[2]        \NL \NR
1655% \NL 0  \NL 0  \NL 0  \NL 0  \NL 0  \NL 0  \VL 3x \VL \NR
1656% \NL    \NL    \NL    \NL    \NL    \NL    \SL[1] \NL \NR
1657% \stopmatrix
1658% \stopformula
1659
1660\definesystemattribute[mathalignmentvrule][public]
1661\definesystemattribute[mathalignmenthrule][public]
1662\definesystemattribute[mathalignmenttop]  [public]
1663\definesystemattribute[mathalignmentmid]  [public]
1664\definesystemattribute[mathalignmentbot]  [public]
1665
1666\setupmathmatrix
1667  [\c!moffset=.25\exheight,
1668   \c!toffset=\mathmatrixparameter\c!moffset,
1669   \c!boffset=\mathmatrixparameter\c!toffset]
1670
1671\newconditional\c_math_matrix_trace_hl
1672
1673\installtextracker
1674  {math.matrices.hl}
1675  {\settrue\c_math_matrix_trace_hl}
1676  {\setfalse\c_math_matrix_trace_hl}
1677
1678\def\math_matrix_HL_indeed#1#2%
1679  {\noalign\bgroup
1680     \math_matrix_check_rule[#2]%
1681     \divideby\scratchdimen\plustwo
1682     \ifdim\scratchdimen>\zeropoint
1683\attribute\mathalignmenttopattribute\dimexpr\mathmatrixparameter\c!toffset\relax
1684\attribute\mathalignmentbotattribute\dimexpr\mathmatrixparameter\c!boffset\relax
1685       \scratchdistance\mathmatrixparameter\c!moffset\relax
1686       \ifdim\scratchdistance>\zeropoint
1687\begingroup
1688\ifconditional\c_math_matrix_trace_hl
1689         \darkred
1690         \hrule
1691           \s!width \onepoint
1692\else
1693         \nohrule
1694\fi
1695           \s!attr  \mathalignmentvruleattribute\plustwo
1696           \s!height\scratchdistance
1697           \s!depth \zeropoint
1698         \relax
1699\endgroup
1700       \fi
1701       \hrule
1702         \s!attr  \mathalignmentvruleattribute\plusthree
1703         \s!height\scratchdimen
1704         \s!depth \scratchdimen
1705       \relax
1706       \scratchdimentwo\zeropoint
1707       \ifnum#1>\plusone
1708         \scratchdimenone.125\d_math_eqalign_distance
1709         \localcontrolledloop\plustwo#1\plusone
1710            {\kern\scratchdimenone
1711             \advanceby\scratchdimentwo\scratchdimenone
1712             \hrule
1713               \s!attr  \mathalignmentvruleattribute\plusthree
1714               \s!height\scratchdimen
1715               \s!depth \scratchdimen
1716             \relax
1717             \advanceby\scratchdimentwo\scratchdimen
1718             \advanceby\scratchdimentwo\scratchdimen
1719            }%
1720%          \kern-2\scratchdimen
1721%          \kern-.125\d_math_eqalign_distance
1722       \fi
1723%        \scratchdistance\mathmatrixparameter\c!moffset\relax
1724       \ifdim\scratchdistance>\zeropoint
1725\begingroup
1726\ifconditional\c_math_matrix_trace_hl
1727         \darkgreen
1728         \hrule
1729           \s!width \onepoint
1730\else
1731         \nohrule
1732\fi
1733           \s!attr  \mathalignmentvruleattribute\plusfour
1734           \s!attr  \mathalignmentmidattribute\scratchdimentwo
1735           \s!height\zeropoint
1736           \s!depth \scratchdistance
1737         \relax
1738\endgroup
1739       \fi
1740     \else
1741        % zero dimensions disable the rule
1742     \fi
1743   \egroup}
1744
1745\permanent\tolerant\noaligned\protected\def\math_matrix_HL  [#1]#*{\math_matrix_HL_indeed\plusone{#1}}
1746\permanent\tolerant\noaligned\protected\def\math_matrix_HLHL[#1]#*{\math_matrix_HL_indeed\plustwo{#1}}
1747
1748\protected\def\math_matrix_vertical_rule_indeed#1#2%
1749  {\math_matrix_check_rule[#2]%
1750   \enablematrixrules
1751   #1
1752      \s!attr   \mathalignmentvruleattribute\plusone
1753      \s!width  \scratchdimen
1754      \s!top   -\dimexpr\mathmatrixparameter\c!toffset\relax
1755      \s!bottom-\dimexpr\mathmatrixparameter\c!boffset\relax
1756   \relax}
1757
1758\protected\def\math_matrix_vertical_rule_yes{\math_matrix_vertical_rule_indeed\vrule  }
1759\protected\def\math_matrix_vertical_rule_nop{\math_matrix_vertical_rule_indeed\novrule}
1760
1761\installcorenamespace{mathmatrixrulealternative}
1762
1763\newboundary\c_math_matrix_vl_boundary
1764%newboundary\c_math_matrix_sl_boundary
1765
1766\protected\def\math_matrix_horizontal_rule_indeed#1#2%
1767  {\math_matrix_check_rule[#2]%
1768   \global\c_math_matrix_first\conditionalfalse
1769   \global\c_math_matrix_sl_seen\conditionaltrue
1770   \enablematrixrules
1771 % \begingroup
1772 % \attribute\mathalignmenthruleattribute\plusone % we check the glue
1773   \leaders#1%
1774      \s!attr   \mathalignmenthruleattribute\plusone
1775      \s!height .5\scratchdimen
1776      \s!depth  .5\scratchdimen
1777    % \s!top   -\dimexpr\mathmatrixparameter\c!toffset\relax
1778    % \s!bottom-\dimexpr\mathmatrixparameter\c!boffset\relax
1779   \hfilll
1780 % \endgroup
1781   \kern\dimexpr.5\d_math_eqalign_distance\relax
1782   \aligntab}
1783
1784\protected\def\math_matrix_horizontal_rule_yes{\math_matrix_horizontal_rule_indeed\hrule  }
1785\protected\def\math_matrix_horizontal_rule_nop{\math_matrix_horizontal_rule_indeed\nohrule}
1786
1787\def\math_matrix_hrule_progress_rest#1%
1788  {\expandedloop
1789     \plusone
1790     \numexpr(\ifchknumber#1\or\lastchknumber\else\c_math_matrix_columns\fi)*\plustwo+\minusone\relax
1791     \plusone
1792   {\span\omit}}%
1793
1794\def\math_matrix_hrule_progress_first#1%
1795  {\expandedloop
1796     \plusone
1797     \numexpr(\ifchknumber#1\or\lastchknumber\else\c_math_matrix_columns\fi+\minusone)*\plustwo+\plusone\relax
1798     \plusone
1799   {\span\omit}}%
1800
1801\def\math_matrix_hrule_progress
1802  {\NL
1803   \ifconditional\c_math_matrix_first
1804     \expandafter\math_matrix_hrule_progress_first
1805   \else
1806     \expandafter\math_matrix_hrule_progress_rest
1807   \fi}
1808
1809\tolerant\permanent\protected\def\SL[#1]#*[#2]#*% [n] [name] | [name] | [n]
1810  {\ifcsname\??mathmatrixrulealternative#2\endcsname
1811     \lastnamedcs{#1}{#2}%
1812   \orelse\ifcsname\??mathmatrixrulealternative#1\endcsname
1813     \lastnamedcs{#2}{#1}%
1814   \else
1815     \csname\??mathmatrixrulealternative\v!auto\endcsname{#1}{#2}%
1816   \fi}
1817
1818\defcsname\??mathmatrixrulealternative\v!auto\endcsname#1#2%
1819  {\math_matrix_hrule_progress{#1}%
1820 % \ifzero\c_math_matrix_first
1821 %   \kern-\dimexpr\linewidth\relax
1822 % \else
1823 %   \kern-\dimexpr.5\d_math_eqalign_distance+\linewidth\relax
1824 % \fi
1825   \kern-\dimexpr\ifzero\c_math_matrix_first\else.5\d_math_eqalign_distance+\fi\linewidth\relax
1826   \math_matrix_horizontal_rule_yes{#2}%
1827   %boundary\c_math_matrix_sl_boundary
1828   \enforced\let\NR\math_matrix_NL_NR}
1829
1830% \permanent\tolerant\protected\def\math_matrix_VL[#1]#*%
1831%   {\span\omit
1832%    \ifconditional\c_math_matrix_first\else
1833%      \kern.5\d_math_eqalign_distance
1834%    \fi
1835%    \math_matrix_vertical_rule_yes{#1}%
1836%    \kern.5\d_math_eqalign_distance
1837%    \global\c_math_matrix_first\conditionalfalse
1838%    \aligntab
1839%    \boundary\c_math_matrix_vl_boundary
1840%    \enforced\let\NR\math_matrix_NL_NR
1841%    }
1842
1843\def\math_matrix_VL_indeed#1#2%%
1844  {\span\omit
1845   \ifconditional\c_math_matrix_first\else
1846     \kern.5\d_math_eqalign_distance
1847   \fi
1848   \math_matrix_vertical_rule_yes{#2}%
1849   \localcontrolledloop\plustwo#1\plusone
1850     {\kern.125\d_math_eqalign_distance
1851      \math_matrix_vertical_rule_yes{#2}}%
1852   \kern.5\d_math_eqalign_distance
1853   \global\c_math_matrix_first\conditionalfalse
1854   \aligntab
1855   \boundary\c_math_matrix_vl_boundary
1856   \enforced\let\NR\math_matrix_NL_NR
1857   }
1858
1859\permanent\tolerant\protected\def\math_matrix_VL  [#1]#*{\math_matrix_VL_indeed\plusone{#1}}
1860\permanent\tolerant\protected\def\math_matrix_VLVL[#1]#*{\math_matrix_VL_indeed\plustwo{#1}}
1861
1862\permanent\tolerant\protected\def\math_matrix_NL[#1]#*%
1863  {\span\omit
1864   \ifconditional\c_math_matrix_first\else
1865     \kern.5\d_math_eqalign_distance
1866   \fi
1867   \math_matrix_vertical_rule_nop{#1}%
1868   \kern.5\d_math_eqalign_distance
1869   \global\c_math_matrix_first\conditionalfalse
1870   \aligntab
1871   \boundary\c_math_matrix_vl_boundary
1872   \enforced\let\NR\math_matrix_NL_NR}
1873
1874\permanent\protected\def\math_matrix_NL_NR
1875  {\ifnum\lastboundary=\c_math_matrix_vl_boundary
1876     \ifconditional \c_math_matrix_sl_seen
1877       \kern-1.5\d_math_eqalign_distance
1878     \else
1879       \kern-.5\d_math_eqalign_distance
1880     \fi
1881   \fi
1882   \math_matrix_anchor_last
1883   \math_matrix_stop_row
1884   \math_matrix_pickup
1885   \crcr
1886   \math_matrix_start_row}
1887
1888\appendtoks
1889   \enforced\let\NL\math_matrix_NL
1890   \global\c_math_matrix_sl_seen\conditionalfalse
1891\to \everymathmatrix
1892
1893\permanent\tolerant\protected\def\math_matrix_VC[#1]#*%
1894  {\NC
1895   \math_matrix_vertical_rule_yes{#1}%
1896   \NC}
1897
1898\permanent\tolerant\protected\def\math_matrix_VT[#1]#*%
1899  {\span\omit
1900   \math_matrix_vertical_rule_yes{#1}%
1901   \aligntab}
1902
1903\def\math_matrix_start_row
1904  {\beginlocalcontrol
1905   \global\c_math_matrix_columns\c_math_eqalign_column
1906   \global\c_math_eqalign_column\zerocount
1907   \global\advanceby\c_math_eqalign_row\plusone
1908   \dostarttagged\t!mtablerow\empty
1909   \endlocalcontrol}
1910
1911\appendtoks
1912   \enforced\let\NR\math_matrix_NR
1913   \enforced\let\NC\math_matrix_NC
1914   \enforced\let\MC\math_matrix_NC
1915   \enforced\let\HL\math_matrix_HL % like the old ones
1916   \enforced\let\VL\math_matrix_VL % like the old ones
1917   \enforced\let\VC\math_matrix_VC % bonus, extra column
1918   \enforced\let\VT\math_matrix_VT % bonus, idem but tight
1919   \enforced\let\TB\math_common_TB
1920   % just because it's easy:
1921   \enforced\let\VLVL\math_matrix_VLVL
1922   \enforced\let\HLHL\math_matrix_HLHL
1923\to \everymathmatrix
1924
1925% \definesystemattribute[mathmatrixornament][public]
1926
1927\newdimension\d_math_matrix_margin_l
1928\newdimension\d_math_matrix_margin_r
1929\newdimension\d_math_matrix_margin_t
1930\newdimension\d_math_matrix_margin_b
1931
1932\newdimension\d_math_matrix_max_left
1933\newdimension\d_math_matrix_max_right
1934
1935\newboundary \c_math_matrix_ornament_l
1936\newboundary \c_math_matrix_ornament_r
1937\newboundary \c_math_matrix_ornament_t
1938\newboundary \c_math_matrix_ornament_b
1939
1940% anchors are wrong now
1941
1942\newconditional\c_math_matrix_text
1943\newconditional\c_math_matrix_text_l
1944\newconditional\c_math_matrix_text_r
1945\newconditional\c_math_matrix_text_t
1946\newconditional\c_math_matrix_text_b
1947
1948\def\math_matrix_ornaments#1#2%
1949  {\NC
1950   \enablematrixornaments
1951   \global\c_math_matrix_text\conditionaltrue
1952   \global\settrue#1%
1953   \boundary#2%
1954   \ignorespaces}
1955
1956\permanent\protected\def\math_matrix_LT{\math_matrix_ornaments\c_math_matrix_text_l\c_math_matrix_ornament_l}
1957\permanent\protected\def\math_matrix_RT{\math_matrix_ornaments\c_math_matrix_text_r\c_math_matrix_ornament_r}
1958\permanent\protected\def\math_matrix_TT{\math_matrix_ornaments\c_math_matrix_text_t\c_math_matrix_ornament_t}
1959\permanent\protected\def\math_matrix_BT{\math_matrix_ornaments\c_math_matrix_text_b\c_math_matrix_ornament_b}
1960
1961\appendtoks
1962   \global\c_math_matrix_text\conditionalfalse
1963   \global\c_math_matrix_text_l\conditionalfalse
1964   \global\c_math_matrix_text_r\conditionalfalse
1965   \global\c_math_matrix_text_t\conditionalfalse
1966   \global\c_math_matrix_text_b\conditionalfalse
1967   \enforced\let\LT\math_matrix_LT
1968   \enforced\let\RT\math_matrix_RT
1969   \enforced\let\TT\math_matrix_TT
1970   \enforced\let\BT\math_matrix_BT
1971\to \everymathmatrix
1972
1973\newconditional\c_math_matrix_text_mode
1974
1975\def\math_matrix_start_processing
1976  {%
1977   \ifmmode
1978     \setfalse\c_math_matrix_text_mode
1979   \else
1980     \settrue\c_math_matrix_text_mode
1981   \fi
1982   \ifconditional\c_math_matrix_text_mode
1983     \dontleavehmode
1984   \else
1985     \mathmatrixparameter\c!left\relax
1986     \math_fenced_start_wrap{\mathmatrixparameter\c!fences}%
1987%      \mathatom \s!class \mathwrappedcode
1988     \mathatom \s!class \mathconstructcode
1989   \fi
1990   \bgroup
1991   \d_math_matrix_margin_l\mathmatrixparameter\c!leftmargin \relax
1992   \d_math_matrix_margin_r\mathmatrixparameter\c!rightmargin\relax
1993   \d_math_matrix_margin_t\strutdp
1994   \d_math_matrix_margin_b\strutht
1995   \global\d_math_matrix_max_left \zeropoint
1996   \global\d_math_matrix_max_right\zeropoint
1997  %\tabskip.5\d_math_eqalign_distance
1998   \tabskip\zeroskip
1999   \math_matrix_pickup
2000   \expand\everymathmatrix
2001   %
2002   \setbox\nextbox\vbox\bgroup
2003   \math_matrix_start_table
2004   \halign
2005      \s!callback
2006        \align_callback_mathmatrix
2007   \bgroup
2008     % preamble
2009     \span\math_matrix_preamble
2010     % done
2011     \crcr
2012     \math_matrix_start_row}
2013
2014\def\math_matrix_stop_processing
2015  {%\math_matrix_stop_wrapup % optional
2016   \math_matrix_stop_row
2017   \egroup
2018   \math_matrix_stop_table
2019   \egroup
2020   \mathmatrixleft  % experimental hook
2021   \math_matrix_finish_nextbox
2022   \mathmatrixright % experimental hook
2023   \egroup
2024   \ifconditional\c_math_matrix_text_mode\else
2025     \math_fenced_stop_wrap
2026     \mathmatrixparameter\c!right\relax
2027   \fi}
2028
2029\permanent\protected\def\mathmatrixmaxleftwidth {\d_math_matrix_max_left }
2030\permanent\protected\def\mathmatrixmaxrightwidth{\d_math_matrix_max_right}
2031
2032\let\math_matrix_strut    \strut
2033\let\math_matrix_set_style\relax
2034
2035\def\math_matrix_check_settings
2036  {\edef\p_strut{\mathmatrixparameter\c!strut}%
2037   \ifx\p_strut\v!no
2038     \enforced\let\math_matrix_strut\relax
2039   \else
2040     \enforced\let\math_matrix_strut\strut
2041     \ifx\p_strut\v!yes\else
2042       \spacing\p_strut
2043     \fi
2044   \fi
2045   \d_math_eqalign_distance\mathmatrixparameter\c!distance\relax
2046 % \d_math_eqalign_rulethickness\mathmatrixparameter\c!rulethickness\relax
2047 % \edef\p_rulecolor{\mathmatrixparameter\c!rulecolor}
2048   \edef\math_matrix_set_style{\mathmatrixparameter\c!style}}
2049
2050\newinteger\c_math_eqalign_column_saved
2051\newinteger\c_math_eqalign_row_saved
2052
2053% \installglobalmacrostack\c_math_matrix_first
2054
2055\tolerant\protected\def\math_matrix_start[#1]#*[#S#2]%
2056  {\begingroup
2057   \globalpushmacro\c_math_matrix_first % hm, does that work?
2058   \c_math_eqalign_column_saved\c_math_eqalign_column
2059   \c_math_eqalign_row_saved\c_math_eqalign_row
2060   \globalpushmacro\c_math_eqalign_first
2061   \cdef\currentmathmatrix{#1}%
2062   \setupcurrentmathmatrix[#2]%
2063   \math_matrix_check_settings
2064   \math_eqalign_set_defaults
2065   \math_eqalign_set_columns{\mathmatrixparameter\c!align}%
2066   \math_matrix_start_processing}
2067
2068\def\math_matrix_stop
2069  {\math_matrix_stop_processing
2070   \globalpushmacro\c_math_eqalign_first
2071   \global\c_math_eqalign_column\c_math_eqalign_column_saved
2072   \global\c_math_eqalign_row\c_math_eqalign_row_saved
2073   \globalpopmacro\c_math_matrix_first
2074   \endgroup}
2075
2076% vcenter:
2077%
2078% delta     = (height(v) + depth(v))/2
2079% axis      = math_axis_size(cur_size)
2080% height(v) = delta + axis
2081% depth(v)  = delta - axis
2082
2083\installcorenamespace{mathmatrixalignlocation}
2084
2085\mutable\lettonothing\mathmatrixleft  % experimental hook
2086\mutable\lettonothing\mathmatrixright % experimental hook
2087
2088% This alignment option will either go away or become a atom property (key).
2089
2090\defcsname\??mathmatrixalignlocation\v!top   \endcsname{\raise\dimexpr(\nextboxdp-\nextboxht)/2 +\mathaxisheight\mathstyle\relax}
2091\defcsname\??mathmatrixalignlocation\v!high  \endcsname{\raise\dimexpr(\nextboxdp-\nextboxht)/2\relax}
2092\defcsname\??mathmatrixalignlocation\v!center\endcsname{\relax}
2093\defcsname\??mathmatrixalignlocation\v!lohi  \endcsname{\relax}
2094\defcsname\??mathmatrixalignlocation\v!normal\endcsname{\relax}
2095\defcsname\??mathmatrixalignlocation\v!bottom\endcsname{\lower\dimexpr(\nextboxdp-\nextboxht)/2 +\mathaxisheight\mathstyle\relax}
2096\defcsname\??mathmatrixalignlocation\v!low   \endcsname{\lower\dimexpr(\nextboxdp-\nextboxht)/2\relax}
2097
2098\def\math_matrix_finish_nextbox
2099  {\scratchcounter\mathstyle\relax
2100   \scratchwidth\wd\nextbox
2101\setbox\scratchbox\hbox\bgroup
2102   \begincsname\??mathmatrixalignlocation\mathmatrixparameter\c!location\endcsname\hbox\bgroup
2103     \normalstartimath
2104     \givenmathstyle\scratchcounter
2105     \ifzeropt\d_math_matrix_margin_l\else\kern\d_math_matrix_margin_l\fi
2106     \ifconditional\c_math_matrix_text_mode
2107       \mathmatrixparameter\c!left\relax
2108       \math_fenced_start_wrap{\mathmatrixparameter\c!fences}%
2109       \mathatom \s!class \mathconstructcode {\vcenter{\box\nextbox}}% \was \vcenter
2110       \math_fenced_stop_wrap
2111       \mathmatrixparameter\c!right\relax
2112     \else
2113        \vcenter{\box\nextbox}% \was \vcenter
2114     \fi
2115     \ifzeropt\d_math_matrix_margin_r\else\kern\d_math_matrix_margin_r\fi
2116     \normalstopimath
2117   \egroup
2118\egroup
2119   \ifconditional\c_math_matrix_text
2120     \ifempty{\mathmatrixparameter\c!left\mathmatrixparameter\c!right\mathmatrixparameter\c!fences}\else
2121       \scratchdistance\dimexpr(\wd\scratchbox-\scratchwidth)/\plustwo\relax
2122       \advanceby\d_math_matrix_margin_l\scratchdistance
2123       \advanceby\d_math_matrix_margin_r\scratchdistance
2124       \clf_shiftmatrixornaments\scratchbox
2125     \fi
2126   \fi
2127   \ifconditional\c_math_matrix_text_b
2128     \dp\scratchbox\dimexpr\dp\scratchbox+\lineheight\relax
2129   \fi
2130   \ifconditional\c_math_matrix_text_t
2131     \ht\scratchbox\dimexpr\ht\scratchbox+\lineheight\relax
2132   \fi
2133   \edef\p_leftedge {\mathmatrixparameter\c!leftedge }%
2134   \edef\p_rightedge{\mathmatrixparameter\c!rightedge}%
2135   \ifempty\p_leftedge\else
2136     \hskip\dimexpr\d_math_matrix_max_left+\p_leftedge\relax
2137   \fi
2138%    \ifconditional\c_math_matrix_text_mode
2139     \box\scratchbox
2140%    \else
2141%      \mathatom \s!class \mathconstructcode {\box\scratchbox}%
2142%    \fi
2143   \ifempty\p_rightedge\else
2144     \hskip\dimexpr\d_math_matrix_max_right+\p_rightedge\relax
2145   \fi
2146   }
2147
2148\definemathmatrix[matrix]
2149\definemathmatrix[\v!mathmatrix]
2150
2151%D \startbuffer
2152%D \placeformula \startformula[-] \startmatrix
2153%D \NC 1 \NC x \NC a \NR
2154%D \NC 2 \NC y \NC b \NR
2155%D \NC 3 \NC z \NC c \NR
2156%D \stopmatrix \stopformula
2157%D \stopbuffer
2158%D
2159%D \typebuffer \getbuffer
2160%D
2161%D \definemathmatrix[bmatrix][left={\left[\mskip\thinmuskip},right={\mskip\thinmuskip\right]},strut=1.25]
2162%D
2163%D \startbuffer
2164%D \placeformula \startformula[-] \startbmatrix
2165%D \NC 1 \NC x \NC a \NR
2166%D \NC 2 \NC y \NC b \NR
2167%D \NC 3 \NC z \NC c \NR
2168%D \stopbmatrix \stopformula
2169%D \stopbuffer
2170%D
2171%D \typebuffer \getbuffer
2172%D
2173%D Taco added some code (dedicated to Aditya Mahajan) that gives more
2174%D control over aligments:
2175
2176%D \startbuffer
2177%D \startformula
2178%D   \startmatrix
2179%D    \NC a + x \NC = \NC a + d \NR
2180%D    \NC y     \NC = \NC d     \NR
2181%D   \stopmatrix
2182%D \stopformula
2183%D \stopbuffer
2184%D
2185%D \typebuffer \getbuffer
2186
2187%D \startbuffer
2188%D \startformula
2189%D   \startmatrix [distance=3pt,align={right,left}]
2190%D    \NC a + x \NC = a + d \NR
2191%D    \NC y     \NC = d     \NR
2192%D   \stopmatrix
2193%D \stopformula
2194%D \stopbuffer
2195%D
2196%D \typebuffer \getbuffer
2197
2198%D \startbuffer
2199%D \startformula
2200%D   \startmatrix [left=\left(,right=\right)]
2201%D    \NC a + x \NR
2202%D    \NC y    \NR
2203%D   \stopmatrix
2204%D \stopformula
2205%D \stopbuffer
2206%D
2207%D \typebuffer \getbuffer
2208%D
2209%D A bit more complex code:
2210%D
2211%D \startbuffer
2212%D \startformula
2213%D    \text{Let }{\cal R} = \bigcup_{P_{X_1},P_{X_2}}
2214%D    \left\{ (R_1, R_2) :
2215%D    \startmatrix[distance=1em,align={left,left,right}]
2216%D      \NC R_1        \NC < I(X_1 ; Y \mid X_2)      \NC R_1       \NR
2217%D      \NC \hfill Q_2 \NC < I(X_2 ; Y \mid X_1)      \NC R_2       \NR
2218%D      \NC R_1 + R_2  \NC < I(X_1 ; Y)               \NC R_1 + R_2 \NR
2219%D    \stopmatrix
2220%D    \right\}
2221%D \stopformula
2222%D \stopbuffer
2223%D
2224%D \typebuffer \getbuffer
2225
2226%D \macros
2227%D   {startmatrices}
2228%D
2229%D Just a handy keystroke safer:
2230
2231\permanent\protected\def\startmatrices
2232  {\begingroup
2233   \setupmathmatrix}
2234
2235\permanent\protected\def\stopmatrices
2236  {\endgroup}
2237
2238%D \startbuffer
2239%D \startformula
2240%D   \startmatrix[left={\left(},right={\right)}]
2241%D     \NC A \NC B \NR \NC C \NC D \NR
2242%D   \stopmatrix
2243%D   =
2244%D   \startmatrix[left={\left(},right={\right)},location=low]
2245%D     \NC A \NC B \NR \NC C \NC D \NR
2246%D   \stopmatrix
2247%D   =
2248%D   \startmatrix[left={\left(},right={\right)},location=high]
2249%D     \NC A \NC B \NR \NC C \NC D \NR
2250%D   \stopmatrix
2251%D \stopformula
2252%D \stopbuffer
2253%D
2254%D \typebuffer \getbuffer
2255%D
2256%D \startbuffer
2257%D \startformula
2258%D   \startmatrices[left={\left(},right={\right)}]
2259%D     \startmatrix
2260%D       \NC A \NC B \NR \NC C \NC D \NR
2261%D     \stopmatrix
2262%D     =
2263%D     \startmatrix[location=bottom]
2264%D       \NC A \NC B \NR \NC C \NC D \NR
2265%D     \stopmatrix
2266%D     =
2267%D     \startmatrix[location=top]
2268%D       \NC A \NC B \NR \NC C \NC D \NR
2269%D     \stopmatrix
2270%D   \stopmatrices
2271%D \stopformula
2272%D \stopbuffer
2273%D
2274%D \typebuffer  % does not run well: \getbuffer
2275
2276%D Handy for the \type {m-matrix} module:
2277
2278\permanent\tolerant\protected\def\startnamedmatrix[#1]#*[#S#2]%
2279  {\begingroup
2280   \cdef\currentmathmatrix{#1}%
2281   \setupcurrentmathmatrix[#2]%
2282   \math_matrix_start[\currentmathmatrix]}
2283
2284\noaligned\permanent\protected\def\stopnamedmatrix
2285  {\math_matrix_stop
2286   \endgroup}
2287
2288%D The following code is derived from Aditya's simplematrix prototype but adapted to
2289%D regular mathmatrices. With a little help from \LUA\ we now have this:
2290%D
2291%D \startbuffer
2292%D \definemathmatrix [Pmatrix] [matrix:parentheses]
2293%D   [align={all:right},
2294%D    simplecommand=Pmatrix]
2295%D
2296%D \definemathmatrix [Tmatrix] [Pmatrix]
2297%D   [action=transpose,
2298%D    simplecommand=Tmatrix]
2299%D
2300%D \definemathmatrix [Nmatrix] [Pmatrix]
2301%D   [action=negate,
2302%D    simplecommand=Nmatrix]
2303%D
2304%D \startformula
2305%D     \Pmatrix{ -1, 2, 3; 4,-5, 6; 7, 8,-9 } \neq
2306%D     \Tmatrix{ -1, 2, 3; 4,-5, 6; 7, 8,-9 } \neq
2307%D     \Nmatrix{ -1, 2, 3; 4,-5, 6; 7, 8,-9 }
2308%D \stopformula
2309%D \stopbuffer
2310%D
2311%D \typebuffer \getbuffer
2312
2313\permanent\tolerant\protected\def\math_matrix_simple[#1]#*[#S#2]#:#3%
2314  {\begingroup
2315   \cdef\currentmathmatrix{#1}%
2316   \setupcurrentmathmatrix[#2]%
2317   \math_matrix_start[\currentmathmatrix]%
2318   \clf_simplematrix{\mathmatrixparameter\c!action}{#3}%
2319   \math_matrix_stop
2320   \endgroup}
2321
2322%D We hook it into the normal mathmatrix code:
2323
2324\appendtoks
2325    \edef\p_simplecommand{\mathmatrixparameter\c!simplecommand}%
2326    \ifempty\p_simplecommand\else
2327        \frozen\protected\instance\edefcsname\p_simplecommand\endcsname{\math_matrix_simple[\currentmathmatrix]}%
2328    \fi
2329\to \everydefinemathmatrix
2330
2331%D And predefine some matrices:
2332
2333% \definemathmatrix[matrix:parentheses][\c!left={\left(\mskip\thinmuskip},\c!right={\mskip\thinmuskip\right)},\c!align=\v!middle]
2334% \definemathmatrix[matrix:brackets]   [\c!left={\left[\mskip\thinmuskip},\c!right={\mskip\thinmuskip\right]},\c!align=\v!middle]
2335% \definemathmatrix[matrix:bars]       [\c!left={\left|\mskip\thinmuskip},\c!right={\mskip\thinmuskip\right|},\c!align=\v!middle]
2336
2337\definemathmatrix
2338  [matrix:none]
2339  [\c!align=\v!middle,
2340   \c!simplecommand=matrix]
2341
2342\definemathmatrix
2343  [matrix:brackets]
2344  [\c!fences=bracket,
2345   \c!align=\v!middle,
2346   \c!simplecommand=bmatrix]
2347
2348\definemathmatrix
2349  [matrix:parentheses]
2350  [\c!fences=parenthesis,
2351   \c!align=\v!middle,
2352   \c!simplecommand=pmatrix]
2353
2354\definemathmatrix
2355  [matrix:bars]
2356  [\c!fences=bar,
2357   \c!align=\v!middle,
2358   \c!simplecommand=vmatrix]
2359
2360\definemathmatrix
2361  [matrix:doublebars]
2362  [\c!fences=doublebar,
2363   \c!align=\v!middle,
2364   \c!simplecommand=vvmatrix]
2365
2366\definemathmatrix
2367  [matrix:triplebars]
2368  [\c!fences=triplebar,
2369   \c!align=\v!middle,
2370   \c!simplecommand=vvvmatrix]
2371
2372\definemathmatrix
2373  [matrix:groups]
2374  [\c!fences=group,
2375   \c!align=\v!middle,
2376   \c!simplecommand=gmatrix]
2377
2378\definemathmatrix
2379  [matrix:braces]
2380  [\c!fences=brace,
2381   \c!align=\v!middle,
2382   \c!simplecommand=bracematrix]%Seldom used, bmatrix occupied by brackets
2383
2384% MPS: Is this one really used? Yes, in the test suite ...
2385
2386\definemathmatrix
2387  [thematrix]
2388  [matrix:parentheses]
2389  [\c!simplecommand=thematrix]
2390
2391%D \startbuffer
2392%D \startformula
2393%D \thematrix{1,2,3,4;5,6,7,8;9,10,11,12}
2394%D \stopformula
2395%D \stopbuffer
2396%D
2397%D \typebuffer \getbuffer
2398%D
2399%D \startbuffer
2400%D \startformula
2401%D \startthematrix
2402%D     \NC 1\NC 2\NC 3\NC 4\NR
2403%D     \NC 5\NC 6\NC 7\NC 8\NR
2404%D     \NC 9\NC10\NC11\NC12\NR
2405%D \stopthematrix
2406%D \stopformula
2407%D \stopbuffer
2408%D
2409%D \typebuffer \getbuffer
2410
2411%D Mikael needed this matrix in one of his advanced math courses that ran begin april 2022
2412%D where new concepts were introduced:
2413
2414% \definemathfence
2415%   [tekcarb]
2416%   [\c!left="005D,\c!right="005B]
2417
2418\definemathmatrix
2419  [xıɹʇɐɯ]
2420  [\c!fences=tekcarb]
2421
2422%D Fortunately we were read for it:
2423%D
2424%D \startbuffer
2425%D \startformula
2426%D \startxıɹʇɐɯ
2427%D   \NC a_1 \NC b_1 \NC c_1 \NR
2428%D   \NC a_2 \NC b_2 \NC c_2 \NR
2429%D \stopxıɹʇɐɯ
2430%D \stopformula
2431%D \stopbuffer
2432%D
2433%D \typebuffer \getbuffer
2434
2435%D \macros
2436%D   {startintertext}
2437%D
2438%D Preliminary feature:
2439%D
2440%D {\em example code}
2441%D
2442%D The intertext commands have to be expandable (in aligment lookahead) so
2443%D we cannot use \type {\protected}.
2444
2445\permanent\def\startintertext#1\stopintertext
2446  {\noalign{\math_intertext{#1}}}
2447
2448\permanent\let\stopintertext\relax
2449
2450\permanent\def\intertext#1%
2451  {\noalign{\math_intertext{#1}}}
2452
2453\protected\def\math_intertext#1%
2454  {\penalty\postdisplaypenalty
2455   \afterdisplayspace
2456   \vbox{\forgetall\noindent#1\par}%
2457   \penalty\predisplaypenalty
2458   \beforedisplayspace}
2459
2460%D \macros
2461%D   {substack}
2462%D
2463%D Preliminary code:
2464%D
2465%D \startbuffer
2466%D \startformula
2467%D    \sum_{%
2468%D      \startsubstack
2469%D       i = 1 \NR
2470%D       i \neq n \NR
2471%D       i \neq m
2472%D       \stopsubstack
2473%D     }a_i
2474%D \stopformula
2475%D \stopbuffer
2476%D
2477%D \getbuffer which was typed as \typebuffer
2478%D
2479%D Notice that these macros give the correct spacing for
2480%D subscripts. Compare for example
2481%D
2482%D \startbuffer
2483%D \startformula
2484%D \sum_{\startsubstack a \NR b \NR \stopsubstack}
2485%D \text{ and }
2486%D \sum_{\scriptstyle a \atop \scriptstyle}
2487%D \stopformula
2488%D \stopbuffer
2489%D
2490%D \typebuffer which gives \getbuffer
2491
2492% no tagging yet : how is it supposed to be coded?
2493
2494\permanent\protected\def\startsubstack
2495  {\begingroup
2496   \vcenter\bgroup
2497   \baselineskip\mathstacktotal
2498   \lineskip\mathstackvgap
2499   \lineskiplimit\lineskip
2500   \mathsurround\zeropoint
2501   \mathsurroundskip\zeroskip
2502   \everycr\emptytoks
2503   \enforced\let\NC\relax
2504   \enforced\let\MC\relax
2505   \enforced\let\NR\crcr
2506   \halign\bgroup\hfil\normalstartimath\scriptstyle\aligncontent\normalstopimath\hfil\crcr}
2507
2508\noaligned\permanent\protected\def\stopsubstack
2509  {\crcr
2510   \egroup
2511   \egroup
2512   \endgroup}
2513
2514%D \macros{overset, underset}
2515%D
2516%D The macros \type {\overset} and \type {\underset} are provided by \AMS\ packages
2517%D in \LATEX. These macro allows you to place a symbol above or below another
2518%D symbol, irrespective of whether the other symbol is a relation or something else,
2519%D and without influencing the spacing. Because in \LUAMETATEX\ we're less limited,
2520%D we have rather simple definitions compared to \MKIV. One cna also do:
2521%D
2522%D \starttyping
2523%D $b\limits^a$
2524%D $<\limits^a$
2525%D \stoptyping
2526
2527\permanent\protected\def\overset #1#2{\mathrel{#2}\limits\normalsuperscript{#1}}
2528\permanent\protected\def\underset#1#2{\mathrel{#2}\limits\normalsubscript  {#1}}
2529
2530%D The following code comes from \type {math-str.mkiv}.
2531%D
2532%D Here we implement a basic math alignment mechanism. Numbers are also handled. The
2533%D macros \type {\startinnermath} and \type {\stopinnermath} can be overloaded in
2534%D specialized modules.
2535
2536\installcorenamespace{mathinnerstart}
2537\installcorenamespace{mathinnerstop}
2538
2539\permanent\protected\def\startinnermath{\expandnamespaceparameter\??mathinnerstart\formulaparameter\c!align\v!normal}
2540\permanent\protected\def\stopinnermath {\expandnamespaceparameter\??mathinnerstop \formulaparameter\c!align\v!normal}
2541
2542\permanent\protected\def\defineinnermathhandler#1#2#3%
2543  {\defcsname\??mathinnerstart#1\endcsname{#2}%
2544   \defcsname\??mathinnerstop #1\endcsname{#3}}
2545
2546\def\strc_math_flush_number_box_normal{\box\b_strc_formulas_number}
2547\def\strc_math_flush_number_box_visual{\ruledhbox{\box\b_strc_formulas_number}}
2548
2549\let\strc_math_flush_number_box\strc_math_flush_number_box_normal
2550
2551% \newdimension  \d_strc_math_display_width
2552% \newdimension  \d_strc_math_indent
2553% \newconditional\c_strc_math_indent
2554
2555\newconditional\c_strc_math_display_overflow
2556\newconstant   \c_strc_math_number_location
2557\newconstant   \c_strc_math_number_variant
2558\newconstant   \c_strc_formulas_frame_mode
2559\newdimension  \d_strc_math_framed_width
2560
2561\defcsname\??formulaoption\v!frame\endcsname
2562  {\edef\p_frame{\formulaparameter\c!frame}%
2563   \ifx\p_frame\v!number
2564     \c_strc_formulas_frame_mode\plustwo % inside frame
2565   \else
2566     \c_strc_formulas_frame_mode\plusone % outside frame
2567   \fi}
2568
2569% mode: 0=no frame | 1=number inside frame | 2=number outside frame
2570
2571% it is a bit of a mess because we solve all kind of bordercases but at some
2572% point it will become clean
2573
2574\def\strc_math_flush_aligned_boxed_direct_yes
2575  {\dontleavehmode
2576   \box\b_strc_math_display
2577   \llap{\strc_math_flush_number_box}}
2578
2579\def\strc_math_flush_aligned_boxed_direct_nop
2580  {\dontleavehmode
2581   \box\b_strc_math_display}
2582
2583\def\strc_math_flush_aligned_left_number_indeed
2584  {\ifvoid\b_strc_formulas_number\else
2585     \setbox\b_strc_formulas_number\hbox to \displaywidth\bgroup
2586       \hss
2587       \hbox{\strc_math_flush_number_box}%
2588     \egroup
2589     \ifcase\c_strc_math_number_location\or
2590       \boxxoffset\b_strc_formulas_number\dimexpr-\displaywidth+\d_strc_formulas_number+\s_strc_formulas_margin_left\relax % brrrrr
2591       \boxyoffset\b_strc_formulas_number-\d_strc_math_first_height
2592       \htdp\b_strc_formulas_number\zeropoint
2593       \strc_math_flush_number_box % left
2594     \fi
2595   \fi}
2596
2597\def\strc_math_flush_aligned_right_number_indeed
2598  {\ifvoid\b_strc_formulas_number\else
2599     \setbox\b_strc_formulas_number\hbox to \displaywidth\bgroup
2600       \hss
2601       \hbox{\strc_math_flush_number_box}%
2602     \egroup
2603     \ifcase\c_strc_math_number_location\or\else
2604       \boxxoffset\b_strc_formulas_number\dimexpr-\s_strc_formulas_margin_right\relax % brrrrr
2605       \boxyoffset\b_strc_formulas_number\d_strc_math_last_depth
2606       \htdp\b_strc_formulas_number\zeropoint
2607       \strc_math_flush_number_box % right
2608     \fi
2609   \fi}
2610
2611% \c_strc_math_ignore_number\conditionaltrue
2612
2613% cleanup timestamp: tales of time, joe bonamassa (live blu-ray in loop mode, 2023)
2614
2615\dimensiondef\d_strc_math_number_eps 5\scaledpoint
2616
2617% line mode
2618
2619\def\strc_math_flush_line_mode
2620  {\ifcase\c_strc_math_ragged_status\or\or\hfill\or\hfill\fi
2621   \box\b_strc_math_display
2622   \ifcase\c_strc_math_ragged_status\or\hfill\or\hfill\or\fi}
2623
2624% wrap mode
2625
2626\def\strc_math_flush_wrap_mode
2627  {\strc_math_setup_align_auto
2628   \bgroup
2629     \leftskip \zeroskip
2630     \rightskip\zeroskip
2631     \global\c_strc_math_positioning\plustwo
2632     \dontleavehmode
2633     \vbox\bgroup
2634       \strc_math_flush_aligned_left_number_indeed
2635       \unvbox\b_strc_math_display
2636       \strc_math_flush_aligned_right_number_indeed
2637     \egroup
2638   \egroup
2639   \ifvmode
2640     \nointerlineskip
2641   \fi}
2642
2643% flow mode
2644
2645\def\strc_math_flush_v_box_bottom
2646  {\ifdone
2647     \global\c_strc_math_positioning42\relax
2648     \unvbox\b_strc_math_display
2649     \strc_math_flush_number_box
2650   \else
2651     \global\c_strc_math_positioning43\relax
2652     \unvbox\b_strc_math_display
2653     \nointerlineskip
2654     \ht\b_strc_formulas_number\zeropoint
2655     \dp\b_strc_formulas_number\zeropoint
2656     \boxyoffset\b_strc_formulas_number\d_strc_math_last_depth
2657     \strc_math_flush_number_box % right
2658     \prevdepth\d_strc_math_last_depth
2659   \fi}
2660
2661\def\strc_math_flush_v_box_top
2662  {\ifdone
2663     \global\c_strc_math_positioning45\relax
2664     \dontleavehmode
2665     \strc_math_flush_number_box
2666     \unvbox\b_strc_math_display
2667   \else
2668     \scratchdepth\dp\b_strc_formulas_number
2669     \global\c_strc_math_positioning46\relax
2670     \ht\b_strc_formulas_number\strutht
2671     \dp\b_strc_formulas_number\strutdp
2672     \dontleavehmode
2673     \strc_math_flush_number_box % left
2674     \vkern-\dimexpr\d_strc_math_first_height+\scratchdepth\relax
2675     \unvbox\b_strc_math_display
2676   \fi}
2677
2678\def\strc_math_flush_v_box_right
2679  {\ifconditional\c_strc_math_ignore_number
2680     \d_strc_formulas_number\zeropoint
2681   \fi
2682   \strc_formulas_start_side_box
2683   \ifzeropt\d_strc_formulas_number
2684     \global\c_strc_math_positioning41\relax
2685     \unvbox\b_strc_math_display
2686   \else
2687     % better verbose than compact so some overlap in code here
2688     \ifcase\c_strc_math_number_variant\or
2689       \s_strc_formulas_margin_right\zeroskip
2690     \fi
2691     \setbox\b_strc_formulas_number\hbox to \displaywidth\bgroup
2692       \hss
2693       \strc_math_flush_number_box
2694       \kern\s_strc_formulas_margin_right
2695     \egroup
2696     \ifcstok{\formulaparameter\c!order}\v!reverse
2697       \ifdim\dimexpr\d_strc_math_first_right-\s_strc_formulas_margin_right\relax<\dimexpr\d_strc_formulas_number-\d_strc_math_number_eps\relax
2698         \donetrue
2699       \else
2700         \donefalse
2701       \fi
2702       \strc_math_flush_v_box_top
2703     \else
2704       \ifdim\dimexpr\d_strc_math_last_right-\s_strc_formulas_margin_right\relax<\dimexpr\d_strc_formulas_number-\d_strc_math_number_eps\relax
2705         \donetrue
2706       \else
2707         \donefalse
2708       \fi
2709       \strc_math_flush_v_box_bottom
2710     \fi
2711   \fi
2712   \strc_formulas_stop_side_box}
2713
2714\def\strc_math_flush_v_box_left
2715  {\ifconditional\c_strc_math_ignore_number
2716     \d_strc_formulas_number\zeropoint
2717   \fi
2718   \strc_formulas_start_side_box
2719   \ifzeropt\d_strc_formulas_number
2720     \global\c_strc_math_positioning44\relax
2721     \unvbox\b_strc_math_display
2722   \else
2723     % better verbose than compact so some overlap in code here
2724     \ifcase\c_strc_math_number_variant\or
2725       \s_strc_formulas_margin_left\zeroskip
2726     \fi
2727     \setbox\b_strc_formulas_number\hbox to \displaywidth\bgroup
2728       \kern\s_strc_formulas_margin_left
2729       \strc_math_flush_number_box
2730       \hss
2731     \egroup
2732     \ifcstok{\formulaparameter\c!order}\v!reverse
2733       \ifdim\dimexpr\d_strc_math_last_left-\s_strc_formulas_margin_left\relax<\dimexpr\d_strc_formulas_number-\d_strc_math_number_eps\relax
2734         \donetrue
2735       \else
2736         \donefalse
2737       \fi
2738       \strc_math_flush_v_box_bottom
2739     \else
2740       \ifdim\dimexpr\d_strc_math_first_left-\s_strc_formulas_margin_left\relax<\dimexpr\d_strc_formulas_number-\d_strc_math_number_eps\relax
2741         \donetrue
2742       \else
2743         \donefalse
2744       \fi
2745       \strc_math_flush_v_box_top
2746     \fi
2747   \fi
2748   \strc_formulas_stop_side_box}
2749
2750\def\strc_math_flush_h_mode
2751  {\global\c_strc_math_positioning\plusthree
2752   \dontleavehmode
2753   \strc_math_flush_aligned_left_number_indeed
2754   \box\b_strc_math_display
2755   \strc_math_flush_aligned_right_number_indeed}
2756
2757\def\strc_math_flush_h_box
2758  {\global\c_strc_math_positioning\plusfive
2759   \dontleavehmode
2760   \strc_math_flush_aligned_left_number_indeed
2761   \box\b_strc_math_display
2762   \strc_math_flush_aligned_right_number_indeed}
2763
2764\def\strc_math_flush_text_mode
2765  {\strc_math_setup_align_auto
2766   \bgroup
2767     \leftskip \zeroskip
2768     \rightskip\zeroskip
2769     \ifhmode
2770       % nil the tracing
2771       \strc_math_flush_h_mode
2772     \orelse\ifvbox\b_strc_math_display
2773       \ifnum\c_strc_math_number_location=\plusone
2774         \strc_math_flush_v_box_left
2775       \else
2776         \strc_math_flush_v_box_right
2777       \fi
2778     \else
2779       % nil the tracing, might never happen
2780       \strc_math_flush_h_box
2781     \fi
2782   \egroup
2783   \ifvmode
2784     \nointerlineskip
2785   \fi}
2786
2787% all modes:
2788
2789\protected\def\strc_math_flush_aligned
2790  {\ifnum\c_strc_math_split_mode=\c_strc_math_line_mode
2791     \strc_math_flush_line_mode
2792   \orelse\ifnum\c_strc_math_split_mode=\c_strc_math_wrap_mode
2793     \strc_math_flush_wrap_mode
2794   \else
2795     \strc_math_flush_text_mode
2796   \fi}
2797
2798\def\strc_math_flush_box_normal
2799  {\ifnum\c_strc_math_split_mode=\c_strc_math_line_mode
2800     \hbox to \displaywidth\bgroup
2801        \strc_math_flush_aligned
2802     \egroup
2803   \else
2804     \strc_math_flush_aligned
2805   \fi}
2806
2807\def\strc_math_flush_box_framed_common
2808  {\d_strc_math_framed_width\displaywidth
2809   \setformulaframedparameter\c!align{\formulaparameter\c!align}%
2810   \letformulaframedparameter\c!strut\v!no
2811   \d_framed_formula\ht\b_strc_math_display
2812   \ifcase\c_strc_math_ragged_status\or      \or\hfill\or\hfill\fi
2813   \inheritedformulaframedframed{\box\b_strc_math_display}%
2814   \ifcase\c_strc_math_ragged_status\or\hfill\or\hfill         \fi}
2815
2816\def\strc_math_flush_box_framed_display
2817  {\let\currentformulaframed\currentformula
2818   \letformulaframedparameter\c!location\v!formula
2819   \setformulaframedparameter\c!width{\d_strc_math_framed_width}%
2820   \strc_math_flush_box_framed_common}
2821
2822\def\strc_math_flush_box_framed_fit_inline
2823  {\let\currentformulaframed\currentformula
2824   \resetformulaframedparameter\c!location
2825   \letformulaframedparameter\c!width\v!fit
2826   \strc_math_flush_box_framed_common}
2827
2828\def\strc_math_flush_box_framed_fit_display
2829  {\let\currentformulaframed\currentformula
2830   \letformulaframedparameter\c!location\v!formula
2831   \letformulaframedparameter\c!width\v!fit
2832   \strc_math_flush_box_framed_common}
2833
2834% combiners
2835
2836\def\strc_math_flush_number_box_left {\ifconditional\c_strc_formulas_overlay_number\rlap\fi{\strc_math_flush_number_box}}
2837\def\strc_math_flush_number_box_right{\ifconditional\c_strc_formulas_overlay_number\llap\fi{\strc_math_flush_number_box}}
2838
2839\def\strc_math_flush_box
2840  {\ifcase\c_strc_formulas_frame_mode
2841     \strc_math_flush_box_normal
2842   \else
2843     \strc_math_flush_box_framed_display
2844   \fi}
2845
2846\def\strc_math_number_right_normal
2847  {\strc_math_flush_aligned
2848   \hss % hss makes room for number
2849   \strc_math_flush_number_box_right}
2850
2851\def\strc_math_number_left_normal
2852  {\strc_math_flush_number_box_left
2853   \strc_math_flush_aligned
2854   \hss} % hss makes room for number
2855
2856\def\strc_math_number_right_normal_outside
2857  {\ifconditional\c_strc_formulas_tight
2858     \strc_math_flush_box_framed_fit_display
2859   \else
2860     \strc_math_flush_box_framed_display
2861   \fi
2862   \hss % hss makes room for number
2863   \strc_math_flush_number_box}
2864
2865\def\strc_math_number_left_normal_outside
2866  {\strc_math_flush_number_box
2867   \hss % hss makes room for number
2868   \ifconditional\c_strc_formulas_tight
2869     \strc_math_flush_box_framed_fit_display
2870   \else
2871     \strc_math_flush_box_framed_display
2872   \fi}
2873
2874\def\strc_math_number_right_normal_inside
2875  {\setbox\b_strc_math_display\hpack to \dimexpr\displaywidth-\d_framed_locator_lo-\d_framed_locator_ro\relax\bgroup
2876     \strc_math_flush_aligned
2877     \hss
2878     \strc_math_flush_number_box
2879   \egroup
2880   \strc_math_flush_box_framed_fit_inline}
2881
2882\def\strc_math_number_left_normal_inside
2883  {\setbox\b_strc_math_display\hpack to \dimexpr\displaywidth-\d_framed_locator_lo-\d_framed_locator_ro\relax\bgroup
2884     \strc_math_flush_number_box
2885     \hss
2886     \strc_math_flush_aligned
2887   \egroup
2888   \strc_math_flush_box_framed_fit_inline}
2889
2890\def\strc_math_number_right_overflow
2891  {\vpack\bgroup
2892     \strc_math_flush_box
2893     \par
2894     \hpack to \displaywidth\bgroup
2895       \hss
2896       \strc_math_flush_number_box_right
2897     \egroup
2898   \egroup}
2899
2900\def\strc_math_number_left_overflow
2901  {\vpack\bgroup
2902     \hpack to \displaywidth\bgroup
2903       \strc_math_flush_number_box_left
2904       \hss
2905     \egroup
2906     \strc_math_flush_box
2907   \egroup}
2908
2909\def\strc_math_number_right_overflow_outside
2910  {\vpack\bgroup
2911     \strc_math_flush_box_framed_fit_inline
2912    %\hskip\zeroskip % nicely breaks the line without introducing funny vertical spacing ... why o why
2913     \hpack to \displaywidth\bgroup
2914       \hss
2915       \strc_math_flush_number_box
2916     \egroup
2917   \egroup}
2918
2919\def\strc_math_number_left_overflow_outside
2920  {\vpack\bgroup
2921     \hpack to \dimexpr\displaywidth-\d_framed_locator_lo\relax\bgroup
2922       \strc_math_flush_number_box
2923       \hss
2924     \egroup
2925     \hskip\zeroskip % nicely breaks the line without introducing funny vertical spacing ... why o why
2926     \strc_math_flush_box_framed_fit_inline
2927   \egroup}
2928
2929\def\strc_math_number_right_overflow_inside
2930  {\setbox\b_strc_math_display\vpack\bgroup
2931     \box\b_strc_math_display
2932     \hpack to \displaywidth\bgroup
2933       \hss
2934       \strc_math_flush_number_box
2935       \kern\d_framed_locator_ro
2936     \egroup
2937   \egroup
2938   \strc_math_flush_box_framed_fit_inline}
2939
2940\def\strc_math_number_left_overflow_inside
2941  {\setbox\b_strc_math_display\vpack\bgroup
2942     \hpack to \displaywidth\bgroup
2943     % \kern\d_framed_locator_lo
2944       \strc_math_flush_number_box
2945       \hss
2946     \egroup
2947     \box\b_strc_math_display
2948   \egroup
2949   \strc_math_flush_box_framed_fit_inline}
2950
2951% checkers
2952
2953\setupmathalignment
2954  [\c!numberdistance=\formulaparameter\c!numberdistance]
2955
2956\protected\def\d_strc_math_total_display_width
2957  {\dimexpr
2958     \d_strc_math_display_width+\d_strc_formulas_number
2959     \ifconditional\c_strc_formulas_overlay_number
2960        \ifcase\c_strc_math_ragged_status\or\or+\d_strc_formulas_number\or\fi
2961     \fi
2962   \relax}
2963
2964\def\strc_math_number_check
2965  {\d_strc_math_display_width\wd\b_strc_math_display
2966   \ifconditional\c_strc_formulas_tight
2967     \ifdim\d_strc_math_total_display_width>\displaywidth
2968       \c_strc_math_display_overflow\conditionaltrue
2969     \else
2970       \displaywidth\d_strc_math_total_display_width
2971       \c_strc_math_display_overflow\conditionalfalse
2972     \fi
2973   \else
2974     \ifdim\dimexpr\d_strc_math_total_display_width+\formulaparameter\c!numberthreshold\relax>\displaywidth
2975       \c_strc_math_display_overflow\conditionaltrue
2976     \else
2977       \c_strc_math_display_overflow\conditionalfalse
2978     \fi
2979   \fi}
2980
2981\def\strc_math_number_check_outside
2982  {\d_strc_math_display_width\naturalwd\b_strc_math_display
2983   \ifdim\dimexpr\d_strc_math_total_display_width+\d_framed_locator_lo+\d_framed_locator_ro\relax>\displaywidth
2984     \c_strc_math_display_overflow\conditionaltrue
2985   \else
2986     \c_strc_math_display_overflow\conditionalfalse
2987   \fi
2988   % still ok?
2989   \ifnum\c_strc_math_ragged_status=\plustwo
2990     \d_strc_math_framed_width\dimexpr\displaywidth-2\d_strc_formulas_number\relax
2991   \else
2992     \d_strc_math_framed_width\dimexpr\displaywidth- \d_strc_formulas_number\relax
2993   \fi}
2994
2995\let\strc_math_number_check_inside\strc_math_number_check_outside
2996
2997% offsets
2998
2999\def\strc_math_number_check_offsets
3000  {\begingroup
3001     \setbox\scratchbox\hbox
3002       {\inheritedformulaframedframed
3003          {\pack_framed_locator_set_lo\pack_framed_locator_set_ro}}%
3004   \endgroup}
3005
3006% tracing
3007
3008\def\strc_math_traced_state_yes
3009  {\llap{\setbox\scratchbox\hbox{\infofont
3010   \ifcase\c_strc_math_ragged_status unset\or flushleft\or middle\or flushright\fi
3011   \space
3012   \ifcase\c_strc_formulas_frame_mode no\or out\or in\fi
3013   \space
3014   \ifconditional\c_strc_math_display_overflow overflow\else fit\fi
3015   \quad}\ht\scratchbox\zeropoint\dp\scratchbox\zeropoint\box\scratchbox}}
3016
3017\let\strc_math_traced_state\relax
3018
3019\installtextracker
3020  {formulas.framed}
3021  {\let\strc_math_traced_state\strc_math_traced_state_yes}
3022  {\let\strc_math_traced_state\relax}
3023
3024% packaging
3025
3026\installcorenamespace{mathboxlocation}
3027
3028\defcsname\??mathboxlocation\v!left \endcsname
3029  {\c_strc_math_number_location\plusone}
3030
3031\defcsname\??mathboxlocation\v!right\endcsname
3032  {\c_strc_math_number_location\plustwo}
3033
3034\defcsname\??mathboxlocation\v!atleftmargin\endcsname
3035  {\c_strc_math_number_location\plusone
3036   \ifzeropt\s_strc_formulas_margin_left
3037     % this can be a helper as now mixed in math-ali
3038     \parinitleftskip\zeroskip
3039   \else
3040     \c_strc_math_number_variant \plusone
3041   \fi}
3042
3043\defcsname\??mathboxlocation\v!atrightmargin\endcsname
3044  {\c_strc_math_number_location\plustwo
3045   \ifzeropt\s_strc_formulas_margin_right
3046     % this can be a helper as now mixed in math-ali
3047     \parfillrightskip\zeroskip
3048   \else
3049     \c_strc_math_number_variant \plusone
3050   \fi}
3051
3052\protected\def\strc_math_box_start#1%
3053  {\c_strc_math_ragged_status#1\relax % already set
3054   \useformulacolorparameter\c!color
3055   \c_strc_math_number_location\zerocount
3056   \c_strc_math_number_variant \zerocount
3057   \begincsname\??mathboxlocation\formulaparameter\c!location\endcsname
3058   %
3059   % We collect the math formula in an hbox. Dimensions don't really play
3060   % a role yet but beware of nesting!
3061   %
3062   \dontcomplain
3063  %\holdingmigrations\plusfour
3064   \setbox\b_strc_math_display\hbox retain \plusfour\bgroup
3065     \startforceddisplaymath}
3066
3067\protected\def\strc_math_box_stop
3068  {\stopforceddisplaymath
3069   \egroup
3070   % preroll left and right offsets
3071   \ifcase\c_strc_formulas_frame_mode
3072     % no frame
3073   \else
3074     \strc_math_number_check_offsets
3075   \fi
3076   \ifcase\c_strc_formulas_frame_mode
3077     \strc_math_number_check
3078   \or
3079     \strc_math_number_check_outside
3080   \else
3081     \strc_math_number_check_inside
3082   \fi
3083   \strc_math_traced_state
3084   \ifnum\c_strc_math_split_mode=\c_strc_math_line_mode
3085     \noindent % \noindentation % not \dontleavehmode
3086     \hbox to \displaywidth \bgroup
3087   \else
3088     \bgroup
3089   \fi
3090   \ifcase\c_strc_math_number_location
3091     \strc_math_flush_box
3092   \or % number left
3093     \ifzeropt\d_strc_formulas_number
3094       \strc_math_flush_number_no
3095     \else
3096       \strc_math_flush_number_left
3097     \fi
3098   \else % number right
3099     \ifzeropt\d_strc_formulas_number
3100       \strc_math_flush_number_no
3101     \else
3102       \strc_math_flush_number_right
3103     \fi
3104   \fi
3105   \egroup
3106   \ifnum\c_strc_math_split_mode=\c_strc_math_flow_mode
3107     \ifhmode \else
3108       \strc_math_show_margins
3109     \fi
3110   \fi}
3111
3112\defineinnermathhandler\v!left      {\strc_math_box_start\plusthree}{\strc_math_box_stop}
3113\defineinnermathhandler\v!flushright{\strc_math_box_start\plusthree}{\strc_math_box_stop}
3114\defineinnermathhandler\v!right     {\strc_math_box_start\plusone  }{\strc_math_box_stop}
3115\defineinnermathhandler\v!flushleft {\strc_math_box_start\plusone  }{\strc_math_box_stop}
3116\defineinnermathhandler\v!center    {\strc_math_box_start\plustwo  }{\strc_math_box_stop}
3117\defineinnermathhandler\v!middle    {\strc_math_box_start\plustwo  }{\strc_math_box_stop}
3118\defineinnermathhandler\v!normal    {\strc_math_box_start\plustwo  }{\strc_math_box_stop}
3119\defineinnermathhandler\v!atmargin  {\strc_math_box_start\plusfour }{\strc_math_box_stop}
3120
3121\def\strc_math_flush_number_no
3122  {\ifnum\c_strc_math_split_mode=\c_strc_math_line_mode
3123     \ifconditional\c_strc_math_display_overflow
3124       \ifcase\c_strc_formulas_frame_mode
3125         \strc_math_flush_box_normal
3126       \else
3127         \strc_math_flush_box_framed_fit_inline
3128       \fi
3129     \else
3130       \ifcase\c_strc_formulas_frame_mode
3131        %\ifconditional\c_strc_formulas_tight
3132        %  \strc_math_flush_box_normal
3133        %\else
3134           \strc_math_flush_box_normal
3135        %\fi
3136       \else
3137         \ifconditional\c_strc_formulas_tight
3138           \strc_math_flush_box_framed_fit_inline
3139         \else
3140           \strc_math_flush_box_framed_display
3141         \fi
3142       \fi
3143     \fi
3144   \else
3145     \strc_math_flush_box
3146   \fi}
3147
3148\def\strc_math_flush_number_left
3149  {\ifnum\c_strc_math_split_mode=\c_strc_math_line_mode
3150     \ifconditional\c_strc_math_display_overflow
3151       \ifcase\c_strc_formulas_frame_mode
3152         \strc_math_number_left_overflow
3153       \or
3154         \strc_math_number_left_overflow_outside
3155       \or
3156         \strc_math_number_left_overflow_inside
3157       \fi
3158     \else
3159       \ifcase\c_strc_formulas_frame_mode
3160         \strc_math_number_left_normal
3161       \or
3162         \strc_math_number_left_normal_outside
3163       \or
3164         \strc_math_number_left_normal_inside
3165       \fi
3166     \fi
3167   \else
3168   % \strc_math_flush_number_box
3169   % \hfill
3170     \strc_math_flush_aligned % we flush in here, otherwise wrong positioning of number (we need to unvbox)
3171   \fi}
3172
3173\def\strc_math_flush_number_right
3174  {\ifnum\c_strc_math_split_mode=\c_strc_math_line_mode
3175     \ifconditional\c_strc_math_display_overflow
3176       \ifcase\c_strc_formulas_frame_mode
3177         \strc_math_number_right_overflow
3178       \or
3179         \strc_math_number_right_overflow_outside
3180       \or
3181         \strc_math_number_right_overflow_inside
3182       \fi
3183     \else
3184       \ifcase\c_strc_formulas_frame_mode
3185         \strc_math_number_right_normal
3186       \or
3187         \strc_math_number_right_normal_outside
3188       \or
3189         \strc_math_number_right_normal_inside
3190       \fi
3191     \fi
3192   \else
3193     \strc_math_flush_aligned
3194   % \hfill
3195   % \strc_math_flush_number_box % we flush in here
3196   \fi}
3197
3198%D Some inline math tweak.
3199
3200\appendtoks
3201    \ifcase\mathnestinglevel\or
3202        % 4=disable 6=only when no spaces
3203        \mathsurroundskip\mathematicsparameter\c!textdistance\relax
3204        \ifzeropt\mathsurroundskip
3205          \ifzeropt\gluestretch\mathsurroundskip
3206            \ifzeropt\glueshrink\mathsurroundskip
3207              \mathsurroundmode\plussix
3208            \else
3209              \mathsurroundskip\zeroskip
3210              \mathsurroundmode\plusfour
3211            \fi
3212          \else
3213            \mathsurroundmode\plussix
3214          \fi
3215        \else
3216          \mathsurroundmode\plussix
3217        \fi
3218    \else
3219      \mathsurroundmode\plusfour
3220      \mathsurroundskip\zeroskip
3221    \fi
3222\to \everymathematics
3223
3224\setupmathematics
3225  [\c!textdistance=\zeropoint]
3226
3227%D This is an experiment. No fancy spacing and alignments here. If we ever go that
3228%D route it might result in incompatible rendering.
3229
3230\permanent\protected\def\startsplitformula
3231  {\ifhmode
3232     \par
3233   \fi
3234   \begingroup
3235   \beforedisplayspace
3236   % subset of \everydisplay:
3237   \c_attr_mathmode\plusone
3238   \indisplaymath\conditionaltrue
3239   % end of subset
3240   \informulatrue}
3241
3242\permanent\protected\def\stopsplitformula
3243  {\afterdisplayspace
3244   \endgroup}
3245
3246%D Kind of new (February 2022):
3247
3248\installcorenamespace {maththreshold}
3249
3250\setupmathematics[\c!threshold=\zeropoint]
3251
3252\permanent\protected\def\installmaththreshold#1#2%
3253  {\expandafter\gluespecdef\csname\??maththreshold#1\endcsname#2\relax}
3254
3255\installmaththreshold\v!none  {\zeropoint}
3256\installmaththreshold\v!small {3\emwidth plus 0.50\emwidth minus 0.25\emwidth}
3257\installmaththreshold\v!medium{4\emwidth plus 0.75\emwidth minus 0.50\emwidth}
3258\installmaththreshold\v!big   {5\emwidth plus 1.00\emwidth minus 0.75\emwidth}
3259
3260\appendtoks
3261    \edef\p_threshold{\mathematicsparameter\c!threshold}%
3262    \maththreshold\ifcsname\??maththreshold\p_threshold\endcsname\lastnamedcs\else\p_threshold\fi\relax
3263% \to \everymath % \everymathematics
3264\to \everymathematics
3265
3266%D Here is simple alignment mechanism:
3267
3268\installcorenamespace{mathsimplealign}
3269
3270\installcommandhandler \??mathsimplealign {mathsimplealign} \??mathsimplealign
3271
3272\setupmathsimplealign
3273  [\c!distance=\v!math,
3274   \c!leftmargin=\zeropoint,
3275   \c!rightmargin=\zeropoint,
3276   \c!left=,
3277   \c!right=,
3278   \c!strut=\v!yes,
3279   \c!spaceinbetween=\mathalignmentparameter\c!spaceinbetween,
3280   \c!align=\v!all:\v!middle,
3281   \c!textdistance=.25\emwidth]
3282
3283\appendtoks
3284    \frozen\instance\protected\edefcsname\e!start\currentmathsimplealign\endcsname{\math_simplealign_start[\currentmathsimplealign]}%
3285    \frozen\instance          \defcsname \e!stop \currentmathsimplealign\endcsname{\math_simplealign_stop}%
3286\to \everydefinemathsimplealign
3287
3288\permanent\protected\def\math_simplealign_NC
3289  {\aligntab}
3290
3291% \permanent\protected\def\math_simplealign_EQ
3292%   {\aligntab=\aligntab}
3293
3294\permanent\protected\def\math_simplealign_EQ
3295  {\aligntab=}
3296
3297\noaligned\tolerant\permanent\protected\def\math_simplealign_NR[#1]#*[#2]%
3298  {\unskip
3299   \strc_formulas_place_number_nested{#1}{#2}%
3300   \math_number_right_of_eqalign
3301   \crcr}
3302
3303\aliased\let\math_align_strut\relax
3304
3305\newconditional\c_math_align_text
3306
3307\permanent\protected\def\math_simplealign_NC{\relax\global\setfalse\c_math_align_text\aligntab}
3308\permanent\protected\def\math_simplealign_EQ{\relax\global\setfalse\c_math_align_text\aligntab=}
3309\permanent\protected\def\math_simplealign_TC{\relax\global\settrue \c_math_align_text\aligntab}
3310
3311\installcorenamespace{mathsimpleendclass}
3312
3313\global\expandafter\integerdef\csname\??mathsimpleendclass\the\zerocount\endcsname\mathendcode
3314
3315\permanent\tolerant\protected\def\math_simplealign_start[#1]#*[#S#2]%
3316  {\begingroup
3317   \cdef\currentmathsimplealign{#1}%
3318   \ifarguments\or\or
3319     \setupcurrentmathsimplealign[#2]%
3320   \fi
3321   \edef\p_strut{\mathsimplealignparameter\c!strut}%
3322   \ifx\p_strut\v!yes
3323     \enforced\let\math_align_strut\strut
3324   \else
3325     \enforced\let\math_align_strut\relax
3326   \fi
3327   \mathatom \s!class \mathwrappedcode \bgroup
3328   \scratchdimen\mathsimplealignparameter\c!leftmargin\relax
3329   \ifzeropt\scratchdimen\else\kern\scratchdimen\fi
3330   \mathsimplealignparameter\c!left\relax
3331   \math_fenced_start_wrap{\mathsimplealignparameter\c!fences}%
3332   \mathatom \s!class \mathconstructcode \bgroup
3333   \math_alignment_location_check{\mathsimplealignparameter\c!location}% vcenter etc
3334   \math_alignment_location_box
3335   \bgroup
3336   \enforced\let\MC\math_simplealign_NC
3337   \enforced\let\NC\math_simplealign_NC
3338   \enforced\let\TC\math_simplealign_TC
3339   \enforced\let\NR\math_simplealign_NR
3340   \enforced\let\EQ\math_simplealign_EQ
3341   \enforced\let\TB\math_common_TB
3342   \math_eqalign_set_defaults
3343   \math_eqalign_set_columns{\mathsimplealignparameter\c!align}%
3344   \global\c_math_eqalign_column\zerocount
3345   \global\c_math_eqalign_row\plusone
3346   \edef\m_simplealign_distance{\mathsimplealignparameter\c!distance}%
3347   \strc_math_setup_spacing_aligned\mathsimplealignparameter
3348   \enablemathalignrelocate
3349   \halign
3350     \s!callback
3351       \align_callback_mathalign
3352     \s!attr
3353       \mathnumberlocationattribute \zerocount
3354     \bgroup
3355     \global\c_math_eqalign_column\zerocount
3356     \global\advanceby\c_math_eqalign_row\zerocount
3357     \ignorespaces
3358     \aligncontent % dummy
3359     \removeunwantedspaces
3360     \lastleftclass \mathbegincode
3361     \lastrightclass\mathendcode
3362     \aligntab
3363     \global\advanceby\c_math_eqalign_column\plusone
3364     \math_left_of_eqalign  % \hfil
3365     \ignorespaces
3366     \math_align_strut
3367   % \mathbeginclass\ifcsname\??mathsimpleendclass\the\numexpr\c_math_eqalign_column-\plusone\relax\endcsname\lastnamedcs\else\mathunsetcode\fi
3368     \mathbeginclass\mathbegincode
3369     \startforceddisplaymath
3370     \aligncontent
3371     \stopforceddisplaymath
3372     \ifnum\lastrightclass<\mathunsetcode
3373       \global\expandafter\integerdef\csname\??mathsimpleendclass\the\c_math_eqalign_column\endcsname\lastrightclass
3374     \fi
3375     \removeunwantedspaces
3376     \math_right_of_eqalign % \hfil
3377     \aligntab
3378     \aligntab
3379     % repeater
3380     \global\advanceby\c_math_eqalign_column\plusone
3381     \math_left_of_eqalign  % \hfil
3382     \ifx\m_simplealign_distance\v!math
3383       \mathbeginclass\ifcsname\??mathsimpleendclass\the\numexpr\c_math_eqalign_column-\plusone\relax\endcsname\lastnamedcs\else\mathunsetcode\fi
3384     \else
3385       \kern\m_simplealign_distance
3386     \fi
3387     \ignorespaces
3388     \math_align_strut
3389     \ifconditional\c_math_align_text
3390       % somehow we can't use content as an argument
3391     \else
3392       \startforceddisplaymath
3393     \fi
3394     \aligncontent
3395     \ifmmode
3396       \stopforceddisplaymath
3397     \fi
3398     \ifnum\lastrightclass<\mathunsetcode
3399       \global\expandafter\integerdef\csname\??mathsimpleendclass\the\c_math_eqalign_column\endcsname\lastrightclass
3400     \fi
3401     \removeunwantedspaces
3402     \math_right_of_eqalign % \hfil
3403     \crcr}
3404
3405\noaligned\permanent\protected\def\math_simplealign_stop
3406  {\crcr
3407   \egroup
3408   \egroup
3409   \egroup
3410   \math_fenced_stop_wrap
3411   \mathsimplealignparameter\c!right\relax
3412   \scratchdimen\mathsimplealignparameter\c!rightmargin\relax
3413   \ifzeropt\scratchdimen\else\kern\scratchdimen\fi
3414   \setbox\scratchbox\hbox{\mathsimplealignparameter\c!text}%
3415   \ifvoid\scratchbox\else
3416     \kern\mathsimplealignparameter\c!textdistance
3417     \vcenter{\box\scratchbox}%
3418   \fi
3419   \egroup
3420   \endgroup}
3421
3422%D It's not that spectacular apart from spacing being proper inter atom spacing
3423%D using one of the new \LUAMETATEX\ mechanisms.
3424%D
3425%D \starttyping
3426%D \definemathsimplealign
3427%D   [whatever]
3428%D   [left={\startmathfenced[sesac]},
3429%D    right=\stopmathfenced]
3430%D
3431%D  % distance=math,
3432%D  % distance=\zeropoint,
3433%D  % distance=1cm,
3434%D  % align={all:left}]
3435%D
3436%D \startformula
3437%D     \startwhatever[text=simple]
3438%D       \NC x \NC = r           \cos\theta \NR
3439%D       \NC y \NC = \frac{1}{2} \sin\theta \NR
3440%D       \NC 9 \NC = 123         \sin\theta \NR
3441%D     \stopwhatever
3442%D \stopformula
3443%D \stoptyping
3444
3445%D Usage \type {\sum _ {\mstack {i \in V_{0}, i \neq j}}}, documented by Mikael:
3446
3447\permanent\protected\def\mstack#1% todo: make it configurable
3448   {\begingroup
3449    \scratchtoks\emptytoks \setcharstrut(\relax
3450    \processcommalist[#1]{\ifempty\scratchtoks\else\toksapp\scratchtoks{\mathstrut\NR}\fi\toksapp\scratchtoks}%
3451    \expandafter\startsubstack\the\scratchtoks\mathstrut\stopsubstack
3452    \endgroup}
3453
3454%D Similar to simplecases:
3455%D
3456%D \starttyping
3457%D \startformula
3458%D     \equationsystem {
3459%D        {(1-a)}x^{2x} - 3y_2 + 14z  = 2 + x,
3460%D        {(1-a)}x^2    - 3y_2 +  4z <= 62,
3461%D        {(1-a)}x^a    - 3y_2 +  4z >= 12,
3462%D        {(1-a)}x^{2a} - 3y_2 + 24z != 4,
3463%D               x^^2   - 3y_2 +  4z ~  1,
3464%D               x^^2   - 3y_2 +  4z ≠  1,
3465%D             -2x      -         4z <> 10,
3466%D     }
3467%D \stopformula
3468%D \stoptyping
3469
3470\permanent\tolerant\protected\def\math_align_simple[#1]#*[#S#2]#:#3%
3471  {\begingroup
3472   \cdef\currentmathsimplealign{#1}%
3473   \setupcurrentmathsimplealign[#2]%
3474   \math_simplealign_start[\currentmathsimplealign]%
3475   \clf_simplealign{\mathsimplealignparameter\c!alternative}{\mathsimplealignparameter\c!action}{#3}%
3476   \math_simplealign_stop
3477   \endgroup}
3478
3479\appendtoks
3480    \edef\p_simplecommand{\mathsimplealignparameter\c!simplecommand}%
3481    \ifempty\p_simplecommand\else
3482        \frozen\protected\instance\edefcsname\p_simplecommand\endcsname{\math_align_simple[\currentmathsimplealign]}%
3483    \fi
3484\to \everydefinemathsimplealign
3485
3486\definemathsimplealign % new !
3487  [equationsystem]
3488  [\c!simplecommand=equationsystem,
3489   \c!alternative=equationsystem, % for the moment we use this key
3490   \c!align={all:right},
3491   \c!distance=\v!math,
3492   \c!left=,
3493   \c!right=]
3494
3495\definemathsimplealign
3496  [lequationsystem]
3497  [equationsystem]
3498  [\c!simplecommand=lequationsystem,
3499   \c!left={\startmathfenced[cases]},
3500   \c!right=\stopmathfenced]
3501
3502\definemathsimplealign
3503  [requationsystem]
3504  [equationsystem]
3505  [\c!simplecommand=requationsystem,
3506   \c!left={\startmathfenced[sesac]},
3507   \c!right=\stopmathfenced]
3508
3509%D There are users who use this so let's for now keep it (I also need to adapt
3510%D x-mathml.mkxl):
3511
3512\newskip \math_old_hideskip   \math_old_hideskip  = -1000pt plus 1fill
3513\newskip \math_old_centering  \math_old_centering =     0pt plus 1000pt minus 1000pt
3514
3515\permanent\protected\def\eqalign#1% rather plain, is this used at all ...
3516  {\dontleavehmode
3517   \mskip\thinmuskip\vcenter\bgroup % \vcenter \s!class \mathwrappercode \bgroup
3518     \mathsurround\zeropoint        % \math_eqalign_set_defaults
3519     \everycr\emptytoks
3520     \tabskip\zeroskip
3521     \enforced\let\hideskip\math_old_hideskip
3522     \enforced\let\centering\math_old_centering
3523     \enforced\def\hidewidth{\hskip\hideskip} % for alignment entries that can stick out
3524     \amcode\ampersandasciicode\alignmentcatcode
3525     \halign
3526       {\strut
3527        \hfil
3528        \mathbeginclass\mathordcode
3529        \mathendclass  \mathordcode
3530        \startforceddisplaymath\aligncontent\stopforceddisplaymath
3531        \aligntab
3532        \mathbeginclass\mathordcode
3533        \mathendclass  \mathordcode
3534        \startforceddisplaymath\aligncontent\stopforceddisplaymath
3535        \hfil
3536        \crcr
3537        #1%
3538        \crcr}%
3539   \egroup\mskip\thinmuskip}        % \egroup
3540
3541\protect \endinput
3542
3543% \placeformula \startformula[-] \startmatrix
3544% \NC 1 \NC x \NC a \NR
3545% \NC 2 \NC y \NC b \NR
3546% \NC 3 \NC z \NC c \NR
3547% \stopmatrix \stopformula
3548
3549% \definemathmatrix[bordermatrix][left={\left[\mskip\thinmuskip},right={\mskip\thinmuskip\right]}]
3550
3551% \placeformula \startformula[-] \startbordermatrix
3552% \NC 1 \NC x \NC a \NR
3553% \NC 2 \NC y \NC b \NR
3554% \NC 3 \NC z \NC c \NR
3555% \stopbordermatrix \stopformula
3556