Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,27 @@ t/complex/aastex631_deluxetable.xml
t/complex/aliceblog.pdf
t/complex/aliceblog.tex
t/complex/aliceblog.xml
t/complex/bibconfig.bib
t/complex/bibconfig_bbl.bbl
t/complex/bibconfig_bbl.tex
t/complex/bibconfig_bbl.xml
t/complex/bibconfig_bbl_bib.bbl
t/complex/bibconfig_bbl_bib.tex
t/complex/bibconfig_bbl_bib.xml
t/complex/bibconfig_bib.bbl
t/complex/bibconfig_bib.tex
t/complex/bibconfig_bib.xml
t/complex/bibconfig_bib_bbl.bbl
t/complex/bibconfig_bib_bbl.tex
t/complex/bibconfig_bib_bbl.xml
t/complex/bibconfig_no_bbl_bib.tex
t/complex/bibconfig_no_bbl_bib.xml
t/complex/bibconfig_no_bib_bbl.bbl
t/complex/bibconfig_no_bib_bbl.tex
t/complex/bibconfig_no_bib_bbl.xml
t/complex/bibconfig_none.bbl
t/complex/bibconfig_none.tex
t/complex/bibconfig_none.xml
t/complex/cleveref_minimal.pdf
t/complex/cleveref_minimal.tex
t/complex/cleveref_minimal.xml
Expand Down
10 changes: 5 additions & 5 deletions lib/LaTeXML/Core.pm
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,17 @@ sub digestFile {
sub iniTeX {
my ($self, $request, $destination, %options) = @_;
my ($dir, $name, $ext);
my $mode = $options{mode} || 'Base'; # normally, w/o TeX (plain) itself
my $mode = $options{mode} || 'Base'; # normally, w/o TeX (plain) itself
if (pathname_is_literaldata($request)) {
$dir = undef; $ext = 'tex';
$name = "Anonymous String"; }
elsif (pathname_is_url($request)) {
$dir = undef; $ext = 'tex';
$name = $request; }
else {
if (my $pathname = pathname_find($request, types => ['tex','ltx'],
paths => $$self{state}->lookupValue('SEARCHPATHS'))
|| pathname_kpsewhich($request, types => ['tex','ltx'],
if (my $pathname = pathname_find($request, types => ['tex', 'ltx'],
paths => $$self{state}->lookupValue('SEARCHPATHS'))
|| pathname_kpsewhich($request, types => ['tex', 'ltx'],
paths => $$self{state}->lookupValue('SEARCHPATHS'))) {
$request = $pathname;
($dir, $name, $ext) = pathname_split($request); }
Expand Down Expand Up @@ -320,7 +320,7 @@ sub initializeState {
my $handleoptions = ($type eq 'sty') || ($type eq 'cls');
if ($options) {
if ($handleoptions) {
$options = [split(/,/, $options)]; }
$options = [LaTeXML::Core::KeyVal::TrimmedCommaList($options)]; }
else {
Warn('unexpected', 'options',
"Attempting to pass options to $preload.$type (not style or class)",
Expand Down
25 changes: 24 additions & 1 deletion lib/LaTeXML/Core/KeyVal.pm
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use base qw(LaTeXML::Common::Object);
our @EXPORT = (
qw(&DefKeyVal &DisableKeyVal &HasKeyVal),
# Semi-internals
qw(&keyval_qname &keyval_get));
qw(&keyval_qname &keyval_get &TrimmedCommaList));

#======================================================================
# Exposed Methods
Expand Down Expand Up @@ -182,6 +182,29 @@ sub defineBoolean {
$mismatch, [("true", "false")], 1);
return; }

#======================================================================

# Helper to split a comma-separated list, unwrapping wrapping braces,
# trimming spaces, and respecting inner braces as argument groupings.
sub TrimmedCommaList {
my ($text) = @_;
$text = ToString($text);
$text =~ s/^\s*\{(.+)\}\s*$/$1/g; # unwrap outer braces
$text =~ s/^\s+|\s+$//g; # trim leading/trailing spaces
my $level = 0;
my @pieces = ();
my $piece = '';
for my $c (split('', $text)) {
if ($c eq '{') { $level++; $piece .= $c; }
elsif ($c eq '}') { $level--; $piece .= $c; }
elsif (($c eq ',') && ($level == 0)) {
push(@pieces, $piece) if length($piece) > 0;
$piece = ''; }
else {
$piece .= $c; } }
push(@pieces, $piece) if length($piece) > 0;
return @pieces; }

#======================================================================
1;

Expand Down
22 changes: 11 additions & 11 deletions lib/LaTeXML/Core/List.pm
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,23 @@ sub List {
if ((scalar(@boxes) >= 2) && ($boxes[-2] eq 'mode')) {
$mode = pop(@boxes); pop(@boxes); }
else {
$mode = $STATE->lookupValue('MODE'); } # HOPEFULLY, mode hasn't changed by now?
@boxes = grep { defined $_ } @boxes; # strip out undefs
# Simplify single box, IFF NOT vertical list or box IS vertical
$mode = $STATE->lookupValue('MODE'); } # HOPEFULLY, mode hasn't changed by now?
@boxes = grep { defined $_ } @boxes; # strip out undefs
# Simplify single box, IFF NOT vertical list or box IS vertical
if ((scalar(@boxes) == 1)
&& (!$mode || ($mode !~ /vertical$/)
|| (($boxes[0]->getProperty('mode')||'') =~ /vertical$/))) {
return $boxes[0]; } # Simplify!
&& (!$mode || ($mode !~ /vertical$/)
|| (($boxes[0]->getProperty('mode') || '') =~ /vertical$/))) {
return $boxes[0]; } # Simplify!
else {
# Flatten horizontal lists within horizontal lists
if($mode eq 'horizontal'){
if ($mode and $mode eq 'horizontal') {
@boxes = map { ((ref $_ eq 'LaTeXML::Core::List')
&& (($_->getProperty('mode')||'') eq 'horizontal')
? $_->unlist : $_); } @boxes; }
&& (($_->getProperty('mode') || '') eq 'horizontal')
? $_->unlist : $_); } @boxes; }
my $list = LaTeXML::Core::List->new(@boxes);
$list->setProperty(mode => $mode);
$list->setProperty(mode => $mode);
$list->setProperty(width => LaTeXML::Package::LookupRegister('\hsize'))
if $mode eq 'horizontal';
if ($mode and $mode eq 'horizontal');
return $list; } }

sub new {
Expand Down
44 changes: 29 additions & 15 deletions lib/LaTeXML/Engine/latex_constructs.pool.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -783,13 +783,18 @@ DefMacroI('\@declaredoptions', undef, Tokens());
DefMacroI('\@curroptions', undef, undef);
DefMacroI('\@unusedoptionlist', undef, Tokens());

DefConstructor('\usepackage OptionalSemiverbatim Semiverbatim []',
"<?latexml package='#2' ?#1(options='#1')?>",
DefConstructor('\usepackage OptionalUndigested Semiverbatim []',
"<?latexml package='#2' ?#1(options='#options')?>",
beforeDigest => sub { onlyPreamble('\usepackage'); },
afterDigest => sub { my ($stomach, $whatsit) = @_;
my $options = [TrimmedCommaList($whatsit->getArg(1))];
# approximate semiverbatim by reparsing the inner lists
my $options = [map {
my ($k, $v) = split(/=/, $_, 2);
defined $v ? ($k . '=' . join(",", TrimmedCommaList($v))) : $k;
} TrimmedCommaList($whatsit->getArg(1))];
$whatsit->setProperty(options => join(",", @$options));
my $packages = $whatsit->getArg(2);
for my $pkg (split(',', ToString($packages))) {
for my $pkg (TrimmedCommaList($packages)) {
$pkg =~ s/\s+//g;
next if !$pkg || $pkg =~ /^%/;
RequirePackage($pkg, options => $options); }
Expand All @@ -802,7 +807,7 @@ DefConstructor('\RequirePackage OptionalSemiverbatim Semiverbatim []',
afterDigest => sub { my ($stomach, $whatsit) = @_;
my $options = [TrimmedCommaList($whatsit->getArg(1))];
my $packages = $whatsit->getArg(2);
for my $pkg (split(',', ToString($packages))) {
for my $pkg (TrimmedCommaList($packages)) {
$pkg =~ s/\s+//g;
next if !$pkg || $pkg =~ /^%/;
RequirePackage($pkg, options => $options); }
Expand Down Expand Up @@ -3961,20 +3966,29 @@ DefMacro('\lx@ifusebbl{}{}{}', sub {
if ((ref $bib_config ne 'ARRAY') || scalar(@$bib_config) == 0) {
Info('missing', 'bib_config', $gullet, "BIB_CONFIG was empty, ignoring bibliography phase.");
return; }
if ($$bib_config[0] eq 'bbl') {
my $allows_bbl = scalar(grep { $_ eq 'bbl' } @$bib_config);
my $allows_bib = scalar(grep { $_ eq 'bib' } @$bib_config);
# bbl flow
if ($allows_bbl && ($$bib_config[0] eq 'bbl')) {
if (not $bbl_path) {
Info('expected', "bbl", $_[0], "Couldn't find bbl file, bibliography may be empty.");
return Tokens(); }
if (!$allows_bib) {
Info('expected', "bbl", $_[0], "Couldn't find bbl file, bibliography may be empty.");
return Tokens(); } }
else {
return $bbl_clause->unlist; } }
# bib flow
return Tokens() unless $allows_bib;
for my $bf (TrimmedCommaList($bib_files)) {
my $bib_path = FindFile($bf, type => 'bib');
if (not $bib_path) {
$missing_bibs .= ',' unless length($missing_bibs) == 0;
$missing_bibs .= $bf; } }
if (length($missing_bibs) == 0 or not $bbl_path) {
return $bib_clause->unlist; }
else {
for my $bf (split(',', $bib_files)) {
my $bib_path = FindFile($bf, type => 'bib');
if (not $bib_path) {
$missing_bibs .= ',' unless length($missing_bibs) == 0;
$missing_bibs .= $bf; } }
if (length($missing_bibs) == 0 or not $bbl_path) {
return $bib_clause->unlist; }
if (!$allows_bbl) {
Info('expected', $missing_bibs, $_[0], "Couldn't find all bib files, bibliography may be empty");
return Tokens(); }
else {
Info('expected', $missing_bibs, $_[0], "Couldn't find all bib files, using " . $jobname . ".bbl instead");
return $bbl_clause->unlist; } } });
Expand Down
22 changes: 7 additions & 15 deletions lib/LaTeXML/Package.pm
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ our @EXPORT = (qw(&DefAutoload &DefExpandable

# Random low-level token or string operations.
qw(&CleanID &CleanLabel &CleanIndexKey &CleanClassName &CleanBibKey &NormalizeBibKey &CleanURL
&ComposeURL &TrimmedCommaList
&ComposeURL
&roman &Roman),
# Math & font state.
qw(&MergeFont),
Expand Down Expand Up @@ -567,13 +567,6 @@ sub ComposeURL {
$url,
($fragid ? '#' . CleanID($fragid) : ''))); }

sub TrimmedCommaList {
my ($text) = @_;
$text = ToString($text);
$text =~ s/^\s+//;
$text =~ s/\s+$//;
return split(/\s*,\s*/, $text); }

#======================================================================
# Defining new Control-sequence Parameter types.
#======================================================================
Expand Down Expand Up @@ -952,15 +945,15 @@ sub Expand {
return () unless @tokens;
my $gullet = $STATE->getStomach->getGullet;
return $gullet->readingFromMouth(Tokens(T_BEGIN, @tokens, T_END), sub {
$gullet->readBalanced(2, 0, 1); }); }
$gullet->readBalanced(2, 0, 1); }); }

# Return $tokens, partially expanded (defer protected, and results of \the)
sub ExpandPartially {
my (@tokens) = @_;
return () unless @tokens;
my $gullet = $STATE->getStomach->getGullet;
return $gullet->readingFromMouth(Tokens(T_BEGIN, @tokens, T_END), sub {
$gullet->readBalanced(1, 0, 1); }); }
$gullet->readBalanced(1, 0, 1); }); }

sub Invocation {
my ($token, @args) = @_;
Expand Down Expand Up @@ -1371,7 +1364,7 @@ sub LookupDimension {
return $defn->valueOf; }
else {
return $STATE->getStomach->getGullet->readingFromMouth($cs, sub {
$_[0]->readDimension; }); } }
$_[0]->readDimension; }); } }
else {
Warn('expected', 'register', $STATE->getStomach,
"The control sequence " . ToString($cs) . " is not a register"); }
Expand Down Expand Up @@ -2547,7 +2540,6 @@ sub InputDefinitions {
my $mode = $STATE->lookupValue('MODE');
my $prevname = $options{handleoptions} && $STATE->lookupDefinition(T_CS('\@currname')) && ToString(Expand(T_CS('\@currname')));
my $prevext = $options{handleoptions} && $STATE->lookupDefinition(T_CS('\@currext')) && ToString(Expand(T_CS('\@currext')));

# This file will be treated somewhat as if it were a class
# IF as_class is true
# OR if it is loaded by such a class, and has withoptions true!!! (yikes)
Expand Down Expand Up @@ -2952,11 +2944,11 @@ sub decodeMathChar {
elsif ($fontdef = LookupValue('textfont_' . $fam)) { $downsize = 2; } }
my $defn = $STATE->lookupDefinition($fontdef);
$fontinfo = $defn && $defn->isFontDef;
if(! $fontinfo) {
$defn = $STATE->lookupDefinition(T_CS('\lx@default@font'));
if (!$fontinfo) {
$defn = $STATE->lookupDefinition(T_CS('\lx@default@font'));
$fontinfo = $defn && $defn->isFontDef; }
if ($fontinfo && (ref $fontinfo eq 'HASH')
&& $basefontinfo && ($$basefontinfo{size} != $curfont->getSize)) {
&& $basefontinfo && ($$basefontinfo{size} != $curfont->getSize)) {
# If we've gotten an explicit font SIZE change; Adjust!
$fontinfo = {%$fontinfo}; $$fontinfo{size} = $curfont->getSize; } }
my $font = $curfont;
Expand Down
2 changes: 1 addition & 1 deletion lib/LaTeXML/Package/latexml.sty.ltxml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ DeclareOption('bibtex', sub { AssignValue('BIB_CONFIG' => ['bib', 'bbl'], 'glo
DeclareOption('nobibtex', sub { AssignValue('BIB_CONFIG' => ['bbl'], 'global'); });

DefKeyVal('LTXML', 'bibconfig', 'Semiverbatim', '', code => sub {
AssignValue('BIB_CONFIG' => [split(',', ToString($_[1]))], 'global');
AssignValue('BIB_CONFIG' => [TrimmedCommaList($_[1])], 'global');
return; });

# Lexeme serialization for math formulas
Expand Down
6 changes: 6 additions & 0 deletions t/complex/bibconfig.bib
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@MISC{example,
author = "Bib",
title = {Some Bib},
year = {2025},
note = {Bib}
}
7 changes: 7 additions & 0 deletions t/complex/bibconfig_bbl.bbl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
\begin{thebibliography}{1}

\bibitem{example}
bbl.
\newblock Some bbl.

\end{thebibliography}
8 changes: 8 additions & 0 deletions t/complex/bibconfig_bbl.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
\documentclass{article}
\usepackage[bibconfig=bbl]{latexml}
\begin{document}
bbl
\nocite{*}
\bibliographystyle{plain}
\bibliography{bibconfig}
\end{document}
30 changes: 30 additions & 0 deletions t/complex/bibconfig_bbl.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<?latexml class="article"?>
<?latexml package="latexml" options="bibconfig=bbl"?>
<?latexml RelaxNGSchema="LaTeXML"?>
<document xmlns="http://dlmf.nist.gov/LaTeXML">
<resource src="LaTeXML.css" type="text/css"/>
<resource src="ltx-article.css" type="text/css"/>
<para xml:id="p1">
<p>bbl</p>
</para>
<bibliography xml:id="bib">
<title>References</title>
<biblist>
<bibitem key="example" xml:id="bib.bib1">
<tags>
<tag>[1]</tag>
<tag role="refnum">1</tag>
</tags>
<bibblock>
bbl.
</bibblock>
<bibblock>Some bbl.
</bibblock>
</bibitem>
</biblist>
</bibliography>
<para xml:id="p2">
<p><cite><bibref bibrefs="*" show="nothing"/></cite></p>
</para>
</document>
7 changes: 7 additions & 0 deletions t/complex/bibconfig_bbl_bib.bbl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
\begin{thebibliography}{1}

\bibitem{example}
bbl.
\newblock Some bbl.

\end{thebibliography}
8 changes: 8 additions & 0 deletions t/complex/bibconfig_bbl_bib.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
\documentclass{article}
\usepackage[bibconfig={bbl,bib}]{latexml}
\begin{document}
bbl
\nocite{*}
\bibliographystyle{plain}
\bibliography{bibconfig}
\end{document}
30 changes: 30 additions & 0 deletions t/complex/bibconfig_bbl_bib.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<?latexml class="article"?>
<?latexml package="latexml" options="bibconfig=bbl,bib"?>
<?latexml RelaxNGSchema="LaTeXML"?>
<document xmlns="http://dlmf.nist.gov/LaTeXML">
<resource src="LaTeXML.css" type="text/css"/>
<resource src="ltx-article.css" type="text/css"/>
<para xml:id="p1">
<p>bbl</p>
</para>
<bibliography xml:id="bib">
<title>References</title>
<biblist>
<bibitem key="example" xml:id="bib.bib1">
<tags>
<tag>[1]</tag>
<tag role="refnum">1</tag>
</tags>
<bibblock>
bbl.
</bibblock>
<bibblock>Some bbl.
</bibblock>
</bibitem>
</biblist>
</bibliography>
<para xml:id="p2">
<p><cite><bibref bibrefs="*" show="nothing"/></cite></p>
</para>
</document>
Loading
Loading