Skip to content

Commit 92c2631

Browse files
committed
Merge patch for bibconfig feature, as well as comma-separated values in \usepackage optional keyvals (PR brucemiller#2733)
2 parents ad4bbfb + b9756ff commit 92c2631

28 files changed

+359
-48
lines changed

MANIFEST

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,27 @@ t/complex/aastex631_deluxetable.xml
989989
t/complex/aliceblog.pdf
990990
t/complex/aliceblog.tex
991991
t/complex/aliceblog.xml
992+
t/complex/bibconfig.bib
993+
t/complex/bibconfig_bbl.bbl
994+
t/complex/bibconfig_bbl.tex
995+
t/complex/bibconfig_bbl.xml
996+
t/complex/bibconfig_bbl_bib.bbl
997+
t/complex/bibconfig_bbl_bib.tex
998+
t/complex/bibconfig_bbl_bib.xml
999+
t/complex/bibconfig_bib.bbl
1000+
t/complex/bibconfig_bib.tex
1001+
t/complex/bibconfig_bib.xml
1002+
t/complex/bibconfig_bib_bbl.bbl
1003+
t/complex/bibconfig_bib_bbl.tex
1004+
t/complex/bibconfig_bib_bbl.xml
1005+
t/complex/bibconfig_no_bbl_bib.tex
1006+
t/complex/bibconfig_no_bbl_bib.xml
1007+
t/complex/bibconfig_no_bib_bbl.bbl
1008+
t/complex/bibconfig_no_bib_bbl.tex
1009+
t/complex/bibconfig_no_bib_bbl.xml
1010+
t/complex/bibconfig_none.bbl
1011+
t/complex/bibconfig_none.tex
1012+
t/complex/bibconfig_none.xml
9921013
t/complex/cleveref_minimal.pdf
9931014
t/complex/cleveref_minimal.tex
9941015
t/complex/cleveref_minimal.xml

lib/LaTeXML/Core.pm

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,17 +168,17 @@ sub digestFile {
168168
sub iniTeX {
169169
my ($self, $request, $destination, %options) = @_;
170170
my ($dir, $name, $ext);
171-
my $mode = $options{mode} || 'Base'; # normally, w/o TeX (plain) itself
171+
my $mode = $options{mode} || 'Base'; # normally, w/o TeX (plain) itself
172172
if (pathname_is_literaldata($request)) {
173173
$dir = undef; $ext = 'tex';
174174
$name = "Anonymous String"; }
175175
elsif (pathname_is_url($request)) {
176176
$dir = undef; $ext = 'tex';
177177
$name = $request; }
178178
else {
179-
if (my $pathname = pathname_find($request, types => ['tex','ltx'],
180-
paths => $$self{state}->lookupValue('SEARCHPATHS'))
181-
|| pathname_kpsewhich($request, types => ['tex','ltx'],
179+
if (my $pathname = pathname_find($request, types => ['tex', 'ltx'],
180+
paths => $$self{state}->lookupValue('SEARCHPATHS'))
181+
|| pathname_kpsewhich($request, types => ['tex', 'ltx'],
182182
paths => $$self{state}->lookupValue('SEARCHPATHS'))) {
183183
$request = $pathname;
184184
($dir, $name, $ext) = pathname_split($request); }
@@ -320,7 +320,7 @@ sub initializeState {
320320
my $handleoptions = ($type eq 'sty') || ($type eq 'cls');
321321
if ($options) {
322322
if ($handleoptions) {
323-
$options = [split(/,/, $options)]; }
323+
$options = [LaTeXML::Core::KeyVal::TrimmedCommaList($options)]; }
324324
else {
325325
Warn('unexpected', 'options',
326326
"Attempting to pass options to $preload.$type (not style or class)",

lib/LaTeXML/Core/KeyVal.pm

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use base qw(LaTeXML::Common::Object);
2323
our @EXPORT = (
2424
qw(&DefKeyVal &DisableKeyVal &HasKeyVal),
2525
# Semi-internals
26-
qw(&keyval_qname &keyval_get));
26+
qw(&keyval_qname &keyval_get &TrimmedCommaList));
2727

2828
#======================================================================
2929
# Exposed Methods
@@ -182,6 +182,29 @@ sub defineBoolean {
182182
$mismatch, [("true", "false")], 1);
183183
return; }
184184

185+
#======================================================================
186+
187+
# Helper to split a comma-separated list, unwrapping wrapping braces,
188+
# trimming spaces, and respecting inner braces as argument groupings.
189+
sub TrimmedCommaList {
190+
my ($text) = @_;
191+
$text = ToString($text);
192+
$text =~ s/^\s*\{(.+)\}\s*$/$1/g; # unwrap outer braces
193+
$text =~ s/^\s+|\s+$//g; # trim leading/trailing spaces
194+
my $level = 0;
195+
my @pieces = ();
196+
my $piece = '';
197+
for my $c (split('', $text)) {
198+
if ($c eq '{') { $level++; $piece .= $c; }
199+
elsif ($c eq '}') { $level--; $piece .= $c; }
200+
elsif (($c eq ',') && ($level == 0)) {
201+
push(@pieces, $piece) if length($piece) > 0;
202+
$piece = ''; }
203+
else {
204+
$piece .= $c; } }
205+
push(@pieces, $piece) if length($piece) > 0;
206+
return @pieces; }
207+
185208
#======================================================================
186209
1;
187210

lib/LaTeXML/Core/List.pm

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,23 @@ sub List {
3535
if ((scalar(@boxes) >= 2) && ($boxes[-2] eq 'mode')) {
3636
$mode = pop(@boxes); pop(@boxes); }
3737
else {
38-
$mode = $STATE->lookupValue('MODE'); } # HOPEFULLY, mode hasn't changed by now?
39-
@boxes = grep { defined $_ } @boxes; # strip out undefs
40-
# Simplify single box, IFF NOT vertical list or box IS vertical
38+
$mode = $STATE->lookupValue('MODE'); } # HOPEFULLY, mode hasn't changed by now?
39+
@boxes = grep { defined $_ } @boxes; # strip out undefs
40+
# Simplify single box, IFF NOT vertical list or box IS vertical
4141
if ((scalar(@boxes) == 1)
42-
&& (!$mode || ($mode !~ /vertical$/)
43-
|| (($boxes[0]->getProperty('mode')||'') =~ /vertical$/))) {
44-
return $boxes[0]; } # Simplify!
42+
&& (!$mode || ($mode !~ /vertical$/)
43+
|| (($boxes[0]->getProperty('mode') || '') =~ /vertical$/))) {
44+
return $boxes[0]; } # Simplify!
4545
else {
4646
# Flatten horizontal lists within horizontal lists
47-
if($mode eq 'horizontal'){
47+
if ($mode and $mode eq 'horizontal') {
4848
@boxes = map { ((ref $_ eq 'LaTeXML::Core::List')
49-
&& (($_->getProperty('mode')||'') eq 'horizontal')
50-
? $_->unlist : $_); } @boxes; }
49+
&& (($_->getProperty('mode') || '') eq 'horizontal')
50+
? $_->unlist : $_); } @boxes; }
5151
my $list = LaTeXML::Core::List->new(@boxes);
52-
$list->setProperty(mode => $mode);
52+
$list->setProperty(mode => $mode);
5353
$list->setProperty(width => LaTeXML::Package::LookupRegister('\hsize'))
54-
if $mode eq 'horizontal';
54+
if ($mode and $mode eq 'horizontal');
5555
return $list; } }
5656

5757
sub new {

lib/LaTeXML/Engine/latex_constructs.pool.ltxml

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -783,13 +783,18 @@ DefMacroI('\@declaredoptions', undef, Tokens());
783783
DefMacroI('\@curroptions', undef, undef);
784784
DefMacroI('\@unusedoptionlist', undef, Tokens());
785785

786-
DefConstructor('\usepackage OptionalSemiverbatim Semiverbatim []',
787-
"<?latexml package='#2' ?#1(options='#1')?>",
786+
DefConstructor('\usepackage OptionalUndigested Semiverbatim []',
787+
"<?latexml package='#2' ?#1(options='#options')?>",
788788
beforeDigest => sub { onlyPreamble('\usepackage'); },
789789
afterDigest => sub { my ($stomach, $whatsit) = @_;
790-
my $options = [TrimmedCommaList($whatsit->getArg(1))];
790+
# approximate semiverbatim by reparsing the inner lists
791+
my $options = [map {
792+
my ($k, $v) = split(/=/, $_, 2);
793+
defined $v ? ($k . '=' . join(",", TrimmedCommaList($v))) : $k;
794+
} TrimmedCommaList($whatsit->getArg(1))];
795+
$whatsit->setProperty(options => join(",", @$options));
791796
my $packages = $whatsit->getArg(2);
792-
for my $pkg (split(',', ToString($packages))) {
797+
for my $pkg (TrimmedCommaList($packages)) {
793798
$pkg =~ s/\s+//g;
794799
next if !$pkg || $pkg =~ /^%/;
795800
RequirePackage($pkg, options => $options); }
@@ -802,7 +807,7 @@ DefConstructor('\RequirePackage OptionalSemiverbatim Semiverbatim []',
802807
afterDigest => sub { my ($stomach, $whatsit) = @_;
803808
my $options = [TrimmedCommaList($whatsit->getArg(1))];
804809
my $packages = $whatsit->getArg(2);
805-
for my $pkg (split(',', ToString($packages))) {
810+
for my $pkg (TrimmedCommaList($packages)) {
806811
$pkg =~ s/\s+//g;
807812
next if !$pkg || $pkg =~ /^%/;
808813
RequirePackage($pkg, options => $options); }
@@ -3961,20 +3966,29 @@ DefMacro('\lx@ifusebbl{}{}{}', sub {
39613966
if ((ref $bib_config ne 'ARRAY') || scalar(@$bib_config) == 0) {
39623967
Info('missing', 'bib_config', $gullet, "BIB_CONFIG was empty, ignoring bibliography phase.");
39633968
return; }
3964-
if ($$bib_config[0] eq 'bbl') {
3969+
my $allows_bbl = scalar(grep { $_ eq 'bbl' } @$bib_config);
3970+
my $allows_bib = scalar(grep { $_ eq 'bib' } @$bib_config);
3971+
# bbl flow
3972+
if ($allows_bbl && ($$bib_config[0] eq 'bbl')) {
39653973
if (not $bbl_path) {
3966-
Info('expected', "bbl", $_[0], "Couldn't find bbl file, bibliography may be empty.");
3967-
return Tokens(); }
3974+
if (!$allows_bib) {
3975+
Info('expected', "bbl", $_[0], "Couldn't find bbl file, bibliography may be empty.");
3976+
return Tokens(); } }
39683977
else {
39693978
return $bbl_clause->unlist; } }
3979+
# bib flow
3980+
return Tokens() unless $allows_bib;
3981+
for my $bf (TrimmedCommaList($bib_files)) {
3982+
my $bib_path = FindFile($bf, type => 'bib');
3983+
if (not $bib_path) {
3984+
$missing_bibs .= ',' unless length($missing_bibs) == 0;
3985+
$missing_bibs .= $bf; } }
3986+
if (length($missing_bibs) == 0 or not $bbl_path) {
3987+
return $bib_clause->unlist; }
39703988
else {
3971-
for my $bf (split(',', $bib_files)) {
3972-
my $bib_path = FindFile($bf, type => 'bib');
3973-
if (not $bib_path) {
3974-
$missing_bibs .= ',' unless length($missing_bibs) == 0;
3975-
$missing_bibs .= $bf; } }
3976-
if (length($missing_bibs) == 0 or not $bbl_path) {
3977-
return $bib_clause->unlist; }
3989+
if (!$allows_bbl) {
3990+
Info('expected', $missing_bibs, $_[0], "Couldn't find all bib files, bibliography may be empty");
3991+
return Tokens(); }
39783992
else {
39793993
Info('expected', $missing_bibs, $_[0], "Couldn't find all bib files, using " . $jobname . ".bbl instead");
39803994
return $bbl_clause->unlist; } } });

lib/LaTeXML/Package.pm

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ our @EXPORT = (qw(&DefAutoload &DefExpandable
111111

112112
# Random low-level token or string operations.
113113
qw(&CleanID &CleanLabel &CleanIndexKey &CleanClassName &CleanBibKey &NormalizeBibKey &CleanURL
114-
&ComposeURL &TrimmedCommaList
114+
&ComposeURL
115115
&roman &Roman),
116116
# Math & font state.
117117
qw(&MergeFont),
@@ -577,13 +577,6 @@ sub ComposeURL {
577577
$url,
578578
($fragid ? '#' . CleanID($fragid) : ''))); }
579579

580-
sub TrimmedCommaList {
581-
my ($text) = @_;
582-
$text = ToString($text);
583-
$text =~ s/^\s+//;
584-
$text =~ s/\s+$//;
585-
return split(/\s*,\s*/, $text); }
586-
587580
#======================================================================
588581
# Defining new Control-sequence Parameter types.
589582
#======================================================================
@@ -962,15 +955,15 @@ sub Expand {
962955
return () unless @tokens;
963956
my $gullet = $STATE->getStomach->getGullet;
964957
return $gullet->readingFromMouth(Tokens(T_BEGIN, @tokens, T_END), sub {
965-
$gullet->readBalanced(2, 0, 1); }); }
958+
$gullet->readBalanced(2, 0, 1); }); }
966959

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

975968
sub Invocation {
976969
my ($token, @args) = @_;
@@ -1381,7 +1374,7 @@ sub LookupDimension {
13811374
return $defn->valueOf; }
13821375
else {
13831376
return $STATE->getStomach->getGullet->readingFromMouth($cs, sub {
1384-
$_[0]->readDimension; }); } }
1377+
$_[0]->readDimension; }); } }
13851378
else {
13861379
Warn('expected', 'register', $STATE->getStomach,
13871380
"The control sequence " . ToString($cs) . " is not a register"); }
@@ -2557,7 +2550,6 @@ sub InputDefinitions {
25572550
my $mode = $STATE->lookupValue('MODE');
25582551
my $prevname = $options{handleoptions} && $STATE->lookupDefinition(T_CS('\@currname')) && ToString(Expand(T_CS('\@currname')));
25592552
my $prevext = $options{handleoptions} && $STATE->lookupDefinition(T_CS('\@currext')) && ToString(Expand(T_CS('\@currext')));
2560-
25612553
# This file will be treated somewhat as if it were a class
25622554
# IF as_class is true
25632555
# OR if it is loaded by such a class, and has withoptions true!!! (yikes)
@@ -2962,11 +2954,11 @@ sub decodeMathChar {
29622954
elsif ($fontdef = LookupValue('textfont_' . $fam)) { $downsize = 2; } }
29632955
my $defn = $STATE->lookupDefinition($fontdef);
29642956
$fontinfo = $defn && $defn->isFontDef;
2965-
if(! $fontinfo) {
2966-
$defn = $STATE->lookupDefinition(T_CS('\lx@default@font'));
2957+
if (!$fontinfo) {
2958+
$defn = $STATE->lookupDefinition(T_CS('\lx@default@font'));
29672959
$fontinfo = $defn && $defn->isFontDef; }
29682960
if ($fontinfo && (ref $fontinfo eq 'HASH')
2969-
&& $basefontinfo && ($$basefontinfo{size} != $curfont->getSize)) {
2961+
&& $basefontinfo && ($$basefontinfo{size} != $curfont->getSize)) {
29702962
# If we've gotten an explicit font SIZE change; Adjust!
29712963
$fontinfo = {%$fontinfo}; $$fontinfo{size} = $curfont->getSize; } }
29722964
my $font = $curfont;

lib/LaTeXML/Package/latexml.sty.ltxml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ DeclareOption('bibtex', sub { AssignValue('BIB_CONFIG' => ['bib', 'bbl'], 'glo
5555
DeclareOption('nobibtex', sub { AssignValue('BIB_CONFIG' => ['bbl'], 'global'); });
5656

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

6161
# Lexeme serialization for math formulas

t/complex/bibconfig.bib

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@MISC{example,
2+
author = "Bib",
3+
title = {Some Bib},
4+
year = {2025},
5+
note = {Bib}
6+
}

t/complex/bibconfig_bbl.bbl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
\begin{thebibliography}{1}
2+
3+
\bibitem{example}
4+
bbl.
5+
\newblock Some bbl.
6+
7+
\end{thebibliography}

t/complex/bibconfig_bbl.tex

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
\documentclass{article}
2+
\usepackage[bibconfig=bbl]{latexml}
3+
\begin{document}
4+
bbl
5+
\nocite{*}
6+
\bibliographystyle{plain}
7+
\bibliography{bibconfig}
8+
\end{document}

0 commit comments

Comments
 (0)