From e3588729615edfd73797a70fe5e28a6971ad0ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Thu, 12 Nov 2026 16:00:18 +0100 Subject: [PATCH 1/3] fix: leave Quarto's book title-block code block alone A book rendered to one file puts each chapter's front matter into a code block with the class quarto-title-block, which a Quarto filter later replaces with the chapter's title block. code-window wrapped it first, so an empty "quarto-title-block" window showed at the start of the chapter. --- CHANGELOG.md | 1 + _extensions/code-window/code-window.lua | 20 ++++++++++++++++++++ _extensions/code-window/main.lua | 2 +- tests/fixtures/book/_quarto.yml | 16 ++++++++++++++++ tests/fixtures/book/chapter.qmd | 9 +++++++++ tests/fixtures/book/index.qmd | 3 +++ tests/run.sh | 24 ++++++++++++++++++++++++ 7 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/book/_quarto.yml create mode 100644 tests/fixtures/book/chapter.qmd create mode 100644 tests/fixtures/book/index.qmd diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f49107..75cb08a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased - fix: The HTML dependency folder now uses the extension version, so browsers load the new files after an upgrade. (#88) +- fix: Leave alone the code block that Quarto adds for a chapter's front matter in a book rendered to one file, so no empty `quarto-title-block` window shows at the start of the chapter. ## 1.8.2 (2026-11-05) diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index 144c1f9..e5c322d 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -113,6 +113,17 @@ local function is_unnamed_cell_output(block) return cell_output.is_marked(block) and str.is_empty(block.attributes['filename']) end +--- Check whether a block is one that Quarto writes for itself and replaces +--- later. A book rendered to one file puts the front matter of each chapter +--- into a code block with the class "quarto-title-block". A filter of Quarto +--- finds that block by its class and puts the chapter's title block in its +--- place, so every pass of this extension leaves it alone. +--- @param block pandoc.CodeBlock Code block element +--- @return boolean +local function is_quarto_block(block) + return block.classes:includes('quarto-title-block') +end + -- ============================================================================ -- BLOCK-LEVEL STYLE OVERRIDE -- ============================================================================ @@ -970,6 +981,10 @@ end --- that rather than skipping validation for the same kind of block, so the --- same document reports the same finding in both formats. function CodeBlock(block) + if is_quarto_block(block) then + return nil + end + -- 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_plain_output = is_unnamed_cell_output(block) @@ -1056,6 +1071,10 @@ 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) + if is_quarto_block(block) then + return { block }, false, nil + end + -- Check this block's own attributes against the CodeBlock group of the -- schema before anything below reads or rewrites them, in either branch. local resolved, auto_label = resolve_and_take(block) @@ -1383,4 +1402,5 @@ return { CodeBlock = CodeBlock, CONFIG = function() return CONFIG end, draws_chrome = draws_chrome, + is_quarto_block = is_quarto_block, } diff --git a/_extensions/code-window/main.lua b/_extensions/code-window/main.lua index 77cbe79..2f28d44 100644 --- a/_extensions/code-window/main.lua +++ b/_extensions/code-window/main.lua @@ -87,7 +87,7 @@ end --- @param block pandoc.CodeBlock --- @return pandoc.CodeBlock|nil Relabelled block, or nil when the pass is skipped local function normalise_language(block) - if not code_window.draws_chrome() then + if not code_window.draws_chrome() or code_window.is_quarto_block(block) then return nil end if not code_window.CONFIG().auto_filename then diff --git a/tests/fixtures/book/_quarto.yml b/tests/fixtures/book/_quarto.yml new file mode 100644 index 0000000..5536410 --- /dev/null +++ b/tests/fixtures/book/_quarto.yml @@ -0,0 +1,16 @@ +project: + type: book + +book: + title: "Book title block" + author: "Code Window" + chapters: + - index.qmd + - chapter.qmd + +filters: + - code-window + +format: + typst: + keep-typ: true diff --git a/tests/fixtures/book/chapter.qmd b/tests/fixtures/book/chapter.qmd new file mode 100644 index 0000000..647a690 --- /dev/null +++ b/tests/fixtures/book/chapter.qmd @@ -0,0 +1,9 @@ +--- +title: "Chapter with front matter" +--- + +Quarto puts this front matter into a code block of its own, which code-window must leave alone. + +```r +x <- 1 +``` diff --git a/tests/fixtures/book/index.qmd b/tests/fixtures/book/index.qmd new file mode 100644 index 0000000..10cadce --- /dev/null +++ b/tests/fixtures/book/index.qmd @@ -0,0 +1,3 @@ +# Preface {.unnumbered} + +A chapter with no front matter of its own. diff --git a/tests/run.sh b/tests/run.sh index d6d17ed..5d43145 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -538,6 +538,30 @@ else "four windows, two of them named bash, in language-not-first.typ" fi +# ============================================================================ +# Quarto's own code blocks are left alone +# ============================================================================ + +# A book rendered to one file puts the front matter of each chapter into a +# code block with the class quarto-title-block. Quarto replaces that block with +# the chapter's title block later, so it gets no window. +book_dir="${work_dir}/book" +cp -R "${tests_dir}/fixtures/book" "${book_dir}" +cp -R "${repo_dir}/_extensions" "${book_dir}/_extensions" +if ! quarto render "${book_dir}" --to typst --quiet >"${work_dir}/book.log" 2>&1; then + printf 'FAIL book: the render failed\n' + tail -n 20 "${work_dir}/book.log" + exit 1 +fi +book_typ="${book_dir}/index.typ" +if [ "$(count_typst_windows "${book_typ}")" -eq 1 ] && + ! grep -q 'quarto-title-block' "${book_typ}"; then + report pass "book: the chapter title block gets no window" +else + report fail "book: the chapter title block gets no window" \ + "one window, for the r block, and no quarto-title-block in index.typ" +fi + # ============================================================================ printf '\n%s passed, %s failed\n' "${passed}" "${failed}" From e183430e79342dd438b7d5f2c9cf3a44f63614dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Thu, 12 Nov 2026 16:03:03 +0100 Subject: [PATCH 2/3] test: render the book fixture through render() --- _extensions/code-window/code-window.lua | 7 ++----- tests/run.sh | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index e5c322d..90bdc65 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -113,11 +113,8 @@ local function is_unnamed_cell_output(block) return cell_output.is_marked(block) and str.is_empty(block.attributes['filename']) end ---- Check whether a block is one that Quarto writes for itself and replaces ---- later. A book rendered to one file puts the front matter of each chapter ---- into a code block with the class "quarto-title-block". A filter of Quarto ---- finds that block by its class and puts the chapter's title block in its ---- place, so every pass of this extension leaves it alone. +--- Check whether a block holds a chapter's front matter, which Quarto writes +--- in a book rendered to one file and later replaces with the title block. --- @param block pandoc.CodeBlock Code block element --- @return boolean local function is_quarto_block(block) diff --git a/tests/run.sh b/tests/run.sh index 5d43145..91dd4ae 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -38,10 +38,15 @@ report() { fi } -# Render a fixture, and stop the run when the render itself fails. +# Render a fixture, and stop the run when the render itself fails. A fixture +# is a file, or a directory that holds a project. # $1 fixture base name. $2 target format. render() { - if ! quarto render "${work_dir}/$1.qmd" --to "$2" --quiet >"${work_dir}/$1.log" 2>&1; then + local target="${work_dir}/$1.qmd" + if [ -d "${work_dir}/$1" ]; then + target="${work_dir}/$1" + fi + if ! quarto render "${target}" --to "$2" --quiet >"${work_dir}/$1.log" 2>&1; then printf 'FAIL %s: the render failed\n' "$1" tail -n 20 "${work_dir}/$1.log" exit 1 @@ -542,17 +547,11 @@ fi # Quarto's own code blocks are left alone # ============================================================================ -# A book rendered to one file puts the front matter of each chapter into a -# code block with the class quarto-title-block. Quarto replaces that block with -# the chapter's title block later, so it gets no window. +# The front matter of a chapter becomes a quarto-title-block code block. book_dir="${work_dir}/book" cp -R "${tests_dir}/fixtures/book" "${book_dir}" -cp -R "${repo_dir}/_extensions" "${book_dir}/_extensions" -if ! quarto render "${book_dir}" --to typst --quiet >"${work_dir}/book.log" 2>&1; then - printf 'FAIL book: the render failed\n' - tail -n 20 "${work_dir}/book.log" - exit 1 -fi +cp -R "${work_dir}/_extensions" "${book_dir}/_extensions" +render book typst book_typ="${book_dir}/index.typ" if [ "$(count_typst_windows "${book_typ}")" -eq 1 ] && ! grep -q 'quarto-title-block' "${book_typ}"; then From 2750c86fa50bf39ea8b22a45a121414e885dbaaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Thu, 12 Nov 2026 16:06:16 +0100 Subject: [PATCH 3/3] docs: add pull request reference to changelog [skip ci] --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75cb08a..65aa0c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Unreleased - fix: The HTML dependency folder now uses the extension version, so browsers load the new files after an upgrade. (#88) -- fix: Leave alone the code block that Quarto adds for a chapter's front matter in a book rendered to one file, so no empty `quarto-title-block` window shows at the start of the chapter. +- fix: Leave alone the code block that Quarto adds for a chapter's front matter in a book rendered to one file, so no empty `quarto-title-block` window shows at the start of the chapter. (#89) ## 1.8.2 (2026-11-05)