Skip to content

Commit 527c335

Browse files
authored
Merge pull request #12002 from quarto-dev/perf/2025-01-31-combine-ast
[perf] lua,ast_pipeline - combine a filter to reduce number of passes
2 parents ca05876 + 5aaaff0 commit 527c335

File tree

2 files changed

+61
-47
lines changed

2 files changed

+61
-47
lines changed

src/resources/filters/normalize/astpipeline.lua

-5
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,5 @@ function quarto_ast_pipeline()
4646
parse_blockreftargets()
4747
}),
4848
},
49-
{
50-
name = "normalize-3",
51-
filter = handle_subfloatreftargets(),
52-
traverser = 'jog',
53-
}
5449
}
5550
end

src/resources/filters/quarto-pre/parsefiguredivs.lua

+61-42
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,11 @@ local classes_to_not_merge = pandoc.List({
1212
"border"
1313
})
1414

15-
function handle_subfloatreftargets()
16-
-- #7045: pull fig-pos and fig-env attributes from subfloat to parent
17-
return {
18-
FloatRefTarget = function(float)
19-
local pulled_attrs = {}
20-
local attrs_to_pull = {
21-
"fig-pos",
22-
"fig-env",
23-
}
24-
local result = _quarto.ast.walk(float, {
25-
FloatRefTarget = function(subfloat)
26-
for _, attr in ipairs(attrs_to_pull) do
27-
if subfloat.attributes[attr] then
28-
pulled_attrs[attr] = subfloat.attributes[attr]
29-
subfloat.attributes[attr] = nil
30-
end
31-
end
32-
return subfloat
33-
end,
34-
}) or pandoc.Div({}) -- won't happen but the lua analyzer doesn't know that
35-
for k, v in pairs(pulled_attrs) do
36-
float.attributes[k] = v
37-
end
38-
return float
39-
end
40-
}
41-
end
15+
-- function handle_subfloatreftargets()
16+
-- return {
17+
-- FloatRefTarget =
18+
-- }
19+
-- end
4220

4321
local function process_div_caption_classes(div)
4422
-- knitr forwards "cap-location: top" as `.caption-top`...
@@ -136,6 +114,11 @@ local function kable_raw_latex_fixups(content, identifier)
136114

