Source file info.ml
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
module type Point = sig
type t
val in_range : ?loc:Loc.t -> t -> bool
val gt_range : ?loc:Loc.t -> t -> bool
type offset_table = string
val to_offset : t -> offset_table -> int
val to_string : t -> string
end
module LineCol : Point with type t = int * int = struct
type t = int * int
type offset_table = string
let line_length offset text =
match String.index_from_opt text offset '\n' with
| Some l -> l - offset
| None -> String.length text - offset
let rec to_offset cur lc (l, c) text =
Io.Log.trace "to_offset"
(Format.asprintf "cur: %d | lc: %d | l: %d c: %d" cur lc l c);
if lc = l then cur + c
else
let ll = line_length cur text + 1 in
to_offset (cur + ll) (lc + 1) (l, c) text
let to_offset (l, c) text = to_offset 0 0 (l, c) text
let to_string (l, c) = "(" ^ string_of_int l ^ "," ^ string_of_int c ^ ")"
let debug_in_range = false
let in_range ?loc (line, col) =
match loc with
| None -> false
| Some loc ->
let r = Types.to_range loc in
let line1 = r.start.line in
let col1 = r.start.character in
let line2 = r.end_.line in
let col2 = r.end_.character in
if debug_in_range then
Io.Log.trace "in_range"
(Format.asprintf "(%d, %d) in (%d,%d)-(%d,%d)" line col line1 col1
line2 col2);
(line1 < line && line < line2)
||
if line1 = line && line2 = line then col1 <= col && col < col2
else (line1 = line && col1 <= col) || (line2 = line && col < col2)
let gt_range ?loc (line, col) =
match loc with
| None -> false
| Some loc ->
let r = Types.to_range loc in
let line1 = r.start.line in
let col1 = r.start.character in
let line2 = r.end_.line in
let col2 = r.end_.character in
if debug_in_range then
Io.Log.trace "gt_range"
(Format.asprintf "(%d, %d) in (%d,%d)-(%d,%d)" line col line1 col1
line2 col2);
line < line1 || (line = line1 && col < col1)
end
module Offset : Point with type t = int = struct
type t = int
type offset_table = string
let in_range ?loc point =
match loc with
| None -> false
| Some loc -> loc.Loc.bp <= point && point < loc.ep
let gt_range ?loc point =
match loc with
| None -> false
| Some loc -> point < loc.Loc.bp
let to_offset off _ = off
let to_string off = string_of_int off
end
type approx =
| Exact
| PrevIfEmpty
| Prev
module type S = sig
module P : Point
type ('a, 'r) query = doc:Doc.t -> point:P.t -> 'a -> 'r option
val node : (approx, Doc.node) query
val loc : (approx, Loc.t) query
val ast : (approx, Coq.Ast.t) query
val goals : (approx, Coq.Goals.reified_pp) query
val messages : (approx, Coq.Message.t list) query
val info : (approx, string) query
val completion : (string, string list) query
end
let some x = Some x
let obind x f = Option.bind f x
module Make (P : Point) : S with module P := P = struct
type ('a, 'r) query = doc:Doc.t -> point:P.t -> 'a -> 'r option
let find ~doc ~point approx =
let rec find prev l =
match l with
| [] -> prev
| node :: xs -> (
let loc = node.Doc.loc in
match approx with
| Exact -> if P.in_range ~loc point then Some node else find None xs
| PrevIfEmpty ->
if P.gt_range ~loc point then prev else find (Some node) xs
| Prev ->
if P.gt_range ~loc point || P.in_range ~loc point then prev
else find (Some node) xs)
in
find None doc.Doc.nodes
let node = find
let if_not_empty (pp : Pp.t) =
if Pp.(repr pp = Ppcmd_empty) then None else Some pp
let reify_goals ppx lemmas =
let open Coq.Goals in
let proof =
Vernacstate.LemmaStack.with_top lemmas ~f:(fun pstate ->
Declare.Proof.get pstate)
in
let { Proof.goals; stack; sigma; _ } = Proof.data proof in
let ppx = List.map (Coq.Goals.process_goal_gen ppx sigma) in
Some
{ goals = ppx goals
; stack = List.map (fun (g1, g2) -> (ppx g1, ppx g2)) stack
; bullet = if_not_empty @@ Proof_bullet.suggest proof
; shelf = Evd.shelf sigma |> ppx
; given_up = Evd.given_up sigma |> Evar.Set.elements |> ppx
}
let pr_goal st =
let ppx env sigma x =
Printer.pr_ltype_env ~goal_concl_style:true env sigma x
in
let lemmas = Coq.State.lemmas ~st in
Option.cata (reify_goals ppx) None lemmas
let loc ~doc ~point approx =
let node = find ~doc ~point approx in
Option.map (fun node -> node.Doc.loc) node
let ast ~doc ~point approx =
let node = find ~doc ~point approx in
Option.bind node (fun node -> node.Doc.ast)
let goals ~doc ~point approx =
find ~doc ~point approx
|> obind (fun node ->
Coq.State.in_state ~st:node.Doc.state ~f:pr_goal node.Doc.state)
let messages ~doc ~point approx =
find ~doc ~point approx |> Option.map (fun node -> node.Doc.messages)
let info ~doc ~point approx =
find ~doc ~point approx |> Option.map (fun node -> node.Doc.memo_info)
let pr_extref gr =
match gr with
| Globnames.TrueGlobal gr -> Printer.pr_global gr
| Globnames.Abbrev kn -> Names.KerName.print kn
let to_qualid p = try Some (Libnames.qualid_of_string p) with _ -> None
let completion ~doc ~point prefix =
find ~doc ~point Exact
|> obind (fun node ->
Coq.State.in_state ~st:node.Doc.state prefix ~f:(fun prefix ->
to_qualid prefix
|> obind (fun p ->
Nametab.completion_canditates p
|> List.map (fun x -> Pp.string_of_ppcmds (pr_extref x))
|> some)))
end
module LC = Make (LineCol)
module O = Make (Offset)