diff --git a/src/tests/VersoTests/LiterateHtml.lean b/src/tests/VersoTests/LiterateHtml.lean
index 2bfbd9295..2b9fab539 100644
--- a/src/tests/VersoTests/LiterateHtml.lean
+++ b/src/tests/VersoTests/LiterateHtml.lean
@@ -302,6 +302,22 @@ private def testUnknownExtensionFallback : Test := do
assertContains "THIS IS THE FALLBACK" html
"HTML missing 'THIS IS THE FALLBACK' marker. The conversion's fallback children were not rendered."
+/--
+The doc comment on a `#guard_msgs` command is not documentation. Instead, it is a specification of
+the expected messages from the wrapped command. It must not be attributed to the declaration in that
+command as a second docstring.
+-/
+private def testGuardMsgsDocstring (data : TestData) : IO Unit := withTestDir data fun jsonDir htmlDir _ _ => do
+ runLiterateHtml jsonDir htmlDir
+ let html ← IO.FS.readFile (htmlDir / "LitConfig" / "GuardMsgs" / "index.html")
+ let docstring := "A theorem whose proof is left open."
+ let occurrences := (html.splitOn docstring).length - 1
+ unless occurrences == 1 do
+ throw <| IO.userError s!"Expected the docstring of `guarded` once in the HTML, found it {occurrences} times. \
+ The expected-messages comment of `#guard_msgs` was attributed to `guarded` as a docstring."
+ unless hasSubstring html "declaration uses" do
+ throw <| IO.userError "The expected-messages comment of `#guard_msgs` is missing from the HTML."
+
/-- Excluded modules produce no HTML output and are absent from the navbar. -/
private def testExclude (data : TestData) : Test := withTestDir data fun jsonDir htmlDir planFile tomlFile => do
IO.FS.writeFile tomlFile "exclude = [\"LitConfig.NoDocstrings\"]\n"
@@ -1205,6 +1221,7 @@ private def htmlTests (data : TestData) (projectDir : System.FilePath) : List (S
("all built-in doc roles", testAllBuiltinDocRoles data),
("custom literate handlers", testCustomLiterateHandlers data),
("docstring code block messages", testDocstringCodeBlockMessages data),
+ ("guard_msgs docstring", testGuardMsgsDocstring data),
("unknown extension fallback", testUnknownExtensionFallback)
]
@@ -1212,7 +1229,7 @@ private def htmlTests (data : TestData) (projectDir : System.FilePath) : List (S
@[test]
def literateHtml : Test := do
let projectDir := "test-projects/literate-config"
- let modules := #["LitConfig", "LitConfig.Core", "LitConfig.Core.Basic", "LitConfig.NoDocstrings", "LitConfig.Builtins", "LitConfig.UserExt"]
+ let modules := #["LitConfig", "LitConfig.Core", "LitConfig.Core.Basic", "LitConfig.NoDocstrings", "LitConfig.Builtins", "LitConfig.UserExt", "LitConfig.GuardMsgs"]
-- First verify test project toolchain matches root toolchain
let rootToolchain := (← IO.FS.readFile "lean-toolchain").trimAscii
diff --git a/src/verso-literate/VersoLiterateMain.lean b/src/verso-literate/VersoLiterateMain.lean
index d5d3b7dcb..289005754 100644
--- a/src/verso-literate/VersoLiterateMain.lean
+++ b/src/verso-literate/VersoLiterateMain.lean
@@ -144,7 +144,12 @@ def findHighestM [Monad m] (stx : Syntax) (fn : Syntax → Option α) : m (Array
Finds the definition sites of each constant in an info tree, and replaces each docstring with a
reference to the definition for later substitution.
-/
-def findDocstringDefs (stx : Syntax) (t : InfoTree) : TermElabM Syntax := do
+partial def findDocstringDefs (stx : Syntax) (t : InfoTree) : TermElabM Syntax := do
+ -- `#guard_msgs` takes the messages it expects as a doc comment, but it's not really
+ -- documentation. It must not be attached to the declaration in the command that `#guard_msgs`
+ -- wraps.
+ if stx.isOfKind ``Lean.guardMsgsCmd then
+ return stx.setArg 4 (← findDocstringDefs stx[4] t)
-- Find the definition sites of all constants in this info tree
let defSites := t.deepestNodes fun _ i _ =>
match i with
diff --git a/test-projects/literate-config/LitConfig.lean b/test-projects/literate-config/LitConfig.lean
index 10705c9f2..819670f8f 100644
--- a/test-projects/literate-config/LitConfig.lean
+++ b/test-projects/literate-config/LitConfig.lean
@@ -3,6 +3,7 @@ import LitConfig.NoDocstrings
import LitConfig.Builtins
import LitConfig.UserExt
import LitConfig.Gallery
+import LitConfig.GuardMsgs
import Verso
/-!
diff --git a/test-projects/literate-config/LitConfig/GuardMsgs.lean b/test-projects/literate-config/LitConfig/GuardMsgs.lean
new file mode 100644
index 000000000..c1e408371
--- /dev/null
+++ b/test-projects/literate-config/LitConfig/GuardMsgs.lean
@@ -0,0 +1,11 @@
+/-!
+# Guarded Messages
+
+{lit}`#guard_msgs` takes the messages that it expects as a doc comment. That comment is not really
+documentation, so the declaration in the guarded command keeps its own docstring, and only that.
+-/
+
+/-- warning: declaration uses `sorry` -/
+#guard_msgs in
+/-- A theorem whose proof is left open. -/
+theorem guarded : 1 + 1 = 2 := sorry