Skip to content

Commit 817998e

Browse files
authored
feat: make release notes insert parts from markdown (#599)
Previously, we turned all headers into emphasized text regardless of level. With this change, we insert nested parts into the current verso document corresponding to the markdown structure. Resolves #542.
1 parent 7cd9b4f commit 817998e

File tree

3 files changed

+44
-22
lines changed

3 files changed

+44
-22
lines changed

.vale/scripts/rewrite_html.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@
77

88
def process_html_file(filepath, output_filepath):
99
"""Reads an HTML file, removes 'QA' from headers, and writes the result to the output path."""
10+
11+
# We exclude release notes. Before
12+
# https://github.com/leanprover/reference-manual/pull/599 we generated one
13+
# block for each release notes document which had class="no-vale" on it.
14+
# However, it's currently not easy to add any attributes to verso parts,
15+
# which https://github.com/leanprover/reference-manual/pull/599 adds, hence
16+
# the current workaround here.
17+
#
18+
# Reconsider this if https://github.com/leanprover/verso/issues/561 is resolved.
19+
if "/releases/" in filepath:
20+
return
21+
1022
with open(filepath, 'r', encoding='utf-8') as file:
1123
soup = BeautifulSoup(file, 'html.parser')
1224

Manual/Meta/ErrorExplanation.lean

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ structure ExplanElabM.State where
292292
/-- The index of the next block in the context's `blocks` to elaborate. -/
293293
blockIdx : Nat := 0
294294
/-- Active Markdown header levels that can be closed by subsequent Markdown -/
295-
levels : HeaderMapping := []
295+
levels : Markdown.HeaderMapping := default
296296
/-- The index of the current code block within this explanation. -/
297297
codeBlockIdx : Nat := 0
298298

@@ -362,7 +362,7 @@ def addPartFromExplanationMarkdown (b : MD4Lean.Block) : ExplanElabM Unit := do
362362
let keywords := tactics.map (·.userName)
363363
let ref ← getRef
364364
let {name, severity .. } ← read
365-
let ls ← addPartFromMarkdown b
365+
let ls ← addPartFromMarkdown b ((← getThe ExplanElabM.State).levels)
366366
(handleHeaders := Markdown.strongEmphHeaders)
367367
(elabInlineCode := some (tryElabInlineCodeStrictRestoringState tactics keywords))
368368
(elabBlockCode := some fun i l s => withRef ref <|
@@ -438,14 +438,6 @@ private def titleOfCodeBlock? (b : MD4Lean.Block) : Option String := do
438438
let info ← infoOfCodeBlock b |>.toOption
439439
info.title?
440440

441-
/-- Closes the last-opened section, throwing an error on failure. -/
442-
def closeEnclosingSection : PartElabM Unit := do
443-
-- We use `default` as the source position because the Markdown doesn't have one
444-
if let some ctxt' := (← getThe PartElabM.State).partContext.close default then
445-
modifyThe PartElabM.State fun st => {st with partContext := ctxt'}
446-
else
447-
throwError m!"Failed to close the last-opened explanation part"
448-
449441
/-- Adds explanation blocks until the "Examples" header is reached. -/
450442
def addNonExampleBlocks : ExplanElabM Unit := do
451443
repeat
@@ -636,8 +628,7 @@ def addExplanationBlocksFor (name : Name) : PartElabM Unit := do
636628
| throwErrorAt (← getRef) "Failed to parse docstring as Markdown"
637629
addExplanationMetadata explan.metadata
638630
let (_, { levels, .. }) ← addExplanationBodyBlocks.run name explan.metadata.severity ast.blocks
639-
for _ in levels do
640-
closeEnclosingSection
631+
closeEnclosingSections levels
641632
catch
642633
| .error ref msg => throw <| .error ref m!"Failed to process explanation for {name}: {msg}"
643634
| e => throw e

Manual/Meta/Markdown.lean

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Author: Joachim Breitner
66

77
import VersoManual
88
import Manual.Meta.Figure
9-
import Lean.Elab.InfoTree.Types
9+
import Lean.Elab.InfoTree
1010

1111
open Verso Doc Elab
1212
open Verso.Genre Manual
@@ -28,12 +28,31 @@ def Block.noVale.descr : BlockDescr where
2828
some <| fun _ goB _ _ content => do
2929
pure {{<div class="no-vale">{{← content.mapM goB}}</div>}}
3030

31-
@[code_block_expander markdown]
32-
def markdown : CodeBlockExpander
33-
| _args, str => do
34-
let str ← parserInputString str
35-
let some ast := MD4Lean.parse str
36-
| throwError "Failed to parse docstring as Markdown"
37-
let content ← ast.blocks.mapM <|
38-
Markdown.blockFromMarkdown (handleHeaders := Markdown.strongEmphHeaders)
39-
pure #[← ``(Block.other Block.noVale #[$content,*])]
31+
/-- Closes the last-opened section, throwing an error on failure. -/
32+
def closeEnclosingSection : PartElabM Unit := do
33+
-- We use `default` as the source position because the Markdown doesn't have one
34+
if let some ctxt' := (← getThe PartElabM.State).partContext.close default then
35+
modifyThe PartElabM.State fun st => {st with partContext := ctxt'}
36+
else
37+
throwError m!"Failed to close the last-opened explanation part"
38+
39+
/-- Closes as many sections as were created by markdown processing. -/
40+
def closeEnclosingSections (headerMapping : Markdown.HeaderMapping) : PartElabM Unit := do
41+
for _ in headerMapping do
42+
closeEnclosingSection
43+
44+
@[part_command Lean.Doc.Syntax.codeblock]
45+
def markdown : PartCommand
46+
| `(Lean.Doc.Syntax.codeblock| ``` $markdown:ident $args*| $txt ``` ) => do
47+
let x ← Lean.Elab.realizeGlobalConstNoOverloadWithInfo markdown
48+
if x != by exact decl_name% then Elab.throwUnsupportedSyntax
49+
for arg in args do
50+
let h ← MessageData.hint m!"Remove it" #[""] (ref? := arg)
51+
logErrorAt arg m!"No arguments expected{h}"
52+
let some ast := MD4Lean.parse txt.getString
53+
| throwError "Failed to parse body of markdown code block"
54+
let mut currentHeaderLevels : Markdown.HeaderMapping := default
55+
for block in ast.blocks do
56+
currentHeaderLevels ← Markdown.addPartFromMarkdown block currentHeaderLevels
57+
closeEnclosingSections currentHeaderLevels
58+
| _ => Elab.throwUnsupportedSyntax

0 commit comments

Comments
 (0)