commit 9061064e9772d9f6809fb4c4ce9712c1f1e7b07f Author: Henrik Hautakoski Date: Sat Nov 1 06:51:09 2025 +0100 Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..b3a81ed --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +# Language Server Protocol for golang + +Language Server Protocol implementation in Go. + +## Design notes + +The package does not include JSON RPC handling as that is better left to other packages. + +## Example + +Example code using [github.com/sourcegraph/jsonrpc2](https://github.com/sourcegraph/jsonrpc2) + +```go + +import ( + "fmt" + "io" + "context" + "encoding/json" + "github.com/sourcegraph/jsonrpc2" +) + +func handler(ctx context.Context, conn *jsonrpc2.Conn, req *jsonrpc2.Request) (any, error) { + + switch req.Method { + case protocol.MethodInitialize: + var params protocol.InitializeParams + if err := json.Unmarshal(*req.Params, ¶ms); err != nil { + return nil, err + } + // handle initialize + case protocol.MethodTextDocumentDidChange: + var params protocol.DidChangeTextDocumentParams + if err := json.Unmarshal(*req.Params, ¶ms); err != nil { + return nil, err + } + // handle did change + default: + // Respond with a method not found error + return nil, &jsonrpc2.Error{ + Code: jsonrpc2.CodeMethodNotFound, + Message: fmt.Sprintf("Method %s not found", req.Method), + } + } + return nil, nil +} + +func (s Server) Run(ctx context.Context, conn io.ReadWriteCloser) error { + stream := jsonrpc2.NewBufferedStream(conn, jsonrpc2.VSCodeObjectCodec{}) + rpc := jsonrpc2.NewConn(ctx, stream, jsonrpc2.HandlerWithError(s.dispatch)) + + select { + case <-ctx.Done(): + return fmt.Errorf("context closed") + case <-rpc.DisconnectNotify(): + return nil + } +} +``` + +# Author + +Henrik Hautakoski diff --git a/base.go b/base.go new file mode 100644 index 0000000..3d39f41 --- /dev/null +++ b/base.go @@ -0,0 +1,144 @@ +package protocol + +// LSPAny can be a primitive (string, number, boolean, null), an object, or an array. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#lspAny +// +// @since 3.17.0 +type LSPAny = any + +// DocumentURI This is just a string alias, typically a `file://` or other scheme URI. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentUri +type DocumentURI string + +// Position in a text document expressed as zero-based line and character offset. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position +type Position struct { + // Line position in a document (zero-based). + Line uint32 `json:"line"` + + // Character offset on a line in a document (zero-based). + // + // The meaning of this offset is determined by the negotiated + // `PositionEncodingKind`. + Character uint32 `json:"character"` +} + +// PositionEncodingKind A set of predefined position encoding kinds. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#positionEncodingKind +// +// @since 3.17.0 +type PositionEncodingKind string + +const ( + // Character offsets count UTF-8 code units. + PositionEncodingKindUTF8 PositionEncodingKind = "utf-8" + + // Character offsets count UTF-16 code units. + // This is the default and must always be supported by servers + PositionEncodingKindUTF16 PositionEncodingKind = "utf-16" + + // Character offsets count UTF-32 code units. + // Implementation note: these are the same as Unicode code points, + // so this `PositionEncodingKind` may also be used for an + // encoding-agnostic representation of character offsets. + PositionEncodingKindUTF32 PositionEncodingKind = "utf-32" +) + +// Range A 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. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#range +type Range struct { + // The range's start position. + Start Position `json:"start"` + + // The range's end position. + End Position `json:"end"` +} + +// LanguageID - language identifier represented as a string. +type LanguageID string + +const ( + // LanguagePHP is the identifier for PHP documents. + LanguagePHP LanguageID = "php" + + // LanguageBlade is the identifier for blade documents. + LanguageBlade LanguageID = "blade" +) + +// Location inside a resource, such as a line inside a text file. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location +type Location struct { + // URI of the document. + URI DocumentURI `json:"uri"` + + // The range within the document. + Range Range `json:"range"` +} + +// LocationLink represents a link between a source and a target location. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#locationLink +// +// @since 3.14.0 +type LocationLink struct { + // Span of the origin of this link. + // Used as the underlined span for mouse interaction. + // Clients should omit this property if the origin selection range is not applicable. + OriginSelectionRange *Range `json:"originSelectionRange,omitempty"` + + // The target resource identifier. + TargetURI DocumentURI `json:"targetUri"` + + // The full target range of this link. + // If the target for example is a symbol then target range is the range enclosing this symbol not including leading/trailing whitespace but everything else + // like comments. This information is typically used to highlight the range in the editor. + TargetRange Range `json:"targetRange"` + + // The range that should be selected and revealed when this link is being followed, e.g. the name of a function. + // Must be contained by the `targetRange`. See also `DocumentSymbol#range`. + TargetSelectionRange Range `json:"targetSelectionRange"` +} + +// ChangeAnnotation represents additional information that describes a change. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#changeAnnotation +// +// @since 3.16.0 +type ChangeAnnotation struct { + // A human-readable string describing the actual change. The string is + // rendered prominent in the user interface. + Label string `json:"label"` + + // A flag which indicates that user confirmation is needed + // before applying the change. + NeedsConfirmation *bool `json:"needsConfirmation,omitempty"` + + // A human-readable string which is rendered less prominent in the + // user interface. + Description string `json:"description,omitempty"` +} + +// MarkupKind 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. +// +// @see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#markupContent +type MarkupKind string + +const ( + // Plain text is supported as a content format + MarkupKindPlainText MarkupKind = "plaintext" + // Markdown is supported as a content format + MarkupKindMarkdown MarkupKind = "markdown" +) diff --git a/capabilities_client.go b/capabilities_client.go new file mode 100644 index 0000000..51e0ea7 --- /dev/null +++ b/capabilities_client.go @@ -0,0 +1,5 @@ +package protocol + +// ClientCapabilities defines the capabilities of the client (e.g., editor or IDE). +// It tells the language server what features the client supports. +type ClientCapabilities struct{} diff --git a/capabilities_server.go b/capabilities_server.go new file mode 100644 index 0000000..b06851e --- /dev/null +++ b/capabilities_server.go @@ -0,0 +1,155 @@ +package protocol + +// ServerCapabilities defines the capabilities of the language server. +type ServerCapabilities struct { + // The position encoding the server picked from the encodings offered + // by the client via the client capability `general.positionEncodings`. + // + // If the client didn't provide any position encodings the only valid + // value that a server can return is 'utf-16'. + // + // If omitted it defaults to 'utf-16'. + // + // @since 3.17.0 + PositionEncoding *PositionEncodingKind `json:"positionEncoding,omitempty"` + + // 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 any `json:"textDocumentSync,omitempty"` // *TextDocumentSyncOptions | TextDocumentSyncKind + + // The server provides completion support. + CompletionProvider *CompletionOptions `json:"completionProvider,omitempty"` + + // The server provides hover support. + HoverProvider bool `json:"hoverProvider,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 code actions. The `CodeActionOptions` return type is + // only valid if the client signals code action literal support via the + // property `textDocument.codeAction.codeActionLiteralSupport`. + CodeActionProvider bool `json:"codeActionProvider,omitempty"` + + // The server has support for pull model diagnostics. + // + // @since 3.17.0 + DiagnosticProvider any `json:"diagnosticProvider,omitempty"` // DiagnosticOptions | DiagnosticRegistrationOptions + + // Experimental server capabilities. + Experimental *LSPAny `json:"experimental,omitempty"` +} + +// TextDocumentSyncKind Defines how the host (editor) should sync document changes to the language server. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentSyncKind +type TextDocumentSyncKind int + +const ( + // Documents should not be synced at all. + TextDocumentSyncKindNone TextDocumentSyncKind = 0 + + // Documents are synced by always sending the full content of the document. + TextDocumentSyncKindFull TextDocumentSyncKind = 1 + + // Documents are synced by sending the full content on open and close. + // After that only incremental updates to the document are sent. + TextDocumentSyncKindIncremental TextDocumentSyncKind = 2 +) + +// CompletionOptions used during `initialize` or server capabilities registration. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionOptions +type CompletionOptions struct { + WorkDoneProgressOptions + + // The additional characters, beyond the defaults provided by the client (typically + // [a-zA-Z]), that should automatically trigger a completion request. For example + // `.` in JavaScript represents the beginning of an object property or method and is + // thus a good candidate for triggering a completion request. + // + // Most tools trigger a 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. + TriggerCharacters []string `json:"triggerCharacters,omitempty"` + + // The list of all possible characters that commit a completion. This field + // can be used if clients don't support individual commit characters per + // completion item. See client capability + // `completion.completionItem.commitCharactersSupport`. + // + // If a server provides both `allCommitCharacters` and commit characters on + // an individual completion item the ones on the completion item win. + // + // @since 3.2.0 + AllCommitCharacters []string `json:"allCommitCharacters,omitempty"` + + // The server provides support to resolve additional + // information for a completion item. + ResolveProvider *bool `json:"resolveProvider,omitempty"` + + // The server supports the following `CompletionItem` specific + // capabilities. + // + // @since 3.17.0 + CompletionItem *CompletionItemCapability `json:"completionItem,omitempty"` +} + +// CompletionItemCapability Capabilities specific to the `CompletionItem`. +// +// @since 3.17.0 +type CompletionItemCapability struct { + // The server has support for completion item label details (see also `CompletionItemLabelDetails`) + // when receiving a completion item in a resolve call. + // @since 3.17.0 + LabelDetailsSupport *bool `json:"labelDetailsSupport,omitempty"` +} + +// SignatureHelpOptions Server capabilities for signature help requests. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#signatureHelpOptions +type SignatureHelpOptions struct { + // The characters that trigger signature help automatically. + TriggerCharacters []string `json:"triggerCharacters,omitempty"` + + // List of characters that re-trigger signature help. + // These are typically the same as `triggerCharacters`, but may contain additional characters. + // @since 3.2.0 + RetriggerCharacters []string `json:"retriggerCharacters,omitempty"` +} + +// DiagnosticOptions registration options to configure pull diagnostics. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnosticOptions +// +// @since 3.17.0 +type DiagnosticOptions struct { + WorkDoneProgressOptions + + // An optional identifier under which the diagnostics are + // managed by the client. + Identifier string `json:"identifier,omitempty"` + + // Whether the language has inter file dependencies meaning that + // editing code in one file can result in a different diagnostic + // set in another file. Inter file dependencies are common for + // most programming languages and typically uncommon for linters. + InterFileDependencies bool `json:"interFileDependencies"` + + // The server provides support for workspace diagnostics as well. + WorkspaceDiagnostics bool `json:"workspaceDiagnostics"` +} + +// WorkDoneProgressOptions indicates if a request supports work-done progress reporting. +type WorkDoneProgressOptions struct { + // WorkDoneProgress is a flag that indicates whether progress reporting is supported. + WorkDoneProgress bool `json:"workDoneProgress,omitempty"` +} diff --git a/client.go b/client.go new file mode 100644 index 0000000..9512d15 --- /dev/null +++ b/client.go @@ -0,0 +1,31 @@ +package protocol + +// ClientInfo Information about the client. +// The client provides this information during the initialize request. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initializeParams +// +// @since 3.15.0 +type ClientInfo struct { + // The name of the client as defined by the client. + // For example "vscode", "emacs" or "vim". + Name string `json:"name"` + + // The client's version as defined by the client. + Version *string `json:"version,omitempty"` +} + +// Command Represents a reference to a command. Provides a title which will be used to represent a command in the UI +// and optionally a command identifier and arguments. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#command +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 []LSPAny `json:"arguments,omitempty"` +} diff --git a/completion.go b/completion.go new file mode 100644 index 0000000..8ee5eb5 --- /dev/null +++ b/completion.go @@ -0,0 +1,263 @@ +package protocol + +// CompletionItemKind is a kind of a completion entry. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemKind +type CompletionItemKind int + +const ( + CompletionItemKindNone CompletionItemKind = 0 + CompletionItemKindText CompletionItemKind = 1 + CompletionItemKindMethod CompletionItemKind = 2 + CompletionItemKindFunction CompletionItemKind = 3 + CompletionItemKindConstructor CompletionItemKind = 4 + CompletionItemKindField CompletionItemKind = 5 + CompletionItemKindVariable CompletionItemKind = 6 + CompletionItemKindClass CompletionItemKind = 7 + CompletionItemKindInterface CompletionItemKind = 8 + CompletionItemKindModule CompletionItemKind = 9 + CompletionItemKindProperty CompletionItemKind = 10 + CompletionItemKindUnit CompletionItemKind = 11 + CompletionItemKindValue CompletionItemKind = 12 + CompletionItemKindEnum CompletionItemKind = 13 + CompletionItemKindKeyword CompletionItemKind = 14 + CompletionItemKindSnippet CompletionItemKind = 15 + CompletionItemKindColor CompletionItemKind = 16 + CompletionItemKindFile CompletionItemKind = 17 + CompletionItemKindReference CompletionItemKind = 18 + CompletionItemKindFolder CompletionItemKind = 19 + CompletionItemKindEnumMember CompletionItemKind = 20 + CompletionItemKindConstant CompletionItemKind = 21 + CompletionItemKindStruct CompletionItemKind = 22 + CompletionItemKindEvent CompletionItemKind = 23 + CompletionItemKindOperator CompletionItemKind = 24 + CompletionItemKindTypeParameter CompletionItemKind = 25 +) + +// CompletionItemTag - Tags are extra annotations that tweak the rendering of a completion item. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemTag +// +// @since 3.15.0 +type CompletionItemTag int + +const ( + // Render a completion as obsolete, usually using a strike-out. + CompletionItemTagDeprecated CompletionItemTag = 1 +) + +// InsertTextFormat - Defines how the insert text in a completion item is interpreted. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#insertTextFormat +type InsertTextFormat int + +const ( + // The primary text to be inserted is treated as a plain string. + InsertTextFormatPlainText 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. + InsertTextFormatSnippet InsertTextFormat = 2 +) + +// InsertTextMode - How whitespace and indentation is handled during completion item insertion. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#insertTextMode +// +// @since 3.16.0 +type InsertTextMode int + +const ( + // The insertion or replace strings is taken as it is. If the + // value is multi line the lines below the cursor will be + // inserted using the indentation defined in the string value. + // The client will not apply any kind of adjustments to the + // string. + InsertTextModeAsIs InsertTextMode = 1 + + // The editor adjusts leading whitespace of new lines so that + // they match the indentation up to the cursor of the line for + // which the item is accepted. + // + // Consider a line like this: <2tabs><3tabs>foo. Accepting a + // multi line completion item is indented using 2 tabs and all + // following lines inserted will be indented using 2 tabs as well. + InsertTextModeAdjustIndentation InsertTextMode = 2 +) + +// CompletionItem - A completion item represents a suggestion to complete text, typically +// during typing. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItem +type CompletionItem struct { + // The label of this completion item. + // + // The label property is also by default the text that + // is inserted when selecting this completion. + // + // If label details are provided the label itself should + // be an unqualified name of the completion item. + Label string `json:"label"` + + // Additional details for the label. + // + // @since 3.17.0 + LabelDetails *CompletionItemLabelDetails `json:"labelDetails,omitempty"` + + // The kind of this completion item. Based of the kind + // an icon is chosen by the editor. The standardized set + // of available values is defined in `CompletionItemKind`. + Kind CompletionItemKind `json:"kind,omitempty"` + + // Tags for this completion item. + // + // @since 3.15.0 + Tags []CompletionItemTag `json:"tags,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 string `json:"documentation,omitempty"` + + // Indicates if this item is deprecated. + // + // Deprecated: Use `tags` instead if supported. + 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 omitted the label is used + // as the sort text for this item. + SortText string `json:"sortText,omitempty"` + + // A string that should be used when filtering a set of + // completion items. When omitted the label is used as the + // filter text for this item. + FilterText string `json:"filterText,omitempty"` + + // A string that should be inserted into a document when selecting + // this completion. When omitted the label is used as the insert text + // for this item. + // + // 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. + 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`. If omitted defaults to `InsertTextFormat.PlainText`. + // + // Please note that the insertTextFormat doesn't apply to + // `additionalTextEdits`. + InsrtTextFormat *InsertTextFormat `json:"insertTextFormat,omitempty"` + + // How whitespace and indentation is handled during completion + // item insertion. If not provided the client's default value depends on + // the `textDocument.completion.insertTextMode` client capability. + // + // @since 3.16.0 + // @since 3.17.0 - support for `textDocument.completion.insertTextMode` + InsertTextMode *InsertTextMode `json:"insertTextMode,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. + // + // Most editors support two different operations when accepting a completion + // item. One is to insert a completion text and the other is to replace an + // existing text with a completion text. Since this can usually not be + // predetermined by a server it can report both ranges. Clients need to + // signal support for `InsertReplaceEdit`s via the + // `textDocument.completion.completionItem.insertReplaceSupport` client + // capability property. + // + // Note 1: The text edit's range as well as both ranges from an insert + // replace edit must be a [single line] and they must contain the position + // at which completion has been requested. + // Note 2: If an `InsertReplaceEdit` is returned the edit's insert range + // must be a prefix of the edit's replace range, that means it must be + // contained and starting at the same position. + // + // @since 3.16.0 additional type `InsertReplaceEdit` + TextEdit *TextEdit `json:"textEdit,omitempty"` + + // The edit text used if the completion item is part of a CompletionList and + // CompletionList defines an item default for the text edit range. + // + // Clients will only honor this property if they opt into completion list + // item defaults using the capability `completionList.itemDefaults`. + // + // If not provided and a list's default range is provided the label + // property is used as a text. + // + // @since 3.17.0 + TextEditText string `json:"textEditText,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"` + + // A data entry field that is preserved on a completion item between + // a completion and a completion resolve request. + Data LSPAny `json:"data,omitempty"` +} + +// CompletionItemLabelDetails - Additional details for a completion item label. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemLabelDetails +// +// @since 3.17.0 +type CompletionItemLabelDetails struct { + // An optional string which is rendered less prominently directly after `CompletionItem.label`, without any spacing. + Detail *string `json:"detail,omitempty"` + + // An optional string which is rendered less prominently after `CompletionItem.detail`. It should be used for additional + // information, like type or symbol information. + Description *string `json:"description,omitempty"` +} + +// CompletionList - represents a collection of completion items. +// It can be either a list of items or a flag indicating if further items can be resolved. +type CompletionList struct { + // IsIncomplete indicates if the list is complete. + // If true, the client should re-trigger completion when typing more characters. + IsIncomplete bool `json:"isIncomplete"` + + // Items contains the completion items. + Items []CompletionItem `json:"items"` +} diff --git a/diagnostics.go b/diagnostics.go new file mode 100644 index 0000000..b89c32f --- /dev/null +++ b/diagnostics.go @@ -0,0 +1,103 @@ +package protocol + +// Diagnostic - Represents a diagnostic, such as a compiler error or warning. +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic +type Diagnostic struct { + // The range at which the message applies. + Range Range `json:"range"` + + // The diagnostic's severity. To avoid interpretation mismatches when a + // server is used with different clients it is highly recommended that + // servers always provide a severity value. If omitted, it’s recommended + // for the client to interpret it as an Error severity. + Severity DiagnosticSeverity `json:"severity,omitempty"` + + // The diagnostic's code, which might appear in the user interface. + Code any `json:"code,omitempty"` // integer or string + + // An optional property to describe the error code. + // + // @since 3.16.0 + CodeDescription *CodeDescription `json:"codeDescription,omitempty"` + + // 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"` + + // Additional metadata about the diagnostic. + // + // @since 3.15.0 + Tags []DiagnosticTag `json:"tags,omitempty"` + + // An array of related diagnostic information, e.g. when symbol-names within + // a scope collide all definitions can be marked via this property. + RelatedInformation []DiagnosticRelatedInformation `json:"relatedInformation,omitempty"` + + // A data entry field that is preserved between + // a `textDocument/publishDiagnostics` notification and + // `textDocument/codeAction` request. + // + // @since 3.16.0 + Data LSPAny `json:"data,omitempty"` +} + +// DiagnosticSeverity - The severity of a diagnostic message. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnosticSeverity +type DiagnosticSeverity int + +const ( + // Reports an error. + DiagnosticSeverityError DiagnosticSeverity = 1 + + // Reports a warning. + DiagnosticSeverityWarning DiagnosticSeverity = 2 + + // Reports an information. + DiagnosticSeverityInformation DiagnosticSeverity = 3 + + // Reports a hint. + DiagnosticSeverityHint DiagnosticSeverity = 4 +) + +// DiagnosticTag - Additional metadata about a diagnostic. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnosticTag +// +// @since 3.15.0 +type DiagnosticTag int + +const ( + // Unused or unnecessary code. + // Clients are allowed to render diagnostics with this tag faded out instead of having + // an error squiggle. + DiagnosticTagUnnecessary DiagnosticTag = 1 + + // Deprecated or obsolete code. + // Clients are allowed to rendered diagnostics with this tag strike-through. + DiagnosticTagDeprecated DiagnosticTag = 2 +) + +// CodeDescription - Structure to capture a description for an error code. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#codeDescription +// +// @since 3.16.0 +type CodeDescription struct { + // An URI to open with more information about the diagnostic error. + Href DocumentURI `json:"href"` +} + +// DiagnosticRelatedInformation - Represents a related message and source code location for a diagnostic. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnosticRelatedInformation +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"` +} diff --git a/document.go b/document.go new file mode 100644 index 0000000..83b458a --- /dev/null +++ b/document.go @@ -0,0 +1,62 @@ +package protocol + +// TextDocumentIdentifier - is used to identify a specific text document. +// It only contains the URI of the document. +type TextDocumentIdentifier struct { + // URI is the unique resource identifier of the document that was closed. + URI string `json:"uri"` +} + +// VersionedTextDocumentIdentifier - identifies a versioned text document. +type VersionedTextDocumentIdentifier struct { + TextDocumentIdentifier + + // Version is the version number of the document. + Version int `json:"version"` +} + +// TextDocumentItem - represents the information related to a text document. +type TextDocumentItem struct { + // URI is the unique resource identifier of the document (usually a file path or URL). + URI string `json:"uri"` + + // LanguageID is the language identifier associated with the document (e.g., "python", "javascript"). + LanguageID LanguageID `json:"languageId"` + + // Version is the version number of the document. + Version int `json:"version"` + + // Text is the content of the document. + Text string `json:"text"` +} + +// TextDocumentPositionParams - represents parameters for requests that operate on a specific text document +// at a specific position, such as hover information or code actions. +type TextDocumentPositionParams struct { + // TextDocument holds the identifier of the text document. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // Position specifies the position within the text document. + Position Position `json:"position"` +} + +// TextEdit - A text edit applicable to a text document. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textEdit +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 - represents edits to a single text document. +type TextDocumentEdit struct { + // TextDocument identifies the text document to change. + TextDocument VersionedTextDocumentIdentifier `json:"textDocument"` + + // Edits is an array of edits to apply to the text document. + Edits []TextEdit `json:"edits"` +} diff --git a/document_change_operation.go b/document_change_operation.go new file mode 100644 index 0000000..3af0f6b --- /dev/null +++ b/document_change_operation.go @@ -0,0 +1,76 @@ +package protocol + +// DocumentChangeOperation - represents any valid document change operation. +type DocumentChangeOperation interface { + isDocumentChangeOperation() +} + +// ResourceOperation - A generic resource operation. +type ResourceOperation struct { + // resource operation kind + Kind string `json:"kind"` + + // An optional annotation identifier describing the operation. + AnnotationID string `json:"annotationId,omitempty"` +} + +// CreateFile operation. +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#createFile +type CreateFile struct { + ResourceOperation + URI DocumentURI `json:"uri"` + Options *CreateFileOptions `json:"options,omitempty"` +} + +func (CreateFile) isDocumentChangeOperation() {} + +// CreateFileOptions - Options to create a file. +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#createFileOptions +type CreateFileOptions struct { + // Overwrite existing file. Overwrite wins over ignoreIfExists. + Overwrite bool `json:"overwrite,omitempty"` + + // Ignore if exists. + IgnoreIfExists bool `json:"ignoreIfExists,omitempty"` +} + +// RenameFile operation. +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#renameFile +type RenameFile struct { + ResourceOperation + OldURI DocumentURI `json:"oldUri"` + NewURI DocumentURI `json:"newUri"` + Options *RenameFileOptions `json:"options,omitempty"` +} + +// RenameFileOptions - Options to rename a file. +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#renameFileOptions +type RenameFileOptions struct { + // Overwrite target if existing. + Overwrite bool `json:"overwrite,omitempty"` + + // Ignores if target exists. + IgnoreIfExists bool `json:"ignoreIfExists,omitempty"` +} + +func (RenameFile) isDocumentChangeOperation() {} + +// DeleteFile operation. +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#deleteFile +type DeleteFile struct { + ResourceOperation + URI DocumentURI `json:"uri"` + Options *DeleteFileOptions `json:"options,omitempty"` +} + +func (DeleteFile) isDocumentChangeOperation() {} + +// DeleteFileOptions - Options to delete a file. +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#deleteFileOptions +type DeleteFileOptions struct { + // Delete content recursively if a folder is denoted. + Recursive bool `json:"recursive,omitempty"` + + // Ignore the operation if the file doesn't exist. + IgnoreIfNotExists bool `json:"ignoreIfNotExists,omitempty"` +} diff --git a/document_code_action.go b/document_code_action.go new file mode 100644 index 0000000..4ebb3dd --- /dev/null +++ b/document_code_action.go @@ -0,0 +1,115 @@ +package protocol + +const ( + // MethodTextDocumentCodeAction method name of "textDocument/codeAction". + MethodTextDocumentCodeAction = "textDocument/codeAction" +) + +// CodeActionKind - defines the type of code action. +type CodeActionKind string + +const ( + CodeActionQuickFix CodeActionKind = "quickfix" + CodeActionRefactor CodeActionKind = "refactor" + CodeActionRefactorExtract CodeActionKind = "refactor.extract" + CodeActionRefactorInline CodeActionKind = "refactor.inline" + CodeActionRefactorRewrite CodeActionKind = "refactor.rewrite" + CodeActionSource CodeActionKind = "source" + CodeActionSourceOrganizeImports CodeActionKind = "source.organizeImports" +) + +// CodeActionTriggerKind - The reason why code actions were requested. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#codeactiontriggerkind +// +// @since 3.17.0 +type CodeActionTriggerKind int + +const ( + // Code actions were explicitly requested by the user or by an extension. + CodeActionTriggerKindInvoked CodeActionTriggerKind = 1 + + // Code actions were requested automatically. + // This typically happens when a diagnostic is reported and code actions are requested. + // This kind of request should not trigger UI (e.g. prompt the user to pick a code action). + CodeActionTriggerKindAutomatic CodeActionTriggerKind = 2 +) + +// CodeActionParams - defines the parameters passed to the `textDocument/codeAction` request. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#codeActionParams +type CodeActionParams struct { + WorkDoneProgressParams + PartialResultParams + + // The text 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"` +} + +// CodeActionContext - contains additional diagnostic information about the context in which a code action is run. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#codeActionContext +type CodeActionContext struct { + // An array of diagnostics known on the client side overlapping the range provided to the `textDocument/codeAction` request. + 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. + // @since 3.15.0 + Only []CodeActionKind `json:"only,omitempty"` + + // The reason why code actions were requested. + // @since 3.17.0 + TriggerKind CodeActionTriggerKind `json:"triggerKind,omitempty"` +} + +// CodeAction - A code action represents a change that can be performed in code, e.g. to fix a problem or to refactor code. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#codeAction +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"` + + // Marks this as a preferred action. + // Preferred actions are used by the `auto fix` command and can be targeted by keybindings. + // @since 3.15.0 + IsPreferred bool `json:"isPreferred,omitempty"` + + // Marks that the code action cannot currently be applied. + // Clients should follow the `disabled` property to determine if the action is shown in the UI. + // @since 3.16.0 + Disabled *CodeActionDisabled `json:"disabled,omitempty"` + + // The workspace edit this code action performs. + Edit *WorkspaceEdit `json:"edit,omitempty"` + + // A command this code action executes. If both `edit` and `command` are specified, edit is applied first. + Command *Command `json:"command,omitempty"` + + // A data entry field that is preserved between a `textDocument/codeAction` request and a `codeAction/resolve` request. + // @since 3.16.0 + Data any `json:"data,omitempty"` +} + +// CodeActionDisabled - is used to signal to the client that a code action is +// currently disabled and not applicable in the current context. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#codeactiondisabled +type CodeActionDisabled struct { + // Human-readable description of why the code action is currently disabled. + // This is displayed in the UI. + Reason string `json:"reason"` +} diff --git a/document_completion.go b/document_completion.go new file mode 100644 index 0000000..c5b0690 --- /dev/null +++ b/document_completion.go @@ -0,0 +1,104 @@ +package protocol + +import ( + "encoding/json" + "errors" +) + +const ( + // MethodTextDocumentCompletion method name of "textDocument/completion". + MethodTextDocumentCompletion = "textDocument/completion" +) + +// CompletionTriggerKind - How a completion was triggered. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionTriggerKind +type CompletionTriggerKind int + +const ( + // Completion was triggered by typing an identifier (24x7 code complete), manual invocation (e.g Ctrl+Space) or via API. + CompletionTriggerKindInvoked CompletionTriggerKind = 1 + + // Completion was triggered by a trigger character specified by the `triggerCharacters` properties of the `CompletionOptions`. + CompletionTriggerKindTriggerCharacter CompletionTriggerKind = 2 + + // Completion was re-triggered as the current completion list is incomplete. + CompletionTriggerKindTriggerForIncompleteCompletions CompletionTriggerKind = 3 +) + +// CompletionContext - Contains additional information about the context in which a completion request is triggered. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionContext +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 !== CompletionTriggerKindTriggerCharacter` + TriggerCharacter string `json:"triggerCharacter,omitempty"` +} + +// CompletionParams - parameters for a completion request. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionParams +type CompletionParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams + + // The completion context. This is only available if the client specifies to send this using the client capability `textDocument.completion.contextSupport === true` + Context *CompletionContext `json:"context,omitempty"` +} + +// CompletionResponse - The result of a textDocument/completion request is either an array of CompletionItem +// or a CompletionList. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completion +type CompletionResponse struct { + // When the result is a list of completion items. + Items []CompletionItem + + // When the result is a completion list with additional metadata like isIncomplete. + List *CompletionList + + // If null + Null bool +} + +func (cr CompletionResponse) MarshalJSON() ([]byte, error) { + if cr.List != nil { + return json.Marshal(cr.List) + } + return json.Marshal(cr.Items) +} + +func (cr *CompletionResponse) UnmarshalJSON(data []byte) error { + // Check for null + if string(data) == "null" { + cr.Null = true + cr.List = nil + cr.Items = nil + return nil + } + + // Try to decode as a CompletionList. + var list CompletionList + if err := json.Unmarshal(data, &list); err == nil && list.Items != nil { + cr.Null = true + cr.List = &list + cr.Items = nil + return nil + } + + // If decoding as CompletionList fails, try to decode as []CompletionItem. + var items []CompletionItem + if err := json.Unmarshal(data, &items); err == nil { + cr.Null = true + cr.List = nil + cr.Items = items + return nil + } + + // Unknown structure + return errors.New("invalid CompletionResponse: not a CompletionList, []CompletionItem or null") +} diff --git a/document_definition.go b/document_definition.go new file mode 100644 index 0000000..e3cf79e --- /dev/null +++ b/document_definition.go @@ -0,0 +1,79 @@ +package protocol + +import ( + "encoding/json" + "errors" +) + +const ( + // MethodTextDocumentDefinition method name of "textDocument/definition". + MethodTextDocumentDefinition = "textDocument/definition" +) + +// DefinitionParams defines the parameters for a textDocument/definition request. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#definitionParams +type DefinitionParams struct { + WorkDoneProgressParams + PartialResultParams + TextDocumentPositionParams +} + +// DefinitionResponse represents the result of a textDocument/definition request. +// +// It can be a single Location, a slice of Locations, a slice of LocationLinks or null. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#definition +type DefinitionResponse struct { + Location *Location + LocationList []Location + LocationLinks []LocationLink + Null bool +} + +func (dr DefinitionResponse) MarshalJSON() ([]byte, error) { + if dr.Location != nil { + return json.Marshal(dr.Location) + } + if dr.LocationList != nil { + return json.Marshal(dr.LocationList) + } + if dr.LocationLinks != nil { + return json.Marshal(dr.LocationLinks) + } + return []byte("null"), nil +} + +func (dr *DefinitionResponse) UnmarshalJSON(data []byte) error { + // Make sure object is reset. + *dr = DefinitionResponse{} + + // Check for null + if string(data) == "null" { + dr.Null = true + return nil + } + + // Try single Location + var loc Location + if err := json.Unmarshal(data, &loc); err == nil && loc.URI != "" { + dr.Location = &loc + return nil + } + + // Try []Location + var locList []Location + if err := json.Unmarshal(data, &locList); err == nil { + dr.LocationList = locList + return nil + } + + // Try []LocationLink + var linkList []LocationLink + if err := json.Unmarshal(data, &linkList); err == nil { + dr.LocationLinks = linkList + return nil + } + + return errors.New("invalid definition response: not null, Location, []Location, or []LocationLink") +} diff --git a/document_diagnostic.go b/document_diagnostic.go new file mode 100644 index 0000000..5f3a1f7 --- /dev/null +++ b/document_diagnostic.go @@ -0,0 +1,102 @@ +package protocol + +import ( + "encoding/json" + "fmt" +) + +const ( + MethodTextDocumentDiagnostic = "textDocument/diagnostic" +) + +// DocumentDiagnosticParams - Parameters of the document diagnostic request. +// +// @since 3.17.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentDiagnosticParams +type DocumentDiagnosticParams struct { + WorkDoneProgressParams + PartialResultParams + + // The text document to request diagnostics for. + TextDocument TextDocumentIdentifier `json:"textDocument"` + + // The additional identifier provided during registration. + Identifier string `json:"identifier,omitempty"` + + // The current version of the document. + // If provided, servers can avoid computing diagnostics again if the document version hasn’t changed. + PreviousResultID string `json:"previousResultId,omitempty"` +} + +// DocumentDiagnosticReport is either a full or an unchanged diagnostic report. +// +// @since 3.17.0 +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentDiagnosticReport +type DocumentDiagnosticReport struct { + Full *FullDocumentDiagnosticReport + Unchanged *UnchangedDocumentDiagnosticReport +} + +// FullDocumentDiagnosticReport - A full diagnostic report with a full set of problems. +// +// @since 3.17.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#fullDocumentDiagnosticReport +type FullDocumentDiagnosticReport struct { + Kind string `json:"kind"` // Should always be "full" + ResultID string `json:"resultId,omitempty"` + Items []Diagnostic `json:"items"` +} + +// UnchangedDocumentDiagnosticReport - An unchanged diagnostic report indicating nothing has changed. +// +// @since 3.17.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#unchangedDocumentDiagnosticReport +type UnchangedDocumentDiagnosticReport struct { + Kind string `json:"kind"` // Should always be "unchanged" + ResultID string `json:"resultId"` +} + +func (r DocumentDiagnosticReport) MarshalJSON() ([]byte, error) { + if r.Full != nil { + return json.Marshal(r.Full) + } + if r.Unchanged != nil { + return json.Marshal(r.Unchanged) + } + return nil, fmt.Errorf("either the Full or Unchanged field needs to be set") +} + +func (r *DocumentDiagnosticReport) UnmarshalJSON(data []byte) error { + // reset object first. + *r = DocumentDiagnosticReport{} + + var temp struct { + Kind string `json:"kind"` + } + + if err := json.Unmarshal(data, &temp); err != nil { + return err + } + + switch temp.Kind { + case "full": + var full FullDocumentDiagnosticReport + if err := json.Unmarshal(data, &full); err != nil { + return err + } + r.Full = &full + case "unchanged": + var unchanged UnchangedDocumentDiagnosticReport + if err := json.Unmarshal(data, &unchanged); err != nil { + return err + } + r.Unchanged = &unchanged + default: + return fmt.Errorf("unknown document diagnostic report kind: %s", temp.Kind) + } + + return nil +} diff --git a/document_hover.go b/document_hover.go new file mode 100644 index 0000000..526ab91 --- /dev/null +++ b/document_hover.go @@ -0,0 +1,128 @@ +package protocol + +import ( + "encoding/json" + "errors" +) + +const ( + MethodTextDocumentHover = "textDocument/hover" +) + +// HoverParams - Parameters for a textDocument/hover request. +// +// @since 3.0.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#hoverParams +type HoverParams struct { + TextDocumentPositionParams + WorkDoneProgressParams +} + +// Hover - The result of a hover request. +// +// @since 3.0.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#hover +type Hover struct { + // The hover's content. + Contents MarkupContentOrMarkedString `json:"contents"` + + // An optional range inside the text document that is used to + // visualize the hover, e.g. by changing the background color. + Range *Range `json:"range,omitempty"` +} + +// HoverResult - The result of a textDocument/hover request. +// +// Can be a Hover object or null. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#hover +type HoverResult struct { + Hover *Hover + Null bool +} + +func (h *HoverResult) UnmarshalJSON(data []byte) error { + *h = HoverResult{} + + if string(data) == "null" { + h.Null = true + return nil + } + var hover Hover + if err := json.Unmarshal(data, &hover); err == nil { + return err + } + h.Hover = &hover + return nil +} + +func (h HoverResult) MarshalJSON() ([]byte, error) { + if h.Null { + return []byte("null"), nil + } + return json.Marshal(h.Hover) +} + +// MarkedString - can be used to render human-readable text, +// optionally with a language hint. +// +// @since 3.0.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#markedString +type MarkedString struct { + Language string `json:"language,omitempty"` + Value string `json:"value"` +} + +// MarkupContent - represents a string value with optional markup kind. +// +// @since 3.0.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#markupContent +type MarkupContent struct { + Kind MarkupKind `json:"kind"` + Value string `json:"value"` // actual content +} + +type MarkupContentOrMarkedString struct { + Markup *MarkupContent + MarkedString *MarkedString + MarkedStrings []MarkedString +} + +func (m MarkupContentOrMarkedString) MarshalJSON() ([]byte, error) { + if m.Markup != nil { + return json.Marshal(m.Markup) + } + if m.MarkedString != nil { + return json.Marshal(m.MarkedString) + } + if len(m.MarkedStrings) > 0 { + return json.Marshal(m.MarkedStrings) + } + return nil, errors.New("one of MarkupContent, MarkedString or MarkedStrings needs to be set") +} + +func (m *MarkupContentOrMarkedString) UnmarshalJSON(data []byte) error { + var markup MarkupContent + if err := json.Unmarshal(data, &markup); err == nil && markup.Kind != "" { + m.Markup = &markup + return nil + } + + var single MarkedString + if err := json.Unmarshal(data, &single); err == nil && (single.Language != "" || single.Value != "") { + m.MarkedString = &single + return nil + } + + var many []MarkedString + if err := json.Unmarshal(data, &many); err == nil { + m.MarkedStrings = many + return nil + } + + return errors.New("invalid contents: not MarkupContent, MarkedString or []MarkedString") +} diff --git a/document_sync.go b/document_sync.go new file mode 100644 index 0000000..24f4de7 --- /dev/null +++ b/document_sync.go @@ -0,0 +1,89 @@ +package protocol + +const ( + MethodTextDocumentDidOpen = "textDocument/didOpen" + + MethodTextDocumentDidClose = "textDocument/didClose" + + MethodTextDocumentDidChange = "textDocument/didChange" + + MethodTextDocumentDidSave = "textDocument/didSave" +) + +// DidOpenTextDocumentParams - The parameters sent in a didOpen notification. +// +// @since 3.0.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#didOpenTextDocumentParams +type DidOpenTextDocumentParams struct { + // The document that was opened. + TextDocument TextDocumentItem `json:"textDocument"` +} + +// DidCloseTextDocumentParams - The parameters sent in a didClose notification. +// +// @since 3.0.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#didCloseTextDocumentParams +type DidCloseTextDocumentParams struct { + // The document that was closed. + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +// DidChangeTextDocumentParams - The parameters sent in a didChange notification. +// +// @since 3.0.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#didChangeTextDocumentParams +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 (at + // array index 0) and c2 (at array index 1) for a document in state S then + // c1 moves the document from S to S' and c2 from S' to S''. So c1 is + // computed on the state S and c2 is computed on the state S'. + // + // To mirror the content of a document using change events use the following + // approach: + // - start with the same initial content + // - apply the 'textDocument/didChange' notifications in the order you + // receive them. + // - apply the `TextDocumentContentChangeEvent`s in a single notification + // in the order you receive them. + ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"` +} + +// DidSaveTextDocumentParams - The parameters sent in a didSave notification. +// +// @since 3.0.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#didSaveTextDocumentParams +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"` +} + +// TextDocumentContentChangeEvent - An event describing a change to a text document. +// If range and rangeLength are omitted, the new text is considered the full content. +// +// @since 3.0.0 +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentContentChangeEvent +type TextDocumentContentChangeEvent struct { + // The range of the document that changed. + Range *Range `json:"range,omitempty"` + + // The optional length of the range that got replaced. + // Deprecated: use range instead. + RangeLength *uint `json:"rangeLength,omitempty"` + + // The new text of the document. + Text string `json:"text"` +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..af72e6a --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/laravel-ls/protocol + +go 1.19 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/lifecycle.go b/lifecycle.go new file mode 100644 index 0000000..988fdc7 --- /dev/null +++ b/lifecycle.go @@ -0,0 +1,82 @@ +package protocol + +const ( + MethodInitialize = "initialize" + + MethodInitialized = "initialized" +) + +// InitializeParams - The initialize parameters. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initializeParams +type InitializeParams struct { + WorkDoneProgressParams + + // The process Id of the parent process that started the server. + // Is null if the process has not been started by another process. + ProcessID *int `json:"processId,omitempty"` + + // The information about the client. + // + // @since 3.15.0 + ClientInfo *ClientInfo `json:"clientInfo,omitempty"` + + // The locale the client is currently showing the user interface in. + // This must not be used to influence the content of hover, completion, signature help etc. + // + // @since 3.16.0 + Locale *string `json:"locale,omitempty"` + + // The rootPath of the workspace. Is null if no folder is open. + // + // @deprecated in favour of rootUri. + RootPath string `json:"rootPath,omitempty"` + + // 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,omitempty"` + + // User provided initialization options. + InitializationOptions LSPAny `json:"initializationOptions,omitempty"` + + // The capabilities provided by the client (editor or tool) + Capabilities ClientCapabilities `json:"capabilities"` + + // The initial trace setting. If omitted trace is disabled ('off'). + Trace *TraceValue `json:"trace,omitempty"` + + // The workspace folders configured in the client when the server starts. + // This property is only available if the client supports workspace folders. + // + // @since 3.6.0 + WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders,omitempty"` +} + +// InitializeResult - The result returned from an initialize request. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initializeResult +type InitializeResult struct { + // The capabilities the language server provides. + Capabilities ServerCapabilities `json:"capabilities"` + + // Information about the server. + // + // @since 3.15.0 + ServerInfo *ServerInfo `json:"serverInfo,omitempty"` +} + +// TraceValue - The LSP allows the client to control the tracing of the server. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#traceValue +type TraceValue string + +const ( + // No tracing. + TraceValueOff TraceValue = "off" + + // Messages only. + TraceValueMessages TraceValue = "messages" + + // Verbose message logging. + TraceValueVerbose TraceValue = "verbose" +) diff --git a/progress.go b/progress.go new file mode 100644 index 0000000..ab42abc --- /dev/null +++ b/progress.go @@ -0,0 +1,41 @@ +package protocol + +import "encoding/json" + +// ProgressToken - A token that can be used to report work done progress. +// Can be a string or a number. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#progress +type ProgressToken struct { + name string + number int32 +} + +func (v *ProgressToken) MarshalJSON() ([]byte, error) { + if v.name != "" { + return json.Marshal(v.name) + } + + return json.Marshal(v.number) +} + +func (v *ProgressToken) UnmarshalJSON(data []byte) error { + *v = ProgressToken{} + if err := json.Unmarshal(data, &v.number); err == nil { + return nil + } + + return json.Unmarshal(data, &v.name) +} + +// WorkDoneProgressParams - is a parameter property of report work done progress. +type WorkDoneProgressParams struct { + // WorkDoneToken an optional token that a server can use to report work done progress. + WorkDoneToken *ProgressToken `json:"workDoneToken,omitempty"` +} + +// PartialResultParams - allows for partial results in responses. +type PartialResultParams struct { + // PartialResultToken is a token for handling partial result updates. + PartialResultToken *ProgressToken `json:"partialResultToken,omitempty"` +} diff --git a/server.go b/server.go new file mode 100644 index 0000000..dbb84b2 --- /dev/null +++ b/server.go @@ -0,0 +1,14 @@ +package protocol + +// ServerInfo - The server info returned from an initialize request. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initializeResult +// +// @since 3.15.0 +type ServerInfo struct { + // The name of the server as defined by the server. + Name string `json:"name"` + + // The server's version, if provided. + Version string `json:"version,omitempty"` +} diff --git a/workspace.go b/workspace.go new file mode 100644 index 0000000..bc8173b --- /dev/null +++ b/workspace.go @@ -0,0 +1,40 @@ +package protocol + +// 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`. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspaceEdit +type WorkspaceEdit struct { + // Holds changes to existing resources. + // Each entry describes edits to a single document. + Changes map[DocumentURI][]TextEdit `json:"changes,omitempty"` + + // Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes are either + // an array of `TextDocumentEdit`s or a mix of `TextDocumentEdit`, `CreateFile`, `RenameFile`, and `DeleteFile` operations. + // + // Changes to existing files are described with `TextDocumentEdit`. + // Changes to the workspace are described with resource operations like `RenameFile`, `CreateFile`, and `DeleteFile`. + // + // @since 3.13.0 + DocumentChanges []DocumentChangeOperation `json:"documentChanges,omitempty"` + + // A map of change annotations that can be referenced in `AnnotatedTextEdit`s or create, rename and delete file operations. + // + // @since 3.16.0 + ChangeAnnotations map[string]ChangeAnnotation `json:"changeAnnotations,omitempty"` +} + +// WorkspaceFolder - A workspace folder inside a client. +// +// See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspaceFolder +// +// @since 3.6.0 +type WorkspaceFolder struct { + // The associated URI for this workspace folder. + URI DocumentURI `json:"uri"` + + // The name of the workspace folder. Used to refer to this + // workspace folder in the user interface. + Name string `json:"name"` +}