diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f49107..65aa0c5 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. (#89) ## 1.8.2 (2026-11-05) diff --git a/_extensions/code-window/code-window.lua b/_extensions/code-window/code-window.lua index 144c1f9..90bdc65 100644 --- a/_extensions/code-window/code-window.lua +++ b/_extensions/code-window/code-window.lua @@ -113,6 +113,14 @@ 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 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) + return block.classes:includes('quarto-title-block') +end + -- ============================================================================ -- BLOCK-LEVEL STYLE OVERRIDE -- ============================================================================ @@ -970,6 +978,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 +1068,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 +1399,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..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 @@ -538,6 +543,24 @@ else "four windows, two of them named bash, in language-not-first.typ" fi +# ============================================================================ +# Quarto's own code blocks are left alone +# ============================================================================ + +# 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 "${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 + 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}"