@@ -43,6 +43,46 @@ def testAddPartFromMarkdown (input : String) : Elab.TermElabM String := do
4343 let (_, _, part) ← addParts.run ⟨Syntax.node .none identKind #[], mkConst ``Manual, .always, .none⟩ default default
4444 part.partContext.priorParts.toList.map displayPartStructure |> String.join |> pure
4545
46+ /--
47+ Every part produced from Markdown headers must have range and selection syntax whose recovered
48+ ranges satisfy the TOC invariant: the selection range lies within `[rangeStart, endPos]`. Violating
49+ it (position-less syntax, or an `endPos` of zero) panics in `requireValidTOCRanges` during the
50+ document-symbol/folding conversion.
51+ -/
52+ partial def partRangesValid : FinishedPart → Bool
53+ | .mk rangeStx selectionStx _ _ _ _ subParts endPos =>
54+ match rangeStx.getRange?, selectionStx.getRange? with
55+ | some r, some sel => (r.start ≤ sel.start) && (sel.stop ≤ endPos) && subParts.all partRangesValid
56+ | _, _ => false
57+ | .included _ => true
58+
59+ open PartElabM in
60+ /--
61+ Parses Markdown under a positioned reference and closes the document at that reference's end, as a
62+ real document's Markdown block elaborator would, then reports whether every resulting part has a
63+ valid TOC range.
64+ -/
65+ def markdownPartRangesValid (input : String) : Elab.TermElabM Bool := do
66+ let some parsed := MD4Lean.parse input
67+ | throwError m! "Couldn't parse markdown { input} "
68+ let ref := Syntax.node (.synthetic ⟨0 ⟩ ⟨100 ⟩) identKind #[]
69+ withRef ref do
70+ let addParts : PartElabM Unit := do
71+ let mut levels := []
72+ for block in parsed.blocks do
73+ levels ← addPartFromMarkdown block levels
74+ closePartsUntil 0 (ref.getTailPos?.getD default)
75+ let (_, _, part) ← addParts.run ⟨Syntax.node .none identKind #[], mkConst ``Manual, .always, .none⟩ default default
76+ return part.partContext.priorParts.all partRangesValid
77+
78+ /-- info: true -/
79+ #guard_msgs in
80+ #eval markdownPartRangesValid r#"
81+ # Acknowledgements
82+ ## Contributors
83+ # Another Section
84+ " #
85+
4686/--
4787info:
4888# header1
0 commit comments