137115
-- we found a table, a label, and a caption. This is a FloatRefTarget.
138116
matches = matches + 1
117+
118+
-- other FloatRefTarget constructions below go through
119+
-- a recursion step to identify subfloats, but we don't have
120+
-- to do that here, since we know that the content of this FloatRefTarget
121+
-- is a single table.
139122
return quarto.FloatRefTarget({
140123
identifier = label_identifier,
141124
type = "Table",
@@ -165,6 +148,39 @@ end
165148

166149
function parse_floatreftargets()
167150

151+
local filter
152+
153+
local function construct(tbl)
154+
local new_content = _quarto.ast.walk(tbl.content, filter)
155+
156+
-- #7045: pull fig-pos and fig-env attributes from subfloat to parent
157+
local pulled_attrs = {}
158+
local attrs_to_pull = {
159+
"fig-pos",
160+
"fig-env",
161+
}
162+
new_content = _quarto.ast.walk(new_content, {
163+
FloatRefTarget = function(subfloat)
164+
for _, attr in ipairs(attrs_to_pull) do
165+
if subfloat.attributes[attr] then
166+
pulled_attrs[attr] = subfloat.attributes[attr]
167+
subfloat.attributes[attr] = nil
168+
end
169+
end
170+
return subfloat
171+
end
172+
})
173+
local inner_tbl = {}
174+
for k, v in pairs(tbl) do
175+
inner_tbl[k] = v
176+
end
177+
for k, v in pairs(pulled_attrs) do
178+
inner_tbl.attr.attributes[k] = v
179+
end
180+
inner_tbl.content = new_content
181+
return quarto.FloatRefTarget(inner_tbl)
182+
end
183+
168184
local function handle_subcells_as_subfloats(params)
169185
local identifier = params.identifier
170186
local div = params.div
@@ -182,10 +198,10 @@ function parse_floatreftargets()
182198
return nil
183199
end
184200
subcap_index = subcap_index + 1
185-
local subfloat = quarto.FloatRefTarget({
201+
local subfloat = construct({
186202
attr = pandoc.Attr(identifier .. "-" .. tostring(subcap_index), {}, {}),
187203
type = category.name,
188-
content = {subdiv},
204+
content = pandoc.Blocks{subdiv},
189205
caption_long = {pandoc.Plain(string_to_quarto_ast_inlines(subcaps[subcap_index]))},
190206
})
191207
subcells:insert(subfloat)
@@ -274,6 +290,7 @@ function parse_floatreftargets()
274290

275291
local identifier = div.identifier
276292
local attr = pandoc.Attr(identifier, div.classes, div.attributes)
293+
assert(content)
277294
if (#content == 1 and content[1].t == "Para" and
278295
content[1].content[1].t == "Image") then
279296
-- if the div contains a single image, then we simply use the image as
@@ -367,7 +384,7 @@ function parse_floatreftargets()
367384
return_cell.content = coalesce_code_blocks(return_cell.content)
368385
return_cell.classes = div.classes
369386
return_cell.attributes = div.attributes
370-
local reftarget = quarto.FloatRefTarget({
387+
local reftarget = construct({
371388
attr = attr,
372389
type = category.name,
373390
content = final_content.content,
@@ -416,15 +433,15 @@ function parse_floatreftargets()
416433
}
417434
end
418435

419-
return quarto.FloatRefTarget({
436+
return construct({
420437
attr = attr,
421438
type = category.name,
422439
content = content,
423440
caption_long = {pandoc.Plain(caption.content)},
424441
}), false
425442
end
426443

427-
return {
444+
filter = {
428445
traverse = "topdown",
429446
Figure = function(fig)
430447
local key_prefix = refType(fig.identifier)
@@ -463,7 +480,7 @@ function parse_floatreftargets()
463480
end
464481
}) or fig.content[1] -- this shouldn't be needed but the lua analyzer doesn't know it
465482

466-
return quarto.FloatRefTarget({
483+
return construct({
467484
attr = fig_attr,
468485
type = category.name,
469486
content = new_content.content,
@@ -502,7 +519,7 @@ function parse_floatreftargets()
502519

503520
local combined = merge_attrs(el.attr, attr)
504521

505-
return quarto.FloatRefTarget({
522+
return construct({
506523
identifier = label,
507524
classes = combined.classes,
508525
attributes = as_plain_table(combined.attributes),
@@ -586,7 +603,7 @@ function parse_floatreftargets()
586603
-- warn("Figure with invalid crossref category: " .. identifier .. "\nWon't be able to cross-reference this figure.")
587604
return nil
588605
end
589-
return quarto.FloatRefTarget({
606+
return construct({
590607
identifier = identifier,
591608
classes = {},
592609
attributes = as_plain_table(img.attributes),
@@ -617,7 +634,7 @@ function parse_floatreftargets()
617634
return
618635
end
619636
local combined = merge_attrs(img.attr, link.attr)
620-
return quarto.FloatRefTarget({
637+
return construct({
621638
identifier = identifier,
622639
classes = combined.classes,
623640
attributes = as_plain_table(combined.attributes),
@@ -642,10 +659,10 @@ function parse_floatreftargets()
642659

643660
local attr = code.attr
644661
-- code.attr = pandoc.Attr("", {}, {})
645-
return quarto.FloatRefTarget({
662+
return construct({
646663
attr = attr,
647664
type = "Listing",
648-
content = { decorated_code.__quarto_custom_node }, -- this custom AST impedance mismatch here is unfortunate
665+
content = pandoc.Blocks{ decorated_code.__quarto_custom_node }, -- this custom AST impedance mismatch here is unfortunate
649666
caption_long = caption,
650667
}), false
651668
end,
@@ -671,10 +688,10 @@ function parse_floatreftargets()
671688

672689
local attr = code.attr
673690
code.attr = pandoc.Attr("", {}, {})
674-
return quarto.FloatRefTarget({
691+
return construct({
675692
attr = attr,
676693
type = "Listing",
677-
content = { content },
694+
content = pandoc.Blocks({ content }),
678695
caption_long = caption_inlines,
679696
}), false
680697
end,
@@ -749,15 +766,17 @@ function parse_floatreftargets()
749766
raw.text = matched[2]
750767
end
751768

752-
return quarto.FloatRefTarget({
769+
return construct({
753770
attr = pandoc.Attr(identifier, {}, {}),
754771
type = "Table",
755-
content = { raw },
772+
content = pandoc.Blocks({ raw }),
756773
caption_long = quarto.utils.as_blocks(caption)
757774
}), false
758775
end
759776

760777
}
778+
779+
return filter
761780
end
762781

763782
function forward_cell_subcaps()

0 commit comments

Comments
 (0)