From a85ead109f43cbe2458308590e2f284c08de4dea Mon Sep 17 00:00:00 2001 From: Gordon Woodhull Date: Thu, 3 Sep 2026 18:01:42 -0400 Subject: [PATCH] Parse markdown adjacent to a raw HTML block line (bd-block-html-adjacent-markdown-unparsed-0qnjuwuy) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 0.29.0 a line of prose immediately after a raw HTML block line was emitted verbatim — backticks, asterisks and every other inline construct survived into the page as literal text:
Example custom instructions This example demonstrates how a `quarto.instructions.md` file shapes … Quarto 1 parses that, as does pandoc 3.8.1, and so did q2 0.28.0. A blank line was where the parser recovered, so to an author it read like a content typo rather than an engine bug. The lift added in bd-block-html-wrapped-in-p-w8qebxig turned a paragraph opening with a block-level HTML tag into a `RawBlock` by re-reading its source text verbatim. The extent was right — a paragraph and a CommonMark type-6 HTML block both run to the next blank line — but re-reading the source also switched off inline parsing inside it. That conflated two pandoc extensions: dropping `native_divs` costs the `

` wrapper and the `Div` node, which was intended; dropping `markdown_in_html_blocks` costs inline parsing, which was not. Measured on a tight `

`, q2's output was byte-identical to `pandoc -f markdown-native_divs-markdown_in_html_blocks`, and its AST was one verbatim `RawBlock` where `-native_divs` alone gives `RawBlock`/`Plain`/ `RawBlock`. `process_paragraph` already held the fully-parsed inlines and discarded them. It now partitions that vector instead: runs of block-level raw HTML coalesce into a `RawBlock`, the text between them becomes a `Plain`, and the parts are returned as `IntermediateSection`, which every block container already splices. Each inline is classified on its own — no tag matching, no lookahead — so this stays inside the no-backtracking constraint in `dev-docs/syntax-notes.md`. Two details earn their comments: the tag test runs on trimmed text, because tree-sitter folds preceding whitespace into a non-first `RawInline`; and each part gets its own span, since cloning the paragraph's onto all of them gives siblings overlapping ranges and misleads the incremental writer. `
`, `\n";
+    let out = roundtrip(src);
+    let reparsed = blocks(&out);
+
+    let script = reparsed
+        .iter()
+        .find_map(|b| match b {
+            Block::RawBlock(r) if r.text.contains("script") => Some(r),
+            _ => None,
+        })
+        .unwrap_or_else(|| {
+            panic!(
+                "expected a