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])); });