diff --git a/src/resources/filters/customnodes/decoratedcodeblock.lua b/src/resources/filters/customnodes/decoratedcodeblock.lua index 9ed8674b85e..26e618d9ec2 100644 --- a/src/resources/filters/customnodes/decoratedcodeblock.lua +++ b/src/resources/filters/customnodes/decoratedcodeblock.lua @@ -38,7 +38,9 @@ _quarto.ast.add_renderer("DecoratedCodeBlock", return true end, function(node) - return node.code_block + return _quarto.ast.walk(node.code_block, { + CodeBlock = render_folded_block + }) end) -- markdown renderer @@ -66,7 +68,9 @@ _quarto.ast.add_renderer("DecoratedCodeBlock", pandoc.Attr("", {"code-with-filename"}) ) else - return el + return _quarto.ast.walk(quarto.utils.as_blocks(el), { + CodeBlock = render_folded_block + }) end end) @@ -76,9 +80,17 @@ _quarto.ast.add_renderer("DecoratedCodeBlock", return _quarto.format.isLatexOutput() end, function(node) - local el = node.code_block -- add listing class to the code block - el.attr.classes:insert("listing") + -- need to walk the code block instead of assigning directly + -- because upstream filters might have replaced the code block with + -- more than one element + node.code_block = _quarto.ast.walk(quarto.utils.as_blocks(node.code_block), { + CodeBlock = function(el) + el.attr.classes:insert("listing") + return render_folded_block(el) + end + }) or node.code_block -- unneeded but the Lua analyzer doesn't know that + -- if we are use the listings package we don't need to do anything -- further, otherwise generate the listing div and return it if not param("listings", false) then @@ -123,7 +135,7 @@ _quarto.ast.add_renderer("DecoratedCodeBlock", listingDiv.content:insert(pandoc.RawBlock("latex", "\\end{codelisting}")) return listingDiv end - return el + return node.code_block end) -- html renderer @@ -132,32 +144,40 @@ _quarto.ast.add_renderer("DecoratedCodeBlock", return _quarto.format.isHtmlOutput() end, function(node) + if node.filename == nil then + return _quarto.ast.walk(quarto.utils.as_blocks(node.code_block), { + CodeBlock = render_folded_block + }) + end local el = node.code_block local filenameEl local caption local classes = pandoc.List() - local fancy_output = false - if node.filename ~= nil then - filenameEl = pandoc.Div({pandoc.Plain{ - pandoc.RawInline("html", "
"),
-        pandoc.Strong{pandoc.Str(node.filename)},
-        pandoc.RawInline("html", "
") - }}, pandoc.Attr("", {"code-with-filename-file"})) - classes:insert("code-with-filename") - fancy_output = true - end - if not fancy_output then - return el - end + filenameEl = pandoc.Div({pandoc.Plain{ + pandoc.RawInline("html", "
"),
+      pandoc.Strong{pandoc.Str(node.filename)},
+      pandoc.RawInline("html", "
") + }}, pandoc.Attr("", {"code-with-filename-file"})) + classes:insert("code-with-filename") local blocks = pandoc.Blocks({}) if caption ~= nil then blocks:insert(caption) end + el = _quarto.ast.walk(quarto.utils.as_blocks(el), { + CodeBlock = render_folded_block + }) or pandoc.Blocks({}) if filenameEl ~= nil then - blocks:insert(filenameEl) + el = _quarto.ast.walk(quarto.utils.as_blocks(el), { + CodeBlock = function(block) + return pandoc.Blocks({ + filenameEl, + block + }) + end + }) or pandoc.Blocks({}) end - blocks:extend(quarto.utils.as_blocks(el) or {}) + blocks:extend(el) return pandoc.Div(blocks, pandoc.Attr("", classes)) end) diff --git a/src/resources/filters/quarto-post/foldcode.lua b/src/resources/filters/quarto-post/foldcode.lua index 73dc101cb31..a26bc33ecf2 100644 --- a/src/resources/filters/quarto-post/foldcode.lua +++ b/src/resources/filters/quarto-post/foldcode.lua @@ -2,94 +2,101 @@ -- Copyright (C) 2021-2022 Posit Software, PBC -- slightly fancy code here to make two operations work in a single pass +function render_folded_block(block) + local make_code_fold_html = function(fold, summary) + local div = pandoc.Div({}, pandoc.Attr("", { + "quarto-scaffold" + })) + quarto_global_state.codeFoldingCss = _quarto.format.isHtmlOutput() + local open = "" + if fold == "show" then + open = " open" + end + local style = "" + local clz = 'code-fold' + if block.attr.classes:includes("hidden") then + clz = clz .. " hidden" + end -local pass_uuid = "8c6b3915-b784-4ce5-8e73-59b368a9f289" + style = ' class="' .. clz .. '"' + local beginPara = pandoc.Plain({ + pandoc.RawInline("html", "\n"), + }) + + if not isEmpty(summary) then + tappend(beginPara.content, markdownToInlines(summary)) + end + beginPara.content:insert(pandoc.RawInline("html", "")) + div.content:insert(beginPara) + div.content:insert(block) + div.content:insert(pandoc.RawBlock("html", "")) + return div + end + local make_code_cell_scaffold = function(div) + return pandoc.Div({ block }, pandoc.Attr("", { "quarto-scaffold" })) + end + if not block.attr.classes:includes("cell-code") then + return nil + end + if not (_quarto.format.isHtmlOutput() or _quarto.format.isMarkdownWithHtmlOutput()) then + return make_code_cell_scaffold(block) + end + local fold = foldAttribute(block) + local summary = summaryAttribute(block) + if fold ~= nil or summary ~= nil then + block.attr.attributes["code-fold"] = nil + block.attr.attributes["code-summary"] = nil + if fold ~= "none" then + return make_code_fold_html(fold, summary) + else + return make_code_cell_scaffold(block) + end + else + return make_code_cell_scaffold(block) + end +end function fold_code_and_lift_codeblocks() return { + traverse = "topdown", FloatRefTarget = function(float, float_node) - -- we need some special case logic to not lift code blocks - -- from listing floats that have no other content. - local other_content_found = false - _quarto.ast.walk(float.content, { - Div = function(div) - if not div.classes:includes(pass_uuid) then - other_content_found = true - end - end, - }) - if not other_content_found then + -- we need to not lift code blocks from listing floats + if float.type == "Listing" then return nil end local blocks = pandoc.Blocks({}) -- ok to lift codeblocks float.content = _quarto.ast.walk(float.content, { + traverse = "topdown", Div = function(div) - if div.classes:includes(pass_uuid) then - blocks:insert(div) - return {} - end - end + other_content_found = true + return nil + end, + DecoratedCodeBlock = function(block) + -- defer the folding of code blocks to the DecoratedCodeBlock renderer + -- so that we can handle filename better + return nil, false + end, + CodeBlock = function(block) + blocks:insert(render_folded_block(block)) + return {} + end, }) if #blocks > 0 then blocks:insert(float_node) - return blocks + return blocks, false end end, - CodeBlock = function(block) - local make_code_fold_html = function(fold, summary) - local div = pandoc.Div({}, pandoc.Attr("", { - "quarto-scaffold", pass_uuid - })) - quarto_global_state.codeFoldingCss = _quarto.format.isHtmlOutput() - local open = "" - if fold == "show" then - open = " open" - end - local style = "" - local clz = 'code-fold' - if block.attr.classes:includes("hidden") then - clz = clz .. " hidden" - end + DecoratedCodeBlock = function(block) + -- defer the folding of code blocks to the DecoratedCodeBlock renderer + -- so that we can handle filename better + return nil, false + end, - style = ' class="' .. clz .. '"' - local beginPara = pandoc.Plain({ - pandoc.RawInline("html", "\n"), - }) - - if not isEmpty(summary) then - tappend(beginPara.content, markdownToInlines(summary)) - end - beginPara.content:insert(pandoc.RawInline("html", "")) - div.content:insert(beginPara) - div.content:insert(block) - div.content:insert(pandoc.RawBlock("html", "")) - return div - end - local make_code_cell_scaffold = function(div) - return pandoc.Div({ block }, pandoc.Attr("", { "quarto-scaffold", pass_uuid })) - end - if not block.attr.classes:includes("cell-code") then - return nil - end - if not (_quarto.format.isHtmlOutput() or _quarto.format.isMarkdownWithHtmlOutput()) then - return make_code_cell_scaffold(block) - end - local fold = foldAttribute(block) - local summary = summaryAttribute(block) - if fold ~= nil or summary ~= nil then - block.attr.attributes["code-fold"] = nil - block.attr.attributes["code-summary"] = nil - if fold ~= "none" then - return make_code_fold_html(fold, summary) - else - return make_code_cell_scaffold(block) - end - else - return make_code_cell_scaffold(block) - end + CodeBlock = function(block) + return render_folded_block(block), false end } end diff --git a/tests/docs/smoke-all/2023/12/12/2683.qmd b/tests/docs/smoke-all/2023/12/12/2683.qmd new file mode 100644 index 00000000000..c697189cf9d --- /dev/null +++ b/tests/docs/smoke-all/2023/12/12/2683.qmd @@ -0,0 +1,23 @@ +--- +title: Test +format: html +_quarto: + tests: + html: + ensureHtmlElements: + - ["details div.code-with-filename-file"] +--- + +Non computation code filename + +```{.r filename="file.R"} +1 + 1 +``` + +Inside code-fold + +```{r filename="file.R"} +#| code-fold: true + +1 + 1 +``` \ No newline at end of file