Skip to content

Commit 6bc66f8

Browse files
authored
Merge pull request #795 from coq-community/overview
Capabilities for outline
2 parents fd68049 + dd01440 commit 6bc66f8

File tree

6 files changed

+123
-8
lines changed

6 files changed

+123
-8
lines changed

language-server/dm/document.ml

+79-8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ module LM = Map.Make (Int)
2222

2323
module SM = Map.Make (Stateid)
2424

25+
type proof_block_type =
26+
| TheoremKind of Decls.theorem_kind
27+
| DefinitionType of Decls.definition_object_kind
28+
29+
type outline_element = {
30+
id: sentence_id;
31+
name: string;
32+
type_: proof_block_type;
33+
statement: string;
34+
range: Range.t
35+
}
36+
37+
type outline = outline_element list
38+
2539
type parsed_ast = {
2640
ast: Synterp.vernac_control_entry;
2741
classification: Vernacextend.vernac_classification;
@@ -71,15 +85,12 @@ type document = {
7185
parsing_errors_by_end : parsing_error LM.t;
7286
comments_by_end : comment LM.t;
7387
schedule : Scheduler.schedule;
88+
outline : outline;
7489
parsed_loc : int;
7590
raw_doc : RawDocument.t;
7691
init_synterp_state : Vernacstate.Synterp.t;
7792
}
7893

79-
let schedule doc = doc.schedule
80-
81-
let raw_document doc = doc.raw_doc
82-
8394
let range_of_sentence raw (sentence : sentence) =
8495
let start = RawDocument.position_of_loc raw sentence.start in
8596
let end_ = RawDocument.position_of_loc raw sentence.stop in
@@ -100,6 +111,61 @@ let range_of_id_with_blank_space document id =
100111
| None -> CErrors.anomaly Pp.(str"Trying to get range of non-existing sentence " ++ Stateid.print id)
101112
| Some sentence -> range_of_sentence_with_blank_space document.raw_doc sentence
102113

114+
115+
let record_outline document id (ast : Synterp.vernac_control_entry) classif (outline : outline) =
116+
let open Vernacextend in
117+
match classif with
118+
| VtStartProof (_, names) ->
119+
let vernac_gen_expr = ast.v.expr in
120+
let type_ = match vernac_gen_expr with
121+
| VernacSynterp _ -> None
122+
| VernacSynPure pure ->
123+
match pure with
124+
| Vernacexpr.VernacStartTheoremProof (kind, _) -> Some (TheoremKind kind)
125+
| Vernacexpr.VernacDefinition ((_, def), _, _) -> Some (DefinitionType def)
126+
| _ -> None
127+
in
128+
let name = match names with
129+
|[] -> "default"
130+
| n :: _ -> Names.Id.to_string n
131+
in
132+
let statement = "" in
133+
begin match type_ with
134+
| None -> outline
135+
| Some type_ ->
136+
let range = range_of_id document id in
137+
let element = {id; type_; name; statement; range} in
138+
element :: outline
139+
end
140+
| VtSideff (names, _) ->
141+
let vernac_gen_expr = ast.v.expr in
142+
let type_ = match vernac_gen_expr with
143+
| VernacSynterp _ -> None
144+
| VernacSynPure pure ->
145+
match pure with
146+
| Vernacexpr.VernacStartTheoremProof (kind, _) -> Some (TheoremKind kind)
147+
| Vernacexpr.VernacDefinition ((_, def), _, _) -> Some (DefinitionType def)
148+
| _ -> None
149+
in
150+
let name = match names with
151+
|[] -> "default"
152+
| n :: _ -> Names.Id.to_string n
153+
in
154+
let statement = "" in
155+
begin match type_ with
156+
| None -> outline
157+
| Some type_ ->
158+
let range = range_of_id document id in
159+
let element = {id; type_; name; statement; range} in
160+
element :: outline
161+
end
162+
| _ -> outline
163+
164+
let schedule doc = doc.schedule
165+
166+
let raw_document doc = doc.raw_doc
167+
168+
let outline doc = doc.outline
103169
let parse_errors parsed =
104170
List.map snd (LM.bindings parsed.parsing_errors_by_end)
105171

@@ -111,19 +177,23 @@ let add_sentence parsed parsing_start start stop (ast: parsed_ast) synterp_state
111177
in
112178
(* FIXME may invalidate scheduler_state_XXX for following sentences -> propagate? *)
113179
let sentence = { parsing_start; start; stop; ast; id; synterp_state; scheduler_state_before; scheduler_state_after } in
114-
{ parsed with sentences_by_end = LM.add stop sentence parsed.sentences_by_end;
180+
let document = {
181+
parsed with sentences_by_end = LM.add stop sentence parsed.sentences_by_end;
115182
sentences_by_id = SM.add id sentence parsed.sentences_by_id;
116-
schedule
117-
}, scheduler_state_after
183+
schedule;
184+
} in
185+
let outline = record_outline document id ast.ast ast.classification parsed.outline in
186+
{document with outline}, scheduler_state_after
118187

119188
let remove_sentence parsed id =
120189
match SM.find_opt id parsed.sentences_by_id with
121190
| None -> parsed
122191
| Some sentence ->
123192
let sentences_by_id = SM.remove id parsed.sentences_by_id in
124193
let sentences_by_end = LM.remove sentence.stop parsed.sentences_by_end in
194+
let outline = List.filter (fun (e : outline_element) -> e.id != id) parsed.outline in
125195
(* TODO clean up the schedule and free cached states *)
126-
{ parsed with sentences_by_id; sentences_by_end; }
196+
{ parsed with sentences_by_id; sentences_by_end; outline }
127197

128198
let sentences parsed =
129199
List.map snd @@ SM.bindings parsed.sentences_by_id
@@ -490,6 +560,7 @@ let create_document init_synterp_state text =
490560
parsing_errors_by_end = LM.empty;
491561
comments_by_end = LM.empty;
492562
schedule = initial_schedule;
563+
outline = [];
493564
init_synterp_state;
494565
}
495566

