%D \module %D [ file=math-stc, %D version=2012.12.29, %D title=\CONTEXT\ Math Macros, %D subtitle=Stackers, %D comment=This replaces math-arr and friends, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. \writestatus{loading}{ConTeXt Math Macros / Stackers} \unprotect % is subtype for tagged needed: dosettagproperty only used here .. maybe for tagged pdf? %D WARNING: If the code here changes, the export needs to be checked! Stackers are %D rather special because the order in mathml matters, so we flush in [base under %D over] order. We also do some analysis at the \TEX\ end (passing the right %D variant). It's easy in the export to deal with it but in the pdf stream less %D trivial as we don't actually analyze there. %D %D At some point the \MKII\ arrow mechanism has been converted to \MKIV, but we kept %D most of the logic. We now have a more generic variant dealing with extensibles. %D There are a few demands than we need to meet: %D %D \startitemize %D \startitem %D The width of the extensible need to adapt itself automatically. %D \stopitem %D \startitem %D We need to be able to control horizontal and vertical offsets. %D \stopitem %D \startitem %D We best have a math as well as a text variant (which is handy for chemistry). %D \stopitem %D \startitem %D For historic reasons we need to deal with optional arguments in a special %D (reverse) way. %D \stopitem %D \startitem %D We need alternatives for extensibles on top, in the middle and at the bottom. %D \stopitem %D \stopitemize %D %D After I had experimented a bit with virtual characters for two headed arrows I %D discussed the issue with the Gyre folks and we came to the conclusion that it %D made sense to have real extensibles instead of constructing them out of snippets. %D After all, \OPENTYPE\ math provides for it. So, in December 2013 beta versions of %D Latin Modern and Gyre fonts came available that had these! Because we still want %D to support the traditional Latin Modern Virtual math font those were extended %D with a couple of virtual extensibles as well. %D %D {\em For the moment we still have some mess here: we can deal with known %D dimensions, but fillers (like \type {\rightarrowfil} don't work with \OPENTYPE\ %D extensibles yet because there is no way to let them stretch like leaders. At some %D point \LUATEX\ might provide a auto||fit||to||encapsulated||box and if not I will %D cook up a \LUA\ based variant.} %D %D We could mess with something like \type {$mid\limits^{top}_{bottom}$} but we like %D a bit more control. At some point we need to add some hacks to get exports %D working well. %D %D In the end we have a more flexible mechanism which also handles text variants. %D When wrapping up some math developments I decided to add mp support here as well. %D A nice evening job with Joe Bonamassa performing live on the big screen (real %D nice bluray's). See meta-imp-mat.mkiv for examples. % possible improvements: % % - we could skip the left/right offsets when offset=normal, this saves some access time % at the lua end and some checking: use \mathhorizontalcode or \mathextensiblecode % but in practice arrows etc are not used that often % At some point we can consider to use the more natural \LUAMETATEX\ features but the % problem is that we lack proper support in fonts and we also have less control. %installcorenamespace {mathextensiblefallbacks} % In math mode we no longer fallback, simply because only a few fonts implement % extensible using minus and equal signs. So either we provide a tweaked one or we % simply ignore the lack. Better choose a font that matches expectations that some % fragile imperfect hackery. %D The extensible gets sort of inlined so we loose tagging applied to the box %D which actually is an nested mlist_to_list call then. Kind of messy in the %D tagging code. \def\math_stackers_fallback {\mathstylehbox to \scratchwidth{\usemathstackerscolorparameter\c!color \hss \hskip\mathstackersparameter\c!topoffset\relax % for manual italic correction % \ifcsname\??mathextensiblefallbacks\the\scratchunicode\endcsname % \lastnamedcs % \else \Umathchar\zerocount\zerocount\scratchunicode % \fi \hss}} \def\math_stackers_regular {\mathstylehbox{\usemathstackerscolorparameter\c!color \hskip\d_math_stackers_offset_l \Uhextensible middle \ifcstok{\mathstackersparameter\c!stretch}\v!yes stretch \fi \ifcstok{\mathstackersparameter\c!shrink}\v!yes shrink \fi width \dimexpr\scratchwidth-\d_math_stackers_offset_l-\d_math_stackers_offset_r\relax \zerocount\scratchunicode \relax \hskip\d_math_stackers_offset_r }} % these delimiters are a unuseable as they don't center for small arguments: % % $\Umathaccent 0 0 "2190{x}$ \par $\Umathaccent 0 0 "27F8{x}$\par % $\Udelimiterunder 0 "2190{x}$ \par $\Udelimiterunder 0 "27F8{x}$\par % \defcsname\??mathextensiblefallbacks\endcsname % {\hpack{\vrule\s!width\scratchwidth\s!height.1\mathexheight\s!depth\zeropoint}} %D We don't really need this because we can assume that fonts have the right %D extensibles. If needed I will make a general virtual extender for \OPENTYPE\ %D fonts. %D %D Because we have quite some control over positioning, we have somewhat extensive %D tracing built in. \let\math_stackers_top \relax \let\math_stackers_middle\relax \let\math_stackers_bottom\relax \let\math_stackers_skip \hskip \installtextracker {math.stackers.texts} {\let\math_stackers_top \filledhboxb \let\math_stackers_middle\filledhboxr \let\math_stackers_bottom\filledhboxg \let\math_stackers_skip \math_stackers_skip_indeed} {\let\math_stackers_top \relax \let\math_stackers_middle\relax \let\math_stackers_bottom\relax \let\math_stackers_skip \hskip} \def\math_stackers_skip_indeed#amount% {\filledhboxk{\strut\hskip#amount}} \lettonothing\math_stackers_start_tagged_mid \lettonothing\math_stackers_start_tagged_top \lettonothing\math_stackers_start_tagged_bot \lettonothing\math_stackers_stop_tagged \def\math_stackers_unicode{\ifcase\scratchunicode\else\the\scratchunicode\fi} \def\math_stackers_reset_variables {\scratchunicode\zerocount \edef\p_offset {\mathstackersparameter\c!offset}% \edef\p_location {\mathstackersparameter\c!location}% \edef\p_strut {\mathstackersparameter\c!strut}% \edef\p_alternative{\mathstackersparameter\c!alternative}% \scratchleftoffset \zeropoint \scratchrightoffset\zeropoint} \appendtoks \def\math_stackers_start_tagged_mid{\dostarttagged\t!mstackermid{\math_stackers_unicode}\hbox\bgroup}% \def\math_stackers_start_tagged_top{\dostarttagged\t!mstackertop{\math_stackers_unicode}\hbox\bgroup}% \def\math_stackers_start_tagged_bot{\dostarttagged\t!mstackerbot{\math_stackers_unicode}\hbox\bgroup}% \def\math_stackers_stop_tagged {\egroup\dostoptagged}% \to \everysetuptagging %D We define a full featured command handler. \installcorenamespace {mathstackers} \installcommandhandler \??mathstackers {mathstackers} \??mathstackers \setupmathstackers [%c!alternative=\v!text, % text | mathematics \c!left=, \c!right=, \c!mathclass=\s!relation, \c!alternative=\v!normal, \c!voffset=.25\mathexheight, % maybe less \c!hoffset=\zeropoint, \c!topoffset=\zeropoint, % for manual italic correction \c!distance=\mathstackersparameter\c!voffset, % distance between symbol and base (can be different from voffset) \c!minheight=\mathexheight, \c!mindepth=\zeropoint, % \c!minwidth=.5\mathemwidth, \c!minwidth=.25\mathemwidth, % \iota \c!order=\v!normal, \c!strut=, \c!color=, % todo: when I need it \c!topcommand=, \c!middlecommand=, \c!bottomcommand=, \c!offset=\v!normal, % normal | min | max \c!location=\v!top] % none | normal | small | medium | big %D We assume that the middle characters (that can be an extensible) to sit on %D top of the baseline by default. \installcorenamespace {mathstackerslocation} \installcorenamespace {mathstackersalternative} \letcsname\??mathstackerslocation\v!top \endcsname\plusone % on top of baseline \letcsname\??mathstackerslocation\v!high \endcsname\plustwo % 25 % down \letcsname\??mathstackerslocation\v!middle \endcsname\plusthree % centered \letcsname\??mathstackerslocation\v!low \endcsname\plusfour % 75 % down \letcsname\??mathstackerslocation\v!bottom \endcsname\plusfive % below baseline \letcsname\??mathstackerslocation \endcsname\zerocount %D First we implement the helper that deals with an extensible in the middle and %D top and|/|or bottom texts: \lettonothing\m_math_stackers_text_top \lettonothing\m_math_stackers_text_bottom \lettonothing\m_math_stackers_text_middle \def\math_stackers_flushtext#command#style#color#text% {\ifdim\scratchleftoffset>\zeropoint \math_stackers_skip\scratchleftoffset \fi \ifx\p_strut\v!no \else \strut \fi \usemathstackersstyleandcolor#style#color% \mathstackersparameter#command#text% \ifdim\scratchrightoffset>\zeropoint \math_stackers_skip\scratchrightoffset \fi} \def\math_stackers_toptext {\math_stackers_flushtext\c!topcommand \c!topstyle \c!topcolor \m_math_stackers_text_top } \def\math_stackers_bottomtext{\math_stackers_flushtext\c!bottomcommand\c!bottomstyle\c!bottomcolor\m_math_stackers_text_bottom} \def\math_stackers_middletext{\math_stackers_flushtext\c!middlecommand\c!middlestyle\c!middlecolor\m_math_stackers_text_middle} \def\math_stackers_content {\ifcase\scratchcounter \math_stackers_fallback \or % left \math_stackers_regular \or % right \math_stackers_regular \or % horizontal \math_stackers_regular \else \math_stackers_fallback \fi} % no checking, we assume sane use \letcsname\??mathstackersalternative\v!normal \endcsname\math_stackers_content \letcsname\??mathstackersalternative\v!default\endcsname\math_stackers_content \setupmathstackers [\c!mp=math:stacker:\the\scratchunicode, \c!mpheight=\mathcharht\scratchunicode, \c!mpdepth=\mathchardp\scratchunicode, \c!mpoffset=.25\mathexheight] \defcsname\??mathstackersalternative\v!mp\endcsname {\normalexpanded{\math_stackers_mp_box {\the\dimexpr\mathstackersparameter\c!mpheight}% {\the\dimexpr\mathstackersparameter\c!mpdepth}% {\the\dimexpr\mathstackersparameter\c!mpoffset}% {\the\dimexpr\triggeredmathstyleparameter\Umathfractionrule}% {\the\dimexpr\triggeredmathstyleparameter\Umathaxis}% {\the\mathexheight}% {\the\mathemwidth}% }} \protected\def\math_stackers_mp_box#1#2#3#4#5#6#7% {\hpack\bgroup % todo: add code key + tag % we can speed up \mathexheight expansion a bit \d_overlay_width \scratchwidth \d_overlay_height #1\relax \d_overlay_depth #2\relax \d_overlay_offset #3\relax \d_overlay_linewidth#4\relax \edef\overlaylinecolor{\mathstackersparameter\c!color}% \edef\p_mp{\mathstackersparameter\c!mp}% \uniqueMPgraphic{\p_mp}{axis=#5,ex=#6,em=#7}% \egroup} \def\math_stackers_check_unicode#codepoint% {\scratchunicode#codepoint\relax \scratchhoffset\mathstackersparameter\c!hoffset\relax \scratchvoffset\mathstackersparameter\c!voffset\relax \scratchcounter\mathhorizontalcode\fam\scratchunicode\relax % also sets \leftscratchoffset and \rightscratchoffset \ifx\p_offset\v!max % heads/tails + hoffset \orelse\ifx\p_offset\v!min % heads/tails - hoffset \advanceby\scratchleftoffset -\scratchhoffset \advanceby\scratchrightoffset-\scratchhoffset \else % \v!normal % hoffset \scratchleftoffset\zeropoint \scratchrightoffset\zeropoint \fi \ifdim\scratchleftoffset<\zeropoint \scratchleftoffset\zeropoint \fi \ifdim\scratchrightoffset<\zeropoint \scratchrightoffset\zeropoint \fi} \def\math_stackers_normalize_three {\scratchheight\ht\scratchboxthree \scratchdepth \dp\scratchboxthree \scratchtopoffset \scratchheight \scratchbottomoffset\scratchdepth \scratchdimen\mathstackersparameter\c!minheight\relax \ifdim\scratchheight<\scratchdimen \scratchheight\scratchdimen \ht\scratchboxthree\scratchheight \fi \scratchdimen\mathstackersparameter\c!mindepth\relax \ifdim\scratchdepth<\scratchdimen \scratchdepth\scratchdimen \dp\scratchboxthree\scratchdepth \fi \advanceby\scratchtopoffset -\scratchheight \advanceby\scratchbottomoffset-\scratchdepth \ifdim\scratchtopoffset<\zeropoint \scratchtopoffset\zeropoint \fi \ifdim\scratchbottomoffset<\zeropoint \scratchbottomoffset\zeropoint \fi} \def\math_stackers_get_max_width {\ifdim\wd\scratchboxone>\scratchwidth \scratchwidth\wd\scratchboxone \fi \ifdim\wd\scratchboxtwo>\scratchwidth \scratchwidth\wd\scratchboxtwo \fi \ifdim\wd\scratchboxthree>\scratchwidth \scratchwidth\wd\scratchboxthree \fi} \def\math_stackers_set_max_width {\ifdim\wd\scratchboxone<\scratchwidth \setbox\scratchboxone\hpack to \scratchwidth{\hss\unhbox\scratchboxone\hss}% unhboxing makes leaders work \fi \ifdim\wd\scratchboxtwo<\scratchwidth \setbox\scratchboxtwo\hpack to \scratchwidth{\hss\unhbox\scratchboxtwo\hss}% \fi \ifdim\wd\scratchboxthree<\scratchwidth \setbox\scratchboxthree\hpack to \scratchwidth{\hss\unhbox\scratchboxthree\hss}% \fi} \protected\def\math_stackers_triplet#method#category#codepoint#toptext#bottomtext% {\begingroup \cdef\currentmathstackers{#category}% \mathstackersparameter\c!left\relax \dostarttagged\t!mstacker\currentmathstackers \ifmmode\math_atom_by_parameter\mathstackersparameter\else\dontleavehmode\fi {\math_stackers_reset_variables \edef\m_math_stackers_text_top {#toptext}% \edef\m_math_stackers_text_bottom{#bottomtext}% \ifparameter#bottomtext\or \ifcstok{\mathstackersparameter\c!order}\v!reverse \swapmacros\m_math_stackers_text_top\m_math_stackers_text_bottom \fi \fi \ifcase#method\relax \math_stackers_check_unicode{#codepoint}% \else %\scratchunicode\zerocount \edef\m_math_stackers_text_middle{#codepoint}% \fi \ifempty\m_math_stackers_text_top \setbox\scratchboxone\emptyhbox \else \setmathsmalltextbox\scratchboxone\hbox{\math_stackers_toptext}% \fi \ifempty\m_math_stackers_text_bottom \setbox\scratchboxtwo\emptyhbox \else \setmathsmalltextbox\scratchboxtwo\hbox{\math_stackers_bottomtext}% \fi % \ifcase#method\relax % e.g. extensible %\scratchwidth\wd % \ifdim\wd\scratchboxone>\wd\scratchboxtwo % \scratchboxone % \else % \scratchboxtwo % \fi %\relax \scratchwidth\mathcharwd\scratchunicode \ifdim\wd\scratchboxone>\scratchwidth \scratchwidth\wd\scratchboxone \fi % no \elseif here \ifdim\wd\scratchboxtwo>\scratchwidth \scratchwidth\wd\scratchboxtwo \fi \else \ifempty\m_math_stackers_text_middle \setbox\scratchboxthree\emptyhbox \else \setmathtextbox\scratchboxthree\hbox{\math_stackers_middletext}% \fi \math_stackers_get_max_width \fi % \scratchdimen\mathstackersparameter\c!minwidth\relax \ifdim\scratchwidth<\scratchdimen \scratchwidth\scratchdimen \fi \advanceby\scratchwidth2\scratchhoffset % \ifcase#method\relax \dostarttaggednodetail\t!mstackermid \setbox\scratchboxthree\csname\??mathstackersalternative\p_alternative\endcsname \dostoptagged \fi % \ifdim\wd\scratchboxthree>\scratchwidth % \scratchwidth\wd\scratchboxthree % \fi % \math_stackers_set_max_width % \ifcsname\??mathstackerslocation\p_location\endcsname \ifcase\csname\??mathstackerslocation\p_location\endcsname\relax \scratchdistance\zeropoint \or % top \scratchdistance\zeropoint \or % high \scratchdistance.25\htdp\scratchboxthree \or % centered \scratchdistance.5\htdp\scratchboxthree \or % low \scratchdistance.75\htdp\scratchboxthree \or % bottom \scratchdistance\htdp\scratchboxthree \else \scratchdistance\zeropoint \fi \else \scratchdistance\p_location\htdp\scratchboxthree \fi % \ifzeropt\scratchdistance\else \setbox\scratchboxthree\hpack{\lower\scratchdistance\box\scratchboxthree}% \fi \math_stackers_normalize_three % analysis: is this still ok here? \ifdim\htdp\scratchboxtwo>\zeropoint \ifdim\htdp\scratchboxone>\zeropoint \dosettagproperty\s!subtype\t!munderover \else \dosettagproperty\s!subtype\t!munder \fi \else \ifdim\htdp\scratchboxone>\zeropoint \dosettagproperty\s!subtype\t!mover \else % brrr \fi \fi % base \math_stackers_start_tagged_mid \math_stackers_middle\bgroup \box\scratchboxthree \egroup \math_stackers_stop_tagged % under \ifdim\htdp\scratchboxtwo>\zeropoint \math_stackers_start_tagged_bot \scratchoffset\scratchvoffset \kern-\scratchwidth \math_stackers_bottom\bgroup \lower\dimexpr\ht\scratchboxtwo+\scratchdepth+\scratchoffset+\scratchbottomoffset\relax \box\scratchboxtwo \egroup \math_stackers_stop_tagged \fi % over \ifdim\htdp\scratchboxone>\zeropoint \math_stackers_start_tagged_top \scratchoffset\scratchvoffset \kern-\scratchwidth \math_stackers_top\bgroup \raise\dimexpr\dp\scratchboxone+\scratchheight+\scratchoffset+\scratchtopoffset\relax \box\scratchboxone \egroup \math_stackers_stop_tagged \fi % }% \dostoptagged \mathstackersparameter\c!right\relax \endgroup} %\math_stackers_stop_group} \permanent\tolerant\protected\def\definemathextensible[#1]#*[#2]#*[#3]% category name unicode {\ifarguments\or\or \frozen\protected\edefcsname#1\endcsname{\math_stackers_auto_normal\noexpand\currentmathstackers{\number#2}}% \or \frozen\protected\edefcsname#2\endcsname{\math_stackers_auto_normal{#1}{\number#3}}% \fi} % \tolerant\protected\def\math_stackers_auto_normal#1#2#*[#3]#:#*#=#*#=% % {\begingroup % \scratchcounter#2\relax % \cdef\currentmathstackers{\ifparameter#3\or#3\else#1\fi}% % \math_stackers_triplet\zerocount\currentmathstackers\scratchcounter{#4}{#5}% % \endgroup} \tolerant\protected\def\math_stackers_auto_normal#1#2#*[#3]#:#*#=#*#=% {\begingroup \scratchcounter#2\relax \cdef\currentmathstackers{#1}% \ifhastok={#3}% \setupcurrentmathstackers[#3]% \orelse\ifparameter#3\or \cdef\currentmathstackers{#3}% \fi \math_stackers_triplet\zerocount\currentmathstackers\scratchcounter{#4}{#5}% \endgroup} %D A few direct accessors (in the meantime we redefined \mathextensible so we renamed the %D following): \permanent\tolerant\protected\def\directmathextensible[#category]% {\begingroup \math_stackers_handle_extensible{\ifparameter#category\or#category\else\v!mathematics\fi}} % will be defined later on \permanent\tolerant\protected\def\directtextextensible[#category]% {\begingroup \math_stackers_handle_extensible{\ifparameter#category\or#category\else\v!text\fi}} % will be defined later on \aliased\let\mathstacker\directmathextensible \aliased\let\textstacker\directtextextensible \def\math_stackers_handle_extensible#category#codepoint#toptext#bottomtext% {\math_stackers_triplet\zerocount{#category}{#codepoint}{#toptext}{#bottomtext}% \endgroup} % 1 0 name n 0 | 0 1 name n 0 | 1 1 name n n \let\math_stackers_stop_group\endgroup \protected\def\math_stackers_start_group#category% {\begingroup \cdef\currentmathstackers{#category}% \ifcstok{\mathstackersparameter\c!mathlimits}\v!yes \def\math_stackers_stop_group{\egroup\endgroup\ordlimits}% % \mathop\bgroup \mathaccent\bgroup \else \let\math_stackers_stop_group\endgroup \fi} \newconstant \c_math_stackers_top \newconstant \c_math_stackers_bottom \newconstant \c_math_stackers_codepoint \newconstant \c_math_stackers_extracode \newdimension\d_math_stackers_offset_l \newdimension\d_math_stackers_offset_r \setupmathstackers[lt=\zeropoint,rt=\zeropoint,lb=\zeropoint,rb=\zeropoint] \tolerant\protected\def\math_stackers_make_double#top#bottom#category#codepoint#codeextra#spacer[#S#settings]#:#*#text% {\math_stackers_start_group{#category}% \c_math_stackers_top #top\relax \c_math_stackers_bottom #bottom\relax \c_math_stackers_codepoint#codepoint\relax \c_math_stackers_extracode#codeextra\relax \ifparameter#settings\or \setupcurrentmathstackers[#settings]% \fi \mathstackersparameter\c!left\relax \dostarttagged\t!mstacker\currentmathstackers \ifmmode\math_atom_by_parameter\mathstackersparameter\else\dontleavehmode\fi {\math_stackers_reset_variables \edef\m_math_stackers_text_middle{#text}% \math_stackers_check_unicode\c_math_stackers_codepoint \ifempty\math_stackers_middle \setbox\scratchboxthree\emptyhbox \else \setmathtextbox\scratchboxthree\hbox{\math_stackers_middletext}% \fi \scratchwidth\wd\scratchboxthree % \scratchdimen\mathstackersparameter\c!minwidth\relax \ifdim\scratchwidth<\scratchdimen \scratchwidth\scratchdimen \fi \advanceby\scratchwidth2\scratchhoffset % %\scratchunicode\c_math_stackers_codepoint \ifcase\c_math_stackers_bottom \d_math_stackers_offset_l\mathstackersparameter{lt}% \d_math_stackers_offset_r\mathstackersparameter{rt}% \orelse\ifcase\c_math_stackers_top \d_math_stackers_offset_l\mathstackersparameter{lb}% \d_math_stackers_offset_r\mathstackersparameter{rb}% \else \d_math_stackers_offset_l\mathstackersparameter{lt}% \d_math_stackers_offset_r\mathstackersparameter{rt}% \fi % \setbox\scratchboxtwo\csname\??mathstackersalternative\p_alternative\endcsname \setbox\scratchboxthree\hpack to \scratchwidth{\hss\box\scratchboxthree\hss}% % \scratchunicode\c_math_stackers_extracode \ifcase\scratchunicode\else % uses \scratchunicode \d_math_stackers_offset_l\mathstackersparameter{lb}% \d_math_stackers_offset_r\mathstackersparameter{rb}% \setbox\scratchboxone\csname\??mathstackersalternative\p_alternative\endcsname \fi % \math_stackers_normalize_three \math_stackers_get_max_width \math_stackers_set_max_width % analysis: is this still ok here? \ifcase\c_math_stackers_bottom \ifcase\c_math_stackers_top \dosettagproperty\s!subtype\t!munderover \else \dosettagproperty\s!subtype\t!mover \fi \else \ifcase\c_math_stackers_top \dosettagproperty\s!subtype\t!munder \else % brrr \fi \fi % base \math_stackers_start_tagged_mid \math_stackers_middle\bgroup \box\scratchboxthree \egroup \math_stackers_stop_tagged % \ifdim\htdp\scratchboxtwo>\zeropoint \ifcase\c_math_stackers_bottom\else \kern-\scratchwidth % under \math_stackers_start_tagged_bot \math_stackers_bottom\bgroup \lower\dimexpr \scratchdepth +\ht\ifcase\c_math_stackers_top\scratchboxtwo\else\scratchboxone\fi +\mathstackersparameter\c!distance % was \c!voffset \relax \ifcase\c_math_stackers_top \box\scratchboxtwo \else \box\scratchboxone \fi \egroup \math_stackers_stop_tagged \fi \ifcase\c_math_stackers_top\else \kern-\scratchwidth % over \math_stackers_start_tagged_top \math_stackers_top\bgroup \raise\dimexpr \scratchheight +\dp\scratchboxtwo % new +\mathstackersparameter\c!distance % was \c!voffset \relax \box\scratchboxtwo \egroup \math_stackers_stop_tagged \fi \fi}% \dostoptagged \mathstackersparameter\c!right\relax \math_stackers_stop_group} \permanent\tolerant\protected\def\definemathoverextensible[#1]#*[#2]#*[#3]% {\ifparameter#3\or \frozen\protected\edefcsname#2\endcsname{\math_stackers_make_double\plusone \zerocount{#1}{\number#3}{0}}% \else \frozen\protected\edefcsname#1\endcsname{\math_stackers_make_double\plusone \zerocount\noexpand\currentmathstackers{\number#2}{0}}% \fi} \permanent\tolerant\protected\def\definemathunderextensible[#1]#*[#2]#*[#3]% {\ifparameter#3\or \frozen\protected\edefcsname#2\endcsname{\math_stackers_make_double\zerocount\plusone{#1}{\number#3}{0}}% \else \frozen\protected\edefcsname#1\endcsname{\math_stackers_make_double\zerocount\plusone\noexpand\currentmathstackers{\number#2}{0}}% \fi} \permanent\tolerant\protected\def\definemathdoubleextensible[#1]#*[#2]#*[#3]#*[#4]% {\ifparameter#4\or \frozen\protected\edefcsname#2\endcsname{\math_stackers_make_double\plusone \plusone{#1}{\number#3}{\number#4}}% \else \frozen\protected\edefcsname#1\endcsname{\math_stackers_make_double\plusone \plusone\noexpand\currentmathstackers{\number#2}{\number#3}}% \fi} \permanent\tolerant\protected\def\definemathover[#category]#spacer[#command]#spacer[#topcode]% {\frozen\protected\defcsname#command\endcsname{\math_stackers_handle_direct\plusone\zerocount{#category}{#topcode}{0}}} \permanent\tolerant\protected\def\definemathunder[#category]#spacer[#command]#spacer[#bottomcode]% {\frozen\protected\defcsname#command\endcsname{\math_stackers_handle_direct\zerocount\plusone{#category}{#bottomcode}{0}}} \permanent\tolerant\protected\def\definemathdouble[#category]#spacer[#command]#spacer[#topcode]#spacer[#bottomcode]% {\frozen\protected\defcsname#command\endcsname{\math_stackers_handle_direct\plusone\plusone{#category}{#topcode}{#bottomcode}}} \permanent\tolerant\protected\def\mathover[#category]#spacer[#S#settings]#:#*#topcode#*#text% {\begingroup \cdef\currentmathstackers{\ifparameter#category\or#category\else\v!top\fi}% \ifparameter#settings\or \setupcurrentmathstackers[#settings]% \fi \math_stackers_make_double\plusone\zerocount {\currentmathstackers}% {#topcode}% {0}% {#text}% \endgroup} \permanent\tolerant\protected\def\mathunder[#category]#spacer[#S#settings]#:#*#bottomcode#*#text% {\begingroup \cdef\currentmathstackers{\ifparameter#category\or#category\else\v!bottom\fi}% \ifparameter#settings\or \setupcurrentmathstackers[#settings]% \fi \math_stackers_make_double\zerocount\plusone {\currentmathstackers}% {#bottomcode}% {0}% {#text}% \endgroup} \permanent\tolerant\protected\def\mathdouble[#category]#spacer[#settings]#:#*#topcode#*#bottomcode#*#text% {\begingroup \cdef\currentmathstackers{\ifparameter#category\or#category\else\v!both\fi}% \ifparameter#settings\or \setupcurrentmathstackers[#settings]% \fi \math_stackers_make_double\plusone\plusone {\currentmathstackers}% {#topcode}% {#bottomcode}% {#text}% \endgroup} \def\math_stackers_handle_direct#top#bottom#category#topcode#bottomcode#text% {\begingroup \math_stackers_make_double#top#bottom{#category}{#topcode}{#bottomcode}{#text}% \endgroup} %D A relative new one is a combination of accents and text (as needed in mathml): \protected\def\math_stackers_make_double_text#where#category#codepoint#text#extra% {\math_stackers_start_group{#category}% \mathstackersparameter\c!left\relax \dostarttagged\t!mstacker\currentmathstackers \ifmmode\math_atom_by_parameter\mathstackersparameter\else\dontleavehmode\fi {\math_stackers_reset_variables \edef\m_math_stackers_text_middle{#text}% \math_stackers_check_unicode{#codepoint}% \scratchunicode#codepoint\relax % \ifempty\math_stackers_middle \setbox\scratchboxthree\emptyhbox \else \setmathtextbox\scratchboxthree\hbox{\math_stackers_middletext}% \fi % \ifcase#where\relax \edef\m_math_stackers_text_top{#extra}% \ifempty\math_stackers_top \setbox\scratchboxone\emptyhbox \else \setmathsmalltextbox\scratchboxone\hbox{\math_stackers_toptext}% \fi \else \edef\m_math_stackers_text_bottom{#extra}% \ifempty\math_stackers_bottom \setbox\scratchboxone\emptyhbox \else \setmathsmalltextbox\scratchboxone\hbox{\math_stackers_bottomtext}% \fi \fi % \scratchwidth\wd \ifdim\wd\scratchboxone>\wd\scratchboxthree \scratchboxone \else \scratchboxthree \fi \relax \scratchdimen\mathstackersparameter\c!minwidth\relax \ifdim\scratchwidth<\scratchdimen \scratchwidth\scratchdimen \fi \advanceby\scratchwidth2\scratchhoffset % \ifdim\wd\scratchboxone<\scratchwidth \setbox\scratchboxone\hpack to \scratchwidth{\hss\unhbox\scratchboxone\hss}% \fi \ifdim\wd\scratchboxthree<\scratchwidth \setbox\scratchboxthree\hpack to \scratchwidth{\hss\unhbox\scratchboxthree\hss}% \fi % \math_stackers_normalize_three % analysis: is this still ok here? \dosettagproperty\s!subtype\t!munderover % base \math_stackers_start_tagged_mid \math_stackers_middle\bgroup \box\scratchboxthree \egroup \math_stackers_stop_tagged % \setbox\scratchboxtwo\csname\??mathstackersalternative\p_alternative\endcsname \kern-\scratchwidth \ifcase#where\relax % under \math_stackers_start_tagged_bot \math_stackers_bottom\bgroup \lower\dimexpr \scratchdepth +\ht\scratchboxtwo +\mathstackersparameter\c!distance \relax \box\scratchboxtwo % accent \egroup \math_stackers_stop_tagged \kern-\scratchwidth % over \math_stackers_start_tagged_top \math_stackers_top\bgroup \raise\dimexpr \scratchheight +\dp\scratchboxone +\mathstackersparameter\c!voffset \relax \box\scratchboxone % toptext \egroup \math_stackers_stop_tagged \else % under \math_stackers_start_tagged_bot \math_stackers_bottom\bgroup \lower\dimexpr \scratchdepth +\ht\scratchboxone +\mathstackersparameter\c!voffset \relax \box\scratchboxone % bottext \egroup \math_stackers_stop_tagged \kern-\scratchwidth % over \math_stackers_start_tagged_top \math_stackers_top\bgroup \raise\dimexpr \scratchheight +\dp\scratchboxtwo % new +\mathstackersparameter\c!distance \relax \box\scratchboxtwo % accent \egroup \math_stackers_stop_tagged \fi }% \dostoptagged \mathstackersparameter\c!right\relax \math_stackers_stop_group} \permanent\tolerant\protected\def\definemathovertextextensible[#1]#*[#2]#*[#3]% {\ifparameter#3\or \frozen\protected\edefcsname#2\endcsname{\math_stackers_make_double_text\plusone{#1}{\number#3}}% \else \frozen\protected\edefcsname#1\endcsname{\math_stackers_make_double_text\plusone\noexpand\currentmathstackers{\number#2}}% \fi} \permanent\tolerant\protected\def\definemathundertextextensible[#1]#*[#2]#*[#3]% {\ifparameter#3\or \frozen\protected\edefcsname#2\endcsname{\math_stackers_make_double_text\zerocount{#1}{\number#3}}% \else \frozen\protected\edefcsname#1\endcsname{\math_stackers_make_double_text\zerocount\noexpand\currentmathstackers{\number#2}}% \fi} \permanent\tolerant\protected\def\mathovertext[#category]% {\begingroup \math_stackers_direct_double_text\plusone {\ifarguments#category\or#category\else\v!top\fi}} \permanent\tolerant\protected\def\mathundertext[#category]% {\begingroup \math_stackers_direct_double_text\zerocount{\ifarguments#category\or#category\else\v!bottom\fi}} \def\math_stackers_direct_double_text#where#category#codepoint#text#extra%% {\math_stackers_make_double_text#where{#category}{#codepoint}{#text}{#extra}% \endgroup} %D Here is a bonus macro that takes three texts. It can be used to get consistent %D mixed usage. \permanent\tolerant\protected\def\mathtriplet[#1]#:#*#=#*#=#*#=% {\begingroup \ifparameter#1\or\cdef\currentmathstackers{#1}\fi \math_stackers_triplet\plusone\currentmathstackers{#2}{#3}{#4}% \endgroup} \permanent\tolerant\protected\def\definemathtriplet[#1]#*[#2]#*[#3]% category name default {\ifarguments\or \frozen\protected\edefcsname#1\endcsname{\math_stackers_auto_triplet_nop[\noexpand\currentmathstackers]}% \or \frozen\protected\edefcsname#2\endcsname{\math_stackers_auto_triplet_nop[#1]}% \or \frozen\protected\edefcsname#2\endcsname{\math_stackers_auto_triplet_yes[#1][#3]}% \fi} \tolerant\protected\def\math_stackers_auto_triplet_yes[#1][#2]#*[#3]#:#*#=#*#=% [#2]% #2 gobble spaces {\begingroup \cdef\currentmathstackers{#1}% \def \m_math_stackers_text_middle{#2}% \ifparameter#3\or\cdef\currentmathstackers{#3}\fi \math_stackers_triplet\plusone\currentmathstackers\m_math_stackers_text_middle{#4}{#5}% \endgroup} \tolerant\protected\def\math_stackers_auto_triplet_nop[#1]#*[#2]#:#*#=#*#=#*#=% [#2]% #2 gobble spaces% {\begingroup \cdef\currentmathstackers{#1}% \ifparameter#2\or\cdef\currentmathstackers{#2}\fi \math_stackers_triplet\plusone\currentmathstackers{#3}{#4}{#5}% \endgroup} %D Definitions: \definemathstackers [\v!mathematics] [\c!topcommand=\mathematics, \c!middlecommand=\mathematics, \c!bottomcommand=\mathematics] \definemathstackers [\s!math] [\v!mathematics] \definemathstackers [\v!text] [\v!mathematics] [\c!topcommand=, \c!middlecommand=\mathematics, \c!bottomcommand=] \definemathstackers [\v!reverse] [\v!mathematics] [\c!order=\v!reverse] \definemathstackers [\v!both] [\v!mathematics] [\c!location=\v!top, % ? \c!mathclass=\s!accent, % check chemistry \c!strut=\v!no, \c!middlecommand=\mathematics, \c!hoffset=\zeropoint] \definemathstackers [\v!top] [\v!both] \definemathstackers [\v!bottom] [\v!both] \definemathstackers [\v!vfenced] [\v!both] [\c!mathclass=\s!ordinary, \c!mathlimits=\v!yes, % only these arrows make sense \c!stretch=\v!yes, \c!shrink=\v!yes] % these are needed for mathml: % \setupmathstackers % [\v!both] % [\c!hoffset=1pt, % \c!voffset=1pt] \definemathstackers [\v!bothtext] [\v!both] [\c!strut=\v!yes] % These are compatibity definitions, math only. % todo: top= bottom= middle= is nicer (compare math-fen) %D We save a few definitions that we automatically got from the \type {char-def.lua} %D database. % Be careful in choosing what accents you take (the code below uses a combining % one): % % \startbuffer % % $\Umathaccent top 0 0 "20D7 {example}$ % % $\Umathaccent top fixed 0 0 "20D7 {example}$ % $\Umathaccent 0 0 "20D7 {example}$ % $\Umathaccent fixed 0 0 "20D7 {example}$ % $\Umathaccent bottom 0 0 "20D7 {example}$ % $\Umathaccent bottom fixed 0 0 "20D7 {example}$ % $\Umathaccent both 0 0 "20D7 % 0 0 "20D7 {example}$ % $\Umathaccent both fixed 0 0 "20D7 % fixed 0 0 "20D7 {example}$ % $\Umathaccent both 0 0 "20D7 % fixed 0 0 "20D7 {example}$ % $\Umathaccent both fixed 0 0 "20D7 % 0 0 "20D7 {example}$ % \stopbuffer % % \setupbodyfont[modern] \getbuffer % \setupbodyfont[xits] \getbuffer % \setupbodyfont[cambria] \getbuffer \immutable\protected\def\normaldoublebrace {\Umathaccent \s!both \zerocount \zerocount "23DE \zerocount \zerocount "23DF } \immutable\protected\def\normaldoubleparent{\Umathaccent \s!both \zerocount \zerocount "23DC \zerocount \zerocount "23DD } % let's keep this .. some are not defined so there's nothing normal \aliased\let\normaloverbrace \overbrace \aliased\let\normalunderbrace \underbrace \aliased\let\normaloverparent \overparent \aliased\let\normalunderparent \underparent \aliased\let\normaloverbracket \overbracket \aliased\let\normalunderbracket \underbracket %aliased\let\normalunderleftarrow \underleftarrow %aliased\let\normaloverleftarrow \overleftarrow %aliased\let\normalunderrightarrow\underrightarrow %aliased\let\normaloverrightarrow \overrightarrow %D Here come the new ones: \definemathstackers [\v!none] [\v!mathematics] [\c!hoffset=\zeropoint] \definemathstackers [\v!normal] [\v!mathematics] [\c!hoffset=0.5\mathemwidth] % the default \definemathstackers [\v!small] [\v!mathematics] [\c!hoffset=1\mathemwidth] \definemathstackers [\v!medium] [\v!mathematics] [\c!hoffset=1.5\mathemwidth] \definemathstackers [\v!big] [\v!mathematics] [\c!hoffset=2\mathemwidth] \definemathextensible [\v!reverse] [xrel] ["2212] % ["002D] \definemathextensible [\v!reverse] [xequal] ["003D] \definemathextensible [\v!reverse] [xleftarrow] ["2190] % ["27F5] \definemathextensible [\v!reverse] [xrightarrow] ["2192] % ["27F6] \definemathextensible [\v!reverse] [xleftrightarrow] ["2194] % ["27F7] \definemathextensible [\v!reverse] [xlongleftarrow] ["27F5] \definemathextensible [\v!reverse] [xlongrightarrow] ["27F6] \definemathextensible [\v!reverse] [xlongleftrightarrow] ["27F7] \definemathextensible [\v!reverse] [xLeftarrow] ["27F8] % why not ["27D2] \definemathextensible [\v!reverse] [xRightarrow] ["27F9] % why not ["27D0] \definemathextensible [\v!reverse] [xLeftrightarrow] ["27FA] % why not ["27D4] \definemathextensible [\v!reverse] [xtwoheadleftarrow] ["219E] \definemathextensible [\v!reverse] [xtwoheadrightarrow] ["21A0] \definemathextensible [\v!reverse] [xmapsto] ["21A6] \definemathextensible [\v!reverse] [xhookleftarrow] ["21A9] \definemathextensible [\v!reverse] [xhookrightarrow] ["21AA] \definemathextensible [\v!reverse] [xleftharpoondown] ["21BD] \definemathextensible [\v!reverse] [xleftharpoonup] ["21BC] \definemathextensible [\v!reverse] [xrightharpoondown] ["21C1] \definemathextensible [\v!reverse] [xrightharpoonup] ["21C0] \definemathextensible [\v!reverse] [xrightoverleftarrow] ["21C4] \definemathextensible [\v!reverse] [xleftoverrightarrow] ["21C6] \definemathextensible [\v!reverse] [xleftrightharpoons] ["21CB] \definemathextensible [\v!reverse] [xrightleftharpoons] ["21CC] \definemathextensible [\v!reverse] [xtriplerel] ["2261] \definemathextensible [\v!mathematics] [mrel] ["2212] % ["002D] \definemathextensible [\v!mathematics] [mequal] ["003D] \definemathextensible [\v!mathematics] [mleftarrow] ["2190] % ["27F5] \definemathextensible [\v!mathematics] [mrightarrow] ["2192] % ["27F6] \definemathextensible [\v!mathematics] [mleftrightarrow] ["2194] % ["27F7] \definemathextensible [\v!mathematics] [mLeftarrow] ["21D0] \definemathextensible [\v!mathematics] [mRightarrow] ["21D2] \definemathextensible [\v!mathematics] [mLeftrightarrow] ["21D4] \definemathextensible [\v!mathematics] [mtwoheadleftarrow] ["219E] \definemathextensible [\v!mathematics] [mtwoheadrightarrow] ["21A0] \definemathextensible [\v!mathematics] [mmapsto] ["21A6] \definemathextensible [\v!mathematics] [mhookleftarrow] ["21A9] \definemathextensible [\v!mathematics] [mhookrightarrow] ["21AA] \definemathextensible [\v!mathematics] [mleftharpoondown] ["21BD] \definemathextensible [\v!mathematics] [mleftharpoonup] ["21BC] \definemathextensible [\v!mathematics] [mrightharpoondown] ["21C1] \definemathextensible [\v!mathematics] [mrightharpoonup] ["21C0] \definemathextensible [\v!mathematics] [mrightoverleftarrow] ["21C4] \definemathextensible [\v!mathematics] [mleftoverrightarrow] ["21C6] \definemathextensible [\v!mathematics] [mleftrightharpoons] ["21CB] \definemathextensible [\v!mathematics] [mrightleftharpoons] ["21CC] \definemathextensible [\v!mathematics] [mtriplerel] ["2261] \definemathextensible [\v!text] [trel] ["2212] % ["002D] \definemathextensible [\v!text] [tequal] ["003D] \definemathextensible [\v!text] [tmapsto] ["21A6] \definemathextensible [\v!text] [tleftarrow] ["2190] % ["27F5] \definemathextensible [\v!text] [trightarrow] ["2192] % ["27F6] \definemathextensible [\v!text] [tleftrightarrow] ["2194] % ["27F7] \definemathextensible [\v!text] [tLeftarrow] ["21D0] \definemathextensible [\v!text] [tRightarrow] ["21D2] \definemathextensible [\v!text] [tLeftrightarrow] ["21D4] \definemathextensible [\v!text] [ttwoheadleftarrow] ["219E] \definemathextensible [\v!text] [ttwoheadrightarrow] ["21A0] \definemathextensible [\v!text] [tmapsto] ["21A6] \definemathextensible [\v!text] [thookleftarrow] ["21A9] \definemathextensible [\v!text] [thookrightarrow] ["21AA] \definemathextensible [\v!text] [tleftharpoondown] ["21BD] \definemathextensible [\v!text] [tleftharpoonup] ["21BC] \definemathextensible [\v!text] [trightharpoondown] ["21C1] \definemathextensible [\v!text] [trightharpoonup] ["21C0] \definemathextensible [\v!text] [trightoverleftarrow] ["21C4] \definemathextensible [\v!text] [tleftoverrightarrow] ["21C6] \definemathextensible [\v!text] [tleftrightharpoons] ["21CB] \definemathextensible [\v!text] [trightleftharpoons] ["21CC] \definemathextensible [\v!text] [ttriplerel] ["2261] \definemathoverextensible [\v!top] [overleftarrow] ["2190] % ["27F5] \definemathoverextensible [\v!top] [overrightarrow] ["2192] % ["27F6] \definemathoverextensible [\v!top] [overleftrightarrow] ["2194] % ["27F7] \definemathoverextensible [\v!top] [overtwoheadleftarrow] ["219E] % ["27F8] \definemathoverextensible [\v!top] [overtwoheadrightarrow] ["21A0] % ["27F9] \definemathoverextensible [\v!top] [overlefttailarrow] ["21A2] \definemathoverextensible [\v!top] [overrighttailarrow] ["21A3] \definemathoverextensible [\v!top] [overleftbararrow] ["21A4] \definemathoverextensible [\v!top] [overrightbararrow] ["21A6] \definemathoverextensible [\v!top] [overlefthookarrow] ["21A9] \definemathoverextensible [\v!top] [overrighthookarrow] ["21AA] \definemathoverextensible [\v!top] [overleftharpoondown] ["21BD] \definemathoverextensible [\v!top] [overleftharpoonup] ["21BC] \definemathoverextensible [\v!top] [overrightharpoondown] ["21C1] \definemathoverextensible [\v!top] [overrightharpoonup] ["21C0] \definemathoverextensible [\v!top] [overRightarrow] ["21D2] % ["27F9] \definemathoverextensible [\v!top] [overLeftarrow] ["21D0] % ["27F8] \definemathoverextensible [\v!top] [overLeftrightarrow] ["21D4] % ["27F8] \definemathoverextensible [\v!top] [overLeftbararrow] ["2906] \definemathoverextensible [\v!top] [overRightbararrow] ["2907] \definemathunderextensible [\v!bottom] [underleftarrow] ["2190] % ["27F5] \definemathunderextensible [\v!bottom] [underrightarrow] ["2192] % ["27F6] \definemathunderextensible [\v!bottom] [underleftrightarrow] ["2194] % ["27F7] \definemathunderextensible [\v!bottom] [undertwoheadleftarrow] ["219E] % ["27F8] \definemathunderextensible [\v!bottom] [undertwoheadrightarrow] ["21A0] % ["27F9] \definemathunderextensible [\v!bottom] [underlefttailarrow] ["21A2] \definemathunderextensible [\v!bottom] [underrighttailarrow] ["21A3] \definemathunderextensible [\v!bottom] [underleftbararrow] ["21A4] \definemathunderextensible [\v!bottom] [underrightbararrow] ["21A6] \definemathunderextensible [\v!bottom] [underlefthookarrow] ["21A9] \definemathunderextensible [\v!bottom] [underrighthookarrow] ["21AA] \definemathunderextensible [\v!bottom] [underleftharpoondown] ["21BD] \definemathunderextensible [\v!bottom] [underleftharpoonup] ["21BC] \definemathunderextensible [\v!bottom] [underrightharpoondown] ["21C1] \definemathunderextensible [\v!bottom] [underrightharpoonup] ["21C0] \definemathunderextensible [\v!bottom] [underRightarrow] ["21D2] % ["27F9] \definemathunderextensible [\v!bottom] [underLeftarrow] ["21D0] % ["27F8] \definemathunderextensible [\v!bottom] [underLeftrightarrow] ["21D4] % ["27F8] \definemathunderextensible [\v!bottom] [underLeftbararrow] ["2906] \definemathunderextensible [\v!bottom] [underRightbararrow] ["2907] %D We don't use overline and underline. This is one of the overlooked aspects of %D unicode cq. opentype math: why treat rules different than e.g. arrows and %D accents. It is a bit unfortunate that the opportunity to move math to new %D technologies happened outside the tex domain (and/or some aspects were kept while %D in fact they were side effects of limitations of traditional fonts). From the %D unicode aware tex engines' implementation point of view things could have been %D done a bit nicer but then: the community didn't seem to care too much and just %D has to follow now. %D %D Anyhow, we use a character based approach so that at least we get unicode stuff %D in the backend (okay, we still need to deal with some cut and paste issues but at %D least we now know what we deal with. \definemathoverextensible [\v!vfenced] [overbar] ["203E] % todo: private \definemathunderextensible [\v!vfenced] [underbar] ["203E] % todo: private \definemathdoubleextensible [\v!vfenced] [doublebar] ["203E] ["203E] % todo: private \definemathoverextensible [\v!vfenced] [overbrace] ["23DE] \definemathunderextensible [\v!vfenced] [underbrace] ["23DF] \definemathdoubleextensible [\v!vfenced] [doublebrace] ["23DE] ["23DF] \definemathoverextensible [\v!vfenced] [overparent] ["23DC] \definemathunderextensible [\v!vfenced] [underparent] ["23DD] \definemathdoubleextensible [\v!vfenced] [doubleparent] ["23DC] ["23DD] \definemathoverextensible [\v!vfenced] [overbracket] ["23B4] \definemathunderextensible [\v!vfenced] [underbracket] ["23B5] \definemathdoubleextensible [\v!vfenced] [doublebracket] ["23B4] ["23B5] %D For mathml: \definemathdoubleextensible [\v!both] [overbarunderbar] ["203E] ["203E] % todo: private \definemathdoubleextensible [\v!both] [overbraceunderbrace] ["23DE] ["23DF] \definemathdoubleextensible [\v!both] [overparentunderparent] ["23DC] ["23DD] \definemathdoubleextensible [\v!both] [overbracketunderbracket] ["23B4] ["23B5] \definemathovertextextensible [\v!bothtext] [overbartext] ["203E] % todo: private \definemathundertextextensible [\v!bothtext] [underbartext] ["203E] % todo: private \definemathovertextextensible [\v!bothtext] [overbracetext] ["23DE] \definemathundertextextensible [\v!bothtext] [underbracetext] ["23DF] \definemathovertextextensible [\v!bothtext] [overparenttext] ["23DC] \definemathundertextextensible [\v!bothtext] [underparenttext] ["23DD] \definemathovertextextensible [\v!bothtext] [overbrackettext] ["23B4] \definemathundertextextensible [\v!bothtext] [underbrackettext] ["23B5] % \def\math_stackers_hacked_fill#1#2#3% % {\mathematics % {\begingroup % \mathsurround\zeropoint % \thickmuskip \zeromuskip % \medmuskip \zeromuskip % \thinmuskip \zeromuskip % \tinymuskip \zeromuskip % \pettymuskip \zeromuskip % \ifrelax#1% % \cleaders\mathstylehbox{#2}\hfill % \else % #1% % \mkern-7\onemuskip % \cleaders\mathstylehbox{\mkern-2\onemuskip#2\mkern-2\onemuskip}\hfill % \mkern-7\onemuskip % #3% % \fi % \endgroup}} % % \immutable\protected\def\rightarrowfill {\math_stackers_hacked_fill \relbar \relbar \rightarrow} % \immutable\protected\def\leftarrowfill {\math_stackers_hacked_fill \leftarrow \relbar \relbar} % \immutable\protected\def\rightoverleftarrowfill{\math_stackers_hacked_fill \relax \crightoverleftarrow \relax} % \immutable\protected\def\leftoverrightarrowfill{\math_stackers_hacked_fill \relax \cleftoverrightarrow \relax} % \immutable\protected\def\equalfill {\math_stackers_hacked_fill \Relbar \Relbar \Relbar} % \immutable\protected\def\Rightarrowfill {\math_stackers_hacked_fill \Relbar \Relbar \Rightarrow} % \immutable\protected\def\Leftarrowfill {\math_stackers_hacked_fill \Leftarrow \Relbar \Relbar} % \immutable\protected\def\Leftrightarrowfill {\math_stackers_hacked_fill \Leftarrow \Relbar \Rightarrow} % \immutable\protected\def\leftrightarrowfill {\math_stackers_hacked_fill \leftarrow \relbar \rightarrow} % \immutable\protected\def\mapstofill {\math_stackers_hacked_fill{\mapstochar\relbar} \relbar \rightarrow} % \immutable\protected\def\twoheadrightarrowfill {\math_stackers_hacked_fill \relbar \relbar \twoheadrightarrow} % \immutable\protected\def\twoheadleftarrowfill {\math_stackers_hacked_fill \twoheadleftarrow \relbar \relbar} % \immutable\protected\def\rightharpoondownfill {\math_stackers_hacked_fill \relbar \relbar \rightharpoondown} % \immutable\protected\def\rightharpoonupfill {\math_stackers_hacked_fill \relbar \relbar \rightharpoonup} % \immutable\protected\def\leftharpoondownfill {\math_stackers_hacked_fill \leftharpoondown \relbar \relbar} % \immutable\protected\def\leftharpoonupfill {\math_stackers_hacked_fill \leftharpoonup \relbar \relbar} % \immutable\protected\def\hookleftfill {\math_stackers_hacked_fill \leftarrow \relbar {\relbar\joinrel\rhook}} % \immutable\protected\def\hookrightfill {\math_stackers_hacked_fill{\lhook\joinrel\relbar}\relbar \rightarrow} % \immutable\protected\def\relfill {\math_stackers_hacked_fill \relbar \relbar \relbar} % \immutable\protected\def\triplerelfill {\math_stackers_hacked_fill \equiv \equiv \equiv} % % \permanent\tolerant\protected\def\defineextensiblefiller[#1]#*[#2]% % {\immutable\letcsname\??mathextensiblefallbacks\number#2\expandafter\endcsname\csname#1\endcsname} \installcorenamespace {mathadaptiveextensible} \defineadaptive [mathfiller] [\c!setups=adaptive:mathfiller, \c!stretch=1fill] \startsetups adaptive:mathfiller \setbox\usedadaptivebox\hbox to \usedadaptivewidth \bgroup \startimath \Uhextensible \s!width \usedadaptivewidth \s!middle \zerocount \usedadaptivealternative \relax \stopimath \egroup \stopsetups % \def\mathfiller#1% % {\begingroup % \scratchunicode#1\relax % \adaptivebox[mathfiller][\c!alternative=#1]{\hss\strut\hss}% % \endgroup} \permanent\protected\def\mathfiller#1% {\adaptivebox[mathfiller][\c!alternative=#1]{\hss\strut\hss}} \permanent\tolerant\protected\def\defineextensiblefiller[#1]#*[#2]% {\frozen\instance\edefcsname#1\endcsname{\mathfiller{\number#2}}} %defineextensiblefiller [barfill] ["203E] % % todo: private \defineextensiblefiller [relfill] ["2212] % ["002D] \defineextensiblefiller [equalfill] ["003D] \defineextensiblefiller [leftarrowfill] ["2190] \defineextensiblefiller [rightarrowfill] ["2192] \defineextensiblefiller [twoheadleftarrowfill] ["219E] \defineextensiblefiller [twoheadrightarrowfill] ["21A0] \defineextensiblefiller [mapstofill] ["21A6] %defineextensiblefiller [hookleftarrowfill] ["21A9] % not in fonts %defineextensiblefiller [hookrightarrowfill] ["21AA] % not in fonts \defineextensiblefiller [leftharpoondownfill] ["21BD] \defineextensiblefiller [leftharpoonupfill] ["21BC] \defineextensiblefiller [rightharpoondownfill] ["21C1] \defineextensiblefiller [rightharpoonupfill] ["21C0] \defineextensiblefiller [rightoverleftarrowfill] ["21C4] \defineextensiblefiller [leftoverrightarrowfill] ["21C6] %defineextensiblefiller [leftrightharpoonsfill] ["21CB] % yet undefined %defineextensiblefiller [rightleftharpoonsfill] ["21CC] % yet undefined \defineextensiblefiller [triplerelfill] ["2261] \defineextensiblefiller [leftrightarrowfill] ["27F7] \defineextensiblefiller [Leftarrowfill] ["27F8] \defineextensiblefiller [Rightarrowfill] ["27F9] \defineextensiblefiller [Leftrightarrowfill] ["27FA] \defineextensiblefiller [Rightleftarrowfill] ["27FA] %D Extra: \permanent\protected\edef\singlebond{\mathematics{\mathsurround\zeropoint\char\number"002D\relax}} \permanent\protected\edef\doublebond{\mathematics{\mathsurround\zeropoint\char\number"003D\relax}} \permanent\protected\edef\triplebond{\mathematics{\mathsurround\zeropoint\char\number"2261\relax}} % \mathchardef\singlebond"002D % \mathchardef\doublebond"003D % \mathchardef\triplebond"2261 %D Also handy: \permanent\tolerant\protected\def\definemathunstacked[#1]#*[#2]#*[#3]% category name unicode {\ifarguments\or\or \frozen\protected\edefcsname#1\endcsname{\math_stackers_unstacked_normal\noexpand\currentmathstackers{\number#2}}% \or \frozen\protected\edefcsname#2\endcsname{\math_stackers_unstacked_normal{#1}{\number#3}}% \fi} \protected\def\math_stackers_unstacked_normal#category#codepoint% {\begingroup \cdef\currentmathstackers{#category}% \scratchdistance\zeropoint \scratchcounter\ifchknum\mathstackersparameter\c!sample\or\mathstackersparameter\c!sample\else\zerocount\fi \scratchunicode#codepoint\relax \ifconditional\indisplaymath\ifcase\scratchcounter\orelse\ifnum\lastatomclass=\mathbegincode \scratchdistance\dimexpr \fontcharwd\mathstylefont\mathstyle\scratchcounter -\fontcharwd\mathstylefont\mathstyle\scratchunicode \relax \fi\fi \math_atom_by_parameter\mathstackersparameter {\usemathstackerscolorparameter\c!color \Umathchar\zerocount\zerocount\scratchunicode\relax \ifzeropt\scratchdistance\else \kern\scratchdistance \fi}% \endgroup} \definemathstackers [\s!implication] [\c!mathclass=\s!implication, \c!sample="27FA] \definemathunstacked [\s!implication] [impliedby] ["27F8] \definemathunstacked [\s!implication] [implies] ["27F9] \definemathunstacked [\s!implication] [iff] ["27FA] % \ifandonlyif \definemathunstacked [\s!implication] [impliesby] ["27FA] % This is a weird one: \definemathstackers [\v!wide] [\c!mathclass=\s!implication] \definemathunstacked [\v!wide] [And]["0026] % \mathrel{\;&\;} % New (an example of using \mathexheight): \definemathstackers [\v!symbol] [\c!voffset=-.3\mathexheight, \c!hoffset=\zeropoint, \c!mathclass=\s!ordinary, \c!topoffset=.4\mathemwidth, % poor man's italic correction \c!middlecommand=\mathematics] \definemathover[\v!symbol][interiorset]["2218] \protect \endinput % \mathrel{\mathop{\hbox to \dimen0{\hss\copy4\hss}} % \limits\normalsuperscript{\box0}\normalsubscript{\box2}}% % $\Uoverdelimiter \zerocount "2194 {xxxx}$ % $\Uunderdelimiter\zerocount "2194 {xxxx}$ % $\Udelimiterover \zerocount "2194 {xxxx}$ % $\Udelimiterunder\zerocount "2194 {xxxx}$ % $\Udelimiterover \zerocount "219A {\Udelimiterunder \zerocount "219B {xxxx}}$ % $a \mathrel{\mathop{\filledhboxr{mid}}}\limits^{\filledhboxg{\strut top}}_{\filledhboxb{\strut bottom}} b$