LaTeXML
view release on metacpan or search on metacpan
lib/LaTeXML/Package/amsmath.sty.ltxml view on Meta::CPAN
# \! == \negthinspace
# \negmedspace
# \negthickspace
# these are now native to LaTeX (see section C.7.7 Spacing)
DefConstructor('\mspace{MuDimension}', "<ltx:XMHint name='mspace' width='#1'/>");
#======================================================================
# Section 4.3 Dots
# Nice idea, but not sure what I really should do about it.
# In principle, a processor has access to the context....
DefMathI('\dotsc', undef, "\x{2026}", role => 'ID', alias => '\dotsc');
DefMathI('\dotsb', undef, "\x{22EF}", role => 'ID', alias => '\dotsb');
DefMathI('\dotsm', undef, "\x{22EF}", role => 'ID', alias => '\dotsm');
DefMathI('\dotsi', undef, "\x{22EF}", role => 'ID', alias => '\dotsi');
DefMathI('\dotso', undef, "\x{2026}", role => 'ID', alias => '\dotso');
# Not really clear when these get set to something other than \relax, in amsfonts.sty
DefMacroI('\DOTSB', undef, Tokens());
DefMacroI('\DOTSI', undef, Tokens());
DefMacroI('\DOTSX', undef, Tokens());
Let('\hdots', '\lx@ldots');
DefMacro('\hdotsfor Number', sub {
(map { T_CS('\hdots') } 1 .. $_[1]->valueOf); });
# The basic idea is simple enough (in TeX world);
# Peek to see what follows (\futurelet) and if mathbin or mathrel, use cdots.
# That corresponds to the @role of the following token (once in XML),
# but we're always too early to check it!
# Using a Digested arg seems a little risky, especially "$", but usually can see @role
# This currently doesn't see deeply enough into $after, eg. \boldsymbol{+}
DefPrimitive('\lx@math@dots Digested', sub {
my ($stomach, $after) = @_;
my $role = $after && $after->getProperty('role');
my %binops = (ADDOP => 1, BINOP => 1, MULOP => 1, RELOP => 1);
return (Box(($role && $binops{$role} ? "\x{22EF}" : "\x{2026}"),
undef, undef, T_CS('\dots'), mode => 'math', name => 'dots', role => 'ID'),
$after); });
DefMacro('\dots', '\ifmmode\lx@math@dots\else\lx@ldots\fi', robust => 1);
#======================================================================
# Section 4.4 Nonbreaking dashes
# \nobreakdash
DefMacro('\nobreakdash', ''); # Ignorable
#======================================================================
# Section 4.5 Accents in math
DefMath('\dddot{}', "\x{02D9}\x{02D9}\x{02D9}", operator_role => 'OVERACCENT'); # DOT ABOVE
DefMath('\ddddot{}', "\x{02D9}\x{02D9}\x{02D9}\x{02D9}", operator_role => 'OVERACCENT'); # DOT ABOVE
# In amsxtra
# \sphat \sptilde
#======================================================================
# Section 4.6 Roots
# It would be nice to carry this info through to mathml, but ignore for now.
DefMacro('\leftroot{}', '');
DefMacro('\uproot{}', '');
#======================================================================
# Section 4.7 Boxed formulas
DefMacro('\boxed{}', '\ifmmode\boxed@math{#1}\else\boxed@text{#1}\fi', robust => 1);
DefConstructor('\boxed@math{}',
"<ltx:XMArg enclose='box'>#1</ltx:XMArg>",
alias => '\boxed');
DefConstructor('\boxed@text{}',
"<ltx:Math mode='display' framed='rectangle'>"
. "<ltx:XMath>"
. "#1"
. "</ltx:XMath>"
. "</ltx:Math>",
mode => 'math', bounded => 1,
beforeDigest => sub {
Let("\\\\", '\lx@newline'); },
alias => '\boxed');
DefMath('\implies', "\x{27F9}", role => 'ARROW', meaning => 'implies');
DefMath('\impliedby', "\x{27F8}", role => 'ARROW', meaning => 'implied-by');
DefMath('\And', '&', role => 'ADDOP', meaning => 'and');
#======================================================================
# Section 4.8 Over and under arrows
# Should be in LaTeX (& TeX): \overrightarrow, \overleftarrow
# Note that the arrow is treated as an accent over/under the argument!
DefMath('\underrightarrow{}', "\x{2192}", operator_role => 'UNDERACCENT');
DefMath('\underleftarrow{}', "\x{2190}", operator_role => 'UNDERACCENT');
DefMath('\overleftrightarrow{}', "\x{2194}", operator_role => 'OVERACCENT');
DefMath('\underleftrightarrow{}', "\x{2194}", operator_role => 'UNDERACCENT');
#======================================================================
# Section 4.9 Extensible arrows
# \xleftarrow, \xrightarrow
# set up a general macro to support variations on xarrows macros (see mathtools)
# \lx@long@arrow{token}{arrow}[under]{over}
DefConstructor('\lx@long@arrow DefToken {}[]{}',
"?#3("
. "<ltx:XMApp role='ARROW'>"
. "<ltx:XMWrap role='UNDERACCENT'>#3</ltx:XMWrap>"
. "<ltx:XMApp role='ARROW'>"
. "<ltx:XMWrap role='OVERACCENT'>#4</ltx:XMWrap>"
. "#2"
. "</ltx:XMApp>"
. "</ltx:XMApp>"
. ")("
. "<ltx:XMApp role='ARROW'>"
. "<ltx:XMWrap role='OVERACCENT'>#4</ltx:XMWrap>"
. "#2"
. "</ltx:XMApp>"
. ")",
reversion => sub {
my ($whatsit, $cs, $arrow, $under, $over) = @_;
($cs, ($under ? (T_OTHER('['), Revert($under), T_OTHER(']')) : ()), T_BEGIN, Revert($over), T_END); },
# specialize to ldots ???
properties => { font => sub { LookupValue('font')->specialize("\x{2026}"); } });
DefMacro('\xrightarrow', '\lx@long@arrow{\xrightarrow}{\rightarrow}');
DefMacro('\xleftarrow', '\lx@long@arrow{\xleftarrow}{\leftarrow}');
lib/LaTeXML/Package/amsmath.sty.ltxml view on Meta::CPAN
alias => '\cfrac',
beforeDigest => sub {
$_[0]->bgroup;
MergeFont(mathstyle => LookupValue('cfracmathstyle')); },
afterDigest => sub {
$_[0]->egroup;
$_[1]->setProperties(name => (LookupValue('CFRACSTYLE') eq 'inline' ? 'cfrac-inline' : 'cfrac'),
mathstyle => LookupValue('cfracmathstyle')); });
AssignValue(CFRACSTYLE => 'display');
# This should get incorporated into any \cfrac's that are constructed in scope.
DefConstructor('\cfracstyle{}', '',
afterDigest => sub {
my $style = ToString($_[1]->getArg(1));
$style = ($style eq 'd' ? 'display' : ($style eq 'i' ? 'inline' : $style));
AssignValue(CFRACSTYLE => $style); });
#======================================================================
# Section 4.13 Smash options
DefConstructor('\smash[]{}', "#2"); # well, what?
#======================================================================
# Section 4.14 Delimiters
# Section 4.14.1 Delimiter sizes
# Redefinitions(?) of \bigl, \bigr, \Bigl,\Bigr, \biggl, \biggr, \Biggl, \Biggr
# Section 4.14.2 Vertical bar notations
DefMath('\lvert', '|', role => 'OPEN', stretchy => 'false');
DefMath('\lVert', "\x{2225}", role => 'OPEN', stretchy => 'false'); # PARALLEL TO
DefMath('\rvert', '|', role => 'CLOSE', stretchy => 'false');
DefMath('\rVert', "\x{2225}", role => 'CLOSE', stretchy => 'false'); # PARALLEL TO
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Section 5 Operator names
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#======================================================================
# Section 5.1 Defining new operator names
# See package amsopn (included by default)
#======================================================================
# Section 5.2 \mod and it's relatives
# \bmod, \pmod which are already in LaTeX
DefMath('\mod', 'mod', role => 'MODIFIEROP', meaning => 'modulo');
DefMath('\pod{}', '(#1)', role => 'MODIFIER', meaning => 'modulo'); # Well, sorta postfix..
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Section 6 The \text command
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# See package amstext, included by default.
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Section 7 Integrals and sums
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#======================================================================
# Section 7.1 Multiline subscripts and superscripts
# \substack, \begin{subarray}
# These make the combining operator be list, but often formulae would be better
DefMacro('\substack{}', '\begin{subarray}{c}#1\end{subarray}');
DefMacro('\subarray{}',
'\lx@ams@matrix{name=subarray,style=\scriptsize,datameaning=list,rowsep=0pt,alignment=#1,alignment-required=true}');
DefMacro('\endsubarray', '\lx@end@ams@matrix');
#======================================================================
# Section 7.2 the \sideset command
# This is intended to be a modifier for \sum or \prod
# NOTE that there can be at most one subscript in each of the pre & post, ditto for superscript.
# Thus, our representation is: sideset(presub,presup,postsub,postsup,object)
# Note, also, that this is quite ugly, but since it is a rather peculiar special case.... ?
DefConstructor('\sideset{}{}{}', sub {
my ($document, $pre, $post, $base, %props) = @_;
my @scripts = (undef, undef, undef, undef);
# Just to be "safe", scan for any NON scripts in the pre-scripts
# They work with \sideset, although it isn't clear what they should mean.
# we'll just insert them in front of the whole mess.
foreach my $script ($pre->unlist) {
if (!IsScript($script)) {
Warn('expected', '<sub/supserscript>', $document,
"Expected a sub/superscript in the prescripts of \\sideset",
"Got " . Stringify($script));
$document->insertElement('ltx:XMWrap', $script); } } # Stick any non-scripts FRONT!
my $node = $document->insertElement('ltx:XMArg', $base);
my $ch = $document->getFirstChildElement($node);
my ($opx, $ignore)
= ($ch && $ch->getAttribute('scriptpos') || 'post') =~ /^(pre|mid|post)?(\d+)?$/;
my $level0 = $props{scriptlevel} || 0;
my $level = $level0;
foreach my $script (reverse $pre->unlist) {
# If it's a script, handle it (non-scripts dealt with above & below)
if (my $scriptop = IsScript($script)) {
$node = sidesetWrap($document, $node, 'pre', $$scriptop[1], $level, $script);
$level++ if $$scriptop[0] eq 'FLOATING'; # After node is seen!
} }
my @after = ();
foreach my $script ($post->unlist) {
# If it's a script, handle it (non-scripts dealt with above & below)
if (my $scriptop = IsScript($script)) {
$level++ if $$scriptop[0] eq 'FLOATING'; # Before node is seen!
$node = sidesetWrap($document, $node, 'post', $$scriptop[1], $level, $script); }
else {
push(@after, $script); } } # Save non-scripts
$document->setAttribute($node, scriptpos => $opx . $level0) if $opx;
# Put any garbage in the post-scripts AFTER
foreach my $nonscript (@after) {
Warn('expected', '<sub/supserscript>', $document,
"Expected a sub/superscript in the postscripts of \\sideset",
"Got " . Stringify($nonscript));
$document->insertElement('ltx:XMWrap', $nonscript); } # Append, afterwards
});
sub sidesetWrap {
my ($document, $node, $x, $y, $level, $script) = @_;
my $new = $document->openElement('ltx:XMApp');
$document->insertElement('ltx:XMTok', undef, role => $y . 'OP', scriptpos => "$x$level");
$new->appendChild($node);
( run in 0.550 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )