-
Notifications
You must be signed in to change notification settings - Fork 437
/
Attr.lean
150 lines (130 loc) · 6.45 KB
/
Attr.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/-
Copyright (c) 2023 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/
prelude
import Lean.Server.CodeActions.Basic
/-!
# Initial setup for code action attributes
* Attribute `@[hole_code_action]` collects code actions which will be called
on each occurrence of a hole (`_`, `?_` or `sorry`).
* Attribute `@[tactic_code_action]` collects code actions which will be called
on each occurrence of a tactic.
* Attribute `@[command_code_action]` collects code actions which will be called
on each occurrence of a command.
-/
namespace Lean.CodeAction
open Lean Elab Server Lsp RequestM Snapshots
/-- A hole code action extension. -/
abbrev HoleCodeAction :=
CodeActionParams → Snapshot →
(ctx : ContextInfo) → (hole : TermInfo) → RequestM (Array LazyCodeAction)
/-- Read a hole code action from a declaration of the right type. -/
def mkHoleCodeAction (n : Name) : ImportM HoleCodeAction := do
let { env, opts, .. } ← read
IO.ofExcept <| unsafe env.evalConstCheck HoleCodeAction opts ``HoleCodeAction n
/-- An extension which collects all the hole code actions. -/
builtin_initialize holeCodeActionExt :
PersistentEnvExtension Name (Name × HoleCodeAction) (Array Name × Array HoleCodeAction) ←
registerPersistentEnvExtension {
mkInitial := pure (#[], #[])
addImportedFn := fun as => return (#[], ← as.foldlM (init := #[]) fun m as =>
as.foldlM (init := m) fun m a => return m.push (← mkHoleCodeAction a))
addEntryFn := fun (s₁, s₂) (n₁, n₂) => (s₁.push n₁, s₂.push n₂)
exportEntriesFn := (·.1)
}
builtin_initialize
registerBuiltinAttribute {
name := `hole_code_action
descr := "Declare a new hole code action, to appear in the code actions on ?_ and _"
applicationTime := .afterCompilation
add := fun decl stx kind => do
Attribute.Builtin.ensureNoArgs stx
unless kind == AttributeKind.global do
throwError "invalid attribute 'hole_code_action', must be global"
if (IR.getSorryDep (← getEnv) decl).isSome then return -- ignore in progress definitions
modifyEnv (holeCodeActionExt.addEntry · (decl, ← mkHoleCodeAction decl))
}
/-- A command code action extension. -/
abbrev CommandCodeAction :=
CodeActionParams → Snapshot → (ctx : ContextInfo) → (node : InfoTree) →
RequestM (Array LazyCodeAction)
/-- Read a command code action from a declaration of the right type. -/
def mkCommandCodeAction (n : Name) : ImportM CommandCodeAction := do
let { env, opts, .. } ← read
IO.ofExcept <| unsafe env.evalConstCheck CommandCodeAction opts ``CommandCodeAction n
/-- An entry in the command code actions extension, containing the attribute arguments. -/
structure CommandCodeActionEntry where
/-- The declaration to tag -/
declName : Name
/-- The command kinds that this extension supports.
If empty it is called on all command kinds. -/
cmdKinds : Array Name
deriving Inhabited
/-- The state of the command code actions extension. -/
structure CommandCodeActions where
/-- The list of command code actions to apply on any command. -/
onAnyCmd : Array CommandCodeAction := {}
/-- The list of command code actions to apply when a particular command kind is highlighted. -/
onCmd : NameMap (Array CommandCodeAction) := {}
deriving Inhabited
/-- Insert a command code action entry into the `CommandCodeActions` structure. -/
def CommandCodeActions.insert (self : CommandCodeActions)
(tacticKinds : Array Name) (action : CommandCodeAction) : CommandCodeActions :=
if tacticKinds.isEmpty then
{ self with onAnyCmd := self.onAnyCmd.push action }
else
{ self with onCmd := tacticKinds.foldl (init := self.onCmd) fun m a =>
m.insert a ((m.findD a #[]).push action) }
builtin_initialize builtinCmdCodeActions : IO.Ref CommandCodeActions ← IO.mkRef {}
def insertBuiltin (args : Array Name) (proc : CommandCodeAction) : IO Unit := do
builtinCmdCodeActions.modify fun self => self.insert args proc
/-- An extension which collects all the command code actions. -/
builtin_initialize cmdCodeActionExt :
PersistentEnvExtension CommandCodeActionEntry (CommandCodeActionEntry × CommandCodeAction)
(Array CommandCodeActionEntry × CommandCodeActions) ←
registerPersistentEnvExtension {
mkInitial := return (#[], ← builtinCmdCodeActions.get)
addImportedFn := fun as => do
let init ← builtinCmdCodeActions.get
return (#[], ← as.foldlM (init := init) fun m as =>
as.foldlM (init := m) fun m ⟨name, kinds⟩ =>
return m.insert kinds (← mkCommandCodeAction name))
addEntryFn := fun (s₁, s₂) (e, n₂) => (s₁.push e, s₂.insert e.cmdKinds n₂)
exportEntriesFn := (·.1)
}
builtin_initialize
registerBuiltinAttribute {
name := `command_code_action
descr := "Declare a new command code action, to appear in the code actions on commands"
applicationTime := .afterCompilation
add := fun decl stx kind => do
unless kind == AttributeKind.global do
throwError "invalid attribute 'command_code_action', must be global"
let `(attr| command_code_action $args*) := stx | return
let args ← args.mapM realizeGlobalConstNoOverloadWithInfo
if (IR.getSorryDep (← getEnv) decl).isSome then return -- ignore in progress definitions
modifyEnv (cmdCodeActionExt.addEntry · (⟨decl, args⟩, ← mkCommandCodeAction decl))
}
private def addBuiltin (declName : Name) (args : Array Name) : AttrM Unit := do
let go : MetaM Unit := do
let val := mkAppN (mkConst ``insertBuiltin) #[toExpr args, mkConst declName]
let initDeclName ← mkFreshUserName (declName ++ `declare)
declareBuiltin initDeclName val
go.run' {}
builtin_initialize
registerBuiltinAttribute {
ref := by exact decl_name%
name := `builtin_command_code_action
descr := "Declare a new builtin command code action, to appear in the code actions on commands"
applicationTime := .afterCompilation
add := fun decl stx kind => do
unless kind == AttributeKind.global do
throwError "invalid attribute 'command_code_action', must be global"
let `(attr| builtin_command_code_action $args*) := stx |
throwError "unexpected 'command_code_action' attribute syntax"
let args ← args.mapM realizeGlobalConstNoOverloadWithInfo
if (IR.getSorryDep (← getEnv) decl).isSome then return -- ignore in progress definitions
addBuiltin decl args
}