@@ -1870,6 +1870,7 @@ def csnames(group, names):
1870
1870
p .required_group = Forward ()
1871
1871
p .optional_group = Forward ()
1872
1872
p .token = Forward ()
1873
+ p .substack = Forward ()
1873
1874
1874
1875
set_names_and_parse_actions () # for mutually recursive definitions.
1875
1876
@@ -1933,6 +1934,9 @@ def csnames(group, names):
1933
1934
1934
1935
p .operatorname = cmd (r"\operatorname" , "{" + ZeroOrMore (p .simple )("name" ) + "}" )
1935
1936
1937
+ p .substack <<= cmd (
1938
+ r"\substack" , OneOrMore (p .required_group ("value" )))
1939
+
1936
1940
p .placeable <<= (
1937
1941
p .accent # Must be before symbol as all accents are symbols
1938
1942
| p .symbol # Must be second to catch all named symbols and single
@@ -1949,6 +1953,7 @@ def csnames(group, names):
1949
1953
| p .sqrt
1950
1954
| p .overline
1951
1955
| p .text
1956
+ | p .substack
1952
1957
)
1953
1958
1954
1959
p .auto_delim <<= (
@@ -2597,3 +2602,24 @@ def auto_delim(self, s, loc, toks):
2597
2602
# if "mid" in toks ... can be removed when requiring pyparsing 3.
2598
2603
toks ["mid" ].asList () if "mid" in toks else [],
2599
2604
toks ["right" ])
2605
+
2606
+ def substack (self , s , loc , toks ):
2607
+ state = self .get_state ()
2608
+ thickness = state .get_current_underline_thickness ()
2609
+ vlist = []
2610
+
2611
+ max_width = max (map (lambda c : c .width , toks [1 :]))
2612
+
2613
+ for sub in toks [1 :]:
2614
+ cp = HCentered ([sub ])
2615
+ cp .hpack (max_width , 'exactly' )
2616
+ vlist .append (cp )
2617
+
2618
+ vlist = [val for pair in zip (vlist ,
2619
+ [Vbox (0 , thickness * 2 )] *
2620
+ len (vlist )) for val in pair ]
2621
+ del vlist [- 1 ]
2622
+
2623
+ vlt = Vlist (vlist )
2624
+ result = [Hlist ([vlt ])]
2625
+ return result
0 commit comments