diff --git a/lib/LaTeXML/Common/Font.pm b/lib/LaTeXML/Common/Font.pm
index 5a0de3410..f9f907287 100644
--- a/lib/LaTeXML/Common/Font.pm
+++ b/lib/LaTeXML/Common/Font.pm
@@ -22,7 +22,7 @@ use LaTeXML::Common::Font::Metric;
use LaTeXML::Common::Font::StandardMetrics;
use LaTeXML::Common::Color;
use List::Util qw(min max sum);
-use base qw(LaTeXML::Common::Object);
+use base qw(LaTeXML::Common::Object);
# Note that this has evolved way beynond just "font",
# but covers text properties (or even display properties) in general
@@ -62,7 +62,7 @@ my $FLAG_EMPH = 0x10;
my %font_family = (
cmr => { family => 'serif' }, cmss => { family => 'sansserif' },
cmtt => { family => 'typewriter' }, cmvtt => { family => 'typewriter' },
- cmti => { family => 'typewriter', shape => 'italic' },
+ cmt => { family => 'serif' }, # for cmti "text italic"
cmfib => { family => 'serif' }, cmfr => { family => 'serif' },
cmdh => { family => 'serif' }, cm => { family => 'serif' },
ptm => { family => 'serif' }, ppl => { family => 'serif' },
diff --git a/lib/LaTeXML/Core/Document.pm b/lib/LaTeXML/Core/Document.pm
index 7c0208785..63b1569be 100644
--- a/lib/LaTeXML/Core/Document.pm
+++ b/lib/LaTeXML/Core/Document.pm
@@ -21,7 +21,7 @@ use LaTeXML::Common::XML;
use LaTeXML::Util::Radix;
use Unicode::Normalize;
use Scalar::Util qw(blessed);
-use base qw(LaTeXML::Common::Object);
+use base qw(LaTeXML::Common::Object);
#**********************************************************************
# These two element names are `leaks' of the document structure into
@@ -771,7 +771,7 @@ sub openText {
$n = $n->parentNode; }
closeToNode($self, $closeto) if $closeto ne $node; # Move to best starting point for this text.
openElement($self, $elementname, font => $font,
- _fontswitch => 1, _autoopened => 1)
+ _fontswitch => 1, _autoopened => 1, _autoclose => 1)
if $bestdiff > 0; # Open if needed.
}
# Finally, insert the darned text.
diff --git a/lib/LaTeXML/Core/State.pm b/lib/LaTeXML/Core/State.pm
index 20d6fcf98..7dbf31c6d 100644
--- a/lib/LaTeXML/Core/State.pm
+++ b/lib/LaTeXML/Core/State.pm
@@ -123,6 +123,17 @@ sub new {
$$self{uccode} = {};
$$self{delcode} = {};
$$self{tracing_definitions} = {};
+ # Initializations that INITEX would have set.
+ $$self{mathcode}{'.'} = [0];
+ for (my $c = ord('0') ; $c <= ord('9') ; $c++) {
+ $$self{mathcode}{ chr($c) } = [0x7000]; }
+ for (my $c = ord('a') ; $c <= ord('z') ; $c++) {
+ my $C = $c + ord('A') - ord('a');
+ $$self{mathcode}{ chr($c) } = [0x7100];
+ $$self{mathcode}{ chr($C) } = [0x7100];
+ $$self{uccode}{ chr($c) } = [$C];
+ $$self{lccode}{ chr($C) } = [$c];
+ $$self{sfcode}{ chr($C) } = [999]; }
return $self; }
sub assign_internal {
diff --git a/lib/LaTeXML/Engine/Base_ParameterTypes.pool.ltxml b/lib/LaTeXML/Engine/Base_ParameterTypes.pool.ltxml
index 764bc8c6f..d9ba052a5 100644
--- a/lib/LaTeXML/Engine/Base_ParameterTypes.pool.ltxml
+++ b/lib/LaTeXML/Engine/Base_ParameterTypes.pool.ltxml
@@ -68,9 +68,13 @@ DefParameterType('Optional', sub {
DefParameterType('GeneralText', sub {
my ($gullet) = @_;
$gullet->unread($gullet->readXToken); # Force expansion to skip before required {
-
return $gullet->readBalanced(0, 0, 1); });
+DefParameterType('XGeneralText', sub {
+ my ($gullet) = @_;
+ $gullet->unread($gullet->readXToken); # Force expansion to skip before required {
+ return $gullet->readBalanced(1, 0, 1); });
+
DefParameterType('Until', sub {
my ($gullet, $until) = @_;
$gullet->readUntil($until); },
@@ -371,26 +375,36 @@ DefParameterType('BalancedParen', sub {
# It is useful when the content would usually need to have been \protect'd
# in order to correctly deal with catcodes.
# BEWARE: This is NOT a shorthand for a simple digested {}!
-DefParameterType('Digested', sub {
- no warnings 'recursion';
- my ($gullet) = @_;
- $gullet->skipSpaces;
- my $ismath = $STATE->lookupValue('IN_MATH');
- my @list = ();
- my $token;
- do { $token = $gullet->readXToken(0);
- } while (defined $token && (($token->getCatcode == CC_SPACE) || $token->equals(T_CS('\relax'))));
- if (!defined $token) { }
- elsif ($token->getCatcode == CC_BEGIN) {
- Digest($token);
- push(@list, $STATE->getStomach->digestNextBody()); pop(@list); } # content w/o the braces
- else {
- push(@list, $STATE->getStomach->invokeToken($token)); }
- @list = grep { ref $_ ne 'LaTeXML::Core::Comment' } @list;
- List(@list, mode => ($ismath ? 'math' : 'text')); },
+sub readDigested {
+ no warnings 'recursion';
+ my ($gullet) = @_;
+ $gullet->skipSpaces;
+ my $ismath = $STATE->lookupValue('IN_MATH');
+ my @list = ();
+ my $token;
+ do { $token = $gullet->readXToken(0);
+ } while (defined $token && (($token->getCatcode == CC_SPACE) || $token->equals(T_CS('\relax'))));
+ if (!defined $token) { }
+ elsif ($token->getCatcode == CC_BEGIN) {
+ Digest($token);
+ push(@list, $STATE->getStomach->digestNextBody()); pop(@list); } # content w/o the braces
+ else {
+ push(@list, $STATE->getStomach->invokeToken($token)); }
+ @list = grep { ref $_ ne 'LaTeXML::Core::Comment' } @list;
+ return List(@list, mode => ($ismath ? 'math' : 'text')); }
+
+DefParameterType('Digested', \&readDigested,
undigested => 1, # since _already_ digested.
reversion => sub { (T_BEGIN, Revert($_[0]), T_END); });
+# Read a Delimiter;
+# Formally a delimiter is either a token, or \delimiter or maybe \radical,
+# but we don't actually restrict to those.
+# Here, we just read a single Digested thing, but reversion gets no braces
+DefParameterType('TeXDelimiter', \&readDigested,
+ undigested => 1, # since _already_ digested.
+ reversion => sub { Revert($_[0]); });
+
# A variation: Digest until we encounter a given token!
DefParameterType('DigestUntil', sub {
my ($gullet, $until) = @_;
diff --git a/lib/LaTeXML/Engine/TeX_FileIO.pool.ltxml b/lib/LaTeXML/Engine/TeX_FileIO.pool.ltxml
index d910db78b..16dfe03e0 100644
--- a/lib/LaTeXML/Engine/TeX_FileIO.pool.ltxml
+++ b/lib/LaTeXML/Engine/TeX_FileIO.pool.ltxml
@@ -106,18 +106,23 @@ DefPrimitive('\openout Number SkipSpaces SkipMatch:= SkipSpaces TeXFileName', su
DefPrimitive('\closeout Number', sub {
my ($stomach, $port) = @_;
$port = ToString($port);
+ if ($LaTeXML::DEBUG{write}) {
+ if (my $filename = LookupValue('output_file:' . $port)) {
+ my $handle = $filename . '_contents';
+ my $contents = LookupValue($handle);
+ Debug("CLOSING $filename with content:\n$contents\n============================="); } }
AssignValue('output_file:' . $port => undef, 'global');
return; });
-DefPrimitive('\write Number {}', sub {
+DefPrimitive('\write Number XGeneralText', sub {
my ($stomach, $port, $tokens) = @_;
$port = ToString($port);
if (my $filename = LookupValue('output_file:' . $port)) {
my $handle = $filename . '_contents';
my $contents = LookupValue($handle);
- AssignValue($handle => $contents . UnTeX(Expand($tokens), 1) . "\n", 'global'); }
+ AssignValue($handle => $contents . UnTeX($tokens, 1) . "\n", 'global'); }
else {
- Note(UnTeX(Expand($tokens))); }
+ Note(UnTeX($tokens)); }
return; });
# Since we don't paginate, we're effectively always "shipping out",
@@ -145,7 +150,7 @@ DefMacro('\input TeXFileName', sub {
#----------------------------------------------------------------------
# \special c sends material to the dvi file for special processing.
-DefPrimitive('\special {}', sub {
+DefPrimitive('\special XGeneralText', sub {
my ($stomach, $arg) = @_;
my $special_str = ToString($arg);
# recognize one special graphics inclusion case
@@ -161,7 +166,7 @@ DefPrimitive('\special {}', sub {
$stomach->getGullet->unread(
T_CS('\ltx@special@graphics'), @kv, T_BEGIN, T_OTHER($graphic), T_END); }
else {
- Info('ignored', 'special', $stomach, 'Unrecognized TeX Special', $arg); }
+ Info('ignored', 'special', $stomach, 'Unrecognized TeX Special' . ToString($arg)); }
return; });
# adapted from graphicx.sty.ltxml
diff --git a/lib/LaTeXML/Engine/TeX_Math.pool.ltxml b/lib/LaTeXML/Engine/TeX_Math.pool.ltxml
index eeb255442..a9225a3d4 100644
--- a/lib/LaTeXML/Engine/TeX_Math.pool.ltxml
+++ b/lib/LaTeXML/Engine/TeX_Math.pool.ltxml
@@ -30,6 +30,9 @@ use LaTeXML::Package;
# \muskip iq assigns to a \muskip register.
# \nonscript c ignores immediately following glue or kern in script and scriptscript styles.
+# This should discard following skip/glue;
+# Should this digest whatever is following tountil non-glue/kern????
+DefPrimitive('\nonscript', undef);
#======================================================================
# The next two sections are the basic LaTeXML Infrastructure for math.
# There are several internal control sequences which need to be renamed!
@@ -347,6 +350,12 @@ sub IsScript {
return [uc($1), uc($2)]; }
return; }
+sub doScriptpos {
+ return (LookupValue('font')->getMathstyle eq 'display' ? 'mid' : 'post'); }
+
+sub doVariablesizeOp {
+ return (LookupValue('font')->getMathstyle eq 'display' ? 'display' : 'text'); }
+
sub scriptHandler {
no warnings 'recursion';
my ($stomach, $op) = @_;
@@ -568,14 +577,14 @@ sub decodeMathChar {
my $font = LookupValue('textfont_' . $fam)
|| LookupValue('scriptfont_' . $fam)
|| LookupValue('scriptscriptfont_' . $fam);
- my $char = chr($n);
- # If no specific class, Lookup properties from a DefMath?
- my $charinfo = LookupValue('math_token_attributes_' . $char);
- my $fontinfo = lookupFontinfo($font);
+ my $char = chr($n);
+ my $fontinfo = lookupFontinfo($font); # Map char(code) to Unicode, via font
+ my $glyph = ($fontinfo && $$fontinfo{encoding} && FontDecode($n, $$fontinfo{encoding}) // $char);
+ # If no specific class, Lookup properties from a DefMath? [Or better yet, Unicode data?]
+ my $charinfo = LookupValue('math_token_attributes_' . $glyph);
my $role = $mathclassrole[$class];
$role = $$charinfo{role} if (!defined $role) && $charinfo;
- return ($role,
- ($fontinfo && $$fontinfo{encoding} ? FontDecode($n, $$fontinfo{encoding}) : $char)); }
+ return ($role, $glyph); }
DefPrimitive('\mathchar Number', sub {
my ($stomach, $code) = @_;
@@ -627,12 +636,23 @@ DefRegister('\mathcode Number', Number(0),
Number(defined $code ? $code : $ch); }, # defaults to the char's code itself(?)
setter => sub { $STATE->assignMathcode(chr($_[2]->valueOf) => $_[0]->valueOf, $_[1]); });
# Not used anywhere (yet)
-DefRegister('\delcode Number', Number(0),
+DefRegister('\delcode Number', Number(-1),
getter => sub { my $code = $STATE->lookupDelcode(chr($_[0]->valueOf));
- Number(defined $code ? $code : 0); },
+ Number(defined $code ? $code : -1); },
setter => sub { $STATE->assignDelcode(chr($_[2]->valueOf) => $_[0]->valueOf, $_[1]); });
-DefRegister('\fam' => Number(-1));
+# This probably needs work;
+# Assigning should choose the font specified by \textfont,\scriptfont...
+# but it should be initialized to -1 at beginning of every math!
+DefRegister('\fam' => Number(-1),
+ getter => sub {
+ $STATE->lookupValue('fontfamily'); },
+ setter => sub {
+ my ($fam, $scope) = @_;
+ $STATE->assignValue('fontfamily' => $fam->valueOf, $scope);
+ if (my $font = $STATE->lookupValue('textfont_' . $fam->valueOf)) {
+ Digest($font); # Digest, since this is a font COMMAND (\font)!!!!!
+} });
#======================================================================
# TeX-level grammatical roles
@@ -652,15 +672,17 @@ DefRegister('\fam' => Number(-1));
# We need a finer granularity than TeX does: an ORD could be several things,
# a BIN could be a MULOP or ADDOP.
# AND, rarely, they're empty.... Is it wrong to drop them?
-DefConstructor('\mathord{}', "?#1(#1)()", bounded => 1);
-DefConstructor('\mathop{}', "?#1(#1)()",
+DefConstructor('\mathord Digested', "?#1(#1)()", bounded => 1);
+# Parameter Should be Digested, but that throws off doScriptPos's position depth !?!?!
+DefConstructor('\mathop {}', "?#1(#1)()",
bounded => 1, properties => { scriptpos => \&doScriptpos });
-DefConstructor('\mathbin{}', "?#1(#1)()", bounded => 1);
-DefConstructor('\mathrel{}', "?#1(#1)()", bounded => 1);
-DefConstructor('\mathopen{}', "?#1(#1)()", bounded => 1);
-DefConstructor('\mathclose{}', "?#1(#1)()", bounded => 1);
-DefConstructor('\mathpunct{}', "?#1(#1)()", bounded => 1);
-DefConstructor('\mathinner{}', "?#1(#1)()", bounded => 1);
+
+DefConstructor('\mathbin Digested', "?#1(#1)()", bounded => 1);
+DefConstructor('\mathrel Digested', "?#1(#1)()", bounded => 1);
+DefConstructor('\mathopen Digested', "?#1(#1)()", bounded => 1);
+DefConstructor('\mathclose Digested', "?#1(#1)()", bounded => 1);
+DefConstructor('\mathpunct Digested', "?#1(#1)()", bounded => 1);
+DefConstructor('\mathinner Digested', "?#1(#1)()", bounded => 1);
#======================================================================
# Delimiters
@@ -670,53 +692,67 @@ DefConstructor('\mathinner{}', "?#1(#1)()",
# This duplicates in slightly different way what DefMath has put together.
# [duplication seems like a bad idea!]
+# This should ultimately be part of some set of Unicode tables.
our %DELIMITER_MAP =
- ('(' => { char => "(", lrole => 'OPEN', rrole => 'CLOSE' },
- ')' => { char => ")", lrole => 'OPEN', rrole => 'CLOSE' },
- '[' => { char => "[", lrole => 'OPEN', rrole => 'CLOSE' },
- ']' => { char => "]", lrole => 'OPEN', rrole => 'CLOSE' },
- '\{' => { char => "{", lrole => 'OPEN', rrole => 'CLOSE' },
- '\}' => { char => "}", lrole => 'OPEN', rrole => 'CLOSE' },
- '\lfloor' => { char => "\x{230A}", lrole => 'OPEN', rrole => 'CLOSE', name => 'lfloor' },
- '\rfloor' => { char => "\x{230B}", lrole => 'OPEN', rrole => 'CLOSE', name => 'rfloor' },
- '\lceil' => { char => "\x{2308}", lrole => 'OPEN', rrole => 'CLOSE', name => 'lceil' },
- '\rceil' => { char => "\x{2309}", lrole => 'OPEN', rrole => 'CLOSE', name => 'rceil' },
- '\langle' => { char => "\x{27E8}", lrole => 'OPEN', rrole => 'CLOSE', name => 'langle' },
- '\rangle' => { char => "\x{27E9}", lrole => 'OPEN', rrole => 'CLOSE', name => 'rangle' },
- '<' => { char => "\x{27E8}", lrole => 'OPEN', rrole => 'CLOSE', name => 'langle' },
- '>' => { char => "\x{27E9}", lrole => 'OPEN', rrole => 'CLOSE', name => 'rangle' },
- '/' => { char => "/", lrole => 'MULOP', rrole => 'MULOP' },
- '\backslash' => { char => UTF(0x5C), lrole => 'MULOP', rrole => 'MULOP', name => 'backslash' },
- '|' => { char => "|", lrole => 'VERTBAR', rrole => 'VERTBAR' },
- '\|' => { char => "\x{2225}", lrole => 'VERTBAR', rrole => 'VERTBAR' },
- '\uparrow' => { char => "\x{2191}", lrole => 'OPEN', rrole => 'CLOSE', name => 'uparrow' }, # ??
- '\Uparrow' => { char => "\x{21D1}", lrole => 'OPEN', rrole => 'CLOSE', name => 'Uparrow' }, # ??
- '\downarrow' => { char => "\x{2193}", lrole => 'OPEN', rrole => 'CLOSE', name => 'downarrow' }, # ??
- '\Downarrow' => { char => "\x{21D3}", lrole => 'OPEN', rrole => 'CLOSE', name => 'Downarrow' }, # ??
- '\updownarrow' => { char => "\x{2195}", lrole => 'OPEN', rrole => 'CLOSE', name => 'updownarrow' }, # ??
- '\Updownarrow' => { char => "\x{21D5}", lrole => 'OPEN', rrole => 'CLOSE', name => 'Updownarrow' }, # ??
+ ('(' => { lrole => 'OPEN', rrole => 'CLOSE' },
+ ')' => { lrole => 'OPEN', rrole => 'CLOSE' },
+ '[' => { lrole => 'OPEN', rrole => 'CLOSE' },
+ ']' => { lrole => 'OPEN', rrole => 'CLOSE' },
+ '{' => { lrole => 'OPEN', rrole => 'CLOSE' },
+ '}' => { lrole => 'OPEN', rrole => 'CLOSE' },
+ "\x{230A}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'lfloor' },
+ "\x{230B}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'rfloor' },
+ "\x{2308}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'lceil' },
+ "\x{2309}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'rceil' },
+ "\x{27E8}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'langle' },
+ "\x{27E9}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'rangle' },
+ '<' => { lrole => 'OPEN', rrole => 'CLOSE', name => 'langle',
+ char => "\x{27E8}", meaning => undef },
+ '>' => { lrole => 'OPEN', rrole => 'CLOSE', name => 'rangle',
+ char => "\x{27E9}", meaning => undef },
+ '/' => { lrole => 'MULOP', rrole => 'MULOP' },
+ UTF(0x5C) => { lrole => 'MULOP', rrole => 'MULOP', name => 'backslash' },
+ '|' => { lrole => 'VERTBAR', rrole => 'VERTBAR' },
+ "\x{2225}" => { lrole => 'VERTBAR', rrole => 'VERTBAR' },
+ "\x{2191}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'uparrow' }, # ??
+ "\x{21D1}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'Uparrow' }, # ??
+ "\x{2193}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'downarrow' }, # ??
+ "\x{21D3}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'Downarrow' }, # ??
+ "\x{2195}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'updownarrow' }, # ??
+ "\x{21D5}" => { lrole => 'OPEN', rrole => 'CLOSE', name => 'Updownarrow' }, # ??
);
-# With new treatment of Simple Symbols as just Box's with assigned attributes,
-# we're not getting whatsits, and so we're not looking them up the same way!!!
-# TEMPORARILY (?) hack the Delimiter map
-foreach my $entry (values %DELIMITER_MAP) {
- $DELIMITER_MAP{ $$entry{char} } = $entry; }
+# The \lx@left, \lx@right versions are like \left,\right but without any extra grouping
+DefConstructor('\lx@left TeXDelimiter',
+ "?#hint()(#1)",
+ afterDigest => sub { my ($stomach, $whatsit) = @_;
+ $whatsit->setProperty(hint => 1) if ToString($whatsit->getArg(1)) eq '.';
+ return; },
+ afterConstruct => sub { augmentDelimiterProperties($_[0], $_[1], 'OPEN'); },
+ alias => '\left');
-sub lookup_delimiter {
- my ($delim) = @_;
- return $DELIMITER_MAP{$delim}; }
+DefConstructor('\lx@right TeXDelimiter',
+ "?#hint()(#1)",
+ afterDigest => sub { my ($stomach, $whatsit) = @_;
+ $whatsit->setProperty(hint => 1) if ToString($whatsit->getArg(1)) eq '.';
+ return; },
+ afterConstruct => sub { augmentDelimiterProperties($_[0], $_[1], 'CLOSE'); },
+ alias => '\right');
# This is a little messier than you'd think.
-# These effectively create a group between the \left,\right.
-# And this also gives us a single list of things to parse separately.
-# Since \left,\right are TeX, primitives and must be paired up,
-# we use a bit of macro trickery to simulate.
-# [The \lx@hidden@bgroup/egroup keep from putting a {} into the UnTeX]
-# HOWEVER, an additional complication is that it is a common mistake to omit the balancing \right!
-# Using an \egroup (or hidden) makes it hard to recover, so use a special egroup
-DefMacro('\left XToken', '\lx@left #1\lx@hidden@bgroup');
-# Like \lx@hidden@egroup, but softer about missing \left
+# These effectively create a (boxing) group BETWEEN the \left,\right. (but should be hidden)
+# But you have to digest \left's delimiter before you can start the {...} group!
+DefConstructor('\left TeXDelimiter',
+ "?#hint()(#1)",
+ afterDigest => sub { my ($stomach, $whatsit) = @_;
+ $whatsit->setProperty(hint => 1) if ToString($whatsit->getArg(1)) eq '.';
+ $stomach->getGullet->unread(T_CS('\lx@hidden@bgroup'));
+ return; },
+ afterConstruct => sub { augmentDelimiterProperties($_[0], $_[1], 'OPEN'); });
+
+DefMacro('\right', '\lx@hidden@egroup@right\lx@right');
+
+# \lx@hidden@egroup@right tries to manage unbalanced {} errors, if an \left was forgotten.
DefConstructor('\lx@hidden@egroup@right', '',
afterDigest => sub {
my ($stomach) = @_;
@@ -727,50 +763,30 @@ DefConstructor('\lx@hidden@egroup@right', '',
$stomach->egroup; } },
reversion => '');
-DefMacro('\right XToken', '\lx@hidden@egroup@right\lx@right #1');
-
-DefConstructor('\lx@left Token',
- "?#char(#char)"
- . "(?#hint()(#1))",
- afterDigest => sub { my ($stomach, $whatsit) = @_;
- my $arg = $whatsit->getArg(1);
- my $delim = ToString($arg);
- if ($delim eq '.') {
- $whatsit->setProperty(hint => 1); }
- elsif (my $entry = $DELIMITER_MAP{$delim}) {
- $whatsit->setProperties(role => $$entry{lrole},
- char => $$entry{char},
- name => $$entry{name},
- stretchy => 'true');
- $whatsit->setFont($arg->getFont()); }
- elsif (($arg->getProperty('role') || '') eq 'OPEN') {
- $arg->setProperty(stretchy => 'true'); }
- else {
- Warn('unexpected', $delim, $stomach,
- "Missing delimiter; '.' inserted"); }
- return; },
- alias => '\left');
-DefConstructor('\lx@right Token',
- "?#char(#char)"
- . "(?#hint()(#1))",
- afterDigest => sub { my ($stomach, $whatsit) = @_;
- my $arg = $whatsit->getArg(1);
- my $delim = ToString($arg);
- if ($delim eq '.') {
- $whatsit->setProperty(hint => 1); }
- elsif (my $entry = $DELIMITER_MAP{$delim}) {
- $whatsit->setProperties(role => $$entry{rrole},
- char => $$entry{char},
- name => $$entry{name},
- stretchy => 'true');
- $whatsit->setFont($arg->getFont()); }
- elsif (($arg->getProperty('role') || '') eq 'CLOSE') {
- $arg->setProperty(stretchy => 'true'); }
- else {
- Warn('unexpected', $delim, $stomach,
- "Missing delimiter; '.' inserted)"); }
- return; },
- alias => '\right');
+# Add delimiter relevant attributes to the current token
+sub augmentDelimiterProperties {
+ my ($document, $whatsit, $pos) = @_;
+ my $current = $document->getNode;
+ my $delim = $document->getLastChildElement($current) || $current;
+ my $char = $delim && $delim->textContent;
+ $document->setNodeBox($delim, $whatsit);
+ if ($whatsit->getProperty('hint')) { }
+ elsif (my $entry = $DELIMITER_MAP{$char}) {
+ $delim->setAttribute(role => $$entry{ ($pos eq 'OPEN' ? 'lrole' : 'rrole') } || $pos);
+ $delim->setAttribute(name => $$entry{name}) if $$entry{name};
+ $delim->setAttribute(stretchy => 'true');
+ if (exists $$entry{meaning}) {
+ if (my $meaning = $$entry{meaning}) {
+ $delim->setAttribute(meaning => $meaning); }
+ else {
+ $delim->removeAttribute('meaning'); } } # RETRACT the assumed meaning on the delimiter
+ if (exists $$entry{char}) {
+ if (my $char = $$entry{char}) {
+ $delim->firstChild->setData($char); } }
+ }
+ elsif (($delim->getAttribute('role') || '') eq $pos) {
+ $delim->setAttribute(stretchy => 'true'); }
+ return; }
#======================================================================
# Limit placement
@@ -1165,7 +1181,7 @@ DefMacroI('\eqno', undef, sub {
|| (ToString($t) =~ /^\\(?:begin|end)\{/) # any sort of environ begin or end???
# This seems needed within AmSTeX environs
) {
- return (Invocation(T_CS('\lx@eqno'), Tokens(@stuff)), $t); }
+ return (Invocation(T_CS('\lx@eqno'), Tokens(@stuff, T_CS('\relax'))), $t); }
else {
push(@stuff, $t); } }
Error('unexpected', '\eqno', $gullet, "Fell of the end reading tag for \\eqno!",
diff --git a/lib/LaTeXML/Engine/plain.pool.ltxml b/lib/LaTeXML/Engine/plain.pool.ltxml
index 36d413088..036ed3c92 100644
--- a/lib/LaTeXML/Engine/plain.pool.ltxml
+++ b/lib/LaTeXML/Engine/plain.pool.ltxml
@@ -20,13 +20,6 @@ use LaTeXML::Package;
# Plain; Extracted from Appendix B.
#**********************************************************************
-# Remember, we're assigning a NUMBER (codepoint) to a CHARACTER!
-foreach my $letter (ord('A') .. ord('Z')) {
- $STATE->assignLCcode(chr($letter), $letter + 0x20, 'global');
- $STATE->assignUCcode(chr($letter), $letter, 'global');
- $STATE->assignLCcode(chr($letter + 0x20), $letter + 0x20, 'global');
- $STATE->assignUCcode(chr($letter + 0x20), $letter, 'global'); }
-
DefRegister('\magnification' => Number(1000));
Let('\bye', '\end');
@@ -818,6 +811,7 @@ DefMathI('\surd', undef, "\x{221A}", role => 'OPERATOR', meaning => 'square-
DefMathI('\top', undef, "\x{22A4}", role => 'ADDOP', meaning => 'top');
DefMathI('\bot', undef, "\x{22A5}", role => 'ADDOP', meaning => 'bottom');
DefMathI('\|', undef, "\x{2225}", role => 'VERTBAR', name => '||');
+
# should get meaning => 'parallel-to' when used as infix, but NOT when for OPEN|CLOSE
DefMathI('\angle', undef, "\x{2220}");
@@ -867,12 +861,6 @@ DefMath('\smallint', "\x{222B}", meaning => 'integral', role => 'INTOP',
#----------------------------------------------------------------------
# Actually LaTeX; Table 3.8. Variable-sized Symbols, p.44.
#----------------------------------------------------------------------
-sub doScriptpos {
- return (LookupValue('font')->getMathstyle eq 'display' ? 'mid' : 'post'); }
-
-sub doVariablesizeOp {
- return (LookupValue('font')->getMathstyle eq 'display' ? 'display' : 'text'); }
-
DefMathI('\sum', undef, "\x{2211}",
role => 'SUMOP',
scriptpos => \&doScriptpos,
diff --git a/lib/LaTeXML/Package.pm b/lib/LaTeXML/Package.pm
index 61c16ef50..9146c7948 100644
--- a/lib/LaTeXML/Package.pm
+++ b/lib/LaTeXML/Package.pm
@@ -1523,8 +1523,8 @@ my $math_options = { # [CONSTANT]
revert_as => 1,
hide_content_reversion => 1 }; # DEPRECATE!
my $simpletoken_options = { # [CONSTANT]
- name => 1, meaning => 1, omcd => 1, role => 1, mathstyle => 1,
- protected => 1, robust => 1,
+ name => 1, meaning => 1, omcd => 1, role => 1, mathstyle => 1, stretchy => 1,
+ protected => 1, robust => 1, alias => 1,
lpadding => 1, rpadding => 1,
font => 1, scriptpos => 1, scope => 1, locked => 1 };
@@ -1746,13 +1746,16 @@ sub defmath_prim {
my %properties = %options;
my $font = LookupValue('font')->merge(%$reqfont)->specialize($string);
my $mode = (LookupValue('IN_MATH') ? 'math' : 'text');
+ my $alias = (ref $options{alias} ? $options{alias}
+ : (defined $options{alias} ? T_CS($options{alias}) : undef));
+ my $reversion =
+ ((!defined $options{reversion}) && (($options{revert_as} || '') eq 'presentation')
+ ? $presentation : $alias // $cs);
foreach my $key (keys %properties) {
my $value = $properties{$key};
if (ref $value eq 'CODE') {
$properties{$key} = &$value(); } }
- LaTeXML::Core::Box->new($string, $font, $locator,
- ((!defined $options{reversion}) && (($options{revert_as} || '') eq 'presentation')
- ? $presentation : $cs),
+ LaTeXML::Core::Box->new($string, $font, $locator, $reversion,
mode => $mode, %properties); }));
return; }
diff --git a/t/ams/mathtools.xml b/t/ams/mathtools.xml
index 684f685bf..7173f2336 100644
--- a/t/ams/mathtools.xml
+++ b/t/ams/mathtools.xml
@@ -1865,7 +1865,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -1904,7 +1904,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2070,7 +2070,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2095,7 +2095,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2107,7 +2107,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2132,7 +2132,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2248,7 +2248,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2280,7 +2280,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2292,7 +2292,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2324,7 +2324,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2440,7 +2440,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2472,7 +2472,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2484,7 +2484,7 @@ Then a switch of tag forms.
- ‖
+ ‖
@@ -2516,7 +2516,7 @@ Then a switch of tag forms.
- ‖
+ ‖
diff --git a/t/ams/matrix.xml b/t/ams/matrix.xml
index 4dca4cc3e..4a1389be8 100644
--- a/t/ams/matrix.xml
+++ b/t/ams/matrix.xml
@@ -172,7 +172,7 @@
- ‖
+ ‖
@@ -188,7 +188,7 @@
- ‖
+ ‖
diff --git a/t/complex/physics.xml b/t/complex/physics.xml
index d515018b0..d9b74f3d7 100644
--- a/t/complex/physics.xml
+++ b/t/complex/physics.xml
@@ -296,9 +296,9 @@
- ‖
+ ‖
a
- ‖
+ ‖
diff --git a/t/digestion/io.pdf b/t/digestion/io.pdf
index 6c7a1daf7..96f545a36 100644
Binary files a/t/digestion/io.pdf and b/t/digestion/io.pdf differ
diff --git a/t/digestion/io.tex b/t/digestion/io.tex
index bb41972aa..5f39974de 100644
--- a/t/digestion/io.tex
+++ b/t/digestion/io.tex
@@ -94,7 +94,8 @@
\immediate\openout\file = generated.data
\immediate\write\file {First line}
\immediate\write\file {Second line}
-\immediate\write\file {Timing \timing.}
+\immediate\write\file {Timing before: \timing.}
+\immediate\write\file {Timing after: \noexpand\timing.}
\immediate\write\file {Last line}
\immediate\closeout\file
\def\timing{After}
diff --git a/t/digestion/io.xml b/t/digestion/io.xml
index 16fe9262b..f7dccd946 100644
--- a/t/digestion/io.xml
+++ b/t/digestion/io.xml
@@ -385,7 +385,10 @@ Line: “First line
Line: “Second line
”
-Line: “Timing Before.
+Line: “Timing before: Before.
+”
+
+Line: “Timing after: After.
”
Line: “Last line
diff --git a/t/math/sampler.xml b/t/math/sampler.xml
index 46e1e2e07..a85e112f8 100644
--- a/t/math/sampler.xml
+++ b/t/math/sampler.xml
@@ -1411,7 +1411,7 @@ are not currently tested.
- ‖
+ ‖
@@ -1436,7 +1436,7 @@ are not currently tested.
- ‖
+ ‖
,
@@ -1449,7 +1449,7 @@ are not currently tested.
- ‖
+ ‖
@@ -1474,7 +1474,7 @@ are not currently tested.
- ‖
+ ‖
diff --git a/t/parse/parens.pdf b/t/parse/parens.pdf
index 8e3fbe7ab..109cabcb0 100644
Binary files a/t/parse/parens.pdf and b/t/parse/parens.pdf differ
diff --git a/t/parse/parens.tex b/t/parse/parens.tex
index b5c5c7b49..aa7511b88 100644
--- a/t/parse/parens.tex
+++ b/t/parse/parens.tex
@@ -40,6 +40,7 @@ \section{Delimiters}
\[ \left\lceil {a \over b} \right\rceil \]
\[ \left< {a \over b} \right> \]
\[ \left\langle {a \over b} \right\rangle \]
+\[ \left\delimiter"426830A {a \over b} \right\delimiter"526930B \]
\[ \left| {a \over b} \right| \]
\[ \left\vert {a \over b} \right\vert \]
\[ \left\| {a \over b} \right\| \]
@@ -48,6 +49,8 @@ \section{Delimiters}
\[ \left\Uparrow {a \over b} \right\Downarrow \]
\[ \left\updownarrow {a \over b} \right\Updownarrow \]
+
+
\def\foo{\langle}
\def\bar{\rangle}
\[ a + \left\foo {b \over c} \right\bar + d \]
diff --git a/t/parse/parens.xml b/t/parse/parens.xml
index 10d3d9330..f873b0abc 100644
--- a/t/parse/parens.xml
+++ b/t/parse/parens.xml
@@ -537,21 +537,21 @@
-
-
+
-
+
- ‖
+ |
a
b
- ‖
+ |
@@ -608,75 +608,96 @@
- ‖
+ ‖
a
b
- ‖
+ ‖
-
+
-
+
- ↑
+ ‖
a
b
- ↓
+ ‖
-
+
-
+
- ⇑
+ ↑
a
b
- ⇓
+ ↓
-
+
-
+
- ↕
+ ⇑
a
b
+ ⇓
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ↕
+
+
+ a
+ b
+
⇕
@@ -685,8 +706,8 @@
-
-
+
+
+
@@ -694,11 +715,11 @@
-
+
⟨
-
+
b
c
@@ -713,11 +734,11 @@
-
-
+
+
- /
+ /
a