@@ -2035,6 +2035,7 @@ def __init__(self):
20352035 p .non_math = Forward ()
20362036 p .operatorname = Forward ()
20372037 p .overline = Forward ()
2038+ p .overset = Forward ()
20382039 p .placeable = Forward ()
20392040 p .rbrace = Forward ()
20402041 p .rbracket = Forward ()
@@ -2053,6 +2054,7 @@ def __init__(self):
20532054 p .symbol = Forward ()
20542055 p .symbol_name = Forward ()
20552056 p .token = Forward ()
2057+ p .underset = Forward ()
20562058 p .unknown_symbol = Forward ()
20572059
20582060 # Set names on everything -- very useful for debugging
@@ -2169,6 +2171,18 @@ def __init__(self):
21692171 - (p .required_group | Error ("Expected \\ overline{value}" ))
21702172 )
21712173
2174+ p .overset <<= Group (
2175+ Suppress (Literal (r"\overset" ))
2176+ - ((p .simple_group + p .simple_group )
2177+ | Error ("Expected \\ overset{body}{annotation}" ))
2178+ )
2179+
2180+ p .underset <<= Group (
2181+ Suppress (Literal (r"\underset" ))
2182+ - ((p .simple_group + p .simple_group )
2183+ | Error ("Expected \\ underset{body}{annotation}" ))
2184+ )
2185+
21722186 p .unknown_symbol <<= Combine (p .bslash + Regex ("[A-Za-z]*" ))
21732187
21742188 p .operatorname <<= Group (
@@ -2190,6 +2204,8 @@ def __init__(self):
21902204 | p .dfrac
21912205 | p .binom
21922206 | p .genfrac
2207+ | p .overset
2208+ | p .underset
21932209 | p .sqrt
21942210 | p .overline
21952211 | p .operatorname
@@ -2842,6 +2858,38 @@ def binom(self, s, loc, toks):
28422858 return self ._genfrac ('(' , ')' , 0.0 , self ._MathStyle .TEXTSTYLE ,
28432859 num , den )
28442860
2861+ def _genset (self , state , body , annotation , overunder ):
2862+ thickness = state .font_output .get_underline_thickness (
2863+ state .font , state .fontsize , state .dpi )
2864+
2865+ body .shrink ()
2866+
2867+ cbody = HCentered ([body ])
2868+ cannotation = HCentered ([annotation ])
2869+ width = max (cbody .width , cannotation .width )
2870+ cbody .hpack (width , 'exactly' )
2871+ cannotation .hpack (width , 'exactly' )
2872+
2873+ vgap = thickness * 3
2874+ if overunder == "under" :
2875+ vlist = Vlist ([cannotation , # annotation
2876+ Vbox (0 , vgap ), # space
2877+ cbody # body
2878+ ])
2879+ # Shift so the annotation sits in the same vertical position
2880+ shift_amount = cannotation .depth + cbody .height + vgap
2881+
2882+ vlist .shift_amount = shift_amount
2883+ else :
2884+ vlist = Vlist ([cbody , # body
2885+ Vbox (0 , vgap ), # space
2886+ cannotation # annotation
2887+ ])
2888+
2889+ # To add horizontal gap between symbols: wrap the Vlist into
2890+ # an Hlist and extend it with an Hbox(0, horizontal_gap)
2891+ return vlist
2892+
28452893 def sqrt (self , s , loc , toks ):
28462894 (root , body ), = toks
28472895 state = self .get_state ()
@@ -2902,6 +2950,24 @@ def overline(self, s, loc, toks):
29022950 hlist = Hlist ([rightside ])
29032951 return [hlist ]
29042952
2953+ def overset (self , s , loc , toks ):
2954+ assert len (toks ) == 1
2955+ assert len (toks [0 ]) == 2
2956+
2957+ state = self .get_state ()
2958+ body , annotation = toks [0 ]
2959+
2960+ return self ._genset (state , body , annotation , overunder = "over" )
2961+
2962+ def underset (self , s , loc , toks ):
2963+ assert len (toks ) == 1
2964+ assert len (toks [0 ]) == 2
2965+
2966+ state = self .get_state ()
2967+ body , annotation = toks [0 ]
2968+
2969+ return self ._genset (state , body , annotation , overunder = "under" )
2970+
29052971 def _auto_sized_delimiter (self , front , middle , back ):
29062972 state = self .get_state ()
29072973 if len (middle ):
0 commit comments