diff --git a/src/resources/filters/ast/customnodes.lua b/src/resources/filters/ast/customnodes.lua index ca61ebc39b9..ecda0ccb24a 100644 --- a/src/resources/filters/ast/customnodes.lua +++ b/src/resources/filters/ast/customnodes.lua @@ -336,16 +336,21 @@ _quarto.ast = { return end local node = node_accessor(table) - local t = pandoc.utils.type(value) - quarto_assert(t ~= 'Div' and t ~= 'Span', "") + local valtype = pandoc.utils.type(value) + quarto_assert(valtype ~= 'Div' and valtype ~= 'Span', "") if index > #node.content then _quarto.ast.grow_scaffold(node, index) end - local pt = pandoc.utils.type(value) - if pt == "Block" or pt == "Inline" then - node.content[index].content = {value} + local inner_node = node.content[index] + local innertype = pandoc.utils.type(inner_node) + if innertype == 'Block' then + inner_node.content = quarto.utils.as_blocks(value) + elseif innertype == 'Inline' then + inner_node.content = quarto.utils.as_inlines(value) else - node.content[index].content = value + warn(debug.traceback( + 'Cannot find the right content type for value ' .. valtype)) + inner_node.content = value end end } @@ -416,13 +421,15 @@ _quarto.ast = { -- luacov: enable end - local forwarder = { } + local forwarder if tisarray(handler.slots) then + forwarder = pandoc.List{} for i, slot in ipairs(handler.slots) do forwarder[slot] = i end - else - forwarder = handler.slots + elseif handler.slots ~= nil then + warn('Expected `slots` to be either an array or nil, got ' .. + tostring(handler.slots)) end quarto[handler.ast_name] = function(params) diff --git a/src/resources/filters/crossref/equations.lua b/src/resources/filters/crossref/equations.lua index f8a12e64f28..0ecb0e430b7 100644 --- a/src/resources/filters/crossref/equations.lua +++ b/src/resources/filters/crossref/equations.lua @@ -20,7 +20,7 @@ function process_equations(blockEl) end local mathInlines = nil - local targetInlines = pandoc.List() + local targetInlines = pandoc.Inlines{} for i, el in ipairs(inlines) do diff --git a/src/resources/filters/crossref/index.lua b/src/resources/filters/crossref/index.lua index 16ad656d1cc..68daa1ede38 100644 --- a/src/resources/filters/crossref/index.lua +++ b/src/resources/filters/crossref/index.lua @@ -65,9 +65,9 @@ end -- add an entry to the index function indexAddEntry(label, parent, order, caption, appendix) if caption ~= nil then - caption = pandoc.List(caption) + caption = quarto.utils.as_blocks(caption) else - caption = pandoc.List({}) + caption = pandoc.Blocks({}) end crossref.index.entries[label] = { parent = parent, diff --git a/src/resources/filters/crossref/preprocess.lua b/src/resources/filters/crossref/preprocess.lua index 1b995b78a6c..6a7c113fe2d 100644 --- a/src/resources/filters/crossref/preprocess.lua +++ b/src/resources/filters/crossref/preprocess.lua @@ -7,7 +7,7 @@ function crossref_mark_subfloats() return { traverse = "topdown", FloatRefTarget = function(float) - float.content = _quarto.ast.walk(float.content, { + float.content = _quarto.ast.walk(float.content or pandoc.Blocks{}, { FloatRefTarget = function(subfloat) float.has_subfloats = true crossref.subfloats[subfloat.identifier] = { diff --git a/src/resources/filters/customnodes/callout.lua b/src/resources/filters/customnodes/callout.lua index 8a9f4c17dee..929c9c5cb8a 100644 --- a/src/resources/filters/customnodes/callout.lua +++ b/src/resources/filters/customnodes/callout.lua @@ -264,7 +264,8 @@ function _callout_main() return _quarto.format.typst.function_call("callout", { { "body", _quarto.format.typst.as_typst_content(callout.content) }, { "title", _quarto.format.typst.as_typst_content( - callout.title or pandoc.Plain(_quarto.modules.callouts.displayName(callout.type)) + (not quarto.utils.is_empty_node(callout.title) and callout.title) or + pandoc.Plain(_quarto.modules.callouts.displayName(callout.type)) )}, { "background_color", pandoc.RawInline("typst", background_color) }, { "icon_color", pandoc.RawInline("typst", icon_color) }, @@ -406,4 +407,4 @@ function crossref_callouts() return callout end } -end \ No newline at end of file +end diff --git a/src/resources/filters/customnodes/content-hidden.lua b/src/resources/filters/customnodes/content-hidden.lua index f27af5a5418..9117085009a 100644 --- a/src/resources/filters/customnodes/content-hidden.lua +++ b/src/resources/filters/customnodes/content-hidden.lua @@ -105,7 +105,8 @@ local _content_hidden_meta = nil function content_hidden_meta(meta) -- return { -- Meta = function(meta) - _content_hidden_meta = meta + -- The call to `pandoc.Meta` ensures that we hold a copy. + _content_hidden_meta = pandoc.Meta(meta) -- end -- } end diff --git a/src/resources/filters/customnodes/floatreftarget.lua b/src/resources/filters/customnodes/floatreftarget.lua index 03c7d35cc0d..9f75512fc0a 100644 --- a/src/resources/filters/customnodes/floatreftarget.lua +++ b/src/resources/filters/customnodes/floatreftarget.lua @@ -767,7 +767,7 @@ function float_reftarget_render_html_figure(float) local float_content = pandoc.Div(_quarto.ast.walk(float.content, { -- strip image captions Image = function(image) - image.caption = {} + image.caption = pandoc.Inlines{} return image end }) or pandoc.Div({})) -- this should never happen but the lua analyzer doesn't know it @@ -1098,4 +1098,4 @@ end, function(float) return pandoc.Para({im}) end) -global_table_guid_id = 0 \ No newline at end of file +global_table_guid_id = 0 diff --git a/src/resources/filters/customnodes/shortcodes.lua b/src/resources/filters/customnodes/shortcodes.lua index ffb5cc1c7a2..32ad1128e69 100644 --- a/src/resources/filters/customnodes/shortcodes.lua +++ b/src/resources/filters/customnodes/shortcodes.lua @@ -11,7 +11,7 @@ _quarto.ast.add_handler({ kind = "Inline", parse = function(span) - local inner_content = pandoc.List({}) + local inner_content = pandoc.Inlines({}) span.content = span.content:filter(function(el) return el.t == "Span" @@ -78,9 +78,9 @@ _quarto.ast.add_handler({ end local node = _quarto.ast.create_custom_node_scaffold("Shortcode", "Inline") - node.content = inner_content:map(function(el) - return pandoc.Span({el}) - end) + node.content = pandoc.Inlines(inner_content:map(function(el) + return pandoc.Span({el}) + end)) local tbl = { __quarto_custom_node = node, name = name, diff --git a/src/resources/filters/layout/html.lua b/src/resources/filters/layout/html.lua index dc387110211..317cd855656 100644 --- a/src/resources/filters/layout/html.lua +++ b/src/resources/filters/layout/html.lua @@ -190,7 +190,7 @@ function renderHtmlFigure(el, render) end) -- remove identifier (it is now on the div) - el.identifier = "" + el.attr.identifier = "" if not figureDiv.classes:find_if(function(str) return str:match("quarto%-figure%-.+") end) then -- apply standalone figure css if not already set diff --git a/src/resources/filters/layout/lightbox.lua b/src/resources/filters/layout/lightbox.lua index 15203c120fd..d2569bd68d5 100644 --- a/src/resources/filters/layout/lightbox.lua +++ b/src/resources/filters/layout/lightbox.lua @@ -176,10 +176,11 @@ function lightbox() return {{ traverse = "topdown", - Meta = function(meta) + Meta = function(meta) -- Set auto lightbox mode, if need be auto = lightbox_module.automatic(meta) == true - end, + imgCount = 0 + end, -- Find images that are already within links -- we'll use this to filter out these images if -- the most is auto diff --git a/src/resources/filters/layout/typst.lua b/src/resources/filters/layout/typst.lua index 4c875f9b4fa..83fdcc3e2be 100644 --- a/src/resources/filters/layout/typst.lua +++ b/src/resources/filters/layout/typst.lua @@ -11,7 +11,7 @@ function make_typst_figure(tbl) local identifier = tbl.identifier local separator = tbl.separator - if (not caption or #caption.content == 0) and tbl.separator == nil then + if quarto.utils.is_empty_node(caption) and tbl.separator == nil then separator = "" end diff --git a/src/resources/filters/normalize/draft.lua b/src/resources/filters/normalize/draft.lua index 7b9c718a18d..d3f043e6438 100644 --- a/src/resources/filters/normalize/draft.lua +++ b/src/resources/filters/normalize/draft.lua @@ -23,17 +23,17 @@ function normalize_draft() end is_draft = meta[kDraft] == true or tcontains(drafts, quarto.doc.input_file); end, - Pandoc = function(pandoc) + Pandoc = function(doc) if _quarto.format.isHtmlOutput() and not _quarto.format.isHtmlSlideOutput() then if is_draft and draft_mode == kDraftModeGone then - pandoc.blocks = {} + doc.blocks = pandoc.Blocks{} quarto.doc.includeText("in-header", '') - return pandoc + return doc elseif is_draft and draft_mode ~= kDraftModeGone then quarto.doc.includeText("in-header", '') - return pandoc + return doc end end end } -end \ No newline at end of file +end diff --git a/src/resources/filters/normalize/flags.lua b/src/resources/filters/normalize/flags.lua index 8815da0a2fa..d695d39b452 100644 --- a/src/resources/filters/normalize/flags.lua +++ b/src/resources/filters/normalize/flags.lua @@ -107,8 +107,7 @@ function compute_flags() -- FIXME: are we actually triggering this with FloatRefTargets? -- table captions local kTblCap = "tbl-cap" - local tblCap = extractTblCapAttrib(node,kTblCap) - if hasTableRef(node) or tblCap then + if hasTableRef(node) or node.attr.attributes[kTblCap] then flags.has_table_captions = true end diff --git a/src/resources/filters/quarto-init/metainit.lua b/src/resources/filters/quarto-init/metainit.lua index 9c3a22407db..9b63df41219 100644 --- a/src/resources/filters/quarto-init/metainit.lua +++ b/src/resources/filters/quarto-init/metainit.lua @@ -8,6 +8,7 @@ function quarto_meta_init() read_includes(meta) init_crossref_options(meta) initialize_custom_crossref_categories(meta) + return meta end } -end \ No newline at end of file +end diff --git a/src/resources/filters/quarto-post/foldcode.lua b/src/resources/filters/quarto-post/foldcode.lua index c5884a3da57..ab68552c298 100644 --- a/src/resources/filters/quarto-post/foldcode.lua +++ b/src/resources/filters/quarto-post/foldcode.lua @@ -65,7 +65,7 @@ function fold_code_and_lift_codeblocks() local prev_annotated_code_block_scaffold = nil local prev_annotated_code_block = nil -- ok to lift codeblocks - float.content = _quarto.ast.walk(float.content, { + float.content = _quarto.ast.walk(float.content or pandoc.Blocks{}, { traverse = "topdown", DecoratedCodeBlock = function(block) -- defer the folding of code blocks to the DecoratedCodeBlock renderer diff --git a/src/resources/filters/quarto-post/typst.lua b/src/resources/filters/quarto-post/typst.lua index 4a2e7f8d6f5..8ebd9c87596 100644 --- a/src/resources/filters/quarto-post/typst.lua +++ b/src/resources/filters/quarto-post/typst.lua @@ -19,7 +19,9 @@ function render_typst() return { { Meta = function(m) - m["toc-depth"] = PANDOC_WRITER_OPTIONS["toc_depth"] + -- This should be a number, but we must represent it as a string, + -- as numbers are disallowed as metadata values. + m["toc-depth"] = tostring(PANDOC_WRITER_OPTIONS["toc_depth"]) m["toc-indent"] = option("toc-indent") if m["number-depth"] then number_depth = tonumber(pandoc.utils.stringify(m["number-depth"])) @@ -138,7 +140,7 @@ function render_typst_fixups() end img.attributes["fig-align"] = nil - return pandoc.Inlines({ + return pandoc.Plain({ pandoc.RawInline("typst", "#align(" .. align .. ")["), img, pandoc.RawInline("typst", "]"), diff --git a/src/resources/filters/quarto-pre/code-annotation.lua b/src/resources/filters/quarto-pre/code-annotation.lua index 4fa26cf24a6..077a10077e6 100644 --- a/src/resources/filters/quarto-pre/code-annotation.lua +++ b/src/resources/filters/quarto-pre/code-annotation.lua @@ -310,7 +310,7 @@ function code_annotations() -- if code annotations is false, then shut it down if codeAnnotations ~= false then - local outputs = pandoc.List() + local outputs = pandoc.Blocks{} -- annotations[annotation-number] = {list of line numbers} local pendingAnnotations = nil diff --git a/src/resources/filters/quarto-pre/output-location.lua b/src/resources/filters/quarto-pre/output-location.lua index eebe8bc2121..c50d388248a 100644 --- a/src/resources/filters/quarto-pre/output-location.lua +++ b/src/resources/filters/quarto-pre/output-location.lua @@ -71,7 +71,7 @@ function output_location() if _quarto.format.isRevealJsOutput() then return { Blocks = function(blocks) - local newBlocks = pandoc.List() + local newBlocks = pandoc.Blocks{} for _,block in pairs(blocks) do local outputLoc = collectCellOutputLocation(block) if outputLoc then diff --git a/src/resources/filters/quarto-pre/parsefiguredivs.lua b/src/resources/filters/quarto-pre/parsefiguredivs.lua index ca075b0a5a9..868643cd308 100644 --- a/src/resources/filters/quarto-pre/parsefiguredivs.lua +++ b/src/resources/filters/quarto-pre/parsefiguredivs.lua @@ -236,7 +236,7 @@ function parse_floatreftargets() end local caption = refCaptionFromDiv(div) if caption ~= nil then - div.content:remove(#div.content) + div.content:remove() -- drop the last element elseif div.attributes[caption_attr_key] ~= nil then caption = pandoc.Plain(string_to_quarto_ast_inlines(div.attributes[caption_attr_key])) div.attributes[caption_attr_key] = nil @@ -246,10 +246,10 @@ function parse_floatreftargets() local found_caption = false content = _quarto.ast.walk(content, { Table = function(table) - if table.caption.long ~= nil then + -- check if caption is non-empty + if table.caption.long and next(table.caption.long) then found_caption = true caption = table.caption.long[1] -- what if there's more than one entry here? - table.caption.long = nil return table end end @@ -458,7 +458,7 @@ function parse_floatreftargets() fig_attr.classes:insert(v) end end - image.caption = {} + image.caption = pandoc.Inlines{} return image end }) or fig.content[1] -- this shouldn't be needed but the lua analyzer doesn't know it @@ -494,7 +494,7 @@ function parse_floatreftargets() end -- we've parsed the caption, so we can remove it from the table - el.caption.long = pandoc.List({}) + el.caption.long = pandoc.Blocks({}) if label == "" then return nil @@ -602,7 +602,7 @@ function parse_floatreftargets() if img.identifier == "" then local caption = img.caption if #caption > 0 then - img.caption = nil + img.caption = pandoc.Inlines{} return pandoc.Figure(link, { long = { caption } }) else return nil @@ -819,4 +819,4 @@ function forward_cell_subcaps() return div end } -end \ No newline at end of file +end diff --git a/src/resources/filters/quarto-pre/table-captions.lua b/src/resources/filters/quarto-pre/table-captions.lua index ede527f83e0..67a3917f75a 100644 --- a/src/resources/filters/quarto-pre/table-captions.lua +++ b/src/resources/filters/quarto-pre/table-captions.lua @@ -140,7 +140,7 @@ function applyTableCaptions(el, tblCaptions, tblLabels) cap:insert(pandoc.Str("{#" .. tblLabels[idx] .. "}")) end idx = idx + 1 - el.caption.long = pandoc.Plain(cap) + el.caption.long = pandoc.Blocks{pandoc.Plain(cap)} return el end end, @@ -231,7 +231,7 @@ function extractTblCapAttrib(el, name, subcap) else value = pandoc.List({ value }) end - el.attr.attributes[name] = nil + -- el.attr.attributes[name] = nil return value end return nil diff --git a/src/resources/filters/quarto-pre/table-rawhtml.lua b/src/resources/filters/quarto-pre/table-rawhtml.lua index 41708cd51b0..e36e946c31b 100644 --- a/src/resources/filters/quarto-pre/table-rawhtml.lua +++ b/src/resources/filters/quarto-pre/table-rawhtml.lua @@ -14,23 +14,32 @@ function table_merge_raw_html() return { Blocks = function(blocks) - local pendingRaw = pandoc.List() - local merged = pandoc.List() - for i,el in ipairs(blocks) do - if _quarto.format.isRawHtml(el) and el.text:find(patterns.html_table_tag_name) then - pendingRaw:insert(el.text) + local pending_raw = pandoc.List() + local next_element_idx = 1 + for _, el in ipairs(blocks) do + if _quarto.format.isRawHtml(el) and + el.text:find(patterns.html_table_tag_name) then + pending_raw:insert(el.text) else - if #pendingRaw > 0 then - merged:insert(pandoc.RawBlock("html", table.concat(pendingRaw, "\n"))) - pendingRaw = pandoc.List() + if next(pending_raw) then + blocks[next_element_idx] = + pandoc.RawBlock("html", table.concat(pending_raw, "\n")) + pending_raw = pandoc.List() + next_element_idx = next_element_idx + 1 end - merged:insert(el) + blocks[next_element_idx] = el + next_element_idx = next_element_idx + 1 end end - if #pendingRaw > 0 then - merged:insert(pandoc.RawBlock("html", table.concat(pendingRaw, "\n"))) + if #pending_raw > 0 then + blocks[next_element_idx] = + pandoc.RawBlock("html", table.concat(pending_raw, "\n")) + next_element_idx = next_element_idx + 1 end - return merged + for i = next_element_idx, #blocks do + blocks[i] = nil + end + return blocks end } end @@ -54,4 +63,4 @@ function table_respecify_gt_css() return el end } -end \ No newline at end of file +end diff --git a/src/resources/pandoc/datadir/init.lua b/src/resources/pandoc/datadir/init.lua index 1dc45ed14b4..4c7f1eecac5 100644 --- a/src/resources/pandoc/datadir/init.lua +++ b/src/resources/pandoc/datadir/init.lua @@ -1546,9 +1546,9 @@ local function processTextDependency(dependency, meta) local textLoc = rawText.location if meta[textLoc] == nil then - meta[textLoc] = {} + meta[textLoc] = pandoc.List{} end - table.insert(meta[textLoc], pandoc.RawBlock(FORMAT, rawText.text)) + meta[textLoc]:insert(pandoc.Blocks{pandoc.RawBlock(FORMAT, rawText.text)}) end -- make the usePackage statement @@ -1568,9 +1568,9 @@ local function usePackage(package, option) local headerLoc = resolveLocation(kInHeader) if meta[headerLoc] == nil then - meta[headerLoc] = {} + meta[headerLoc] = pandoc.List{} end - table.insert(meta[headerLoc], usePackage(rawPackage.package, rawPackage.options)) + meta[headerLoc]:insert(usePackage(rawPackage.package, rawPackage.options)) end @@ -1584,28 +1584,28 @@ local function processDependencies(meta) -- holds a list of hashes for dependencies that -- have been processed. Process each dependency -- only once - local injectedText = {} - local injectedFile = {} - local injectedPackage = {} + local injectedText = pandoc.List{} + local injectedFile = pandoc.List{} + local injectedPackage = pandoc.List{} -- each line was written as a dependency. -- process them and contribute the appropriate headers - for line in io.lines(dependenciesFile) do + for line in io.lines(dependenciesFile) do local dependency = json.decode(line) if dependency.type == 'text' then if not utils.table.contains(injectedText, dependency.content) then processTextDependency(dependency, meta) - injectedText[#injectedText + 1] = dependency.content + injectedText:insert(dependency.content) end elseif dependency.type == "file" then if not utils.table.contains(injectedFile, dependency.content.path) then processFileDependency(dependency, meta) - injectedFile[#injectedFile + 1] = dependency.content.path + injectedFile:insert(dependency.content.path) end elseif dependency.type == "usepackage" then if not utils.table.contains(injectedPackage, dependency.content.package) then processUsePackageDependency(dependency, meta) - injectedPackage[#injectedPackage + 1] = dependency.content.package + injectedPackage:insert(dependency.content.package) end end end