language-server/dm/document.mli

+16
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,24 @@ open Lsp.Types
2222
sentences *)
2323
type document
2424

25+
type proof_block_type =
26+
| TheoremKind of Decls.theorem_kind
27+
| DefinitionType of Decls.definition_object_kind
28+
29+
type outline_element = {
30+
id: sentence_id;
31+
name: string;
32+
type_: proof_block_type;
33+
statement: string;
34+
range: Range.t
35+
}
36+
37+
type outline = outline_element list
38+
2539
val raw_document : document -> RawDocument.t
2640

41+
val outline : document -> outline
42+
2743
val create_document : Vernacstate.Synterp.t -> string -> document
2844
(** [create_document init_synterp_state text] creates a fresh document with content defined by
2945
[text] under [init_synterp_state]. *)

language-server/dm/documentManager.ml

+12
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,18 @@ let clear_observe_id st =
246246
let reset_to_top st =
247247
{ st with observe_id = Some Top }
248248

249+
let get_document_symbols st =
250+
let outline = Document.outline st.document in
251+
let to_document_symbol elem =
252+
let Document.{name; statement; range; type_} = elem in
253+
let kind = begin match type_ with
254+
| TheoremKind _ -> SymbolKind.Function
255+
| DefinitionType _ ->SymbolKind.Variable
256+
end in
257+
DocumentSymbol.{name; detail=(Some statement); kind; range; selectionRange=range; children=None; deprecated=None; tags=None;}
258+
in
259+
List.map to_document_symbol outline
260+
249261
let interpret_to st id =
250262
let observe_id = if st.observe_id = None then None else (Some (Id id)) in
251263
let st = { st with observe_id} in

language-server/dm/documentManager.mli

+2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ val observe_id_range : state -> Range.t option
8787

8888
val get_messages : state -> Position.t option -> (DiagnosticSeverity.t * pp) list
8989

90+
val get_document_symbols : state -> DocumentSymbol.t list
91+
9092
val all_diagnostics : state -> Diagnostic.t list
9193
(** all_diagnostics [doc] returns the diagnostics corresponding to the sentences
9294
that have been executed in [doc]. *)

language-server/dm/scheduler.ml

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ type task =
4444
| SubProof of ast list
4545
| ModuleWithSignature of ast list
4646
*)
47+
48+
4749
type proof_block = {
4850
proof_sentences : executable_sentence list;
4951
opener_id : sentence_id;

language-server/vscoqtop/lspManager.ml

+12
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,13 @@ let do_initialize id params =
146146
end;
147147
let textDocumentSync = `TextDocumentSyncKind TextDocumentSyncKind.Incremental in
148148
let completionProvider = CompletionOptions.create ~resolveProvider:false () in
149+
let documentSymbolProvider = `Bool true in
149150
let hoverProvider = `Bool true in
150151
let capabilities = ServerCapabilities.create
151152
~textDocumentSync
152153
~completionProvider
153154
~hoverProvider
155+
~documentSymbolProvider
154156
()
155157
in
156158
let initialize_result = Lsp.Types.InitializeResult.{
@@ -438,6 +440,14 @@ let textDocumentCompletion id params =
438440
let message = e in
439441
Error(message), []
440442

443+
let documentSymbol id params =
444+
let Lsp.Types.DocumentSymbolParams.{ textDocument = {uri}} = params in
445+
match Hashtbl.find_opt states (DocumentUri.to_path uri) with
446+
| None -> log @@ "[documentSymbol] ignoring event on non existant document"; Error("Document does not exist"), []
447+
| Some tab -> log @@ "[documentSymbol] getting symbols";
448+
let symbols = Dm.DocumentManager.get_document_symbols tab.st in
449+
Ok(Some (`DocumentSymbol symbols)), []
450+
441451
let coqtopResetCoq id params =
442452
let Request.Client.ResetParams.{ textDocument = { uri } } = params in
443453
match Hashtbl.find_opt states (DocumentUri.to_path uri) with
@@ -529,6 +539,8 @@ let dispatch_std_request : type a. Jsonrpc.Id.t -> a Lsp.Client_request.t -> (a,
529539
textDocumentCompletion id params
530540
| TextDocumentHover params ->
531541
textDocumentHover id params, []
542+
| DocumentSymbol params ->
543+
documentSymbol id params
532544
| UnknownRequest _ | _ -> Error "Received unknown request", []
533545

534546
let dispatch_request : type a. Jsonrpc.Id.t -> a Request.Client.t -> (a,string) result * events =

0 commit comments

Comments
 (0)