Skip to content

fix(markdown): exclude headings inside block quotes from the outline - #527

Open
Booyaka101 wants to merge 1 commit into
stevearc:masterfrom
Booyaka101:fix-markdown-blockquote-headings
Open

fix(markdown): exclude headings inside block quotes from the outline#527
Booyaka101 wants to merge 1 commit into
stevearc:masterfrom
Booyaka101:fix-markdown-blockquote-headings

Conversation

@Booyaka101

Copy link
Copy Markdown
Contributor

Closes #526.

Markdown headings written inside a block quote show up in the outline:

# h1

> ## h2 nested

## h2 real

> ## h2 nested is quoted content, but the markdown grammar still parses it as an atx_heading (nested under a block_quote), so queries/markdown/aerial.scm captures it and it lands in the outline alongside the real headings.

The fix

Add (#not-has-ancestor? @level block_quote) to both the atx_heading and setext_heading patterns, so a heading anywhere inside a block quote is skipped.

I did this at the query layer rather than filtering in M.markdown.postprocess on purpose: get_parent runs (and mutates the heading stack) before postprocess gets a chance to drop the item, so dropping there leaves the popped parent behind and real headings around a block quote stop nesting correctly. Excluding at the query layer keeps the stack intact — # Top / > # quoted / ## Sub still produces Top > Sub.

has-ancestor? and the not- predicate negation are both in core since Neovim 0.11 (aerial's minimum), so this needs no new dependency.

Tests

Added a block-quoted section (plus a following # Title 8) to tests/treesitter/markdown_test.md and refreshed the snapshots. The quoted headings are absent and Title 8 confirms parsing recovers after the quote. Reverting the query change makes the treesitter snapshot fail, so the fixture guards the regression.

Headings written inside a block quote (e.g. `> ## Heading`) parse as
atx_heading/setext_heading nodes and were added to the outline, even though
they are quoted content rather than document structure.

Constrain both heading patterns in queries/markdown/aerial.scm with
`(#not-has-ancestor? @Level block_quote)`, so quoted headings are skipped at
the query layer. Filtering here rather than in postprocess keeps the parent
stack intact, so real headings surrounding a block quote still nest correctly.
`has-ancestor?` and the `not-` negation are both available in Neovim 0.11+.

Adds a block-quoted section to the markdown treesitter fixture as a regression
test.

Closes stevearc#526
@github-actions
github-actions Bot requested a review from stevearc June 7, 2026 03:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: in markdown files, quoted headings are part of the outline

1 participant