Skip to content

✨ NEW: Add section reference plugin (section_ref)#144

Open
chrisjsewell wants to merge 4 commits into
masterfrom
claude/mdit-section-reference-plugin-yfvmtz
Open

✨ NEW: Add section reference plugin (section_ref)#144
chrisjsewell wants to merge 4 commits into
masterfrom
claude/mdit-section-reference-plugin-yfvmtz

Conversation

@chrisjsewell

@chrisjsewell chrisjsewell commented Jul 16, 2026

Copy link
Copy Markdown
Member

What

Adds a new section_ref inline plugin that captures section-sign references — §1, §1.1, §2.3.4 — the syntax LLMs commonly use to refer to numbered headings in documents.

See §1, §1.1 and §2.3.4 for details.

Each reference becomes a dedicated section_ref token:

  • content: the matched text (e.g. "§1.1")
  • markup: "§"
  • meta["numbers"]: the parsed section number as a list of ints (e.g. [1, 1]), so consumers don't re-parse the dotted string (a list rather than a tuple so Token.as_dict()/JSON round-trips are type-stable; leading zeros are normalized, with the original text preserved in content)

so downstream renderers (notably MyST-Parser) can resolve them to heading cross-references. The default rendering is a neutral <span class="section-ref">§1.1</span>, overridable via md.add_render_rule("section_ref", ...).

Initial use case

executablebooks/MyST-Parser#1170 (draft) consumes this plugin as a new section_ref MyST extension, resolving the references to internal links targeting the correspondingly numbered heading of the document. That PR is blocked on this one being merged and released (it needs mdit-py-plugins >= 0.7).

Matching rules

  • § must be immediately followed by ASCII digits ([0-9], never unicode digits), optionally in further dot-separated groups — § 1 and bare § stay literal text
  • trailing punctuation is not consumed: see §1. captures §1
  • a directly-following ASCII letter rejects the match (§1a, §1.2b), while non-ASCII letters do not block it (见§3章 captures §3)
  • standard CommonMark backslash-escaping applies: \§1 stays literal
  • inline code, code fences, autolinked URLs, and link destinations/titles are unaffected

Implementation notes

§ is not one of markdown-it's default text-rule terminator characters, so a plain inline rule would never fire mid-paragraph. The plugin therefore uses md.inline.add_terminator_char("§"), the same mechanism as the gfm_autolink plugin, and raises a RuntimeError on markdown-it-py < 4.1.0 (package dependency range unchanged).

Testing

  • 24 new tests: token-contract test, version-guard test, and 22 rendering fixtures (tests/fixtures/section_ref.md) covering emphasis/link/code/heading contexts, boundary and escaping edge cases
  • full suite passes (507 tests); ruff + mypy --strict clean under both markdown-it-py 3.x and 4.x
  • adversarially probed against a MyST-style plugin stack (attrs, myst_role, dollarmath, gfm_autolink, footnote, deflist, anchors), GFM autolink URLs containing §, link-label posMax slices, the typographer, and cross-instance state leakage

🤖 Generated with Claude Code

https://claude.ai/code/session_01LwRkZLzpbHdb3pgmctmn6H

Captures section-sign references such as §1, §1.1 and §2.3.4 — the
syntax LLMs commonly use to refer to numbered headings — into dedicated
`section_ref` inline tokens (meta["number"] holds the number string),
so downstream renderers such as MyST-Parser can resolve them to heading
cross-references. Default rendering is a `<span class="section-ref">`.

Uses `md.inline.add_terminator_char("§")` (markdown-it-py >= 4.1.0),
since § is not a default text-rule terminator character.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwRkZLzpbHdb3pgmctmn6H
@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.79%. Comparing base (d11bdaf) to head (6a4040d).
⚠️ Report is 14 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #144      +/-   ##
==========================================
- Coverage   92.80%   92.79%   -0.02%     
==========================================
  Files          31       40       +9     
  Lines        1835     2289     +454     
==========================================
+ Hits         1703     2124     +421     
- Misses        132      165      +33     
Flag Coverage Δ
pytests 92.79% <100.00%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

claude added 3 commits July 16, 2026 09:48
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwRkZLzpbHdb3pgmctmn6H
meta["numbers"] now holds e.g. [1, 1] for §1.1, so downstream renderers
do not need to re-parse the dotted number string. A list (not tuple) is
used so Token.as_dict()/JSON round-trips are type-stable. The original
matched text remains available in token.content.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwRkZLzpbHdb3pgmctmn6H
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