From ff3f684ce0136592e4f7398b9a9fabaf9b712dbc Mon Sep 17 00:00:00 2001 From: Ian Cottrell Date: Mon, 24 Sep 2018 17:24:58 -0400 Subject: [PATCH] internal/lsp: the core lsp protocol This is not intended to be a user friendly package, just the rawest correct implemenation of the protocol as a building block Change-Id: Ib672b7f1e2fd8284be422dc7964f1876e94c9578 Reviewed-on: https://go-review.googlesource.com/136676 Reviewed-by: Alan Donovan Reviewed-by: Rebecca Stambler --- internal/lsp/protocol/basic.go | 362 +++++++++ internal/lsp/protocol/client.go | 205 +++++ internal/lsp/protocol/diagnostics.go | 20 + internal/lsp/protocol/doc.go | 16 + internal/lsp/protocol/general.go | 849 ++++++++++++++++++++ internal/lsp/protocol/language.go | 1020 +++++++++++++++++++++++++ internal/lsp/protocol/protocol.go | 34 + internal/lsp/protocol/registration.go | 61 ++ internal/lsp/protocol/server.go | 718 +++++++++++++++++ internal/lsp/protocol/text.go | 130 ++++ internal/lsp/protocol/window.go | 77 ++ internal/lsp/protocol/workspace.go | 203 +++++ 12 files changed, 3695 insertions(+) create mode 100644 internal/lsp/protocol/basic.go create mode 100644 internal/lsp/protocol/client.go create mode 100644 internal/lsp/protocol/diagnostics.go create mode 100644 internal/lsp/protocol/doc.go create mode 100644 internal/lsp/protocol/general.go create mode 100644 internal/lsp/protocol/language.go create mode 100644 internal/lsp/protocol/protocol.go create mode 100644 internal/lsp/protocol/registration.go create mode 100644 internal/lsp/protocol/server.go create mode 100644 internal/lsp/protocol/text.go create mode 100644 internal/lsp/protocol/window.go create mode 100644 internal/lsp/protocol/workspace.go diff --git a/internal/lsp/protocol/basic.go b/internal/lsp/protocol/basic.go new file mode 100644 index 0000000000..05174d9fa7 --- /dev/null +++ b/internal/lsp/protocol/basic.go @@ -0,0 +1,362 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the corresponding structures to the +// "Basic JSON Structures" part of the LSP specification. + +package protocol + +const ( + // CodeRequestCancelled is the error code that is returned when a request is + // cancelled early. + CodeRequestCancelled = -32800 +) + +// DocumentURI represents the URI of a document. +// Many of the interfaces contain fields that correspond to the URI of a document. +// For clarity, the type of such a field is declared as a DocumentURI. +// Over the wire, it will still be transferred as a string, but this guarantees +// that the contents of that string can be parsed as a valid URI. +type DocumentURI string + +// Position in a text document expressed as zero-based line and zero-based character offset. +// A position is between two characters like an ‘insert’ cursor in a editor. +type Position struct { + /** + * Line position in a document (zero-based). + */ + Line float64 `json:"line"` + + /** + * Character offset on a line in a document (zero-based). Assuming that the line is + * represented as a string, the `character` value represents the gap between the + * `character` and `character + 1`. + * + * If the character value is greater than the line length it defaults back to the + * line length. + */ + Character float64 `json:"character"` +} + +// Range in a text document expressed as (zero-based) start and end positions. +// A range is comparable to a selection in an editor. +// Therefore the end position is exclusive. +// If you want to specify a range that contains a line including the line +// ending character(s) then use an end position denoting the start of the next +// line. +type Range struct { + /** + * The range's start position. + */ + Start Position `json:"start"` + + /** + * The range's end position. + */ + End Position `json:"end"` +} + +// Location represents a location inside a resource, such as a line inside a text file. +type Location struct { + URI DocumentURI `json:"uri"` + Range Range `json:"range"` +} + +// Diagnostic represents a diagnostic, such as a compiler error or warning. +// Diagnostic objects are only valid in the scope of a resource. +type Diagnostic struct { + /** + * The range at which the message applies. + */ + Range Range `json:"range"` + + /** + * The diagnostic's severity. Can be omitted. If omitted it is up to the + * client to interpret diagnostics as error, warning, info or hint. + */ + Severity DiagnosticSeverity `json:"severity,omitempty"` + + /** + * The diagnostic's code, which might appear in the user interface. + */ + Code string `json:"code,omitempty"` // number | string + + /** + * A human-readable string describing the source of this + * diagnostic, e.g. 'typescript' or 'super lint'. + */ + Source string `json:"source,omitempty"` + + /** + * The diagnostic's message. + */ + Message string `json:"message"` + + /** + * An array of related diagnostic information, e.g. when symbol-names within + * a scope collide all definitions can be marked via this property. + */ + Related []DiagnosticRelatedInformation `json:"relatedInformation,omitempty"` +} + +// DiagnosticSeverity indicates the severity of a Diagnostic message. +type DiagnosticSeverity float64 + +const ( + /** + * Reports an error. + */ + SeverityError DiagnosticSeverity = 1 + /** + * Reports a warning. + */ + SeverityWarning DiagnosticSeverity = 2 + /** + * Reports an information. + */ + SeverityInformation DiagnosticSeverity = 3 + /** + * Reports a hint. + */ + SeverityHint DiagnosticSeverity = 4 +) + +// DiagnosticRelatedInformation represents a related message and source code +// location for a diagnostic. +// This should be used to point to code locations that cause or related to a +// diagnostics, e.g when duplicating a symbol in a scope. +type DiagnosticRelatedInformation struct { + /** + * The location of this related diagnostic information. + */ + Location Location `json:"location"` + + /** + * The message of this related diagnostic information. + */ + Message string `json:"message"` +} + +// Command represents a reference to a command. +// Provides a title which will be used to represent a command in the UI. +// Commands are identified by a string identifier. +// The protocol currently doesn’t specify a set of well-known commands. +// So executing a command requires some tool extension code. +type Command struct { + /** + * Title of the command, like `save`. + */ + Title string `json:"title"` + + /** + * The identifier of the actual command handler. + */ + Command string `json:"command"` + + /** + * Arguments that the command handler should be + * invoked with. + */ + Arguments []interface{} `json:"arguments,omitempty"` +} + +// TextEdit is a textual edit applicable to a text document. +type TextEdit struct { + /** + * The range of the text document to be manipulated. To insert + * text into a document create a range where start === end. + */ + Range Range `json:"range"` + + /** + * The string to be inserted. For delete operations use an + * empty string. + */ + NewText string `json:"newText"` +} + +// TextDocumentEdit describes textual changes on a single text document. +// The text document is referred to as a VersionedTextDocumentIdentifier to +// allow clients to check the text document version before an edit is applied. +// A TextDocumentEdit describes all changes on a version Si and after they are +// applied move the document to version Si+1. +// So the creator of a TextDocumentEdit doesn’t need to sort the array or do +// any kind of ordering. +// However the edits must be non overlapping. +type TextDocumentEdit struct { + /** + * The text document to change. + */ + TextDocument VersionedTextDocumentIdentifier `json:"textDocument"` + + /** + * The edits to be applied. + */ + Edits []TextEdit `json:"edits"` +} + +// WorkspaceEdit represents changes to many resources managed in the workspace. +// The edit should either provide Changes or DocumentChanges. +// If the client can handle versioned document edits and if DocumentChanges are +// present, the latter are preferred over Changes. +type WorkspaceEdit struct { + /** + * Holds changes to existing resources. + */ + Changes map[DocumentURI][]TextEdit `json:"changes,omitempty"` + + /** + * An array of `TextDocumentEdit`s to express changes to n different text documents + * where each text document edit addresses a specific version of a text document. + * Whether a client supports versioned document edits is expressed via + * `WorkspaceClientCapabilities.workspaceEdit.documentChanges`. + */ + DocumentChanges []TextDocumentEdit `json:"documentChanges,omitempty"` +} + +// TextDocumentIdentifier identifies a document using a URI. +// On the protocol level, URIs are passed as strings. +// The corresponding JSON structure looks like this. +type TextDocumentIdentifier struct { + /** + * The text document's URI. + */ + URI DocumentURI `json:"uri"` +} + +// TextDocumentItem is an item to transfer a text document from the client to +// the server. +type TextDocumentItem struct { + /** + * The text document's URI. + */ + URI DocumentURI `json:"uri"` + + /** + * The text document's language identifier. + */ + LanguageID string `json:"languageId"` + + /** + * The version number of this document (it will increase after each + * change, including undo/redo). + */ + Version float64 `json:"version"` + + /** + * The content of the opened text document. + */ + Text string `json:"text"` +} + +// VersionedTextDocumentIdentifier is an identifier to denote a specific version of a text document. +type VersionedTextDocumentIdentifier struct { + TextDocumentIdentifier + + /** + * The version number of this document. If a versioned text document identifier + * is sent from the server to the client and the file is not open in the editor + * (the server has not received an open notification before) the server can send + * `null` to indicate that the version is known and the content on disk is the + * truth (as speced with document content ownership) + */ + Version *uint64 `json:"version"` +} + +// TextDocumentPositionParams is a parameter literal used in requests to pass +// a text document and a position inside that document. +type TextDocumentPositionParams struct { + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The position inside the text document. + */ + Position Position `json:"position"` +} + +// DocumentFilter is a document filter denotes a document through properties +// like language, scheme or pattern. +// An example is a filter that applies to TypeScript files on disk. +// Another example is a filter the applies to JSON files with name package.json: +// { language: 'typescript', scheme: 'file' } +// { language: 'json', pattern: '**/package.json' } +type DocumentFilter struct { + /** + * A language id, like `typescript`. + */ + Language string `json:"language,omitempty"` + + /** + * A URI [scheme](#URI.scheme), like `file` or `untitled`. + */ + Scheme string `json:"scheme,omitempty"` + + /** + * A glob pattern, like `*.{ts,js}`. + */ + Pattern string `json:"pattern,omitempty"` +} + +// A document selector is the combination of one or more document filters. +type DocumentSelector []DocumentFilter + +/** + * Describes the content type that a client supports in various + * result literals like `Hover`, `ParameterInfo` or `CompletionItem`. + * + * Please note that `MarkupKinds` must not start with a `$`. This kinds + * are reserved for internal usage. + */ +type MarkupKind string + +const ( + /** + * Plain text is supported as a content format + */ + PlainText MarkupKind = "plaintext" + + /** + * Markdown is supported as a content format + */ + Markdown MarkupKind = "markdown" +) + +/** + * A `MarkupContent` literal represents a string value which content is interpreted base on its + * kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds. + * + * If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues. + * See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting + * + * Here is an example how such a string can be constructed using JavaScript / TypeScript: + * ```ts + * let markdown: MarkdownContent = { + * kind: MarkupKind.Markdown, + * value: [ + * '# Header', + * 'Some text', + * '```typescript', + * 'someCode();', + * '```' + * ].join('\n') + * }; + * ``` + * + * *Please Note* that clients might sanitize the return markdown. A client could decide to + * remove HTML from the markdown to avoid script execution. + */ +type MarkupContent struct { + /** + * The type of the Markup + */ + Kind MarkupKind `json:"kind"` + + /** + * The content itself + */ + Value string `json:"value"` +} diff --git a/internal/lsp/protocol/client.go b/internal/lsp/protocol/client.go new file mode 100644 index 0000000000..1e713289d9 --- /dev/null +++ b/internal/lsp/protocol/client.go @@ -0,0 +1,205 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package protocol + +import ( + "context" + "encoding/json" + + "golang.org/x/tools/internal/jsonrpc2" +) + +type Client interface { + ShowMessage(context.Context, *ShowMessageParams) error + ShowMessageRequest(context.Context, *ShowMessageRequestParams) (*MessageActionItem, error) + LogMessage(context.Context, *LogMessageParams) error + Telemetry(context.Context, interface{}) error + RegisterCapability(context.Context, *RegistrationParams) error + UnregisterCapability(context.Context, *UnregistrationParams) error + WorkspaceFolders(context.Context) ([]WorkspaceFolder, error) + Configuration(context.Context, *ConfigurationParams) ([]interface{}, error) + ApplyEdit(context.Context, *ApplyWorkspaceEditParams) (bool, error) + PublishDiagnostics(context.Context, *PublishDiagnosticsParams) error +} + +func clientHandler(client Client) jsonrpc2.Handler { + return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) (interface{}, *jsonrpc2.Error) { + switch r.Method { + case "$/cancelRequest": + var params CancelParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + conn.Cancel(params.ID) + return nil, nil + + case "window/showMessage": + var params ShowMessageParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := client.ShowMessage(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "window/showMessageRequest": + var params ShowMessageRequestParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := client.ShowMessageRequest(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "window/logMessage": + var params LogMessageParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := client.LogMessage(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "telemetry/event": + var params interface{} + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := client.Telemetry(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "client/registerCapability": + var params RegistrationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := client.RegisterCapability(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "client/unregisterCapability": + var params UnregistrationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := client.UnregisterCapability(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "workspace/workspaceFolders": + if r.Params != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params") + } + resp, err := client.WorkspaceFolders(ctx) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "workspace/configuration": + var params ConfigurationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := client.Configuration(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "workspace/applyEdit": + var params ApplyWorkspaceEditParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := client.ApplyEdit(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/publishDiagnostics": + var params PublishDiagnosticsParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := client.PublishDiagnostics(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + default: + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method) + } + } +} + +type clientDispatcher struct { + *jsonrpc2.Conn +} + +func (c *clientDispatcher) ShowMessage(ctx context.Context, params *ShowMessageParams) error { + return c.Conn.Notify(ctx, "window/showMessage", params) +} + +func (c *clientDispatcher) ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (*MessageActionItem, error) { + var result MessageActionItem + if err := c.Conn.Call(ctx, "window/showMessageRequest", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (c *clientDispatcher) LogMessage(ctx context.Context, params *LogMessageParams) error { + return c.Conn.Notify(ctx, "window/logMessage", params) +} + +func (c *clientDispatcher) Telemetry(ctx context.Context, params interface{}) error { + return c.Conn.Notify(ctx, "telemetry/event", params) +} + +func (c *clientDispatcher) RegisterCapability(ctx context.Context, params *RegistrationParams) error { + return c.Conn.Notify(ctx, "client/registerCapability", params) +} + +func (c *clientDispatcher) UnregisterCapability(ctx context.Context, params *UnregistrationParams) error { + return c.Conn.Notify(ctx, "client/unregisterCapability", params) +} + +func (c *clientDispatcher) WorkspaceFolders(ctx context.Context) ([]WorkspaceFolder, error) { + var result []WorkspaceFolder + if err := c.Conn.Call(ctx, "workspace/workspaceFolders", nil, &result); err != nil { + return nil, err + } + return result, nil +} + +func (c *clientDispatcher) Configuration(ctx context.Context, params *ConfigurationParams) ([]interface{}, error) { + var result []interface{} + if err := c.Conn.Call(ctx, "workspace/configuration", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (c *clientDispatcher) ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (bool, error) { + var result bool + if err := c.Conn.Call(ctx, "workspace/applyEdit", params, &result); err != nil { + return false, err + } + return result, nil +} + +func (c *clientDispatcher) PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) error { + return c.Conn.Notify(ctx, "textDocument/publishDiagnostics", params) +} diff --git a/internal/lsp/protocol/diagnostics.go b/internal/lsp/protocol/diagnostics.go new file mode 100644 index 0000000000..2fe45ce3ba --- /dev/null +++ b/internal/lsp/protocol/diagnostics.go @@ -0,0 +1,20 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the corresponding structures to the +// "Diagnostics" part of the LSP specification. + +package protocol + +type PublishDiagnosticsParams struct { + /** + * The URI for which diagnostic information is reported. + */ + URI DocumentURI `json:"uri"` + + /** + * An array of diagnostic information items. + */ + Diagnostics []Diagnostic `json:"diagnostics"` +} diff --git a/internal/lsp/protocol/doc.go b/internal/lsp/protocol/doc.go new file mode 100644 index 0000000000..2ffdf51287 --- /dev/null +++ b/internal/lsp/protocol/doc.go @@ -0,0 +1,16 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package protocol contains the structs that map directly to the wire format +// of the "Language Server Protocol". +// +// It is a literal transcription, with unmodified comments, and only the changes +// required to make it go code. +// Names are uppercased to export them. +// All fields have JSON tags added to correct the names. +// Fields marked with a ? are also marked as "omitempty" +// Fields that are "|| null" are made pointers +// Fields that are string or number are left as string +// Fields that are type "number" are made float64 +package protocol diff --git a/internal/lsp/protocol/general.go b/internal/lsp/protocol/general.go new file mode 100644 index 0000000000..be8fa68ae6 --- /dev/null +++ b/internal/lsp/protocol/general.go @@ -0,0 +1,849 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the corresponding structures to the +// "General" messages part of the LSP specification. + +package protocol + +import "golang.org/x/tools/internal/jsonrpc2" + +type CancelParams struct { + /** + * The request id to cancel. + */ + ID jsonrpc2.ID `json:"id"` +} + +type InitializeParams struct { + /** + * The process Id of the parent process that started + * the server. Is null if the process has not been started by another process. + * If the parent process is not alive then the server should exit (see exit notification) its process. + */ + ProcessID *float64 `json:"processId"` + + /** + * The rootPath of the workspace. Is null + * if no folder is open. + * + * @deprecated in favour of rootURI. + */ + RootPath *string `json:"rootPath"` + + /** + * The rootURI of the workspace. Is null if no + * folder is open. If both `rootPath` and `rootURI` are set + * `rootURI` wins. + */ + RootURI *DocumentURI `json:"rootURI"` + + /** + * User provided initialization options. + */ + InitializationOptions interface{} `json:"initializationOptions"` + + /** + * The capabilities provided by the client (editor or tool) + */ + Capabilities ClientCapabilities `json:"capabilities"` + + /** + * The initial trace setting. If omitted trace is disabled ('off'). + */ + Trace string `json:"trace"` // 'off' | 'messages' | 'verbose' + + /** + * The workspace folders configured in the client when the server starts. + * This property is only available if the client supports workspace folders. + * It can be `null` if the client supports workspace folders but none are + * configured. + * + * Since 3.6.0 + */ + WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders,omitempty"` +} + +/** + * Workspace specific client capabilities. + */ +type WorkspaceClientCapabilities struct { + /** + * The client supports applying batch edits to the workspace by supporting + * the request 'workspace/applyEdit' + */ + ApplyEdit bool `json:"applyEdit,omitempty"` + + /** + * Capabilities specific to `WorkspaceEdit`s + */ + WorkspaceEdit struct { + /** + * The client supports versioned document changes in `WorkspaceEdit`s + */ + DocumentChanges bool `json:"documentChanges,omitempty"` + } `json:"workspaceEdit,omitempty"` + + /** + * Capabilities specific to the `workspace/didChangeConfiguration` notification. + */ + DidChangeConfiguration struct { + /** + * Did change configuration notification supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"didChangeConfiguration,omitempty"` + + /** + * Capabilities specific to the `workspace/didChangeWatchedFiles` notification. + */ + DidChangeWatchedFiles struct { + /** + * Did change watched files notification supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"didChangeWatchedFiles,omitempty"` + + /** + * Capabilities specific to the `workspace/symbol` request. + */ + Symbol struct { + /** + * Symbol request supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /** + * Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. + */ + SymbolKind struct { + /** + * The symbol kind values the client supports. When this + * property exists the client also guarantees that it will + * handle values outside its set gracefully and falls back + * to a default value when unknown. + * + * If this property is not present the client only supports + * the symbol kinds from `File` to `Array` as defined in + * the initial version of the protocol. + */ + ValueSet []SymbolKind `json:"valueSet,omitempty"` + } `json:"symbolKind,omitempty"` + } `json:"symbol,omitempty"` + + /** + * Capabilities specific to the `workspace/executeCommand` request. + */ + ExecuteCommand struct { + /** + * Execute command supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"executeCommand,omitempty"` + + /** + * The client has support for workspace folders. + * + * Since 3.6.0 + */ + WorkspaceFolders bool `json:"workspaceFolders,omitempty"` + + /** + * The client supports `workspace/configuration` requests. + * + * Since 3.6.0 + */ + Configuration bool `json:"configuration,omitempty"` +} + +/** + * Text document specific client capabilities. + */ +type TextDocumentClientCapabilities struct { + Synchronization struct { + /** + * Whether text document synchronization supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /** + * The client supports sending will save notifications. + */ + WillSave bool `json:"willSave,omitempty"` + + /** + * The client supports sending a will save request and + * waits for a response providing text edits which will + * be applied to the document before it is saved. + */ + WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"` + + /** + * The client supports did save notifications. + */ + DidSave bool `json:"didSave,omitempty"` + } `json:"synchronization,omitempty"` + + /** + * Capabilities specific to the `textDocument/completion` + */ + Completion struct { + /** + * Whether completion supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /** + * The client supports the following `CompletionItem` specific + * capabilities. + */ + CompletionItem struct { + /** + * Client supports snippets as insert text. + * + * A snippet can define tab stops and placeholders with `$1`, `$2` + * and `${3:foo}`. `$0` defines the final tab stop, it defaults to + * the end of the snippet. Placeholders with equal identifiers are linked, + * that is typing in one will update others too. + */ + SnippetSupport bool `json:"snippetSupport,omitempty"` + + /** + * Client supports commit characters on a completion item. + */ + CommitCharactersSupport bool `json:"commitCharactersSupport,omitempty"` + + /** + * Client supports the follow content formats for the documentation + * property. The order describes the preferred format of the client. + */ + DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"` + + /** + * Client supports the deprecated property on a completion item. + */ + DeprecatedSupport bool `json:"deprecatedSupport,omitempty"` + + /** + * Client supports the preselect property on a completion item. + */ + PreselectSupport bool `json:"preselectSupport,omitempty"` + } `json:"completionItem,omitempty"` + + CompletionItemKind struct { + /** + * The completion item kind values the client supports. When this + * property exists the client also guarantees that it will + * handle values outside its set gracefully and falls back + * to a default value when unknown. + * + * If this property is not present the client only supports + * the completion items kinds from `Text` to `Reference` as defined in + * the initial version of the protocol. + */ + ValueSet []CompletionItemKind `json:"valueSet,omitempty"` + } `json:"completionItemKind,omitempty"` + + /** + * The client supports to send additional context information for a + * `textDocument/completion` request. + */ + ContextSupport bool `json:"contextSupport,omitempty"` + } `json:"completion"` + + /** + * Capabilities specific to the `textDocument/hover` + */ + Hover struct { + /** + * Whether hover supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /** + * Client supports the follow content formats for the content + * property. The order describes the preferred format of the client. + */ + ContentFormat []MarkupKind `json:"contentFormat,omitempty"` + } `json:"hover,omitempty"` + + /** + * Capabilities specific to the `textDocument/signatureHelp` + */ + SignatureHelp struct { + /** + * Whether signature help supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /** + * The client supports the following `SignatureInformation` + * specific properties. + */ + SignatureInformation struct { + /** + * Client supports the follow content formats for the documentation + * property. The order describes the preferred format of the client. + */ + DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"` + } `json:"signatureInformation,omitempty"` + } `json:"signatureHelp,omitempty"` + + /** + * Capabilities specific to the `textDocument/references` + */ + References struct { + /** + * Whether references supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"references,omitempty"` + + /** + * Capabilities specific to the `textDocument/documentHighlight` + */ + DocumentHighlight struct { + /** + * Whether document highlight supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"documentHighlight,omitempty"` + + /** + * Capabilities specific to the `textDocument/documentSymbol` + */ + DocumentSymbol struct { + /** + * Whether document symbol supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /** + * Specific capabilities for the `SymbolKind`. + */ + SymbolKind struct { + /** + * The symbol kind values the client supports. When this + * property exists the client also guarantees that it will + * handle values outside its set gracefully and falls back + * to a default value when unknown. + * + * If this property is not present the client only supports + * the symbol kinds from `File` to `Array` as defined in + * the initial version of the protocol. + */ + ValueSet []SymbolKind `json:"valueSet,omitempty"` + } `json:"symbolKind,omitempty"` + + /** + * The client support hierarchical document symbols. + */ + HierarchicalDocumentSymbolSupport bool `json:"hierarchicalDocumentSymbolSupport,omitempty"` + } `json:"documentSymbol,omitempty"` + + /** + * Capabilities specific to the `textDocument/formatting` + */ + Formatting struct { + /** + * Whether formatting supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"formatting,omitempty"` + + /** + * Capabilities specific to the `textDocument/rangeFormatting` + */ + RangeFormatting struct { + /** + * Whether range formatting supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"rangeFormatting,omitempty"` + + /** + * Capabilities specific to the `textDocument/onTypeFormatting` + */ + OnTypeFormatting struct { + /** + * Whether on type formatting supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"onTypeFormatting,omitempty"` + + /** + * Capabilities specific to the `textDocument/definition` + */ + Definition struct { + /** + * Whether definition supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"definition,omitempty"` + + /** + * Capabilities specific to the `textDocument/typeDefinition` + * + * Since 3.6.0 + */ + TypeDefinition struct { + /** + * Whether typeDefinition supports dynamic registration. If this is set to `true` + * the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` + * return value for the corresponding server capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"typeDefinition,omitempty"` + + /** + * Capabilities specific to the `textDocument/implementation`. + * + * Since 3.6.0 + */ + Implementation struct { + /** + * Whether implementation supports dynamic registration. If this is set to `true` + * the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` + * return value for the corresponding server capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"implementation,omitempty"` + + /** + * Capabilities specific to the `textDocument/codeAction` + */ + CodeAction struct { + /** + * Whether code action supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + /** + * The client support code action literals as a valid + * response of the `textDocument/codeAction` request. + * + * Since 3.8.0 + */ + CodeActionLiteralSupport struct { + /** + * The code action kind is support with the following value + * set. + */ + CodeActionKind struct { + + /** + * The code action kind values the client supports. When this + * property exists the client also guarantees that it will + * handle values outside its set gracefully and falls back + * to a default value when unknown. + */ + ValueSet []CodeActionKind `json:"valueSet"` + } `json:"codeActionKind"` + } `json:"codeActionLiteralSupport,omitempty"` + } `json:"codeAction,omitempty"` + + /** + * Capabilities specific to the `textDocument/codeLens` + */ + CodeLens struct { + /** + * Whether code lens supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"codeLens,omitempty"` + + /** + * Capabilities specific to the `textDocument/documentLink` + */ + DocumentLink struct { + /** + * Whether document link supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"documentLink,omitempty"` + + /** + * Capabilities specific to the `textDocument/documentColor` and the + * `textDocument/colorPresentation` request. + * + * Since 3.6.0 + */ + ColorProvider struct { + /** + * Whether colorProvider supports dynamic registration. If this is set to `true` + * the client supports the new `(ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` + * return value for the corresponding server capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"colorProvider,omitempty"` + + /** + * Capabilities specific to the `textDocument/rename` + */ + Rename struct { + /** + * Whether rename supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + } `json:"rename,omitempty"` + + /** + * Capabilities specific to `textDocument/publishDiagnostics`. + */ + PublishDiagnostics struct { + /** + * Whether the clients accepts diagnostics with related information. + */ + RelatedInformation bool `json:"relatedInformation,omitempty"` + } `json:"publishDiagnostics,omitempty"` + + /** + * Capabilities specific to `textDocument/foldingRange` requests. + * + * Since 3.10.0 + */ + FoldingRange struct { + /** + * Whether implementation supports dynamic registration for folding range providers. If this is set to `true` + * the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` + * return value for the corresponding server capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + /** + * The maximum number of folding ranges that the client prefers to receive per document. The value serves as a + * hint, servers are free to follow the limit. + */ + RangeLimit float64 `json:"rangeLimit,omitempty"` + /** + * If set, the client signals that it only supports folding complete lines. If set, client will + * ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange. + */ + LineFoldingOnly bool `json:"lineFoldingOnly,omitempty"` + } +} + +// ClientCapabilities now define capabilities for dynamic registration, workspace +// and text document features the client supports. The experimental can be used to +// pass experimental capabilities under development. For future compatibility a +// ClientCapabilities object literal can have more properties set than currently +// defined. Servers receiving a ClientCapabilities object literal with unknown +// properties should ignore these properties. A missing property should be +// interpreted as an absence of the capability. If a property is missing that +// defines sub properties all sub properties should be interpreted as an absence +// of the capability. +// +// Client capabilities got introduced with version 3.0 of the protocol. They +// therefore only describe capabilities that got introduced in 3.x or later. +// Capabilities that existed in the 2.x version of the protocol are still +// mandatory for clients. Clients cannot opt out of providing them. So even if a +// client omits the ClientCapabilities.textDocument.synchronization it is still +// required that the client provides text document synchronization (e.g. open, +// changed and close notifications). +type ClientCapabilities struct { + /** + * Workspace specific client capabilities. + */ + Workspace WorkspaceClientCapabilities `json:"workspace,omitempty"` + + /** + * Text document specific client capabilities. + */ + TextDocument TextDocumentClientCapabilities `json:"textDocument,omitempty"` + + /** + * Experimental client capabilities. + */ + Experimental interface{} `json:"experimental,omitempty"` +} + +type InitializeResult struct { + /** + * The capabilities the language server provides. + */ + Capabilities ServerCapabilities `json:"capabilities"` +} + +/** + * Defines how the host (editor) should sync document changes to the language server. + */ +type TextDocumentSyncKind float64 + +const ( + /** + * Documents should not be synced at all. + */ + None TextDocumentSyncKind = 0 + + /** + * Documents are synced by always sending the full content + * of the document. + */ + Full TextDocumentSyncKind = 1 + + /** + * Documents are synced by sending the full content on open. + * After that only incremental updates to the document are + * send. + */ + Incremental TextDocumentSyncKind = 2 +) + +/** + * Completion options. + */ +type CompletionOptions struct { + /** + * The server provides support to resolve additional + * information for a completion item. + */ + ResolveProvider bool `json:"resolveProvider,omitempty"` + + /** + * The characters that trigger completion automatically. + */ + TriggerCharacters []string `json:"triggerCharacters,omitempty"` +} + +/** + * Signature help options. + */ +type SignatureHelpOptions struct { + /** + * The characters that trigger signature help + * automatically. + */ + TriggerCharacters []string `json:"triggerCharacters,omitempty"` +} + +/** + * Code Lens options. + */ +type CodeLensOptions struct { + /** + * Code lens has a resolve provider as well. + */ + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +/** + * Format document on type options. + */ +type DocumentOnTypeFormattingOptions struct { + /** + * A character on which formatting should be triggered, like `}`. + */ + FirstTriggerCharacter string `json:"firstTriggerCharacter"` + + /** + * More trigger characters. + */ + MoreTriggerCharacter []string `json:"moreTriggerCharacter,omitempty"` +} + +/** + * Document link options. + */ +type DocumentLinkOptions struct { + /** + * Document links have a resolve provider as well. + */ + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +/** + * Execute command options. + */ +type ExecuteCommandOptions struct { + /** + * The commands to be executed on the server + */ + Commands []string `json:"commands"` +} + +/** + * Save options. + */ +type SaveOptions struct { + /** + * The client is supposed to include the content on save. + */ + IncludeText bool `json:"includeText,omitempty"` +} + +/** + * Color provider options. + */ +type ColorProviderOptions struct { +} + +/** + * Folding range provider options. + */ +type FoldingRangeProviderOptions struct { +} + +type TextDocumentSyncOptions struct { + /** + * Open and close notifications are sent to the server. + */ + OpenClose bool `json:"openClose,omitempty"` + /** + * Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full + * and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None. + */ + Change float64 `json:"change,omitempty"` + /** + * Will save notifications are sent to the server. + */ + WillSave bool `json:"willSave,omitempty"` + /** + * Will save wait until requests are sent to the server. + */ + WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"` + /** + * Save notifications are sent to the server. + */ + Save SaveOptions `json:"save,omitempty"` +} + +/** + * Static registration options to be returned in the initialize request. + */ +type StaticRegistrationOptions struct { + /** + * The id used to register the request. The id can be used to deregister + * the request again. See also Registration#id. + */ + ID string `json:"id,omitempty"` +} + +type ServerCapabilities struct { + /** + * Defines how text documents are synced. Is either a detailed structure defining each notification or + * for backwards compatibility the TextDocumentSyncKind number. If omitted it defaults to `TextDocumentSyncKind.None`. + */ + TextDocumentSync interface{} `json:"textDocumentSync,omitempty"` // TextDocumentSyncOptions | number + /** + * The server provides hover support. + */ + HoverProvider bool `json:"hoverProvider,omitempty"` + /** + * The server provides completion support. + */ + CompletionProvider CompletionOptions `json:"completionProvider,omitempty"` + /** + * The server provides signature help support. + */ + SignatureHelpProvider SignatureHelpOptions `json:"signatureHelpProvider,omitempty"` + /** + * The server provides goto definition support. + */ + DefinitionProvider bool `json:"definitionProvider,omitempty"` + /** + * The server provides Goto Type Definition support. + * + * Since 3.6.0 + */ + TypeDefinitionProvider interface{} `json:"typeDefinitionProvider,omitempty"` // boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions) + /** + * The server provides Goto Implementation support. + * + * Since 3.6.0 + */ + ImplementationProvider interface{} `json:"implementationProvider,omitempty"` // boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions) + /** + * The server provides find references support. + */ + ReferencesProvider bool `json:"referencesProvider,omitempty"` + /** + * The server provides document highlight support. + */ + DocumentHighlightProvider bool `json:"documentHighlightProvider,omitempty"` + /** + * The server provides document symbol support. + */ + DocumentSymbolProvider bool `json:"documentSymbolProvider,omitempty"` + /** + * The server provides workspace symbol support. + */ + WorkspaceSymbolProvider bool `json:"workspaceSymbolProvider,omitempty"` + /** + * The server provides code actions. + */ + CodeActionProvider bool `json:"codeActionProvider,omitempty"` + /** + * The server provides code lens. + */ + CodeLensProvider CodeLensOptions `json:"codeLensProvider,omitempty"` + /** + * The server provides document formatting. + */ + DocumentFormattingProvider bool `json:"documentFormattingProvider,omitempty"` + /** + * The server provides document range formatting. + */ + DocumentRangeFormattingProvider bool `json:"documentRangeFormattingProvider,omitempty"` + /** + * The server provides document formatting on typing. + */ + DocumentOnTypeFormattingProvider DocumentOnTypeFormattingOptions `json:"documentOnTypeFormattingProvider,omitempty"` + /** + * The server provides rename support. + */ + RenameProvider bool `json:"renameProvider,omitempty"` + /** + * The server provides document link support. + */ + DocumentLinkProvider DocumentLinkOptions `json:"documentLinkProvider,omitempty"` + /** + * The server provides color provider support. + * + * Since 3.6.0 + */ + //TODO: complex union type to decode here + ColorProvider interface{} `json:"colorProvider,omitempty"` // boolean | ColorProviderOptions | (ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions) + /** + * The server provides folding provider support. + * + * Since 3.10.0 + */ + //TODO: complex union type to decode here + FoldingRangeProvider interface{} `json:"foldingRangeProvider,omitempty"` // boolean | FoldingRangeProviderOptions | (FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions) + /** + * The server provides execute command support. + */ + ExecuteCommandProvider ExecuteCommandOptions `json:"executeCommandProvider,omitempty"` + /** + * Workspace specific server capabilities + */ + Workspace struct { + /** + * The server supports workspace folder. + * + * Since 3.6.0 + */ + WorkspaceFolders struct { + /** + * The server has support for workspace folders + */ + Supported bool `json:"supported,omitempty"` + /** + * Whether the server wants to receive workspace folder + * change notifications. + * + * If a strings is provided the string is treated as a ID + * under which the notification is registered on the client + * side. The ID can be used to unregister for these events + * using the `client/unregisterCapability` request. + */ + ChangeNotifications interface{} `json:"changeNotifications,omitempty"` // string | boolean + } `json:"workspaceFolders,omitempty"` + } `json:"workspace,omitempty"` + /** + * Experimental server capabilities. + */ + Experimental interface{} `json:"experimental,omitempty"` +} + +type InitializedParams struct { +} diff --git a/internal/lsp/protocol/language.go b/internal/lsp/protocol/language.go new file mode 100644 index 0000000000..78732b13f1 --- /dev/null +++ b/internal/lsp/protocol/language.go @@ -0,0 +1,1020 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the corresponding structures to the +// "Language Features" part of the LSP specification. + +package protocol + +type CompletionParams struct { + TextDocumentPositionParams + + /** + * The completion context. This is only available if the client specifies + * to send this using `ClientCapabilities.textDocument.completion.contextSupport === true` + */ + Context CompletionContext `json:"context,omitempty"` +} + +/** + * How a completion was triggered + */ +type CompletionTriggerKind float64 + +const ( + /** + * Completion was triggered by typing an identifier (24x7 code + * complete), manual invocation (e.g Ctrl+Space) or via API. + */ + Invoked CompletionTriggerKind = 1 + + /** + * Completion was triggered by a trigger character specified by + * the `triggerCharacters` properties of the `CompletionRegistrationOptions`. + */ + TriggerCharacter CompletionTriggerKind = 2 + + /** + * Completion was re-triggered as the current completion list is incomplete. + */ + TriggerForIncompleteCompletions CompletionTriggerKind = 3 +) + +/** + * Contains additional information about the context in which a completion request is triggered. + */ +type CompletionContext struct { + /** + * How the completion was triggered. + */ + TriggerKind CompletionTriggerKind `json:"triggerKind"` + + /** + * The trigger character (a single character) that has trigger code complete. + * Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` + */ + TriggerCharacter string `json:"triggerCharacter,omitempty"` +} + +/** + * Represents a collection of [completion items](#CompletionItem) to be presented + * in the editor. + */ +type CompletionList struct { + /** + * This list it not complete. Further typing should result in recomputing + * this list. + */ + IsIncomplete bool `json:"isIncomplete"` + + /** + * The completion items. + */ + Items []CompletionItem `json:"items"` +} + +/** + * Defines whether the insert text in a completion item should be interpreted as + * plain text or a snippet. + */ +type InsertTextFormat float64 + +const ( + /** + * The primary text to be inserted is treated as a plain string. + */ + PlainTextFormat InsertTextFormat = 1 + + /** + * The primary text to be inserted is treated as a snippet. + * + * A snippet can define tab stops and placeholders with `$1`, `$2` + * and `${3:foo}`. `$0` defines the final tab stop, it defaults to + * the end of the snippet. Placeholders with equal identifiers are linked, + * that is typing in one will update others too. + */ + SnippetTextFormat InsertTextFormat = 2 +) + +type CompletionItem struct { + /** + * The label of this completion item. By default + * also the text that is inserted when selecting + * this completion. + */ + Label string `json:"label"` + + /** + * The kind of this completion item. Based of the kind + * an icon is chosen by the editor. + */ + Kind float64 `json:"kind,omitempty"` + + /** + * A human-readable string with additional information + * about this item, like type or symbol information. + */ + Detail string `json:"detail,omitempty"` + + /** + * A human-readable string that represents a doc-comment. + */ + Documentation interface{} `json:"documentation,omitempty"` // string | MarkupContent + + /** + * Indicates if this item is deprecated. + */ + Deprecated bool `json:"deprecated,omitempty"` + + /** + * Select this item when showing. + * + * *Note* that only one completion item can be selected and that the + * tool / client decides which item that is. The rule is that the *first* + * item of those that match best is selected. + */ + Preselect bool `json:"preselect,omitempty"` + + /** + * A string that should be used when comparing this item + * with other items. When `falsy` the label is used. + */ + SortText string `json:"sortText,omitempty"` + + /** + * A string that should be used when filtering a set of + * completion items. When `falsy` the label is used. + */ + FilterText string `json:"filterText,omitempty"` + + /** + * A string that should be inserted into a document when selecting + * this completion. When `falsy` the label is used. + * + * The `insertText` is subject to interpretation by the client side. + * Some tools might not take the string literally. For example + * VS Code when code complete is requested in this example `con` + * and a completion item with an `insertText` of `console` is provided it + * will only insert `sole`. Therefore it is recommended to use `textEdit` instead + * since it avoids additional client side interpretation. + * + * @deprecated Use textEdit instead. + */ + InsertText string `json:"insertText,omitempty"` + + /** + * The format of the insert text. The format applies to both the `insertText` property + * and the `newText` property of a provided `textEdit`. + */ + InsertTextFormat InsertTextFormat `json:"insertTextFormat,omitempty"` + + /** + * An edit which is applied to a document when selecting this completion. When an edit is provided the value of + * `insertText` is ignored. + * + * *Note:* The range of the edit must be a single line range and it must contain the position at which completion + * has been requested. + */ + TextEdit TextEdit `json:"textEdit,omitempty"` + + /** + * An optional array of additional text edits that are applied when + * selecting this completion. Edits must not overlap (including the same insert position) + * with the main edit nor with themselves. + * + * Additional text edits should be used to change text unrelated to the current cursor position + * (for example adding an import statement at the top of the file if the completion item will + * insert an unqualified type). + */ + AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"` + + /** + * An optional set of characters that when pressed while this completion is active will accept it first and + * then type that character. *Note* that all commit characters should have `length=1` and that superfluous + * characters will be ignored. + */ + CommitCharacters []string `json:"commitCharacters,omitempty"` + + /** + * An optional command that is executed *after* inserting this completion. *Note* that + * additional modifications to the current document should be described with the + * additionalTextEdits-property. + */ + Command Command `json:"command,omitempty"` + + /** + * An data entry field that is preserved on a completion item between + * a completion and a completion resolve request. + */ + Data interface{} `json:"data"` +} + +/** + * The kind of a completion entry. + */ +type CompletionItemKind float64 + +const ( + TextCompletion CompletionItemKind = 1 + MethodCompletion CompletionItemKind = 2 + FunctionCompletion CompletionItemKind = 3 + ConstructorCompletion CompletionItemKind = 4 + FieldCompletion CompletionItemKind = 5 + VariableCompletion CompletionItemKind = 6 + ClassCompletion CompletionItemKind = 7 + InterfaceCompletion CompletionItemKind = 8 + ModuleCompletion CompletionItemKind = 9 + PropertyCompletion CompletionItemKind = 10 + UnitCompletion CompletionItemKind = 11 + ValueCompletion CompletionItemKind = 12 + EnumCompletion CompletionItemKind = 13 + KeywordCompletion CompletionItemKind = 14 + SnippetCompletion CompletionItemKind = 15 + ColorCompletion CompletionItemKind = 16 + FileCompletion CompletionItemKind = 17 + ReferenceCompletion CompletionItemKind = 18 + FolderCompletion CompletionItemKind = 19 + EnumMemberCompletion CompletionItemKind = 20 + ConstantCompletion CompletionItemKind = 21 + StructCompletion CompletionItemKind = 22 + EventCompletion CompletionItemKind = 23 + OperatorCompletion CompletionItemKind = 24 + TypeParameterCompletion CompletionItemKind = 25 +) + +type CompletionRegistrationOptions struct { + TextDocumentRegistrationOptions + /** + * Most tools trigger completion request automatically without explicitly requesting + * it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user + * starts to type an identifier. For example if the user types `c` in a JavaScript file + * code complete will automatically pop up present `console` besides others as a + * completion item. Characters that make up identifiers don't need to be listed here. + * + * If code complete should automatically be trigger on characters not being valid inside + * an identifier (for example `.` in JavaScript) list them in `triggerCharacters`. + */ + TriggerCharacters []string `json:"triggerCharacters,omitempty"` + + /** + * The server provides support to resolve additional + * information for a completion item. + */ + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +/** + * The result of a hover request. + */ +type Hover struct { + /** + * The hover's content + */ + Contents MarkupContent `json:"contents"` + + /** + * An optional range is a range inside a text document + * that is used to visualize a hover, e.g. by changing the background color. + */ + Range Range `json:"range,omitempty"` +} + +/** + * Signature help represents the signature of something + * callable. There can be multiple signature but only one + * active and only one active parameter. + */ +type SignatureHelp struct { + /** + * One or more signatures. + */ + Signatures []SignatureInformation `json:"signatures"` + + /** + * The active signature. If omitted or the value lies outside the + * range of `signatures` the value defaults to zero or is ignored if + * `signatures.length === 0`. Whenever possible implementors should + * make an active decision about the active signature and shouldn't + * rely on a default value. + * In future version of the protocol this property might become + * mandatory to better express this. + */ + ActiveSignature float64 `json:"activeSignature,omitempty"` + + /** + * The active parameter of the active signature. If omitted or the value + * lies outside the range of `signatures[activeSignature].parameters` + * defaults to 0 if the active signature has parameters. If + * the active signature has no parameters it is ignored. + * In future version of the protocol this property might become + * mandatory to better express the active parameter if the + * active signature does have any. + */ + ActiveParameter float64 `json:"activeParameter,omitempty"` +} + +/** + * Represents the signature of something callable. A signature + * can have a label, like a function-name, a doc-comment, and + * a set of parameters. + */ +type SignatureInformation struct { + /** + * The label of this signature. Will be shown in + * the UI. + */ + Label string `json:"label"` + + /** + * The human-readable doc-comment of this signature. Will be shown + * in the UI but can be omitted. + */ + Documentation interface{} `json:"documentation,omitempty"` // string | MarkupContent + + /** + * The parameters of this signature. + */ + Parameters []ParameterInformation `json:"parameters,omitempty"` +} + +/** + * Represents a parameter of a callable-signature. A parameter can + * have a label and a doc-comment. + */ +type ParameterInformation struct { + /** + * The label of this parameter. Will be shown in + * the UI. + */ + Label string `json:"label"` + + /** + * The human-readable doc-comment of this parameter. Will be shown + * in the UI but can be omitted. + */ + Documentation interface{} `json:"documentation,omitempty"` // string | MarkupContent +} + +type SignatureHelpRegistrationOptions struct { + TextDocumentRegistrationOptions + /** + * The characters that trigger signature help + * automatically. + */ + TriggerCharacters []string `json:"triggerCharacters,omitempty"` +} + +type ReferenceParams struct { + TextDocumentPositionParams + Context ReferenceContext +} + +type ReferenceContext struct { + /** + * Include the declaration of the current symbol. + */ + IncludeDeclaration bool `json:"includeDeclaration"` +} + +/** + * A document highlight is a range inside a text document which deserves + * special attention. Usually a document highlight is visualized by changing + * the background color of its range. + * + */ +type DocumentHighlight struct { + /** + * The range this highlight applies to. + */ + Range Range `json:"range"` + + /** + * The highlight kind, default is DocumentHighlightKind.Text. + */ + Kind float64 `json:"kind,omitempty"` +} + +/** + * A document highlight kind. + */ +type DocumentHighlightKind float64 + +const ( + /** + * A textual occurrence. + */ + TextHighlight DocumentHighlightKind = 1 + + /** + * Read-access of a symbol, like reading a variable. + */ + ReadHighlight DocumentHighlightKind = 2 + + /** + * Write-access of a symbol, like writing to a variable. + */ + WriteHighlight DocumentHighlightKind = 3 +) + +type DocumentSymbolParams struct { + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +/** + * A symbol kind. + */ +type SymbolKind float64 + +const ( + FileSymbol SymbolKind = 1 + ModuleSymbol SymbolKind = 2 + NamespaceSymbol SymbolKind = 3 + PackageSymbol SymbolKind = 4 + ClassSymbol SymbolKind = 5 + MethodSymbol SymbolKind = 6 + PropertySymbol SymbolKind = 7 + FieldSymbol SymbolKind = 8 + ConstructorSymbol SymbolKind = 9 + EnumSymbol SymbolKind = 10 + InterfaceSymbol SymbolKind = 11 + FunctionSymbol SymbolKind = 12 + VariableSymbol SymbolKind = 13 + ConstantSymbol SymbolKind = 14 + StringSymbol SymbolKind = 15 + NumberSymbol SymbolKind = 16 + BooleanSymbol SymbolKind = 17 + ArraySymbol SymbolKind = 18 + ObjectSymbol SymbolKind = 19 + KeySymbol SymbolKind = 20 + NullSymbol SymbolKind = 21 + EnumMemberSymbol SymbolKind = 22 + StructSymbol SymbolKind = 23 + EventSymbol SymbolKind = 24 + OperatorSymbol SymbolKind = 25 + TypeParameterSymbol SymbolKind = 26 +) + +/** + * Represents programming constructs like variables, classes, interfaces etc. that appear in a document. Document symbols can be + * hierarchical and they have two ranges: one that encloses its definition and one that points to its most interesting range, + * e.g. the range of an identifier. + */ +type DocumentSymbol struct { + + /** + * The name of this symbol. + */ + Name string `json:"name"` + + /** + * More detail for this symbol, e.g the signature of a function. If not provided the + * name is used. + */ + Detail string `json:"detail,omitempty"` + + /** + * The kind of this symbol. + */ + Kind SymbolKind `json:"kind"` + + /** + * Indicates if this symbol is deprecated. + */ + Deprecated bool `json:"deprecated,omitempty"` + + /** + * The range enclosing this symbol not including leading/trailing whitespace but everything else + * like comments. This information is typically used to determine if the clients cursor is + * inside the symbol to reveal in the symbol in the UI. + */ + Range Range `json:"range"` + + /** + * The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. + * Must be contained by the `range`. + */ + SelectionRange Range `json:"selectionRange"` + + /** + * Children of this symbol, e.g. properties of a class. + */ + Children []DocumentSymbol `json:"children,omitempty"` +} + +/** + * Represents information about programming constructs like variables, classes, + * interfaces etc. + */ +type SymbolInformation struct { + /** + * The name of this symbol. + */ + Name string `json:"name"` + + /** + * The kind of this symbol. + */ + Kind float64 `json:"kind"` + + /** + * Indicates if this symbol is deprecated. + */ + Deprecated bool `json:"deprecated,omitempty"` + + /** + * The location of this symbol. The location's range is used by a tool + * to reveal the location in the editor. If the symbol is selected in the + * tool the range's start information is used to position the cursor. So + * the range usually spans more then the actual symbol's name and does + * normally include things like visibility modifiers. + * + * The range doesn't have to denote a node range in the sense of a abstract + * syntax tree. It can therefore not be used to re-construct a hierarchy of + * the symbols. + */ + Location Location `json:"location"` + + /** + * The name of the symbol containing this symbol. This information is for + * user interface purposes (e.g. to render a qualifier in the user interface + * if necessary). It can't be used to re-infer a hierarchy for the document + * symbols. + */ + ContainerName string `json:"containerName,omitempty"` +} + +/** + * Params for the CodeActionRequest + */ +type CodeActionParams struct { + /** + * The document in which the command was invoked. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The range for which the command was invoked. + */ + Range Range `json:"range"` + + /** + * Context carrying additional information. + */ + Context CodeActionContext `json:"context"` +} + +/** + * The kind of a code action. + * + * Kinds are a hierarchical list of identifiers separated by `.`, e.g. `"refactor.extract.function"`. + * + * The set of kinds is open and client needs to announce the kinds it supports to the server during + * initialization. + */ +type CodeActionKind string + +/** + * A set of predefined code action kinds + */ +const ( + /** + * Base kind for quickfix actions: 'quickfix' + */ + QuickFix CodeActionKind = "quickfix" + + /** + * Base kind for refactoring actions: 'refactor' + */ + Refactor CodeActionKind = "refactor" + + /** + * Base kind for refactoring extraction actions: 'refactor.extract' + * + * Example extract actions: + * + * - Extract method + * - Extract function + * - Extract variable + * - Extract interface from class + * - ... + */ + RefactorExtract CodeActionKind = "refactor.extract" + + /** + * Base kind for refactoring inline actions: 'refactor.inline' + * + * Example inline actions: + * + * - Inline function + * - Inline variable + * - Inline constant + * - ... + */ + RefactorInline CodeActionKind = "refactor.inline" + + /** + * Base kind for refactoring rewrite actions: 'refactor.rewrite' + * + * Example rewrite actions: + * + * - Convert JavaScript function to class + * - Add or remove parameter + * - Encapsulate field + * - Make method static + * - Move method to base class + * - ... + */ + RefactorRewrite CodeActionKind = "refactor.rewrite" + + /** + * Base kind for source actions: `source` + * + * Source code actions apply to the entire file. + */ + Source CodeActionKind = "source" + + /** + * Base kind for an organize imports source action: `source.organizeImports` + */ + SourceOrganizeImports CodeActionKind = "source.organizeImports" +) + +/** + * Contains additional diagnostic information about the context in which + * a code action is run. + */ +type CodeActionContext struct { + /** + * An array of diagnostics. + */ + Diagnostics []Diagnostic `json:"diagnostics"` + + /** + * Requested kind of actions to return. + * + * Actions not of this kind are filtered out by the client before being shown. So servers + * can omit computing them. + */ + Only []CodeActionKind `json:"only,omitempty"` +} + +/** + * A code action represents a change that can be performed in code, e.g. to fix a problem or + * to refactor code. + * + * A CodeAction must set either `edit` and/or a `command`. If both are supplied, the `edit` is applied first, then the `command` is executed. + */ +type CodeAction struct { + + /** + * A short, human-readable, title for this code action. + */ + Title string `json:"title"` + + /** + * The kind of the code action. + * + * Used to filter code actions. + */ + Kind CodeActionKind `json:"kind,omitempty"` + + /** + * The diagnostics that this code action resolves. + */ + Diagnostics []Diagnostic `json:"diagnostics,omitempty"` + + /** + * The workspace edit this code action performs. + */ + Edit WorkspaceEdit `json:"edit,omitempty"` + + /** + * A command this code action executes. If a code action + * provides an edit and a command, first the edit is + * executed and then the command. + */ + Command Command `json:"command,omitempty"` +} + +type CodeLensParams struct { + /** + * The document to request code lens for. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +/** + * A code lens represents a command that should be shown along with + * source text, like the number of references, a way to run tests, etc. + * + * A code lens is _unresolved_ when no command is associated to it. For performance + * reasons the creation of a code lens and resolving should be done in two stages. + */ +type CodeLens struct { + /** + * The range in which this code lens is valid. Should only span a single line. + */ + Range Range `json:"range"` + + /** + * The command this code lens represents. + */ + Command Command `json:"command,omitempty"` + + /** + * A data entry field that is preserved on a code lens item between + * a code lens and a code lens resolve request. + */ + Data interface{} `json:"data"` +} + +type CodeLensRegistrationOptions struct { + TextDocumentRegistrationOptions + /** + * Code lens has a resolve provider as well. + */ + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +type DocumentLinkParams struct { + /** + * The document to provide document links for. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +/** + * A document link is a range in a text document that links to an internal or external resource, like another + * text document or a web site. + */ +type DocumentLink struct { + /** + * The range this link applies to. + */ + Range Range `json:"range"` + /** + * The uri this link points to. If missing a resolve request is sent later. + */ + Target DocumentURI `json:"target,omitempty"` + /** + * A data entry field that is preserved on a document link between a + * DocumentLinkRequest and a DocumentLinkResolveRequest. + */ + Data interface{} `json:"data,omitempty"` +} + +type DocumentLinkRegistrationOptions struct { + TextDocumentRegistrationOptions + /** + * Document links have a resolve provider as well. + */ + ResolveProvider bool `json:"resolveProvider,omitempty"` +} + +type DocumentColorParams struct { + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +type ColorInformation struct { + /** + * The range in the document where this color appears. + */ + Range Range `json:"range"` + + /** + * The actual color value for this color range. + */ + Color Color `json:"color"` +} + +/** + * Represents a color in RGBA space. + */ +type Color struct { + + /** + * The red component of this color in the range [0-1]. + */ + Red float64 `json:"red"` + + /** + * The green component of this color in the range [0-1]. + */ + Green float64 `json:"green"` + + /** + * The blue component of this color in the range [0-1]. + */ + Blue float64 `json:"blue"` + + /** + * The alpha component of this color in the range [0-1]. + */ + Alpha float64 `json:"alpha"` +} + +type ColorPresentationParams struct { + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The color information to request presentations for. + */ + Color Color `json:"color"` + + /** + * The range where the color would be inserted. Serves as a context. + */ + Range Range `json:"range"` +} + +type ColorPresentation struct { + /** + * The label of this color presentation. It will be shown on the color + * picker header. By default this is also the text that is inserted when selecting + * this color presentation. + */ + Label string `json:"label"` + /** + * An [edit](#TextEdit) which is applied to a document when selecting + * this presentation for the color. When `falsy` the [label](#ColorPresentation.label) + * is used. + */ + TextEdit TextEdit `json:"textEdit,omitempty"` + /** + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + */ + AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"` +} + +type DocumentFormattingParams struct { + /** + * The document to format. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The format options. + */ + Options FormattingOptions `json:"options"` +} + +/** + * Value-object describing what options formatting should use. + */ +type FormattingOptions struct { + /** + * Size of a tab in spaces. + */ + TabSize float64 `json:"tabSize"` + + /** + * Prefer spaces over tabs. + */ + InsertSpaces bool `json:"insertSpaces"` + + /** + * Signature for further properties. + */ + // TODO: [key: string]: boolean | number | string; +} + +type DocumentRangeFormattingParams struct { + /** + * The document to format. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The range to format + */ + Range Range `json:"range"` + + /** + * The format options + */ + Options FormattingOptions `json:"options"` +} + +type DocumentOnTypeFormattingParams struct { + /** + * The document to format. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The position at which this request was sent. + */ + Position Position `json:"position"` + + /** + * The character that has been typed. + */ + Ch string `json:"ch"` + + /** + * The format options. + */ + Options FormattingOptions `json:"options"` +} + +type DocumentOnTypeFormattingRegistrationOptions struct { + TextDocumentRegistrationOptions + /** + * A character on which formatting should be triggered, like `}`. + */ + FirstTriggerCharacter string `json:"firstTriggerCharacter"` + /** + * More trigger characters. + */ + MoreTriggerCharacter []string `json:"moreTriggerCharacter"` +} + +type RenameParams struct { + /** + * The document to rename. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The position at which this request was sent. + */ + Position Position `json:"position"` + + /** + * The new name of the symbol. If the given name is not valid the + * request must return a [ResponseError](#ResponseError) with an + * appropriate message set. + */ + NewName string `json:"newName"` +} + +type FoldingRangeRequestParam struct { + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +/** + * Enum of known range kinds + */ +type FoldingRangeKind string + +const ( + /** + * Folding range for a comment + */ + Comment FoldingRangeKind = "comment" + /** + * Folding range for a imports or includes + */ + Imports FoldingRangeKind = "imports" + /** + * Folding range for a region (e.g. `#region`) + */ + Region FoldingRangeKind = "region" +) + +/** + * Represents a folding range. + */ +type FoldingRange struct { + + /** + * The zero-based line number from where the folded range starts. + */ + StartLine float64 `json:"startLine"` + + /** + * The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. + */ + StartCharacter float64 `json:"startCharacter,omitempty"` + + /** + * The zero-based line number where the folded range ends. + */ + EndLine float64 `json:"endLine"` + + /** + * The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. + */ + EndCharacter float64 `json:"endCharacter,omitempty"` + + /** + * Describes the kind of the folding range such as `comment' or 'region'. The kind + * is used to categorize folding ranges and used by commands like 'Fold all comments'. See + * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. + */ + Kind string `json:"kind,omitempty"` +} diff --git a/internal/lsp/protocol/protocol.go b/internal/lsp/protocol/protocol.go new file mode 100644 index 0000000000..2768250284 --- /dev/null +++ b/internal/lsp/protocol/protocol.go @@ -0,0 +1,34 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package protocol + +import ( + "context" + + "golang.org/x/tools/internal/jsonrpc2" +) + +func canceller(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request) { + conn.Notify(context.Background(), "$/cancelRequest", &CancelParams{ID: *req.ID}) +} + +func RunClient(ctx context.Context, stream jsonrpc2.Stream, client Client, opts ...interface{}) (*jsonrpc2.Conn, Server) { + opts = append([]interface{}{clientHandler(client), canceller}, opts...) + conn := jsonrpc2.NewConn(ctx, stream, opts...) + return conn, &serverDispatcher{Conn: conn} +} + +func RunServer(ctx context.Context, stream jsonrpc2.Stream, server Server, opts ...interface{}) (*jsonrpc2.Conn, Client) { + opts = append([]interface{}{serverHandler(server), canceller}, opts...) + conn := jsonrpc2.NewConn(ctx, stream, opts...) + return conn, &clientDispatcher{Conn: conn} +} + +func toJSONError(err error) *jsonrpc2.Error { + if jsonError, ok := err.(*jsonrpc2.Error); ok { + return jsonError + } + return jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) +} diff --git a/internal/lsp/protocol/registration.go b/internal/lsp/protocol/registration.go new file mode 100644 index 0000000000..31e1eb592c --- /dev/null +++ b/internal/lsp/protocol/registration.go @@ -0,0 +1,61 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the corresponding structures to the +// "Client" part of the LSP specification. + +package protocol + +/** + * General parameters to register for a capability. + */ +type Registration struct { + /** + * The id used to register the request. The id can be used to deregister + * the request again. + */ + ID string `json:"id"` + + /** + * The method / capability to register for. + */ + Method string `json:"method"` + + /** + * Options necessary for the registration. + */ + RegisterOptions interface{} `json:"registerOptions,omitempty"` +} + +type RegistrationParams struct { + Registrations []Registration `json:"registrations"` +} + +type TextDocumentRegistrationOptions struct { + /** + * A document selector to identify the scope of the registration. If set to null + * the document selector provided on the client side will be used. + */ + DocumentSelector *DocumentSelector `json:"documentSelector"` +} + +/** + * General parameters to unregister a capability. + */ +type Unregistration struct { + /** + * The id used to unregister the request or notification. Usually an id + * provided during the register request. + */ + ID string `json:"id"` + + /** + * The method / capability to unregister for. + */ + Method string `json:"method"` +} + +type UnregistrationParams struct { + Unregisterations []Unregistration `json:"unregisterations"` +} diff --git a/internal/lsp/protocol/server.go b/internal/lsp/protocol/server.go new file mode 100644 index 0000000000..22694f15d9 --- /dev/null +++ b/internal/lsp/protocol/server.go @@ -0,0 +1,718 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package protocol + +import ( + "context" + "encoding/json" + + "golang.org/x/tools/internal/jsonrpc2" +) + +type Server interface { + Initialize(context.Context, *InitializeParams) (*InitializeResult, error) + Initialized(context.Context, *InitializedParams) error + Shutdown(context.Context) error + Exit(context.Context) error + DidChangeWorkspaceFolders(context.Context, *DidChangeWorkspaceFoldersParams) error + DidChangeConfiguration(context.Context, *DidChangeConfigurationParams) error + DidChangeWatchedFiles(context.Context, *DidChangeWatchedFilesParams) error + Symbols(context.Context, *WorkspaceSymbolParams) ([]SymbolInformation, error) + ExecuteCommand(context.Context, *ExecuteCommandParams) (interface{}, error) + DidOpen(context.Context, *DidOpenTextDocumentParams) error + DidChange(context.Context, *DidChangeTextDocumentParams) error + WillSave(context.Context, *WillSaveTextDocumentParams) error + WillSaveWaitUntil(context.Context, *WillSaveTextDocumentParams) ([]TextEdit, error) + DidSave(context.Context, *DidSaveTextDocumentParams) error + DidClose(context.Context, *DidCloseTextDocumentParams) error + Completion(context.Context, *CompletionParams) (*CompletionList, error) + CompletionResolve(context.Context, *CompletionItem) (*CompletionItem, error) + Hover(context.Context, *TextDocumentPositionParams) (*Hover, error) + SignatureHelp(context.Context, *TextDocumentPositionParams) (*SignatureHelp, error) + Definition(context.Context, *TextDocumentPositionParams) ([]Location, error) + TypeDefinition(context.Context, *TextDocumentPositionParams) ([]Location, error) + Implementation(context.Context, *TextDocumentPositionParams) ([]Location, error) + References(context.Context, *ReferenceParams) ([]Location, error) + DocumentHighlight(context.Context, *TextDocumentPositionParams) ([]DocumentHighlight, error) + DocumentSymbol(context.Context, *DocumentSymbolParams) ([]DocumentSymbol, error) + CodeAction(context.Context, *CodeActionParams) ([]CodeAction, error) + CodeLens(context.Context, *CodeLensParams) ([]CodeLens, error) + CodeLensResolve(context.Context, *CodeLens) (*CodeLens, error) + DocumentLink(context.Context, *DocumentLinkParams) ([]DocumentLink, error) + DocumentLinkResolve(context.Context, *DocumentLink) (*DocumentLink, error) + DocumentColor(context.Context, *DocumentColorParams) ([]ColorInformation, error) + ColorPresentation(context.Context, *ColorPresentationParams) ([]ColorPresentation, error) + Formatting(context.Context, *DocumentFormattingParams) ([]TextEdit, error) + RangeFormatting(context.Context, *DocumentRangeFormattingParams) ([]TextEdit, error) + OnTypeFormatting(context.Context, *DocumentOnTypeFormattingParams) ([]TextEdit, error) + Rename(context.Context, *RenameParams) ([]WorkspaceEdit, error) + FoldingRanges(context.Context, *FoldingRangeRequestParam) ([]FoldingRange, error) +} + +func serverHandler(server Server) jsonrpc2.Handler { + return func(ctx context.Context, conn *jsonrpc2.Conn, r *jsonrpc2.Request) (interface{}, *jsonrpc2.Error) { + switch r.Method { + case "initialize": + var params InitializeParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.Initialize(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "initialized": + var params InitializedParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := server.Initialized(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "shutdown": + if r.Params != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params") + } + if err := server.Shutdown(ctx); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "exit": + if r.Params != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params") + } + if err := server.Exit(ctx); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "$/cancelRequest": + var params CancelParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + conn.Cancel(params.ID) + return nil, nil + + case "workspace/didChangeWorkspaceFolders": + var params DidChangeWorkspaceFoldersParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := server.DidChangeWorkspaceFolders(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "workspace/didChangeConfiguration": + var params DidChangeConfigurationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := server.DidChangeConfiguration(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "workspace/didChangeWatchedFiles": + var params DidChangeWatchedFilesParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := server.DidChangeWatchedFiles(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "workspace/symbol": + var params WorkspaceSymbolParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.Symbols(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "workspace/executeCommand": + var params ExecuteCommandParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.ExecuteCommand(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/didOpen": + var params DidOpenTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := server.DidOpen(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "textDocument/didChange": + var params DidChangeTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := server.DidChange(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "textDocument/willSave": + var params WillSaveTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := server.WillSave(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "textDocument/willSaveWaitUntil": + var params WillSaveTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.WillSaveWaitUntil(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/didSave": + var params DidSaveTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := server.DidSave(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "textDocument/didClose": + var params DidCloseTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := server.DidClose(ctx, ¶ms); err != nil { + return nil, toJSONError(err) + } + return nil, nil + + case "textDocument/completion": + var params CompletionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.Completion(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "completionItem/resolve": + var params CompletionItem + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.CompletionResolve(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/hover": + var params TextDocumentPositionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.Hover(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/signatureHelp": + var params TextDocumentPositionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.SignatureHelp(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/definition": + var params TextDocumentPositionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.Definition(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/typeDefinition": + var params TextDocumentPositionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.TypeDefinition(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/implementation": + var params TextDocumentPositionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.Implementation(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/references": + var params ReferenceParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.References(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/documentHighlight": + var params TextDocumentPositionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.DocumentHighlight(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/documentSymbol": + var params DocumentSymbolParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.DocumentSymbol(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/codeAction": + var params CodeActionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.CodeAction(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/codeLens": + var params CodeLensParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.CodeLens(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "codeLens/resolve": + var params CodeLens + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.CodeLensResolve(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/documentLink": + var params DocumentLinkParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.DocumentLink(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "documentLink/resolve": + var params DocumentLink + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.DocumentLinkResolve(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/documentColor": + var params DocumentColorParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.DocumentColor(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/colorPresentation": + var params ColorPresentationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.ColorPresentation(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/formatting": + var params DocumentFormattingParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.Formatting(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/rangeFormatting": + var params DocumentRangeFormattingParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.RangeFormatting(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/onTypeFormatting": + var params DocumentOnTypeFormattingParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.OnTypeFormatting(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/rename": + var params RenameParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.Rename(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + + case "textDocument/foldingRanges": + var params FoldingRangeRequestParam + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + resp, err := server.FoldingRanges(ctx, ¶ms) + if err != nil { + return nil, toJSONError(err) + } + return resp, nil + default: + return nil, jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not found", r.Method) + } + } +} + +type serverDispatcher struct { + *jsonrpc2.Conn +} + +func (s *serverDispatcher) Initialize(ctx context.Context, params *InitializeParams) (*InitializeResult, error) { + var result InitializeResult + if err := s.Conn.Call(ctx, "initialize", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) Initialized(ctx context.Context, params *InitializedParams) error { + return s.Conn.Notify(ctx, "initialized", params) +} + +func (s *serverDispatcher) Shutdown(ctx context.Context) error { + return s.Conn.Call(ctx, "shutdown", nil, nil) +} + +func (s *serverDispatcher) Exit(ctx context.Context) error { + return s.Conn.Notify(ctx, "exit", nil) +} + +func (s *serverDispatcher) DidChangeWorkspaceFolders(ctx context.Context, params *DidChangeWorkspaceFoldersParams) error { + return s.Conn.Notify(ctx, "workspace/didChangeWorkspaceFolders", params) +} + +func (s *serverDispatcher) DidChangeConfiguration(ctx context.Context, params *DidChangeConfigurationParams) error { + return s.Conn.Notify(ctx, "workspace/didChangeConfiguration", params) +} + +func (s *serverDispatcher) DidChangeWatchedFiles(ctx context.Context, params *DidChangeWatchedFilesParams) error { + return s.Conn.Notify(ctx, "workspace/didChangeWatchedFiles", params) +} + +func (s *serverDispatcher) Symbols(ctx context.Context, params *WorkspaceSymbolParams) ([]SymbolInformation, error) { + var result []SymbolInformation + if err := s.Conn.Call(ctx, "workspace/symbol", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) ExecuteCommand(ctx context.Context, params *ExecuteCommandParams) (interface{}, error) { + var result interface{} + if err := s.Conn.Call(ctx, "workspace/executeCommand", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) DidOpen(ctx context.Context, params *DidOpenTextDocumentParams) error { + return s.Conn.Notify(ctx, "textDocument/didOpen", params) +} + +func (s *serverDispatcher) DidChange(ctx context.Context, params *DidChangeTextDocumentParams) error { + return s.Conn.Notify(ctx, "textDocument/didChange", params) +} + +func (s *serverDispatcher) WillSave(ctx context.Context, params *WillSaveTextDocumentParams) error { + return s.Conn.Notify(ctx, "textDocument/willSave", params) +} + +func (s *serverDispatcher) WillSaveWaitUntil(ctx context.Context, params *WillSaveTextDocumentParams) ([]TextEdit, error) { + var result []TextEdit + if err := s.Conn.Call(ctx, "textDocument/willSaveWaitUntil", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) DidSave(ctx context.Context, params *DidSaveTextDocumentParams) error { + return s.Conn.Notify(ctx, "textDocument/didSave", params) +} + +func (s *serverDispatcher) DidClose(ctx context.Context, params *DidCloseTextDocumentParams) error { + return s.Conn.Notify(ctx, "textDocument/didClose", params) +} + +func (s *serverDispatcher) Completion(ctx context.Context, params *CompletionParams) (*CompletionList, error) { + var result CompletionList + if err := s.Conn.Call(ctx, "textDocument/completion", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) CompletionResolve(ctx context.Context, params *CompletionItem) (*CompletionItem, error) { + var result CompletionItem + if err := s.Conn.Call(ctx, "completionItem/resolve", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) Hover(ctx context.Context, params *TextDocumentPositionParams) (*Hover, error) { + var result Hover + if err := s.Conn.Call(ctx, "textDocument/hover", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) SignatureHelp(ctx context.Context, params *TextDocumentPositionParams) (*SignatureHelp, error) { + var result SignatureHelp + if err := s.Conn.Call(ctx, "textDocument/signatureHelp", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) Definition(ctx context.Context, params *TextDocumentPositionParams) ([]Location, error) { + var result []Location + if err := s.Conn.Call(ctx, "textDocument/definition", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) TypeDefinition(ctx context.Context, params *TextDocumentPositionParams) ([]Location, error) { + var result []Location + if err := s.Conn.Call(ctx, "textDocument/typeDefinition", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) Implementation(ctx context.Context, params *TextDocumentPositionParams) ([]Location, error) { + var result []Location + if err := s.Conn.Call(ctx, "textDocument/implementation", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) References(ctx context.Context, params *ReferenceParams) ([]Location, error) { + var result []Location + if err := s.Conn.Call(ctx, "textDocument/references", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) DocumentHighlight(ctx context.Context, params *TextDocumentPositionParams) ([]DocumentHighlight, error) { + var result []DocumentHighlight + if err := s.Conn.Call(ctx, "textDocument/documentHighlight", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) DocumentSymbol(ctx context.Context, params *DocumentSymbolParams) ([]DocumentSymbol, error) { + var result []DocumentSymbol + if err := s.Conn.Call(ctx, "textDocument/documentSymbol", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) CodeAction(ctx context.Context, params *CodeActionParams) ([]CodeAction, error) { + var result []CodeAction + if err := s.Conn.Call(ctx, "textDocument/codeAction", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) CodeLens(ctx context.Context, params *CodeLensParams) ([]CodeLens, error) { + var result []CodeLens + if err := s.Conn.Call(ctx, "textDocument/codeLens", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) CodeLensResolve(ctx context.Context, params *CodeLens) (*CodeLens, error) { + var result CodeLens + if err := s.Conn.Call(ctx, "codeLens/resolve", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) DocumentLink(ctx context.Context, params *DocumentLinkParams) ([]DocumentLink, error) { + var result []DocumentLink + if err := s.Conn.Call(ctx, "textDocument/documentLink", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) DocumentLinkResolve(ctx context.Context, params *DocumentLink) (*DocumentLink, error) { + var result DocumentLink + if err := s.Conn.Call(ctx, "documentLink/resolve", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) DocumentColor(ctx context.Context, params *DocumentColorParams) ([]ColorInformation, error) { + var result []ColorInformation + if err := s.Conn.Call(ctx, "textDocument/documentColor", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) ColorPresentation(ctx context.Context, params *ColorPresentationParams) ([]ColorPresentation, error) { + var result []ColorPresentation + if err := s.Conn.Call(ctx, "textDocument/colorPresentation", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) Formatting(ctx context.Context, params *DocumentFormattingParams) ([]TextEdit, error) { + var result []TextEdit + if err := s.Conn.Call(ctx, "textDocument/formatting", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) RangeFormatting(ctx context.Context, params *DocumentRangeFormattingParams) ([]TextEdit, error) { + var result []TextEdit + if err := s.Conn.Call(ctx, "textDocument/rangeFormatting", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) OnTypeFormatting(ctx context.Context, params *DocumentOnTypeFormattingParams) ([]TextEdit, error) { + var result []TextEdit + if err := s.Conn.Call(ctx, "textDocument/onTypeFormatting", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) Rename(ctx context.Context, params *RenameParams) ([]WorkspaceEdit, error) { + var result []WorkspaceEdit + if err := s.Conn.Call(ctx, "textDocument/rename", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) FoldingRanges(ctx context.Context, params *FoldingRangeRequestParam) ([]FoldingRange, error) { + var result []FoldingRange + if err := s.Conn.Call(ctx, "textDocument/foldingRanges", params, &result); err != nil { + return nil, err + } + return result, nil +} diff --git a/internal/lsp/protocol/text.go b/internal/lsp/protocol/text.go new file mode 100644 index 0000000000..83456a415b --- /dev/null +++ b/internal/lsp/protocol/text.go @@ -0,0 +1,130 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the corresponding structures to the +// "Text Synchronization" part of the LSP specification. + +package protocol + +type DidOpenTextDocumentParams struct { + /** + * The document that was opened. + */ + TextDocument TextDocumentItem `json:"textDocument"` +} + +type DidChangeTextDocumentParams struct { + /** + * The document that did change. The version number points + * to the version after all provided content changes have + * been applied. + */ + TextDocument VersionedTextDocumentIdentifier `json:"textDocument"` + + /** + * The actual content changes. The content changes describe single state changes + * to the document. So if there are two content changes c1 and c2 for a document + * in state S10 then c1 move the document to S11 and c2 to S12. + */ + ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"` +} + +/** + * An event describing a change to a text document. If range and rangeLength are omitted + * the new text is considered to be the full content of the document. + */ +type TextDocumentContentChangeEvent struct { + /** + * The range of the document that changed. + */ + Range Range `json:"range,omitempty"` + + /** + * The length of the range that got replaced. + */ + RangeLength float64 `json:"rangeLength,omitempty"` + + /** + * The new text of the range/document. + */ + Text string `json:"text"` +} + +/** + * Describe options to be used when registering for text document change events. + */ +type TextDocumentChangeRegistrationOptions struct { + TextDocumentRegistrationOptions + /** + * How documents are synced to the server. See TextDocumentSyncKind.Full + * and TextDocumentSyncKind.Incremental. + */ + SyncKind float64 `json:"syncKind"` +} + +/** + * The parameters send in a will save text document notification. + */ +type WillSaveTextDocumentParams struct { + /** + * The document that will be saved. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The 'TextDocumentSaveReason'. + */ + Reason TextDocumentSaveReason `json:"reason"` +} + +/** + * Represents reasons why a text document is saved. + */ +type TextDocumentSaveReason float64 + +const ( + /** + * Manually triggered, e.g. by the user pressing save, by starting debugging, + * or by an API call. + */ + Manual TextDocumentSaveReason = 1 + + /** + * Automatic after a delay. + */ + AfterDelay TextDocumentSaveReason = 2 + + /** + * When the editor lost focus. + */ + FocusOut TextDocumentSaveReason = 3 +) + +type DidSaveTextDocumentParams struct { + /** + * The document that was saved. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * Optional the content when saved. Depends on the includeText value + * when the save notification was requested. + */ + Text string `json:"text,omitempty"` +} + +type TextDocumentSaveRegistrationOptions struct { + TextDocumentRegistrationOptions + /** + * The client is supposed to include the content on save. + */ + IncludeText bool `json:"includeText,omitempty"` +} + +type DidCloseTextDocumentParams struct { + /** + * The document that was closed. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} diff --git a/internal/lsp/protocol/window.go b/internal/lsp/protocol/window.go new file mode 100644 index 0000000000..11055682ec --- /dev/null +++ b/internal/lsp/protocol/window.go @@ -0,0 +1,77 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the corresponding structures to the +// "Window" messages part of the LSP specification. + +package protocol + +type ShowMessageParams struct { + /** + * The message type. See {@link MessageType}. + */ + Type MessageType `json:"type"` + + /** + * The actual message. + */ + Message string `json:"message"` +} + +type MessageType float64 + +const ( + /** + * An error message. + */ + Error MessageType = 1 + /** + * A warning message. + */ + Warning MessageType = 2 + /** + * An information message. + */ + Info MessageType = 3 + /** + * A log message. + */ + Log MessageType = 4 +) + +type ShowMessageRequestParams struct { + /** + * The message type. See {@link MessageType}. + */ + Type MessageType `json:"type"` + + /** + * The actual message. + */ + Message string `json:"message"` + + /** + * The message action items to present. + */ + Actions []MessageActionItem `json:"actions,omitempty"` +} + +type MessageActionItem struct { + /** + * A short title like 'Retry', 'Open Log' etc. + */ + Title string +} + +type LogMessageParams struct { + /** + * The message type. See {@link MessageType}. + */ + Type MessageType `json:"type"` + + /** + * The actual message. + */ + Message string `json:"message"` +} diff --git a/internal/lsp/protocol/workspace.go b/internal/lsp/protocol/workspace.go new file mode 100644 index 0000000000..c46584927a --- /dev/null +++ b/internal/lsp/protocol/workspace.go @@ -0,0 +1,203 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains the corresponding structures to the +// "Workspace" part of the LSP specification. + +package protocol + +type WorkspaceFolder struct { + /** + * The associated URI for this workspace folder. + */ + URI string `json:"uri"` + + /** + * The name of the workspace folder. Defaults to the + * uri's basename. + */ + Name string `json:"name"` +} + +type DidChangeWorkspaceFoldersParams struct { + /** + * The actual workspace folder change event. + */ + Event WorkspaceFoldersChangeEvent `json:"event"` +} + +/** + * The workspace folder change event. + */ +type WorkspaceFoldersChangeEvent struct { + /** + * The array of added workspace folders + */ + Added []WorkspaceFolder `json:"added"` + + /** + * The array of the removed workspace folders + */ + Removed []WorkspaceFolder `json:"removed"` +} + +type DidChangeConfigurationParams struct { + /** + * The actual changed settings + */ + Settings interface{} `json:"settings"` +} + +type ConfigurationParams struct { + Items []ConfigurationItem `json:"items"` +} + +type ConfigurationItem struct { + /** + * The scope to get the configuration section for. + */ + ScopeURI string `json:"scopeURI,omitempty"` + + /** + * The configuration section asked for. + */ + Section string `json:"section,omitempty"` +} + +type DidChangeWatchedFilesParams struct { + /** + * The actual file events. + */ + Changes []FileEvent `json:"changes"` +} + +/** + * An event describing a file change. + */ +type FileEvent struct { + /** + * The file's URI. + */ + URI DocumentURI `json:"uri"` + /** + * The change type. + */ + Type float64 `json:"type"` +} + +/** + * The file event type. + */ +type FileChangeType float64 + +const ( + /** + * The file got created. + */ + Created FileChangeType = 1 + /** + * The file got changed. + */ + Changed FileChangeType = 2 + /** + * The file got deleted. + */ + Deleted FileChangeType = 3 +) + +/** + * Describe options to be used when registering for text document change events. + */ +type DidChangeWatchedFilesRegistrationOptions struct { + /** + * The watchers to register. + */ + Watchers []FileSystemWatcher `json:"watchers"` +} + +type FileSystemWatcher struct { + /** + * The glob pattern to watch + */ + GlobPattern string `json:"globPattern"` + + /** + * The kind of events of interest. If omitted it defaults + * to WatchKind.Create | WatchKind.Change | WatchKind.Delete + * which is 7. + */ + Kind float64 `json:"kind,omitempty"` +} + +type WatchKind float64 + +const ( + /** + * Interested in create events. + */ + Create WatchKind = 1 + + /** + * Interested in change events + */ + Change WatchKind = 2 + + /** + * Interested in delete events + */ + Delete WatchKind = 4 +) + +/** + * The parameters of a Workspace Symbol Request. + */ +type WorkspaceSymbolParams struct { + /** + * A non-empty query string + */ + Query string `json:"query"` +} + +type ExecuteCommandParams struct { + + /** + * The identifier of the actual command handler. + */ + Command string `json:"command"` + /** + * Arguments that the command should be invoked with. + */ + Arguments []interface{} `json:"arguments,omitempty"` +} + +/** + * Execute command registration options. + */ +type ExecuteCommandRegistrationOptions struct { + /** + * The commands to be executed on the server + */ + Commands []string `json:"commands"` +} + +type ApplyWorkspaceEditParams struct { + /** + * An optional label of the workspace edit. This label is + * presented in the user interface for example on an undo + * stack to undo the workspace edit. + */ + Label string `json:"label,omitempty"` + + /** + * The edits to apply. + */ + Edit WorkspaceEdit `json:"edit"` +} + +type ApplyWorkspaceEditResponse struct { + /** + * Indicates whether the edit was applied or not. + */ + Applied bool `json:"applied"` +}