delay-init 1/4 - initializationOptions cleanup
[hiphop-php.git] / hphp / hack / src / utils / lsp / lsp.ml
blobe138eb5552302ec10a781d50b72491e6755215f6
1 (*
2 * Copyright (c) 2016, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 (**
11 * This file is an OCaml representation of the Language Server Protocol
12 * https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md
13 * based on the current v3.
15 * Changes to make it more natural in OCaml:
16 * - We don't represent the common base types of Requests/Errors/Notifications
17 * because base types don't naturally mix with abstract data types, and
18 * because code for these things is done more naturally at the JSON layer
19 * - We avoid option types where we can. The idea is to follow the internet
20 * "robustness" rule of being liberal in what we accept, conservative in
21 * what we emit: if we're parsing a message and it lacks a field, and if
22 * the spec tells us how to interpret absence, then we do that interpretation
23 * at the JSON->LSP parsing level (so long as the interpretation is lossless).
24 * On the emitting side, we might as well emit all fields.
25 * - For every request, like Initialize or workspace/Symbol, we've invented
26 * "Initialize.response = (Initialize.result, Initialize.error) Result"
27 * or "Symbol.response = (Symbol.result, Error.error) Result" to show
28 * the two possible return types from this request. Note that each different
29 * request can have its own custom error type, although most don't.
30 * - Most datatypes go in modules since there are so many name-clashes in
31 * the protocol and OCaml doesn't like name-clashes. Only exceptions are
32 * the really primitive types like location and documentUri.
33 * The few places where we still had to rename fields to avoid OCaml name
34 * clashes I've noted in the comments with the word "wire" to indicate the
35 * over-the-wire form of the name.
36 * - Names have been translated from jsonConvention into ocaml convention
37 * only where necessary, e.g. because ocaml uses lowercase for types.
38 * - The spec has space for extra fields like "experimental". It obviously
39 * doesn't make sense to encode them in a type system. I've omitted them
40 * entirely.
43 type lsp_id =
44 | NumberId of int
45 | StringId of string
47 type documentUri = DocumentUri of string [@@deriving eq]
49 let uri_of_string (s : string) : documentUri = DocumentUri s
51 let string_of_uri (DocumentUri s) : string = s
53 (* A position is between two characters like an 'insert' cursor in a editor *)
54 type position = {
55 line: int;
56 (* line position in a document [zero-based] *)
57 character: int; (* character offset on a line in a document [zero-based] *)
59 [@@deriving eq]
61 (* A range is comparable to a selection in an editor *)
62 type range = {
63 start: position;
64 (* the range's start position *)
65 end_: position; (* the range's end position [exclusive] *)
67 [@@deriving eq]
69 type textDocumentSaveReason =
70 | Manual [@value 1]
71 | AfterDelay [@value 2]
72 | FocusOut [@value 3]
73 [@@deriving enum]
75 (* Represents a location inside a resource, such as a line inside a text file *)
76 module Location = struct
77 type t = {
78 uri: documentUri;
79 range: range;
81 [@@deriving eq]
82 end
84 (* Represents a location inside a resource which also wants to display a
85 friendly name to the user. *)
86 module DefinitionLocation = struct
87 type t = {
88 location: Location.t;
89 title: string option;
91 end
93 (* markedString can be used to render human readable text. It is either a
94 * markdown string or a code-block that provides a language and a code snippet.
95 * Note that markdown strings will be sanitized by the client - including
96 * escaping html *)
97 type markedString =
98 | MarkedString of string
99 (* lang, value *)
100 | MarkedCode of string * string
102 (* Represents a reference to a command. Provides a title which will be used to
103 * represent a command in the UI. Commands are identitifed using a string
104 * identifier and the protocol currently doesn't specify a set of well known
105 * commands. So executing a command requires some tool extension code. *)
106 module Command = struct
107 type t = {
108 title: string;
109 (* title of the command, like `save` *)
110 command: string;
111 (* the identifier of the actual command handler *)
112 arguments: Hh_json.json list; (* wire: it can be omitted *)
116 (* A textual edit applicable to a text document. If n textEdits are applied
117 to a text document all text edits describe changes to the initial document
118 version. Execution wise text edits should applied from the bottom to the
119 top of the text document. Overlapping text edits are not supported. *)
120 module TextEdit = struct
121 type t = {
122 range: range;
123 (* to insert text, use a range where start = end *)
124 newText: string; (* for delete operations, use an empty string *)
128 (* Text documents are identified using a URI. *)
129 module TextDocumentIdentifier = struct
130 type t = { uri: documentUri (* the text document's URI *) }
133 (* An identifier to denote a specific version of a text document. *)
134 module VersionedTextDocumentIdentifier = struct
135 type t = {
136 uri: documentUri;
137 (* the text document's URI *)
138 version: int; (* the version number of this document *)
142 (* Describes textual changes on a single text document. The text document is
143 referred to as a VersionedTextDocumentIdentifier to allow clients to check
144 the text document version before an edit is applied. *)
145 module TextDocumentEdit = struct
146 type t = {
147 textDocument: VersionedTextDocumentIdentifier.t;
148 edits: TextEdit.t list;
152 (* A workspace edit represents changes to many resources managed in the
153 workspace. A workspace edit consists of a mapping from a URI to an
154 array of TextEdits to be applied to the document with that URI. *)
155 module WorkspaceEdit = struct
156 type t = {
157 changes: TextEdit.t list SMap.t; (* holds changes to existing docs *)
161 (* An item to transfer a text document from the client to the server. The
162 version number strictly increases after each change, including undo/redo. *)
163 module TextDocumentItem = struct
164 type t = {
165 uri: documentUri;
166 (* the text document's URI *)
167 languageId: string;
168 (* the text document's language identifier *)
169 version: int;
170 (* the version of the document *)
171 text: string; (* the content of the opened text document *)
176 * A code lens represents a command that should be shown along with
177 * source text, like the number of references, a way to run tests, etc.
179 * A code lens is _unresolved_ when no command is associated to it. For performance
180 * reasons the creation of a code lens and resolving should be done in two stages.
182 module CodeLens = struct
183 type t = {
184 range: range;
185 command: Command.t;
186 data: Hh_json.json option;
190 (* A parameter literal used in requests to pass a text document and a position
191 inside that document. *)
192 module TextDocumentPositionParams = struct
193 type t = {
194 textDocument: TextDocumentIdentifier.t;
195 (* the text document *)
196 position: position; (* the position inside the text document *)
200 (* A document filter denotes a document through properties like language,
201 schema or pattern. E.g. language:"typescript",scheme:"file"
202 or language:"json",pattern:"**/package.json" *)
203 module DocumentFilter = struct
204 type t = {
205 language: string option;
206 (* a language id, like "typescript" *)
207 scheme: string option;
208 (* a uri scheme, like "file" or "untitled" *)
209 pattern: string option; (* a glob pattern, like "*.{ts,js}" *)
213 (* A document selector is the combination of one or many document filters. *)
214 module DocumentSelector = struct
215 type t = DocumentFilter.t list
218 (* Represents information about programming constructs like variables etc. *)
219 module SymbolInformation = struct
220 (* These numbers should match
221 * https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#symbolKind
223 type symbolKind =
224 | File [@value 1]
225 | Module [@value 2]
226 | Namespace [@value 3]
227 | Package [@value 4]
228 | Class [@value 5]
229 | Method [@value 6]
230 | Property [@value 7]
231 | Field [@value 8]
232 | Constructor [@value 9]
233 | Enum [@value 10]
234 | Interface [@value 11]
235 | Function [@value 12]
236 | Variable [@value 13]
237 | Constant [@value 14]
238 | String [@value 15]
239 | Number [@value 16]
240 | Boolean [@value 17]
241 | Array [@value 18]
242 | Object [@value 19]
243 | Key [@value 20]
244 | Null [@value 21]
245 | EnumMember [@value 22]
246 | Struct [@value 23]
247 | Event [@value 24]
248 | Operator [@value 25]
249 | TypeParameter [@value 26]
250 [@@deriving enum]
252 type t = {
253 name: string;
254 kind: symbolKind;
255 location: Location.t;
256 (* the span of the symbol including its contents *)
257 containerName: string option; (* the symbol containing this symbol *)
261 (* For showing messages (not diagnostics) in the user interface. *)
262 module MessageType = struct
263 type t =
264 | ErrorMessage [@value 1]
265 | WarningMessage [@value 2]
266 | InfoMessage [@value 3]
267 | LogMessage [@value 4]
268 [@@deriving eq, enum]
271 module CodeActionKind = struct
272 (* The kind of a code action.
273 * Kinds are a hierarchical list of identifiers separated by `.`, e.g.
274 * `"refactor.extract.function"`.
275 * The set of kinds is open and client needs to announce the kinds it supports
276 * to the server during initialization.
277 * CodeActionKind.t uses a pair to represent a non-empty list and provides utility
278 * functions for creation, membership, printing.
279 * Module CodeAction below also references this module as Kind.
281 type t = string * string list
283 (* is x of kind k? *)
284 let is_kind : t -> t -> bool =
285 let rec is_prefix_of ks xs =
286 match (ks, xs) with
287 | ([], _) -> true
288 | (k :: ks, x :: xs) when String.equal k x -> is_prefix_of ks xs
289 | (_, _) -> false
291 (fun (k, ks) (x, xs) -> String.equal k x && is_prefix_of ks xs)
293 (* does `ks` contain kind `k` *)
294 let contains_kind k ks = List.exists (is_kind k) ks
296 (* does an optional list of kinds `ks` contain kind `k` *)
297 let contains_kind_opt ~default k ks =
298 match ks with
299 | Some ks -> contains_kind k ks
300 | None -> default
302 (* Create a kind from a string that follows the spec *)
303 let kind_of_string : string -> t =
304 fun s ->
305 match String.split_on_char '.' s with
306 | [] -> failwith "split_on_char does not return an empty list"
307 | k :: ks -> (k, ks)
309 (* Create the equivalent string that the spec would have required *)
310 let string_of_kind : t -> string = (fun (k, ks) -> String.concat "." (k :: ks))
312 (* Create a new sub-kind of an existing kind *)
313 let sub_kind : t -> string -> t =
314 let cons_to_end (ss : string list) (s : string) =
315 Base.List.(fold_right ss ~f:cons ~init:[s])
317 (fun (k, ks) s -> (k, cons_to_end ks s))
319 (* Some of the constants defined by the spec *)
320 let quickfix = kind_of_string "quickfix"
322 let refactor = kind_of_string "refactor"
324 (* Document wide code actions *)
325 let source = kind_of_string "source"
328 (* Cancellation notification, method="$/cancelRequest" *)
329 module CancelRequest = struct
330 type params = cancelParams
332 and cancelParams = { id: lsp_id (* the request id to cancel *) }
335 (* SetTraceNotification, method="$/setTraceNotification" *)
336 module SetTraceNotification = struct
337 type params =
338 | Verbose
339 | Off
342 (* Initialize request, method="initialize" *)
343 module Initialize = struct
344 type textDocumentSyncKind =
345 (* docs should not be synced at all. Wire "None" *)
346 | NoSync [@value 0]
347 (* synced by always sending full content. Wire "Full" *)
348 | FullSync [@value 1]
349 | IncrementalSync [@value 2]
350 [@@deriving enum]
352 type params = {
353 processId: int option;
354 (* pid of parent process *)
355 rootPath: string option;
356 (* deprecated *)
357 rootUri: documentUri option;
358 (* the root URI of the workspace *)
359 initializationOptions: initializationOptions;
360 client_capabilities: client_capabilities;
361 (* "capabilities" over wire *)
362 trace: trace; (* the initial trace setting, default="off" *)
365 and result = {
366 server_capabilities: server_capabilities; (* "capabilities" over wire *)
369 and errorData = {
370 retry: bool; (* should client retry the initialize request *)
373 and trace =
374 | Off
375 | Messages
376 | Verbose
378 and initializationOptions = {
379 useTextEditAutocomplete: bool;
380 namingTableSavedStatePath: string option;
381 namingTableSavedStateTestDelay: float;
384 and client_capabilities = {
385 workspace: workspaceClientCapabilities;
386 textDocument: textDocumentClientCapabilities;
387 window: windowClientCapabilities;
388 telemetry: telemetryClientCapabilities; (* omitted: experimental *)
391 and workspaceClientCapabilities = {
392 applyEdit: bool;
393 (* client supports appling batch edits *)
394 workspaceEdit: workspaceEdit;
395 didChangeWatchedFiles: dynamicRegistration;
396 (* omitted: other dynamic-registration fields *)
399 and dynamicRegistration = {
400 dynamicRegistration: bool;
401 (* client supports dynamic registration for this capability *)
404 and workspaceEdit = {
405 documentChanges: bool; (* client supports versioned doc changes *)
408 and textDocumentClientCapabilities = {
409 synchronization: synchronization;
410 completion: completion; (** textDocument/completion *)
411 codeAction: codeAction;
412 definition: definition;
413 typeDefinition: typeDefinition;
414 declaration: declaration;
415 implementation: implementation;
418 (* synchronization capabilities say what messages the client is capable
419 * of sending, should be be so asked by the server.
420 * We use the "can_" prefix for OCaml naming reasons; it's absent in LSP *)
421 and synchronization = {
422 can_willSave: bool;
423 (* client can send textDocument/willSave *)
424 can_willSaveWaitUntil: bool;
425 (* textDoc.../willSaveWaitUntil *)
426 can_didSave: bool; (* textDocument/didSave *)
429 and completion = { completionItem: completionItem }
431 and completionItem = {
432 snippetSupport: bool; (* client can do snippets as insert text *)
435 and codeAction = {
436 (* Whether code action supports dynamic registration. *)
437 codeAction_dynamicRegistration: bool;
438 (* wire: dynamicRegistraction *)
439 (* The client support code action literals as a valid
440 * response of the `textDocument/codeAction` request. *)
441 codeActionLiteralSupport: codeActionliteralSupport option;
444 and definition = { definitionLinkSupport: bool }
446 and typeDefinition = { typeDefinitionLinkSupport: bool }
448 and declaration = { declarationLinkSupport: bool }
450 and implementation = { implementationLinkSupport: bool }
452 and codeActionliteralSupport = {
453 (* The code action kind values the client supports. When this
454 * property exists the client also guarantees that it will
455 * handle values outside its set gracefully and falls back
456 * to a default value when unknown. *)
457 codeAction_valueSet: CodeActionKind.t list; (* wire: valueSet *)
460 and windowClientCapabilities = {
461 status: bool;
462 (* Nuclide-specific: client supports window/showStatusRequest *)
465 and telemetryClientCapabilities = {
466 connectionStatus: bool;
467 (* Nuclide-specific: client supports telemetry/connectionStatus *)
470 (* What capabilities the server provides *)
471 and server_capabilities = {
472 textDocumentSync: textDocumentSyncOptions;
473 (* how to sync *)
474 hoverProvider: bool;
475 completionProvider: completionOptions option;
476 signatureHelpProvider: signatureHelpOptions option;
477 definitionProvider: bool;
478 typeDefinitionProvider: bool;
479 referencesProvider: bool;
480 documentHighlightProvider: bool;
481 documentSymbolProvider: bool;
482 (* ie. document outline *)
483 workspaceSymbolProvider: bool;
484 (* ie. find-symbol-in-project *)
485 codeActionProvider: bool;
486 codeLensProvider: codeLensOptions option;
487 documentFormattingProvider: bool;
488 documentRangeFormattingProvider: bool;
489 documentOnTypeFormattingProvider: documentOnTypeFormattingOptions option;
490 renameProvider: bool;
491 documentLinkProvider: documentLinkOptions option;
492 executeCommandProvider: executeCommandOptions option;
493 implementationProvider: bool;
494 (* Nuclide-specific features below *)
495 typeCoverageProviderFB: bool;
496 rageProviderFB: bool;
499 and completionOptions = {
500 resolveProvider: bool;
501 (* server resolves extra info on demand *)
502 completion_triggerCharacters: string list; (* wire "triggerCharacters" *)
505 and signatureHelpOptions = {
506 sighelp_triggerCharacters: string list; (* wire "triggerCharacters" *)
509 and codeLensOptions = {
510 codelens_resolveProvider: bool; (* wire "resolveProvider" *)
513 and documentOnTypeFormattingOptions = {
514 firstTriggerCharacter: string;
515 (* e.g. "}" *)
516 moreTriggerCharacter: string list;
519 and documentLinkOptions = {
520 doclink_resolveProvider: bool; (* wire "resolveProvider" *)
523 and executeCommandOptions = {
524 commands: string list; (* the commands to be executed on the server *)
527 (* text document sync options say what messages the server requests the
528 * client to send. We use the "want_" prefix for OCaml naming reasons;
529 * this prefix is absent in LSP. *)
530 and textDocumentSyncOptions = {
531 want_openClose: bool;
532 (* textDocument/didOpen+didClose *)
533 want_change: textDocumentSyncKind;
534 want_willSave: bool;
535 (* textDocument/willSave *)
536 want_willSaveWaitUntil: bool;
537 (* textDoc.../willSaveWaitUntil *)
538 want_didSave: saveOptions option; (* textDocument/didSave *)
541 (* full only on open. Wire "Incremental" *)
542 and saveOptions = {
543 includeText: bool; (* the client should include content on save *)
547 (* Rage request, method="telemetry/rage" *)
548 module RageFB = struct
549 type result = rageItem list
551 and rageItem = {
552 title: string option;
553 data: string;
557 (* Code Lens resolve request, method="codeLens/resolve" *)
558 module CodeLensResolve = struct
559 type params = CodeLens.t
561 and result = CodeLens.t
564 (* Hover request, method="textDocument/hover" *)
565 module Hover = struct
566 type params = TextDocumentPositionParams.t
568 and result = hoverResult option
570 and hoverResult = {
571 contents: markedString list;
572 (* wire: either a single one or an array *)
573 range: range option;
577 (* PublishDiagnostics notification, method="textDocument/PublishDiagnostics" *)
578 module PublishDiagnostics = struct
579 type diagnosticSeverity =
580 | Error [@value 1]
581 | Warning [@value 2]
582 | Information [@value 3]
583 | Hint [@value 4]
584 [@@deriving eq, enum]
586 type params = publishDiagnosticsParams
588 and publishDiagnosticsParams = {
589 uri: documentUri;
590 diagnostics: diagnostic list;
591 isStatusFB: bool;
594 and diagnostic = {
595 range: range;
596 (* the range at which the message applies *)
597 severity: diagnosticSeverity option;
598 (* if omitted, client decides *)
599 code: diagnosticCode;
600 (* the diagnostic's code. *)
601 source: string option;
602 (* human-readable string, eg. typescript/lint *)
603 message: string;
604 (* the diagnostic's message *)
605 relatedInformation: diagnosticRelatedInformation list;
606 relatedLocations: relatedLocation list; (* legacy FB extension *)
608 [@@deriving eq]
610 and diagnosticCode =
611 | IntCode of int
612 | StringCode of string
613 | NoCode
614 [@@deriving eq]
616 and diagnosticRelatedInformation = {
617 relatedLocation: Location.t;
618 (* wire: just "location" *)
619 relatedMessage: string; (* wire: just "message" *)
621 [@@deriving eq]
623 (* legacy FB extension *)
624 and relatedLocation = diagnosticRelatedInformation
627 (* DidOpenTextDocument notification, method="textDocument/didOpen" *)
628 module DidOpen = struct
629 type params = didOpenTextDocumentParams
631 and didOpenTextDocumentParams = {
632 textDocument: TextDocumentItem.t; (* the document that was opened *)
636 (* DidCloseTextDocument notification, method="textDocument/didClose" *)
637 module DidClose = struct
638 type params = didCloseTextDocumentParams
640 and didCloseTextDocumentParams = {
641 textDocument: TextDocumentIdentifier.t; (* the doc that was closed *)
645 (* DidSaveTextDocument notification, method="textDocument/didSave" *)
646 module DidSave = struct
647 type params = didSaveTextDocumentParams
649 and didSaveTextDocumentParams = {
650 textDocument: TextDocumentIdentifier.t;
651 (* the doc that was saved *)
652 text: string option; (* content when saved; depends on includeText *)
656 (* DidChangeTextDocument notification, method="textDocument/didChange" *)
657 module DidChange = struct
658 type params = didChangeTextDocumentParams
660 and didChangeTextDocumentParams = {
661 textDocument: VersionedTextDocumentIdentifier.t;
662 contentChanges: textDocumentContentChangeEvent list;
665 and textDocumentContentChangeEvent = {
666 range: range option;
667 (* the range of the document that changed *)
668 rangeLength: int option;
669 (* the length that got replaced *)
670 text: string; (* the new text of the range/document *)
674 (* WillSaveWaitUntilTextDocument request, method="textDocument/willSaveWaitUntil" *)
675 module WillSaveWaitUntil = struct
676 type params = willSaveWaitUntilTextDocumentParams
678 and willSaveWaitUntilTextDocumentParams = {
679 textDocument: TextDocumentIdentifier.t;
680 reason: textDocumentSaveReason;
683 and result = TextEdit.t list
686 (* Watched files changed notification, method="workspace/didChangeWatchedFiles" *)
687 module DidChangeWatchedFiles = struct
688 type registerOptions = { watchers: fileSystemWatcher list }
690 and fileSystemWatcher = { globPattern: string }
692 type fileChangeType =
693 | Created [@value 1]
694 | Updated [@value 2]
695 | Deleted [@value 3]
696 [@@deriving enum]
698 type params = { changes: fileEvent list }
700 and fileEvent = {
701 uri: documentUri;
702 type_: fileChangeType;
706 (* Goto Definition request, method="textDocument/definition" *)
707 module Definition = struct
708 type params = TextDocumentPositionParams.t
710 and result = DefinitionLocation.t list
712 (* wire: either a single one or an array *)
715 (* Goto TypeDefinition request, method="textDocument/typeDefinition" *)
716 module TypeDefinition = struct
717 type params = TextDocumentPositionParams.t
719 and result = DefinitionLocation.t list
722 (* Go To Implementation request, method="textDocument/implementation" *)
723 module Implementation = struct
724 type params = TextDocumentPositionParams.t
726 and result = Location.t list
729 module CodeAction = struct
730 (* A code action represents a change that can be performed in code, e.g. to fix a problem or
731 to refactor code. *)
732 type t = {
733 (* A short, human-readable, title for this code action. *)
734 title: string;
735 (* The kind of the code action. Used to filter code actions. *)
736 kind: CodeActionKind.t;
737 (* The diagnostics that this code action resolves. *)
738 diagnostics: PublishDiagnostics.diagnostic list;
739 (* A CodeAction must set either `edit` and/or a `command`.
740 If both are supplied, the `edit` is applied first, then the `command` is executed. *)
741 action: edit_and_or_command;
744 and edit_and_or_command =
745 | EditOnly of WorkspaceEdit.t
746 | CommandOnly of Command.t
747 | BothEditThenCommand of (WorkspaceEdit.t * Command.t)
749 type result = command_or_action list
751 and command_or_action =
752 | Command of Command.t
753 | Action of t
756 (* Code Action Request, method="textDocument/codeAction" *)
757 module CodeActionRequest = struct
758 type params = {
759 (* The document in which the command was invoked. *)
760 textDocument: TextDocumentIdentifier.t;
761 (* The range for which the command was invoked. *)
762 range: range;
763 (* Context carrying additional information. *)
764 context: codeActionContext;
767 (* Contains additional diagnostic information about the context in which
768 a code action is run. *)
769 and codeActionContext = {
770 diagnostics: PublishDiagnostics.diagnostic list;
771 only: CodeActionKind.t list option;
775 (* Completion request, method="textDocument/completion" *)
776 module Completion = struct
777 (* These numbers should match
778 * https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
780 type completionItemKind =
781 | Text [@value 1]
782 | Method [@value 2]
783 | Function [@value 3]
784 | Constructor [@value 4]
785 | Field [@value 5]
786 | Variable [@value 6]
787 | Class [@value 7]
788 | Interface [@value 8]
789 | Module [@value 9]
790 | Property [@value 10]
791 | Unit [@value 11]
792 | Value [@value 12]
793 | Enum [@value 13]
794 | Keyword [@value 14]
795 | Snippet [@value 15]
796 | Color [@value 16]
797 | File [@value 17]
798 | Reference [@value 18]
799 | Folder [@value 19]
800 | MemberOf [@value 20]
801 | Constant [@value 21]
802 | Struct [@value 22]
803 | Event [@value 23]
804 | Operator [@value 24]
805 | TypeParameter [@value 25]
806 [@@deriving enum]
808 (* These numbers should match
809 * https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
811 type insertTextFormat =
812 | PlainText [@value 1] (* the insertText/textEdits are just plain strings *)
813 | SnippetFormat [@value 2] (* wire: just "Snippet" *)
814 [@@deriving enum]
816 type completionTriggerKind =
817 | Invoked [@value 1]
818 | TriggerCharacter [@value 2]
819 | TriggerForIncompleteCompletions [@value 3]
820 [@@deriving enum]
822 let is_invoked = function
823 | Invoked -> true
824 | TriggerCharacter
825 | TriggerForIncompleteCompletions ->
826 false
828 type params = completionParams
830 and completionParams = {
831 loc: TextDocumentPositionParams.t;
832 context: completionContext option;
835 and completionContext = {
836 triggerKind: completionTriggerKind;
837 triggerCharacter: string option;
840 and result = completionList
842 (* wire: can also be 'completionItem list' *)
843 and completionList = {
844 isIncomplete: bool;
845 (* further typing should result in recomputing *)
846 items: completionItem list;
849 and completionDocumentation =
850 | MarkedStringsDocumentation of markedString list
851 | UnparsedDocumentation of Hh_json.json
853 and completionItem = {
854 label: string;
855 (* the label in the UI *)
856 kind: completionItemKind option;
857 (* tells editor which icon to use *)
858 detail: string option;
859 (* human-readable string like type/symbol info *)
860 inlineDetail: string option;
861 (* nuclide-specific, right column *)
862 itemType: string option;
863 (* nuclide-specific, left column *)
864 documentation: completionDocumentation option;
865 (* human-readable doc-comment *)
866 sortText: string option;
867 (* used for sorting; if absent, uses label *)
868 filterText: string option;
869 (* used for filtering; if absent, uses label *)
870 insertText: string option;
871 (* used for inserting; if absent, uses label *)
872 insertTextFormat: insertTextFormat option;
873 textEdits: TextEdit.t list;
874 (* wire: split into hd and tl *)
875 command: Command.t option;
876 (* if present, is executed after completion *)
877 data: Hh_json.json option;
881 (* Completion Item Resolve request, method="completionItem/resolve" *)
882 module CompletionItemResolve = struct
883 type params = Completion.completionItem
885 and result = Completion.completionItem
888 (* Workspace Symbols request, method="workspace/symbol" *)
889 module WorkspaceSymbol = struct
890 type params = workspaceSymbolParams
892 and result = SymbolInformation.t list
894 and workspaceSymbolParams = { query: string (* a non-empty query string *) }
897 (* Document Symbols request, method="textDocument/documentSymbol" *)
898 module DocumentSymbol = struct
899 type params = documentSymbolParams
901 and result = SymbolInformation.t list
903 and documentSymbolParams = { textDocument: TextDocumentIdentifier.t }
906 (* Find References request, method="textDocument/references" *)
907 module FindReferences = struct
908 type params = referenceParams
910 and result = Location.t list
912 and referenceParams = {
913 loc: TextDocumentPositionParams.t;
914 (* wire: loc's members are part of referenceParams *)
915 context: referenceContext;
918 and referenceContext = {
919 includeDeclaration: bool;
920 (* include declaration of current symbol *)
921 includeIndirectReferences: bool;
925 (* Document Highlights request, method="textDocument/documentHighlight" *)
926 module DocumentHighlight = struct
927 type params = TextDocumentPositionParams.t
929 type documentHighlightKind =
930 (* a textual occurrence *)
931 | Text [@value 1]
932 (* read-access of a symbol, like reading a variable *)
933 | Read [@value 2]
934 (* write-access of a symbol, like writing a variable *)
935 | Write [@value 3]
936 [@@deriving enum]
938 type result = documentHighlight list
940 and documentHighlight = {
941 range: range;
942 (* the range this highlight applies to *)
943 kind: documentHighlightKind option;
947 (* Type Coverage request, method="textDocument/typeCoverage" *)
948 (* THIS IS A NUCLIDE-SPECIFIC EXTENSION TO LSP. *)
949 module TypeCoverageFB = struct
950 type params = typeCoverageParams
952 and result = {
953 coveredPercent: int;
954 uncoveredRanges: uncoveredRange list;
955 defaultMessage: string;
958 and typeCoverageParams = { textDocument: TextDocumentIdentifier.t }
960 and uncoveredRange = {
961 range: range;
962 message: string option;
966 (* Document Formatting request, method="textDocument/formatting" *)
967 module DocumentFormatting = struct
968 type params = documentFormattingParams
970 and result = TextEdit.t list
972 and documentFormattingParams = {
973 textDocument: TextDocumentIdentifier.t;
974 options: formattingOptions;
977 and formattingOptions = {
978 tabSize: int;
979 (* size of a tab in spaces *)
980 insertSpaces: bool;
981 (* prefer spaces over tabs *)
982 (* omitted: signature for further properties *)
986 (* Document Range Formatting request, method="textDocument/rangeFormatting" *)
987 module DocumentRangeFormatting = struct
988 type params = documentRangeFormattingParams
990 and result = TextEdit.t list
992 and documentRangeFormattingParams = {
993 textDocument: TextDocumentIdentifier.t;
994 range: range;
995 options: DocumentFormatting.formattingOptions;
999 (* Document On Type Formatting req., method="textDocument/onTypeFormatting" *)
1000 module DocumentOnTypeFormatting = struct
1001 type params = documentOnTypeFormattingParams
1003 and result = TextEdit.t list
1005 and documentOnTypeFormattingParams = {
1006 textDocument: TextDocumentIdentifier.t;
1007 position: position;
1008 (* the position at which this request was sent *)
1009 ch: string;
1010 (* the character that has been typed *)
1011 options: DocumentFormatting.formattingOptions;
1015 (* Document Signature Help request, method="textDocument/signatureHelp" *)
1016 module SignatureHelp = struct
1017 type params = TextDocumentPositionParams.t
1019 and result = t option
1021 and t = {
1022 signatures: signature_information list;
1023 activeSignature: int;
1024 activeParameter: int;
1027 and signature_information = {
1028 siginfo_label: string;
1029 siginfo_documentation: string option;
1030 parameters: parameter_information list;
1033 and parameter_information = {
1034 parinfo_label: string;
1035 parinfo_documentation: string option;
1039 (* Workspace Rename request, method="textDocument/rename" *)
1040 module Rename = struct
1041 type params = renameParams
1043 and result = WorkspaceEdit.t
1045 and renameParams = {
1046 textDocument: TextDocumentIdentifier.t;
1047 position: position;
1048 newName: string;
1052 (* Code Lens request, method="textDocument/codeLens" *)
1053 module DocumentCodeLens = struct
1054 type params = codelensParams
1056 and result = CodeLens.t list
1058 and codelensParams = { textDocument: TextDocumentIdentifier.t }
1061 (* LogMessage notification, method="window/logMessage" *)
1062 module LogMessage = struct
1063 type params = logMessageParams
1065 and logMessageParams = {
1066 type_: MessageType.t;
1067 message: string;
1071 (* ShowMessage notification, method="window/showMessage" *)
1072 module ShowMessage = struct
1073 type params = showMessageParams
1075 and showMessageParams = {
1076 type_: MessageType.t;
1077 message: string;
1081 (* ShowMessage request, method="window/showMessageRequest" *)
1082 module ShowMessageRequest = struct
1083 type t =
1084 | Present of { id: lsp_id }
1085 | Absent
1087 and params = showMessageRequestParams
1089 and result = messageActionItem option
1091 and showMessageRequestParams = {
1092 type_: MessageType.t;
1093 message: string;
1094 actions: messageActionItem list;
1097 and messageActionItem = { title: string }
1100 (* ShowStatus request, method="window/showStatus" *)
1101 module ShowStatusFB = struct
1102 type params = showStatusParams
1104 and result = ShowMessageRequest.messageActionItem option
1106 and showStatusParams = {
1107 request: ShowMessageRequest.showMessageRequestParams;
1108 progress: int option;
1109 total: int option;
1110 shortMessage: string option;
1111 telemetry: Hh_json.json option;
1115 (* ConnectionStatus notification, method="telemetry/connectionStatus" *)
1116 module ConnectionStatusFB = struct
1117 type params = connectionStatusParams
1119 and connectionStatusParams = { isConnected: bool }
1122 (* ToggleTypeCoverage notification, method="workspace/toggleTypeCoverage" *)
1123 module ToggleTypeCoverageFB = struct
1124 type params = toggleTypeCoverageParams
1126 and toggleTypeCoverageParams = { toggle: bool }
1129 (* ErrorResponse *)
1130 module Error = struct
1131 type code =
1132 | ParseError [@value -32700]
1133 | InvalidRequest [@value -32600]
1134 | MethodNotFound [@value -32601]
1135 | InvalidParams [@value -32602]
1136 | InternalError [@value -32603]
1137 | ServerErrorStart [@value -32099]
1138 | ServerErrorEnd [@value -32000]
1139 | ServerNotInitialized [@value -32002]
1140 | UnknownErrorCode [@value -32001]
1141 | RequestCancelled [@value -32800]
1142 | ContentModified [@value -32801]
1143 [@@deriving show, enum]
1145 type t = {
1146 code: code;
1147 message: string;
1148 data: Hh_json.json option;
1151 (** For methods which want to return exceptions, and they also want to decide
1152 how the exception gets serialized over LSP, they should throw this one. *)
1153 exception LspException of t
1156 type lsp_registration_options =
1157 | DidChangeWatchedFilesRegistrationOptions of
1158 DidChangeWatchedFiles.registerOptions
1160 (* Register capability request, method="client/registerCapability" *)
1161 module RegisterCapability = struct
1162 type params = { registrations: registration list }
1164 and registration = {
1165 id: string;
1166 method_: string;
1167 registerOptions: lsp_registration_options;
1170 let make_registration (registerOptions : lsp_registration_options) :
1171 registration =
1172 (* The ID field is arbitrary but unique per type of capability (for future
1173 deregistering, which we don't do). *)
1174 let (id, method_) =
1175 match registerOptions with
1176 | DidChangeWatchedFilesRegistrationOptions _ ->
1177 ("did-change-watched-files", "workspace/didChangeWatchedFiles")
1179 { id; method_; registerOptions }
1183 * Here are gathered-up ADTs for all the messages we handle
1186 type lsp_request =
1187 | InitializeRequest of Initialize.params
1188 | RegisterCapabilityRequest of RegisterCapability.params
1189 | ShutdownRequest
1190 | CodeLensResolveRequest of CodeLensResolve.params
1191 | HoverRequest of Hover.params
1192 | DefinitionRequest of Definition.params
1193 | TypeDefinitionRequest of TypeDefinition.params
1194 | ImplementationRequest of Implementation.params
1195 | CodeActionRequest of CodeActionRequest.params
1196 | CompletionRequest of Completion.params
1197 | CompletionItemResolveRequest of CompletionItemResolve.params
1198 | WorkspaceSymbolRequest of WorkspaceSymbol.params
1199 | DocumentSymbolRequest of DocumentSymbol.params
1200 | FindReferencesRequest of FindReferences.params
1201 | DocumentHighlightRequest of DocumentHighlight.params
1202 | TypeCoverageRequestFB of TypeCoverageFB.params
1203 | DocumentFormattingRequest of DocumentFormatting.params
1204 | DocumentRangeFormattingRequest of DocumentRangeFormatting.params
1205 | DocumentOnTypeFormattingRequest of DocumentOnTypeFormatting.params
1206 | ShowMessageRequestRequest of ShowMessageRequest.params
1207 | ShowStatusRequestFB of ShowStatusFB.params
1208 | RageRequestFB
1209 | RenameRequest of Rename.params
1210 | DocumentCodeLensRequest of DocumentCodeLens.params
1211 | SignatureHelpRequest of SignatureHelp.params
1212 | HackTestStartServerRequestFB
1213 | HackTestStopServerRequestFB
1214 | HackTestShutdownServerlessRequestFB
1215 | WillSaveWaitUntilRequest of WillSaveWaitUntil.params
1216 | UnknownRequest of string * Hh_json.json option
1218 type lsp_result =
1219 | InitializeResult of Initialize.result
1220 | ShutdownResult
1221 | CodeLensResolveResult of CodeLensResolve.result
1222 | HoverResult of Hover.result
1223 | DefinitionResult of Definition.result
1224 | TypeDefinitionResult of TypeDefinition.result
1225 | ImplementationResult of Implementation.result
1226 | CodeActionResult of CodeAction.result
1227 | CompletionResult of Completion.result
1228 | CompletionItemResolveResult of CompletionItemResolve.result
1229 | WorkspaceSymbolResult of WorkspaceSymbol.result
1230 | DocumentSymbolResult of DocumentSymbol.result
1231 | FindReferencesResult of FindReferences.result
1232 | DocumentHighlightResult of DocumentHighlight.result
1233 | TypeCoverageResultFB of TypeCoverageFB.result
1234 | DocumentFormattingResult of DocumentFormatting.result
1235 | DocumentRangeFormattingResult of DocumentRangeFormatting.result
1236 | DocumentOnTypeFormattingResult of DocumentOnTypeFormatting.result
1237 | ShowMessageRequestResult of ShowMessageRequest.result
1238 | ShowStatusResultFB of ShowStatusFB.result
1239 | RageResultFB of RageFB.result
1240 | RenameResult of Rename.result
1241 | DocumentCodeLensResult of DocumentCodeLens.result
1242 | SignatureHelpResult of SignatureHelp.result
1243 | HackTestStartServerResultFB
1244 | HackTestStopServerResultFB
1245 | HackTestShutdownServerlessResultFB
1246 | RegisterCapabilityRequestResult
1247 | WillSaveWaitUntilResult of WillSaveWaitUntil.result
1248 | ErrorResult of Error.t
1250 type lsp_notification =
1251 | ExitNotification
1252 | CancelRequestNotification of CancelRequest.params
1253 | PublishDiagnosticsNotification of PublishDiagnostics.params
1254 | DidOpenNotification of DidOpen.params
1255 | DidCloseNotification of DidClose.params
1256 | DidSaveNotification of DidSave.params
1257 | DidChangeNotification of DidChange.params
1258 | DidChangeWatchedFilesNotification of DidChangeWatchedFiles.params
1259 | LogMessageNotification of LogMessage.params
1260 | TelemetryNotification of LogMessage.params * (string * Hh_json.json) list
1261 (** For telemetry, LSP allows 'any', but we're going to send params+list *)
1262 | ShowMessageNotification of ShowMessage.params
1263 | ConnectionStatusNotificationFB of ConnectionStatusFB.params
1264 | InitializedNotification
1265 | SetTraceNotification of SetTraceNotification.params
1266 | LogTraceNotification (* $/logTraceNotification *)
1267 | ToggleTypeCoverageNotificationFB of ToggleTypeCoverageFB.params
1268 | UnknownNotification of string * Hh_json.json option
1270 type lsp_message =
1271 | RequestMessage of lsp_id * lsp_request
1272 | ResponseMessage of lsp_id * lsp_result
1273 | NotificationMessage of lsp_notification
1275 type 'a lsp_handler = 'a lsp_result_handler * 'a lsp_error_handler
1277 and 'a lsp_error_handler = Error.t * string -> 'a -> 'a
1279 and 'a lsp_result_handler =
1280 | ShowMessageHandler of (ShowMessageRequest.result -> 'a -> 'a)
1281 | ShowStatusHandler of (ShowStatusFB.result -> 'a -> 'a)
1283 module IdKey = struct
1284 type t = lsp_id
1286 let compare (x : t) (y : t) =
1287 match (x, y) with
1288 | (NumberId x, NumberId y) -> x - y
1289 | (NumberId _, StringId _) -> -1
1290 | (StringId x, StringId y) -> String.compare x y
1291 | (StringId _, NumberId _) -> 1
1294 module IdSet = Set.Make (IdKey)
1295 module IdMap = WrappedMap.Make (IdKey)
1297 module UriKey = struct
1298 type t = documentUri
1300 let compare (DocumentUri x) (DocumentUri y) = String.compare x y
1303 module UriSet = Set.Make (UriKey)
1304 module UriMap = WrappedMap.Make (UriKey)