Add LSP telemetry message for hh_server busy status
[hiphop-php.git] / hphp / hack / src / utils / lsp / lsp.ml
blobd53ea9519462a244cb84c2242a9d73e53a21d8c3
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 = string
49 (* A position is between two characters like an 'insert' cursor in a editor *)
50 type position = {
51 line: int; (* line position in a document [zero-based] *)
52 character: int; (* character offset on a line in a document [zero-based] *)
55 (* A range is comparable to a selection in an editor *)
56 type range = {
57 start: position; (* the range's start position *)
58 end_: position; (* the range's end position [exclusive] *)
61 (* Represents a location inside a resource, such as a line inside a text file *)
62 module Location = struct
63 type t = {
64 uri: documentUri;
65 range: range;
67 end
69 (* Represents a location inside a resource which also wants to display a
70 friendly name to the user. *)
71 module DefinitionLocation = struct
72 type t = {
73 location: Location.t;
74 title: string option;
76 end
78 (* markedString can be used to render human readable text. It is either a
79 * markdown string or a code-block that provides a language and a code snippet.
80 * Note that markdown strings will be sanitized by the client - including
81 * escaping html *)
82 type markedString =
83 | MarkedString of string
84 | MarkedCode of string * string (* lang, value *)
86 (* Represents a reference to a command. Provides a title which will be used to
87 * represent a command in the UI. Commands are identitifed using a string
88 * identifier and the protocol currently doesn't specify a set of well known
89 * commands. So executing a command requires some tool extension code. *)
90 module Command = struct
91 type t = {
92 title: string; (* title of the command, like `save` *)
93 command: string; (* the identifier of the actual command handler *)
94 arguments: Hh_json.json list; (* wire: it can be omitted *)
96 end
98 (* A textual edit applicable to a text document. If n textEdits are applied
99 to a text document all text edits describe changes to the initial document
100 version. Execution wise text edits should applied from the bottom to the
101 top of the text document. Overlapping text edits are not supported. *)
102 module TextEdit = struct
103 type t = {
104 range: range; (* to insert text, use a range where start = end *)
105 newText: string; (* for delete operations, use an empty string *)
109 (* Text documents are identified using a URI. *)
110 module TextDocumentIdentifier = struct
111 type t = {
112 uri: documentUri; (* the text document's URI *)
116 (* An identifier to denote a specific version of a text document. *)
117 module VersionedTextDocumentIdentifier = struct
118 type t = {
119 uri: documentUri; (* the text document's URI *)
120 version: int; (* the version number of this document *)
124 (* Describes textual changes on a single text document. The text document is
125 referred to as a VersionedTextDocumentIdentifier to allow clients to check
126 the text document version before an edit is applied. *)
127 module TextDocumentEdit = struct
128 type t = {
129 textDocument: VersionedTextDocumentIdentifier.t;
130 edits: TextEdit.t list;
134 (* A workspace edit represents changes to many resources managed in the
135 workspace. A workspace edit consists of a mapping from a URI to an
136 array of TextEdits to be applied to the document with that URI. *)
137 module WorkspaceEdit = struct
138 type t = {
139 changes: TextEdit.t list SMap.t; (* holds changes to existing docs *)
143 (* An item to transfer a text document from the client to the server. The
144 version number strictly increases after each change, including undo/redo. *)
145 module TextDocumentItem = struct
146 type t = {
147 uri: documentUri; (* the text document's URI *)
148 languageId: string; (* the text document's language identifier *)
149 version: int; (* the version of the document *)
150 text: string; (* the content of the opened text document *)
155 * A code lens represents a command that should be shown along with
156 * source text, like the number of references, a way to run tests, etc.
158 * A code lens is _unresolved_ when no command is associated to it. For performance
159 * reasons the creation of a code lens and resolving should be done in two stages.
161 module CodeLens = struct
162 type t = {
163 range: range;
164 command: Command.t;
165 data: Hh_json.json option;
169 (* A parameter literal used in requests to pass a text document and a position
170 inside that document. *)
171 module TextDocumentPositionParams = struct
172 type t = {
173 textDocument: TextDocumentIdentifier.t; (* the text document *)
174 position: position; (* the position inside the text document *)
178 (* A document filter denotes a document through properties like language,
179 schema or pattern. E.g. language:"typescript",scheme:"file"
180 or language:"json",pattern:"**/package.json" *)
181 module DocumentFilter = struct
182 type t = {
183 language: string option; (* a language id, like "typescript" *)
184 scheme: string option; (* a uri scheme, like "file" or "untitled" *)
185 pattern: string option; (* a glob pattern, like "*.{ts,js}" *)
189 (* A document selector is the combination of one or many document filters. *)
190 module DocumentSelector = struct
191 type t = DocumentFilter.t list
195 (* Represents information about programming constructs like variables etc. *)
196 module SymbolInformation = struct
197 type t = {
198 name: string;
199 kind: symbolKind;
200 location: Location.t; (* the span of the symbol including its contents *)
201 containerName: string option; (* the symbol containing this symbol *)
204 and symbolKind =
205 | File (* 1 *)
206 | Module (* 2 *)
207 | Namespace (* 3 *)
208 | Package (* 4 *)
209 | Class (* 5 *)
210 | Method (* 6 *)
211 | Property (* 7 *)
212 | Field (* 8 *)
213 | Constructor (* 9 *)
214 | Enum (* 10 *)
215 | Interface (* 11 *)
216 | Function (* 12 *)
217 | Variable (* 13 *)
218 | Constant (* 14 *)
219 | String (* 15 *)
220 | Number (* 16 *)
221 | Boolean (* 17 *)
222 | Array (* 18 *)
226 (* For showing messages (not diagnostics) in the user interface. *)
227 module MessageType = struct
228 type t =
229 | ErrorMessage (* 1 *)
230 | WarningMessage (* 2 *)
231 | InfoMessage (* 3 *)
232 | LogMessage (* 4 *)
235 module CodeActionKind = struct
236 (* The kind of a code action.
237 * Kinds are a hierarchical list of identifiers separated by `.`, e.g.
238 * `"refactor.extract.function"`.
239 * The set of kinds is open and client needs to announce the kinds it supports
240 * to the server during initialization.
241 * CodeActionKind.t uses a pair to represent a non-empty list and provides utility
242 * functions for creation, membership, printing.
243 * Module CodeAction below also references this module as Kind.
245 type t = (string * string list)
247 (* is x of kind k? *)
248 let is_kind : t -> t -> bool =
249 let rec is_prefix_of ks xs =
250 match ks, xs with
251 | [], _ -> true
252 | (k :: ks), (x :: xs) when String.equal k x -> is_prefix_of ks xs
253 | _, _ -> false in
254 fun (k, ks) (x, xs) -> String.equal k x && is_prefix_of ks xs
256 (* does `ks` contain kind `k` *)
257 let contains_kind k ks = List.exists (is_kind k) ks
259 (* does an optional list of kinds `ks` contain kind `k` *)
260 let contains_kind_opt ~default k ks =
261 match ks with
262 | Some ks -> contains_kind k ks
263 | None -> default
265 (* Create a kind from a string that follows the spec *)
266 let kind_of_string : string -> t =
267 fun s ->
268 match String.split_on_char '.' s with
269 | [] -> failwith "split_on_char does not return an empty list"
270 | (k :: ks) -> (k, ks)
272 (* Create the equivalent string that the spec would have required *)
273 let string_of_kind : t -> string =
274 fun (k, ks) -> String.concat "." (k :: ks)
276 (* Create a new sub-kind of an existing kind *)
277 let sub_kind : t -> string -> t =
278 let cons_to_end (ss : string list) (s : string) =
279 Core_list.(fold_right ss ~f:cons ~init:[s]) in
280 fun (k, ks) s -> (k, cons_to_end ks s)
282 (* Some of the constants defined by the spec *)
283 let quickfix = kind_of_string "quickfix"
285 (* Document wide code actions *)
286 let source = kind_of_string "source"
289 (* Cancellation notification, method="$/cancelRequest" *)
290 module CancelRequest = struct
291 type params = cancelParams
293 and cancelParams = {
294 id: lsp_id; (* the request id to cancel *)
298 (* Initialize request, method="initialize" *)
299 module Initialize = struct
300 type params = {
301 processId: int option; (* pid of parent process *)
302 rootPath: string option; (* deprecated *)
303 rootUri: documentUri option; (* the root URI of the workspace *)
304 initializationOptions: initializationOptions;
305 client_capabilities: client_capabilities; (* "capabilities" over wire *)
306 trace: trace; (* the initial trace setting, default="off" *)
309 and result = {
310 server_capabilities: server_capabilities; (* "capabilities" over wire *)
313 and errorData = {
314 retry: bool; (* should client retry the initialize request *)
317 and trace =
318 | Off
319 | Messages
320 | Verbose
322 (* Following initialization options are unfortunately a mix of Hack
323 * and Flow. We should find a way to separate them.
324 * Anyway, they're all optional in the source json, but we pick
325 * a default if necessary while parsing. *)
326 and initializationOptions = {
327 useTextEditAutocomplete: bool; (* only supported for Hack so far *)
328 liveSyntaxErrors: bool; (* implicitly true for Hack; supported in Flow *)
329 namingTableSavedStatePath: string option; (* only supported for Hack *)
330 sendServerStatusEvents: bool; (* only supported for Hack *)
333 and client_capabilities = {
334 workspace: workspaceClientCapabilities;
335 textDocument: textDocumentClientCapabilities;
336 window: windowClientCapabilities;
337 telemetry: telemetryClientCapabilities;
338 (* omitted: experimental *)
341 and workspaceClientCapabilities = {
342 applyEdit: bool; (* client supports appling batch edits *)
343 workspaceEdit: workspaceEdit;
345 didChangeWatchedFiles: dynamicRegistration;
346 (* omitted: other dynamic-registration fields *)
349 and dynamicRegistration = {
350 dynamicRegistration: bool; (* client supports dynamic registration for this capability *)
353 and workspaceEdit = {
354 documentChanges: bool; (* client supports versioned doc changes *)
357 and textDocumentClientCapabilities = {
358 synchronization: synchronization;
359 completion: completion; (* textDocument/completion *)
360 codeAction: codeAction;
361 (* omitted: dynamic-registration fields *)
364 (* synchronization capabilities say what messages the client is capable
365 * of sending, should be be so asked by the server.
366 * We use the "can_" prefix for OCaml naming reasons; it's absent in LSP *)
367 and synchronization = {
368 can_willSave: bool; (* client can send textDocument/willSave *)
369 can_willSaveWaitUntil: bool; (* textDoc.../willSaveWaitUntil *)
370 can_didSave: bool; (* textDocument/didSave *)
373 and completion = {
374 completionItem: completionItem;
377 and completionItem = {
378 snippetSupport: bool; (* client can do snippets as insert text *)
381 and codeAction = {
382 (* Whether code action supports dynamic registration. *)
383 codeAction_dynamicRegistration : bool; (* wire: dynamicRegistraction *)
384 (* The client support code action literals as a valid
385 * response of the `textDocument/codeAction` request. *)
386 codeActionLiteralSupport : codeActionliteralSupport option;
389 and codeActionliteralSupport = {
390 (* The code action kind values the client supports. When this
391 * property exists the client also guarantees that it will
392 * handle values outside its set gracefully and falls back
393 * to a default value when unknown. *)
394 codeAction_valueSet: CodeActionKind.t list (* wire: valueSet *)
397 and windowClientCapabilities = {
398 status: bool; (* Nuclide-specific: client supports window/showStatusRequest *)
399 progress: bool; (* Nuclide-specific: client supports window/progress *)
400 actionRequired: bool; (* Nuclide-specific: client supports window/actionRequired *)
403 and telemetryClientCapabilities = {
404 connectionStatus: bool; (* Nuclide-specific: client supports telemetry/connectionStatus *)
407 (* What capabilities the server provides *)
408 and server_capabilities = {
409 textDocumentSync: textDocumentSyncOptions; (* how to sync *)
410 hoverProvider: bool;
411 completionProvider: completionOptions option;
412 signatureHelpProvider: signatureHelpOptions option;
413 definitionProvider: bool;
414 typeDefinitionProvider: bool;
415 referencesProvider: bool;
416 documentHighlightProvider: bool;
417 documentSymbolProvider: bool; (* ie. document outline *)
418 workspaceSymbolProvider: bool; (* ie. find-symbol-in-project *)
419 codeActionProvider: bool;
420 codeLensProvider: codeLensOptions option;
421 documentFormattingProvider: bool;
422 documentRangeFormattingProvider: bool;
423 documentOnTypeFormattingProvider: documentOnTypeFormattingOptions option;
424 renameProvider: bool;
425 documentLinkProvider: documentLinkOptions option;
426 executeCommandProvider: executeCommandOptions option;
427 typeCoverageProvider: bool; (* Nuclide-specific feature *)
428 rageProvider: bool;
429 (* omitted: experimental *)
432 and completionOptions = {
433 resolveProvider: bool; (* server resolves extra info on demand *)
434 completion_triggerCharacters: string list; (* wire "triggerCharacters" *)
437 and signatureHelpOptions = {
438 sighelp_triggerCharacters: string list; (* wire "triggerCharacters" *)
441 and codeLensOptions = {
442 codelens_resolveProvider: bool; (* wire "resolveProvider" *)
445 and documentOnTypeFormattingOptions = {
446 firstTriggerCharacter: string; (* e.g. "}" *)
447 moreTriggerCharacter: string list;
450 and documentLinkOptions = {
451 doclink_resolveProvider: bool; (* wire "resolveProvider" *)
454 and executeCommandOptions = {
455 commands: string list; (* the commands to be executed on the server *)
458 (* text document sync options say what messages the server requests the
459 * client to send. We use the "want_" prefix for OCaml naming reasons;
460 * this prefix is absent in LSP. *)
461 and textDocumentSyncOptions = {
462 want_openClose: bool; (* textDocument/didOpen+didClose *)
463 want_change: textDocumentSyncKind;
464 want_willSave: bool; (* textDocument/willSave *)
465 want_willSaveWaitUntil: bool; (* textDoc.../willSaveWaitUntil *)
466 want_didSave: saveOptions option; (* textDocument/didSave *)
469 and textDocumentSyncKind =
470 | NoSync (* 0 *) (* docs should not be synced at all. Wire "None" *)
471 | FullSync (* 1 *) (* synced by always sending full content. Wire "Full" *)
472 | IncrementalSync (* 2 *) (* full only on open. Wire "Incremental" *)
474 and saveOptions = {
475 includeText: bool; (* the client should include content on save *)
479 (* Shutdown request, method="shutdown" *)
480 module Shutdown = struct
483 (* Exit notification, method="exit" *)
484 module Exit = struct
487 (* Rage request, method="telemetry/rage" *)
488 module Rage = struct
489 type result = rageItem list
491 and rageItem = {
492 title: string option;
493 data: string;
497 (* Code Lens resolve request, method="codeLens/resolve" *)
498 module CodeLensResolve = struct
499 type params = CodeLens.t
501 and result = CodeLens.t
504 (* Hover request, method="textDocument/hover" *)
505 module Hover = struct
506 type params = TextDocumentPositionParams.t
508 and result = hoverResult option
510 and hoverResult = {
511 contents: markedString list; (* wire: either a single one or an array *)
512 range: range option;
516 (* PublishDiagnostics notification, method="textDocument/PublishDiagnostics" *)
517 module PublishDiagnostics = struct
519 type diagnosticSeverity =
520 | Error [@value 1]
521 | Warning [@value 2]
522 | Information [@value 3]
523 | Hint [@value 4]
524 [@@ deriving enum]
526 type params = publishDiagnosticsParams
528 and publishDiagnosticsParams = {
529 uri: documentUri;
530 diagnostics: diagnostic list;
533 and diagnostic = {
534 range: range; (* the range at which the message applies *)
535 severity: diagnosticSeverity option; (* if omitted, client decides *)
536 code: diagnosticCode; (* the diagnostic's code. *)
537 source: string option; (* human-readable string, eg. typescript/lint *)
538 message: string; (* the diagnostic's message *)
539 relatedInformation: diagnosticRelatedInformation list;
540 relatedLocations: relatedLocation list; (* legacy FB extension *)
543 and diagnosticCode =
544 | IntCode of int
545 | StringCode of string
546 | NoCode
549 and diagnosticRelatedInformation = {
550 relatedLocation: Location.t; (* wire: just "location" *)
551 relatedMessage: string; (* wire: just "message" *)
554 (* legacy FB extension *)
555 and relatedLocation = diagnosticRelatedInformation
558 (* DidOpenTextDocument notification, method="textDocument/didOpen" *)
559 module DidOpen = struct
560 type params = didOpenTextDocumentParams
562 and didOpenTextDocumentParams = {
563 textDocument: TextDocumentItem.t; (* the document that was opened *)
567 (* DidCloseTextDocument notification, method="textDocument/didClose" *)
568 module DidClose = struct
569 type params = didCloseTextDocumentParams
571 and didCloseTextDocumentParams = {
572 textDocument: TextDocumentIdentifier.t; (* the doc that was closed *)
576 (* DidSaveTextDocument notification, method="textDocument/didSave" *)
577 module DidSave = struct
578 type params = didSaveTextDocumentParams
580 and didSaveTextDocumentParams = {
581 textDocument: TextDocumentIdentifier.t; (* the doc that was saved *)
582 text: string option; (* content when saved; depends on includeText *)
586 (* DidChangeTextDocument notification, method="textDocument/didChange" *)
587 module DidChange = struct
588 type params = didChangeTextDocumentParams
590 and didChangeTextDocumentParams = {
591 textDocument: VersionedTextDocumentIdentifier.t;
592 contentChanges: textDocumentContentChangeEvent list;
595 and textDocumentContentChangeEvent = {
596 range: range option; (* the range of the document that changed *)
597 rangeLength: int option; (* the length that got replaced *)
598 text: string; (* the new text of the range/document *)
602 (* Watched files changed notification, method="workspace/didChangeWatchedFiles" *)
603 module DidChangeWatchedFiles = struct
604 type registerOptions = {
605 watchers: fileSystemWatcher list;
608 and fileSystemWatcher = {
609 globPattern: string;
612 type fileChangeType =
613 | Created [@value 1]
614 | Updated [@value 2]
615 | Deleted [@value 3]
616 [@@deriving enum]
618 type params = {
619 changes: fileEvent list;
622 and fileEvent = {
623 uri: documentUri;
624 type_: fileChangeType;
628 (* Goto Definition request, method="textDocument/definition" *)
629 module Definition = struct
630 type params = TextDocumentPositionParams.t
632 and result = DefinitionLocation.t list (* wire: either a single one or an array *)
635 (* Goto TypeDefinition request, method="textDocument/typeDefinition" *)
636 module TypeDefinition = struct
637 type params = TextDocumentPositionParams.t
639 and result = DefinitionLocation.t list
642 module CodeAction = struct
643 (* A code action represents a change that can be performed in code, e.g. to fix a problem or
644 to refactor code. *)
645 type t = {
646 (* A short, human-readable, title for this code action. *)
647 title: string;
648 (* The kind of the code action. Used to filter code actions. *)
649 kind: CodeActionKind.t;
650 (* The diagnostics that this code action resolves. *)
651 diagnostics: PublishDiagnostics.diagnostic list;
652 (* A CodeAction must set either `edit` and/or a `command`.
653 If both are supplied, the `edit` is applied first, then the `command` is executed. *)
654 action : edit_and_or_command;
657 and edit_and_or_command =
658 | EditOnly of WorkspaceEdit.t
659 | CommandOnly of Command.t
660 | BothEditThenCommand of (WorkspaceEdit.t * Command.t)
662 type result = command_or_action list
664 and command_or_action =
665 | Command of Command.t
666 | Action of t
669 (* Code Action Request, method="textDocument/codeAction" *)
670 module CodeActionRequest = struct
671 type params = {
672 (* The document in which the command was invoked. *)
673 textDocument: TextDocumentIdentifier.t;
674 (* The range for which the command was invoked. *)
675 range: range;
676 (* Context carrying additional information. *)
677 context: codeActionContext;
680 (* Contains additional diagnostic information about the context in which
681 a code action is run. *)
682 and codeActionContext = {
683 diagnostics: PublishDiagnostics.diagnostic list;
684 only: CodeActionKind.t list option
688 (* Completion request, method="textDocument/completion" *)
689 module Completion = struct
690 (* These numbers should match
691 * https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
693 type completionItemKind =
694 | Text [@value 1]
695 | Method [@value 2]
696 | Function [@value 3]
697 | Constructor [@value 4]
698 | Field [@value 5]
699 | Variable [@value 6]
700 | Class [@value 7]
701 | Interface [@value 8]
702 | Module [@value 9]
703 | Property [@value 10]
704 | Unit [@value 11]
705 | Value [@value 12]
706 | Enum [@value 13]
707 | Keyword [@value 14]
708 | Snippet [@value 15]
709 | Color [@value 16]
710 | File [@value 17]
711 | Reference [@value 18]
712 | Folder [@value 19]
713 | EnumMember [@value 20]
714 | Constant [@value 21]
715 | Struct [@value 22]
716 | Event [@value 23]
717 | Operator [@value 24]
718 | TypeParameter [@value 25]
719 [@@deriving enum]
721 (* These numbers should match
722 * https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
724 type insertTextFormat =
725 | PlainText [@value 1] (* the insertText/textEdits are just plain strings *)
726 | SnippetFormat [@value 2] (* wire: just "Snippet" *)
727 [@@deriving enum]
729 type params = completionParams
731 and completionParams = {
732 loc: TextDocumentPositionParams.t;
733 context: completionContext option;
736 and completionContext = {
737 triggerKind: completionTriggerKind;
740 and completionTriggerKind =
741 | Invoked (* 1 *)
742 | TriggerCharacter (* 2 *)
743 | TriggerForIncompleteCompletions (* 3 *)
745 and result = completionList (* wire: can also be 'completionItem list' *)
747 and completionList = {
748 isIncomplete: bool; (* further typing should result in recomputing *)
749 items: completionItem list;
752 and completionItem = {
753 label: string; (* the label in the UI *)
754 kind: completionItemKind option; (* tells editor which icon to use *)
755 detail: string option; (* human-readable string like type/symbol info *)
756 inlineDetail: string option; (* nuclide-specific, right column *)
757 itemType: string option; (* nuclide-specific, left column *)
758 documentation: markedString list option; (* human-readable doc-comment *)
759 sortText: string option; (* used for sorting; if absent, uses label *)
760 filterText: string option; (* used for filtering; if absent, uses label *)
761 insertText: string option; (* used for inserting; if absent, uses label *)
762 insertTextFormat: insertTextFormat option;
763 textEdits: TextEdit.t list; (* wire: split into hd and tl *)
764 command: Command.t option; (* if present, is executed after completion *)
765 data: Hh_json.json option;
771 (* Completion Item Resolve request, method="completionItem/resolve" *)
772 module CompletionItemResolve = struct
773 type params = Completion.completionItem
775 and result = Completion.completionItem
779 (* Workspace Symbols request, method="workspace/symbol" *)
780 module WorkspaceSymbol = struct
781 type params = workspaceSymbolParams
783 and result = SymbolInformation.t list
785 and workspaceSymbolParams = {
786 query: string; (* a non-empty query string *)
791 (* Document Symbols request, method="textDocument/documentSymbols" *)
792 module DocumentSymbol = struct
793 type params = documentSymbolParams
795 and result = SymbolInformation.t list
797 and documentSymbolParams = {
798 textDocument: TextDocumentIdentifier.t;
803 (* Find References request, method="textDocument/references" *)
804 module FindReferences = struct
805 type params = referenceParams
807 and result = Location.t list
809 and referenceParams = {
810 loc: TextDocumentPositionParams.t; (* wire: loc's members are part of referenceParams *)
811 context: referenceContext;
814 and referenceContext = {
815 includeDeclaration: bool; (* include declaration of current symbol *)
816 includeIndirectReferences: bool;
821 (* Document Highlights request, method="textDocument/documentHighlight" *)
822 module DocumentHighlight = struct
823 type params = TextDocumentPositionParams.t
825 and result = documentHighlight list
827 and documentHighlight = {
828 range: range; (* the range this highlight applies to *)
829 kind: documentHighlightKind option;
832 and documentHighlightKind =
833 | Text (* 1 *) (* a textual occurrence *)
834 | Read (* 2 *) (* read-access of a symbol, like reading a variable *)
835 | Write (* 3 *) (* write-access of a symbol, like writing a variable *)
839 (* Type Coverage request, method="textDocument/typeCoverage" *)
840 (* THIS IS A NUCLIDE-SPECIFIC EXTENSION TO LSP. *)
841 module TypeCoverage = struct
842 type params = typeCoverageParams
844 and result = {
845 coveredPercent: int;
846 uncoveredRanges: uncoveredRange list;
847 defaultMessage: string;
850 and typeCoverageParams = {
851 textDocument: TextDocumentIdentifier.t;
854 and uncoveredRange = {
855 range: range;
856 message: string option;
861 (* Document Formatting request, method="textDocument/formatting" *)
862 module DocumentFormatting = struct
863 type params = documentFormattingParams
865 and result = TextEdit.t list
867 and documentFormattingParams = {
868 textDocument: TextDocumentIdentifier.t;
869 options: formattingOptions;
872 and formattingOptions = {
873 tabSize: int; (* size of a tab in spaces *)
874 insertSpaces: bool; (* prefer spaces over tabs *)
875 (* omitted: signature for further properties *)
880 (* Document Range Formatting request, method="textDocument/rangeFormatting" *)
881 module DocumentRangeFormatting = struct
882 type params = documentRangeFormattingParams
884 and result = TextEdit.t list
886 and documentRangeFormattingParams = {
887 textDocument: TextDocumentIdentifier.t;
888 range: range;
889 options: DocumentFormatting.formattingOptions;
894 (* Document On Type Formatting req., method="textDocument/onTypeFormatting" *)
895 module DocumentOnTypeFormatting = struct
896 type params = documentOnTypeFormattingParams
898 and result = TextEdit.t list
900 and documentOnTypeFormattingParams = {
901 textDocument: TextDocumentIdentifier.t;
902 position: position; (* the position at which this request was sent *)
903 ch: string; (* the character that has been typed *)
904 options: DocumentFormatting.formattingOptions;
909 (* Document Signature Help request, method="textDocument/signatureHelp" *)
910 module SignatureHelp = struct
911 type params = TextDocumentPositionParams.t
913 and result = t option
915 and t = {
916 signatures: signature_information list;
917 activeSignature: int;
918 activeParameter: int;
921 and signature_information = {
922 siginfo_label: string;
923 siginfo_documentation: string option;
924 parameters: parameter_information list;
927 and parameter_information = {
928 parinfo_label: string;
929 parinfo_documentation: string option;
933 (* Workspace Rename request, method="textDocument/rename" *)
934 module Rename = struct
935 type params = renameParams
937 and result = WorkspaceEdit.t
939 and renameParams = {
940 textDocument: TextDocumentIdentifier.t;
941 position: position;
942 newName: string;
946 (* Code Lens request, method="textDocument/codeLens" *)
947 module DocumentCodeLens = struct
948 type params = codelensParams
950 and result = CodeLens.t list
952 and codelensParams = {
953 textDocument: TextDocumentIdentifier.t;
957 (* LogMessage notification, method="window/logMessage" *)
958 module LogMessage = struct
959 type params = logMessageParams
961 and logMessageParams = {
962 type_: MessageType.t;
963 message: string;
968 (* ShowMessage notification, method="window/showMessage" *)
969 module ShowMessage = struct
970 type params = showMessageParams
972 and showMessageParams = {
973 type_: MessageType.t;
974 message: string;
979 (* ShowMessage request, method="window/showMessageRequest" *)
980 module ShowMessageRequest = struct
981 type t = Present of {id: lsp_id;} | Absent
983 and params = showMessageRequestParams
985 and result = messageActionItem option
987 and showMessageRequestParams = {
988 type_: MessageType.t;
989 message: string;
990 actions: messageActionItem list;
993 and messageActionItem = {
994 title: string;
999 (* ShowStatus request, method="window/showStatus" *)
1000 module ShowStatus = struct
1001 type params = showStatusParams
1003 and result = ShowMessageRequest.messageActionItem option
1005 and showStatusParams = {
1006 request: ShowMessageRequest.showMessageRequestParams;
1007 progress: int option;
1008 total: int option;
1009 shortMessage: string option;
1014 (* Progress notification, method="window/progress" *)
1015 module Progress = struct
1016 type t = Present of {id: int; label: string;} | Absent
1018 and params = progressParams
1020 and progressParams = {
1021 (* LSP progress notifications have a lifetime that starts with their 1st *)
1022 (* window/progress update message and ends with an update message with *)
1023 (* label = None. They use an ID number (not JsonRPC id) to associate *)
1024 (* multiple messages to a single lifetime stream. *)
1025 id: int;
1026 label: string option;
1031 (* ActionRequired notification, method="window/actionRequired" *)
1032 module ActionRequired = struct
1033 type t = Present of {id: int; label: string;} | Absent
1035 and params = actionRequiredParams
1037 and actionRequiredParams = {
1038 (* See progressParams.id for an explanation of this field. *)
1039 id: int;
1040 label: string option;
1045 (* ConnectionStatus notification, method="telemetry/connectionStatus" *)
1046 module ConnectionStatus = struct
1047 type params = connectionStatusParams
1049 and connectionStatusParams = {
1050 isConnected: bool;
1055 (* Module for dynamic view, method="workspace/toggleTypeCoverage" *)
1056 module ToggleTypeCoverage = struct
1057 type params = toggleTypeCoverageParams
1058 and toggleTypeCoverageParams = {
1059 toggle: bool;
1063 (* ErrorResponse *)
1064 module Error = struct
1065 type t = {code: int; message: string; data: Hh_json.json option}
1067 (* Legacy: some code uses exceptions instead of Error.t. *)
1068 (* Be careful with that since if you unmarshal one then you can't pattern-match it. *)
1070 (* Defined by JSON-RPC. *)
1071 exception Parse of string (* -32700 *)
1072 exception InvalidRequest of string (* -32600 *)
1073 exception MethodNotFound of string (* -32601 *)
1074 exception InvalidParams of string (* -32602 *)
1075 exception InternalError of string (* -32603 *)
1076 exception ServerErrorStart of string * Initialize.errorData (* -32099 *)
1077 exception ServerErrorEnd of string (* -32000 *)
1078 exception ServerNotInitialized of string (* -32002 *)
1079 exception Unknown of string (* -32001 *)
1081 (* Defined by the protocol. *)
1082 exception RequestCancelled of string (* -32800 *)
1084 module Code = struct
1085 (* Defined by JSON RPC *)
1086 let parseError = -32700
1087 let invalidRequest = -32600
1088 let methodNotFound = -32601
1089 let invalidParams = -32602
1090 let internalError = -32603
1091 let serverErrorStart = -32099
1092 let serverErrorEnd = -32000
1093 let serverNotInitialized = -32002
1094 let unknownErrorCode = -32001
1096 (* Defined by the protocol. *)
1097 let requestCancelled = -32800
1098 let contentModified = -32801
1102 type lsp_registration_options =
1103 | DidChangeWatchedFilesRegistrationOptions of
1104 DidChangeWatchedFiles.registerOptions
1106 (* Register capability request, method="client/registerCapability" *)
1107 module RegisterCapability = struct
1108 type params = {
1109 registrations: registration list;
1112 and registration = {
1113 id: string;
1114 method_: string;
1115 registerOptions: lsp_registration_options;
1118 let make_registration
1119 (registerOptions: lsp_registration_options)
1120 : registration =
1121 (* The ID field is arbitrary but unique per type of capability (for future
1122 deregistering, which we don't do). *)
1123 let (id, method_) =
1124 match registerOptions with
1125 | DidChangeWatchedFilesRegistrationOptions _ ->
1126 ("did-change-watched-files", "workspace/didChangeWatchedFiles")
1128 { id; method_; registerOptions }
1133 * Here are gathered-up ADTs for all the messages we handle
1136 type lsp_request =
1137 | InitializeRequest of Initialize.params
1138 | RegisterCapabilityRequest of RegisterCapability.params
1139 | ShutdownRequest
1140 | CodeLensResolveRequest of CodeLensResolve.params
1141 | HoverRequest of Hover.params
1142 | DefinitionRequest of Definition.params
1143 | TypeDefinitionRequest of TypeDefinition.params
1144 | CodeActionRequest of CodeActionRequest.params
1145 | CompletionRequest of Completion.params
1146 | CompletionItemResolveRequest of CompletionItemResolve.params
1147 | WorkspaceSymbolRequest of WorkspaceSymbol.params
1148 | DocumentSymbolRequest of DocumentSymbol.params
1149 | FindReferencesRequest of FindReferences.params
1150 | DocumentHighlightRequest of DocumentHighlight.params
1151 | TypeCoverageRequest of TypeCoverage.params
1152 | DocumentFormattingRequest of DocumentFormatting.params
1153 | DocumentRangeFormattingRequest of DocumentRangeFormatting.params
1154 | DocumentOnTypeFormattingRequest of DocumentOnTypeFormatting.params
1155 | ShowMessageRequestRequest of ShowMessageRequest.params
1156 | ShowStatusRequest of ShowStatus.params
1157 | RageRequest
1158 | RenameRequest of Rename.params
1159 | DocumentCodeLensRequest of DocumentCodeLens.params
1160 | UnknownRequest of string * Hh_json.json option
1162 type lsp_result =
1163 | InitializeResult of Initialize.result
1164 | ShutdownResult
1165 | CodeLensResolveResult of CodeLensResolve.result
1166 | HoverResult of Hover.result
1167 | DefinitionResult of Definition.result
1168 | TypeDefinitionResult of TypeDefinition.result
1169 | CodeActionResult of CodeAction.result
1170 | CompletionResult of Completion.result
1171 | CompletionItemResolveResult of CompletionItemResolve.result
1172 | WorkspaceSymbolResult of WorkspaceSymbol.result
1173 | DocumentSymbolResult of DocumentSymbol.result
1174 | FindReferencesResult of FindReferences.result
1175 | DocumentHighlightResult of DocumentHighlight.result
1176 | TypeCoverageResult of TypeCoverage.result
1177 | DocumentFormattingResult of DocumentFormatting.result
1178 | DocumentRangeFormattingResult of DocumentRangeFormatting.result
1179 | DocumentOnTypeFormattingResult of DocumentOnTypeFormatting.result
1180 | ShowMessageRequestResult of ShowMessageRequest.result
1181 | ShowStatusResult of ShowStatus.result
1182 | RageResult of Rage.result
1183 | RenameResult of Rename.result
1184 | DocumentCodeLensResult of DocumentCodeLens.result
1185 | ErrorResult of Error.t * string (* the string is a stacktrace *)
1187 type lsp_notification =
1188 | ExitNotification
1189 | CancelRequestNotification of CancelRequest.params
1190 | PublishDiagnosticsNotification of PublishDiagnostics.params
1191 | DidOpenNotification of DidOpen.params
1192 | DidCloseNotification of DidClose.params
1193 | DidSaveNotification of DidSave.params
1194 | DidChangeNotification of DidChange.params
1195 | DidChangeWatchedFilesNotification of DidChangeWatchedFiles.params
1196 | LogMessageNotification of LogMessage.params
1197 | TelemetryNotification of LogMessage.params (* LSP allows 'any' but we only send these *)
1198 | ShowMessageNotification of ShowMessage.params
1199 | ProgressNotification of Progress.params
1200 | ActionRequiredNotification of ActionRequired.params
1201 | ConnectionStatusNotification of ConnectionStatus.params
1202 | InitializedNotification
1203 | SetTraceNotification (* $/setTraceNotification *)
1204 | LogTraceNotification (* $/logTraceNotification *)
1205 | UnknownNotification of string * Hh_json.json option
1207 type lsp_message =
1208 | RequestMessage of lsp_id * lsp_request
1209 | ResponseMessage of lsp_id * lsp_result
1210 | NotificationMessage of lsp_notification
1212 type 'a lsp_handler = 'a lsp_result_handler * 'a lsp_error_handler
1214 and 'a lsp_error_handler = (Error.t * string) -> 'a -> 'a
1216 and 'a lsp_result_handler =
1217 | ShowMessageHandler of (ShowMessageRequest.result -> 'a -> 'a)
1218 | ShowStatusHandler of (ShowStatus.result -> 'a -> 'a)
1220 module IdKey = struct
1221 type t = lsp_id
1223 let compare (x: t) (y:t) =
1224 match x, y with
1225 | NumberId x, NumberId y -> x - y
1226 | NumberId _, StringId _ -> -1
1227 | StringId x, StringId y -> String.compare x y
1228 | StringId _, NumberId _ -> 1
1231 module IdSet = Set.Make (IdKey)
1232 module IdMap = MyMap.Make (IdKey)