From ad11d69d19db4c03bc98d7ac5f005afaaea73306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 31 Aug 2026 20:57:39 +0200 Subject: [PATCH 1/5] feat: add the cell-output option Quarto writes the output of an executed cell as a code block with no language, which the filter could not tell apart from a fenced block written without one. Output was labelled DEFAULT and framed like source. Output now keeps the shape Quarto gives it. Set cell-output to true to frame it again. Closes #39 --- CHANGELOG.md | 4 ++ .../code-window/_modules/cell-output.lua | 72 +++++++++++++++++++ _extensions/code-window/_modules/language.lua | 10 ++- _extensions/code-window/_schema.yml | 4 ++ _extensions/code-window/code-window.lua | 22 +++++- _extensions/code-window/main.lua | 9 ++- docs/reference.qmd | 18 +++++ 7 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 _extensions/code-window/_modules/cell-output.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index 52aa5a9..ca5721a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### New Features + +- feat: Add the `cell-output` option. The output of an executed cell is no longer framed, and `cell-output: true` frames it again. (#39) + ## 1.3.3 (2026-08-02) ### Refactoring diff --git a/_extensions/code-window/_modules/cell-output.lua b/_extensions/code-window/_modules/cell-output.lua new file mode 100644 index 0000000..0269ba5 --- /dev/null +++ b/_extensions/code-window/_modules/cell-output.lua @@ -0,0 +1,72 @@ +--- @module "cell-output" +--- @license MIT +--- @copyright 2026 Mickaël Canouil +--- @author Mickaël Canouil +--- @brief Mark the code blocks that hold the output of an executed cell. +--- @description Quarto puts the result of an executed cell in a Div with the +--- `cell-output` classes, and the code block inside carries no language class. +--- A CodeBlock filter sees that block on its own and cannot tell it apart from +--- a fenced block written without a language. This pass marks it while the +--- parent Div is still in reach, so the language and window passes can leave it +--- alone. + +local M = {} + +local MARKER = 'code-window-cell-output' + +local get_config = nil + +--- Inject the configuration accessor. +--- Called by main.lua before any filter handler runs. +--- @param fn function Accessor returning the CodeWindowConfig table +function M.set_config(fn) + get_config = fn +end + +--- Check whether a Div holds the output of an executed cell. +--- @param div pandoc.Div +--- @return boolean +local function is_cell_output(div) + for _, class in ipairs(div.classes) do + if class == 'cell-output' or class:match('^cell%-output%-') then + return true + end + end + return false +end + +--- Mark every code block inside a cell-output Div. +--- Does nothing when the extension is off, or when cell output is framed on +--- request through the `cell-output` option. +--- @param div pandoc.Div +--- @return pandoc.Div|nil Marked Div, or nil when the Div is left as it is +function M.Div(div) + local config = get_config and get_config() + if not config or not config.enabled or config.cell_output then + return nil + end + if not is_cell_output(div) then + return nil + end + return div:walk({ + CodeBlock = function(block) + block.attributes[MARKER] = 'true' + return block + end, + }) +end + +--- Check whether a code block holds the output of an executed cell. +--- @param block pandoc.CodeBlock +--- @return boolean +function M.is_marked(block) + return block.attributes[MARKER] == 'true' +end + +--- Remove the marker, so it never reaches the output document. +--- @param block pandoc.CodeBlock +function M.strip(block) + block.attributes[MARKER] = nil +end + +return M diff --git a/_extensions/code-window/_modules/language.lua b/_extensions/code-window/_modules/language.lua index a769346..59bdeef 100644 --- a/_extensions/code-window/_modules/language.lua +++ b/_extensions/code-window/_modules/language.lua @@ -4,6 +4,9 @@ --- @author Mickaël Canouil --- @brief Normalise code blocks with no or unknown language class. +local cell_output = require( + quarto.utils.resolve_path('_modules/cell-output.lua'):gsub('%.lua$', '')) + local M = {} local known_language_cache = {} @@ -34,9 +37,14 @@ end --- keeps its original token as the label. The label is carried on the --- `code-window-auto-label` attribute (not `filename`, which is reserved for --- author-set filenames) and consumed by the auto-filename windowing path. +--- The output of an executed cell is left as Quarto wrote it. --- @param block pandoc.CodeBlock ---- @return pandoc.CodeBlock +--- @return pandoc.CodeBlock|nil function M.CodeBlock(block) + if cell_output.is_marked(block) then + return nil + end + if not block.classes or #block.classes == 0 then block.classes:insert('default') if not block.attributes['filename'] or block.attributes['filename'] == '' then diff --git a/_extensions/code-window/_schema.yml b/_extensions/code-window/_schema.yml index 66c0d10..41bbfb4 100644 --- a/_extensions/code-window/_schema.yml +++ b/_extensions/code-window/_schema.yml @@ -14,6 +14,10 @@ options: enum: ["default", "macos", "windows"] default: "macos" description: "Window decoration style: 'macos' (traffic lights), 'windows' (title bar buttons), or 'default' (plain filename). Can be overridden per block with the 'code-window-style' attribute." + cell-output: + type: boolean + default: false + description: "Frame the output of an executed cell like a code block. Off by default, so output keeps the shape Quarto gives it." wrapper: type: string default: "code-window" diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index 87ae7a4..97a06f1 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -17,6 +17,7 @@ local log = require(quarto.utils.resolve_path('_modules/logging.lua'):gsub('%.lu local meta_mod = require(quarto.utils.resolve_path('_modules/metadata.lua'):gsub('%.lua$', '')) local pdoc = require(quarto.utils.resolve_path('_modules/pandoc-helpers.lua'):gsub('%.lua$', '')) local html_mod = require(quarto.utils.resolve_path('_modules/html.lua'):gsub('%.lua$', '')) +local cell_output = require(quarto.utils.resolve_path('_modules/cell-output.lua'):gsub('%.lua$', '')) local code_annotations = nil -- ============================================================================ @@ -27,6 +28,7 @@ local code_annotations = nil --- @field enabled boolean Whether code-window styling is enabled --- @field auto_filename boolean Whether to auto-generate filename from language --- @field style string Window decoration style ('macos', 'windows', 'default') +--- @field cell_output boolean Whether the output of an executed cell is framed --- @field typst_wrapper string Typst wrapper function name --- @field hotfix_code_annotations boolean Whether to apply the code-annotations hot-fix for Typst --- @field hotfix_skylighting boolean Whether to apply the Skylighting hot-fix for Typst @@ -37,6 +39,7 @@ local DEFAULTS = { ['enabled'] = 'true', ['auto-filename'] = 'true', ['style'] = 'macos', + ['cell-output'] = 'false', ['wrapper'] = 'code-window', ['collapse'] = 'false', ['lines-label'] = 'true', @@ -635,7 +638,9 @@ function Meta(meta) CURRENT_FORMAT = pdoc.get_quarto_format() local opts = meta_mod.get_options({ extension = EXTENSION_NAME, - keys = { 'enabled', 'auto-filename', 'style', 'wrapper', 'collapse', 'lines-label' }, + keys = { + 'enabled', 'auto-filename', 'style', 'cell-output', 'wrapper', 'collapse', 'lines-label', + }, meta = meta, defaults = DEFAULTS, }) @@ -698,6 +703,7 @@ function Meta(meta) enabled = opts['enabled'] == 'true', auto_filename = opts['auto-filename'] == 'true', style = VALID_STYLES[opts['style']] and opts['style'] or 'macos', + cell_output = opts['cell-output'] == 'true', typst_wrapper = opts['wrapper'], collapse = global_collapse, lines_label = opts['lines-label'] == 'true', @@ -746,11 +752,20 @@ end --- Process CodeBlock elements for HTML/Reveal.js only. --- Typst processing is handled by the Blocks filter. function CodeBlock(block) + -- The Typst path reads the marker in the Pandoc filter, which runs first, so + -- this pass is where it is removed for every format. + local is_cell_output = cell_output.is_marked(block) + cell_output.strip(block) + if not CURRENT_FORMAT or not CONFIG or not CONFIG.enabled then block.attributes['code-window-no-auto-filename'] = nil return block end + if is_cell_output then + return block + end + if CURRENT_FORMAT == 'html' then return process_html(block) end @@ -770,6 +785,11 @@ end --- @return boolean window_opted_out True when code-window-enabled="false" was set --- @return string|nil lines_label Highlighted-lines spec for the title bar local function resolve_window_params(block) + -- The output of an executed cell keeps the shape Quarto gave it. + if cell_output.is_marked(block) then + return nil, false, nil, true, nil + end + -- Per-block opt-out: code-window-enabled="false" skips window chrome. local block_enabled = block.attributes['code-window-enabled'] if block_enabled then diff --git a/_extensions/code-window/main.lua b/_extensions/code-window/main.lua index 44e1498..a05e7f1 100644 --- a/_extensions/code-window/main.lua +++ b/_extensions/code-window/main.lua @@ -12,6 +12,9 @@ local log = require(quarto.utils.resolve_path('_modules/logging.lua'):gsub('%.lu -- LOAD SUBMODULES -- ============================================================================ +local cell_output = require( + quarto.utils.resolve_path('_modules/cell-output.lua'):gsub('%.lua$', '')) + local language = require( quarto.utils.resolve_path('_modules/language.lua'):gsub('%.lua$', '')) @@ -22,6 +25,7 @@ local code_window = require( quarto.utils.resolve_path('code-window.lua'):gsub('%.lua$', '')) code_window.set_code_annotations(code_annotations) +cell_output.set_config(code_window.CONFIG) -- ============================================================================ -- SKYLIGHTING HOT-FIX @@ -49,9 +53,12 @@ end -- FILTER ASSEMBLY -- ============================================================================ +-- Meta runs first because the cell-output pass needs the configuration, and +-- that pass runs before the language pass so a marked block is never relabelled. local filters = { - { CodeBlock = language.CodeBlock }, { Meta = code_window.Meta }, + { Div = cell_output.Div }, + { CodeBlock = language.CodeBlock }, { Pandoc = code_window.Pandoc }, { CodeBlock = code_window.CodeBlock }, } diff --git a/docs/reference.qmd b/docs/reference.qmd index 6b66f21..4c3f8d1 100644 --- a/docs/reference.qmd +++ b/docs/reference.qmd @@ -18,6 +18,7 @@ extensions: code-window: style: macos auto-filename: true + cell-output: false collapse: false lines-label: true ``` @@ -27,6 +28,7 @@ extensions: | `enabled` | boolean | `true` | Whether the filter runs at all. | | `style` | string | `macos` | The window chrome: `macos` for traffic lights, `windows` for title-bar buttons, `default` for a plain filename. | | `auto-filename` | boolean | `true` | Use the block's language as the filename when none is given. | +| `cell-output` | boolean | `false` | Frame the output of an executed cell as well as its source. | | `collapse` | boolean or string | `false` | Wrap every block in a `
`. `open` renders it expanded, `closed` or `true` collapsed. HTML only. | | `lines-label` | boolean | `true` | Show a chip beside the filename with the highlighted-line spec. | | `wrapper` | string | `code-window` | The Typst function used to draw the chrome. | @@ -60,6 +62,22 @@ The result is the same window; it needs JavaScript, as the rest of the HTML chro Typst frames derived and author-set filenames alike, without a script. ::: +## Executed cells + +Quarto writes the output of an executed cell as a code block with no language. +That block keeps the shape Quarto gives it: no chrome, and no derived filename. +Only the source of the cell is framed. + +Set `cell-output` to `true` to frame the output as well. + +```yaml +extensions: + code-window: + cell-output: true +``` + +The output has no attributes an author can reach, so this option is the only control over it. + ## How the chrome is applied In HTML the extension marks blocks and injects a stylesheet and a script. From 822ac06684f87f5917d0f96fced0647cfea93db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 31 Aug 2026 21:03:03 +0200 Subject: [PATCH 2/5] refactor: gate the cell-output pass at document level Read the configuration once per document and walk the tree only when the output has to stay unframed. Drop the unused opt-out return value of resolve_window_params. --- .../code-window/_modules/cell-output.lua | 15 ------------- _extensions/code-window/code-window.lua | 13 ++++++------ _extensions/code-window/main.lua | 21 +++++++++++++++++-- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/_extensions/code-window/_modules/cell-output.lua b/_extensions/code-window/_modules/cell-output.lua index 0269ba5..ebc5ee3 100644 --- a/_extensions/code-window/_modules/cell-output.lua +++ b/_extensions/code-window/_modules/cell-output.lua @@ -14,15 +14,6 @@ local M = {} local MARKER = 'code-window-cell-output' -local get_config = nil - ---- Inject the configuration accessor. ---- Called by main.lua before any filter handler runs. ---- @param fn function Accessor returning the CodeWindowConfig table -function M.set_config(fn) - get_config = fn -end - --- Check whether a Div holds the output of an executed cell. --- @param div pandoc.Div --- @return boolean @@ -36,15 +27,9 @@ local function is_cell_output(div) end --- Mark every code block inside a cell-output Div. ---- Does nothing when the extension is off, or when cell output is framed on ---- request through the `cell-output` option. --- @param div pandoc.Div --- @return pandoc.Div|nil Marked Div, or nil when the Div is left as it is function M.Div(div) - local config = get_config and get_config() - if not config or not config.enabled or config.cell_output then - return nil - end if not is_cell_output(div) then return nil end diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index 97a06f1..9b12301 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -755,7 +755,9 @@ function CodeBlock(block) -- The Typst path reads the marker in the Pandoc filter, which runs first, so -- this pass is where it is removed for every format. local is_cell_output = cell_output.is_marked(block) - cell_output.strip(block) + if is_cell_output then + cell_output.strip(block) + end if not CURRENT_FORMAT or not CONFIG or not CONFIG.enabled then block.attributes['code-window-no-auto-filename'] = nil @@ -782,12 +784,11 @@ end --- @return string|nil filename --- @return boolean is_auto --- @return string|nil block_style ---- @return boolean window_opted_out True when code-window-enabled="false" was set --- @return string|nil lines_label Highlighted-lines spec for the title bar local function resolve_window_params(block) -- The output of an executed cell keeps the shape Quarto gave it. if cell_output.is_marked(block) then - return nil, false, nil, true, nil + return nil, false, nil, nil end -- Per-block opt-out: code-window-enabled="false" skips window chrome. @@ -796,7 +797,7 @@ local function resolve_window_params(block) block.attributes['code-window-enabled'] = nil end if block_enabled == 'false' then - return nil, false, nil, true, nil + return nil, false, nil, nil end local block_style = read_block_style(block) @@ -823,7 +824,7 @@ local function resolve_window_params(block) lines_label = read_block_lines_label(block) end - return filename, is_auto, block_style, false, lines_label + return filename, is_auto, block_style, lines_label end --- Process a single CodeBlock for Typst, returning replacement blocks. @@ -834,7 +835,7 @@ end --- @return boolean consumed_next Whether the next block was consumed --- @return integer|nil annotation_block_id Block ID if annotations were found (for parent propagation) local function process_typst_block(block, next_block) - local filename, is_auto, block_style, window_opted_out, lines_label = resolve_window_params(block) + local filename, is_auto, block_style, lines_label = resolve_window_params(block) local has_window = filename and filename ~= '' local effective_style = block_style or CONFIG.style diff --git a/_extensions/code-window/main.lua b/_extensions/code-window/main.lua index a05e7f1..efaf606 100644 --- a/_extensions/code-window/main.lua +++ b/_extensions/code-window/main.lua @@ -25,7 +25,24 @@ local code_window = require( quarto.utils.resolve_path('code-window.lua'):gsub('%.lua$', '')) code_window.set_code_annotations(code_annotations) -cell_output.set_config(code_window.CONFIG) + +-- ============================================================================ +-- CELL OUTPUT +-- ============================================================================ + +--- Mark the code blocks that hold the output of an executed cell, so the later +--- passes leave them as Quarto wrote them. Reads the configuration once and +--- walks the document only when the output has to stay unframed. +--- @param doc pandoc.Pandoc +--- @return pandoc.Pandoc|nil Marked document, or nil when nothing is marked +local function mark_cell_output(doc) + local config = code_window.CONFIG() + if not config or not config.enabled or config.cell_output then + return nil + end + doc.blocks = doc.blocks:walk({ Div = cell_output.Div }) + return doc +end -- ============================================================================ -- SKYLIGHTING HOT-FIX @@ -57,7 +74,7 @@ end -- that pass runs before the language pass so a marked block is never relabelled. local filters = { { Meta = code_window.Meta }, - { Div = cell_output.Div }, + { Pandoc = mark_cell_output }, { CodeBlock = language.CodeBlock }, { Pandoc = code_window.Pandoc }, { CodeBlock = code_window.CodeBlock }, From cffb690658608451abdfb389581b490fff7de81e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 31 Aug 2026 21:11:18 +0200 Subject: [PATCH 3/5] fix: frame executed cell output that carries a filename An engine can name an output block, through knitr's attr-output for example. HTML framed that block through Quarto's own wrapper while Typst did not, so the two formats disagreed. --- _extensions/code-window/code-window.lua | 7 ++++--- docs/reference.qmd | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index 9b12301..d29b828 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -764,7 +764,7 @@ function CodeBlock(block) return block end - if is_cell_output then + if is_cell_output and str.is_empty(block.attributes['filename']) then return block end @@ -786,8 +786,9 @@ end --- @return string|nil block_style --- @return string|nil lines_label Highlighted-lines spec for the title bar local function resolve_window_params(block) - -- The output of an executed cell keeps the shape Quarto gave it. - if cell_output.is_marked(block) then + -- The output of an executed cell keeps the shape Quarto gave it, unless the + -- engine gave it a filename of its own. + if cell_output.is_marked(block) and str.is_empty(block.attributes['filename']) then return nil, false, nil, nil end diff --git a/docs/reference.qmd b/docs/reference.qmd index 4c3f8d1..27720df 100644 --- a/docs/reference.qmd +++ b/docs/reference.qmd @@ -76,7 +76,8 @@ extensions: cell-output: true ``` -The output has no attributes an author can reach, so this option is the only control over it. +An engine can put a filename on the output block, through knitr's `attr-output` for example. +Output named that way is always framed, whatever this option says. ## How the chrome is applied From eeb4bf960e74e2f6df33a217216f1beedd0bb5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Tue, 1 Sep 2026 00:37:21 +0200 Subject: [PATCH 4/5] fix: keep cell output plain when the filter is off The language pass runs whether the extension is on or off, so cell output was relabelled with enabled: false and the internal auto-label attribute reached the rendered document. --- CHANGELOG.md | 4 ++++ _extensions/code-window/code-window.lua | 1 + _extensions/code-window/main.lua | 8 +++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca5721a..473a2d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - feat: Add the `cell-output` option. The output of an executed cell is no longer framed, and `cell-output: true` frames it again. (#39) +### Bug Fixes + +- fix: Remove the internal `code-window-auto-label` attribute from the rendered document when the filter is off. + ## 1.3.3 (2026-08-02) ### Refactoring diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index d29b828..e8b14c3 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -761,6 +761,7 @@ function CodeBlock(block) if not CURRENT_FORMAT or not CONFIG or not CONFIG.enabled then block.attributes['code-window-no-auto-filename'] = nil + block.attributes['code-window-auto-label'] = nil return block end diff --git a/_extensions/code-window/main.lua b/_extensions/code-window/main.lua index efaf606..d3118fe 100644 --- a/_extensions/code-window/main.lua +++ b/_extensions/code-window/main.lua @@ -32,12 +32,14 @@ code_window.set_code_annotations(code_annotations) --- Mark the code blocks that hold the output of an executed cell, so the later --- passes leave them as Quarto wrote them. Reads the configuration once and ---- walks the document only when the output has to stay unframed. +--- walks the document only when the output has to stay unframed. The language +--- pass runs whether the extension is on or off, so the mark is set in both +--- cases; the window passes remove it either way. --- @param doc pandoc.Pandoc ---- @return pandoc.Pandoc|nil Marked document, or nil when nothing is marked +--- @return pandoc.Pandoc|nil Marked document, or nil when the pass is skipped local function mark_cell_output(doc) local config = code_window.CONFIG() - if not config or not config.enabled or config.cell_output then + if not config or config.cell_output then return nil end doc.blocks = doc.blocks:walk({ Div = cell_output.Div }) From e375e0407c02de88a44a70ffc2723184ccb435e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Tue, 1 Sep 2026 00:44:28 +0200 Subject: [PATCH 5/5] fix: leave annotations and labels off cell output Annotations were resolved on an unnamed output block before the window was skipped, so output that holds an annotation comment was rewritten. The internal auto-label attribute also reached the document on the paths that return before the auto-filename branch. --- CHANGELOG.md | 2 +- _extensions/code-window/code-window.lua | 43 +++++++++++++++++-------- _extensions/code-window/main.lua | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 473a2d3..5496fa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ ### Bug Fixes -- fix: Remove the internal `code-window-auto-label` attribute from the rendered document when the filter is off. +- fix: Remove the internal `code-window-auto-label` attribute from the rendered document. ## 1.3.3 (2026-08-02) diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index e8b14c3..1523271 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -63,6 +63,18 @@ local CONFIG = nil local TYPST_BG_COLOUR = nil local ANNOTATION_BLOCK_COUNTER = 0 +-- ============================================================================ +-- CELL OUTPUT +-- ============================================================================ + +--- Check whether a block holds the output of an executed cell that the engine +--- did not name. Such a block keeps the shape Quarto gave it. +--- @param block pandoc.CodeBlock Code block element +--- @return boolean +local function is_unnamed_cell_output(block) + return cell_output.is_marked(block) and str.is_empty(block.attributes['filename']) +end + -- ============================================================================ -- BLOCK-LEVEL STYLE OVERRIDE -- ============================================================================ @@ -483,6 +495,12 @@ end --- @param block pandoc.CodeBlock Code block element --- @return pandoc.Div|pandoc.CodeBlock Wrapped block or original local function process_html(block) + -- Default/unknown/no-language blocks carry their label on + -- code-window-auto-label (set by the language module). Read it here so no + -- return path can leak it into the rendered document. + local auto_label = block.attributes['code-window-auto-label'] + block.attributes['code-window-auto-label'] = nil + -- Per-block opt-out: code-window-enabled="false" skips window chrome. local block_enabled = block.attributes['code-window-enabled'] if block_enabled then @@ -523,11 +541,8 @@ local function process_html(block) return block end - -- Default/unknown/no-language blocks carry their label on - -- code-window-auto-label (set by the language module); everything else uses - -- its language class. - local filename = block.attributes['code-window-auto-label'] or block.classes[1] - block.attributes['code-window-auto-label'] = nil + -- Blocks with a language of their own are labelled with its class. + local filename = auto_label or block.classes[1] -- Set the filename attribute so Quarto creates its own .code-with-filename -- wrapper. This preserves the CodeBlock+OrderedList sibling structure @@ -754,8 +769,8 @@ end function CodeBlock(block) -- The Typst path reads the marker in the Pandoc filter, which runs first, so -- this pass is where it is removed for every format. - local is_cell_output = cell_output.is_marked(block) - if is_cell_output then + local is_plain_output = is_unnamed_cell_output(block) + if cell_output.is_marked(block) then cell_output.strip(block) end @@ -765,7 +780,7 @@ function CodeBlock(block) return block end - if is_cell_output and str.is_empty(block.attributes['filename']) then + if is_plain_output then return block end @@ -787,12 +802,6 @@ end --- @return string|nil block_style --- @return string|nil lines_label Highlighted-lines spec for the title bar local function resolve_window_params(block) - -- The output of an executed cell keeps the shape Quarto gave it, unless the - -- engine gave it a filename of its own. - if cell_output.is_marked(block) and str.is_empty(block.attributes['filename']) then - return nil, false, nil, nil - end - -- Per-block opt-out: code-window-enabled="false" skips window chrome. local block_enabled = block.attributes['code-window-enabled'] if block_enabled then @@ -837,6 +846,12 @@ end --- @return boolean consumed_next Whether the next block was consumed --- @return integer|nil annotation_block_id Block ID if annotations were found (for parent propagation) local function process_typst_block(block, next_block) + -- The output of an executed cell keeps the shape Quarto gave it, annotations + -- included, unless the engine gave it a filename of its own. + if is_unnamed_cell_output(block) then + return { block }, false, nil + end + local filename, is_auto, block_style, lines_label = resolve_window_params(block) local has_window = filename and filename ~= '' local effective_style = block_style or CONFIG.style diff --git a/_extensions/code-window/main.lua b/_extensions/code-window/main.lua index d3118fe..25b61da 100644 --- a/_extensions/code-window/main.lua +++ b/_extensions/code-window/main.lua @@ -39,7 +39,7 @@ code_window.set_code_annotations(code_annotations) --- @return pandoc.Pandoc|nil Marked document, or nil when the pass is skipped local function mark_cell_output(doc) local config = code_window.CONFIG() - if not config or config.cell_output then + if not config or (config.enabled and config.cell_output) then return nil end doc.blocks = doc.blocks:walk({ Div = cell_output.Div })