Skip to content

fix(markdown): include setext headings in the document outline - #391

Merged
petertzy merged 3 commits into
petertzy:mainfrom
harsh-thakkar7:fix/outline-misses-setext-headings
Oct 8, 2026
Merged

petertzy merged 3 commits into
petertzy:mainfrom
harsh-thakkar7:fix/outline-misses-setext-headings

Conversation

@harsh-thakkar7

Copy link
Copy Markdown
Contributor

What

The /api/markdown/outline endpoint only scanned ATX (#) headings, but the preview renderer also anchors CommonMark setext headings:

  • Title + ===== → <h1 id="title">
  • Sub + ----- → <h2 id="sub">

So whole sections were visible and linkable in the preview yet silently missing from the outline panel and its table of contents.

Fix

Add a fence-aware setext scan in the outline extractor that mirrors the renderer exactly: = underlines become level 1, two-or-more - underlines become level 2, blank-line-separated underlines stay thematic breaks, backtick fences are skipped, and an ATX heading line never double-counts. Both heading kinds are merged in source order.

Tests

  • tests/test_markdown_outline.py: setext level-1/2 nodes with correct anchors and line numbers, outline anchors == rendered anchor ids, plus thematic-break and fenced-code exclusions.
  • Full backend suite passes (474 tests). Ruff clean.

harsh-thakkar7 and others added 3 commits October 8, 2026 16:26
The outline endpoint only scanned ATX (#) headings, so sections written as
'Title' + '====' underlines were anchored by the preview but missing from
the outline and its table of contents. Scan for CommonMark setext
underlines too (matching the renderer: '=' -> h1, two or more '-' -> h2,
backtick fences skipped) and merge both heading kinds in source order.
@petertzy

petertzy commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Approved — this is a necessary correctness fix. The outline now includes CommonMark Setext headings in source order and produces the same anchors as the preview renderer, while preserving exclusions for thematic breaks and fenced code.
I also fixed the fence scanner so a backtick line with an info string does not incorrectly close an existing code fence and expose code content as a heading. Markdown outline tests, the full backend suite (480 passed), frontend tests (94/94), Ruff, ESLint, and TypeScript checks all pass.

@petertzy
petertzy merged commit 55217d8 into petertzy:main Oct 8, 2026
2 checks passed
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.

2 participants