diff --git a/protocol_3_17/base-protocol.go b/protocol_3_17/base-protocol.go new file mode 100644 index 0000000..fd3ecef --- /dev/null +++ b/protocol_3_17/base-protocol.go @@ -0,0 +1,130 @@ +package protocol + +import ( + "encoding/json" + "strconv" + + "github.com/tliron/glsp" +) + +var True bool = true +var False bool = false + +type Method = string + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#number + +/** + * Defines an integer number in the range of -2^31 to 2^31 - 1. + */ +type Integer = int32 + +/** + * Defines an unsigned integer number in the range of 0 to 2^31 - 1. + */ +type UInteger = uint32 + +/** + * Defines a decimal number. Since decimal numbers are very + * rare in the language server specification we denote the + * exact range with every decimal using the mathematics + * interval notation (e.g. [0, 1] denotes all decimals d with + * 0 <= d <= 1. + */ +type Decimal = float32 + +type IntegerOrString struct { + Value any // Integer | string +} + +// ([json.Marshaler] interface) +func (self *IntegerOrString) MarshalJSON() ([]byte, error) { + return json.Marshal(self.Value) +} + +// ([json.Unmarshaler] interface) +func (self *IntegerOrString) UnmarshalJSON(data []byte) error { + var value Integer + if err := json.Unmarshal(data, &value); err == nil { + self.Value = value + return nil + } else { + var value string + if err := json.Unmarshal(data, &value); err == nil { + self.Value = value + return nil + } else { + return err + } + } +} + +type BoolOrString struct { + Value any // bool | string +} + +// ([json.Marshaler] interface) +func (self BoolOrString) MarshalJSON() ([]byte, error) { + return json.Marshal(self.Value) +} + +// ([json.Unmarshaler] interface) +func (self *BoolOrString) UnmarshalJSON(data []byte) error { + var value bool + if err := json.Unmarshal(data, &value); err == nil { + self.Value = value + return nil + } else { + var value string + if err := json.Unmarshal(data, &value); err == nil { + self.Value = value + return nil + } else { + return err + } + } +} + +// ([fmt.Stringer] interface) +func (self BoolOrString) String() string { + if value, ok := self.Value.(bool); ok { + return strconv.FormatBool(value) + } + if value, ok := self.Value.(string); ok { + return value + } + return "" +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#cancelRequest + +const MethodCancelRequest = Method("$/cancelRequest") + +type CancelRequestFunc func(context *glsp.Context, params *CancelParams) error + +type CancelParams struct { + /** + * The request id to cancel. + */ + ID IntegerOrString `json:"id"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#progress + +const MethodProgress = Method("$/progress") + +type ProgressFunc func(context *glsp.Context, params *ProgressParams) error + +type ProgressParams struct { + /** + * The progress token provided by the client or server. + */ + Token ProgressToken `json:"token"` + + /** + * The progress data. + */ + Value any `json:"value"` +} + +type ProgressToken = IntegerOrString diff --git a/protocol_3_17/base-structures.go b/protocol_3_17/base-structures.go new file mode 100644 index 0000000..8cdf340 --- /dev/null +++ b/protocol_3_17/base-structures.go @@ -0,0 +1,943 @@ +package protocol + +import ( + "encoding/json" + "strings" + "unicode/utf8" + + protocol316 "github.com/tliron/glsp/protocol_3_16" +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#uri + +type DocumentUri = string + +type URI = string + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#regExp + +/** + * Client capabilities specific to regular expressions. + */ +type RegularExpressionsClientCapabilities struct { + /** + * The engine's name. + */ + Engine string `json:"engine"` + + /** + * The engine's version. + */ + Version *string `json:"version,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocuments + +var EOL = []string{"\n", "\r\n", "\r"} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#positionEncodingKind + +/** + * A set of predefined position encoding kinds. + * + * @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") +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position + +type Position struct { + /** + * Line position in a document (zero-based). + */ + Line UInteger `json:"line"` + + /** + * Character offset on a line in a document (zero-based). The meaning of this + * offset is determined by the negotiated `PositionEncodingKind`. + * + * If the character value is greater than the line length it defaults back + * to the line length. + */ + Character UInteger `json:"character"` +} + +func (self Position) IndexIn(content string) int { + // This code is modified from the gopls implementation found: + // https://cs.opensource.google/go/x/tools/+/refs/tags/v0.1.5:internal/span/utf16.go;l=70 + + // In accordance with the LSP Spec: + // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocuments + // self.Character represents utf-16 code units by default, not bytes and so we need to + // convert utf-16 code units to a byte offset. + + // Find the byte offset for the line + index := 0 + for row := UInteger(0); row < self.Line; row++ { + content_ := content[index:] + if next := strings.Index(content_, "\n"); next != -1 { + index += next + 1 + } else { + return 0 + } + } + + // The index represents the byte offset from the beginning of the line + // count self.Character utf-16 code units from the index byte offset. + + byteOffset := index + remains := content[index:] + chr := int(self.Character) + + for count := 1; count <= chr; count++ { + + if len(remains) <= 0 { + // char goes past content + // this a error + return 0 + } + + r, w := utf8.DecodeRuneInString(remains) + if r == '\n' { + // Per the LSP spec: + // + // > If the character value is greater than the line length it + // > defaults back to the line length. + break + } + + remains = remains[w:] + if r >= 0x10000 { + // a two point rune + count++ + // if we finished in a two point rune, do not advance past the first + if count > chr { + break + } + } + byteOffset += w + + } + + return byteOffset +} + +func (self Position) EndOfLineIn(content string) Position { + index := self.IndexIn(content) + content_ := content[index:] + if eol := strings.Index(content_, "\n"); eol != -1 { + return Position{ + Line: self.Line, + Character: self.Character + UInteger(eol), + } + } else { + return self + } +} + +// 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"` +} + +func (self Range) IndexesIn(content string) (int, int) { + return self.Start.IndexIn(content), self.End.IndexIn(content) +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location + +type Location struct { + URI DocumentUri `json:"uri"` + Range Range `json:"range"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#locationLink + +type LocationLink struct { + /** + * Span of the origin of this link. + * + * Used as the underlined span for mouse interaction. Defaults to the word + * range at the mouse position. + */ + OriginSelectionRange *Range `json:"originSelectionRange,omitempty"` + + /** + * The target resource identifier of this link. + */ + 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 the + * `targetRange`. See also `DocumentSymbol#range` + */ + TargetSelectionRange Range `json:"targetSelectionRange"` +} + +// 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. 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 *IntegerOrString `json:"code,omitempty"` + + /** + * 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 any `json:"data,omitempty"` +} + +type DiagnosticSeverity Integer + +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) +) + +/** + * The diagnostic tags. + * + * @since 3.15.0 + */ +type DiagnosticTag Integer + +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) +) + +/** + * Represents a related message and source code location for a diagnostic. + * This should be used to point to code locations that cause or are 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"` +} + +/** + * Structure to capture a description for an error code. + * + * @since 3.16.0 + */ +type CodeDescription struct { + /** + * An URI to open with more information about the diagnostic error. + */ + HRef URI `json:"href"` +} + +// 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 []any `json:"arguments,omitempty"` +} + +// 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"` +} + +/** + * Additional information that describes document changes. + * + * @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"` +} + +/** + * An identifier referring to a change annotation managed by a workspace + * edit. + * + * @since 3.16.0 + */ +type ChangeAnnotationIdentifier = string + +/** + * A special text edit with an additional change annotation. + * + * @since 3.16.0 + */ +type AnnotatedTextEdit struct { + TextEdit + + /** + * The actual annotation identifier. + */ + AnnotationID ChangeAnnotationIdentifier `json:"annotationId"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentEdit + +type TextDocumentEdit struct { + /** + * The text document to change. + */ + TextDocument OptionalVersionedTextDocumentIdentifier `json:"textDocument"` + + /** + * The edits to be applied. + * + * @since 3.16.0 - support for AnnotatedTextEdit. This is guarded by the + * client capability `workspace.workspaceEdit.changeAnnotationSupport` + */ + Edits []any `json:"edits"` // TextEdit | AnnotatedTextEdit +} + +// ([json.Unmarshaler] interface) +func (self *TextDocumentEdit) UnmarshalJSON(data []byte) error { + var value struct { + TextDocument OptionalVersionedTextDocumentIdentifier `json:"textDocument"` + Edits []json.RawMessage `json:"edits"` // TextEdit | AnnotatedTextEdit + } + + if err := json.Unmarshal(data, &value); err == nil { + self.TextDocument = value.TextDocument + + for _, edit := range value.Edits { + var raw map[string]json.RawMessage + if err = json.Unmarshal(edit, &raw); err != nil { + return err + } + if _, hasAnnotation := raw["annotationId"]; hasAnnotation { + var value AnnotatedTextEdit + if err = json.Unmarshal(edit, &value); err != nil { + return err + } + self.Edits = append(self.Edits, value) + } else { + var value TextEdit + if err = json.Unmarshal(edit, &value); err != nil { + return err + } + self.Edits = append(self.Edits, value) + } + } + + return nil + } else { + return err + } +} + +// Re-use file operations from 3.16 as they are unchanged +type CreateFileOptions = protocol316.CreateFileOptions +type CreateFile = protocol316.CreateFile +type RenameFileOptions = protocol316.RenameFileOptions +type RenameFile = protocol316.RenameFile +type DeleteFileOptions = protocol316.DeleteFileOptions +type DeleteFile = protocol316.DeleteFile + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspaceEdit + +type WorkspaceEdit struct { + /** + * Holds changes to existing resources. + */ + Changes map[DocumentUri][]TextEdit `json:"changes,omitempty"` + + /** + * Depending on the client capability + * `workspace.workspaceEdit.resourceOperations` document changes are either + * 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. Or it can contain above `TextDocumentEdit`s mixed with + * create, rename and delete file / folder operations. + * + * Whether a client supports versioned document edits is expressed via + * `workspace.workspaceEdit.documentChanges` client capability. + * + * If a client neither supports `documentChanges` nor + * `workspace.workspaceEdit.resourceOperations` then only plain `TextEdit`s + * using the `changes` property are supported. + */ + DocumentChanges []any `json:"documentChanges,omitempty"` // TextDocumentEdit | CreateFile | RenameFile | DeleteFile + + /** + * A map of change annotations that can be referenced in + * `AnnotatedTextEdit`s or create, rename and delete file / folder + * operations. + * + * Whether clients honor this property depends on the client capability + * `workspace.changeAnnotationSupport`. + * + * @since 3.16.0 + */ + ChangeAnnotations map[ChangeAnnotationIdentifier]ChangeAnnotation `json:"changeAnnotations,omitempty"` +} + +// ([json.Unmarshaler] interface) +func (self *WorkspaceEdit) UnmarshalJSON(data []byte) error { + var value struct { + Changes map[DocumentUri][]TextEdit `json:"changes"` + DocumentChanges []json.RawMessage `json:"documentChanges"` // TextDocumentEdit | CreateFile | RenameFile | DeleteFile + ChangeAnnotations map[ChangeAnnotationIdentifier]ChangeAnnotation `json:"changeAnnotations"` + } + + if err := json.Unmarshal(data, &value); err == nil { + self.Changes = value.Changes + self.ChangeAnnotations = value.ChangeAnnotations + + for _, documentChange := range value.DocumentChanges { + var kindCheck struct { + Kind string `json:"kind"` + } + _ = json.Unmarshal(documentChange, &kindCheck) + + switch kindCheck.Kind { + case "create": + var value CreateFile + if err = json.Unmarshal(documentChange, &value); err != nil { + return err + } + self.DocumentChanges = append(self.DocumentChanges, value) + case "rename": + var value RenameFile + if err = json.Unmarshal(documentChange, &value); err != nil { + return err + } + self.DocumentChanges = append(self.DocumentChanges, value) + case "delete": + var value DeleteFile + if err = json.Unmarshal(documentChange, &value); err != nil { + return err + } + self.DocumentChanges = append(self.DocumentChanges, value) + default: + var value TextDocumentEdit + if err = json.Unmarshal(documentChange, &value); err != nil { + return err + } + self.DocumentChanges = append(self.DocumentChanges, value) + } + } + + return nil + } else { + return err + } +} + +// Re-use capabilities from 3.16 where applicable +type WorkspaceEditClientCapabilities = protocol316.WorkspaceEditClientCapabilities +type ResourceOperationKind = protocol316.ResourceOperationKind +type FailureHandlingKind = protocol316.FailureHandlingKind + +const ( + ResourceOperationKindCreate = protocol316.ResourceOperationKindCreate + ResourceOperationKindRename = protocol316.ResourceOperationKindRename + ResourceOperationKindDelete = protocol316.ResourceOperationKindDelete +) + +const ( + FailureHandlingKindAbort = protocol316.FailureHandlingKindAbort + FailureHandlingKindTransactional = protocol316.FailureHandlingKindTransactional + FailureHandlingKindTextOnlyTransactional = protocol316.FailureHandlingKindTextOnlyTransactional + FailureHandlingKindUndo = protocol316.FailureHandlingKindUndo +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentIdentifier + +type TextDocumentIdentifier struct { + /** + * The text document's URI. + */ + URI DocumentUri `json:"uri"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentItem + +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 Integer `json:"version"` + + /** + * The content of the opened text document. + */ + Text string `json:"text"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#versionedTextDocumentIdentifier + +type VersionedTextDocumentIdentifier struct { + TextDocumentIdentifier + + /** + * The version number of this document. + * + * The version number of a document will increase after each change, + * including undo/redo. The number doesn't need to be consecutive. + */ + Version Integer `json:"version"` +} + +type OptionalVersionedTextDocumentIdentifier struct { + TextDocumentIdentifier + + /** + * The version number of this document. If an optional 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 master (as specified with document + * content ownership). + * + * The version number of a document will increase after each change, + * including undo/redo. The number doesn't need to be consecutive. + */ + Version *Integer `json:"version"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams + +type TextDocumentPositionParams struct { + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The position inside the text document. + */ + Position Position `json:"position"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentFilter + +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}`. + * + * Glob patterns can have the following syntax: + * - `*` to match one or more characters in a path segment + * - `?` to match on one character in a path segment + * - `**` to match any number of path segments, including none + * - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript + * and JavaScript files) + * - `[]` to declare a range of characters to match in a path segment + * (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + * - `[!...]` to negate a range of characters to match in a path segment + * (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but + * not `example.0`) + */ + Pattern *string `json:"pattern,omitempty"` +} + +type DocumentSelector []DocumentFilter + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#staticRegistrationOptions + +/** + * 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"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentRegistrationOptions + +/** + * General text document registration options. + */ +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"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#markupContent + +/** + * 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 + */ + MarkupKindPlainText = MarkupKind("plaintext") + + /** + * Markdown is supported as a content format + */ + MarkupKindMarkdown = 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. + * + * Here is an example how such a string can be constructed using + * JavaScript / TypeScript: + * ```typescript + * 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"` +} + +/** + * Client capabilities specific to the used markdown parser. + * + * @since 3.16.0 + */ +type MarkdownClientCapabilities struct { + /** + * The name of the parser. + */ + Parser string `json:"parser"` + + /** + * The version of the parser. + */ + Version *string `json:"version,omitempty"` + + /** + * A list of HTML tags that the client allows / supports in + * Markdown. + * + * @since 3.17.0 + */ + AllowedTags []string `json:"allowedTags,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workDoneProgress + +type WorkDoneProgressBegin struct { + Kind string `json:"kind"` // == "begin" + + /** + * Mandatory title of the progress operation. Used to briefly inform about + * the kind of operation being performed. + * + * Examples: "Indexing" or "Linking dependencies". + */ + Title string `json:"title"` + + /** + * Controls if a cancel button should show to allow the user to cancel the + * long running operation. Clients that don't support cancellation are + * allowed to ignore the setting. + */ + Cancellable *bool `json:"cancellable,omitempty"` + + /** + * Optional, more detailed associated progress message. Contains + * complementary information to the `title`. + * + * Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + * If unset, the previous progress message (if any) is still valid. + */ + Message *string `json:"message,omitempty"` + + /** + * Optional progress percentage to display (value 100 is considered 100%). + * If not provided infinite progress is assumed and clients are allowed + * to ignore the `percentage` value in subsequent in report notifications. + * + * The value should be steadily rising. Clients are free to ignore values + * that are not following this rule. The value range is [0, 100] + */ + Percentage *UInteger `json:"percentage,omitempty"` +} + +type WorkDoneProgressReport struct { + Kind string `json:"kind"` // == "report" + + /** + * Controls enablement state of a cancel button. This property is only valid + * if a cancel button got requested in the `WorkDoneProgressStart` payload. + * + * Clients that don't support cancellation or don't support control the + * button's enablement state are allowed to ignore the setting. + */ + Cancellable *bool `json:"cancellable,omitempty"` + + /** + * Optional, more detailed associated progress message. Contains + * complementary information to the `title`. + * + * Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + * If unset, the previous progress message (if any) is still valid. + */ + Message *string `json:"message,omitempty"` + + /** + * Optional progress percentage to display (value 100 is considered 100%). + * If not provided infinite progress is assumed and clients are allowed + * to ignore the `percentage` value in subsequent in report notifications. + * + * The value should be steadily rising. Clients are free to ignore values + * that are not following this rule. The value range is [0, 100] + */ + Percentage *UInteger `json:"percentage,omitempty"` +} + +type WorkDoneProgressEnd struct { + Kind string `json:"kind"` // == "end" + + /** + * Optional, a final message indicating to for example indicate the outcome + * of the operation. + */ + Message *string `json:"message,omitempty"` +} + +type WorkDoneProgressParams struct { + /** + * An optional token that a server can use to report work done progress. + */ + WorkDoneToken *ProgressToken `json:"workDoneToken,omitempty"` +} + +type WorkDoneProgressOptions struct { + WorkDoneProgress *bool `json:"workDoneProgress,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#partialResults + +type PartialResultParams struct { + /** + * An optional token that a server can use to report partial results (e.g. + * streaming) to the client. + */ + PartialResultToken *ProgressToken `json:"partialResultToken,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#traceValue + +type TraceValue string + +const ( + TraceValueOff = TraceValue("off") + TraceValueMessage = TraceValue("message") // The spec clearly says "message", but some implementations use "messages" instead + TraceValueVerbose = TraceValue("verbose") +) diff --git a/protocol_3_17/client.go b/protocol_3_17/client.go new file mode 100644 index 0000000..2793dc8 --- /dev/null +++ b/protocol_3_17/client.go @@ -0,0 +1,57 @@ +package protocol + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#client_registerCapability + +/** + * 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 any `json:"registerOptions,omitempty"` +} + +const ServerClientRegisterCapability = Method("client/registerCapability") + +type RegistrationParams struct { + Registrations []Registration `json:"registrations"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#client_unregisterCapability + +/** + * 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"` +} + +const ServerClientUnregisterCapability = Method("client/unregisterCapability") + +type UnregistrationParams struct { + // This should correctly be named `unregistrations`. However changing this + // is a breaking change and needs to wait until we deliver a 4.x version + // of the specification. + Unregisterations []Unregistration `json:"unregisterations"` +} diff --git a/protocol_3_17/custom.go b/protocol_3_17/custom.go new file mode 100644 index 0000000..419fa97 --- /dev/null +++ b/protocol_3_17/custom.go @@ -0,0 +1,17 @@ +package protocol + +import ( + "encoding/json" + + "github.com/tliron/glsp" +) + +type CustomRequestHandler struct { + Func CustomRequestFunc + // This field should be private however it is used in both versions of the protocol + Params json.RawMessage +} + +type CustomRequestHandlers map[string]CustomRequestHandler + +type CustomRequestFunc func(context *glsp.Context, params json.RawMessage) (any, error) diff --git a/protocol_3_17/diagnostics.go b/protocol_3_17/diagnostics.go index 24c0069..bd6495c 100644 --- a/protocol_3_17/diagnostics.go +++ b/protocol_3_17/diagnostics.go @@ -186,7 +186,7 @@ type RelatedFullDocumentDiagnosticReport struct { * * @since 3.17.0 */ - RelatedDocuments map[protocol316.DocumentUri]interface{} `json:"relatedDocuments,omitempty"` + RelatedDocuments map[protocol316.DocumentUri]any `json:"relatedDocuments,omitempty"` } /** @@ -205,7 +205,7 @@ type RelatedUnchangedDocumentDiagnosticReport struct { * * @since 3.17.0 */ - RelatedDocuments map[protocol316.DocumentUri]interface{} `json:"relatedDocuments,omitempty"` + RelatedDocuments map[protocol316.DocumentUri]any `json:"relatedDocuments,omitempty"` } /** @@ -214,7 +214,7 @@ type RelatedUnchangedDocumentDiagnosticReport struct { * @since 3.17.0 */ type DocumentDiagnosticReportPartialResult struct { - RelatedDocuments map[protocol316.DocumentUri]interface{} `json:"relatedDocuments"` + RelatedDocuments map[protocol316.DocumentUri]any `json:"relatedDocuments"` } /** @@ -225,3 +225,134 @@ type DocumentDiagnosticReportPartialResult struct { type DiagnosticServerCancellationData struct { RetriggerRequest bool `json:"retriggerRequest"` } + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_diagnostic + +/** + * Workspace client capabilities specific to diagnostic pull requests. + * + * @since 3.17.0 + */ +type DiagnosticWorkspaceClientCapabilities struct { + /** + * Whether the client implementation supports a refresh request sent from + * the server to the client. + * + * Note that this event is global and will force the client to re-calculate + * all pulled diagnostics for all open documents. It should be used with + * absolute care and is useful for situation where a server for example + * detects a project wide change that requires such a calculation. + */ + RefreshSupport *bool `json:"refreshSupport,omitempty"` +} + +const MethodWorkspaceDiagnostic = protocol316.Method("workspace/diagnostic") + +type WorkspaceDiagnosticFunc func(context *glsp.Context, params *WorkspaceDiagnosticParams) (*WorkspaceDiagnosticReport, error) + +/** + * Parameters of the workspace diagnostic request. + * + * @since 3.17.0 + */ +type WorkspaceDiagnosticParams struct { + protocol316.WorkDoneProgressParams + protocol316.PartialResultParams + + /** + * The additional identifier provided during registration. + */ + Identifier *string `json:"identifier,omitempty"` + + /** + * The currently known diagnostic reports with their + * previous result ids. + */ + PreviousResultIds []PreviousResultId `json:"previousResultIds"` +} + +/** + * A previous result id in a workspace pull request. + * + * @since 3.17.0 + */ +type PreviousResultId struct { + /** + * The URI for which the client knows a result id. + */ + URI protocol316.DocumentUri `json:"uri"` + + /** + * The value of the previous result id. + */ + Value string `json:"value"` +} + +/** + * A workspace diagnostic report. + * + * @since 3.17.0 + */ +type WorkspaceDiagnosticReport struct { + Items []WorkspaceDocumentDiagnosticReport `json:"items"` +} + +/** + * A workspace diagnostic document report. + * + * @since 3.17.0 + */ +type WorkspaceDocumentDiagnosticReport any // WorkspaceFullDocumentDiagnosticReport | WorkspaceUnchangedDocumentDiagnosticReport + +/** + * A full document diagnostic report for a workspace diagnostic result. + * + * @since 3.17.0 + */ +type WorkspaceFullDocumentDiagnosticReport struct { + FullDocumentDiagnosticReport + + /** + * The URI for which diagnostic information is reported. + */ + URI protocol316.DocumentUri `json:"uri"` + + /** + * The version number for which the diagnostics are reported. + * If the document is not marked as open `null` can be provided. + */ + Version *protocol316.Integer `json:"version"` +} + +/** + * An unchanged document diagnostic report for a workspace diagnostic result. + * + * @since 3.17.0 + */ +type WorkspaceUnchangedDocumentDiagnosticReport struct { + UnchangedDocumentDiagnosticReport + + /** + * The URI for which diagnostic information is reported. + */ + URI protocol316.DocumentUri `json:"uri"` + + /** + * The version number for which the diagnostics are reported. + * If the document is not marked as open `null` can be provided. + */ + Version *protocol316.Integer `json:"version"` +} + +/** + * A partial result for a workspace diagnostic report. + * + * @since 3.17.0 + */ +type WorkspaceDiagnosticReportPartialResult struct { + Items []WorkspaceDocumentDiagnosticReport `json:"items"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh + +const MethodWorkspaceDiagnosticRefresh = protocol316.Method("workspace/diagnostics/refresh") diff --git a/protocol_3_17/general-messages.go b/protocol_3_17/general-messages.go index 8cd5970..83ae415 100644 --- a/protocol_3_17/general-messages.go +++ b/protocol_3_17/general-messages.go @@ -7,7 +7,7 @@ import ( protocol316 "github.com/tliron/glsp/protocol_3_16" ) -// https://microsoft.github.io/language-server-protocol/specifications/specification-3-16#initialize +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize const MethodInitialize = protocol316.Method("initialize") @@ -26,7 +26,74 @@ type InitializeParams struct { type ClientCapabilities struct { protocol316.ClientCapabilities + /** + * Text document specific client capabilities. + */ TextDocument *TextDocumentClientCapabilities `json:"textDocument,omitempty"` + + /** + * Capabilities specific to the notebook document support. + * + * @since 3.17.0 + */ + NotebookDocument *NotebookDocumentClientCapabilities `json:"notebookDocument,omitempty"` + + /** + * General client capabilities. + * + * @since 3.16.0 + */ + General *GeneralClientCapabilities `json:"general,omitempty"` +} + +/** + * General client capabilities. + * + * @since 3.16.0 + */ +type GeneralClientCapabilities struct { + /** + * Client capability that signals how the client + * handles stale requests (e.g. a request + * for which the client will not process the response + * anymore since the information is outdated). + * + * @since 3.17.0 + */ + StaleRequestSupport *struct { + /** + * The client will actively cancel the request. + */ + Cancel bool `json:"cancel"` + + /** + * The list of requests for which the client + * will retry the request if it receives a + * response with error code `ContentModified` + */ + RetryOnContentModified []string `json:"retryOnContentModified"` + } `json:"staleRequestSupport,omitempty"` + + /** + * Client capabilities specific to regular expressions. + * + * @since 3.16.0 + */ + RegularExpressions *RegularExpressionsClientCapabilities `json:"regularExpressions,omitempty"` + + /** + * Client capabilities specific to the client's markdown parser. + * + * @since 3.16.0 + */ + Markdown *MarkdownClientCapabilities `json:"markdown,omitempty"` + + /** + * Client capabilities specific to the client's position encoding. + * + * @since 3.17.0 + */ + PositionEncodings []PositionEncodingKind `json:"positionEncodings,omitempty"` } /** @@ -41,6 +108,27 @@ type TextDocumentClientCapabilities struct { * @since 3.17.0 */ Diagnostic *DiagnosticClientCapabilities `json:"diagnostic,omitempty"` + + /** + * Capabilities specific to the type hierarchy feature. + * + * @since 3.17.0 + */ + TypeHierarchy *TypeHierarchyClientCapabilities `json:"typeHierarchy,omitempty"` + + /** + * Capabilities specific to the inline values feature. + * + * @since 3.17.0 + */ + InlineValue *InlineValueClientCapabilities `json:"inlineValue,omitempty"` + + /** + * Capabilities specific to the inlay hint feature. + * + * @since 3.17.0 + */ + InlayHint *InlayHintClientCapabilities `json:"inlayHint,omitempty"` } type ServerCapabilities struct { @@ -52,6 +140,34 @@ type ServerCapabilities struct { * @since 3.17.0 */ DiagnosticProvider any `json:"diagnosticProvider,omitempty"` // nil | DiagnosticOptions | DiagnosticRegistrationOptions + + /** + * The server provides type hierarchy support. + * + * @since 3.17.0 + */ + TypeHierarchyProvider any `json:"typeHierarchyProvider,omitempty"` // nil | bool | TypeHierarchyOptions | TypeHierarchyRegistrationOptions + + /** + * The server provides inline values. + * + * @since 3.17.0 + */ + InlineValueProvider any `json:"inlineValueProvider,omitempty"` // nil | bool | InlineValueOptions | InlineValueRegistrationOptions + + /** + * The server provides inlay hints. + * + * @since 3.17.0 + */ + InlayHintProvider any `json:"inlayHintProvider,omitempty"` // nil | bool | InlayHintOptions | InlayHintRegistrationOptions + + /** + * Whether the server supports notebook document synchronization + * + * @since 3.17.0 + */ + NotebookDocumentSync any `json:"notebookDocumentSync,omitempty"` // nil | NotebookDocumentSyncOptions | NotebookDocumentSyncRegistrationOptions } func (self *ServerCapabilities) UnmarshalJSON(data []byte) error { @@ -85,7 +201,11 @@ func (self *ServerCapabilities) UnmarshalJSON(data []byte) error { WorkspaceSymbolProvider json.RawMessage `json:"workspaceSymbolProvider,omitempty"` // nil | bool | WorkspaceSymbolOptions Workspace *protocol316.ServerCapabilitiesWorkspace `json:"workspace,omitempty"` Experimental *any `json:"experimental,omitempty"` - DiagnosticProvider json.RawMessage `json:"diagnosticProvider,omitempty"` // nil | DiagnosticOptions | DiagnosticRegistrationOptions + DiagnosticProvider json.RawMessage `json:"diagnosticProvider,omitempty"` // nil | DiagnosticOptions | DiagnosticRegistrationOptions + TypeHierarchyProvider json.RawMessage `json:"typeHierarchyProvider,omitempty"` // nil | bool | TypeHierarchyOptions | TypeHierarchyRegistrationOptions + InlineValueProvider json.RawMessage `json:"inlineValueProvider,omitempty"` // nil | bool | InlineValueOptions | InlineValueRegistrationOptions + InlayHintProvider json.RawMessage `json:"inlayHintProvider,omitempty"` // nil | bool | InlayHintOptions | InlayHintRegistrationOptions + NotebookDocumentSync json.RawMessage `json:"notebookDocumentSync,omitempty"` // nil | NotebookDocumentSyncOptions | NotebookDocumentSyncRegistrationOptions } if err := json.Unmarshal(data, &value); err == nil { @@ -450,6 +570,77 @@ func (self *ServerCapabilities) UnmarshalJSON(data []byte) error { } } + if value.TypeHierarchyProvider != nil { + var value_ bool + if err = json.Unmarshal(value.TypeHierarchyProvider, &value_); err == nil { + self.TypeHierarchyProvider = value_ + } else { + var value_ TypeHierarchyOptions + if err = json.Unmarshal(value.TypeHierarchyProvider, &value_); err == nil { + self.TypeHierarchyProvider = value_ + } else { + var value_ TypeHierarchyRegistrationOptions + if err = json.Unmarshal(value.TypeHierarchyProvider, &value_); err == nil { + self.TypeHierarchyProvider = value_ + } else { + return err + } + } + } + } + + if value.InlineValueProvider != nil { + var value_ bool + if err = json.Unmarshal(value.InlineValueProvider, &value_); err == nil { + self.InlineValueProvider = value_ + } else { + var value_ InlineValueOptions + if err = json.Unmarshal(value.InlineValueProvider, &value_); err == nil { + self.InlineValueProvider = value_ + } else { + var value_ InlineValueRegistrationOptions + if err = json.Unmarshal(value.InlineValueProvider, &value_); err == nil { + self.InlineValueProvider = value_ + } else { + return err + } + } + } + } + + if value.InlayHintProvider != nil { + var value_ bool + if err = json.Unmarshal(value.InlayHintProvider, &value_); err == nil { + self.InlayHintProvider = value_ + } else { + var value_ InlayHintOptions + if err = json.Unmarshal(value.InlayHintProvider, &value_); err == nil { + self.InlayHintProvider = value_ + } else { + var value_ InlayHintRegistrationOptions + if err = json.Unmarshal(value.InlayHintProvider, &value_); err == nil { + self.InlayHintProvider = value_ + } else { + return err + } + } + } + } + + if value.NotebookDocumentSync != nil { + var value_ NotebookDocumentSyncOptions + if err = json.Unmarshal(value.NotebookDocumentSync, &value_); err == nil { + self.NotebookDocumentSync = value_ + } else { + var value_ NotebookDocumentSyncRegistrationOptions + if err = json.Unmarshal(value.NotebookDocumentSync, &value_); err == nil { + self.NotebookDocumentSync = value_ + } else { + return err + } + } + } + return nil } else { return err diff --git a/protocol_3_17/handler.go b/protocol_3_17/handler.go index ce072e4..175bb80 100644 --- a/protocol_3_17/handler.go +++ b/protocol_3_17/handler.go @@ -14,6 +14,25 @@ type Handler struct { Initialize InitializeFunc TextDocumentDiagnostic TextDocumentDiagnosticFunc + WorkspaceDiagnostic WorkspaceDiagnosticFunc + + // Type Hierarchy - @since 3.17.0 + TextDocumentPrepareTypeHierarchy TextDocumentPrepareTypeHierarchyFunc + TypeHierarchySupertypes TypeHierarchySupertypesFunc + TypeHierarchySubtypes TypeHierarchySubtypesFunc + + // Inline Value - @since 3.17.0 + TextDocumentInlineValue TextDocumentInlineValueFunc + + // Inlay Hint - @since 3.17.0 + TextDocumentInlayHint TextDocumentInlayHintFunc + InlayHintResolve InlayHintResolveFunc + + // Notebook Document - @since 3.17.0 + NotebookDocumentDidOpen NotebookDocumentDidOpenFunc + NotebookDocumentDidChange NotebookDocumentDidChangeFunc + NotebookDocumentDidSave NotebookDocumentDidSaveFunc + NotebookDocumentDidClose NotebookDocumentDidCloseFunc initialized bool lock sync.Mutex @@ -649,6 +668,120 @@ func (self *Handler) Handle(context *glsp.Context) (r any, validMethod bool, val } } + case MethodWorkspaceDiagnostic: + if self.WorkspaceDiagnostic != nil { + validMethod = true + var params WorkspaceDiagnosticParams + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + r, err = self.WorkspaceDiagnostic(context, ¶ms) + } + } + + // Type Hierarchy - @since 3.17.0 + case MethodTextDocumentPrepareTypeHierarchy: + if self.TextDocumentPrepareTypeHierarchy != nil { + validMethod = true + var params TypeHierarchyPrepareParams + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + r, err = self.TextDocumentPrepareTypeHierarchy(context, ¶ms) + } + } + + case MethodTypeHierarchySupertypes: + if self.TypeHierarchySupertypes != nil { + validMethod = true + var params TypeHierarchySupertypesParams + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + r, err = self.TypeHierarchySupertypes(context, ¶ms) + } + } + + case MethodTypeHierarchySubtypes: + if self.TypeHierarchySubtypes != nil { + validMethod = true + var params TypeHierarchySubtypesParams + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + r, err = self.TypeHierarchySubtypes(context, ¶ms) + } + } + + // Inline Value - @since 3.17.0 + case MethodTextDocumentInlineValue: + if self.TextDocumentInlineValue != nil { + validMethod = true + var params InlineValueParams + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + r, err = self.TextDocumentInlineValue(context, ¶ms) + } + } + + // Inlay Hint - @since 3.17.0 + case MethodTextDocumentInlayHint: + if self.TextDocumentInlayHint != nil { + validMethod = true + var params InlayHintParams + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + r, err = self.TextDocumentInlayHint(context, ¶ms) + } + } + + case MethodInlayHintResolve: + if self.InlayHintResolve != nil { + validMethod = true + var params InlayHint + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + r, err = self.InlayHintResolve(context, ¶ms) + } + } + + // Notebook Document - @since 3.17.0 + case MethodNotebookDocumentDidOpen: + if self.NotebookDocumentDidOpen != nil { + validMethod = true + var params DidOpenNotebookDocumentParams + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + err = self.NotebookDocumentDidOpen(context, ¶ms) + } + } + + case MethodNotebookDocumentDidChange: + if self.NotebookDocumentDidChange != nil { + validMethod = true + var params DidChangeNotebookDocumentParams + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + err = self.NotebookDocumentDidChange(context, ¶ms) + } + } + + case MethodNotebookDocumentDidSave: + if self.NotebookDocumentDidSave != nil { + validMethod = true + var params DidSaveNotebookDocumentParams + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + err = self.NotebookDocumentDidSave(context, ¶ms) + } + } + + case MethodNotebookDocumentDidClose: + if self.NotebookDocumentDidClose != nil { + validMethod = true + var params DidCloseNotebookDocumentParams + if err = json.Unmarshal(context.Params, ¶ms); err == nil { + validParams = true + err = self.NotebookDocumentDidClose(context, ¶ms) + } + } + default: if self.CustomRequest != nil { if handler, ok := self.CustomRequest[context.Method]; ok && (handler.Func != nil) { @@ -828,8 +961,6 @@ func (self *Handler) CreateServerCapabilities() ServerCapabilities { capabilities.SemanticTokensProvider.(*protocol316.SemanticTokensOptions).Range = true } - // TODO: self.TextDocumentSemanticTokensRefresh? - if self.TextDocumentMoniker != nil { capabilities.MonikerProvider = true } @@ -915,9 +1046,41 @@ func (self *Handler) CreateServerCapabilities() ServerCapabilities { if self.TextDocumentDiagnostic != nil { capabilities.DiagnosticProvider = DiagnosticOptions{ InterFileDependencies: true, - WorkspaceDiagnostics: false, + WorkspaceDiagnostics: self.WorkspaceDiagnostic != nil, + } + } + + // Type Hierarchy - @since 3.17.0 + if self.TextDocumentPrepareTypeHierarchy != nil { + capabilities.TypeHierarchyProvider = true + } + + // Inline Value - @since 3.17.0 + if self.TextDocumentInlineValue != nil { + capabilities.InlineValueProvider = true + } + + // Inlay Hint - @since 3.17.0 + if self.TextDocumentInlayHint != nil { + capabilities.InlayHintProvider = &InlayHintOptions{} + } + + // Notebook Document - @since 3.17.0 + if self.NotebookDocumentDidOpen != nil || self.NotebookDocumentDidChange != nil || + self.NotebookDocumentDidSave != nil || self.NotebookDocumentDidClose != nil { + // Basic notebook sync support - can be customized as needed + capabilities.NotebookDocumentSync = &NotebookDocumentSyncOptions{ + NotebookSelector: []NotebookSelector{ + { + Notebook: "*", // Match all notebook types by default + }, + }, } } + if self.TextDocumentInlayHint != nil { + capabilities.InlayHintProvider = true + } + return capabilities } diff --git a/protocol_3_17/json_test.go b/protocol_3_17/json_test.go new file mode 100644 index 0000000..5b86ce9 --- /dev/null +++ b/protocol_3_17/json_test.go @@ -0,0 +1,474 @@ +package protocol + +import ( + "encoding/json" + "testing" + + protocol316 "github.com/tliron/glsp/protocol_3_16" +) + +func TestPositionEncodingJSONSerialization(t *testing.T) { + // Test position encoding kinds + tests := []struct { + name string + encoding PositionEncodingKind + expected string + }{ + {"UTF-8", PositionEncodingKindUTF8, `"utf-8"`}, + {"UTF-16", PositionEncodingKindUTF16, `"utf-16"`}, + {"UTF-32", PositionEncodingKindUTF32, `"utf-32"`}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Test marshaling + data, err := json.Marshal(tt.encoding) + if err != nil { + t.Fatalf("Failed to marshal %s: %v", tt.name, err) + } + if string(data) != tt.expected { + t.Errorf("Expected %s, got %s", tt.expected, string(data)) + } + + // Test unmarshaling + var decoded PositionEncodingKind + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("Failed to unmarshal %s: %v", tt.name, err) + } + if decoded != tt.encoding { + t.Errorf("Expected %s, got %s", tt.encoding, decoded) + } + }) + } +} + +func TestTypeHierarchyItemJSONSerialization(t *testing.T) { + original := TypeHierarchyItem{ + Name: "TestClass", + Kind: 1, + URI: "file:///test.go", + Range: Range{Start: Position{Line: 0, Character: 0}, End: Position{Line: 10, Character: 0}}, + SelectionRange: Range{Start: Position{Line: 0, Character: 0}, End: Position{Line: 0, Character: 9}}, + Detail: stringPtr("A test class"), + Data: map[string]any{"test": "data"}, + } + + // Test round-trip serialization + data, err := json.Marshal(original) + if err != nil { + t.Fatalf("Failed to marshal TypeHierarchyItem: %v", err) + } + + var decoded TypeHierarchyItem + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("Failed to unmarshal TypeHierarchyItem: %v", err) + } + + // Verify fields + if decoded.Name != original.Name { + t.Errorf("Name mismatch: expected %s, got %s", original.Name, decoded.Name) + } + if decoded.Kind != original.Kind { + t.Errorf("Kind mismatch: expected %d, got %d", original.Kind, decoded.Kind) + } + if decoded.URI != original.URI { + t.Errorf("URI mismatch: expected %s, got %s", original.URI, decoded.URI) + } + if decoded.Detail == nil { + t.Fatal("Detail should not be nil after unmarshaling") + } + if *decoded.Detail != *original.Detail { + t.Errorf("Detail mismatch: expected %s, got %s", *original.Detail, *decoded.Detail) + } +} + +func TestInlayHintJSONSerialization(t *testing.T) { + // Test with string label + hintWithStringLabel := InlayHint{ + Position: Position{Line: 5, Character: 10}, + Label: "i32", + Kind: &[]InlayHintKind{InlayHintKindType}[0], + Tooltip: "Type annotation", + } + + data, err := json.Marshal(hintWithStringLabel) + if err != nil { + t.Fatalf("Failed to marshal InlayHint with string label: %v", err) + } + + var decoded InlayHint + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("Failed to unmarshal InlayHint with string label: %v", err) + } + + if decoded.Position.Line != hintWithStringLabel.Position.Line { + t.Errorf("Position.Line mismatch: expected %d, got %d", hintWithStringLabel.Position.Line, decoded.Position.Line) + } + + // Test with label parts + hintWithLabelParts := InlayHint{ + Position: Position{Line: 3, Character: 15}, + Label: []InlayHintLabelPart{ + {Value: "name", Tooltip: "Parameter name"}, + {Value: ": ", Tooltip: nil}, + {Value: "string", Tooltip: "Parameter type"}, + }, + Kind: &[]InlayHintKind{InlayHintKindParameter}[0], + } + + data, err = json.Marshal(hintWithLabelParts) + if err != nil { + t.Fatalf("Failed to marshal InlayHint with label parts: %v", err) + } + + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("Failed to unmarshal InlayHint with label parts: %v", err) + } +} + +func TestInlineValueJSONSerialization(t *testing.T) { + // Test InlineValueText + inlineText := InlineValueText{ + Range: Range{Start: Position{Line: 5, Character: 0}, End: Position{Line: 5, Character: 10}}, + Text: "42", + } + + data, err := json.Marshal(inlineText) + if err != nil { + t.Fatalf("Failed to marshal InlineValueText: %v", err) + } + + var decoded InlineValueText + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("Failed to unmarshal InlineValueText: %v", err) + } + + if decoded.Text != inlineText.Text { + t.Errorf("Text mismatch: expected %s, got %s", inlineText.Text, decoded.Text) + } + + // Test InlineValueVariableLookup + variableLookup := InlineValueVariableLookup{ + Range: Range{Start: Position{Line: 10, Character: 5}, End: Position{Line: 10, Character: 15}}, + VariableName: stringPtr("myVar"), + CaseSensitiveLookup: true, + } + + data, err = json.Marshal(variableLookup) + if err != nil { + t.Fatalf("Failed to marshal InlineValueVariableLookup: %v", err) + } + + var decodedLookup InlineValueVariableLookup + err = json.Unmarshal(data, &decodedLookup) + if err != nil { + t.Fatalf("Failed to unmarshal InlineValueVariableLookup: %v", err) + } + + if decodedLookup.VariableName == nil { + t.Fatal("VariableName should not be nil after unmarshaling") + } + if *decodedLookup.VariableName != *variableLookup.VariableName { + t.Errorf("VariableName mismatch: expected %s, got %s", *variableLookup.VariableName, *decodedLookup.VariableName) + } +} + +func TestNotebookDocumentJSONSerialization(t *testing.T) { + notebook := NotebookDocument{ + URI: "file:///notebook.ipynb", + NotebookType: "jupyter-notebook", + Version: 1, + Cells: []NotebookCell{ + { + Kind: 1, // NotebookCellKindMarkdown + Document: "file:///cell1.md", + Metadata: func() *any { m := any(map[string]any{"tags": []string{"markdown"}}); return &m }(), + }, + { + Kind: 2, // NotebookCellKindCode + Document: "file:///cell2.py", + ExecutionSummary: &ExecutionSummary{ + ExecutionOrder: 1, + Success: boolPtr(true), + }, + }, + }, + } + + data, err := json.Marshal(notebook) + if err != nil { + t.Fatalf("Failed to marshal NotebookDocument: %v", err) + } + + var decoded NotebookDocument + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("Failed to unmarshal NotebookDocument: %v", err) + } + + if decoded.NotebookType != notebook.NotebookType { + t.Errorf("NotebookType mismatch: expected %s, got %s", notebook.NotebookType, decoded.NotebookType) + } + + if len(decoded.Cells) != len(notebook.Cells) { + t.Errorf("Cells length mismatch: expected %d, got %d", len(notebook.Cells), len(decoded.Cells)) + } + + if decoded.Cells[0].Kind != 1 { // NotebookCellKindMarkdown + t.Errorf("First cell kind mismatch: expected %d, got %d", 1, decoded.Cells[0].Kind) + } + + if decoded.Cells[1].ExecutionSummary == nil { + t.Fatal("ExecutionSummary should not be nil after unmarshaling") + } + if decoded.Cells[1].ExecutionSummary.ExecutionOrder != 1 { + t.Errorf("ExecutionOrder mismatch: expected 1, got %d", decoded.Cells[1].ExecutionSummary.ExecutionOrder) + } +} + +func TestDiagnosticPullModelJSONSerialization(t *testing.T) { + // Test DocumentDiagnosticParams + params := DocumentDiagnosticParams{ + TextDocument: protocol316.TextDocumentIdentifier{URI: "file:///test.go"}, + Identifier: stringPtr("go-lsp"), + PreviousResultId: stringPtr("result-123"), + } + + data, err := json.Marshal(params) + if err != nil { + t.Fatalf("Failed to marshal DocumentDiagnosticParams: %v", err) + } + + var decoded DocumentDiagnosticParams + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("Failed to unmarshal DocumentDiagnosticParams: %v", err) + } + + if *decoded.Identifier != *params.Identifier { + t.Errorf("Identifier mismatch: expected %s, got %s", *params.Identifier, *decoded.Identifier) + } + + // Test FullDocumentDiagnosticReport + report := FullDocumentDiagnosticReport{ + Kind: string(DocumentDiagnosticReportKindFull), + ResultID: stringPtr("result-456"), + Items: []protocol316.Diagnostic{ + { + Range: protocol316.Range{Start: protocol316.Position{Line: 1, Character: 0}, End: protocol316.Position{Line: 1, Character: 5}}, + Message: "Test diagnostic", + Severity: func() *protocol316.DiagnosticSeverity { s := protocol316.DiagnosticSeverityError; return &s }(), + }, + }, + } + + data, err = json.Marshal(report) + if err != nil { + t.Fatalf("Failed to marshal FullDocumentDiagnosticReport: %v", err) + } + + var decodedReport FullDocumentDiagnosticReport + err = json.Unmarshal(data, &decodedReport) + if err != nil { + t.Fatalf("Failed to unmarshal FullDocumentDiagnosticReport: %v", err) + } + + if decodedReport.Kind != report.Kind { + t.Errorf("Kind mismatch: expected %s, got %s", report.Kind, decodedReport.Kind) + } + + if len(decodedReport.Items) != 1 { + t.Errorf("Items length mismatch: expected 1, got %d", len(decodedReport.Items)) + } +} + +func TestClientCapabilitiesJSONSerialization(t *testing.T) { + capabilities := ClientCapabilities{ + TextDocument: &TextDocumentClientCapabilities{ + Diagnostic: &DiagnosticClientCapabilities{ + DynamicRegistration: true, + RelatedDocumentSupport: false, + }, + TypeHierarchy: &TypeHierarchyClientCapabilities{ + DynamicRegistration: boolPtr(true), + }, + InlineValue: &InlineValueClientCapabilities{ + DynamicRegistration: boolPtr(false), + }, + InlayHint: &InlayHintClientCapabilities{ + DynamicRegistration: boolPtr(true), + ResolveSupport: &struct { + Properties []string `json:"properties"` + }{ + Properties: []string{"tooltip", "textEdits"}, + }, + }, + }, + NotebookDocument: &NotebookDocumentClientCapabilities{ + Synchronization: NotebookDocumentSyncClientCapabilities{ + DynamicRegistration: boolPtr(true), + ExecutionSummarySupport: boolPtr(true), + }, + }, + General: &GeneralClientCapabilities{ + PositionEncodings: []PositionEncodingKind{ + PositionEncodingKindUTF8, + PositionEncodingKindUTF16, + }, + }, + } + + data, err := json.Marshal(capabilities) + if err != nil { + t.Fatalf("Failed to marshal ClientCapabilities: %v", err) + } + + var decoded ClientCapabilities + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("Failed to unmarshal ClientCapabilities: %v", err) + } + + // Verify key fields + if decoded.TextDocument.Diagnostic.DynamicRegistration != true { + t.Error("Diagnostic.DynamicRegistration should be true") + } + + if len(decoded.General.PositionEncodings) != 2 { + t.Errorf("Expected 2 position encodings, got %d", len(decoded.General.PositionEncodings)) + } + + if decoded.General.PositionEncodings[0] != PositionEncodingKindUTF8 { + t.Errorf("Expected first encoding to be UTF-8, got %s", decoded.General.PositionEncodings[0]) + } +} + +func TestWorkspaceDiagnosticJSONSerialization(t *testing.T) { + // Test WorkspaceDiagnosticParams roundtrip + params := WorkspaceDiagnosticParams{ + Identifier: stringPtr("go-lsp"), + PreviousResultIds: []PreviousResultId{ + {URI: "file:///a.go", Value: "result-1"}, + {URI: "file:///b.go", Value: "result-2"}, + }, + } + + data, err := json.Marshal(params) + if err != nil { + t.Fatalf("Failed to marshal WorkspaceDiagnosticParams: %v", err) + } + + var decodedParams WorkspaceDiagnosticParams + err = json.Unmarshal(data, &decodedParams) + if err != nil { + t.Fatalf("Failed to unmarshal WorkspaceDiagnosticParams: %v", err) + } + + if *decodedParams.Identifier != *params.Identifier { + t.Errorf("Identifier mismatch: expected %s, got %s", *params.Identifier, *decodedParams.Identifier) + } + + if len(decodedParams.PreviousResultIds) != 2 { + t.Fatalf("PreviousResultIds length mismatch: expected 2, got %d", len(decodedParams.PreviousResultIds)) + } + + if decodedParams.PreviousResultIds[0].URI != "file:///a.go" { + t.Errorf("PreviousResultIds[0].URI mismatch: expected file:///a.go, got %s", decodedParams.PreviousResultIds[0].URI) + } + + if decodedParams.PreviousResultIds[1].Value != "result-2" { + t.Errorf("PreviousResultIds[1].Value mismatch: expected result-2, got %s", decodedParams.PreviousResultIds[1].Value) + } + + // Test WorkspaceDiagnosticReport roundtrip + report := WorkspaceDiagnosticReport{ + Items: []WorkspaceDocumentDiagnosticReport{ + WorkspaceFullDocumentDiagnosticReport{ + FullDocumentDiagnosticReport: FullDocumentDiagnosticReport{ + Kind: string(DocumentDiagnosticReportKindFull), + ResultID: stringPtr("result-3"), + Items: []protocol316.Diagnostic{ + { + Range: protocol316.Range{Start: protocol316.Position{Line: 1, Character: 0}, End: protocol316.Position{Line: 1, Character: 5}}, + Message: "unused variable", + }, + }, + }, + URI: "file:///a.go", + Version: func() *protocol316.Integer { v := protocol316.Integer(3); return &v }(), + }, + }, + } + + data, err = json.Marshal(report) + if err != nil { + t.Fatalf("Failed to marshal WorkspaceDiagnosticReport: %v", err) + } + + var decodedReport WorkspaceDiagnosticReport + err = json.Unmarshal(data, &decodedReport) + if err != nil { + t.Fatalf("Failed to unmarshal WorkspaceDiagnosticReport: %v", err) + } + + if len(decodedReport.Items) != 1 { + t.Fatalf("Items length mismatch: expected 1, got %d", len(decodedReport.Items)) + } +} + +func TestServerCapabilitiesJSONSerialization(t *testing.T) { + capabilities := ServerCapabilities{ + DiagnosticProvider: DiagnosticOptions{ + InterFileDependencies: true, + WorkspaceDiagnostics: true, + Identifier: stringPtr("test-server"), + }, + TypeHierarchyProvider: true, + InlineValueProvider: &InlineValueOptions{}, + InlayHintProvider: &InlayHintOptions{ + ResolveProvider: boolPtr(true), + }, + NotebookDocumentSync: &NotebookDocumentSyncOptions{ + NotebookSelector: []NotebookSelector{ + { + Notebook: "jupyter-notebook", + Cells: []NotebookCellSelector{ + {Language: "python"}, + {Language: "markdown"}, + }, + }, + }, + Save: boolPtr(true), + }, + } + + data, err := json.Marshal(capabilities) + if err != nil { + t.Fatalf("Failed to marshal ServerCapabilities: %v", err) + } + + var decoded ServerCapabilities + err = json.Unmarshal(data, &decoded) + if err != nil { + t.Fatalf("Failed to unmarshal ServerCapabilities: %v", err) + } + + // Verify some key fields (the complex unmarshaling logic would need more comprehensive testing) + if decoded.TypeHierarchyProvider != true { + t.Error("TypeHierarchyProvider should be true") + } +} + +// Helper functions +func stringPtr(s string) *string { + return &s +} + +func boolPtr(b bool) *bool { + return &b +} diff --git a/protocol_3_17/language-features.go b/protocol_3_17/language-features.go new file mode 100644 index 0000000..34091b2 --- /dev/null +++ b/protocol_3_17/language-features.go @@ -0,0 +1,3759 @@ +package protocol + +import ( + "encoding/json" + + "github.com/tliron/glsp" +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_completion + +type CompletionClientCapabilities 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 following 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"` + + /** + * Client supports the tag property on a completion item. Clients + * supporting tags have to handle unknown tags gracefully. Clients + * especially need to preserve unknown tags when sending a completion + * item back to the server in a resolve call. + * + * @since 3.15.0 + */ + TagSupport *struct { + /** + * The tags supported by the client. + */ + ValueSet []CompletionItemTag `json:"valueSet"` + } `json:"tagSupport,omitempty"` + + /** + * Client supports insert replace edit to control different behavior if + * a completion item is inserted in the text or should replace text. + * + * @since 3.16.0 + */ + InsertReplaceSupport *bool `json:"insertReplaceSupport,omitempty"` + + /** + * Indicates which properties a client can resolve lazily on a + * completion item. Before version 3.16.0 only the predefined properties + * `documentation` and `details` could be resolved lazily. + * + * @since 3.16.0 + */ + ResolveSupport *struct { + /** + * The properties that a client can resolve lazily. + */ + Properties []string `json:"properties"` + } `json:"resolveSupport,omitempty"` + + /** + * The client supports the `insertTextMode` property on + * a completion item to override the whitespace handling mode + * as defined by the client (see `insertTextMode`). + * + * @since 3.16.0 + */ + InsertTextModeSupport *struct { + ValueSet []InsertTextMode `json:"valueSet"` + } `json:"insertTextModeSupport,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"` +} + +/** + * Completion options. + */ +type CompletionOptions struct { + WorkDoneProgressOptions + + /** + * 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 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"` +} + +type CompletionRegistrationOptions struct { + TextDocumentRegistrationOptions + CompletionOptions +} + +const MethodTextDocumentCompletion = Method("textDocument/completion") + +// Returns: []CompletionItem | CompletionList | nil +type TextDocumentCompletionFunc func(context *glsp.Context, params *CompletionParams) (any, error) + +type CompletionParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams + + /** + * The completion context. This is only available if the client specifies + * to send this using the client capability + * `completion.contextSupport === true` + */ + Context *CompletionContext `json:"context,omitempty"` +} + +/** + * How a completion was triggered + */ +type CompletionTriggerKind Integer + +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 + * `CompletionRegistrationOptions`. + */ + CompletionTriggerKindTriggerCharacter = CompletionTriggerKind(2) + + /** + * Completion was re-triggered as the current completion list is incomplete. + */ + CompletionTriggerKindTriggerForIncompleteCompletions = 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 Integer + +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) +) + +/** + * Completion item tags are extra annotations that tweak the rendering of a + * completion item. + * + * @since 3.15.0 + */ +type CompletionItemTag Integer + +const ( + /** + * Render a completion as obsolete, usually using a strike-out. + */ + CompletionItemTagDeprecated = CompletionItemTag(1) +) + +/** + * A special text edit to provide an insert and a replace operation. + * + * @since 3.16.0 + */ +type InsertReplaceEdit struct { + /** + * The string to be inserted. + */ + NewText string `json:"newText"` + + /** + * The range if the insert is requested + */ + Insert Range `json:"insert"` + + /** + * The range if the replace is requested. + */ + Replace Range `json:"replace"` +} + +/** + * How whitespace and indentation is handled during completion + * item insertion. + * + * @since 3.16.0 + */ +type InsertTextMode Integer + +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) +) + +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. 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 any `json:"documentation,omitempty"` // nil | string | MarkupContent + + /** + * 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 `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. + */ + 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`. + */ + InsertTextFormat *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 + */ + 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 `InsertReplaceEdits` via the + * `textDocument.completion.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 any `json:"textEdit,omitempty"` // nil | TextEdit | InsertReplaceEdit + + /** + * 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 any `json:"data,omitempty"` +} + +// ([json.Unmarshaler] interface) +func (self *CompletionItem) UnmarshalJSON(data []byte) error { + var value struct { + Label string `json:"label"` + Kind *CompletionItemKind `json:"kind,omitempty"` + Tags []CompletionItemTag `json:"tags,omitempty"` + Detail *string `json:"detail,omitempty"` + Documentation json.RawMessage `json:"documentation,omitempty"` // nil | string | MarkupContent + Deprecated *bool `json:"deprecated,omitempty"` + Preselect *bool `json:"preselect,omitempty"` + SortText *string `json:"sortText,omitempty"` + FilterText *string `json:"filterText,omitempty"` + InsertText *string `json:"insertText,omitempty"` + InsertTextFormat *InsertTextFormat `json:"insertTextFormat,omitempty"` + InsertTextMode *InsertTextMode `json:"insertTextMode,omitempty"` + TextEdit json.RawMessage `json:"textEdit,omitempty"` // nil | TextEdit | InsertReplaceEdit + AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"` + CommitCharacters []string `json:"commitCharacters,omitempty"` + Command *Command `json:"command,omitempty"` + Data any `json:"data,omitempty"` + } + + if err := json.Unmarshal(data, &value); err == nil { + self.Label = value.Label + self.Kind = value.Kind + self.Tags = value.Tags + self.Detail = value.Detail + self.Deprecated = value.Deprecated + self.Preselect = value.Preselect + self.SortText = value.SortText + self.FilterText = value.FilterText + self.InsertText = value.InsertText + self.InsertTextFormat = value.InsertTextFormat + self.InsertTextMode = value.InsertTextMode + self.AdditionalTextEdits = value.AdditionalTextEdits + self.CommitCharacters = value.CommitCharacters + self.Command = value.Command + self.Data = value.Data + + if value.Documentation != nil { + var value_ string + if err = json.Unmarshal(value.Documentation, &value_); err == nil { + self.Documentation = value_ + } else { + var value_ MarkupContent + if err = json.Unmarshal(value.Documentation, &value_); err == nil { + self.Documentation = value_ + } else { + return err + } + } + } + + if value.TextEdit != nil { + var raw map[string]json.RawMessage + if err = json.Unmarshal(value.TextEdit, &raw); err != nil { + return err + } + if _, hasInsert := raw["insert"]; hasInsert { + var value_ InsertReplaceEdit + if err = json.Unmarshal(value.TextEdit, &value_); err != nil { + return err + } + self.TextEdit = value_ + } else { + var value_ TextEdit + if err = json.Unmarshal(value.TextEdit, &value_); err != nil { + return err + } + self.TextEdit = value_ + } + } + + return nil + } else { + return err + } +} + +/** + * The kind of a completion entry. + */ +type CompletionItemKind Integer + +const ( + 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) +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#completionItem_resolve + +const MethodCompletionItemResolve = Method("completionItem/resolve") + +type CompletionItemResolveFunc func(context *glsp.Context, params *CompletionItem) (*CompletionItem, error) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_hover + +type HoverClientCapabilities struct { + /** + * Whether hover supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + + /** + * Client supports the following content formats if the content + * property refers to a `literal of type MarkupContent`. + * The order describes the preferred format of the client. + */ + ContentFormat []MarkupKind `json:"contentFormat,omitempty"` +} + +type HoverOptions struct { + WorkDoneProgressOptions +} + +type HoverRegistrationOptions struct { + TextDocumentRegistrationOptions + HoverOptions +} + +const MethodTextDocumentHover = Method("textDocument/hover") + +type TextDocumentHoverFunc func(context *glsp.Context, params *HoverParams) (*Hover, error) + +type HoverParams struct { + TextDocumentPositionParams + WorkDoneProgressParams +} + +/** + * The result of a hover request. + */ +type Hover struct { + /** + * The hover's content + */ + Contents any `json:"contents"` // MarkupContent | MarkedString | []MarkedString + + /** + * 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"` +} + +// ([json.Unmarshaler] interface) +func (self *Hover) UnmarshalJSON(data []byte) error { + var value struct { + Contents json.RawMessage `json:"contents"` // MarkupContent | MarkedString | []MarkedString + Range *Range `json:"range,omitempty"` + } + + if err := json.Unmarshal(data, &value); err == nil { + self.Range = value.Range + + var value_ MarkupContent + if err = json.Unmarshal(value.Contents, &value_); err == nil { + self.Contents = value_ + } else { + var value_ MarkedString + if err = json.Unmarshal(value.Contents, &value_); err == nil { + self.Contents = value_ + } else { + var value_ []MarkedString + if err = json.Unmarshal(value.Contents, &value_); err == nil { + self.Contents = value_ + } else { + return err + } + } + } + + return nil + } else { + return err + } +} + +/** + * MarkedString can be used to render human readable text. It is either a + * markdown string or a code-block that provides a language and a code snippet. + * The language identifier is semantically equal to the optional language + * identifier in fenced code blocks in GitHub issues. + * + * The pair of a language and a value is an equivalent to markdown: + * ```${language} + * ${value} + * ``` + * + * Note that markdown strings will be sanitized - that means html will be + * escaped. + * + * @deprecated use MarkupContent instead. + */ +type MarkedString struct { + value any // string | MarkedStringStruct +} + +type MarkedStringStruct struct { + Language string `json:"language"` + Value string `json:"value"` +} + +// ([json.Marshaler] interface) +func (self MarkedString) MarshalJSON() ([]byte, error) { + return json.Marshal(self.value) +} + +// ([json.Unmarshaler] interface) +func (self *MarkedString) UnmarshalJSON(data []byte) error { + var value string + if err := json.Unmarshal(data, &value); err == nil { + self.value = value + return nil + } else { + var value MarkedStringStruct + if err := json.Unmarshal(data, &value); err == nil { + self.value = value + return nil + } else { + return err + } + } +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_signatureHelp + +type SignatureHelpClientCapabilities 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 following content formats for the documentation + * property. The order describes the preferred format of the client. + */ + DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"` + + /** + * Client capabilities specific to parameter information. + */ + ParameterInformation *struct { + /** + * The client supports processing label offsets instead of a + * simple label string. + * + * @since 3.14.0 + */ + LabelOffsetSupport *bool `json:"labelOffsetSupport,omitempty"` + } `json:"parameterInformation,omitempty"` + + /** + * The client supports the `activeParameter` property on + * `SignatureInformation` literal. + * + * @since 3.16.0 + */ + ActiveParameterSupport *bool `json:"activeParameterSupport,omitempty"` + } `json:"signatureInformation,omitempty"` + + /** + * The client supports to send additional context information for a + * `textDocument/signatureHelp` request. A client that opts into + * contextSupport will also support the `retriggerCharacters` on + * `SignatureHelpOptions`. + * + * @since 3.15.0 + */ + ContextSupport *bool `json:"contextSupport,omitempty"` +} + +type SignatureHelpOptions struct { + WorkDoneProgressOptions + + /** + * The characters that trigger signature help + * automatically. + */ + TriggerCharacters []string `json:"triggerCharacters,omitempty"` + + /** + * List of characters that re-trigger signature help. + * + * These trigger characters are only active when signature help is already + * showing. All trigger characters are also counted as re-trigger + * characters. + * + * @since 3.15.0 + */ + RetriggerCharacters []string `json:"retriggerCharacters,omitempty"` +} + +type SignatureHelpRegistrationOptions struct { + TextDocumentRegistrationOptions + SignatureHelpOptions +} + +const MethodTextDocumentSignatureHelp = Method("textDocument/signatureHelp") + +type TextDocumentSignatureHelpFunc func(context *glsp.Context, params *SignatureHelpParams) (*SignatureHelp, error) + +type SignatureHelpParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + + /** + * The signature help context. This is only available if the client + * specifies to send this using the client capability + * `textDocument.signatureHelp.contextSupport === true` + * + * @since 3.15.0 + */ + Context *SignatureHelpContext `json:"context,omitempty"` +} + +/** + * How a signature help was triggered. + * + * @since 3.15.0 + */ +type SignatureHelpTriggerKind Integer + +const ( + /** + * Signature help was invoked manually by the user or by a command. + */ + SignatureHelpTriggerKindInvoked = SignatureHelpTriggerKind(1) + + /** + * Signature help was triggered by a trigger character. + */ + SignatureHelpTriggerKindTriggerCharacter = SignatureHelpTriggerKind(2) + + /** + * Signature help was triggered by the cursor moving or by the document + * content changing. + */ + SignatureHelpTriggerKindContentChange = SignatureHelpTriggerKind(3) +) + +/** + * Additional information about the context in which a signature help request + * was triggered. + * + * @since 3.15.0 + */ +type SignatureHelpContext struct { + /** + * Action that caused signature help to be triggered. + */ + TriggerKind SignatureHelpTriggerKind `json:"triggerKind"` + + /** + * Character that caused signature help to be triggered. + * + * This is undefined when triggerKind !== + * SignatureHelpTriggerKind.TriggerCharacter + */ + TriggerCharacter *string `json:"triggerCharacter,omitempty"` + + /** + * `true` if signature help was already showing when it was triggered. + * + * Retriggers occur when the signature help is already active and can be + * caused by actions such as typing a trigger character, a cursor move, or + * document content changes. + */ + IsRetrigger bool `json:"isRetrigger"` + + /** + * The currently active `SignatureHelp`. + * + * The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field + * updated based on the user navigating through available signatures. + */ + ActiveSignatureHelp *SignatureHelp `json:"activeSignatureHelp,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. If no signatures are available the signature help + * request should return `null`. + */ + 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 + * the `SignatureHelp` has no signatures. + * + * 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 *UInteger `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 *UInteger `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 any `json:"documentation,omitempty"` // nil | string | MarkupContent + + /** + * The parameters of this signature. + */ + Parameters []ParameterInformation `json:"parameters,omitempty"` + + /** + * The index of the active parameter. + * + * If provided, this is used in place of `SignatureHelp.activeParameter`. + * + * @since 3.16.0 + */ + ActiveParameter *UInteger `json:"activeParameter,omitempty"` +} + +// ([json.Unmarshaler] interface) +func (self *SignatureInformation) UnmarshalJSON(data []byte) error { + var value struct { + Label string `json:"label"` + Documentation json.RawMessage `json:"documentation"` // nil | string | MarkupContent + Parameters []ParameterInformation `json:"parameters"` + ActiveParameter *UInteger `json:"activeParameter"` + } + + if err := json.Unmarshal(data, &value); err == nil { + self.Label = value.Label + self.Parameters = value.Parameters + self.ActiveParameter = value.ActiveParameter + + if value.Documentation != nil { + var value_ string + if err = json.Unmarshal(value.Documentation, &value_); err == nil { + self.Documentation = value_ + } else { + var value_ MarkupContent + if err = json.Unmarshal(value.Documentation, &value_); err == nil { + self.Documentation = value_ + } else { + return err + } + } + } + + return nil + } else { + return err + } +} + +/** + * 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 information. + * + * Either a string or an inclusive start and exclusive end offsets within + * its containing signature label. (see SignatureInformation.label). The + * offsets are based on a UTF-16 string representation as `Position` and + * `Range` does. + * + * *Note*: a label of type string should be a substring of its containing + * signature label. Its intended use case is to highlight the parameter + * label part in the `SignatureInformation.label`. + */ + Label any `json:"label"` // string | [2]UInteger + + /** + * The human-readable doc-comment of this parameter. Will be shown + * in the UI but can be omitted. + */ + Documentation any `json:"documentation,omitempty"` // nil | string | MarkupContent +} + +// ([json.Unmarshaler] interface) +func (self *ParameterInformation) UnmarshalJSON(data []byte) error { + var value struct { + Label json.RawMessage `json:"label"` // string | [2]UInteger + Documentation json.RawMessage `json:"documentation"` // nil | string | MarkupContent + } + + if err := json.Unmarshal(data, &value); err == nil { + var value_ string + if err = json.Unmarshal(value.Label, &value_); err == nil { + self.Label = value_ + } else { + var value_ []UInteger + if err = json.Unmarshal(value.Label, &value_); err == nil { + self.Label = value_ + } else { + return err + } + } + + if value.Documentation != nil { + var value_ string + if err = json.Unmarshal(value.Documentation, &value_); err == nil { + self.Documentation = value_ + } else { + var value_ MarkupContent + if err = json.Unmarshal(value.Documentation, &value_); err == nil { + self.Documentation = value_ + } else { + return err + } + } + } + + return nil + } else { + return err + } +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_declaration + +type DeclarationClientCapabilities struct { + /** + * Whether declaration supports dynamic registration. If this is set to + * `true` the client supports the new `DeclarationRegistrationOptions` + * return value for the corresponding server capability as well. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + + /** + * The client supports additional metadata in the form of declaration links. + */ + LinkSupport *bool `json:"linkSupport,omitempty"` +} + +type DeclarationOptions struct { + WorkDoneProgressOptions +} + +type DeclarationRegistrationOptions struct { + DeclarationOptions + TextDocumentRegistrationOptions + StaticRegistrationOptions +} + +const MethodTextDocumentDeclaration = Method("textDocument/declaration") + +// Returns: Location | []Location | []LocationLink | nil +type TextDocumentDeclarationFunc func(context *glsp.Context, params *DeclarationParams) (any, error) + +type DeclarationParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_definition + +type DefinitionClientCapabilities struct { + /** + * Whether definition supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + + /** + * The client supports additional metadata in the form of definition links. + * + * @since 3.14.0 + */ + LinkSupport *bool `json:"linkSupport,omitempty"` +} + +type DefinitionOptions struct { + WorkDoneProgressOptions +} + +type DefinitionRegistrationOptions struct { + TextDocumentRegistrationOptions + DefinitionOptions +} + +const MethodTextDocumentDefinition = Method("textDocument/definition") + +// Returns: Location | []Location | []LocationLink | nil +type TextDocumentDefinitionFunc func(context *glsp.Context, params *DefinitionParams) (any, error) + +type DefinitionParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_typeDefinition + +type TypeDefinitionClientCapabilities struct { + /** + * Whether implementation supports dynamic registration. If this is set to + * `true` the client supports the new `TypeDefinitionRegistrationOptions` + * return value for the corresponding server capability as well. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + + /** + * The client supports additional metadata in the form of definition links. + * + * @since 3.14.0 + */ + LinkSupport *bool `json:"linkSupport,omitempty"` +} + +type TypeDefinitionOptions struct { + WorkDoneProgressOptions +} + +type TypeDefinitionRegistrationOptions struct { + TextDocumentRegistrationOptions + TypeDefinitionOptions + StaticRegistrationOptions +} + +const MethodTextDocumentTypeDefinition = Method("textDocument/typeDefinition") + +// Returns: Location | []Location | []LocationLink | nil +type TextDocumentTypeDefinitionFunc func(context *glsp.Context, params *TypeDefinitionParams) (any, error) + +type TypeDefinitionParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_implementation + +type ImplementationClientCapabilities struct { + /** + * Whether implementation supports dynamic registration. If this is set to + * `true` the client supports the new `ImplementationRegistrationOptions` + * return value for the corresponding server capability as well. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + + /** + * The client supports additional metadata in the form of definition links. + * + * @since 3.14.0 + */ + LinkSupport *bool `json:"linkSupport,omitempty"` +} + +type ImplementationOptions struct { + WorkDoneProgressOptions +} + +type ImplementationRegistrationOptions struct { + TextDocumentRegistrationOptions + ImplementationOptions + StaticRegistrationOptions +} + +const MethodTextDocumentImplementation = Method("textDocument/implementation") + +// Returns: Location | []Location | []LocationLink | nil +type TextDocumentImplementationFunc func(context *glsp.Context, params *ImplementationParams) (any, error) + +type ImplementationParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_references + +type ReferenceClientCapabilities struct { + /** + * Whether references supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +type ReferenceOptions struct { + WorkDoneProgressOptions +} + +type ReferenceRegistrationOptions struct { + TextDocumentRegistrationOptions + ReferenceOptions +} + +const MethodTextDocumentReferences = Method("textDocument/references") + +type TextDocumentReferencesFunc func(context *glsp.Context, params *ReferenceParams) ([]Location, error) + +type ReferenceParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams + + Context ReferenceContext `json:"context"` +} + +type ReferenceContext struct { + /** + * Include the declaration of the current symbol. + */ + IncludeDeclaration bool `json:"includeDeclaration"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_documentHighlight + +type DocumentHighlightClientCapabilities struct { + /** + * Whether document highlight supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +type DocumentHighlightOptions struct { + WorkDoneProgressOptions +} + +type DocumentHighlightRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentHighlightOptions +} + +const MethodTextDocumentDocumentHighlight = Method("textDocument/documentHighlight") + +type TextDocumentDocumentHighlightFunc func(context *glsp.Context, params *DocumentHighlightParams) ([]DocumentHighlight, error) + +type DocumentHighlightParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +/** + * 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 *DocumentHighlightKind `json:"kind,omitempty"` +} + +/** + * A document highlight kind. + */ +type DocumentHighlightKind Integer + +const ( + /** + * A textual occurrence. + */ + DocumentHighlightKindText = DocumentHighlightKind(1) + + /** + * Read-access of a symbol, like reading a variable. + */ + DocumentHighlightKindRead = DocumentHighlightKind(2) + + /** + * Write-access of a symbol, like writing to a variable. + */ + DocumentHighlightKindWrite = DocumentHighlightKind(3) +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_documentSymbol + +type DocumentSymbolClientCapabilities struct { + /** + * Whether document symbol supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + + /** + * Specific capabilities for the `SymbolKind` in the + * `textDocument/documentSymbol` 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"` + + /** + * The client supports hierarchical document symbols. + */ + HierarchicalDocumentSymbolSupport *bool `json:"hierarchicalDocumentSymbolSupport,omitempty"` + + /** + * The client supports tags on `SymbolInformation`. Tags are supported on + * `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true. + * Clients supporting tags have to handle unknown tags gracefully. + * + * @since 3.16.0 + */ + TagSupport *struct { + /** + * The tags supported by the client. + */ + ValueSet []SymbolTag `json:"valueSet"` + } `json:"tagSupport,omitempty"` + + /** + * The client supports an additional label presented in the UI when + * registering a document symbol provider. + * + * @since 3.16.0 + */ + LabelSupport *bool `json:"labelSupport,omitempty"` +} + +type DocumentSymbolOptions struct { + WorkDoneProgressOptions + + /** + * A human-readable string that is shown when multiple outlines trees + * are shown for the same document. + * + * @since 3.16.0 + */ + Label *string `json:"label,omitempty"` +} + +type DocumentSymbolRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentSymbolOptions +} + +const MethodTextDocumentDocumentSymbol = Method("textDocument/documentSymbol") + +// Returns: []DocumentSymbol | []SymbolInformation | nil +type TextDocumentDocumentSymbolFunc func(context *glsp.Context, params *DocumentSymbolParams) (any, error) + +type DocumentSymbolParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +/** + * A symbol kind. + */ +type SymbolKind Integer + +const ( + SymbolKindFile = SymbolKind(1) + SymbolKindModule = SymbolKind(2) + SymbolKindNamespace = SymbolKind(3) + SymbolKindPackage = SymbolKind(4) + SymbolKindClass = SymbolKind(5) + SymbolKindMethod = SymbolKind(6) + SymbolKindProperty = SymbolKind(7) + SymbolKindField = SymbolKind(8) + SymbolKindConstructor = SymbolKind(9) + SymbolKindEnum = SymbolKind(10) + SymbolKindInterface = SymbolKind(11) + SymbolKindFunction = SymbolKind(12) + SymbolKindVariable = SymbolKind(13) + SymbolKindConstant = SymbolKind(14) + SymbolKindString = SymbolKind(15) + SymbolKindNumber = SymbolKind(16) + SymbolKindBoolean = SymbolKind(17) + SymbolKindArray = SymbolKind(18) + SymbolKindObject = SymbolKind(19) + SymbolKindKey = SymbolKind(20) + SymbolKindNull = SymbolKind(21) + SymbolKindEnumMember = SymbolKind(22) + SymbolKindStruct = SymbolKind(23) + SymbolKindEvent = SymbolKind(24) + SymbolKindOperator = SymbolKind(25) + SymbolKindTypeParameter = SymbolKind(26) +) + +/** + * Symbol tags are extra annotations that tweak the rendering of a symbol. + * + * @since 3.16.0 + */ +type SymbolTag Integer + +const ( + /** + * Render a symbol as obsolete, usually using a strike-out. + */ + SymbolTagDeprecated = SymbolTag(1) +) + +/** + * 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. Will be displayed in the user interface and + * therefore must not be an empty string or a string only consisting of + * white spaces. + */ + Name string `json:"name"` + + /** + * More detail for this symbol, e.g the signature of a function. + */ + Detail *string `json:"detail,omitempty"` + + /** + * The kind of this symbol. + */ + Kind SymbolKind `json:"kind"` + + /** + * Tags for this document symbol. + * + * @since 3.16.0 + */ + Tags []SymbolTag `json:"tags,omitempty"` + + /** + * Indicates if this symbol is deprecated. + * + * @deprecated Use tags instead + */ + 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 SymbolKind `json:"kind"` + + /** + * Tags for this completion item. + * + * @since 3.16.0 + */ + Tags []SymbolTag `json:"tags,omitempty"` + + /** + * Indicates if this symbol is deprecated. + * + * @deprecated Use tags instead + */ + 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"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_codeAction + +type CodeActionClientCapabilities struct { + /** + * Whether code action supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + + /** + * The client supports code action literals as a valid + * response of the `textDocument/codeAction` request. + * + * @since 3.8.0 + */ + CodeActionLiteralSupport *struct { + /** + * The code action kind is supported 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"` + + /** + * Whether code action supports the `isPreferred` property. + * + * @since 3.15.0 + */ + IsPreferredSupport *bool `json:"isPreferredSupport,omitempty"` + + /** + * Whether code action supports the `disabled` property. + * + * @since 3.16.0 + */ + DisabledSupport *bool `json:"disabledSupport,omitempty"` + + /** + * Whether code action supports the `data` property which is + * preserved between a `textDocument/codeAction` and a + * `codeAction/resolve` request. + * + * @since 3.16.0 + */ + DataSupport *bool `json:"dataSupport,omitempty"` + + /** + * Whether the client supports resolving additional code action + * properties via a separate `codeAction/resolve` request. + * + * @since 3.16.0 + */ + ResolveSupport *struct { + /** + * The properties that a client can resolve lazily. + */ + Properties []string `json:"properties"` + } `json:"resolveSupport,omitempty"` + + /** + * Whether the client honors the change annotations in + * text edits and resource operations returned via the + * `CodeAction#edit` property by for example presenting + * the workspace edit in the user interface and asking + * for confirmation. + * + * @since 3.16.0 + */ + HonorsChangeAnnotations *bool `json:"honorsChangeAnnotations,omitempty"` +} + +type CodeActionOptions struct { + WorkDoneProgressOptions + + /** + * CodeActionKinds that this server may return. + * + * The list of kinds may be generic, such as `CodeActionKind.Refactor`, + * or the server may list out every specific kind they provide. + */ + CodeActionKinds []CodeActionKind `json:"codeActionKinds,omitempty"` + + /** + * The server provides support to resolve additional + * information for a code action. + * + * @since 3.16.0 + */ + ResolveProvider *bool `json:"resolveProvider,omitempty"` +} + +type CodeActionRegistrationOptions struct { + TextDocumentRegistrationOptions + CodeActionOptions +} + +const MethodTextDocumentCodeAction = Method("textDocument/codeAction") + +// Returns: Command | []CodeAction | nil +type TextDocumentCodeActionFunc func(context *glsp.Context, params *CodeActionParams) (any, error) + +/** + * Params for the CodeActionRequest + */ +type CodeActionParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * 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 ( + /** + * Empty kind. + */ + CodeActionKindEmpty = CodeActionKind("") + + /** + * Base kind for quickfix actions: 'quickfix'. + */ + CodeActionKindQuickFix = CodeActionKind("quickfix") + + /** + * Base kind for refactoring actions: 'refactor'. + */ + CodeActionKindRefactor = CodeActionKind("refactor") + + /** + * Base kind for refactoring extraction actions: 'refactor.extract'. + * + * Example extract actions: + * + * - Extract method + * - Extract function + * - Extract variable + * - Extract interface from class + * - ... + */ + CodeActionKindRefactorExtract = CodeActionKind("refactor.extract") + + /** + * Base kind for refactoring inline actions: 'refactor.inline'. + * + * Example inline actions: + * + * - Inline function + * - Inline variable + * - Inline constant + * - ... + */ + CodeActionKindRefactorInline = 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 + * - ... + */ + CodeActionKindRefactorRewrite = CodeActionKind("refactor.rewrite") + + /** + * Base kind for source actions: `source`. + * + * Source code actions apply to the entire file. + */ + CodeActionKindSource = CodeActionKind("source") + + /** + * Base kind for an organize imports source action: + * `source.organizeImports`. + */ + CodeActionKindSourceOrganizeImports = CodeActionKind("source.organizeImports") +) + +/** +* Contains additional diagnostic information about the context in which +* a code action is run. + */ +type CodeActionContext struct { + /** + * An array of diagnostics known on the client side overlapping the range + * provided to the `textDocument/codeAction` request. They are provided so + * that the server knows which errors are currently presented to the user + * for the given range. There is no guarantee that these accurately reflect + * the error state of the resource. The primary parameter + * to compute code actions is the provided range. + */ + 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"` + + /** + * Marks this as a preferred action. Preferred actions are used by the + * `auto fix` command and can be targeted by keybindings. + * + * A quick fix should be marked preferred if it properly addresses the + * underlying error. A refactoring should be marked preferred if it is the + * most reasonable choice of actions to take. + * + * @since 3.15.0 + */ + IsPreferred *bool `json:"isPreferred,omitempty"` + + /** + * Marks that the code action cannot currently be applied. + * + * Clients should follow the following guidelines regarding disabled code + * actions: + * + * - Disabled code actions are not shown in automatic lightbulbs code + * action menus. + * + * - Disabled actions are shown as faded out in the code action menu when + * the user request a more specific type of code action, such as + * refactorings. + * + * - If the user has a keybinding that auto applies a code action and only + * a disabled code actions are returned, the client should show the user + * an error message with `reason` in the editor. + * + * @since 3.16.0 + */ + Disabled *struct { + /** + * Human readable description of why the code action is currently + * disabled. + * + * This is displayed in the code actions UI. + */ + Reason string `json:"reason"` + } `json:"disabled,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"` + + /** + * A data entry field that is preserved on a code action between + * a `textDocument/codeAction` and a `codeAction/resolve` request. + * + * @since 3.16.0 + */ + Data any `json:"data,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#codeAction_resolve + +const MethodCodeActionResolve = Method("codeAction/resolve") + +type CodeActionResolveFunc func(context *glsp.Context, params *CodeAction) (*CodeAction, error) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_codeLens + +type CodeLensClientCapabilities struct { + /** + * Whether code lens supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +type CodeLensOptions struct { + WorkDoneProgressOptions + + /** + * Code lens has a resolve provider as well. + */ + ResolveProvider *bool `json:"resolveProvider,omitempty"` +} + +type CodeLensRegistrationOptions struct { + TextDocumentRegistrationOptions + CodeLensOptions +} + +const MethodTextDocumentCodeLens = Method("textDocument/codeLens") + +type TextDocumentCodeLensFunc func(context *glsp.Context, params *CodeLensParams) ([]CodeLens, error) + +type CodeLensParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * 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 any `json:"data,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#codeLens_resolve + +const MethodCodeLensResolve = Method("codeLens/resolve") + +type CodeLensResolveFunc func(context *glsp.Context, params *CodeLens) (*CodeLens, error) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#codeLens_refresh + +type CodeLensWorkspaceClientCapabilities struct { + /** + * Whether the client implementation supports a refresh request sent from the + * server to the client. + * + * Note that this event is global and will force the client to refresh all + * code lenses currently shown. It should be used with absolute care and is + * useful for situation where a server for example detect a project wide + * change that requires such a calculation. + */ + RefreshSupport *bool `json:"refreshSupport,omitempty"` +} + +const ServerWorkspaceCodeLensRefresh = Method("workspace/codeLens/refresh") + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_documentLink + +type DocumentLinkClientCapabilities struct { + /** + * Whether document link supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + + /** + * Whether the client supports the `tooltip` property on `DocumentLink`. + * + * @since 3.15.0 + */ + TooltipSupport *bool `json:"tooltipSupport,omitempty"` +} + +type DocumentLinkOptions struct { + WorkDoneProgressOptions + + /** + * Document links have a resolve provider as well. + */ + ResolveProvider *bool `json:"resolveProvider,omitempty"` +} + +type DocumentLinkRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentLinkOptions +} + +const MethodTextDocumentDocumentLink = Method("textDocument/documentLink") + +type TextDocumentDocumentLinkFunc func(context *glsp.Context, params *DocumentLinkParams) ([]DocumentLink, error) + +type DocumentLinkParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * 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"` + + /** + * The tooltip text when you hover over this link. + * + * If a tooltip is provided, is will be displayed in a string that includes + * instructions on how to trigger the link, such as `{0} (ctrl + click)`. + * The specific instructions vary depending on OS, user settings, and + * localization. + * + * @since 3.15.0 + */ + Tooltip *string `json:"tooltip,omitempty"` + + /** + * A data entry field that is preserved on a document link between a + * DocumentLinkRequest and a DocumentLinkResolveRequest. + */ + Data any `json:"data,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#documentLink_resolve + +const MethodDocumentLinkResolve = Method("documentLink/resolve") + +type DocumentLinkResolveFunc func(context *glsp.Context, params *DocumentLink) (*DocumentLink, error) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_documentColor + +type DocumentColorClientCapabilities struct { + /** + * Whether document color supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +type DocumentColorOptions struct { + WorkDoneProgressOptions +} + +type DocumentColorRegistrationOptions struct { + TextDocumentRegistrationOptions + StaticRegistrationOptions + DocumentColorOptions +} + +const MethodTextDocumentColor = Method("textDocument/documentColor") + +type TextDocumentColorFunc func(context *glsp.Context, params *DocumentColorParams) ([]ColorInformation, error) + +type DocumentColorParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * 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 Decimal `json:"red"` + + /** + * The green component of this color in the range [0-1]. + */ + Green Decimal `json:"green"` + + /** + * The blue component of this color in the range [0-1]. + */ + Blue Decimal `json:"blue"` + + /** + * The alpha component of this color in the range [0-1]. + */ + Alpha Decimal `json:"alpha"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_colorPresentation + +const MethodTextDocumentColorPresentation = Method("textDocument/colorPresentation") + +type TextDocumentColorPresentationFunc func(context *glsp.Context, params *ColorPresentationParams) ([]ColorPresentation, error) + +type ColorPresentationParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * 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"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_formatting + +type DocumentFormattingClientCapabilities struct { + /** + * Whether formatting supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +type DocumentFormattingOptions struct { + WorkDoneProgressOptions +} + +type DocumentFormattingRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentFormattingOptions +} + +const MethodTextDocumentFormatting = Method("textDocument/formatting") + +type TextDocumentFormattingFunc func(context *glsp.Context, params *DocumentFormattingParams) ([]TextEdit, error) + +type DocumentFormattingParams struct { + WorkDoneProgressParams + + /** + * The document to format. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The format options. + */ + Options FormattingOptions `json:"options"` +} + +type FormattingOptions map[string]any // bool | Integer | string + +/** + * Value-object describing what options formatting should use. + */ +const ( + /** + * Size of a tab in spaces. + */ + FormattingOptionTabSize = "tabSize" + + /** + * Prefer spaces over tabs. + */ + FormattingOptionInsertSpaces = "insertSpaces" + + /** + * Trim trailing whitespace on a line. + * + * @since 3.15.0 + */ + FormattingOptionTrimTrailingWhitespace = "trimTrailingWhitespace" + + /** + * Insert a newline character at the end of the file if one does not exist. + * + * @since 3.15.0 + */ + FormattingOptionInsertFinalNewline = "insertFinalNewline" + + /** + * Trim all newlines after the final newline at the end of the file. + * + * @since 3.15.0 + */ + FormattingOptionTrimFinalNewlines = "trimFinalNewlines" +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_rangeFormatting + +type DocumentRangeFormattingClientCapabilities struct { + /** + * Whether formatting supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +type DocumentRangeFormattingOptions struct { + WorkDoneProgressOptions +} + +type DocumentRangeFormattingRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentRangeFormattingOptions +} + +const MethodTextDocumentRangeFormatting = Method("textDocument/rangeFormatting") + +type TextDocumentRangeFormattingFunc func(context *glsp.Context, params *DocumentRangeFormattingParams) ([]TextEdit, error) + +type DocumentRangeFormattingParams struct { + WorkDoneProgressParams + + /** + * The document to format. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The range to format + */ + Range Range `json:"range"` + + /** + * The format options + */ + Options FormattingOptions `json:"options"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_onTypeFormatting + +type DocumentOnTypeFormattingClientCapabilities struct { + /** + * Whether on type formatting supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +type DocumentOnTypeFormattingOptions struct { + /** + * A character on which formatting should be triggered, like `}`. + */ + FirstTriggerCharacter string `json:"firstTriggerCharacter"` + + /** + * More trigger characters. + */ + MoreTriggerCharacter []string `json:"moreTriggerCharacter,omitempty"` +} + +type DocumentOnTypeFormattingRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentOnTypeFormattingOptions +} + +const MethodTextDocumentOnTypeFormatting = Method("textDocument/onTypeFormatting") + +type TextDocumentOnTypeFormattingFunc func(context *glsp.Context, params *DocumentOnTypeFormattingParams) ([]TextEdit, error) + +type DocumentOnTypeFormattingParams struct { + TextDocumentPositionParams + /** + * The character that has been typed. + */ + Ch string `json:"ch"` + + /** + * The format options. + */ + Options FormattingOptions `json:"options"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_rename + +type PrepareSupportDefaultBehavior Integer + +const ( + /** + * The client's default behavior is to select the identifier + * according the to language's syntax rule. + */ + PrepareSupportDefaultBehaviorIdentifier = PrepareSupportDefaultBehavior(1) +) + +type RenameClientCapabilities struct { + /** + * Whether rename supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + + /** + * Client supports testing for validity of rename operations + * before execution. + * + * @since 3.12.0 + */ + PrepareSupport *bool `json:"prepareSupport,omitempty"` + + /** + * Client supports the default behavior result + * (`{ defaultBehavior: boolean }`). + * + * The value indicates the default behavior used by the + * client. + * + * @since 3.16.0 + */ + PrepareSupportDefaultBehavior *PrepareSupportDefaultBehavior `json:"prepareSupportDefaultBehavior,omitempty"` + + /** + * Whether th client honors the change annotations in + * text edits and resource operations returned via the + * rename request's workspace edit by for example presenting + * the workspace edit in the user interface and asking + * for confirmation. + * + * @since 3.16.0 + */ + HonorsChangeAnnotations *bool `json:"honorsChangeAnnotations,omitempty"` +} + +type RenameOptions struct { + WorkDoneProgressOptions + + /** + * Renames should be checked and tested before being executed. + */ + PrepareProvider *bool `json:"prepareProvider,omitempty"` +} + +type RenameRegistrationOptions struct { + TextDocumentRegistrationOptions + RenameOptions +} + +const MethodTextDocumentRename = Method("textDocument/rename") + +type TextDocumentRenameFunc func(context *glsp.Context, params *RenameParams) (*WorkspaceEdit, error) + +type RenameParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + + /** + * 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"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_prepareRename + +const MethodTextDocumentPrepareRename = Method("textDocument/prepareRename") + +// Returns: Range | RangeWithPlaceholder | DefaultBehavior | nil +type TextDocumentPrepareRenameFunc func(context *glsp.Context, params *PrepareRenameParams) (any, error) + +type PrepareRenameParams struct { + TextDocumentPositionParams +} + +type RangeWithPlaceholder struct { + Range Range `json:"range"` + Placeholder string `json:"placeholder"` +} + +type DefaultBehavior struct { + DefaultBehavior bool `json:"defaultBehavior"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_foldingRange + +type FoldingRangeClientCapabilities struct { + /** + * Whether implementation supports dynamic registration for folding range + * providers. If this is set to `true` the client supports the new + * `FoldingRangeRegistrationOptions` 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 *UInteger `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"` +} + +type FoldingRangeOptions struct { + WorkDoneProgressOptions +} + +type FoldingRangeRegistrationOptions struct { + TextDocumentRegistrationOptions + FoldingRangeOptions + StaticRegistrationOptions +} + +const MethodTextDocumentFoldingRange = Method("textDocument/foldingRange") + +type TextDocumentFoldingRangeFunc func(context *glsp.Context, params *FoldingRangeParams) ([]FoldingRange, error) + +type FoldingRangeParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +/** + * Enum of known range kinds + */ +type FoldingRangeKind string + +const ( + /** + * Folding range for a comment + */ + FoldingRangeKindComment = FoldingRangeKind("comment") + + /** + * Folding range for a imports or includes + */ + FoldingRangeKindImports = FoldingRangeKind("imports") + + /** + * Folding range for a region (e.g. `#region`) + */ + FoldingRangeKindRegion = FoldingRangeKind("region") +) + +/** + * Represents a folding range. To be valid, start and end line must be bigger + * than zero and smaller than the number of lines in the document. Clients + * are free to ignore invalid ranges. + */ +type FoldingRange struct { + /** + * The zero-based start line of the range to fold. The folded area starts + * after the line's last character. To be valid, the end must be zero or + * larger and smaller than the number of lines in the document. + */ + StartLine UInteger `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 *UInteger `json:"startCharacter,omitempty"` + + /** + * The zero-based end line of the range to fold. The folded area ends with + * the line's last character. To be valid, the end must be zero or larger + * and smaller than the number of lines in the document. + */ + EndLine UInteger `json:"endLine"` + + /** + * The zero-based character offset before the folded range ends. If not + * defined, defaults to the length of the end line. + */ + EndCharacter *UInteger `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"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_selectionRange + +type SelectionRangeClientCapabilities struct { + /** + * Whether implementation supports dynamic registration for selection range + * providers. If this is set to `true` the client supports the new + * `SelectionRangeRegistrationOptions` return value for the corresponding + * server capability as well. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +type SelectionRangeOptions struct { + WorkDoneProgressOptions +} + +type SelectionRangeRegistrationOptions struct { + SelectionRangeOptions + TextDocumentRegistrationOptions + StaticRegistrationOptions +} + +const MethodTextDocumentSelectionRange = Method("textDocument/selectionRange") + +type TextDocumentSelectionRangeFunc func(context *glsp.Context, params *SelectionRangeParams) ([]SelectionRange, error) + +type SelectionRangeParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The positions inside the text document. + */ + Positions []Position `json:"positions"` +} + +type SelectionRange struct { + /** + * The [range](#Range) of this selection range. + */ + Range Range `json:"range"` + + /** + * The parent selection range containing this range. Therefore + * `parent.range` must contain `this.range`. + */ + Parent *SelectionRange `json:"parent,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_prepareCallHierarchy + +type CallHierarchyClientCapabilities 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"` +} + +type CallHierarchyOptions struct { + WorkDoneProgressOptions +} + +type CallHierarchyRegistrationOptions struct { + TextDocumentRegistrationOptions + CallHierarchyOptions + StaticRegistrationOptions +} + +const MethodTextDocumentPrepareCallHierarchy = Method("textDocument/prepareCallHierarchy") + +type TextDocumentPrepareCallHierarchyFunc func(context *glsp.Context, params *CallHierarchyPrepareParams) ([]CallHierarchyItem, error) + +type CallHierarchyPrepareParams struct { + TextDocumentPositionParams + WorkDoneProgressParams +} + +type CallHierarchyItem struct { + /** + * The name of this item. + */ + Name string `json:"name"` + + /** + * The kind of this item. + */ + Kind SymbolKind `json:"kind"` + + /** + * Tags for this item. + */ + Tags []SymbolTag `json:"tags,omitempty"` + + /** + * More detail for this item, e.g. the signature of a function. + */ + Detail *string `json:"detail,omitempty"` + + /** + * The resource identifier of this item. + */ + URI DocumentUri `json:"uri"` + + /** + * The range enclosing this symbol not including leading/trailing whitespace + * but everything else, e.g. comments and code. + */ + 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`](#CallHierarchyItem.range). + */ + SelectionRange Range `json:"selectionRange"` + + /** + * A data entry field that is preserved between a call hierarchy prepare and + * incoming calls or outgoing calls requests. + */ + Data any `json:"data,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#callHierarchy_incomingCalls + +const MethodCallHierarchyIncomingCalls = Method("callHierarchy/incomingCalls") + +type CallHierarchyIncomingCallsFunc func(context *glsp.Context, params *CallHierarchyIncomingCallsParams) ([]CallHierarchyIncomingCall, error) + +type CallHierarchyIncomingCallsParams struct { + WorkDoneProgressParams + PartialResultParams + + Item CallHierarchyItem `json:"item"` +} + +type CallHierarchyIncomingCall struct { + /** + * The item that makes the call. + */ + From CallHierarchyItem `json:"from"` + + /** + * The ranges at which the calls appear. This is relative to the caller + * denoted by [`this.from`](#CallHierarchyIncomingCall.from). + */ + FromRanges []Range `json:"fromRanges"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#callHierarchy_outgoingCalls + +const MethodCallHierarchyOutgoingCalls = Method("callHierarchy/outgoingCalls") + +type CallHierarchyOutgoingCallsFunc func(context *glsp.Context, params *CallHierarchyOutgoingCallsParams) ([]CallHierarchyOutgoingCall, error) + +type CallHierarchyOutgoingCallsParams struct { + WorkDoneProgressParams + PartialResultParams + + Item CallHierarchyItem `json:"item"` +} + +type CallHierarchyOutgoingCall struct { + /** + * The item that is called. + */ + To CallHierarchyItem `json:"to"` + + /** + * The range at which this item is called. This is the range relative to + * the caller, e.g the item passed to `callHierarchy/outgoingCalls` request. + */ + FromRanges []Range `json:"fromRanges"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_semanticTokens + +type SemanticTokenType string + +const ( + SemanticTokenTypeNamespace = SemanticTokenType("namespace") + /** + * Represents a generic type. Acts as a fallback for types which + * can't be mapped to a specific type like class or enum. + */ + SemanticTokenTypeType = SemanticTokenType("type") + SemanticTokenTypeClass = SemanticTokenType("class") + SemanticTokenTypeEnum = SemanticTokenType("enum") + SemanticTokenTypeInterface = SemanticTokenType("interface") + SemanticTokenTypeStruct = SemanticTokenType("struct") + SemanticTokenTypeTypeParameter = SemanticTokenType("typeParameter") + SemanticTokenTypeParameter = SemanticTokenType("parameter") + SemanticTokenTypeVariable = SemanticTokenType("variable") + SemanticTokenTypeProperty = SemanticTokenType("property") + SemanticTokenTypeEnumMember = SemanticTokenType("enumMember") + SemanticTokenTypeEvent = SemanticTokenType("event") + SemanticTokenTypeFunction = SemanticTokenType("function") + SemanticTokenTypeMethod = SemanticTokenType("method") + SemanticTokenTypeMacro = SemanticTokenType("macro") + SemanticTokenTypeKeyword = SemanticTokenType("keyword") + SemanticTokenTypeModifier = SemanticTokenType("modifier") + SemanticTokenTypeComment = SemanticTokenType("comment") + SemanticTokenTypeString = SemanticTokenType("string") + SemanticTokenTypeNumber = SemanticTokenType("number") + SemanticTokenTypeRegexp = SemanticTokenType("regexp") + SemanticTokenTypeOperator = SemanticTokenType("operator") +) + +type SemanticTokenModifier string + +const ( + SemanticTokenModifierDeclaration = SemanticTokenModifier("declaration") + SemanticTokenModifierDefinition = SemanticTokenModifier("definition") + SemanticTokenModifierReadonly = SemanticTokenModifier("readonly") + SemanticTokenModifierStatic = SemanticTokenModifier("static") + SemanticTokenModifierDeprecated = SemanticTokenModifier("deprecated") + SemanticTokenModifierAbstract = SemanticTokenModifier("abstract") + SemanticTokenModifierAsync = SemanticTokenModifier("async") + SemanticTokenModifierModification = SemanticTokenModifier("modification") + SemanticTokenModifierDocumentation = SemanticTokenModifier("documentation") + SemanticTokenModifierDefaultLibrary = SemanticTokenModifier("defaultLibrary") +) + +type TokenFormat string + +const ( + TokenFormatRelative = TokenFormat("relative") +) + +type SemanticTokensLegend struct { + /** + * The token types a server uses. + */ + TokenTypes []string `json:"tokenTypes"` + + /** + * The token modifiers a server uses. + */ + TokenModifiers []string `json:"tokenModifiers"` +} + +type SemanticDelta struct { + Delta *bool `json:"delta,omitempty"` +} + +type SemanticTokensClientCapabilities 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"` + + /** + * Which requests the client supports and might send to the server + * depending on the server's capability. Please note that clients might not + * show semantic tokens or degrade some of the user experience if a range + * or full request is advertised by the client but not provided by the + * server. If for example the client capability `requests.full` and + * `request.range` are both set to true but the server only provides a + * range provider the client might not render a minimap correctly or might + * even decide to not show any semantic tokens at all. + */ + Requests struct { + /** + * The client will send the `textDocument/semanticTokens/range` request + * if the server provides a corresponding handler. + */ + Range any `json:"range,omitempty"` // nil | bool | struct{} + + /** + * The client will send the `textDocument/semanticTokens/full` request + * if the server provides a corresponding handler. + */ + Full any `json:"full,omitempty"` // nil | bool | SemanticDelta + } `json:"requests"` + + /** + * The token types that the client supports. + */ + TokenTypes []string `json:"tokenTypes"` + + /** + * The token modifiers that the client supports. + */ + TokenModifiers []string `json:"tokenModifiers"` + + /** + * The formats the clients supports. + */ + Formats []TokenFormat `json:"formats"` + + /** + * Whether the client supports tokens that can overlap each other. + */ + OverlappingTokenSupport *bool `json:"overlappingTokenSupport,omitempty"` + + /** + * Whether the client supports tokens that can span multiple lines. + */ + MultilineTokenSupport *bool `json:"multilineTokenSupport,omitempty"` +} + +// ([json.Unmarshaler] interface) +func (self *SemanticTokensClientCapabilities) UnmarshalJSON(data []byte) error { + var value struct { + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + Requests struct { + Range json.RawMessage `json:"range,omitempty"` // nil | bool | struct{} + Full json.RawMessage `json:"full,omitempty"` // nil | bool | SemanticDelta + } `json:"requests"` + TokenTypes []string `json:"tokenTypes"` + TokenModifiers []string `json:"tokenModifiers"` + Formats []TokenFormat `json:"formats"` + OverlappingTokenSupport *bool `json:"overlappingTokenSupport,omitempty"` + MultilineTokenSupport *bool `json:"multilineTokenSupport,omitempty"` + } + + if err := json.Unmarshal(data, &value); err == nil { + self.DynamicRegistration = value.DynamicRegistration + self.TokenTypes = value.TokenTypes + self.TokenModifiers = value.TokenModifiers + self.Formats = value.Formats + self.OverlappingTokenSupport = value.OverlappingTokenSupport + self.MultilineTokenSupport = value.MultilineTokenSupport + + if value.Requests.Range != nil { + var value_ bool + if err = json.Unmarshal(value.Requests.Range, &value_); err == nil { + self.Requests.Range = value_ + } else { + var value_ struct{} + if err = json.Unmarshal(value.Requests.Range, &value_); err == nil { + self.Requests.Range = value_ + } else { + return err + } + } + } + + if value.Requests.Full != nil { + var value_ bool + if err = json.Unmarshal(value.Requests.Full, &value_); err == nil { + self.Requests.Full = value_ + } else { + var value_ SemanticDelta + if err = json.Unmarshal(value.Requests.Full, &value_); err == nil { + self.Requests.Full = value_ + } else { + return err + } + } + } + + return nil + } else { + return err + } +} + +type SemanticTokensOptions struct { + WorkDoneProgressOptions + + /** + * The legend used by the server + */ + Legend SemanticTokensLegend `json:"legend"` + + /** + * Server supports providing semantic tokens for a specific range + * of a document. + */ + Range any `json:"range,omitempty"` // nil | bool | struct{} + + /** + * Server supports providing semantic tokens for a full document. + */ + Full any `json:"full,omitempty"` // nil | bool | SemanticDelta +} + +// ([json.Unmarshaler] interface) +func (self *SemanticTokensOptions) UnmarshalJSON(data []byte) error { + var value struct { + WorkDoneProgressOptions + Legend SemanticTokensLegend `json:"legend"` + Range json.RawMessage `json:"range,omitempty"` // nil | bool | struct{} + Full json.RawMessage `json:"full,omitempty"` // nil | bool | SemanticDelta + } + + if err := json.Unmarshal(data, &value); err == nil { + self.WorkDoneProgressOptions = value.WorkDoneProgressOptions + self.Legend = value.Legend + + if value.Range != nil { + var value_ bool + if err = json.Unmarshal(value.Range, &value_); err == nil { + self.Range = value_ + } else { + var value_ struct{} + if err = json.Unmarshal(value.Range, &value_); err == nil { + self.Range = value_ + } else { + return err + } + } + } + + if value.Full != nil { + var value_ bool + if err = json.Unmarshal(value.Full, &value_); err == nil { + self.Full = value_ + } else { + var value_ SemanticDelta + if err = json.Unmarshal(value.Full, &value_); err == nil { + self.Full = value_ + } else { + return err + } + } + } + + return nil + } else { + return err + } +} + +type SemanticTokensRegistrationOptions struct { + TextDocumentRegistrationOptions + SemanticTokensOptions + StaticRegistrationOptions +} + +const MethodTextDocumentSemanticTokensFull = Method("textDocument/semanticTokens/full") + +type TextDocumentSemanticTokensFullFunc func(context *glsp.Context, params *SemanticTokensParams) (*SemanticTokens, error) + +type SemanticTokensParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +type SemanticTokens struct { + /** + * An optional result id. If provided and clients support delta updating + * the client will include the result id in the next semantic token request. + * A server can then instead of computing all semantic tokens again simply + * send a delta. + */ + ResultID *string `json:"resultId,omitempty"` + + /** + * The actual tokens. + */ + Data []UInteger `json:"data"` +} + +type SemanticTokensPartialResult struct { + Data []UInteger `json:"data"` +} + +const MethodTextDocumentSemanticTokensFullDelta = Method("textDocument/semanticTokens/full/delta") + +// Returns: SemanticTokens | SemanticTokensDelta | SemanticTokensDeltaPartialResult | nil +type TextDocumentSemanticTokensFullDeltaFunc func(context *glsp.Context, params *SemanticTokensDeltaParams) (any, error) + +type SemanticTokensDeltaParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The result id of a previous response. The result Id can either point to + * a full response or a delta response depending on what was received last. + */ + PreviousResultID string `json:"previousResultId"` +} + +type SemanticTokensDelta struct { + ResultId *string `json:"resultId,omitempty"` + + /** + * The semantic token edits to transform a previous result into a new + * result. + */ + Edits []SemanticTokensEdit `json:"edits"` +} + +type SemanticTokensEdit struct { + /** + * The start offset of the edit. + */ + Start UInteger `json:"start"` + + /** + * The count of elements to remove. + */ + DeleteCount UInteger `json:"deleteCount"` + + /** + * The elements to insert. + */ + Data []UInteger `json:"data,omitempty"` +} + +type SemanticTokensDeltaPartialResult struct { + Edits []SemanticTokensEdit `json:"edits"` +} + +const MethodTextDocumentSemanticTokensRange = Method("textDocument/semanticTokens/range") + +// Returns: SemanticTokens | SemanticTokensPartialResult | nil +type TextDocumentSemanticTokensRangeFunc func(context *glsp.Context, params *SemanticTokensRangeParams) (any, error) + +type SemanticTokensRangeParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The range the semantic tokens are requested for. + */ + Range Range `json:"range"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_linkedEditingRange + +type LinkedEditingRangeClientCapabilities 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"` +} + +type LinkedEditingRangeOptions struct { + WorkDoneProgressOptions +} + +type LinkedEditingRangeRegistrationOptions struct { + TextDocumentRegistrationOptions + LinkedEditingRangeOptions + StaticRegistrationOptions +} + +const MethodTextDocumentLinkedEditingRange = Method("textDocument/linkedEditingRange") + +type TextDocumentLinkedEditingRangeFunc func(context *glsp.Context, params *LinkedEditingRangeParams) (*LinkedEditingRanges, error) + +type LinkedEditingRangeParams struct { + TextDocumentPositionParams + WorkDoneProgressParams +} + +type LinkedEditingRanges struct { + /** + * A list of ranges that can be renamed together. The ranges must have + * identical length and contain identical text content. The ranges cannot overlap. + */ + Ranges []Range `json:"ranges"` + + /** + * An optional word pattern (regular expression) that describes valid contents for + * the given ranges. If no pattern is provided, the client configuration's word + * pattern will be used. + */ + WordPattern *string `json:"wordPattern,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#textDocument_moniker + +type MonikerClientCapabilities 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"` +} + +type MonikerOptions struct { + WorkDoneProgressOptions +} + +type MonikerRegistrationOptions struct { + TextDocumentRegistrationOptions + MonikerOptions +} + +const MethodTextDocumentMoniker = Method("textDocument/moniker") + +type TextDocumentMonikerFunc func(context *glsp.Context, params *MonikerParams) ([]Moniker, error) + +type MonikerParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +/** + * Moniker uniqueness level to define scope of the moniker. + */ +type UniquenessLevel string + +const ( + /** + * The moniker is only unique inside a document + */ + UniquenessLevelDocument = UniquenessLevel("document") + + /** + * The moniker is unique inside a project for which a dump got created + */ + UniquenessLevelProject = UniquenessLevel("project") + + /** + * The moniker is unique inside the group to which a project belongs + */ + UniquenessLevelGroup = UniquenessLevel("group") + + /** + * The moniker is unique inside the moniker scheme. + */ + UniquenessLevelScheme = UniquenessLevel("scheme") + + /** + * The moniker is globally unique + */ + UniquenessLevelGlobal = UniquenessLevel("global") +) + +/** + * The moniker kind. + */ +type MonikerKind string + +const ( + /** + * The moniker represent a symbol that is imported into a project + */ + MonikerKindImport = MonikerKind("import") + + /** + * The moniker represents a symbol that is exported from a project + */ + MonikerKindExport = MonikerKind("export") + + /** + * The moniker represents a symbol that is local to a project (e.g. a local + * variable of a function, a class not visible outside the project, ...) + */ + MonikerKindLocal = MonikerKind("local") +) + +/** + * Moniker definition to match LSIF 0.5 moniker definition. + */ +type Moniker struct { + /** + * The scheme of the moniker. For example tsc or .Net + */ + Scheme string `json:"scheme"` + + /** + * The identifier of the moniker. The value is opaque in LSIF however + * schema owners are allowed to define the structure if they want. + */ + Identifier string `json:"identifier"` + + /** + * The scope in which the moniker is unique + */ + Unique UniquenessLevel `json:"unique"` + + /** + * The moniker kind if known. + */ + Kind *MonikerKind `json:"kind,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_prepareTypeHierarchy + +/** + * @since 3.17.0 + */ +type TypeHierarchyClientCapabilities 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"` +} + +type TypeHierarchyOptions struct { + WorkDoneProgressOptions +} + +type TypeHierarchyRegistrationOptions struct { + TextDocumentRegistrationOptions + TypeHierarchyOptions + StaticRegistrationOptions +} + +const MethodTextDocumentPrepareTypeHierarchy = Method("textDocument/prepareTypeHierarchy") + +type TextDocumentPrepareTypeHierarchyFunc func(context *glsp.Context, params *TypeHierarchyPrepareParams) ([]TypeHierarchyItem, error) + +type TypeHierarchyPrepareParams struct { + TextDocumentPositionParams + WorkDoneProgressParams +} + +/** + * @since 3.17.0 + */ +type TypeHierarchyItem struct { + /** + * The name of this item. + */ + Name string `json:"name"` + + /** + * The kind of this item. + */ + Kind SymbolKind `json:"kind"` + + /** + * Tags for this item. + */ + Tags []SymbolTag `json:"tags,omitempty"` + + /** + * More detail for this item, e.g. the signature of a function. + */ + Detail *string `json:"detail,omitempty"` + + /** + * The resource identifier of this item. + */ + URI DocumentUri `json:"uri"` + + /** + * The range enclosing this symbol not including leading/trailing whitespace + * but everything else, e.g. comments and code. + */ + 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`](#TypeHierarchyItem.range). + */ + SelectionRange Range `json:"selectionRange"` + + /** + * A data entry field that is preserved between a type hierarchy prepare and + * supertypes or subtypes requests. It could also be used to identify the + * type hierarchy in the server, helping improve the performance on + * resolving supertypes and subtypes. + */ + Data any `json:"data,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#typeHierarchy_supertypes + +const MethodTypeHierarchySupertypes = Method("typeHierarchy/supertypes") + +type TypeHierarchySupertypesFunc func(context *glsp.Context, params *TypeHierarchySupertypesParams) ([]TypeHierarchyItem, error) + +type TypeHierarchySupertypesParams struct { + WorkDoneProgressParams + PartialResultParams + + Item TypeHierarchyItem `json:"item"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#typeHierarchy_subtypes + +const MethodTypeHierarchySubtypes = Method("typeHierarchy/subtypes") + +type TypeHierarchySubtypesFunc func(context *glsp.Context, params *TypeHierarchySubtypesParams) ([]TypeHierarchyItem, error) + +type TypeHierarchySubtypesParams struct { + WorkDoneProgressParams + PartialResultParams + + Item TypeHierarchyItem `json:"item"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_inlineValue + +/** + * Client capabilities specific to inline values. + * + * @since 3.17.0 + */ +type InlineValueClientCapabilities struct { + /** + * Whether implementation supports dynamic registration for inline value providers. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +/** + * Inline value options used during static registration. + * + * @since 3.17.0 + */ +type InlineValueOptions struct { + WorkDoneProgressOptions +} + +/** + * Inline value options used during static or dynamic registration. + * + * @since 3.17.0 + */ +type InlineValueRegistrationOptions struct { + InlineValueOptions + TextDocumentRegistrationOptions + StaticRegistrationOptions +} + +const MethodTextDocumentInlineValue = Method("textDocument/inlineValue") + +type TextDocumentInlineValueFunc func(context *glsp.Context, params *InlineValueParams) ([]InlineValue, error) + +/** + * A parameter literal used in inline value requests. + * + * @since 3.17.0 + */ +type InlineValueParams struct { + WorkDoneProgressParams + + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The document range for which inline values should be computed. + */ + Range Range `json:"range"` + + /** + * Additional information about the context in which inline values were + * requested. + */ + Context InlineValueContext `json:"context"` +} + +/** + * @since 3.17.0 + */ +type InlineValueContext struct { + /** + * The stack frame (as a DAP Id) where the execution has stopped. + */ + FrameId Integer `json:"frameId"` + + /** + * The document range where execution has stopped. + * Typically the end position of the range denotes the line where the inline values are shown. + */ + StoppedLocation Range `json:"stoppedLocation"` +} + +/** + * Inline value information can be provided by different means: + * - directly as a text value (class InlineValueText). + * - as a name to use for a variable lookup (class InlineValueVariableLookup) + * - as an evaluatable expression (class InlineValueEvaluatableExpression) + * The InlineValue types combines all inline value types into one type. + * + * @since 3.17.0 + */ +type InlineValue any // InlineValueText | InlineValueVariableLookup | InlineValueEvaluatableExpression + +/** + * Provide inline value as text. + * + * @since 3.17.0 + */ +type InlineValueText struct { + /** + * The document range for which the inline value applies. + */ + Range Range `json:"range"` + + /** + * The text of the inline value. + */ + Text string `json:"text"` +} + +/** + * Provide inline value through a variable lookup. + * If only a range is specified, the variable name will be extracted from the underlying document. + * An optional variable name can be used to override the extracted name. + * + * @since 3.17.0 + */ +type InlineValueVariableLookup struct { + /** + * The document range for which the inline value applies. + * The range is used to extract the variable name from the underlying document. + */ + Range Range `json:"range"` + + /** + * If specified the name of the variable to look up. + */ + VariableName *string `json:"variableName,omitempty"` + + /** + * How to perform the lookup. + */ + CaseSensitiveLookup bool `json:"caseSensitiveLookup"` +} + +/** + * Provide an inline value through an expression evaluation. + * If only a range is specified, the expression will be extracted from the underlying document. + * An optional expression can be used to override the extracted expression. + * + * @since 3.17.0 + */ +type InlineValueEvaluatableExpression struct { + /** + * The document range for which the inline value applies. + * The range is used to extract the evaluatable expression from the underlying document. + */ + Range Range `json:"range"` + + /** + * If specified the expression overrides the extracted expression. + */ + Expression *string `json:"expression,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_inlineValue_refresh + +const ServerWorkspaceInlineValueRefresh = Method("workspace/inlineValue/refresh") + +type InlineValueWorkspaceClientCapabilities struct { + /** + * Whether the client implementation supports a refresh request sent from the + * server to the client. + * + * Note that this event is global and will force the client to refresh all + * inline values currently shown. It should be used with absolute care and is + * useful for situation where a server for example detect a project wide + * change that requires such a calculation. + */ + RefreshSupport *bool `json:"refreshSupport,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_inlayHint + +/** + * Inlay hint client capabilities. + * + * @since 3.17.0 + */ +type InlayHintClientCapabilities struct { + /** + * Whether inlay hints support dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` + + /** + * Indicates which properties a client can resolve lazily on a inlay + * hint. + */ + ResolveSupport *struct { + /** + * The properties that a client can resolve lazily. + */ + Properties []string `json:"properties"` + } `json:"resolveSupport,omitempty"` +} + +/** + * Inlay hint options used during static registration. + * + * @since 3.17.0 + */ +type InlayHintOptions struct { + WorkDoneProgressOptions + + /** + * The server provides support to resolve additional + * information for an inlay hint item. + */ + ResolveProvider *bool `json:"resolveProvider,omitempty"` +} + +/** + * Inlay hint options used during static or dynamic registration. + * + * @since 3.17.0 + */ +type InlayHintRegistrationOptions struct { + InlayHintOptions + TextDocumentRegistrationOptions + StaticRegistrationOptions +} + +const MethodTextDocumentInlayHint = Method("textDocument/inlayHint") + +type TextDocumentInlayHintFunc func(context *glsp.Context, params *InlayHintParams) ([]InlayHint, error) + +/** + * A parameter literal used in inlay hint requests. + * + * @since 3.17.0 + */ +type InlayHintParams struct { + WorkDoneProgressParams + + /** + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /** + * The visible document range for which inlay hints should be computed. + */ + Range Range `json:"range"` +} + +/** + * Inlay hint information. + * + * @since 3.17.0 + */ +type InlayHint struct { + /** + * The position of this hint. + */ + Position Position `json:"position"` + + /** + * The label of this hint. A human readable string or an array of + * InlayHintLabelPart label parts. + * + * *Note* that neither the string nor the label part can be empty. + */ + Label any `json:"label"` // string | InlayHintLabelPart[] + + /** + * The kind of this hint. Can be omitted in which case the client + * should fall back to a reasonable default. + */ + Kind *InlayHintKind `json:"kind,omitempty"` + + /** + * Optional text edits that are performed when accepting this inlay hint. + * + * *Note* that edits are expected to change the document so that the inlay + * hint (or its nearest variant) is now part of the document and the inlay + * hint itself is now obsolete. + */ + TextEdits []TextEdit `json:"textEdits,omitempty"` + + /** + * The tooltip text when you hover over this item. + */ + Tooltip any `json:"tooltip,omitempty"` // string | MarkupContent + + /** + * Render padding before the hint. + * + * Note: Padding should use the editor's background color, not the + * background color of the hint itself. That means padding can be used + * to visually align/separate an inlay hint. + */ + PaddingLeft *bool `json:"paddingLeft,omitempty"` + + /** + * Render padding after the hint. + * + * Note: Padding should use the editor's background color, not the + * background color of the hint itself. That means padding can be used + * to visually align/separate an inlay hint. + */ + PaddingRight *bool `json:"paddingRight,omitempty"` + + /** + * A data entry field that is preserved on a inlay hint between + * a `textDocument/inlayHint` and a `inlayHint/resolve` request. + */ + Data any `json:"data,omitempty"` +} + +/** + * An inlay hint label part allows for interactive and composite labels + * of inlay hints. + * + * @since 3.17.0 + */ +type InlayHintLabelPart struct { + /** + * The value of this label part. + */ + Value string `json:"value"` + + /** + * The tooltip text when you hover over this label part. Depending on + * the client capability `inlayHint.resolveSupport` clients might resolve + * this property late using the resolve request. + */ + Tooltip any `json:"tooltip,omitempty"` // string | MarkupContent + + /** + * An optional source code location that represents this + * label part. + * + * The editor will use this location for the hover and for code navigation + * features: This part will become a clickable link that resolves to the + * definition of the symbol at the given location (not necessarily the + * location itself), it shows the hover that shows at the given location, + * and it shows a context menu with further code navigation commands. + * + * Depending on the client capability `inlayHint.resolveSupport` clients + * might resolve this property late using the resolve request. + */ + Location *Location `json:"location,omitempty"` + + /** + * An optional command for this label part. + * + * Depending on the client capability `inlayHint.resolveSupport` clients + * might resolve this property late using the resolve request. + */ + Command *Command `json:"command,omitempty"` +} + +/** + * Inlay hint kinds. + * + * @since 3.17.0 + */ +type InlayHintKind Integer + +const ( + /** + * An inlay hint that for a type annotation. + */ + InlayHintKindType = InlayHintKind(1) + + /** + * An inlay hint that is for a parameter. + */ + InlayHintKindParameter = InlayHintKind(2) +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHint_resolve + +const MethodInlayHintResolve = Method("inlayHint/resolve") + +type InlayHintResolveFunc func(context *glsp.Context, params *InlayHint) (*InlayHint, error) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_inlayHint_refresh + +const ServerWorkspaceInlayHintRefresh = Method("workspace/inlayHint/refresh") + +type InlayHintWorkspaceClientCapabilities struct { + /** + * Whether the client implementation supports a refresh request sent from + * the server to the client. + * + * Note that this event is global and will force the client to refresh all + * inlay hints currently shown. It should be used with absolute care and + * is useful for situation where a server for example detects a project wide + * change that requires such a calculation. + */ + RefreshSupport *bool `json:"refreshSupport,omitempty"` +} diff --git a/protocol_3_17/notebook-document.go b/protocol_3_17/notebook-document.go new file mode 100644 index 0000000..ca1b910 --- /dev/null +++ b/protocol_3_17/notebook-document.go @@ -0,0 +1,423 @@ +package protocol + +import "github.com/tliron/glsp" + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notebookDocument_synchronization + +/** + * A notebook document. + * + * @since 3.17.0 + */ +type NotebookDocument struct { + /** + * The notebook document's URI. + */ + URI DocumentUri `json:"uri"` + + /** + * The type of the notebook. + */ + NotebookType string `json:"notebookType"` + + /** + * The version number of this document (it will increase after each + * change, including undo/redo). + */ + Version Integer `json:"version"` + + /** + * Additional metadata stored with the notebook + * document. + */ + Metadata *any `json:"metadata,omitempty"` + + /** + * The cells of a notebook. + */ + Cells []NotebookCell `json:"cells"` +} + +/** + * A notebook cell. + * + * A cell's document URI must be unique across ALL notebook cells and can therefore + * be used to uniquely identify a notebook cell or the cell's text document. + * + * @since 3.17.0 + */ +type NotebookCell struct { + /** + * The cell's kind + */ + Kind NotebookCellKind `json:"kind"` + + /** + * The URI of the cell's text document + * content. + */ + Document DocumentUri `json:"document"` + + /** + * Additional metadata stored with the cell. + */ + Metadata *any `json:"metadata,omitempty"` + + /** + * Additional execution summary information + * if supported by the client. + */ + ExecutionSummary *ExecutionSummary `json:"executionSummary,omitempty"` +} + +/** + * A notebook cell kind. + * + * @since 3.17.0 + */ +type NotebookCellKind Integer + +const ( + /** + * A markup-cell is formatted source that is used for display. + */ + NotebookCellKindMarkup = NotebookCellKind(1) + + /** + * A code-cell is source code. + */ + NotebookCellKindCode = NotebookCellKind(2) +) + +type ExecutionSummary struct { + /** + * The execution order number. + */ + ExecutionOrder UInteger `json:"executionOrder"` + + /** + * Whether the execution was successful or + * not if known by the client. + */ + Success *bool `json:"success,omitempty"` +} + +/** + * A versioned notebook document identifier. + * + * @since 3.17.0 + */ +type VersionedNotebookDocumentIdentifier struct { + /** + * The version number of this notebook document. + */ + Version Integer `json:"version"` + + /** + * The notebook document's URI. + */ + URI DocumentUri `json:"uri"` +} + +/** + * A change describing how to move a `NotebookCell` + * array from state S to S'. + * + * @since 3.17.0 + */ +type NotebookCellArrayChange struct { + /** + * The start offset of the cell that changed. + */ + Start UInteger `json:"start"` + + /** + * The deleted cells + */ + DeleteCount UInteger `json:"deleteCount"` + + /** + * The new cells, if any + */ + Cells []NotebookCell `json:"cells,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notebookDocument_didOpen + +const MethodNotebookDocumentDidOpen = Method("notebookDocument/didOpen") + +type NotebookDocumentDidOpenFunc func(context *glsp.Context, params *DidOpenNotebookDocumentParams) error + +/** + * The params sent in a open notebook document notification. + * + * @since 3.17.0 + */ +type DidOpenNotebookDocumentParams struct { + /** + * The notebook document that got opened. + */ + NotebookDocument NotebookDocument `json:"notebookDocument"` + + /** + * The text documents that represent the content + * of a notebook cell. + */ + CellTextDocuments []TextDocumentItem `json:"cellTextDocuments"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notebookDocument_didChange + +const MethodNotebookDocumentDidChange = Method("notebookDocument/didChange") + +type NotebookDocumentDidChangeFunc func(context *glsp.Context, params *DidChangeNotebookDocumentParams) error + +/** + * The params sent in a change notebook document notification. + * + * @since 3.17.0 + */ +type DidChangeNotebookDocumentParams struct { + /** + * The notebook document that did change. The version number points + * to the version after all provided changes have been applied. + */ + NotebookDocument VersionedNotebookDocumentIdentifier `json:"notebookDocument"` + + /** + * The actual changes to the notebook document. + * + * The change describes single state change to the notebook document. + * So it moves a notebook document, its cells and its cell text document + * contents from state S to S'. + * + * To mirror the content of a notebook using change events use the + * following approach: + * - start with the same initial content + * - apply the 'notebookDocument/didChange' notifications in the order + * you receive them. + */ + Change NotebookDocumentChangeEvent `json:"change"` +} + +/** + * A change event for a notebook document. + * + * @since 3.17.0 + */ +type NotebookDocumentChangeEvent struct { + /** + * The changed meta data if any. + */ + Metadata *any `json:"metadata,omitempty"` + + /** + * Changes to cells + */ + Cells *struct { + /** + * Changes to the cell structure to add or + * remove cells. + */ + Structure *struct { + /** + * The change to the cell array. + */ + Array NotebookCellArrayChange `json:"array"` + + /** + * Additional opened cell text documents. + */ + DidOpen []TextDocumentItem `json:"didOpen,omitempty"` + + /** + * Additional closed cell text documents. + */ + DidClose []TextDocumentIdentifier `json:"didClose,omitempty"` + } `json:"structure,omitempty"` + + /** + * Changes to notebook cells properties like its + * kind, execution summary or metadata. + */ + Data []NotebookCell `json:"data,omitempty"` + + /** + * Changes to the text content of notebook cells. + */ + TextContent []struct { + Document VersionedTextDocumentIdentifier `json:"document"` + Changes []TextDocumentContentChangeEvent `json:"changes"` + } `json:"textContent,omitempty"` + } `json:"cells,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notebookDocument_didSave + +const MethodNotebookDocumentDidSave = Method("notebookDocument/didSave") + +type NotebookDocumentDidSaveFunc func(context *glsp.Context, params *DidSaveNotebookDocumentParams) error + +/** + * The params sent in a save notebook document notification. + * + * @since 3.17.0 + */ +type DidSaveNotebookDocumentParams struct { + /** + * The notebook document that got saved. + */ + NotebookDocument NotebookDocumentIdentifier `json:"notebookDocument"` +} + +/** + * A literal to identify a notebook document in the client. + * + * @since 3.17.0 + */ +type NotebookDocumentIdentifier struct { + /** + * The notebook document's URI. + */ + URI DocumentUri `json:"uri"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notebookDocument_didClose + +const MethodNotebookDocumentDidClose = Method("notebookDocument/didClose") + +type NotebookDocumentDidCloseFunc func(context *glsp.Context, params *DidCloseNotebookDocumentParams) error + +/** + * The params sent in a close notebook document notification. + * + * @since 3.17.0 + */ +type DidCloseNotebookDocumentParams struct { + /** + * The notebook document that got closed. + */ + NotebookDocument NotebookDocumentIdentifier `json:"notebookDocument"` + + /** + * The text documents that represent the content + * of a notebook cell that got closed. + */ + CellTextDocuments []TextDocumentIdentifier `json:"cellTextDocuments"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#notebookDocument_synchronization + +/** + * Notebook specific client capabilities. + * + * @since 3.17.0 + */ +type NotebookDocumentClientCapabilities struct { + /** + * Capabilities specific to notebook document synchronization + * + * @since 3.17.0 + */ + Synchronization NotebookDocumentSyncClientCapabilities `json:"synchronization"` +} + +/** + * Notebook specific synchronization client capabilities. + * + * @since 3.17.0 + */ +type NotebookDocumentSyncClientCapabilities 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"` + + /** + * The client supports sending execution summary data per cell. + */ + ExecutionSummarySupport *bool `json:"executionSummarySupport,omitempty"` +} + +/** + * Options specific to a notebook plus its associated text documents. + * + * @since 3.17.0 + */ +type NotebookDocumentSyncOptions struct { + /** + * The notebooks to be synced + */ + NotebookSelector []NotebookSelector `json:"notebookSelector"` + + /** + * Whether save notification should be forwarded to + * the server. Will only be honored if mode === `notebook`. + */ + Save *bool `json:"save,omitempty"` +} + +/** + * Registration options specific to a notebook. + * + * @since 3.17.0 + */ +type NotebookDocumentSyncRegistrationOptions struct { + NotebookDocumentSyncOptions + StaticRegistrationOptions +} + +/** + * A notebook selector is the combination of one or two filters: + * - `notebook`: a filter that applies to notebook documents + * - `cells`: a filter that applies to the cells of matching notebook documents. + * + * @since 3.17.0 + */ +type NotebookSelector struct { + /** + * The notebook to be synced If a string + * value is provided it matches against the + * notebook type. '*' matches every notebook. + */ + Notebook any `json:"notebook,omitempty"` // string | NotebookDocumentFilter + + /** + * The cells of the matching notebook to be synced. + */ + Cells []NotebookCellSelector `json:"cells,omitempty"` +} + +/** + * A notebook document filter represents a filter on notebook documents. + * + * @since 3.17.0 + */ +type NotebookDocumentFilter struct { + /** + * The type of the enclosing notebook. + */ + NotebookType *string `json:"notebookType,omitempty"` + + /** + * A Uri [scheme](#Uri.scheme), like `file` or `untitled`. + */ + Scheme *string `json:"scheme,omitempty"` + + /** + * A glob pattern. + */ + Pattern *string `json:"pattern,omitempty"` +} + +/** + * A notebook cell selector. + * + * @since 3.17.0 + */ +type NotebookCellSelector struct { + Language string `json:"language"` +} diff --git a/protocol_3_17/protocol_test.go b/protocol_3_17/protocol_test.go new file mode 100644 index 0000000..a33b15b --- /dev/null +++ b/protocol_3_17/protocol_test.go @@ -0,0 +1,124 @@ +package protocol + +import ( + "testing" + + "github.com/tliron/glsp" +) + +func TestHandler317Features(t *testing.T) { + // Compile-time check that 3.17 constants exist + _ = PositionEncodingKindUTF8 + _ = PositionEncodingKindUTF16 + _ = PositionEncodingKindUTF32 + _ = MethodTextDocumentPrepareTypeHierarchy + _ = MethodTypeHierarchySupertypes + _ = MethodTypeHierarchySubtypes + _ = MethodTextDocumentInlineValue + _ = MethodTextDocumentInlayHint + _ = MethodInlayHintResolve + _ = MethodTextDocumentDiagnostic + _ = MethodWorkspaceDiagnostic + _ = MethodWorkspaceDiagnosticRefresh + + // Capabilities without handlers should have nil providers + handler := &Handler{} + capabilities := handler.CreateServerCapabilities() + if capabilities.TypeHierarchyProvider != nil { + t.Error("TypeHierarchyProvider should be nil without handler") + } + if capabilities.InlineValueProvider != nil { + t.Error("InlineValueProvider should be nil without handler") + } + if capabilities.InlayHintProvider != nil { + t.Error("InlayHintProvider should be nil without handler") + } + if capabilities.DiagnosticProvider != nil { + t.Error("DiagnosticProvider should be nil without handler") + } + + // Capabilities with handlers should set providers + handler.TextDocumentPrepareTypeHierarchy = func(_ *glsp.Context, _ *TypeHierarchyPrepareParams) ([]TypeHierarchyItem, error) { + return nil, nil + } + handler.TextDocumentDiagnostic = func(_ *glsp.Context, _ *DocumentDiagnosticParams) (any, error) { + return nil, nil + } + handler.WorkspaceDiagnostic = func(_ *glsp.Context, _ *WorkspaceDiagnosticParams) (*WorkspaceDiagnosticReport, error) { + return nil, nil + } + capabilities = handler.CreateServerCapabilities() + + if capabilities.TypeHierarchyProvider == nil { + t.Error("TypeHierarchyProvider should be set when handler is registered") + } + if capabilities.DiagnosticProvider == nil { + t.Fatal("DiagnosticProvider should be set when handler is registered") + } + diagOpts, ok := capabilities.DiagnosticProvider.(DiagnosticOptions) + if !ok { + t.Fatal("DiagnosticProvider should be DiagnosticOptions") + } + if !diagOpts.WorkspaceDiagnostics { + t.Error("WorkspaceDiagnostics should be true when WorkspaceDiagnostic handler is set") + } +} + +func TestPositionEncoding(t *testing.T) { + // Test position encoding kinds + utf8 := PositionEncodingKindUTF8 + utf16 := PositionEncodingKindUTF16 + utf32 := PositionEncodingKindUTF32 + + if utf8 != "utf-8" { + t.Errorf("Expected utf-8, got %s", utf8) + } + if utf16 != "utf-16" { + t.Errorf("Expected utf-16, got %s", utf16) + } + if utf32 != "utf-32" { + t.Errorf("Expected utf-32, got %s", utf32) + } +} + +func TestTypeHierarchyItem(t *testing.T) { + // Test that we can create a TypeHierarchyItem + item := TypeHierarchyItem{ + Name: "TestClass", + Kind: 1, // Assuming this corresponds to a class + URI: "file:///test.go", + Range: Range{Start: Position{Line: 0, Character: 0}, End: Position{Line: 10, Character: 0}}, + SelectionRange: Range{Start: Position{Line: 0, Character: 0}, End: Position{Line: 0, Character: 9}}, + } + + if item.Name != "TestClass" { + t.Errorf("Expected TestClass, got %s", item.Name) + } +} + +func TestInlayHint(t *testing.T) { + // Test that we can create an InlayHint + hint := InlayHint{ + Position: Position{Line: 5, Character: 10}, + Label: "i32", + Kind: &[]InlayHintKind{InlayHintKindType}[0], + } + + if hint.Position.Line != 5 { + t.Errorf("Expected line 5, got %d", hint.Position.Line) + } +} + +func TestHandlerInitialization(t *testing.T) { + handler := &Handler{} + + // Test handler initialization state + if handler.IsInitialized() { + t.Error("Handler should not be initialized by default") + } + + handler.SetInitialized(true) + if !handler.IsInitialized() { + t.Error("Handler should be initialized after SetInitialized(true)") + } +} diff --git a/protocol_3_17/telemetry.go b/protocol_3_17/telemetry.go new file mode 100644 index 0000000..fd866e8 --- /dev/null +++ b/protocol_3_17/telemetry.go @@ -0,0 +1,5 @@ +package protocol + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#telemetry_event + +const ServerTelemetryEvent = Method("telemetry/event") diff --git a/protocol_3_17/text-document-synchronization.go b/protocol_3_17/text-document-synchronization.go new file mode 100644 index 0000000..68a9b60 --- /dev/null +++ b/protocol_3_17/text-document-synchronization.go @@ -0,0 +1,351 @@ +package protocol + +import ( + "encoding/json" + + "github.com/tliron/glsp" +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_synchronization + +type TextDocumentSyncKind Integer + +/** + * Defines how the host (editor) should sync document changes to the language + * server. + */ +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. + * After that only incremental updates to the document are + * send. + */ + TextDocumentSyncKindIncremental = TextDocumentSyncKind(2) +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_didOpen + +const MethodTextDocumentDidOpen = Method("textDocument/didOpen") + +type TextDocumentDidOpenFunc func(context *glsp.Context, params *DidOpenTextDocumentParams) error + +type DidOpenTextDocumentParams struct { + /** + * The document that was opened. + */ + TextDocument TextDocumentItem `json:"textDocument"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_didChange + +/** + * 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 TextDocumentSyncKind `json:"syncKind"` +} + +const MethodTextDocumentDidChange = Method("textDocument/didChange") + +type TextDocumentDidChangeFunc func(context *glsp.Context, params *DidChangeTextDocumentParams) error + +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 []any `json:"contentChanges"` // TextDocumentContentChangeEvent or TextDocumentContentChangeEventWhole +} + +// ([json.Unmarshaler] interface) +func (self *DidChangeTextDocumentParams) UnmarshalJSON(data []byte) error { + var value struct { + TextDocument VersionedTextDocumentIdentifier `json:"textDocument"` + ContentChanges []json.RawMessage `json:"contentChanges"` // TextDocumentContentChangeEvent or TextDocumentContentChangeEventWhole + } + + if err := json.Unmarshal(data, &value); err == nil { + self.TextDocument = value.TextDocument + + for _, contentChange := range value.ContentChanges { + var changeEvent TextDocumentContentChangeEvent + if err = json.Unmarshal(contentChange, &changeEvent); err == nil { + if changeEvent.Range != nil { + self.ContentChanges = append(self.ContentChanges, changeEvent) + } else { + changeEventWhole := TextDocumentContentChangeEventWhole{ + Text: changeEvent.Text, + } + self.ContentChanges = append(self.ContentChanges, changeEventWhole) + } + } else { + return err + } + } + + return nil + } else { + return err + } +} + +/** + * 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"` + + /** + * The optional length of the range that got replaced. + * + * @deprecated use range instead. + */ + RangeLength *UInteger `json:"rangeLength,omitempty"` + + /** + * The new text for the provided range. + */ + Text string `json:"text"` +} + +type TextDocumentContentChangeEventWhole struct { + /** + * The new text of the whole document. + */ + Text string `json:"text"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_willSave + +const MethodTextDocumentWillSave = Method("textDocument/willSave") + +type TextDocumentWillSaveFunc func(context *glsp.Context, params *WillSaveTextDocumentParams) error + +/** + * 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"` +} + +type TextDocumentSaveReason Integer + +/** + * Represents reasons why a text document is saved. + */ +const ( + /** + * Manually triggered, e.g. by the user pressing save, by starting + * debugging, or by an API call. + */ + TextDocumentSaveReasonManual = TextDocumentSaveReason(1) + + /** + * Automatic after a delay. + */ + TextDocumentSaveReasonAfterDelay = TextDocumentSaveReason(2) + + /** + * When the editor lost focus. + */ + TextDocumentSaveReasonFocusOut = TextDocumentSaveReason(3) +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_willSaveWaitUntil + +const MethodTextDocumentWillSaveWaitUntil = Method("textDocument/willSaveWaitUntil") + +type TextDocumentWillSaveWaitUntilFunc func(context *glsp.Context, params *WillSaveTextDocumentParams) ([]TextEdit, error) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_didSave + +type SaveOptions struct { + /** + * The client is supposed to include the content on save. + */ + IncludeText *bool `json:"includeText,omitempty"` +} + +type TextDocumentSaveRegistrationOptions struct { + TextDocumentRegistrationOptions + + /** + * The client is supposed to include the content on save. + */ + IncludeText *bool `json:"includeText"` +} + +const MethodTextDocumentDidSave = Method("textDocument/didSave") + +type TextDocumentDidSaveFunc func(context *glsp.Context, params *DidSaveTextDocumentParams) error + +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"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_didClose + +type TextDocumentSyncClientCapabilities 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"` +} + +type TextDocumentSyncOptions struct { + /** + * Open and close notifications are sent to the server. If omitted open + * close notification should not be sent. + */ + 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 *TextDocumentSyncKind `json:"change,omitempty"` + + /** + * If present will save notifications are sent to the server. If omitted + * the notification should not be sent. + */ + WillSave *bool `json:"willSave,omitempty"` + + /** + * If present will save wait until requests are sent to the server. If + * omitted the request should not be sent. + */ + WillSaveWaitUntil *bool `json:"willSaveWaitUntil,omitempty"` + + /** + * If present save notifications are sent to the server. If omitted the + * notification should not be sent. + */ + Save any `json:"save,omitempty"` // nil | bool | SaveOptions +} + +// ([json.Unmarshaler] interface) +func (self *TextDocumentSyncOptions) UnmarshalJSON(data []byte) error { + var value struct { + OpenClose *bool `json:"openClose"` + Change *TextDocumentSyncKind `json:"change"` + WillSave *bool `json:"willSave"` + WillSaveWaitUntil *bool `json:"willSaveWaitUntil"` + Save json.RawMessage `json:"save"` // nil | bool | SaveOptions + } + + if err := json.Unmarshal(data, &value); err == nil { + self.OpenClose = value.OpenClose + self.Change = value.Change + self.WillSave = value.WillSave + self.WillSaveWaitUntil = value.WillSaveWaitUntil + + if value.Save != nil { + if string(value.Save) == "null" { + self.Save = nil + } else { + var value_ bool + if err = json.Unmarshal(value.Save, &value_); err == nil { + self.Save = value_ + } else { + var value_ SaveOptions + if err = json.Unmarshal(value.Save, &value_); err == nil { + self.Save = value_ + } else { + return err + } + } + } + } + + return nil + } else { + return err + } +} + +const MethodTextDocumentDidClose = Method("textDocument/didClose") + +type TextDocumentDidCloseFunc func(context *glsp.Context, params *DidCloseTextDocumentParams) error + +type DidCloseTextDocumentParams struct { + /** + * The document that was closed. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} diff --git a/protocol_3_17/trace.go b/protocol_3_17/trace.go new file mode 100644 index 0000000..f292234 --- /dev/null +++ b/protocol_3_17/trace.go @@ -0,0 +1,69 @@ +package protocol + +import ( + "fmt" + "sync" + + "github.com/tliron/glsp" +) + +var traceValue TraceValue = TraceValueOff +var traceValueLock sync.Mutex + +func GetTraceValue() TraceValue { + traceValueLock.Lock() + defer traceValueLock.Unlock() + return traceValue +} + +func SetTraceValue(value TraceValue) { + traceValueLock.Lock() + defer traceValueLock.Unlock() + + // The spec clearly says "message", but some implementations use "messages" instead + if value == "messages" { + value = TraceValueMessage + } + + traceValue = value +} + +func HasTraceLevel(value TraceValue) bool { + value_ := GetTraceValue() + switch value_ { + case TraceValueOff: + return false + + case TraceValueMessage: + return value == TraceValueMessage + + case TraceValueVerbose: + return true + + default: + panic(fmt.Sprintf("unsupported trace level: %s", value_)) + } +} + +func HasTraceMessageType(type_ MessageType) bool { + switch type_ { + case MessageTypeError, MessageTypeWarning, MessageTypeInfo: + return HasTraceLevel(TraceValueMessage) + + case MessageTypeLog: + return HasTraceLevel(TraceValueVerbose) + + default: + panic(fmt.Sprintf("unsupported message type: %d", type_)) + } +} + +func Trace(context *glsp.Context, type_ MessageType, message string) error { + if HasTraceMessageType(type_) { + go context.Notify(ServerWindowLogMessage, &LogMessageParams{ + Type: type_, + Message: message, + }) + } + return nil +} diff --git a/protocol_3_17/window.go b/protocol_3_17/window.go new file mode 100644 index 0000000..6e42713 --- /dev/null +++ b/protocol_3_17/window.go @@ -0,0 +1,189 @@ +package protocol + +import "github.com/tliron/glsp" + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_showMessage + +const ServerWindowShowMessage = Method("window/showMessage") + +type ShowMessageParams struct { + /** + * The message type. See {@link MessageType}. + */ + Type MessageType `json:"type"` + + /** + * The actual message. + */ + Message string `json:"message"` +} + +type MessageType Integer + +const ( + /** + * An error message. + */ + MessageTypeError = MessageType(1) + + /** + * A warning message. + */ + MessageTypeWarning = MessageType(2) + + /** + * An information message. + */ + MessageTypeInfo = MessageType(3) + + /** + * A log message. + */ + MessageTypeLog = MessageType(4) +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_showMessageRequest + +type ShowMessageRequestClientCapabilities struct { + /** + * Capabilities specific to the `MessageActionItem` type. + */ + MessageActionItem *struct { + /** + * Whether the client supports additional attributes which + * are preserved and sent back to the server in the + * request's response. + */ + AdditionalPropertiesSupport *bool `json:"additionalPropertiesSupport,omitempty"` + } `json:"messageActionItem,omitempty"` +} + +const ServerWindowShowMessageRequest = Method("window/showMessageRequest") + +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 `json:"title"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_showDocument + +/** + * Client capabilities for the show document request. + * + * @since 3.16.0 + */ +type ShowDocumentClientCapabilities struct { + /** + * The client has support for the show document + * request. + */ + Support bool `json:"support"` +} + +const ServerWindowShowDocument = Method("window/showDocument") + +/** + * Params to show a document. + * + * @since 3.16.0 + */ +type ShowDocumentParams struct { + /** + * The document uri to show. + */ + URI URI `json:"uri"` + + /** + * Indicates to show the resource in an external program. + * To show for example `https://code.visualstudio.com/` + * in the default WEB browser set `external` to `true`. + */ + External *bool `json:"external,omitempty"` + + /** + * An optional property to indicate whether the editor + * showing the document should take focus or not. + * Clients might ignore this property if an external + * program is started. + */ + TakeFocus *bool `json:"takeFocus,omitempty"` + + /** + * An optional selection range if the document is a text + * document. Clients might ignore the property if an + * external program is started or the file is not a text + * file. + */ + Selection *Range `json:"selection,omitempty"` +} + +/** + * The result of an show document request. + * + * @since 3.16.0 + */ +type ShowDocumentResult struct { + /** + * A boolean indicating if the show was successful. + */ + Success bool `json:"success"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_logMessage + +const ServerWindowLogMessage = Method("window/logMessage") + +type LogMessageParams struct { + /** + * The message type. See {@link MessageType} + */ + Type MessageType `json:"type"` + + /** + * The actual message + */ + Message string `json:"message"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_workDoneProgress_create + +const ServerWindowWorkDoneProgressCreate = Method("window/workDoneProgress/create") + +type WorkDoneProgressCreateParams struct { + /** + * The token to be used to report progress. + */ + Token ProgressToken `json:"token"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#window_workDoneProgress_cancel + +const MethodWindowWorkDoneProgressCancel = Method("window/workDoneProgress/cancel") + +type WindowWorkDoneProgressCancelFunc func(context *glsp.Context, params *WorkDoneProgressCancelParams) error + +type WorkDoneProgressCancelParams struct { + /** + * The token to be used to report progress. + */ + Token ProgressToken `json:"token"` +} diff --git a/protocol_3_17/workspace.go b/protocol_3_17/workspace.go new file mode 100644 index 0000000..80cad4e --- /dev/null +++ b/protocol_3_17/workspace.go @@ -0,0 +1,594 @@ +package protocol + +import "github.com/tliron/glsp" + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_workspaceFolders + +const ServerWorkspaceWorkspaceFolders = Method("workspace/workspaceFolders") + +type WorkspaceFoldersServerCapabilities struct { + /** + * The server has support for workspace folders + */ + Supported *bool `json:"supported"` + + /** + * Whether the server wants to receive workspace folder + * change notifications. + * + * If a string is provided, the string is treated as an 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 *BoolOrString `json:"changeNotifications,omitempty"` +} + +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"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_didChangeWorkspaceFolders + +const MethodWorkspaceDidChangeWorkspaceFolders = Method("workspace/didChangeWorkspaceFolders") + +type WorkspaceDidChangeWorkspaceFoldersFunc func(context *glsp.Context, params *DidChangeWorkspaceFoldersParams) error + +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"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_didChangeConfiguration + +type DidChangeConfigurationClientCapabilities struct { + /** + * Did change configuration notification supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +const MethodWorkspaceDidChangeConfiguration = Method("workspace/didChangeConfiguration") + +type WorkspaceDidChangeConfigurationFunc func(context *glsp.Context, params *DidChangeConfigurationParams) error + +type DidChangeConfigurationParams struct { + /** + * The actual changed settings + */ + Settings any `json:"settings"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_configuration + +const ServerWorkspaceConfiguration = Method("workspace/configuration") + +type ConfigurationParams struct { + Items []ConfigurationItem `json:"items"` +} + +type ConfigurationItem struct { + /** + * The scope to get the configuration section for. + */ + ScopeURI *DocumentUri `json:"scopeUri,omitempty"` + + /** + * The configuration section asked for. + */ + Section *string `json:"section,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_didChangeWatchedFiles + +type DidChangeWatchedFilesClientCapabilities struct { + /** + * Did change watched files notification supports dynamic registration. + * Please note that the current protocol doesn't support static + * configuration for file changes from the server side. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +/** + * Describe options to be used when registering for file system change events. + */ +type DidChangeWatchedFilesRegistrationOptions struct { + /** + * The watchers to register. + */ + Watchers []FileSystemWatcher `json:"watchers"` +} + +type FileSystemWatcher struct { + /** + * The glob pattern to watch. + * + * Glob patterns can have the following syntax: + * - `*` to match one or more characters in a path segment + * - `?` to match on one character in a path segment + * - `**` to match any number of path segments, including none + * - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript + * and JavaScript files) + * - `[]` to declare a range of characters to match in a path segment + * (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + * - `[!...]` to negate a range of characters to match in a path segment + * (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not + * `example.0`) + */ + 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 *UInteger `json:"kind,omitempty"` +} + +const ( + /** + * Interested in create events. + */ + WatchKindCreate = UInteger(1) + + /** + * Interested in change events + */ + WatchKindChange = UInteger(2) + + /** + * Interested in delete events + */ + WatchKindDelete = UInteger(4) +) + +const MethodWorkspaceDidChangeWatchedFiles = Method("workspace/didChangeWatchedFiles") + +type WorkspaceDidChangeWatchedFilesFunc func(context *glsp.Context, params *DidChangeWatchedFilesParams) error + +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 UInteger `json:"type"` +} + +/** + * The file event type. + */ +const ( + /** + * The file got created. + */ + FileChangeTypeCreated = UInteger(1) + + /** + * The file got changed. + */ + FileChangeTypeChanged = UInteger(2) + + /** + * The file got deleted. + */ + FileChangeTypeDeleted = UInteger(3) +) + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_symbol + +type WorkspaceSymbolClientCapabilities 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"` + + /** + * The client supports tags on `SymbolInformation`. + * Clients supporting tags have to handle unknown tags gracefully. + * + * @since 3.16.0 + */ + TagSupport *struct { + /** + * The tags supported by the client. + */ + ValueSet []SymbolTag `json:"valueSet"` + } `json:"tagSupport,omitempty"` +} + +type WorkspaceSymbolOptions struct { + WorkDoneProgressOptions +} + +type WorkspaceSymbolRegistrationOptions struct { + WorkspaceSymbolOptions +} + +const MethodWorkspaceSymbol = Method("workspace/symbol") + +type WorkspaceSymbolFunc func(context *glsp.Context, params *WorkspaceSymbolParams) ([]SymbolInformation, error) + +type WorkspaceSymbolParams struct { + WorkDoneProgressParams + PartialResultParams + + /** + * A query string to filter symbols by. Clients may send an empty + * string here to request all symbols. + */ + Query string `json:"query"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_executeCommand + +type ExecuteCommandClientCapabilities struct { + /** + * Execute command supports dynamic registration. + */ + DynamicRegistration *bool `json:"dynamicRegistration,omitempty"` +} + +type ExecuteCommandOptions struct { + WorkDoneProgressOptions + + /** + * The commands to be executed on the server + */ + Commands []string `json:"commands"` +} + +/** + * Execute command registration options. + */ +type ExecuteCommandRegistrationOptions struct { + ExecuteCommandOptions +} + +const MethodWorkspaceExecuteCommand = Method("workspace/executeCommand") + +type WorkspaceExecuteCommandFunc func(context *glsp.Context, params *ExecuteCommandParams) (any, error) + +type ExecuteCommandParams struct { + WorkDoneProgressParams + + /** + * The identifier of the actual command handler. + */ + Command string `json:"command"` + + /** + * Arguments that the command should be invoked with. + */ + Arguments []any `json:"arguments,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_applyEdit + +const ServerWorkspaceApplyEdit = Method("workspace/applyEdit") + +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"` + + /** + * An optional textual description for why the edit was not applied. + * This may be used by the server for diagnostic logging or to provide + * a suitable error for a request that triggered the edit. + */ + FailureReason *string `json:"failureReason,omitempty"` + + /** + * Depending on the client's failure handling strategy `failedChange` + * might contain the index of the change that failed. This property is + * only available if the client signals a `failureHandlingStrategy` + * in its client capabilities. + */ + FailedChange *UInteger `json:"failedChange,omitempty"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_willCreateFiles + +/** + * The options to register for file operations. + * + * @since 3.16.0 + */ +type FileOperationRegistrationOptions struct { + /** + * The actual filters. + */ + Filters []FileOperationFilter `json:"filters"` +} + +type FileOperationPatternKind string + +/** + * A pattern kind describing if a glob pattern matches a file a folder or + * both. + * + * @since 3.16.0 + */ +const ( + /** + * The pattern matches a file only. + */ + FileOperationPatternKindFile = FileOperationPatternKind("file") + + /** + * The pattern matches a folder only. + */ + FileOperationPatternKindFolder = FileOperationPatternKind("folder") +) + +/** + * Matching options for the file operation pattern. + * + * @since 3.16.0 + */ +type FileOperationPatternOptions struct { + + /** + * The pattern should be matched ignoring casing. + */ + IgnoreCase *bool `json:"ignoreCase,omitempty"` +} + +/** + * A pattern to describe in which file operation requests or notifications + * the server is interested in. + * + * @since 3.16.0 + */ +type FileOperationPattern struct { + /** + * The glob pattern to match. Glob patterns can have the following syntax: + * - `*` to match one or more characters in a path segment + * - `?` to match on one character in a path segment + * - `**` to match any number of path segments, including none + * - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript + * and JavaScript files) + * - `[]` to declare a range of characters to match in a path segment + * (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + * - `[!...]` to negate a range of characters to match in a path segment + * (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but + * not `example.0`) + */ + Glob string `json:"glob"` + + /** + * Whether to match files or folders with this pattern. + * + * Matches both if undefined. + */ + Matches *FileOperationPatternKind `json:"matches,omitempty"` + + /** + * Additional options used during matching. + */ + Options *FileOperationPatternOptions `json:"options,omitempty"` +} + +/** + * A filter to describe in which file operation requests or notifications + * the server is interested in. + * + * @since 3.16.0 + */ +type FileOperationFilter struct { + /** + * A Uri like `file` or `untitled`. + */ + Scheme *string `json:"scheme,omitempty"` + + /** + * The actual file operation pattern. + */ + Pattern FileOperationPattern `json:"pattern"` +} + +const MethodWorkspaceWillCreateFiles = Method("workspace/willCreateFiles") + +type WorkspaceWillCreateFilesFunc func(context *glsp.Context, params *CreateFilesParams) (*WorkspaceEdit, error) + +/** + * The parameters sent in notifications/requests for user-initiated creation + * of files. + * + * @since 3.16.0 + */ +type CreateFilesParams struct { + /** + * An array of all files/folders created in this operation. + */ + Files []FileCreate `json:"files"` +} + +/** + * Represents information on a file/folder create. + * + * @since 3.16.0 + */ +type FileCreate struct { + /** + * A file:// URI for the location of the file/folder being created. + */ + URI string `json:"uri"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_didCreateFiles + +const MethodWorkspaceDidCreateFiles = Method("workspace/didCreateFiles") + +type WorkspaceDidCreateFilesFunc func(context *glsp.Context, params *CreateFilesParams) error + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_willRenameFiles + +const MethodWorkspaceWillRenameFiles = Method("workspace/willRenameFiles") + +type WorkspaceWillRenameFilesFunc func(context *glsp.Context, params *RenameFilesParams) (*WorkspaceEdit, error) + +/** + * The parameters sent in notifications/requests for user-initiated renames + * of files. + * + * @since 3.16.0 + */ +type RenameFilesParams struct { + /** + * An array of all files/folders renamed in this operation. When a folder + * is renamed, only the folder will be included, and not its children. + */ + Files []FileRename `json:"files"` +} + +/** + * Represents information on a file/folder rename. + * + * @since 3.16.0 + */ +type FileRename struct { + /** + * A file:// URI for the original location of the file/folder being renamed. + */ + OldURI string `json:"oldUri"` + + /** + * A file:// URI for the new location of the file/folder being renamed. + */ + NewURI string `json:"newUri"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_didRenameFiles + +const MethodWorkspaceDidRenameFiles = Method("workspace/didRenameFiles") + +type WorkspaceDidRenameFilesFunc func(context *glsp.Context, params *RenameFilesParams) error + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_willDeleteFiles + +const MethodWorkspaceWillDeleteFiles = Method("workspace/willDeleteFiles") + +type WorkspaceWillDeleteFilesFunc func(context *glsp.Context, params *DeleteFilesParams) (*WorkspaceEdit, error) + +/** + * The parameters sent in notifications/requests for user-initiated deletes + * of files. + * + * @since 3.16.0 + */ +type DeleteFilesParams struct { + /** + * An array of all files/folders deleted in this operation. + */ + Files []FileDelete `json:"files"` +} + +/** + * Represents information on a file/folder delete. + * + * @since 3.16.0 + */ +type FileDelete struct { + /** + * A file:// URI for the location of the file/folder being deleted. + */ + URI string `json:"uri"` +} + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification#workspace_didDeleteFiles + +const MethodWorkspaceDidDeleteFiles = Method("workspace/didDeleteFiles") + +type WorkspaceDidDeleteFilesFunc func(context *glsp.Context, params *DeleteFilesParams) error + +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens +const MethodWorkspaceSemanticTokensRefresh = Method("workspace/semanticTokens/refresh") + +type WorkspaceSemanticTokensRefreshFunc func(context *glsp.Context) error + +type SemanticTokensWorkspaceClientCapabilities struct { + /** + * Whether the client implementation supports a refresh request sent from + * the server to the client. + * + * Note that this event is global and will force the client to refresh all + * semantic tokens currently shown. It should be used with absolute care + * and is useful for situation where a server for example detect a project + * wide change that requires such a calculation. + */ + RefreshSupport *bool `json:"refreshSupport,omitempty"` +}