feat: add MessageData.withExprHover (#13763)

This PR adds `MessageData.withExprHover`, for creating messages that
show information about an expression when hovered over. A
`withExprHoverM` variant captures the current local context.
This commit is contained in:
Kyle Miller 2026-05-17 06:39:49 -07:00 committed by GitHub
parent 43ef70db63
commit ce5814043b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 42 additions and 11 deletions

View file

@ -90,17 +90,7 @@ private def showParserName [Monad m] [MonadEnv m] (firsts : NameMap String) (n :
env.constants.find?' n |>.map (·.levelParams.map Level.param) |>.getD []
let tok := ((← customTacticName n) <|> firsts.get? n).map Std.Format.text |>.getD (format n)
pure <| .ofFormatWithInfos {
fmt := "`" ++ .tag 0 tok ++ "`",
infos :=
.ofList [(0, .ofTermInfo {
lctx := .empty,
expr := .const n params,
stx := .ident .none (toString n).toRawSubstring n [.decl n []],
elaborator := `Delab,
expectedType? := none
})] _
}
pure m!"`{.withExprHover tok (.const n params) {}}`"
/--
Displays all available tactic tags, with documentation.

View file

@ -275,6 +275,47 @@ def ofConstName (constName : Name) (fullNames : Bool := false) : MessageData :=
return Dynamic.mk msg)
(fun _ => false)
/--
Creates message data wrapping `fmt` that gives information about `expr` when hovered over.
Options:
- `location?` overrides what "go to definition" does
- `docString?` allows overriding the docstring for the expression
- `mkDocString?` allows generating a dynamic docstring; if this is provided, `docString?` is ignored
- `explicit` makes the hover pretty print the head application in explicit mode;
the default value is `false` (note: delaboration expression hovers normally set this to `true`,
since their purpose is to get more information about a given expression)
-/
def withExprHover (fmt : Format) (expr : Expr) (lctx : LocalContext)
(location? : Option DeclarationLocation := none)
(docString? : Option String := none)
(mkDocString? : Option (PPContext → IO String) := none)
(explicit : Bool := false) : MessageData :=
.ofFormatWithInfos {
fmt := .tag 0 fmt
infos :=
.ofList [(0, Elab.Info.ofDelabTermInfo {
expr, lctx, location?, explicit,
stx := .missing, -- unused for delaborator hovers
expectedType? := none, -- unused for delaborator hovers
elaborator := `Delab.withExprHover,
mkDocString? := mkDocString? <|> docString?.map (fun _ => pure ·)
})]
}
/--
Calls `withExprHover`, but uses the current local context if one is not given.
See `withExprHover` for a description of each parameter.
-/
def withExprHoverM {m} [Monad m] [MonadLCtx m]
(fmt : Format) (expr : Expr) (lctx? : Option LocalContext := none)
(location? : Option DeclarationLocation := none)
(docString? : Option String := none)
(mkDocString? : Option (PPContext → IO String) := none)
(explicit : Bool := false) : m MessageData := do
let lctx ← lctx?.getDM getLCtx
return withExprHover fmt expr lctx location? docString? mkDocString? explicit
partial def hasSyntheticSorry (msg : MessageData) : Bool :=
visit none msg
where