From d1ef9676376a7afa954784d284507bc2b83175ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Tue, 22 Sep 2026 22:49:25 +0200 Subject: [PATCH 1/3] fix: honour code-window-collapse false on a block The call site read the block override with a bare or, so an explicit false fell through to the document option and the block was folded anyway. The comment above the reader already said this must not happen. --- CHANGELOG.md | 1 + _extensions/code-window/code-window.lua | 18 +++++++++++++++--- tests/fixtures/collapse-block-off.qmd | 16 ++++++++++++++++ tests/run.sh | 13 +++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 tests/fixtures/collapse-block-off.qmd diff --git a/CHANGELOG.md b/CHANGELOG.md index ecd6d3e..9900fe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - fix: Remove the extension's own label attribute when the output format gets no window chrome, so a writer that keeps attributes no longer prints it. (#63) - fix: Check every code block attribute in the code-window group against the schema, so a value nothing validated before, such as code-window-enabled, is now reported when it is wrong. The extension's own duplicate warnings for an invalid code-window-style or code-window-collapse are removed, since the schema already names the same mistake. (#60) - fix: Honour an explicit code-window-no-auto-filename="false", which previously suppressed auto-filename exactly like "true". (#60) +- fix: Honour `code-window-collapse="false"` on a block, which could not turn off a document that sets `collapse`. The block fell back to the document setting and was folded anyway. - fix: Remove the extension's own duplicate collapse and style warnings at the document option level, now that the schema reports each mistake once. (#60) - fix: Match the code-window-collapse attribute schema to the string Pandoc always provides, so a documented "true" or "false" value no longer warns. (#60) - fix: Validate a code block's attributes on the HTML path the same way the Typst path already does, so an invalid attribute on a block holding executed-cell output is now reported on HTML too, instead of being silently accepted. (#60) diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index 55586c0..745723a 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -248,12 +248,20 @@ end --- test needed. --- @param resolved table This block's attributes, resolved against the schema --- @return string|nil Resolved collapse mode ("open"/"closed") or nil when off +--- @return boolean Whether this block decided, which is what separates an +--- explicit "false" from an attribute the block never wrote local function read_block_collapse(resolved) local raw = resolved['code-window-collapse'] if raw == nil then - return nil + return nil, false + end + local mode = VALID_COLLAPSE[raw] + if mode == nil then + -- A value the schema does not accept. The check reports it, and the + -- document option decides as though the block had written nothing. + return nil, false end - return resolve_collapse(raw) + return resolve_collapse(raw), true end --- Read a highlight-lines spec from the block, looking at the @@ -664,7 +672,11 @@ local function process_html(block, resolved, auto_label) return block end - local effective_collapse = read_block_collapse(resolved) or CONFIG.collapse + local block_collapse, block_decided = read_block_collapse(resolved) + local effective_collapse = block_collapse + if not block_decided then + effective_collapse = CONFIG.collapse + end local explicit_filename = block.attributes['filename'] -- Add the marker classes and the chip the injected script reads. Both diff --git a/tests/fixtures/collapse-block-off.qmd b/tests/fixtures/collapse-block-off.qmd new file mode 100644 index 0000000..a5a342e --- /dev/null +++ b/tests/fixtures/collapse-block-off.qmd @@ -0,0 +1,16 @@ +--- +title: "Collapse turned off for one block" +format: html +filters: + - code-window +extensions: + code-window: + collapse: true +--- + +The document folds every block. +This one opts out, so it carries no collapse class. + +```{.python filename="opted-out.py" code-window-collapse="false"} +x = 1 +``` diff --git a/tests/run.sh b/tests/run.sh index cae2fc8..9ebd88b 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -280,6 +280,19 @@ else "a #code-window( call in wrapper-default.typ" fi +# ============================================================================ +# A block opts out of the document's collapse setting +# ============================================================================ + +render collapse-block-off html + +if block_classes "${work_dir}/collapse-block-off.html" | grep -q 'cw-collapse'; then + report fail "collapse-block-off: the block opts out of collapsing" \ + "no cw-collapse class in collapse-block-off.html" +else + report pass "collapse-block-off: the block opts out of collapsing" +fi + # ============================================================================ printf '\n%s passed, %s failed\n' "${passed}" "${failed}" From ab15fb5979681aa6176400c06feed1836fd243c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Tue, 22 Sep 2026 22:52:05 +0200 Subject: [PATCH 2/3] fix: mark the block that turns collapsing off The script reads a missing marker as an inheriting block, so the Lua change alone left the block folded in the browser. The opt-out now carries cw-collapse-none, which the script honours as off. --- _extensions/code-window/code-window.lua | 9 +++++++-- tests/fixtures/collapse-block-off.qmd | 6 +++++- tests/run.sh | 23 +++++++++++++++++++---- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index 745723a..f17d542 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -685,8 +685,13 @@ local function process_html(block, resolved, auto_label) if overrides.style then table.insert(block.classes, 'cw-style-' .. overrides.style) end + -- A block that turned collapsing off is marked as well. The script reads + -- the absence of a marker as "this block said nothing" and falls back to + -- the document setting, so an opt-out needs a marker of its own. if effective_collapse then table.insert(block.classes, 'cw-collapse-' .. effective_collapse) + elseif block_decided then + table.insert(block.classes, 'cw-collapse-none') end if overrides.lines_label then block.attributes['code-window-lines-label'] = overrides.lines_label @@ -767,8 +772,8 @@ document.addEventListener("DOMContentLoaded",function(){ } var collapse=null; if(marker){ - var cm=marker.className.match(/cw-collapse-(open|closed)/); - if(cm){collapse=cm[1];marker.classList.remove(cm[0]);} + var cm=marker.className.match(/cw-collapse-(open|closed|none)/); + if(cm){collapse=cm[1]==='none'?false:cm[1];marker.classList.remove(cm[0]);} } if(collapse===null&&DEFAULT_COLLAPSE){collapse=DEFAULT_COLLAPSE;} if(marker&&marker.hasAttribute("data-code-window-lines-label")){ diff --git a/tests/fixtures/collapse-block-off.qmd b/tests/fixtures/collapse-block-off.qmd index a5a342e..0788196 100644 --- a/tests/fixtures/collapse-block-off.qmd +++ b/tests/fixtures/collapse-block-off.qmd @@ -9,8 +9,12 @@ extensions: --- The document folds every block. -This one opts out, so it carries no collapse class. +The first block opts out, and the second takes the document setting. ```{.python filename="opted-out.py" code-window-collapse="false"} x = 1 ``` + +```{.python filename="inherits.py"} +y = 2 +``` diff --git a/tests/run.sh b/tests/run.sh index 9ebd88b..eddea8c 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -286,11 +286,26 @@ fi render collapse-block-off html -if block_classes "${work_dir}/collapse-block-off.html" | grep -q 'cw-collapse'; then - report fail "collapse-block-off: the block opts out of collapsing" \ - "no cw-collapse class in collapse-block-off.html" +# The script folds a block that carries no marker, reading the absence as +# "this block said nothing", so the opt-out is a marker of its own rather +# than a missing one. The second block is here to show the two differ. +collapse_markers="$(block_classes "${work_dir}/collapse-block-off.html" | grep -o 'cw-collapse-[a-z]*' | sort | tr '\n' ' ')" + +if [ "${collapse_markers}" = "cw-collapse-closed cw-collapse-none " ]; then + report pass "collapse-block-off: the block opts out and its neighbour does not" +else + report fail "collapse-block-off: the block opts out and its neighbour does not" \ + "cw-collapse-none on one block and cw-collapse-closed on the other, got: ${collapse_markers}" +fi + +# The document setting still reaches the page, which is what the opt-out has +# to override, and the script has to know the marker to honour it. +if grep -q 'DEFAULT_COLLAPSE="closed"' "${work_dir}/collapse-block-off.html" && + grep -q 'cw-collapse-(open|closed|none)' "${work_dir}/collapse-block-off.html"; then + report pass "collapse-block-off: the script reads the opt-out marker" else - report pass "collapse-block-off: the block opts out of collapsing" + report fail "collapse-block-off: the script reads the opt-out marker" \ + 'DEFAULT_COLLAPSE="closed" and a cw-collapse-(open|closed|none) match in the injected script' fi # ============================================================================ From d99c969b333390e971dacfbb68829212929f6f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Tue, 22 Sep 2026 22:56:53 +0200 Subject: [PATCH 3/3] fix: mark the opt-out only where the document collapses --- _extensions/code-window/code-window.lua | 4 ++-- tests/run.sh | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index f17d542..ca8c465 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -261,7 +261,7 @@ local function read_block_collapse(resolved) -- document option decides as though the block had written nothing. return nil, false end - return resolve_collapse(raw), true + return mode or nil, true end --- Read a highlight-lines spec from the block, looking at the @@ -690,7 +690,7 @@ local function process_html(block, resolved, auto_label) -- the document setting, so an opt-out needs a marker of its own. if effective_collapse then table.insert(block.classes, 'cw-collapse-' .. effective_collapse) - elseif block_decided then + elseif block_decided and CONFIG.collapse then table.insert(block.classes, 'cw-collapse-none') end if overrides.lines_label then diff --git a/tests/run.sh b/tests/run.sh index eddea8c..7b060b5 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -299,13 +299,12 @@ else fi # The document setting still reaches the page, which is what the opt-out has -# to override, and the script has to know the marker to honour it. -if grep -q 'DEFAULT_COLLAPSE="closed"' "${work_dir}/collapse-block-off.html" && - grep -q 'cw-collapse-(open|closed|none)' "${work_dir}/collapse-block-off.html"; then - report pass "collapse-block-off: the script reads the opt-out marker" +# to override. +if grep -q 'DEFAULT_COLLAPSE="closed"' "${work_dir}/collapse-block-off.html"; then + report pass "collapse-block-off: the document setting reaches the page" else - report fail "collapse-block-off: the script reads the opt-out marker" \ - 'DEFAULT_COLLAPSE="closed" and a cw-collapse-(open|closed|none) match in the injected script' + report fail "collapse-block-off: the document setting reaches the page" \ + 'DEFAULT_COLLAPSE="closed" in collapse-block-off.html' fi # ============================================================================