diff --git a/lib/LaTeXML/Core/Alignment.pm b/lib/LaTeXML/Core/Alignment.pm
index 6b6458bf5..ff3fc946f 100644
--- a/lib/LaTeXML/Core/Alignment.pm
+++ b/lib/LaTeXML/Core/Alignment.pm
@@ -21,8 +21,8 @@ use LaTeXML::Common::XML;
use LaTeXML::Common::Dimension;
use LaTeXML::Core::Alignment::Template;
use List::Util qw(max sum);
-use base qw(LaTeXML::Core::Whatsit);
-use base qw(Exporter);
+use base qw(LaTeXML::Core::Whatsit);
+use base qw(Exporter);
our @EXPORT = (qw(
&ReadAlignmentTemplate &MatrixTemplate));
@@ -1407,7 +1407,7 @@ sub summarize_alignment {
__END__
-=pod
+=pod
=head1 NAME
diff --git a/lib/LaTeXML/Core/Definition/Constructor.pm b/lib/LaTeXML/Core/Definition/Constructor.pm
index 2fc65df7d..85ac60ec7 100644
--- a/lib/LaTeXML/Core/Definition/Constructor.pm
+++ b/lib/LaTeXML/Core/Definition/Constructor.pm
@@ -74,6 +74,7 @@ sub getNumArgs {
# Digest the constructor; This should occur in the Stomach to create a Whatsit.
# The whatsit which will be further processed to create the document.
sub invoke {
+ no warnings 'recursion';
my ($self, $stomach) = @_;
# Call any `Before' code.
my $_tracing = $STATE->lookupValue('TRACING') || 0;
diff --git a/lib/LaTeXML/Core/Parameter.pm b/lib/LaTeXML/Core/Parameter.pm
index 462ccc069..31fbff912 100644
--- a/lib/LaTeXML/Core/Parameter.pm
+++ b/lib/LaTeXML/Core/Parameter.pm
@@ -84,7 +84,7 @@ sub read {
# Hmmm, seem to still need it...
if ($$self{semiverbatim}) { # Open coded setupCatcodes
$STATE->beginSemiverbatim(@{ $$self{semiverbatim} }); }
-
+ no warnings 'recursion';
my $value = &{ $$self{reader} }($gullet, @{ $$self{extra} || [] });
$value = $value->neutralize(@{ $$self{semiverbatim} }) if $$self{semiverbatim} && (ref $value)
&& $value->can('neutralize');
diff --git a/lib/LaTeXML/Core/Parameters.pm b/lib/LaTeXML/Core/Parameters.pm
index bc0454d1e..7db50f067 100644
--- a/lib/LaTeXML/Core/Parameters.pm
+++ b/lib/LaTeXML/Core/Parameters.pm
@@ -57,12 +57,14 @@ sub revertArguments {
return @tokens; }
sub readArguments {
+ no warnings 'recursion';
my ($self, $gullet, $fordefn) = @_;
my @args = ();
my ($p, $v);
return map { $p = $_; $v = $p && $p->read($gullet, $fordefn); ($$p{novalue} ? () : $v); } @$self; }
sub readArgumentsAndDigest {
+ no warnings 'recursion';
my ($self, $stomach, $fordefn) = @_;
my @args = ();
my $gullet = $stomach->getGullet;
@@ -77,6 +79,7 @@ sub reparseArgument {
my ($self, $gullet, $tokens) = @_;
if (defined $tokens) {
return $gullet->readingFromMouth(LaTeXML::Core::Mouth->new(), sub { # start with empty mouth
+ no warnings 'recursion';
my ($gulletx) = @_;
$gulletx->unread($tokens); # but put back tokens to be read
my @values = $self->readArguments($gulletx);
diff --git a/lib/LaTeXML/MathParser.pm b/lib/LaTeXML/MathParser.pm
index 965267ccf..ad18c944f 100644
--- a/lib/LaTeXML/MathParser.pm
+++ b/lib/LaTeXML/MathParser.pm
@@ -1008,7 +1008,11 @@ sub is_genuinely_unparsed {
if (!$node->getAttribute('idref')) {
return 1; }
else {
- return is_genuinely_unparsed(realizeXMNode($node), $document); } }
+ my $real_node = realizeXMNode($node);
+ # Note that some parses fail with an ARRAY ref [ltx:Error,...]
+ # so realizeXMNode may fail!
+ return 1 if (ref $real_node) !~ /^XML::LibXML/;
+ return is_genuinely_unparsed($real_node, $document); } }
elsif ($tag eq 'ltx:XMDual') {
my ($content, $presentation) = element_nodes($node);
return is_genuinely_unparsed($content, $document); }
diff --git a/lib/LaTeXML/Package/LaTeX.pool.ltxml b/lib/LaTeXML/Package/LaTeX.pool.ltxml
index 45789dad0..e7aba2021 100644
--- a/lib/LaTeXML/Package/LaTeX.pool.ltxml
+++ b/lib/LaTeXML/Package/LaTeX.pool.ltxml
@@ -4919,8 +4919,8 @@ EOL
Let('\lx@parboxnewline', '\lx@newline'); # Obsolete, but in case still used
# NOTE: There are 2 extra arguments (See LaTeX Companion, p.866)
-# for height and inner-pos. We're ignoring them, for now, though.
-DefConstructor('\parbox[] OptionalUndigested OptionalUndigested {Dimension} VBoxContents', sub {
+# for height and inner-pos. We're ignoring inner-pos, for now, though.
+DefConstructor('\parbox[] [Dimension] OptionalUndigested {Dimension} VBoxContents', sub {
my ($document, $attachment, $b, $c, $width, $body, %props) = @_;
insertBlock($document, $body,
width => $width,
diff --git a/lib/LaTeXML/Package/TeX.pool.ltxml b/lib/LaTeXML/Package/TeX.pool.ltxml
index 3554447be..978fee0f3 100644
--- a/lib/LaTeXML/Package/TeX.pool.ltxml
+++ b/lib/LaTeXML/Package/TeX.pool.ltxml
@@ -456,6 +456,7 @@ DefParameterType('BalancedParen', sub {
# 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');
@@ -4443,11 +4444,12 @@ DefPrimitiveI(T_SUB, undef, sub { scriptHandler($_[0], 'SUBSCRIPT'); });
# at the least they're ugly; in some applications they affect "round trip" processing.
# OTOH, direct use of \@@POSTSUPERSCRIPT, etal, MAY need to have extra braces around them.
# So, when reverting, we're going to a bit of extra trouble to make sure we have ONE set
-# of braces, but no extras!! [Worry about lists of lists...]
+# of braces, but no extras!!
sub revertScript {
my ($script) = @_;
- my @tokens = $script->revert;
- my @t = @tokens;
+ # We need to handle lists of lists, see arXiv:2210.11051
+ my @tokens = Tokens($script->revert)->unlist;
+ my @t = @tokens;
my $l;
if ($t[0]->defined_as(T_BEGIN)) {
$l++; shift(@t); }
diff --git a/lib/LaTeXML/Package/import.sty.ltxml b/lib/LaTeXML/Package/import.sty.ltxml
index 1b0e9d537..6efd4a8bf 100644
--- a/lib/LaTeXML/Package/import.sty.ltxml
+++ b/lib/LaTeXML/Package/import.sty.ltxml
@@ -20,6 +20,8 @@ use LaTeXML::Util::Pathname;
DefPrimitive('\lx@set@path OptionalMatch:* {}', sub {
my ($stomach, $star, $path) = @_;
$path = ToString(Expand($path));
+ if (!pathname_is_absolute($path)) {
+ $path = pathname_absolute($path, LookupValue('SOURCEDIRECTORY')); }
if ($star) { # * omits TEXINPUTS!
AssignValue(SEARCHPATHS => [pathname_canonical($path)]); }
else {
@@ -46,4 +48,3 @@ Let('\subinputfrom', '\subimport');
#======================================================================
1;
-
diff --git a/lib/LaTeXML/Package/lipsum.sty.ltxml b/lib/LaTeXML/Package/lipsum.sty.ltxml
index f4038c831..4f8648571 100644
--- a/lib/LaTeXML/Package/lipsum.sty.ltxml
+++ b/lib/LaTeXML/Package/lipsum.sty.ltxml
@@ -15,6 +15,6 @@ use strict;
use warnings;
use LaTeXML::Package;
-LoadPool('expl3');
+RequirePackage('xparse');
InputDefinitions('lipsum', type => 'sty', noltxml => 1);
1;
diff --git a/lib/LaTeXML/Package/listings.sty.ltxml b/lib/LaTeXML/Package/listings.sty.ltxml
index 3956c00e4..1c953d114 100644
--- a/lib/LaTeXML/Package/listings.sty.ltxml
+++ b/lib/LaTeXML/Package/listings.sty.ltxml
@@ -1286,13 +1286,11 @@ sub lstProcess {
grep { $$delimiters{$_}{escape} } sort keys %$delimiters);
local $LaTeXML::QUOTED_RE = "\\\\\\\\"; # start w/ backslashed backslash?
local $LaTeXML::SPACE = (lstGetBoolean('showspaces') ? T_CS('\@lst@visible@space') : T_CS(" "));
- local $LaTeXML::CASE_SENSITIVE = lstGetBoolean('sensitive');
- # Don't these need \Q,\E?
- # local $LaTeXML::LITERATE_RE = join('|', map { "\\Q" . $$_[0] . "\\E"; } @$literate);
- local $LaTeXML::LITERATE_RE = join('|', map { $$_[0]; } @$literate);
- local $LaTeXML::LITERATE_INNER_RE = join('|', map { $$_[0]; } grep { !$$_[2]; } @$literate);
- if (!$LaTeXML::CASE_SENSITIVE) { # Clunky, inefficient, but until we know, we don't know
- foreach my $word (keys %$words) { # Modify in place (they'll get rebuilt if/when needed)
+ local $LaTeXML::CASE_SENSITIVE = lstGetBoolean('sensitive');
+ local $LaTeXML::LITERATE_RE = join('|', map { quotemeta($$_[0]); } @$literate);
+ local $LaTeXML::LITERATE_INNER_RE = join('|', map { quotemeta($$_[0]); } grep { !$$_[2]; } @$literate);
+ if (!$LaTeXML::CASE_SENSITIVE) { # Clunky, inefficient, but until we know, we don't know
+ foreach my $word (keys %$words) { # Modify in place (they'll get rebuilt if/when needed)
$$words{ uc($word) } = $$words{$word}; } }
# === Start processing
diff --git a/lib/LaTeXML/Package/multirow.sty.ltxml b/lib/LaTeXML/Package/multirow.sty.ltxml
index 330ac3b19..8de0cf616 100644
--- a/lib/LaTeXML/Package/multirow.sty.ltxml
+++ b/lib/LaTeXML/Package/multirow.sty.ltxml
@@ -16,11 +16,22 @@ use warnings;
use LaTeXML::Package;
DefPrimitive('\multirowsetup', undef);
-DefPrimitive('\multirow[]{Number}[Number]{}[Dimension]{}', sub {
+DefPrimitive('\multirow[]{Float}[Number]{}[Dimension]{}', sub {
my ($stomach, $attachment, $nrows, $bigstruts, $width, $fixup, $content) = @_;
if (my $alignment = LookupValue('Alignment')) {
my $colspec = $alignment->currentColumn;
- $$colspec{rowspan} = $nrows->valueOf;
+ my $rowspan = $nrows->valueOf;
+ if ($rowspan < 0) {
+ # Example from arXiv:2210.15835
+ # \multirow{-8.2}{*}{\includegraphics[width=0.398\linewidth]{figures/NoPredict0msDelayRef}}
+ Warn("unsupported", "multirow", $stomach,
+ "Negative row sizes for \\multirow are not yet supported.");
+ $rowspan = 1; }
+ elsif ($rowspan != int($rowspan)) {
+ Warn("unsupported", "multirow", $stomach,
+ "Fractional row sizes for \\multirow are not yet supported.");
+ $rowspan = int($rowspan); }
+ $$colspec{rowspan} = $rowspan;
$$colspec{vattach} = translateAttachment($attachment) if $attachment;
}
Digest(Tokens(T_CS('\hbox'), T_BEGIN, T_CS('\multirowsetup'), $content->unlist, T_END)); });
diff --git a/lib/LaTeXML/Package/ulem.sty.ltxml b/lib/LaTeXML/Package/ulem.sty.ltxml
index 9566b2311..c8ab4da47 100644
--- a/lib/LaTeXML/Package/ulem.sty.ltxml
+++ b/lib/LaTeXML/Package/ulem.sty.ltxml
@@ -18,20 +18,22 @@ use LaTeXML::Package;
RequireResource('ltx-ulem.css');
#======================================================================
-DefConstructor('\uline{}',
- "#1");
-DefConstructor('\uuline{}',
- "#1");
-DefConstructor('\uwave{}',
- "#1");
-DefConstructor('\sout{}',
- "#1");
-DefConstructor('\xout{}',
- "#1");
-DefConstructor('\dashuline{}',
- "#1");
-DefConstructor('\dotuline{}',
- "#1");
+# TODO: We still need to propagate the XMWrap class to the inner argument,
+# not yet implemented in MathParser?
+DefConstructor('\uline{}', "?#isMath(#1)"
+ . "(#1)");
+DefConstructor('\uuline{}', "?#isMath(#1)"
+ . "(#1)");
+DefConstructor('\uwave{}', "?#isMath(#1)"
+ . "(#1)");
+DefConstructor('\sout{}', "?#isMath(#1)"
+ . "(#1)");
+DefConstructor('\xout{}', "?#isMath(#1)"
+ . "(#1)");
+DefConstructor('\dashuline{}', "?#isMath(#1)"
+ . "(#1)");
+DefConstructor('\dotuline{}', "?#isMath(#1)"
+ . "(#1)");
DefMacro('\normalem', '');
#======================================================================
diff --git a/lib/LaTeXML/Package/xy.tex.ltxml b/lib/LaTeXML/Package/xy.tex.ltxml
index dd6018694..36b723265 100644
--- a/lib/LaTeXML/Package/xy.tex.ltxml
+++ b/lib/LaTeXML/Package/xy.tex.ltxml
@@ -36,7 +36,15 @@ DefMacro('\xyoption{}', sub {
elsif ($xy_unsupported{$option}) {
Warn('xy', 'unsupported', $gullet,
"The xy extension/feature $option_s may not be supported"); }
- return Tokens(T_CS('\lx@xy@xyoption@orig'), T_BEGIN, $option, T_END); });
+ my $cache_key = "loaded_xyoption_$option_s";
+ if (LookupValue($cache_key)) {
+ Info('xy', 'ignored', "xyoption $option_s was requested twice, not reloading");
+ return ();
+ } else {
+ Note("loading xyoption $option_s.");
+ AssignValue($cache_key, 1, 'global');
+ return Tokens(T_CS('\lx@xy@xyoption@orig'), T_BEGIN, $option, T_END); }
+}, locked => 1);
# Redefine so we get more tracable/debugable info
DefPrimitive('\xywarning@{}', sub { Info('xy', 'warning', $_[0], ToString($_[1])); });