Repository navigation
fix(ai-toc): include setext headings in the generated table of contents - #393
Merged
petertzy merged 3 commits intoOct 8, 2026
Merged
Conversation
_generate_markdown_toc only recognised ATX ("# Heading") lines, so a
document written with setext headings produced an empty
"## Table of Contents" even though the preview renderer anchors those
headings as h1/h2. The outline endpoint (backend/routers/markdown.py)
already treats setext headings as real headings, and heading_anchor.py
exists precisely so the two callers cannot diverge.
Teach the TOC generator to recognise a text line followed by a run of
"=" (level 1) or two or more "-" (level 2), matching the renderer:
backtick/tilde fences are skipped, a blank line before the underline
makes it a thematic break, and ATX/underline lines never double as
setext text. Duplicate slugs are still disambiguated GitHub-style.
Owner
|
Approved — this is a necessary correctness fix. The AI-generated table of contents now includes Setext headings with the correct levels, source order, and duplicate-anchor handling, so generated links match the document heading structure. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The AI table-of-contents generator (
_generate_markdown_tocinbackend/ai_logic.py, used by/toc) only recognizes ATX (# Heading) headings. For a document written with CommonMark setext headings it returns an empty string, so/tocproduces no table of contents at all — yet the preview renderer anchors those same headings (<h1 id="title">,<h2 id="sub">).backend/heading_anchor.pyexists precisely so the outline and the TOC “never diverge again”; this path was still diverging.Before:
_generate_markdown_toc(...)returned"".After: it returns
- [Title](#title)and- [Sub](#sub), matching the renderer’s anchors.Change
_iter_toc_headings(), a fence-aware scanner that yields(level, title)for both ATX and setext headings — a text line over=is level 1, over two or more-is level 2 (a single-is a list item, not a heading). This mirrors the renderer, so every emitted anchor resolves._generate_markdown_toc()now consumes it, keeping source order and the existing GitHub-style duplicate-anchor suffixes (-1,-2, …).Tests
Added to
tests/test_markdown_toc.py: setext inclusion and levels, source-order mixing with ATX, duplicate setext anchors, the two-dash boundary, the blank-line-is-a-thematic-break case, and setext-looking text inside a code fence. Mutation-tested the new suite (2-dash bound, level swap, fence skip, dedup). Full backend suite: 478 passed;ruff checkandruff format --checkclean.