Changed: DB Params

This commit is contained in:
2025-03-20 12:35:13 +01:00
parent 8640a12439
commit b71b3d12ca
822 changed files with 134218 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"encoding/json"
"fmt"
)
// CancelParams params of cancelRequest.
type CancelParams struct {
// ID is the request id to cancel.
ID any `json:"id"` // int32 | string
}
// ProgressParams params of Progress netification.
//
// @since 3.15.0.
type ProgressParams struct {
// Token is the progress token provided by the client or server.
Token ProgressToken `json:"token"`
// Value is the progress data.
Value any `json:"value"`
}
// ProgressToken is the progress token provided by the client or server.
//
// @since 3.15.0.
type ProgressToken struct {
name string
number int32
}
// compile time check whether the ProgressToken implements a fmt.Formatter, fmt.Stringer, json.Marshaler and json.Unmarshaler interfaces.
var (
_ fmt.Formatter = (*ProgressToken)(nil)
_ fmt.Stringer = (*ProgressToken)(nil)
_ json.Marshaler = (*ProgressToken)(nil)
_ json.Unmarshaler = (*ProgressToken)(nil)
)
// NewProgressToken returns a new ProgressToken.
func NewProgressToken(s string) *ProgressToken {
return &ProgressToken{name: s}
}
// NewNumberProgressToken returns a new number ProgressToken.
func NewNumberProgressToken(n int32) *ProgressToken {
return &ProgressToken{number: n}
}
// Format writes the ProgressToken to the formatter.
//
// If the rune is q the representation is non ambiguous,
// string forms are quoted.
func (v ProgressToken) Format(f fmt.State, r rune) {
const numF = `%d`
strF := `%s`
if r == 'q' {
strF = `%q`
}
switch {
case v.name != "":
fmt.Fprintf(f, strF, v.name)
default:
fmt.Fprintf(f, numF, v.number)
}
}
// String returns a string representation of the ProgressToken.
func (v ProgressToken) String() string {
return fmt.Sprint(v)
}
// MarshalJSON implements json.Marshaler.
func (v *ProgressToken) MarshalJSON() ([]byte, error) {
if v.name != "" {
return json.Marshal(v.name)
}
return json.Marshal(v.number)
}
// UnmarshalJSON implements json.Unmarshaler.
func (v *ProgressToken) UnmarshalJSON(data []byte) error {
*v = ProgressToken{}
if err := json.Unmarshal(data, &v.number); err == nil {
return nil
}
return json.Unmarshal(data, &v.name)
}

View File

@@ -0,0 +1,186 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"fmt"
"reflect"
"testing"
"encoding/json"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)
func TestCancelParams(t *testing.T) {
t.Parallel()
const want = `{"id":"testID"}`
wantType := CancelParams{
ID: "testID",
}
t.Run("Marshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field CancelParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field string
want CancelParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got CancelParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestProgressParams(t *testing.T) {
t.Parallel()
const wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb"
const want = `{"token":"` + wantWorkDoneToken + `","value":"testValue"}`
token := NewProgressToken(wantWorkDoneToken)
wantType := ProgressParams{
Token: *token,
Value: "testValue",
}
t.Run("Marshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field ProgressParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field string
want ProgressParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got ProgressParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got, cmpopts.IgnoreFields(ProgressParams{}, "Token")); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
if token := got.Token; !reflect.ValueOf(token).IsZero() {
if diff := cmp.Diff(fmt.Sprint(token), wantWorkDoneToken); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
}
})
}
})
}

705
templ/lsp/protocol/basic.go Normal file
View File

@@ -0,0 +1,705 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"github.com/a-h/templ/lsp/uri"
)
// DocumentURI represents the URI of a document.
//
// Many of the interfaces contain fields that correspond to the URI of a document.
// For clarity, the type of such a field is declared as a DocumentURI.
// Over the wire, it will still be transferred as a string, but this guarantees
// that the contents of that string can be parsed as a valid URI.
type DocumentURI = uri.URI
// URI a tagging interface for normal non document URIs.
//
// @since 3.16.0.
type URI = uri.URI
// EOL denotes represents the character offset.
var EOL = []string{"\n", "\r\n", "\r"}
// Position represents a text document expressed as zero-based line and zero-based character offset.
//
// The offsets are based on a UTF-16 string representation.
// So a string of the form "a𐐀b" the character offset of the character "a" is 0,
// the character offset of "𐐀" is 1 and the character offset of "b" is 3 since 𐐀 is represented using two code
// units in UTF-16.
//
// Positions are line end character agnostic. So you can not specify a position that
// denotes "\r|\n" or "\n|" where "|" represents the character offset.
//
// Position is between two characters like an "insert" cursor in a editor.
// Special values like for example "-1" to denote the end of a line are not supported.
type Position struct {
// Line position in a document (zero-based).
//
// If a line number is greater than the number of lines in a document, it defaults back to the number of lines in
// the document.
// If a line number is negative, it defaults to 0.
Line uint32 `json:"line"`
// Character offset on a line in a document (zero-based).
//
// Assuming that the line is represented as a string, the Character value represents the gap between the
// "character" and "character + 1".
//
// If the character value is greater than the line length it defaults back to the line length.
// If a line number is negative, it defaults to 0.
Character uint32 `json:"character"`
}
// Range represents a text document expressed as (zero-based) start and end positions.
//
// A range is comparable to a selection in an editor. Therefore the end position is exclusive.
// If you want to specify a range that contains a line including the line ending character(s) then use an end position
// denoting the start of the next line.
type Range struct {
// Start is the range's start position.
Start Position `json:"start"`
// End is the range's end position.
End Position `json:"end"`
}
// Location represents a location inside a resource, such as a line inside a text file.
type Location struct {
URI DocumentURI `json:"uri"`
Range Range `json:"range"`
}
// LocationLink represents a link between a source and a target location.
type LocationLink struct {
// OriginSelectionRange 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"`
// TargetURI is the target resource identifier of this link.
TargetURI DocumentURI `json:"targetUri"`
// TargetRange is 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"`
// TargetSelectionRange is 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"`
}
// Command represents a reference to a command. Provides a title which will be used to represent a command in the UI.
//
// Commands are identified by a string identifier.
// The recommended way to handle commands is to implement their execution on the server side if the client and
// server provides the corresponding capabilities.
//
// Alternatively the tool extension code could handle the command. The protocol currently doesn't specify
// a set of well-known commands.
type Command struct {
// Title of the command, like `save`.
Title string `json:"title"`
// Command is 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"`
}
// TextEdit is a textual edit applicable to a text document.
type TextEdit struct {
// Range is 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"`
// NewText is the string to be inserted. For delete operations use an
// empty string.
NewText string `json:"newText"`
}
// ChangeAnnotation is the additional information that describes document changes.
//
// @since 3.16.0.
type ChangeAnnotation struct {
// Label a human-readable string describing the actual change.
// The string is rendered prominent in the user interface.
Label string `json:"label"`
// NeedsConfirmation is a flag which indicates that user confirmation is needed
// before applying the change.
NeedsConfirmation bool `json:"needsConfirmation,omitempty"`
// Description is a human-readable string which is rendered less prominent in
// the user interface.
Description string `json:"description,omitempty"`
}
// ChangeAnnotationIdentifier an identifier referring to a change annotation managed by a workspace
// edit.
//
// @since 3.16.0.
type ChangeAnnotationIdentifier string
// AnnotatedTextEdit is a special text edit with an additional change annotation.
//
// @since 3.16.0.
type AnnotatedTextEdit struct {
TextEdit
// AnnotationID is the actual annotation identifier.
AnnotationID ChangeAnnotationIdentifier `json:"annotationId"`
}
// TextDocumentEdit describes textual changes on a single text document.
//
// The TextDocument is referred to as a OptionalVersionedTextDocumentIdentifier to allow clients to check the
// text document version before an edit is applied.
//
// TextDocumentEdit describes all changes on a version "Si" and after they are applied move the document to
// version "Si+1".
// So the creator of a TextDocumentEdit doesn't need to sort the array or do any kind of ordering. However the
// edits must be non overlapping.
type TextDocumentEdit struct {
// TextDocument is the text document to change.
TextDocument OptionalVersionedTextDocumentIdentifier `json:"textDocument"`
// Edits is the edits to be applied.
//
// @since 3.16.0 - support for AnnotatedTextEdit.
// This is guarded by the client capability Workspace.WorkspaceEdit.ChangeAnnotationSupport.
Edits []TextEdit `json:"edits"` // []TextEdit | []AnnotatedTextEdit
}
// ResourceOperationKind is the file event type.
type ResourceOperationKind string
const (
// CreateResourceOperation supports creating new files and folders.
CreateResourceOperation ResourceOperationKind = "create"
// RenameResourceOperation supports renaming existing files and folders.
RenameResourceOperation ResourceOperationKind = "rename"
// DeleteResourceOperation supports deleting existing files and folders.
DeleteResourceOperation ResourceOperationKind = "delete"
)
// CreateFileOptions represents an options to create a file.
type CreateFileOptions struct {
// Overwrite existing file. Overwrite wins over `ignoreIfExists`.
Overwrite bool `json:"overwrite,omitempty"`
// IgnoreIfExists ignore if exists.
IgnoreIfExists bool `json:"ignoreIfExists,omitempty"`
}
// CreateFile represents a create file operation.
type CreateFile struct {
// Kind a create.
Kind ResourceOperationKind `json:"kind"` // should be `create`
// URI is the resource to create.
URI DocumentURI `json:"uri"`
// Options additional options.
Options *CreateFileOptions `json:"options,omitempty"`
// AnnotationID an optional annotation identifier describing the operation.
//
// @since 3.16.0.
AnnotationID ChangeAnnotationIdentifier `json:"annotationId,omitempty"`
}
// RenameFileOptions represents a rename file options.
type RenameFileOptions struct {
// Overwrite target if existing. Overwrite wins over `ignoreIfExists`.
Overwrite bool `json:"overwrite,omitempty"`
// IgnoreIfExists ignores if target exists.
IgnoreIfExists bool `json:"ignoreIfExists,omitempty"`
}
// RenameFile represents a rename file operation.
type RenameFile struct {
// Kind a rename.
Kind ResourceOperationKind `json:"kind"` // should be `rename`
// OldURI is the old (existing) location.
OldURI DocumentURI `json:"oldUri"`
// NewURI is the new location.
NewURI DocumentURI `json:"newUri"`
// Options rename options.
Options *RenameFileOptions `json:"options,omitempty"`
// AnnotationID an optional annotation identifier describing the operation.
//
// @since 3.16.0.
AnnotationID ChangeAnnotationIdentifier `json:"annotationId,omitempty"`
}
// DeleteFileOptions represents a delete file options.
type DeleteFileOptions struct {
// Recursive delete the content recursively if a folder is denoted.
Recursive bool `json:"recursive,omitempty"`
// IgnoreIfNotExists ignore the operation if the file doesn't exist.
IgnoreIfNotExists bool `json:"ignoreIfNotExists,omitempty"`
}
// DeleteFile represents a delete file operation.
type DeleteFile struct {
// Kind is a delete.
Kind ResourceOperationKind `json:"kind"` // should be `delete`
// URI is the file to delete.
URI DocumentURI `json:"uri"`
// Options delete options.
Options *DeleteFileOptions `json:"options,omitempty"`
// AnnotationID an optional annotation identifier describing the operation.
//
// @since 3.16.0.
AnnotationID ChangeAnnotationIdentifier `json:"annotationId,omitempty"`
}
// WorkspaceEdit represent a changes to many resources managed in the workspace.
//
// The edit should either provide changes or documentChanges.
// If the client can handle versioned document edits and if documentChanges are present, the latter are preferred over
// changes.
type WorkspaceEdit struct {
// Changes holds changes to existing resources.
Changes map[DocumentURI][]TextEdit `json:"changes,omitempty"`
// DocumentChanges 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 []TextDocumentEdit `json:"documentChanges,omitempty"`
// ChangeAnnotations is 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"`
}
// TextDocumentIdentifier indicates the using a URI. On the protocol level, URIs are passed as strings.
type TextDocumentIdentifier struct {
// URI is the text document's URI.
URI DocumentURI `json:"uri"`
}
// TextDocumentItem represent an item to transfer a text document from the client to the server.
type TextDocumentItem struct {
// URI is the text document's URI.
URI DocumentURI `json:"uri"`
// LanguageID is the text document's language identifier.
LanguageID LanguageIdentifier `json:"languageId"`
// Version is the version number of this document (it will increase after each
// change, including undo/redo).
Version int32 `json:"version"`
// Text is the content of the opened text document.
Text string `json:"text"`
}
// LanguageIdentifier represent a text document's language identifier.
type LanguageIdentifier string
const (
// ABAPLanguage ABAP Language.
ABAPLanguage LanguageIdentifier = "abap"
// BatLanguage Windows Bat Language.
BatLanguage LanguageIdentifier = "bat"
// BibtexLanguage BibTeX Language.
BibtexLanguage LanguageIdentifier = "bibtex"
// ClojureLanguage Clojure Language.
ClojureLanguage LanguageIdentifier = "clojure"
// CoffeescriptLanguage CoffeeScript Language.
CoffeeScriptLanguage LanguageIdentifier = "coffeescript"
// CLanguage C Language.
CLanguage LanguageIdentifier = "c"
// CppLanguage C++ Language.
CppLanguage LanguageIdentifier = "cpp"
// CsharpLanguage C# Language.
CsharpLanguage LanguageIdentifier = "csharp"
// CSSLanguage CSS Language.
CSSLanguage LanguageIdentifier = "css"
// DiffLanguage Diff Language.
DiffLanguage LanguageIdentifier = "diff"
// DartLanguage Dart Language.
DartLanguage LanguageIdentifier = "dart"
// DockerfileLanguage Dockerfile Language.
DockerfileLanguage LanguageIdentifier = "dockerfile"
// ElixirLanguage Elixir Language.
ElixirLanguage LanguageIdentifier = "elixir"
// ErlangLanguage Erlang Language.
ErlangLanguage LanguageIdentifier = "erlang"
// FsharpLanguage F# Language.
FsharpLanguage LanguageIdentifier = "fsharp"
// GitCommitLanguage Git Language.
GitCommitLanguage LanguageIdentifier = "git-commit"
// GitRebaseLanguage Git Language.
GitRebaseLanguage LanguageIdentifier = "git-rebase"
// GoLanguage Go Language.
GoLanguage LanguageIdentifier = "go"
// GroovyLanguage Groovy Language.
GroovyLanguage LanguageIdentifier = "groovy"
// HandlebarsLanguage Handlebars Language.
HandlebarsLanguage LanguageIdentifier = "handlebars"
// HTMLLanguage HTML Language.
HTMLLanguage LanguageIdentifier = "html"
// IniLanguage Ini Language.
IniLanguage LanguageIdentifier = "ini"
// JavaLanguage Java Language.
JavaLanguage LanguageIdentifier = "java"
// JavaScriptLanguage JavaScript Language.
JavaScriptLanguage LanguageIdentifier = "javascript"
// JavaScriptReactLanguage JavaScript React Language.
JavaScriptReactLanguage LanguageIdentifier = "javascriptreact"
// JSONLanguage JSON Language.
JSONLanguage LanguageIdentifier = "json"
// LatexLanguage LaTeX Language.
LatexLanguage LanguageIdentifier = "latex"
// LessLanguage Less Language.
LessLanguage LanguageIdentifier = "less"
// LuaLanguage Lua Language.
LuaLanguage LanguageIdentifier = "lua"
// MakefileLanguage Makefile Language.
MakefileLanguage LanguageIdentifier = "makefile"
// MarkdownLanguage Markdown Language.
MarkdownLanguage LanguageIdentifier = "markdown"
// ObjectiveCLanguage Objective-C Language.
ObjectiveCLanguage LanguageIdentifier = "objective-c"
// ObjectiveCppLanguage Objective-C++ Language.
ObjectiveCppLanguage LanguageIdentifier = "objective-cpp"
// PerlLanguage Perl Language.
PerlLanguage LanguageIdentifier = "perl"
// Perl6Language Perl Language.
Perl6Language LanguageIdentifier = "perl6"
// PHPLanguage PHP Language.
PHPLanguage LanguageIdentifier = "php"
// PowershellLanguage Powershell Language.
PowershellLanguage LanguageIdentifier = "powershell"
// JadeLanguage Pug Language.
JadeLanguage LanguageIdentifier = "jade"
// PythonLanguage Python Language.
PythonLanguage LanguageIdentifier = "python"
// RLanguage R Language.
RLanguage LanguageIdentifier = "r"
// RazorLanguage Razor(cshtml) Language.
RazorLanguage LanguageIdentifier = "razor"
// RubyLanguage Ruby Language.
RubyLanguage LanguageIdentifier = "ruby"
// RustLanguage Rust Language.
RustLanguage LanguageIdentifier = "rust"
// SCSSLanguage SCSS Languages syntax using curly brackets.
SCSSLanguage LanguageIdentifier = "scss"
// SASSLanguage SCSS Languages indented syntax.
SASSLanguage LanguageIdentifier = "sass"
// ScalaLanguage Scala Language.
ScalaLanguage LanguageIdentifier = "scala"
// ShaderlabLanguage ShaderLab Language.
ShaderlabLanguage LanguageIdentifier = "shaderlab"
// ShellscriptLanguage Shell Script (Bash) Language.
ShellscriptLanguage LanguageIdentifier = "shellscript"
// SQLLanguage SQL Language.
SQLLanguage LanguageIdentifier = "sql"
// SwiftLanguage Swift Language.
SwiftLanguage LanguageIdentifier = "swift"
// TypeScriptLanguage TypeScript Language.
TypeScriptLanguage LanguageIdentifier = "typescript"
// TypeScriptReactLanguage TypeScript React Language.
TypeScriptReactLanguage LanguageIdentifier = "typescriptreact"
// TeXLanguage TeX Language.
TeXLanguage LanguageIdentifier = "tex"
// VBLanguage Visual Basic Language.
VBLanguage LanguageIdentifier = "vb"
// XMLLanguage XML Language.
XMLLanguage LanguageIdentifier = "xml"
// XslLanguage XSL Language.
XslLanguage LanguageIdentifier = "xsl"
// YamlLanguage YAML Language.
YamlLanguage LanguageIdentifier = "yaml"
)
// languageIdentifierMap map of LanguageIdentifiers.
var languageIdentifierMap = map[string]LanguageIdentifier{
"abap": ABAPLanguage,
"bat": BatLanguage,
"bibtex": BibtexLanguage,
"clojure": ClojureLanguage,
"coffeescript": CoffeeScriptLanguage,
"c": CLanguage,
"cpp": CppLanguage,
"csharp": CsharpLanguage,
"css": CSSLanguage,
"diff": DiffLanguage,
"dart": DartLanguage,
"dockerfile": DockerfileLanguage,
"elixir": ElixirLanguage,
"erlang": ErlangLanguage,
"fsharp": FsharpLanguage,
"git-commit": GitCommitLanguage,
"git-rebase": GitRebaseLanguage,
"go": GoLanguage,
"groovy": GroovyLanguage,
"handlebars": HandlebarsLanguage,
"html": HTMLLanguage,
"ini": IniLanguage,
"java": JavaLanguage,
"javascript": JavaScriptLanguage,
"javascriptreact": JavaScriptReactLanguage,
"json": JSONLanguage,
"latex": LatexLanguage,
"less": LessLanguage,
"lua": LuaLanguage,
"makefile": MakefileLanguage,
"markdown": MarkdownLanguage,
"objective-c": ObjectiveCLanguage,
"objective-cpp": ObjectiveCppLanguage,
"perl": PerlLanguage,
"perl6": Perl6Language,
"php": PHPLanguage,
"powershell": PowershellLanguage,
"jade": JadeLanguage,
"python": PythonLanguage,
"r": RLanguage,
"razor": RazorLanguage,
"ruby": RubyLanguage,
"rust": RustLanguage,
"scss": SCSSLanguage,
"sass": SASSLanguage,
"scala": ScalaLanguage,
"shaderlab": ShaderlabLanguage,
"shellscript": ShellscriptLanguage,
"sql": SQLLanguage,
"swift": SwiftLanguage,
"typescript": TypeScriptLanguage,
"typescriptreact": TypeScriptReactLanguage,
"tex": TeXLanguage,
"vb": VBLanguage,
"xml": XMLLanguage,
"xsl": XslLanguage,
"yaml": YamlLanguage,
}
// ToLanguageIdentifier converts ft to LanguageIdentifier.
func ToLanguageIdentifier(ft string) LanguageIdentifier {
langID, ok := languageIdentifierMap[ft]
if ok {
return langID
}
return LanguageIdentifier(ft)
}
// VersionedTextDocumentIdentifier represents an identifier to denote a specific version of a text document.
//
// This information usually flows from the client to the server.
type VersionedTextDocumentIdentifier struct {
TextDocumentIdentifier
// Version is 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 int32 `json:"version"`
}
// OptionalVersionedTextDocumentIdentifier represents an identifier which optionally denotes a specific version of
// a text document.
//
// This information usually flows from the server to the client.
//
// @since 3.16.0.
type OptionalVersionedTextDocumentIdentifier struct {
TextDocumentIdentifier
// Version is 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 *int32 `json:"version"` // int32 | null
}
// TextDocumentPositionParams is a parameter literal used in requests to pass a text document and a position
// inside that document.
//
// It is up to the client to decide how a selection is converted into a position when issuing a request for a text
// document.
//
// The client can for example honor or ignore the selection direction to make LSP request consistent with features
// implemented internally.
type TextDocumentPositionParams struct {
// TextDocument is the text document.
TextDocument TextDocumentIdentifier `json:"textDocument"`
// Position is the position inside the text document.
Position Position `json:"position"`
}
// DocumentFilter is a document filter denotes a document through properties like language, scheme or pattern.
//
// An example is a filter that applies to TypeScript files on disk.
type DocumentFilter struct {
// Language a language id, like `typescript`.
Language string `json:"language,omitempty"`
// Scheme a URI scheme, like `file` or `untitled`.
Scheme string `json:"scheme,omitempty"`
// Pattern 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"`
}
// DocumentSelector is a document selector is the combination of one or more document filters.
type DocumentSelector []*DocumentFilter
// MarkupKind describes the content type that a client supports in various
// result literals like `Hover`, `ParameterInfo` or `CompletionItem`.
//
// Please note that `MarkupKinds` must not start with a `$`. This kinds
// are reserved for internal usage.
type MarkupKind string
const (
// PlainText is supported as a content format.
PlainText MarkupKind = "plaintext"
// Markdown is supported as a content format.
Markdown MarkupKind = "markdown"
)
// MarkupContent a `MarkupContent` literal represents a string value which content is interpreted base on its
// kind flag.
//
// Currently the protocol supports `plaintext` and `markdown` as markup kinds.
//
// If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues.
// See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
//
// Here is an example how such a string can be constructed using JavaScript / TypeScript:
//
// let markdown: MarkdownContent = {
// kind: MarkupKind.Markdown,
// value: [
// '# Header',
// 'Some text',
// '```typescript',
// 'someCode();',
// '```'
// ].join('\n')
// };
//
// NOTE: clients might sanitize the return markdown. A client could decide to
// remove HTML from the markdown to avoid script execution.
type MarkupContent struct {
// Kind is the type of the Markup
Kind MarkupKind `json:"kind"`
// Value is the content itself
Value string `json:"value"`
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,103 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
// CallHierarchy capabilities specific to the "textDocument/callHierarchy".
//
// @since 3.16.0.
type CallHierarchy struct {
// DynamicRegistration 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"`
}
// CallHierarchyPrepareParams params of CallHierarchyPrepare.
//
// @since 3.16.0.
type CallHierarchyPrepareParams struct {
TextDocumentPositionParams
WorkDoneProgressParams
}
// CallHierarchyItem is the result of a "textDocument/prepareCallHierarchy" request.
//
// @since 3.16.0.
type CallHierarchyItem struct {
// name is the name of this item.
Name string `json:"name"`
// Kind is the kind of this item.
Kind SymbolKind `json:"kind"`
// Tags for this item.
Tags []SymbolTag `json:"tags,omitempty"`
// Detail more detail for this item, e.g. the signature of a function.
Detail string `json:"detail,omitempty"`
// URI is the resource identifier of this item.
URI DocumentURI `json:"uri"`
// Range is the range enclosing this symbol not including leading/trailing whitespace
// but everything else, e.g. comments and code.
Range Range `json:"range"`
// SelectionRange is 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"`
// Data is a data entry field that is preserved between a call hierarchy prepare and
// incoming calls or outgoing calls requests.
Data any `json:"data,omitempty"`
}
// CallHierarchyIncomingCallsParams params of CallHierarchyIncomingCalls.
//
// @since 3.16.0.
type CallHierarchyIncomingCallsParams struct {
WorkDoneProgressParams
PartialResultParams
// Item is the IncomingCalls item.
Item CallHierarchyItem `json:"item"`
}
// CallHierarchyIncomingCall is the result of a "callHierarchy/incomingCalls" request.
//
// @since 3.16.0.
type CallHierarchyIncomingCall struct {
// From is the item that makes the call.
From CallHierarchyItem `json:"from"`
// FromRanges is the ranges at which the calls appear. This is relative to the caller
// denoted by From.
FromRanges []Range `json:"fromRanges"`
}
// CallHierarchyOutgoingCallsParams params of CallHierarchyOutgoingCalls.
//
// @since 3.16.0.
type CallHierarchyOutgoingCallsParams struct {
WorkDoneProgressParams
PartialResultParams
// Item is the OutgoingCalls item.
Item CallHierarchyItem `json:"item"`
}
// CallHierarchyOutgoingCall is the result of a "callHierarchy/outgoingCalls" request.
//
// @since 3.16.0.
type CallHierarchyOutgoingCall struct {
// To is the item that is called.
To CallHierarchyItem `json:"to"`
// FromRanges is 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"`
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,523 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"strconv"
)
// ServerCapabilities efines the capabilities provided by a language server.
type ServerCapabilities struct {
// TextDocumentSync defines how text documents are synced. Is either a detailed structure defining each notification
// or for backwards compatibility the TextDocumentSyncKind number.
//
// If omitted it defaults to TextDocumentSyncKind.None`
TextDocumentSync any `json:"textDocumentSync,omitempty"` // *TextDocumentSyncOptions | TextDocumentSyncKind
// CompletionProvider is The server provides completion support.
CompletionProvider *CompletionOptions `json:"completionProvider,omitempty"`
// HoverProvider is the server provides hover support.
HoverProvider any `json:"hoverProvider,omitempty"` // TODO(zchee): bool | *HoverOptions
// SignatureHelpProvider is the server provides signature help support.
SignatureHelpProvider *SignatureHelpOptions `json:"signatureHelpProvider,omitempty"`
// DeclarationProvider is the server provides Goto Declaration support.
//
// @since 3.14.0.
DeclarationProvider any `json:"declarationProvider,omitempty"` // TODO(zchee): bool | *DeclarationOptions | *DeclarationRegistrationOptions
// DefinitionProvider is the server provides Goto definition support.
DefinitionProvider any `json:"definitionProvider,omitempty"` // TODO(zchee): bool | *DefinitionOptions
// TypeDefinitionProvider is the provides Goto Type Definition support.
//
// @since 3.6.0.
TypeDefinitionProvider any `json:"typeDefinitionProvider,omitempty"` // TODO(zchee): bool | *TypeDefinitionOptions | *TypeDefinitionRegistrationOptions
// ImplementationProvider is the provides Goto Implementation support.
//
// @since 3.6.0.
ImplementationProvider any `json:"implementationProvider,omitempty"` // TODO(zchee): bool | *ImplementationOptions | *ImplementationRegistrationOptions
// ReferencesProvider is the server provides find references support.
ReferencesProvider any `json:"referencesProvider,omitempty"` // TODO(zchee): bool | *ReferenceOptions
// DocumentHighlightProvider is the server provides document highlight support.
DocumentHighlightProvider any `json:"documentHighlightProvider,omitempty"` // TODO(zchee): bool | *DocumentHighlightOptions
// DocumentSymbolProvider is the server provides document symbol support.
DocumentSymbolProvider any `json:"documentSymbolProvider,omitempty"` // TODO(zchee): bool | *DocumentSymbolOptions
// CodeActionProvider is the server provides code actions.
//
// CodeActionOptions may only be specified if the client states that it supports CodeActionLiteralSupport in its
// initial Initialize request.
CodeActionProvider any `json:"codeActionProvider,omitempty"` // TODO(zchee): bool | *CodeActionOptions
// CodeLensProvider is the server provides code lens.
CodeLensProvider *CodeLensOptions `json:"codeLensProvider,omitempty"`
// The server provides document link support.
DocumentLinkProvider *DocumentLinkOptions `json:"documentLinkProvider,omitempty"`
// ColorProvider is the server provides color provider support.
//
// @since 3.6.0.
ColorProvider any `json:"colorProvider,omitempty"` // TODO(zchee): bool | *DocumentColorOptions | *DocumentColorRegistrationOptions
// WorkspaceSymbolProvider is the server provides workspace symbol support.
WorkspaceSymbolProvider any `json:"workspaceSymbolProvider,omitempty"` // TODO(zchee): bool | *WorkspaceSymbolOptions
// DocumentFormattingProvider is the server provides document formatting.
DocumentFormattingProvider any `json:"documentFormattingProvider,omitempty"` // TODO(zchee): bool | *DocumentFormattingOptions
// DocumentRangeFormattingProvider is the server provides document range formatting.
DocumentRangeFormattingProvider any `json:"documentRangeFormattingProvider,omitempty"` // TODO(zchee): bool | *DocumentRangeFormattingOptions
// DocumentOnTypeFormattingProvider is the server provides document formatting on typing.
DocumentOnTypeFormattingProvider *DocumentOnTypeFormattingOptions `json:"documentOnTypeFormattingProvider,omitempty"`
// RenameProvider is the server provides rename support.
//
// RenameOptions may only be specified if the client states that it supports PrepareSupport in its
// initial Initialize request.
RenameProvider any `json:"renameProvider,omitempty"` // TODO(zchee): bool | *RenameOptions
// FoldingRangeProvider is the server provides folding provider support.
//
// @since 3.10.0.
FoldingRangeProvider any `json:"foldingRangeProvider,omitempty"` // TODO(zchee): bool | *FoldingRangeOptions | *FoldingRangeRegistrationOptions
// SelectionRangeProvider is the server provides selection range support.
//
// @since 3.15.0.
SelectionRangeProvider any `json:"selectionRangeProvider,omitempty"` // TODO(zchee): bool | *SelectionRangeOptions | *SelectionRangeRegistrationOptions
// ExecuteCommandProvider is the server provides execute command support.
ExecuteCommandProvider *ExecuteCommandOptions `json:"executeCommandProvider,omitempty"`
// CallHierarchyProvider is the server provides call hierarchy support.
//
// @since 3.16.0.
CallHierarchyProvider any `json:"callHierarchyProvider,omitempty"` // TODO(zchee): bool | *CallHierarchyOptions | *CallHierarchyRegistrationOptions
// LinkedEditingRangeProvider is the server provides linked editing range support.
//
// @since 3.16.0.
LinkedEditingRangeProvider any `json:"linkedEditingRangeProvider,omitempty"` // TODO(zchee): bool | *LinkedEditingRangeOptions | *LinkedEditingRangeRegistrationOptions
// SemanticTokensProvider is the server provides semantic tokens support.
//
// @since 3.16.0.
SemanticTokensProvider any `json:"semanticTokensProvider,omitempty"` // TODO(zchee): *SemanticTokensOptions | *SemanticTokensRegistrationOptions
// Workspace is the window specific server capabilities.
Workspace *ServerCapabilitiesWorkspace `json:"workspace,omitempty"`
// MonikerProvider is the server provides moniker support.
//
// @since 3.16.0.
MonikerProvider any `json:"monikerProvider,omitempty"` // TODO(zchee): bool | *MonikerOptions | *MonikerRegistrationOptions
// Experimental server capabilities.
Experimental any `json:"experimental,omitempty"`
}
// TextDocumentSyncOptions TextDocumentSync options.
type TextDocumentSyncOptions struct {
// OpenClose open and close notifications are sent to the server.
OpenClose bool `json:"openClose,omitempty"`
// Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full
// and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None.
Change TextDocumentSyncKind `json:"change,omitempty"`
// WillSave notifications are sent to the server.
WillSave bool `json:"willSave,omitempty"`
// WillSaveWaitUntil will save wait until requests are sent to the server.
WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"`
// Save notifications are sent to the server.
Save *SaveOptions `json:"save,omitempty"`
}
// SaveOptions save options.
type SaveOptions struct {
// IncludeText is the client is supposed to include the content on save.
IncludeText bool `json:"includeText,omitempty"`
}
// TextDocumentSyncKind defines how the host (editor) should sync document changes to the language server.
type TextDocumentSyncKind float64
const (
// TextDocumentSyncKindNone documents should not be synced at all.
TextDocumentSyncKindNone TextDocumentSyncKind = 0
// TextDocumentSyncKindFull documents are synced by always sending the full content
// of the document.
TextDocumentSyncKindFull TextDocumentSyncKind = 1
// TextDocumentSyncKindIncremental documents are synced by sending the full content on open.
// After that only incremental updates to the document are
// send.
TextDocumentSyncKindIncremental TextDocumentSyncKind = 2
)
// String implements fmt.Stringer.
func (k TextDocumentSyncKind) String() string {
switch k {
case TextDocumentSyncKindNone:
return "None"
case TextDocumentSyncKindFull:
return "Full"
case TextDocumentSyncKindIncremental:
return "Incremental"
default:
return strconv.FormatFloat(float64(k), 'f', -10, 64)
}
}
// CompletionOptions Completion options.
type CompletionOptions struct {
// The server provides support to resolve additional
// information for a completion item.
ResolveProvider bool `json:"resolveProvider,omitempty"`
// The characters that trigger completion automatically.
TriggerCharacters []string `json:"triggerCharacters,omitempty"`
}
// HoverOptions option of hover provider server capabilities.
type HoverOptions struct {
WorkDoneProgressOptions
}
// SignatureHelpOptions SignatureHelp options.
type SignatureHelpOptions struct {
// The characters that trigger signature help
// automatically.
TriggerCharacters []string `json:"triggerCharacters,omitempty"`
// RetriggerCharacters is the slist 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"`
}
// DeclarationOptions registration option of Declaration server capability.
//
// @since 3.15.0.
type DeclarationOptions struct {
WorkDoneProgressOptions
}
// DeclarationRegistrationOptions registration option of Declaration server capability.
//
// @since 3.15.0.
type DeclarationRegistrationOptions struct {
DeclarationOptions
TextDocumentRegistrationOptions
StaticRegistrationOptions
}
// DefinitionOptions registration option of Definition server capability.
//
// @since 3.15.0.
type DefinitionOptions struct {
WorkDoneProgressOptions
}
// TypeDefinitionOptions registration option of TypeDefinition server capability.
//
// @since 3.15.0.
type TypeDefinitionOptions struct {
WorkDoneProgressOptions
}
// TypeDefinitionRegistrationOptions registration option of TypeDefinition server capability.
//
// @since 3.15.0.
type TypeDefinitionRegistrationOptions struct {
TextDocumentRegistrationOptions
TypeDefinitionOptions
StaticRegistrationOptions
}
// ImplementationOptions registration option of Implementation server capability.
//
// @since 3.15.0.
type ImplementationOptions struct {
WorkDoneProgressOptions
}
// ImplementationRegistrationOptions registration option of Implementation server capability.
//
// @since 3.15.0.
type ImplementationRegistrationOptions struct {
TextDocumentRegistrationOptions
ImplementationOptions
StaticRegistrationOptions
}
// ReferenceOptions registration option of Reference server capability.
type ReferenceOptions struct {
WorkDoneProgressOptions
}
// DocumentHighlightOptions registration option of DocumentHighlight server capability.
//
// @since 3.15.0.
type DocumentHighlightOptions struct {
WorkDoneProgressOptions
}
// DocumentSymbolOptions registration option of DocumentSymbol server capability.
//
// @since 3.15.0.
type DocumentSymbolOptions struct {
WorkDoneProgressOptions
// Label 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"`
}
// CodeActionOptions CodeAction options.
type CodeActionOptions struct {
// 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"`
// ResolveProvider is the server provides support to resolve additional
// information for a code action.
//
// @since 3.16.0.
ResolveProvider bool `json:"resolveProvider,omitempty"`
}
// CodeLensOptions CodeLens options.
type CodeLensOptions struct {
// Code lens has a resolve provider as well.
ResolveProvider bool `json:"resolveProvider,omitempty"`
}
// DocumentLinkOptions document link options.
type DocumentLinkOptions struct {
// ResolveProvider document links have a resolve provider as well.
ResolveProvider bool `json:"resolveProvider,omitempty"`
}
// DocumentColorOptions registration option of DocumentColor server capability.
//
// @since 3.15.0.
type DocumentColorOptions struct {
WorkDoneProgressOptions
}
// DocumentColorRegistrationOptions registration option of DocumentColor server capability.
//
// @since 3.15.0.
type DocumentColorRegistrationOptions struct {
TextDocumentRegistrationOptions
StaticRegistrationOptions
DocumentColorOptions
}
// WorkspaceSymbolOptions registration option of WorkspaceSymbol server capability.
//
// @since 3.15.0.
type WorkspaceSymbolOptions struct {
WorkDoneProgressOptions
}
// DocumentFormattingOptions registration option of DocumentFormatting server capability.
//
// @since 3.15.0.
type DocumentFormattingOptions struct {
WorkDoneProgressOptions
}
// DocumentRangeFormattingOptions registration option of DocumentRangeFormatting server capability.
//
// @since 3.15.0.
type DocumentRangeFormattingOptions struct {
WorkDoneProgressOptions
}
// DocumentOnTypeFormattingOptions format document on type options.
type DocumentOnTypeFormattingOptions struct {
// FirstTriggerCharacter a character on which formatting should be triggered, like "}".
FirstTriggerCharacter string `json:"firstTriggerCharacter"`
// MoreTriggerCharacter more trigger characters.
MoreTriggerCharacter []string `json:"moreTriggerCharacter,omitempty"`
}
// RenameOptions rename options.
type RenameOptions struct {
// PrepareProvider renames should be checked and tested before being executed.
PrepareProvider bool `json:"prepareProvider,omitempty"`
}
// FoldingRangeOptions registration option of FoldingRange server capability.
//
// @since 3.15.0.
type FoldingRangeOptions struct {
WorkDoneProgressOptions
}
// FoldingRangeRegistrationOptions registration option of FoldingRange server capability.
//
// @since 3.15.0.
type FoldingRangeRegistrationOptions struct {
TextDocumentRegistrationOptions
FoldingRangeOptions
StaticRegistrationOptions
}
// ExecuteCommandOptions execute command options.
type ExecuteCommandOptions struct {
// Commands is the commands to be executed on the server
Commands []string `json:"commands"`
}
// CallHierarchyOptions option of CallHierarchy.
//
// @since 3.16.0.
type CallHierarchyOptions struct {
WorkDoneProgressOptions
}
// CallHierarchyRegistrationOptions registration options of CallHierarchy.
//
// @since 3.16.0.
type CallHierarchyRegistrationOptions struct {
TextDocumentRegistrationOptions
CallHierarchyOptions
StaticRegistrationOptions
}
// LinkedEditingRangeOptions option of linked editing range provider server capabilities.
//
// @since 3.16.0.
type LinkedEditingRangeOptions struct {
WorkDoneProgressOptions
}
// LinkedEditingRangeRegistrationOptions registration option of linked editing range provider server capabilities.
//
// @since 3.16.0.
type LinkedEditingRangeRegistrationOptions struct {
TextDocumentRegistrationOptions
LinkedEditingRangeOptions
StaticRegistrationOptions
}
// SemanticTokensOptions option of semantic tokens provider server capabilities.
//
// @since 3.16.0.
type SemanticTokensOptions struct {
WorkDoneProgressOptions
}
// SemanticTokensRegistrationOptions registration option of semantic tokens provider server capabilities.
//
// @since 3.16.0.
type SemanticTokensRegistrationOptions struct {
TextDocumentRegistrationOptions
SemanticTokensOptions
StaticRegistrationOptions
}
// ServerCapabilitiesWorkspace specific server capabilities.
type ServerCapabilitiesWorkspace struct {
// WorkspaceFolders is the server supports workspace folder.
//
// @since 3.6.0.
WorkspaceFolders *ServerCapabilitiesWorkspaceFolders `json:"workspaceFolders,omitempty"`
// FileOperations is the server is interested in file notifications/requests.
//
// @since 3.16.0.
FileOperations *ServerCapabilitiesWorkspaceFileOperations `json:"fileOperations,omitempty"`
}
// ServerCapabilitiesWorkspaceFolders is the server supports workspace folder.
//
// @since 3.6.0.
type ServerCapabilitiesWorkspaceFolders struct {
// Supported is the server has support for workspace folders
Supported bool `json:"supported,omitempty"`
// ChangeNotifications whether the server wants to receive workspace folder
// change notifications.
//
// If a strings is provided the string is treated as a ID
// under which the notification is registered on the client
// side. The ID can be used to unregister for these events
// using the `client/unregisterCapability` request.
ChangeNotifications any `json:"changeNotifications,omitempty"` // string | boolean
}
// ServerCapabilitiesWorkspaceFileOperations is the server is interested in file notifications/requests.
//
// @since 3.16.0.
type ServerCapabilitiesWorkspaceFileOperations struct {
// DidCreate is the server is interested in receiving didCreateFiles
// notifications.
DidCreate *FileOperationRegistrationOptions `json:"didCreate,omitempty"`
// WillCreate is the server is interested in receiving willCreateFiles requests.
WillCreate *FileOperationRegistrationOptions `json:"willCreate,omitempty"`
// DidRename is the server is interested in receiving didRenameFiles
// notifications.
DidRename *FileOperationRegistrationOptions `json:"didRename,omitempty"`
// WillRename is the server is interested in receiving willRenameFiles requests.
WillRename *FileOperationRegistrationOptions `json:"willRename,omitempty"`
// DidDelete is the server is interested in receiving didDeleteFiles file
// notifications.
DidDelete *FileOperationRegistrationOptions `json:"didDelete,omitempty"`
// WillDelete is the server is interested in receiving willDeleteFiles file
// requests.
WillDelete *FileOperationRegistrationOptions `json:"willDelete,omitempty"`
}
// FileOperationRegistrationOptions is the options to register for file operations.
//
// @since 3.16.0.
type FileOperationRegistrationOptions struct {
// filters is the actual filters.
Filters []FileOperationFilter `json:"filters"`
}
// MonikerOptions option of moniker provider server capabilities.
//
// @since 3.16.0.
type MonikerOptions struct {
WorkDoneProgressOptions
}
// MonikerRegistrationOptions registration option of moniker provider server capabilities.
//
// @since 3.16.0.
type MonikerRegistrationOptions struct {
TextDocumentRegistrationOptions
MonikerOptions
}

View File

@@ -0,0 +1,412 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"bytes"
"context"
"fmt"
"log/slog"
"encoding/json"
"github.com/a-h/templ/lsp/jsonrpc2"
"github.com/a-h/templ/lsp/xcontext"
)
// ClientDispatcher returns a Client that dispatches LSP requests across the
// given jsonrpc2 connection.
func ClientDispatcher(conn jsonrpc2.Conn, logger *slog.Logger) Client {
return &client{
Conn: conn,
logger: logger,
}
}
// ClientHandler handler of LSP client.
func ClientHandler(log *slog.Logger, client Client, handler jsonrpc2.Handler) jsonrpc2.Handler {
h := func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {
if ctx.Err() != nil {
xctx := xcontext.Detach(ctx)
return reply(xctx, nil, ErrRequestCancelled)
}
handled, err := clientDispatch(ctx, log, client, reply, req)
if handled || err != nil {
return err
}
return handler(ctx, reply, req)
}
return h
}
// clientDispatch implements jsonrpc2.Handler.
//
//nolint:funlen,cyclop
func clientDispatch(ctx context.Context, log *slog.Logger, client Client, reply jsonrpc2.Replier, req jsonrpc2.Request) (handled bool, err error) {
if ctx.Err() != nil {
return true, reply(ctx, nil, ErrRequestCancelled)
}
dec := json.NewDecoder(bytes.NewReader(req.Params()))
switch req.Method() {
case MethodProgress: // notification
defer log.Debug(MethodProgress, slog.Any("error", err))
var params ProgressParams
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
err := client.Progress(ctx, &params)
return true, reply(ctx, nil, err)
case MethodWorkDoneProgressCreate: // request
defer log.Debug(MethodWorkDoneProgressCreate, slog.Any("error", err))
var params WorkDoneProgressCreateParams
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
err := client.WorkDoneProgressCreate(ctx, &params)
return true, reply(ctx, nil, err)
case MethodWindowLogMessage: // notification
defer log.Debug(MethodWindowLogMessage, slog.Any("error", err))
var params LogMessageParams
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
err := client.LogMessage(ctx, &params)
return true, reply(ctx, nil, err)
case MethodTextDocumentPublishDiagnostics: // notification
defer log.Debug(MethodTextDocumentPublishDiagnostics, slog.Any("error", err))
var params PublishDiagnosticsParams
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
err := client.PublishDiagnostics(ctx, &params)
return true, reply(ctx, nil, err)
case MethodWindowShowMessage: // notification
defer log.Debug(MethodWindowShowMessage, slog.Any("error", err))
var params ShowMessageParams
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
err := client.ShowMessage(ctx, &params)
return true, reply(ctx, nil, err)
case MethodWindowShowMessageRequest: // request
defer log.Debug(MethodWindowShowMessageRequest, slog.Any("error", err))
var params ShowMessageRequestParams
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
resp, err := client.ShowMessageRequest(ctx, &params)
return true, reply(ctx, resp, err)
case MethodTelemetryEvent: // notification
defer log.Debug(MethodTelemetryEvent, slog.Any("error", err))
var params any
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
err := client.Telemetry(ctx, &params)
return true, reply(ctx, nil, err)
case MethodClientRegisterCapability: // request
defer log.Debug(MethodClientRegisterCapability, slog.Any("error", err))
var params RegistrationParams
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
err := client.RegisterCapability(ctx, &params)
return true, reply(ctx, nil, err)
case MethodClientUnregisterCapability: // request
defer log.Debug(MethodClientUnregisterCapability, slog.Any("error", err))
var params UnregistrationParams
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
err := client.UnregisterCapability(ctx, &params)
return true, reply(ctx, nil, err)
case MethodWorkspaceApplyEdit: // request
defer log.Debug(MethodWorkspaceApplyEdit, slog.Any("error", err))
var params ApplyWorkspaceEditParams
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
resp, err := client.ApplyEdit(ctx, &params)
return true, reply(ctx, resp, err)
case MethodWorkspaceConfiguration: // request
defer log.Debug(MethodWorkspaceConfiguration, slog.Any("error", err))
var params ConfigurationParams
if err := dec.Decode(&params); err != nil {
return true, replyParseError(ctx, reply, err)
}
resp, err := client.Configuration(ctx, &params)
return true, reply(ctx, resp, err)
case MethodWorkspaceWorkspaceFolders: // request
defer log.Debug(MethodWorkspaceWorkspaceFolders, slog.Any("error", err))
if len(req.Params()) > 0 {
return true, reply(ctx, nil, fmt.Errorf("expected no params: %w", jsonrpc2.ErrInvalidParams))
}
resp, err := client.WorkspaceFolders(ctx)
return true, reply(ctx, resp, err)
default:
return false, nil
}
}
// Client represents a Language Server Protocol client.
type Client interface {
Progress(ctx context.Context, params *ProgressParams) (err error)
WorkDoneProgressCreate(ctx context.Context, params *WorkDoneProgressCreateParams) (err error)
LogMessage(ctx context.Context, params *LogMessageParams) (err error)
PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) (err error)
ShowMessage(ctx context.Context, params *ShowMessageParams) (err error)
ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (result *MessageActionItem, err error)
Telemetry(ctx context.Context, params any) (err error)
RegisterCapability(ctx context.Context, params *RegistrationParams) (err error)
UnregisterCapability(ctx context.Context, params *UnregistrationParams) (err error)
ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (result *ApplyWorkspaceEditResponse, err error)
Configuration(ctx context.Context, params *ConfigurationParams) (result []any, err error)
WorkspaceFolders(ctx context.Context) (result []WorkspaceFolder, err error)
}
// list of client methods.
const (
// MethodProgress method name of "$/progress".
MethodProgress = "$/progress"
// MethodWorkDoneProgressCreate method name of "window/workDoneProgress/create".
MethodWorkDoneProgressCreate = "window/workDoneProgress/create"
// MethodWindowShowMessage method name of "window/showMessage".
MethodWindowShowMessage = "window/showMessage"
// MethodWindowShowMessageRequest method name of "window/showMessageRequest.
MethodWindowShowMessageRequest = "window/showMessageRequest"
// MethodWindowLogMessage method name of "window/logMessage.
MethodWindowLogMessage = "window/logMessage"
// MethodTelemetryEvent method name of "telemetry/event.
MethodTelemetryEvent = "telemetry/event"
// MethodClientRegisterCapability method name of "client/registerCapability.
MethodClientRegisterCapability = "client/registerCapability"
// MethodClientUnregisterCapability method name of "client/unregisterCapability.
MethodClientUnregisterCapability = "client/unregisterCapability"
// MethodTextDocumentPublishDiagnostics method name of "textDocument/publishDiagnostics.
MethodTextDocumentPublishDiagnostics = "textDocument/publishDiagnostics"
// MethodWorkspaceApplyEdit method name of "workspace/applyEdit.
MethodWorkspaceApplyEdit = "workspace/applyEdit"
// MethodWorkspaceConfiguration method name of "workspace/configuration.
MethodWorkspaceConfiguration = "workspace/configuration"
// MethodWorkspaceWorkspaceFolders method name of "workspace/workspaceFolders".
MethodWorkspaceWorkspaceFolders = "workspace/workspaceFolders"
)
// client implements a Language Server Protocol client.
type client struct {
jsonrpc2.Conn
logger *slog.Logger
}
// compiler time check whether the Client implements ClientInterface interface.
var _ Client = (*client)(nil)
// Progress is the base protocol offers also support to report progress in a generic fashion.
//
// This mechanism can be used to report any kind of progress including work done progress (usually used to report progress in the user interface using a progress bar) and
// partial result progress to support streaming of results.
//
// @since 3.16.0.
func (c *client) Progress(ctx context.Context, params *ProgressParams) (err error) {
c.logger.Debug("call " + MethodProgress)
defer c.logger.Debug("end "+MethodProgress, slog.Any("error", err))
return c.Conn.Notify(ctx, MethodProgress, params)
}
// WorkDoneProgressCreate sends the request is sent from the server to the client to ask the client to create a work done progress.
//
// @since 3.16.0.
func (c *client) WorkDoneProgressCreate(ctx context.Context, params *WorkDoneProgressCreateParams) (err error) {
c.logger.Debug("call " + MethodWorkDoneProgressCreate)
defer c.logger.Debug("end "+MethodWorkDoneProgressCreate, slog.Any("error", err))
return Call(ctx, c.Conn, MethodWorkDoneProgressCreate, params, nil)
}
// LogMessage sends the notification from the server to the client to ask the client to log a particular message.
func (c *client) LogMessage(ctx context.Context, params *LogMessageParams) (err error) {
c.logger.Debug("call " + MethodWindowLogMessage)
defer c.logger.Debug("end "+MethodWindowLogMessage, slog.Any("error", err))
return c.Conn.Notify(ctx, MethodWindowLogMessage, params)
}
// PublishDiagnostics sends the notification from the server to the client to signal results of validation runs.
//
// Diagnostics are “owned” by the server so it is the servers responsibility to clear them if necessary. The following rule is used for VS Code servers that generate diagnostics:
//
// - if a language is single file only (for example HTML) then diagnostics are cleared by the server when the file is closed.
// - if a language has a project system (for example C#) diagnostics are not cleared when a file closes. When a project is opened all diagnostics for all files are recomputed (or read from a cache).
//
// When a file changes it is the servers responsibility to re-compute diagnostics and push them to the client.
// If the computed set is empty it has to push the empty array to clear former diagnostics.
// Newly pushed diagnostics always replace previously pushed diagnostics. There is no merging that happens on the client side.
func (c *client) PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) (err error) {
c.logger.Debug("call " + MethodTextDocumentPublishDiagnostics)
defer c.logger.Debug("end "+MethodTextDocumentPublishDiagnostics, slog.Any("error", err))
return c.Conn.Notify(ctx, MethodTextDocumentPublishDiagnostics, params)
}
// ShowMessage sends the notification from a server to a client to ask the
// client to display a particular message in the user interface.
func (c *client) ShowMessage(ctx context.Context, params *ShowMessageParams) (err error) {
return c.Conn.Notify(ctx, MethodWindowShowMessage, params)
}
// ShowMessageRequest sends the request from a server to a client to ask the client to display a particular message in the user interface.
//
// In addition to the show message notification the request allows to pass actions and to wait for an answer from the client.
func (c *client) ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (_ *MessageActionItem, err error) {
c.logger.Debug("call " + MethodWindowShowMessageRequest)
defer c.logger.Debug("end "+MethodWindowShowMessageRequest, slog.Any("error", err))
var result *MessageActionItem
if err := Call(ctx, c.Conn, MethodWindowShowMessageRequest, params, &result); err != nil {
return nil, err
}
return result, nil
}
// Telemetry sends the notification from the server to the client to ask the client to log a telemetry event.
func (c *client) Telemetry(ctx context.Context, params any) (err error) {
c.logger.Debug("call " + MethodTelemetryEvent)
defer c.logger.Debug("end "+MethodTelemetryEvent, slog.Any("error", err))
return c.Conn.Notify(ctx, MethodTelemetryEvent, params)
}
// RegisterCapability sends the request from the server to the client to register for a new capability on the client side.
//
// Not all clients need to support dynamic capability registration.
//
// A client opts in via the dynamicRegistration property on the specific client capabilities.
// A client can even provide dynamic registration for capability A but not for capability B (see TextDocumentClientCapabilities as an example).
func (c *client) RegisterCapability(ctx context.Context, params *RegistrationParams) (err error) {
c.logger.Debug("call " + MethodClientRegisterCapability)
defer c.logger.Debug("end "+MethodClientRegisterCapability, slog.Any("error", err))
return Call(ctx, c.Conn, MethodClientRegisterCapability, params, nil)
}
// UnregisterCapability sends the request from the server to the client to unregister a previously registered capability.
func (c *client) UnregisterCapability(ctx context.Context, params *UnregistrationParams) (err error) {
c.logger.Debug("call " + MethodClientUnregisterCapability)
defer c.logger.Debug("end "+MethodClientUnregisterCapability, slog.Any("error", err))
return Call(ctx, c.Conn, MethodClientUnregisterCapability, params, nil)
}
// ApplyEdit sends the request from the server to the client to modify resource on the client side.
func (c *client) ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (result *ApplyWorkspaceEditResponse, err error) {
c.logger.Debug("call " + MethodWorkspaceApplyEdit)
defer c.logger.Debug("end "+MethodWorkspaceApplyEdit, slog.Any("error", err))
if err := Call(ctx, c.Conn, MethodWorkspaceApplyEdit, params, &result); err != nil {
return nil, err
}
return result, nil
}
// Configuration sends the request from the server to the client to fetch configuration settings from the client.
//
// The request can fetch several configuration settings in one roundtrip.
// The order of the returned configuration settings correspond to the order of the
// passed ConfigurationItems (e.g. the first item in the response is the result for the first configuration item in the params).
func (c *client) Configuration(ctx context.Context, params *ConfigurationParams) (_ []any, err error) {
c.logger.Debug("call " + MethodWorkspaceConfiguration)
defer c.logger.Debug("end "+MethodWorkspaceConfiguration, slog.Any("error", err))
var result []any
if err := Call(ctx, c.Conn, MethodWorkspaceConfiguration, params, &result); err != nil {
return nil, err
}
return result, nil
}
// WorkspaceFolders sends the request from the server to the client to fetch the current open list of workspace folders.
//
// Returns null in the response if only a single file is open in the tool. Returns an empty array if a workspace is open but no folders are configured.
//
// @since 3.6.0.
func (c *client) WorkspaceFolders(ctx context.Context) (result []WorkspaceFolder, err error) {
c.logger.Debug("call " + MethodWorkspaceWorkspaceFolders)
defer c.logger.Debug("end "+MethodWorkspaceWorkspaceFolders, slog.Any("error", err))
if err := Call(ctx, c.Conn, MethodWorkspaceWorkspaceFolders, nil, &result); err != nil {
return nil, err
}
return result, nil
}

View File

@@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: 2020 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"context"
)
type ctxClientKey int
var ctxClient ctxClientKey = 0
// WithClient returns the context with Client value.
func WithClient(ctx context.Context, client Client) context.Context {
return context.WithValue(ctx, ctxClient, client)
}
// ClientFromContext extracts Client from context.
func ClientFromContext(ctx context.Context) Client {
client, ok := ctx.Value(ctxClient).(Client)
if !ok {
return nil
}
return client
}

View File

@@ -0,0 +1,264 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
// ClientCapabilitiesShowDocument alias of ShowDocumentClientCapabilities.
//
// Deprecated: Use ShowDocumentClientCapabilities instead.
type ClientCapabilitiesShowDocument = ShowDocumentClientCapabilities
// ClientCapabilitiesShowMessageRequest alias of ShowMessageRequestClientCapabilities.
//
// Deprecated: Use ShowMessageRequestClientCapabilities instead.
type ClientCapabilitiesShowMessageRequest = ShowMessageRequestClientCapabilities
// ClientCapabilitiesShowMessageRequestMessageActionItem alias of ShowMessageRequestClientCapabilitiesMessageActionItem.
//
// Deprecated: Use ShowMessageRequestClientCapabilitiesMessageActionItem instead.
type ClientCapabilitiesShowMessageRequestMessageActionItem = ShowMessageRequestClientCapabilitiesMessageActionItem
// ReferencesParams alias of ReferenceParams.
//
// Deprecated: Use ReferenceParams instead.
type ReferencesParams = ReferenceParams
// TextDocumentClientCapabilitiesCallHierarchy alias of CallHierarchyClientCapabilities.
//
// Deprecated: Use CallHierarchyClientCapabilities instead.
type TextDocumentClientCapabilitiesCallHierarchy = CallHierarchyClientCapabilities
// TextDocumentClientCapabilitiesCodeAction alias of CodeActionClientCapabilities.
//
// Deprecated: Use CodeActionClientCapabilities instead.
type TextDocumentClientCapabilitiesCodeAction = CodeActionClientCapabilities
// TextDocumentClientCapabilitiesCodeActionKind alias of CodeActionClientCapabilitiesKind.
//
// Deprecated: Use CodeActionClientCapabilitiesKind instead.
type TextDocumentClientCapabilitiesCodeActionKind = CodeActionClientCapabilitiesKind
// TextDocumentClientCapabilitiesCodeActionLiteralSupport alias of CodeActionClientCapabilitiesLiteralSupport.
//
// Deprecated: Use CodeActionClientCapabilitiesLiteralSupport instead.
type TextDocumentClientCapabilitiesCodeActionLiteralSupport = CodeActionClientCapabilitiesLiteralSupport
// TextDocumentClientCapabilitiesCodeActionResolveSupport alias of CodeActionClientCapabilitiesResolveSupport.
//
// Deprecated: Use CodeActionClientCapabilitiesResolveSupport instead.
type TextDocumentClientCapabilitiesCodeActionResolveSupport = CodeActionClientCapabilitiesResolveSupport
// TextDocumentClientCapabilitiesCodeLens alias of CodeLensClientCapabilities.
//
// Deprecated: Use CodeLensClientCapabilities instead.
type TextDocumentClientCapabilitiesCodeLens = CodeLensClientCapabilities
// TextDocumentClientCapabilitiesColorProvider alias of DocumentColorClientCapabilities.
//
// Deprecated: Use DocumentColorClientCapabilities instead.
type TextDocumentClientCapabilitiesColorProvider = DocumentColorClientCapabilities
// TextDocumentClientCapabilitiesCompletion alias of CompletionTextDocumentClientCapabilities.
//
// Deprecated: Use CompletionTextDocumentClientCapabilities instead.
type TextDocumentClientCapabilitiesCompletion = CompletionTextDocumentClientCapabilities
// TextDocumentClientCapabilitiesCompletionItem alias of CompletionTextDocumentClientCapabilitiesItem.
//
// Deprecated: Use CompletionTextDocumentClientCapabilitiesItem instead.
type TextDocumentClientCapabilitiesCompletionItem = CompletionTextDocumentClientCapabilitiesItem
// TextDocumentClientCapabilitiesCompletionItemInsertTextModeSupport alias of CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport.
//
// Deprecated: Use CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport instead.
type TextDocumentClientCapabilitiesCompletionItemInsertTextModeSupport = CompletionTextDocumentClientCapabilitiesItemInsertTextModeSupport
// TextDocumentClientCapabilitiesCompletionItemKind alias of CompletionTextDocumentClientCapabilitiesItemKind.
//
// Deprecated: Use CompletionTextDocumentClientCapabilitiesItemKind instead.
type TextDocumentClientCapabilitiesCompletionItemKind = CompletionTextDocumentClientCapabilitiesItemKind
// TextDocumentClientCapabilitiesCompletionItemResolveSupport alias of CompletionTextDocumentClientCapabilitiesItemResolveSupport.
//
// Deprecated: Use CompletionTextDocumentClientCapabilitiesItemResolveSupport instead.
type TextDocumentClientCapabilitiesCompletionItemResolveSupport = CompletionTextDocumentClientCapabilitiesItemResolveSupport
// TextDocumentClientCapabilitiesCompletionItemTagSupport alias of CompletionTextDocumentClientCapabilitiesItemTagSupport.
//
// Deprecated: Use CompletionTextDocumentClientCapabilitiesItemTagSupport instead.
type TextDocumentClientCapabilitiesCompletionItemTagSupport = CompletionTextDocumentClientCapabilitiesItemTagSupport
// TextDocumentClientCapabilitiesDeclaration alias of DeclarationTextDocumentClientCapabilities.
//
// Deprecated: Use DeclarationTextDocumentClientCapabilities instead.
type TextDocumentClientCapabilitiesDeclaration = DeclarationTextDocumentClientCapabilities
// TextDocumentClientCapabilitiesDefinition alias of DefinitionTextDocumentClientCapabilities.
//
// Deprecated: Use DefinitionTextDocumentClientCapabilities instead.
type TextDocumentClientCapabilitiesDefinition = DefinitionTextDocumentClientCapabilities
// TextDocumentClientCapabilitiesDocumentHighlight alias of DocumentHighlightClientCapabilities.
//
// Deprecated: Use DocumentHighlightClientCapabilities instead.
type TextDocumentClientCapabilitiesDocumentHighlight = DocumentHighlightClientCapabilities
// TextDocumentClientCapabilitiesDocumentLink alias of DocumentLinkClientCapabilities.
//
// Deprecated: Use DocumentLinkClientCapabilities instead.
type TextDocumentClientCapabilitiesDocumentLink = DocumentLinkClientCapabilities
// TextDocumentClientCapabilitiesDocumentSymbol alias of DocumentSymbolClientCapabilities.
//
// Deprecated: Use DocumentSymbolClientCapabilities instead.
type TextDocumentClientCapabilitiesDocumentSymbol = DocumentSymbolClientCapabilities
// TextDocumentClientCapabilitiesDocumentSymbolTagSupport alias of DocumentSymbolClientCapabilitiesTagSupport.
//
// Deprecated: Use DocumentSymbolClientCapabilitiesTagSupport instead.
type TextDocumentClientCapabilitiesDocumentSymbolTagSupport = DocumentSymbolClientCapabilitiesTagSupport
// TextDocumentClientCapabilitiesFoldingRange alias of FoldingRangeClientCapabilities.
//
// Deprecated: Use FoldingRangeClientCapabilities instead.
type TextDocumentClientCapabilitiesFoldingRange = FoldingRangeClientCapabilities
// TextDocumentClientCapabilitiesFormatting alias of DocumentFormattingClientCapabilities.
//
// Deprecated: Use DocumentFormattingClientCapabilities instead.
type TextDocumentClientCapabilitiesFormatting = DocumentFormattingClientCapabilities
// TextDocumentClientCapabilitiesHover alias of HoverTextDocumentClientCapabilities.
//
// Deprecated: Use HoverTextDocumentClientCapabilities instead.
type TextDocumentClientCapabilitiesHover = HoverTextDocumentClientCapabilities
// TextDocumentClientCapabilitiesImplementation alias of ImplementationTextDocumentClientCapabilities.
//
// Deprecated: Use ImplementationTextDocumentClientCapabilities instead.
type TextDocumentClientCapabilitiesImplementation = ImplementationTextDocumentClientCapabilities
// TextDocumentClientCapabilitiesLinkedEditingRange alias of LinkedEditingRangeClientCapabilities.
//
// Deprecated: Use LinkedEditingRangeClientCapabilities instead.
type TextDocumentClientCapabilitiesLinkedEditingRange = LinkedEditingRangeClientCapabilities
// TextDocumentClientCapabilitiesMoniker of MonikerClientCapabilities.
//
// Deprecated: Use MonikerClientCapabilities instead.
type TextDocumentClientCapabilitiesMoniker = MonikerClientCapabilities
// TextDocumentClientCapabilitiesOnTypeFormatting of DocumentOnTypeFormattingClientCapabilities.
//
// Deprecated: Use DocumentOnTypeFormattingClientCapabilities instead.
type TextDocumentClientCapabilitiesOnTypeFormatting = DocumentOnTypeFormattingClientCapabilities
// TextDocumentClientCapabilitiesPublishDiagnostics of PublishDiagnosticsClientCapabilities.
//
// Deprecated: Use PublishDiagnosticsClientCapabilities instead.
type TextDocumentClientCapabilitiesPublishDiagnostics = PublishDiagnosticsClientCapabilities
// TextDocumentClientCapabilitiesPublishDiagnosticsTagSupport of PublishDiagnosticsClientCapabilitiesTagSupport.
//
// Deprecated: Use PublishDiagnosticsClientCapabilitiesTagSupport instead.
type TextDocumentClientCapabilitiesPublishDiagnosticsTagSupport = PublishDiagnosticsClientCapabilitiesTagSupport
// TextDocumentClientCapabilitiesRangeFormatting of DocumentRangeFormattingClientCapabilities.
//
// Deprecated: Use DocumentRangeFormattingClientCapabilities instead.
type TextDocumentClientCapabilitiesRangeFormatting = DocumentRangeFormattingClientCapabilities
// TextDocumentClientCapabilitiesReferences of ReferencesTextDocumentClientCapabilities.
//
// Deprecated: Use ReferencesTextDocumentClientCapabilities instead.
type TextDocumentClientCapabilitiesReferences = ReferencesTextDocumentClientCapabilities
// TextDocumentClientCapabilitiesRename of RenameClientCapabilities.
//
// Deprecated: Use RenameClientCapabilities instead.
type TextDocumentClientCapabilitiesRename = RenameClientCapabilities
// TextDocumentClientCapabilitiesSelectionRange of SelectionRangeClientCapabilities.
//
// Deprecated: Use SelectionRangeClientCapabilities instead.
type TextDocumentClientCapabilitiesSelectionRange = SelectionRangeClientCapabilities
// TextDocumentClientCapabilitiesSemanticTokens of SemanticTokensClientCapabilities.
//
// Deprecated: Use SemanticTokensClientCapabilities instead.
type TextDocumentClientCapabilitiesSemanticTokens = SemanticTokensClientCapabilities
// TextDocumentClientCapabilitiesSignatureHelp of SignatureHelpTextDocumentClientCapabilities.
//
// Deprecated: Use SignatureHelpTextDocumentClientCapabilities instead.
type TextDocumentClientCapabilitiesSignatureHelp = SignatureHelpTextDocumentClientCapabilities
// TextDocumentClientCapabilitiesSynchronization of TextDocumentSyncClientCapabilities.
//
// Deprecated: Use TextDocumentSyncClientCapabilities instead.
type TextDocumentClientCapabilitiesSynchronization = TextDocumentSyncClientCapabilities
// TextDocumentClientCapabilitiesTypeDefinition of TypeDefinitionTextDocumentClientCapabilities.
//
// Deprecated: Use TypeDefinitionTextDocumentClientCapabilities instead.
type TextDocumentClientCapabilitiesTypeDefinition = TypeDefinitionTextDocumentClientCapabilities
// Abort alias of FailureHandlingKindAbort.
//
// Deprecated: Use FailureHandlingKindAbort instead.
const Abort = FailureHandlingKindAbort
// TextOnlyTransactional alias of FailureHandlingKindTextOnlyTransactional.
//
// Deprecated: Use FailureHandlingKindTextOnlyTransactional instead.
const TextOnlyTransactional = FailureHandlingKindTextOnlyTransactional
// Transactional alias of FailureHandlingKindTransactional.
//
// Deprecated: Use FailureHandlingKindTransactional instead.
const Transactional = FailureHandlingKindTransactional
// Undo alias of FailureHandlingKindUndo.
//
// Deprecated: Use FailureHandlingKindUndo instead.
const Undo = FailureHandlingKindUndo
// WorkspaceClientCapabilitiesSymbol alias of WorkspaceSymbolClientCapabilities.
//
// Deprecated: Use WorkspaceSymbolClientCapabilities instead.
type WorkspaceClientCapabilitiesSymbol = WorkspaceSymbolClientCapabilities
// WorkspaceClientCapabilitiesSymbolKind alias of SymbolKindCapabilities.
//
// Deprecated: Use SymbolKindCapabilities instead.
type WorkspaceClientCapabilitiesSymbolKind = SymbolKindCapabilities
// WorkspaceClientCapabilitiesCodeLens alias of CodeLensWorkspaceClientCapabilities.
//
// Deprecated: Use CodeLensWorkspaceClientCapabilities instead.
type WorkspaceClientCapabilitiesCodeLens = CodeLensWorkspaceClientCapabilities
// WorkspaceClientCapabilitiesDidChangeConfiguration alias of DidChangeConfigurationWorkspaceClientCapabilities.
//
// Deprecated: Use DidChangeConfigurationWorkspaceClientCapabilities instead.
type WorkspaceClientCapabilitiesDidChangeConfiguration = DidChangeConfigurationWorkspaceClientCapabilities
// WorkspaceClientCapabilitiesDidChangeWatchedFiles alias of DidChangeWatchedFilesWorkspaceClientCapabilities.
//
// Deprecated: Use DidChangeWatchedFilesWorkspaceClientCapabilities instead.
type WorkspaceClientCapabilitiesDidChangeWatchedFiles = DidChangeWatchedFilesWorkspaceClientCapabilities
// WorkspaceClientCapabilitiesExecuteCommand alias of ExecuteCommandClientCapabilities.
//
// Deprecated: Use ExecuteCommandClientCapabilities instead.
type WorkspaceClientCapabilitiesExecuteCommand = ExecuteCommandClientCapabilities
// WorkspaceClientCapabilitiesSemanticTokens alias of SemanticTokensWorkspaceClientCapabilities.
//
// Deprecated: Use SemanticTokensWorkspaceClientCapabilities instead.
type WorkspaceClientCapabilitiesSemanticTokens = SemanticTokensWorkspaceClientCapabilities
// WorkspaceClientCapabilitiesSemanticTokensRequests alias of SemanticTokensWorkspaceClientCapabilitiesRequests.
//
// Deprecated: Use SemanticTokensWorkspaceClientCapabilitiesRequests instead.
type WorkspaceClientCapabilitiesSemanticTokensRequests = SemanticTokensWorkspaceClientCapabilitiesRequests

View File

@@ -0,0 +1,149 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"strconv"
)
// Diagnostic represents a diagnostic, such as a compiler error or warning.
//
// Diagnostic objects are only valid in the scope of a resource.
type Diagnostic struct {
// Range is the range at which the message applies.
Range Range `json:"range"`
// Severity is 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"`
// Code is the diagnostic's code, which might appear in the user interface.
Code any `json:"code,omitempty"` // int32 | string;
// CodeDescription an optional property to describe the error code.
//
// @since 3.16.0.
CodeDescription *CodeDescription `json:"codeDescription,omitempty"`
// Source a human-readable string describing the source of this
// diagnostic, e.g. 'typescript' or 'super lint'.
Source string `json:"source,omitempty"`
// Message is the diagnostic's message.
Message string `json:"message"`
// Tags is the additional metadata about the diagnostic.
//
// @since 3.15.0.
Tags []DiagnosticTag `json:"tags,omitempty"`
// RelatedInformation 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"`
// Data is 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"`
}
// DiagnosticSeverity indicates the severity of a Diagnostic message.
type DiagnosticSeverity float64
const (
// DiagnosticSeverityError reports an error.
DiagnosticSeverityError DiagnosticSeverity = 1
// DiagnosticSeverityWarning reports a warning.
DiagnosticSeverityWarning DiagnosticSeverity = 2
// DiagnosticSeverityInformation reports an information.
DiagnosticSeverityInformation DiagnosticSeverity = 3
// DiagnosticSeverityHint reports a hint.
DiagnosticSeverityHint DiagnosticSeverity = 4
)
// String implements fmt.Stringer.
func (d DiagnosticSeverity) String() string {
switch d {
case DiagnosticSeverityError:
return "Error"
case DiagnosticSeverityWarning:
return "Warning"
case DiagnosticSeverityInformation:
return "Information"
case DiagnosticSeverityHint:
return "Hint"
default:
return strconv.FormatFloat(float64(d), 'f', -10, 64)
}
}
// CodeDescription is the structure to capture a description for an error code.
//
// @since 3.16.0.
type CodeDescription struct {
// Href an URI to open with more information about the diagnostic error.
Href URI `json:"href"`
}
// DiagnosticTag is the diagnostic tags.
//
// @since 3.15.0.
type DiagnosticTag float64
// list of DiagnosticTag.
const (
// DiagnosticTagUnnecessary unused or unnecessary code.
//
// Clients are allowed to render diagnostics with this tag faded out instead of having
// an error squiggle.
DiagnosticTagUnnecessary DiagnosticTag = 1
// DiagnosticTagDeprecated deprecated or obsolete code.
//
// Clients are allowed to rendered diagnostics with this tag strike through.
DiagnosticTagDeprecated DiagnosticTag = 2
)
// String implements fmt.Stringer.
func (d DiagnosticTag) String() string {
switch d {
case DiagnosticTagUnnecessary:
return "Unnecessary"
case DiagnosticTagDeprecated:
return "Deprecated"
default:
return strconv.FormatFloat(float64(d), 'f', -10, 64)
}
}
// DiagnosticRelatedInformation represents a related message and source code location for a diagnostic.
//
// This should be used to point to code locations that cause or related to a diagnostics, e.g when duplicating
// a symbol in a scope.
type DiagnosticRelatedInformation struct {
// Location is the location of this related diagnostic information.
Location Location `json:"location"`
// Message is the message of this related diagnostic information.
Message string `json:"message"`
}
// PublishDiagnosticsParams represents a params of PublishDiagnostics notification.
type PublishDiagnosticsParams struct {
// URI is the URI for which diagnostic information is reported.
URI DocumentURI `json:"uri"`
// Version optional the version number of the document the diagnostics are published for.
//
// @since 3.15
Version uint32 `json:"version,omitempty"`
// Diagnostics an array of diagnostic information items.
Diagnostics []Diagnostic `json:"diagnostics"`
}

View File

@@ -0,0 +1,640 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"testing"
"encoding/json"
"github.com/google/go-cmp/cmp"
"github.com/a-h/templ/lsp/uri"
)
func TestDiagnostic(t *testing.T) {
t.Parallel()
const (
want = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","tags":[1,2],"relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}],"data":"testData"}`
wantNilSeverity = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}],"data":"testData"}`
wantNilCode = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}],"data":"testData"}`
wantNilRelatedInformation = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","data":"testData"}`
wantNilAll = `{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"message":"foo bar"}`
wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"severity":1,"code":"foo/bar","codeDescription":{"href":"file:///path/to/test.go"},"source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}},"message":"basic_gen.go"}],"data":"invalidData"}`
)
wantType := Diagnostic{
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
Severity: DiagnosticSeverityError,
Code: "foo/bar",
CodeDescription: &CodeDescription{
Href: uri.File("/path/to/test.go"),
},
Source: "test foo bar",
Message: "foo bar",
Tags: []DiagnosticTag{
DiagnosticTagUnnecessary,
DiagnosticTagDeprecated,
},
RelatedInformation: []DiagnosticRelatedInformation{
{
Location: Location{
URI: uri.File("/path/to/basic.go"),
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
},
Message: "basic_gen.go",
},
},
Data: "testData",
}
wantTypeNilSeverity := Diagnostic{
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
Code: "foo/bar",
CodeDescription: &CodeDescription{
Href: uri.File("/path/to/test.go"),
},
Source: "test foo bar",
Message: "foo bar",
RelatedInformation: []DiagnosticRelatedInformation{
{
Location: Location{
URI: uri.File("/path/to/basic.go"),
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
},
Message: "basic_gen.go",
},
},
Data: "testData",
}
wantTypeNilCode := Diagnostic{
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
Severity: DiagnosticSeverityError,
CodeDescription: &CodeDescription{
Href: uri.File("/path/to/test.go"),
},
Source: "test foo bar",
Message: "foo bar",
RelatedInformation: []DiagnosticRelatedInformation{
{
Location: Location{
URI: uri.File("/path/to/basic.go"),
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
},
Message: "basic_gen.go",
},
},
Data: "testData",
}
wantTypeNilRelatedInformation := Diagnostic{
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
Severity: DiagnosticSeverityError,
Code: "foo/bar",
CodeDescription: &CodeDescription{
Href: uri.File("/path/to/test.go"),
},
Source: "test foo bar",
Message: "foo bar",
Data: "testData",
}
wantTypeNilAll := Diagnostic{
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
Message: "foo bar",
}
t.Run("Marshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field Diagnostic
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidNilSeverity",
field: wantTypeNilSeverity,
want: wantNilSeverity,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidNilCode",
field: wantTypeNilCode,
want: wantNilCode,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidNilRelatedInformation",
field: wantTypeNilRelatedInformation,
want: wantNilRelatedInformation,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantTypeNilAll,
want: wantNilAll,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field string
want Diagnostic
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "ValidNilSeverity",
field: wantNilSeverity,
want: wantTypeNilSeverity,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "ValidNilCode",
field: wantNilCode,
want: wantTypeNilCode,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "ValidNilRelatedInformation",
field: wantNilRelatedInformation,
want: wantTypeNilRelatedInformation,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantNilAll,
want: wantTypeNilAll,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got Diagnostic
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestDiagnosticSeverity_String(t *testing.T) {
t.Parallel()
tests := []struct {
name string
d DiagnosticSeverity
want string
}{
{
name: "Error",
d: DiagnosticSeverityError,
want: "Error",
},
{
name: "Warning",
d: DiagnosticSeverityWarning,
want: "Warning",
},
{
name: "Information",
d: DiagnosticSeverityInformation,
want: "Information",
},
{
name: "Hint",
d: DiagnosticSeverityHint,
want: "Hint",
},
{
name: "Unknown",
d: DiagnosticSeverity(0),
want: "0",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := tt.d.String(); got != tt.want {
t.Errorf("DiagnosticSeverity.String() = %v, want %v", tt.want, got)
}
})
}
}
func TestDiagnosticTag_String(t *testing.T) {
t.Parallel()
tests := []struct {
name string
d DiagnosticTag
want string
}{
{
name: "Unnecessary",
d: DiagnosticTagUnnecessary,
want: "Unnecessary",
},
{
name: "Deprecated",
d: DiagnosticTagDeprecated,
want: "Deprecated",
},
{
name: "Unknown",
d: DiagnosticTag(0),
want: "0",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := tt.d.String(); got != tt.want {
t.Errorf("DiagnosticSeverity.String() = %v, want %v", tt.want, got)
}
})
}
}
func TestDiagnosticRelatedInformation(t *testing.T) {
t.Parallel()
const (
want = `{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"basic_gen.go"}`
wantInvalid = `{"location":{"uri":"file:///path/to/basic.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}},"message":"basic_gen.go"}`
)
wantType := DiagnosticRelatedInformation{
Location: Location{
URI: uri.File("/path/to/basic.go"),
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
},
Message: "basic_gen.go",
}
t.Run("Marshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field DiagnosticRelatedInformation
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field string
want DiagnosticRelatedInformation
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got DiagnosticRelatedInformation
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestPublishDiagnosticsParams(t *testing.T) {
t.Parallel()
const (
want = `{"uri":"file:///path/to/diagnostics.go","version":1,"diagnostics":[{"range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/diagnostics.go","range":{"start":{"line":25,"character":1},"end":{"line":27,"character":3}}},"message":"diagnostics.go"}]}]}`
wantInvalid = `{"uri":"file:///path/to/diagnostics_gen.go","version":2,"diagnostics":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}},"severity":1,"code":"foo/bar","source":"test foo bar","message":"foo bar","relatedInformation":[{"location":{"uri":"file:///path/to/diagnostics_gen.go","range":{"start":{"line":2,"character":1},"end":{"line":3,"character":2}}},"message":"diagnostics_gen.go"}]}]}`
)
wantType := PublishDiagnosticsParams{
URI: DocumentURI("file:///path/to/diagnostics.go"),
Version: 1,
Diagnostics: []Diagnostic{
{
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
Severity: DiagnosticSeverityError,
Code: "foo/bar",
Source: "test foo bar",
Message: "foo bar",
RelatedInformation: []DiagnosticRelatedInformation{
{
Location: Location{
URI: uri.File("/path/to/diagnostics.go"),
Range: Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 27,
Character: 3,
},
},
},
Message: "diagnostics.go",
},
},
},
},
}
t.Run("Marshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field PublishDiagnosticsParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field string
want PublishDiagnosticsParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got PublishDiagnosticsParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}

23
templ/lsp/protocol/doc.go Normal file
View File

@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
// Package protocol implements Language Server Protocol specification in Go.
//
// This package contains the structs that map directly to the wire format
// of the Language Server Protocol.
//
// It is a literal transcription, with unmodified comments, and only the changes
// required to make it Go code.
//
// - Names are uppercased to export them.
//
// - All fields have JSON tags added to correct the names.
//
// - Fields marked with a ? are also marked as "omitempty".
//
// - Fields that are "|| null" are made pointers.
//
// - Fields that are string or number are left as string.
//
// - Fields that are type "number" are made float64.
package protocol // import "github.com/a-h/templ/lsp/protocol"

View File

@@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import "github.com/a-h/templ/lsp/jsonrpc2"
const (
// LSPReservedErrorRangeStart is the start range of LSP reserved error codes.
//
// It doesn't denote a real error code.
//
// @since 3.16.0.
LSPReservedErrorRangeStart jsonrpc2.Code = -32899
// ContentModified is the state change that invalidates the result of a request in execution.
//
// Defined by the protocol.
CodeContentModified jsonrpc2.Code = -32801
// RequestCancelled is the cancellation error.
//
// Defined by the protocol.
CodeRequestCancelled jsonrpc2.Code = -32800
// LSPReservedErrorRangeEnd is the end range of LSP reserved error codes.
//
// It doesn't denote a real error code.
//
// @since 3.16.0.
LSPReservedErrorRangeEnd jsonrpc2.Code = -32800
)
var (
// ErrContentModified should be used when a request is canceled early.
ErrContentModified = jsonrpc2.NewError(CodeContentModified, "cancelled JSON-RPC")
// ErrRequestCancelled should be used when a request is canceled early.
ErrRequestCancelled = jsonrpc2.NewError(CodeRequestCancelled, "cancelled JSON-RPC")
)

View File

@@ -0,0 +1,461 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
// TraceValue represents a InitializeParams Trace mode.
type TraceValue string
// list of TraceValue.
const (
// TraceOff disable tracing.
TraceOff TraceValue = "off"
// TraceMessage normal tracing mode.
TraceMessage TraceValue = "message"
// TraceVerbose verbose tracing mode.
TraceVerbose TraceValue = "verbose"
)
// ClientInfo information about the client.
//
// @since 3.15.0.
type ClientInfo struct {
// Name is the name of the client as defined by the client.
Name string `json:"name"`
// Version is the client's version as defined by the client.
Version string `json:"version,omitempty"`
}
// InitializeParams params of Initialize request.
type InitializeParams struct {
WorkDoneProgressParams
// ProcessID is the process Id of the parent process that started
// the server. Is null if the process has not been started by another process.
// If the parent process is not alive then the server should exit (see exit notification) its process.
ProcessID int32 `json:"processId"`
// ClientInfo is the information about the client.
//
// @since 3.15.0
ClientInfo *ClientInfo `json:"clientInfo,omitempty"`
// Locale is the locale the client is currently showing the user interface
// in. This must not necessarily be the locale of the operating
// system.
//
// Uses IETF language tags as the value's syntax
// (See https://en.wikipedia.org/wiki/IETF_language_tag)
//
// @since 3.16.0.
Locale string `json:"locale,omitempty"`
// RootPath is the rootPath of the workspace. Is null
// if no folder is open.
//
// Deprecated: Use RootURI instead.
RootPath string `json:"rootPath,omitempty"`
// RootURI is the rootUri of the workspace. Is null if no
// folder is open. If both `rootPath` and "rootUri" are set
// "rootUri" wins.
//
// Deprecated: Use WorkspaceFolders instead.
RootURI DocumentURI `json:"rootUri,omitempty"`
// InitializationOptions user provided initialization options.
InitializationOptions any `json:"initializationOptions,omitempty"`
// Capabilities is the capabilities provided by the client (editor or tool)
Capabilities ClientCapabilities `json:"capabilities"`
// Trace is the initial trace setting. If omitted trace is disabled ('off').
Trace TraceValue `json:"trace,omitempty"`
// WorkspaceFolders is the workspace folders configured in the client when the server starts.
// This property is only available if the client supports workspace folders.
// It can be `null` if the client supports workspace folders but none are
// configured.
//
// @since 3.6.0.
WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders,omitempty"`
}
// InitializeResult result of ClientCapabilities.
type InitializeResult struct {
// Capabilities is the capabilities the language server provides.
Capabilities ServerCapabilities `json:"capabilities"`
// ServerInfo Information about the server.
//
// @since 3.15.0.
ServerInfo *ServerInfo `json:"serverInfo,omitempty"`
}
// LogTraceParams params of LogTrace notification.
//
// @since 3.16.0.
type LogTraceParams struct {
// Message is the message to be logged.
Message string `json:"message"`
// Verbose is the additional information that can be computed if the "trace" configuration
// is set to "verbose".
Verbose TraceValue `json:"verbose,omitempty"`
}
// SetTraceParams params of SetTrace notification.
//
// @since 3.16.0.
type SetTraceParams struct {
// Value is the new value that should be assigned to the trace setting.
Value TraceValue `json:"value"`
}
// FileOperationPatternKind is a pattern kind describing if a glob pattern matches a file a folder or
// both.
//
// @since 3.16.0.
type FileOperationPatternKind string
// list of FileOperationPatternKind.
const (
// FileOperationPatternKindFile is the pattern matches a file only.
FileOperationPatternKindFile FileOperationPatternKind = "file"
// FileOperationPatternKindFolder is the pattern matches a folder only.
FileOperationPatternKindFolder FileOperationPatternKind = "folder"
)
// FileOperationPatternOptions matching options for the file operation pattern.
//
// @since 3.16.0.
type FileOperationPatternOptions struct {
// IgnoreCase is The pattern should be matched ignoring casing.
IgnoreCase bool `json:"ignoreCase,omitempty"`
}
// FileOperationPattern 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"`
// Matches whether to match files or folders with this pattern.
//
// Matches both if undefined.
Matches FileOperationPatternKind `json:"matches,omitempty"`
// Options additional options used during matching.
Options FileOperationPatternOptions `json:"options,omitempty"`
}
// FileOperationFilter is a filter to describe in which file operation requests or notifications
// the server is interested in.
//
// @since 3.16.0.
type FileOperationFilter struct {
// Scheme is a URI like "file" or "untitled".
Scheme string `json:"scheme,omitempty"`
// Pattern is the actual file operation pattern.
Pattern FileOperationPattern `json:"pattern"`
}
// CreateFilesParams is the parameters sent in notifications/requests for user-initiated creation
// of files.
//
// @since 3.16.0.
type CreateFilesParams struct {
// Files an array of all files/folders created in this operation.
Files []FileCreate `json:"files"`
}
// FileCreate nepresents information on a file/folder create.
//
// @since 3.16.0.
type FileCreate struct {
// URI is a file:// URI for the location of the file/folder being created.
URI string `json:"uri"`
}
// RenameFilesParams is the parameters sent in notifications/requests for user-initiated renames
// of files.
//
// @since 3.16.0.
type RenameFilesParams struct {
// Files 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"`
}
// FileRename represents information on a file/folder rename.
//
// @since 3.16.0.
type FileRename struct {
// OldURI is a file:// URI for the original location of the file/folder being renamed.
OldURI string `json:"oldUri"`
// NewURI is a file:// URI for the new location of the file/folder being renamed.
NewURI string `json:"newUri"`
}
// DeleteFilesParams is the parameters sent in notifications/requests for user-initiated deletes
// of files.
//
// @since 3.16.0.
type DeleteFilesParams struct {
// Files an array of all files/folders deleted in this operation.
Files []FileDelete `json:"files"`
}
// FileDelete represents information on a file/folder delete.
//
// @since 3.16.0.
type FileDelete struct {
// URI is a file:// URI for the location of the file/folder being deleted.
URI string `json:"uri"`
}
// DocumentHighlightParams params of DocumentHighlight request.
//
// @since 3.15.0.
type DocumentHighlightParams struct {
TextDocumentPositionParams
WorkDoneProgressParams
PartialResultParams
}
// DeclarationParams params of Declaration request.
//
// @since 3.15.0.
type DeclarationParams struct {
TextDocumentPositionParams
WorkDoneProgressParams
PartialResultParams
}
// DefinitionParams params of Definition request.
//
// @since 3.15.0.
type DefinitionParams struct {
TextDocumentPositionParams
WorkDoneProgressParams
PartialResultParams
}
// TypeDefinitionParams params of TypeDefinition request.
//
// @since 3.15.0.
type TypeDefinitionParams struct {
TextDocumentPositionParams
WorkDoneProgressParams
PartialResultParams
}
// ImplementationParams params of Implementation request.
//
// @since 3.15.0.
type ImplementationParams struct {
TextDocumentPositionParams
WorkDoneProgressParams
PartialResultParams
}
// ShowDocumentParams params to show a document.
//
// @since 3.16.0.
type ShowDocumentParams struct {
// URI is the document uri to show.
URI URI `json:"uri"`
// External 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"`
// TakeFocus 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"`
// Selection 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"`
}
// ShowDocumentResult is the result of an show document request.
//
// @since 3.16.0.
type ShowDocumentResult struct {
// Success a boolean indicating if the show was successful.
Success bool `json:"success"`
}
// ServerInfo Information about the server.
//
// @since 3.15.0.
type ServerInfo struct {
// Name is the name of the server as defined by the server.
Name string `json:"name"`
// Version is the server's version as defined by the server.
Version string `json:"version,omitempty"`
}
// InitializeError known error codes for an "InitializeError".
type InitializeError struct {
// Retry indicates whether the client execute the following retry logic:
// (1) show the message provided by the ResponseError to the user
// (2) user selects retry or cancel
// (3) if user selected retry the initialize method is sent again.
Retry bool `json:"retry,omitempty"`
}
// ReferencesOptions ReferencesProvider options.
//
// @since 3.15.0.
type ReferencesOptions struct {
WorkDoneProgressOptions
}
// WorkDoneProgressOptions WorkDoneProgress options.
//
// @since 3.15.0.
type WorkDoneProgressOptions struct {
WorkDoneProgress bool `json:"workDoneProgress,omitempty"`
}
// LinkedEditingRangeParams params for the LinkedEditingRange request.
//
// @since 3.16.0.
type LinkedEditingRangeParams struct {
TextDocumentPositionParams
WorkDoneProgressParams
}
// LinkedEditingRanges result of LinkedEditingRange request.
//
// @since 3.16.0.
type LinkedEditingRanges struct {
// Ranges 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"`
// WordPattern 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"`
}
// MonikerParams params for the Moniker request.
//
// @since 3.16.0.
type MonikerParams struct {
TextDocumentPositionParams
WorkDoneProgressParams
PartialResultParams
}
// UniquenessLevel is the Moniker uniqueness level to define scope of the moniker.
//
// @since 3.16.0.
type UniquenessLevel string
// list of UniquenessLevel.
const (
// UniquenessLevelDocument is the moniker is only unique inside a document.
UniquenessLevelDocument UniquenessLevel = "document"
// UniquenessLevelProject is the moniker is unique inside a project for which a dump got created.
UniquenessLevelProject UniquenessLevel = "project"
// UniquenessLevelGroup is the moniker is unique inside the group to which a project belongs.
UniquenessLevelGroup UniquenessLevel = "group"
// UniquenessLevelScheme is the moniker is unique inside the moniker scheme.
UniquenessLevelScheme UniquenessLevel = "scheme"
// UniquenessLevelGlobal is the moniker is globally unique.
UniquenessLevelGlobal UniquenessLevel = "global"
)
// MonikerKind is the moniker kind.
//
// @since 3.16.0.
type MonikerKind string
// list of MonikerKind.
const (
// MonikerKindImport is the moniker represent a symbol that is imported into a project.
MonikerKindImport MonikerKind = "import"
// MonikerKindExport is the moniker represents a symbol that is exported from a project.
MonikerKindExport MonikerKind = "export"
// MonikerKindLocal is 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.
//
// @since 3.16.0.
type Moniker struct {
// Scheme is the scheme of the moniker. For example tsc or .Net.
Scheme string `json:"scheme"`
// Identifier is 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"`
// Unique is the scope in which the moniker is unique.
Unique UniquenessLevel `json:"unique"`
// Kind is the moniker kind if known.
Kind MonikerKind `json:"kind,omitempty"`
}
// StaticRegistrationOptions staticRegistration options to be returned in the initialize request.
type StaticRegistrationOptions struct {
// ID is 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"`
}
// DocumentLinkRegistrationOptions DocumentLinkRegistration options.
type DocumentLinkRegistrationOptions struct {
TextDocumentRegistrationOptions
// ResolveProvider document links have a resolve provider as well.
ResolveProvider bool `json:"resolveProvider,omitempty"`
}
// InitializedParams params of Initialized notification.
type InitializedParams struct{}
// WorkspaceFolders represents a slice of WorkspaceFolder.
type WorkspaceFolders []WorkspaceFolder

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"context"
"fmt"
"encoding/json"
"github.com/a-h/templ/lsp/jsonrpc2"
"github.com/a-h/templ/lsp/xcontext"
)
// CancelHandler handler of cancelling.
func CancelHandler(handler jsonrpc2.Handler) jsonrpc2.Handler {
handler, canceller := jsonrpc2.CancelHandler(handler)
h := func(ctx context.Context, reply jsonrpc2.Replier, req jsonrpc2.Request) error {
if req.Method() != MethodCancelRequest {
// TODO(iancottrell): See if we can generate a reply for the request to be cancelled
// at the point of cancellation rather than waiting for gopls to naturally reply.
// To do that, we need to keep track of whether a reply has been sent already and
// be careful about racing between the two paths.
// TODO(iancottrell): Add a test that watches the stream and verifies the response
// for the cancelled request flows.
reply := func(ctx context.Context, resp any, err error) error {
// https://microsoft.github.io/language-server-protocol/specifications/specification-current/#cancelRequest
if ctx.Err() != nil && err == nil {
err = ErrRequestCancelled
}
ctx = xcontext.Detach(ctx)
return reply(ctx, resp, err)
}
return handler(ctx, reply, req)
}
var params CancelParams
if err := json.Unmarshal(req.Params(), &params); err != nil {
return replyParseError(ctx, reply, err)
}
switch id := params.ID.(type) {
case int32:
canceller(jsonrpc2.NewNumberID(id))
case string:
canceller(jsonrpc2.NewStringID(id))
default:
return replyParseError(ctx, reply, fmt.Errorf("request ID %v malformed", id))
}
return reply(ctx, nil, nil)
}
return h
}
// Handlers default jsonrpc2.Handler.
func Handlers(handler jsonrpc2.Handler) jsonrpc2.Handler {
return CancelHandler(
jsonrpc2.AsyncHandler(
jsonrpc2.ReplyHandler(handler),
),
)
}
// Call calls method to params and result.
func Call(ctx context.Context, conn jsonrpc2.Conn, method string, params, result any) error {
id, err := conn.Call(ctx, method, params, result)
if ctx.Err() != nil {
notifyCancel(ctx, conn, id)
}
return err
}
func notifyCancel(ctx context.Context, conn jsonrpc2.Conn, id jsonrpc2.ID) {
ctx = xcontext.Detach(ctx)
// Note that only *jsonrpc2.ID implements json.Marshaler.
_ = conn.Notify(ctx, MethodCancelRequest, &CancelParams{ID: &id})
}
func replyParseError(ctx context.Context, reply jsonrpc2.Replier, err error) error {
return reply(ctx, nil, fmt.Errorf("%s: %w", jsonrpc2.ErrParse, err))
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,119 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
// WorkDoneProgressKind kind of WorkDoneProgress.
//
// @since 3.15.0.
type WorkDoneProgressKind string
// list of WorkDoneProgressKind.
const (
// WorkDoneProgressKindBegin kind of WorkDoneProgressBegin.
WorkDoneProgressKindBegin WorkDoneProgressKind = "begin"
// WorkDoneProgressKindReport kind of WorkDoneProgressReport.
WorkDoneProgressKindReport WorkDoneProgressKind = "report"
// WorkDoneProgressKindEnd kind of WorkDoneProgressEnd.
WorkDoneProgressKindEnd WorkDoneProgressKind = "end"
)
// WorkDoneProgressBegin is the to start progress reporting a "$/progress" notification.
//
// @since 3.15.0.
type WorkDoneProgressBegin struct {
// Kind is the kind of WorkDoneProgressBegin.
//
// It must be WorkDoneProgressKindBegin.
Kind WorkDoneProgressKind `json:"kind"`
// Title 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"`
// Cancellable 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"`
// Message is 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"`
// Percentage is 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.
Percentage uint32 `json:"percentage,omitempty"`
}
// WorkDoneProgressReport is the reporting progress is done.
//
// @since 3.15.0.
type WorkDoneProgressReport struct {
// Kind is the kind of WorkDoneProgressReport.
//
// It must be WorkDoneProgressKindReport.
Kind WorkDoneProgressKind `json:"kind"`
// Cancellable controls enablement state of a cancel button.
//
// Clients that don't support cancellation or don't support controlling the button's
// enablement state are allowed to ignore the property.
Cancellable bool `json:"cancellable,omitempty"`
// Message is 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"`
// Percentage is 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.
Percentage uint32 `json:"percentage,omitempty"`
}
// WorkDoneProgressEnd is the signaling the end of a progress reporting is done.
//
// @since 3.15.0.
type WorkDoneProgressEnd struct {
// Kind is the kind of WorkDoneProgressEnd.
//
// It must be WorkDoneProgressKindEnd.
Kind WorkDoneProgressKind `json:"kind"`
// Message is optional, a final message indicating to for example indicate the outcome
// of the operation.
Message string `json:"message,omitempty"`
}
// WorkDoneProgressParams is a parameter property of report work done progress.
//
// @since 3.15.0.
type WorkDoneProgressParams struct {
// WorkDoneToken an optional token that a server can use to report work done progress.
WorkDoneToken *ProgressToken `json:"workDoneToken,omitempty"`
}
// PartialResultParams is the parameter literal used to pass a partial result token.
//
// @since 3.15.0.
type PartialResultParams struct {
// PartialResultToken an optional token that a server can use to report partial results
// (for example, streaming) to the client.
PartialResultToken *ProgressToken `json:"partialResultToken,omitempty"`
}

View File

@@ -0,0 +1,509 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"fmt"
"testing"
"encoding/json"
"github.com/google/go-cmp/cmp"
)
func TestWorkDoneProgressBegin(t *testing.T) {
t.Parallel()
const (
want = `{"kind":"begin","title":"testTitle","cancellable":true,"message":"testMessage","percentage":30}`
wantNil = `{"kind":"begin","title":"testTitle"}`
wantInvalid = `{"kind":"invalid","title":"invalidTitle","cancellable":false,"message":"invalidMessage","percentage":0}`
)
wantType := WorkDoneProgressBegin{
Kind: WorkDoneProgressKindBegin,
Title: "testTitle",
Cancellable: true,
Message: "testMessage",
Percentage: uint32(30),
}
wantTypeNil := WorkDoneProgressBegin{
Kind: WorkDoneProgressKindBegin,
Title: "testTitle",
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field WorkDoneProgressBegin
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Nil",
field: wantTypeNil,
want: wantNil,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want WorkDoneProgressBegin
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Nil",
field: wantNil,
want: wantTypeNil,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got WorkDoneProgressBegin
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestWorkDoneProgressReport(t *testing.T) {
t.Parallel()
const (
want = `{"kind":"report","cancellable":true,"message":"testMessage","percentage":30}`
wantNil = `{"kind":"report"}`
wantInvalid = `{"kind":"invalid","cancellable":false,"message":"invalidMessage","percentage":0}`
)
wantType := WorkDoneProgressReport{
Kind: WorkDoneProgressKindReport,
Cancellable: true,
Message: "testMessage",
Percentage: uint32(30),
}
wantTypeNil := WorkDoneProgressReport{
Kind: WorkDoneProgressKindReport,
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field WorkDoneProgressReport
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Nil",
field: wantTypeNil,
want: wantNil,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want WorkDoneProgressReport
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Nil",
field: wantNil,
want: wantTypeNil,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got WorkDoneProgressReport
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestWorkDoneProgressEnd(t *testing.T) {
t.Parallel()
const (
want = `{"kind":"end","message":"testMessage"}`
wantNil = `{"kind":"end"}`
wantInvalid = `{"kind":"invalid","message":"invalidMessage"}`
)
wantType := WorkDoneProgressEnd{
Kind: WorkDoneProgressKindEnd,
Message: "testMessage",
}
wantTypeNil := WorkDoneProgressEnd{
Kind: WorkDoneProgressKindEnd,
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field WorkDoneProgressEnd
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Nil",
field: wantTypeNil,
want: wantNil,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want WorkDoneProgressEnd
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Nil",
field: wantNil,
want: wantTypeNil,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got WorkDoneProgressEnd
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestWorkDoneProgressParams(t *testing.T) {
t.Parallel()
const wantWorkDoneToken = "156edea9-9d8d-422f-b7ee-81a84594afbb"
const want = `{"workDoneToken":"` + wantWorkDoneToken + `"}`
wantType := WorkDoneProgressParams{
WorkDoneToken: NewProgressToken(wantWorkDoneToken),
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field WorkDoneProgressParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want WorkDoneProgressParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got WorkDoneProgressParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if workDoneToken := got.WorkDoneToken; workDoneToken != nil {
if diff := cmp.Diff(fmt.Sprint(workDoneToken), wantWorkDoneToken); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
}
})
}
})
}
func TestPartialResultParams(t *testing.T) {
t.Parallel()
const wantPartialResultParams = "156edea9-9d8d-422f-b7ee-81a84594afbb"
const want = `{"partialResultToken":"` + wantPartialResultParams + `"}`
wantType := PartialResultParams{
PartialResultToken: NewProgressToken(wantPartialResultParams),
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field PartialResultParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want PartialResultParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got PartialResultParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if partialResultToken := got.PartialResultToken; partialResultToken != nil {
if diff := cmp.Diff(fmt.Sprint(partialResultToken), wantPartialResultParams); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
}
})
}
})
}

View File

@@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"context"
"log/slog"
"github.com/a-h/templ/lsp/jsonrpc2"
)
// NewServer returns the context in which client is embedded, jsonrpc2.Conn, and the Client.
func NewServer(ctx context.Context, server Server, stream jsonrpc2.Stream, logger *slog.Logger) (context.Context, jsonrpc2.Conn, Client) {
conn := jsonrpc2.NewConn(stream)
cliint := ClientDispatcher(conn, logger.With(slog.String("name", "client")))
ctx = WithClient(ctx, cliint)
conn.Go(ctx,
Handlers(
ServerHandler(logger, server, jsonrpc2.MethodNotFoundHandler),
),
)
return ctx, conn, cliint
}
// NewClient returns the context in which Client is embedded, jsonrpc2.Conn, and the Server.
func NewClient(ctx context.Context, client Client, stream jsonrpc2.Stream, logger *slog.Logger) (context.Context, jsonrpc2.Conn, Server) {
ctx = WithClient(ctx, client)
conn := jsonrpc2.NewConn(stream)
conn.Go(ctx,
Handlers(
ClientHandler(logger, client, jsonrpc2.MethodNotFoundHandler),
),
)
server := ServerDispatcher(conn, logger.With(slog.String("name", "server")))
return ctx, conn, server
}

View File

@@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
// Registration general parameters to register for a capability.
type Registration struct {
// ID is the id used to register the request. The id can be used to deregister
// the request again.
ID string `json:"id"`
// Method is the method / capability to register for.
Method string `json:"method"`
// RegisterOptions options necessary for the registration.
RegisterOptions any `json:"registerOptions,omitempty"`
}
// RegistrationParams params of Register Capability.
type RegistrationParams struct {
Registrations []Registration `json:"registrations"`
}
// TextDocumentRegistrationOptions TextDocumentRegistration options.
type TextDocumentRegistrationOptions struct {
// DocumentSelector 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"`
}
// Unregistration general parameters to unregister a capability.
type Unregistration struct {
// ID is the id used to unregister the request or notification. Usually an id
// provided during the register request.
ID string `json:"id"`
// Method is the method / capability to unregister for.
Method string `json:"method"`
}
// UnregistrationParams params of Unregistration.
type UnregistrationParams struct {
Unregisterations []Unregistration `json:"unregisterations"`
}

View File

@@ -0,0 +1,579 @@
// SPDX-FileCopyrightText: 2020 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"testing"
"encoding/json"
"github.com/google/go-cmp/cmp"
)
func TestRegistration(t *testing.T) {
t.Parallel()
const (
want = `{"id":"1","method":"testMethod","registerOptions":{"foo":"bar"}}`
wantInterfaces = `{"id":"1","method":"testMethod","registerOptions":["foo","bar"]}`
wantNil = `{"id":"1","method":"testMethod"}`
wantInvalid = `{"id":"2","method":"invalidMethod","registerOptions":{"baz":"qux"}}`
)
wantTypeStringInterface := Registration{
ID: "1",
Method: "testMethod",
RegisterOptions: map[string]any{
"foo": "bar",
},
}
wantTypeStringString := Registration{
ID: "1",
Method: "testMethod",
RegisterOptions: map[string]string{
"foo": "bar",
},
}
wantTypeInterfaces := Registration{
ID: "1",
Method: "testMethod",
RegisterOptions: []any{
"foo",
"bar",
},
}
wantTypeNil := Registration{
ID: "1",
Method: "testMethod",
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field Registration
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "ValidStringInterface",
field: wantTypeStringInterface,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidStringString",
field: wantTypeStringString,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidInterfaces",
field: wantTypeInterfaces,
want: wantInterfaces,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantTypeNil,
want: wantNil,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantTypeStringInterface,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want Registration
wantUnmarshalErr bool
wantErr bool
}{
{
name: "ValidStringInterface",
field: want,
want: wantTypeStringInterface,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "ValidInterfaces",
field: wantInterfaces,
want: wantTypeInterfaces,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantNil,
want: wantTypeNil,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantTypeStringInterface,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got Registration
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestRegistrationParams(t *testing.T) {
t.Parallel()
const (
want = `{"registrations":[{"id":"1","method":"testMethod","registerOptions":{"foo":"bar"}}]}`
wantNil = `{"registrations":[{"id":"1","method":"testMethod"}]}`
wantInvalid = `{"registrations":[{"id":"2","method":"invalidMethod","registerOptions":{"baz":"qux"}}]}`
)
wantType := RegistrationParams{
Registrations: []Registration{
{
ID: "1",
Method: "testMethod",
RegisterOptions: map[string]any{
"foo": "bar",
},
},
},
}
wantTypeNil := RegistrationParams{
Registrations: []Registration{
{
ID: "1",
Method: "testMethod",
},
},
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field RegistrationParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantTypeNil,
want: wantNil,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want RegistrationParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantNil,
want: wantTypeNil,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got RegistrationParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestTextDocumentRegistrationOptions(t *testing.T) {
t.Parallel()
const (
want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"},{"language":"cpp","scheme":"untitled","pattern":"*.{cpp,hpp}"}]}`
wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"},{"language":"c","scheme":"untitled","pattern":"*.{c,h}"}]}`
)
wantType := TextDocumentRegistrationOptions{
DocumentSelector: DocumentSelector{
{
Language: "go",
Scheme: "file",
Pattern: "*.go",
},
{
Language: "cpp",
Scheme: "untitled",
Pattern: "*.{cpp,hpp}",
},
},
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field TextDocumentRegistrationOptions
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want TextDocumentRegistrationOptions
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got TextDocumentRegistrationOptions
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestUnregistration(t *testing.T) {
t.Parallel()
const (
want = `{"id":"1","method":"testMethod"}`
wantInvalid = `{"id":"2","method":"invalidMethod"}`
)
wantType := Unregistration{
ID: "1",
Method: "testMethod",
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field Unregistration
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want Unregistration
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got Unregistration
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestUnregistrationParams(t *testing.T) {
t.Parallel()
const (
want = `{"unregisterations":[{"id":"1","method":"testMethod"}]}`
wantInvalid = `{"unregisterations":[{"id":"2","method":"invalidMethod"}]}`
)
wantType := UnregistrationParams{
Unregisterations: []Unregistration{
{
ID: "1",
Method: "testMethod",
},
},
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field UnregistrationParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want UnregistrationParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got UnregistrationParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}

View File

@@ -0,0 +1,110 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
// SelectionRangeProviderOptions selection range provider options interface.
type SelectionRangeProviderOptions any
// SelectionRange represents a selection range represents a part of a selection hierarchy.
//
// A selection range may have a parent selection range that contains it.
//
// @since 3.15.0.
type SelectionRange struct {
// Range is the Range of this selection range.
Range Range `json:"range"`
// Parent is the parent selection range containing this range. Therefore `parent.range` must contain this Range.
Parent *SelectionRange `json:"parent,omitempty"`
}
// EnableSelectionRange is the whether the selection range.
type EnableSelectionRange bool
// compile time check whether the EnableSelectionRange implements a SelectionRangeProviderOptions interface.
var _ SelectionRangeProviderOptions = (*EnableSelectionRange)(nil)
// Value implements SelectionRangeProviderOptions interface.
func (v EnableSelectionRange) Value() any {
return bool(v)
}
// NewEnableSelectionRange returns the new EnableSelectionRange underlying types SelectionRangeProviderOptions.
func NewEnableSelectionRange(enable bool) SelectionRangeProviderOptions {
v := EnableSelectionRange(enable)
return &v
}
// SelectionRangeOptions is the server capability of selection range.
type SelectionRangeOptions struct {
WorkDoneProgressOptions
}
// compile time check whether the EnableSelectionRange implements a SelectionRangeProviderOptions interface.
var _ SelectionRangeProviderOptions = (*EnableSelectionRange)(nil)
// Value implements SelectionRangeProviderOptions interface.
func (v *SelectionRangeOptions) Value() any {
return v
}
// NewSelectionRangeOptions returns the new SelectionRangeOptions underlying types SelectionRangeProviderOptions.
func NewSelectionRangeOptions(enableWorkDoneProgress bool) SelectionRangeProviderOptions {
v := SelectionRangeOptions{
WorkDoneProgressOptions: WorkDoneProgressOptions{
WorkDoneProgress: enableWorkDoneProgress,
},
}
return &v
}
// SelectionRangeRegistrationOptions is the server capability of selection range registration.
type SelectionRangeRegistrationOptions struct {
SelectionRangeOptions
TextDocumentRegistrationOptions
StaticRegistrationOptions
}
// compile time check whether the SelectionRangeRegistrationOptions implements a SelectionRangeProviderOptions interface.
var _ SelectionRangeProviderOptions = (*SelectionRangeRegistrationOptions)(nil)
// Value implements SelectionRangeProviderOptions interface.
func (v *SelectionRangeRegistrationOptions) Value() any {
return v
}
// NewSelectionRangeRegistrationOptions returns the new SelectionRangeRegistrationOptions underlying types SelectionRangeProviderOptions.
func NewSelectionRangeRegistrationOptions(enableWorkDoneProgress bool, selector DocumentSelector, id string) SelectionRangeProviderOptions {
v := SelectionRangeRegistrationOptions{
SelectionRangeOptions: SelectionRangeOptions{
WorkDoneProgressOptions: WorkDoneProgressOptions{
WorkDoneProgress: enableWorkDoneProgress,
},
},
TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{
DocumentSelector: selector,
},
StaticRegistrationOptions: StaticRegistrationOptions{
ID: id,
},
}
return &v
}
// SelectionRangeParams represents a parameter literal used in selection range requests.
//
// @since 3.15.0.
type SelectionRangeParams struct {
WorkDoneProgressParams
PartialResultParams
// TextDocument is the text document.
TextDocument TextDocumentIdentifier `json:"textDocument"`
// Positions is the positions inside the text document.
Positions []Position `json:"positions"`
}

View File

@@ -0,0 +1,179 @@
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
// SemanticTokenTypes represents a type of semantic token.
//
// @since 3.16.0.
type SemanticTokenTypes string
// list of SemanticTokenTypes.
const (
SemanticTokenNamespace SemanticTokenTypes = "namespace"
// Represents a generic type. Acts as a fallback for types which
// can't be mapped to a specific type like class or enum.
SemanticTokenType SemanticTokenTypes = "type"
SemanticTokenClass SemanticTokenTypes = "class"
SemanticTokenEnum SemanticTokenTypes = "enum"
SemanticTokenInterface SemanticTokenTypes = "interface"
SemanticTokenStruct SemanticTokenTypes = "struct"
SemanticTokenTypeParameter SemanticTokenTypes = "typeParameter"
SemanticTokenParameter SemanticTokenTypes = "parameter"
SemanticTokenVariable SemanticTokenTypes = "variable"
SemanticTokenProperty SemanticTokenTypes = "property"
SemanticTokenEnumMember SemanticTokenTypes = "enumMember"
SemanticTokenEvent SemanticTokenTypes = "event"
SemanticTokenFunction SemanticTokenTypes = "function"
SemanticTokenMethod SemanticTokenTypes = "method"
SemanticTokenMacro SemanticTokenTypes = "macro"
SemanticTokenKeyword SemanticTokenTypes = "keyword"
SemanticTokenModifier SemanticTokenTypes = "modifier"
SemanticTokenComment SemanticTokenTypes = "comment"
SemanticTokenString SemanticTokenTypes = "string"
SemanticTokenNumber SemanticTokenTypes = "number"
SemanticTokenRegexp SemanticTokenTypes = "regexp"
SemanticTokenOperator SemanticTokenTypes = "operator"
)
// SemanticTokenModifiers represents a modifiers of semantic token.
//
// @since 3.16.0.
type SemanticTokenModifiers string
// list of SemanticTokenModifiers.
const (
SemanticTokenModifierDeclaration SemanticTokenModifiers = "declaration"
SemanticTokenModifierDefinition SemanticTokenModifiers = "definition"
SemanticTokenModifierReadonly SemanticTokenModifiers = "readonly"
SemanticTokenModifierStatic SemanticTokenModifiers = "static"
SemanticTokenModifierDeprecated SemanticTokenModifiers = "deprecated"
SemanticTokenModifierAbstract SemanticTokenModifiers = "abstract"
SemanticTokenModifierAsync SemanticTokenModifiers = "async"
SemanticTokenModifierModification SemanticTokenModifiers = "modification"
SemanticTokenModifierDocumentation SemanticTokenModifiers = "documentation"
SemanticTokenModifierDefaultLibrary SemanticTokenModifiers = "defaultLibrary"
)
// TokenFormat is an additional token format capability to allow future extensions of the format.
//
// @since 3.16.0.
type TokenFormat string
// TokenFormatRelative described using relative positions.
const TokenFormatRelative TokenFormat = "relative"
// SemanticTokensLegend is the on the capability level types and modifiers are defined using strings.
//
// However the real encoding happens using numbers.
//
// The server therefore needs to let the client know which numbers it is using for which types and modifiers.
//
// @since 3.16.0.
type SemanticTokensLegend struct {
// TokenTypes is the token types a server uses.
TokenTypes []SemanticTokenTypes `json:"tokenTypes"`
// TokenModifiers is the token modifiers a server uses.
TokenModifiers []SemanticTokenModifiers `json:"tokenModifiers"`
}
// SemanticTokensParams params for the SemanticTokensFull request.
//
// @since 3.16.0.
type SemanticTokensParams struct {
WorkDoneProgressParams
PartialResultParams
// TextDocument is the text document.
TextDocument TextDocumentIdentifier `json:"textDocument"`
}
// SemanticTokens is the result of SemanticTokensFull request.
//
// @since 3.16.0.
type SemanticTokens struct {
// ResultID 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"`
// Data is the actual tokens.
Data []uint32 `json:"data"`
}
// SemanticTokensPartialResult is the partial result of SemanticTokensFull request.
//
// @since 3.16.0.
type SemanticTokensPartialResult struct {
// Data is the actual tokens.
Data []uint32 `json:"data"`
}
// SemanticTokensDeltaParams params for the SemanticTokensFullDelta request.
//
// @since 3.16.0.
type SemanticTokensDeltaParams struct {
WorkDoneProgressParams
PartialResultParams
// TextDocument is the text document.
TextDocument TextDocumentIdentifier `json:"textDocument"`
// PreviousResultID is 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"`
}
// SemanticTokensDelta result of SemanticTokensFullDelta request.
//
// @since 3.16.0.
type SemanticTokensDelta struct {
// ResultID is the result id.
//
// This field is readonly.
ResultID string `json:"resultId,omitempty"`
// Edits is the semantic token edits to transform a previous result into a new
// result.
Edits []SemanticTokensEdit `json:"edits"`
}
// SemanticTokensDeltaPartialResult is the partial result of SemanticTokensFullDelta request.
//
// @since 3.16.0.
type SemanticTokensDeltaPartialResult struct {
Edits []SemanticTokensEdit `json:"edits"`
}
// SemanticTokensEdit is the semantic token edit.
//
// @since 3.16.0.
type SemanticTokensEdit struct {
// Start is the start offset of the edit.
Start uint32 `json:"start"`
// DeleteCount is the count of elements to remove.
DeleteCount uint32 `json:"deleteCount"`
// Data is the elements to insert.
Data []uint32 `json:"data,omitempty"`
}
// SemanticTokensRangeParams params for the SemanticTokensRange request.
//
// @since 3.16.0.
type SemanticTokensRangeParams struct {
WorkDoneProgressParams
PartialResultParams
// TextDocument is the text document.
TextDocument TextDocumentIdentifier `json:"textDocument"`
// Range is the range the semantic tokens are requested for.
Range Range `json:"range"`
}

1893
templ/lsp/protocol/server.go Normal file

File diff suppressed because it is too large Load Diff

111
templ/lsp/protocol/text.go Normal file
View File

@@ -0,0 +1,111 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"strconv"
)
// DidOpenTextDocumentParams params of DidOpenTextDocument notification.
type DidOpenTextDocumentParams struct {
// TextDocument is the document that was opened.
TextDocument TextDocumentItem `json:"textDocument"`
}
// DidChangeTextDocumentParams params of DidChangeTextDocument notification.
type DidChangeTextDocumentParams struct {
// TextDocument is the document that did change. The version number points
// to the version after all provided content changes have
// been applied.
TextDocument VersionedTextDocumentIdentifier `json:"textDocument"`
// ContentChanges is the actual content changes. The content changes describe single state changes
// to the document. So if there are two content changes c1 and c2 for a document
// in state S then c1 move the document to S' and c2 to S''.
ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"` // []TextDocumentContentChangeEvent | text
}
// TextDocumentSaveReason represents reasons why a text document is saved.
type TextDocumentSaveReason float64
const (
// TextDocumentSaveReasonManual is the manually triggered, e.g. by the user pressing save, by starting debugging,
// or by an API call.
TextDocumentSaveReasonManual TextDocumentSaveReason = 1
// TextDocumentSaveReasonAfterDelay is the automatic after a delay.
TextDocumentSaveReasonAfterDelay TextDocumentSaveReason = 2
// TextDocumentSaveReasonFocusOut when the editor lost focus.
TextDocumentSaveReasonFocusOut TextDocumentSaveReason = 3
)
// String implements fmt.Stringer.
func (t TextDocumentSaveReason) String() string {
switch t {
case TextDocumentSaveReasonManual:
return "Manual"
case TextDocumentSaveReasonAfterDelay:
return "AfterDelay"
case TextDocumentSaveReasonFocusOut:
return "FocusOut"
default:
return strconv.FormatFloat(float64(t), 'f', -10, 64)
}
}
// TextDocumentChangeRegistrationOptions describe options to be used when registering for text document change events.
type TextDocumentChangeRegistrationOptions struct {
TextDocumentRegistrationOptions
// SyncKind how documents are synced to the server. See TextDocumentSyncKind.Full
// and TextDocumentSyncKind.Incremental.
SyncKind TextDocumentSyncKind `json:"syncKind"`
}
// WillSaveTextDocumentParams is the parameters send in a will save text document notification.
type WillSaveTextDocumentParams struct {
// TextDocument is the document that will be saved.
TextDocument TextDocumentIdentifier `json:"textDocument"`
// Reason is the 'TextDocumentSaveReason'.
Reason TextDocumentSaveReason `json:"reason,omitempty"`
}
// DidSaveTextDocumentParams params of DidSaveTextDocument notification.
type DidSaveTextDocumentParams struct {
// Text optional the content when saved. Depends on the includeText value
// when the save notification was requested.
Text string `json:"text,omitempty"`
// TextDocument is the document that was saved.
TextDocument TextDocumentIdentifier `json:"textDocument"`
}
// TextDocumentContentChangeEvent 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 {
// Range is the range of the document that changed.
Range *Range `json:"range,omitempty"`
// RangeLength is the length of the range that got replaced.
RangeLength uint32 `json:"rangeLength,omitempty"`
// Text is the new text of the document.
Text string `json:"text"`
}
// TextDocumentSaveRegistrationOptions TextDocumentSave Registration options.
type TextDocumentSaveRegistrationOptions struct {
TextDocumentRegistrationOptions
// IncludeText is the client is supposed to include the content on save.
IncludeText bool `json:"includeText,omitempty"`
}
// DidCloseTextDocumentParams params of DidCloseTextDocument notification.
type DidCloseTextDocumentParams struct {
// TextDocument the document that was closed.
TextDocument TextDocumentIdentifier `json:"textDocument"`
}

View File

@@ -0,0 +1,930 @@
// SPDX-FileCopyrightText: 2020 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"testing"
"encoding/json"
"github.com/google/go-cmp/cmp"
"github.com/a-h/templ/lsp/uri"
)
func TestDidOpenTextDocumentParams(t *testing.T) {
t.Parallel()
const (
want = `{"textDocument":{"uri":"file:///path/to/basic.go","languageId":"go","version":10,"text":"Go Language"}}`
wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go","languageId":"cpp","version":10,"text":"C++ Language"}}`
)
wantType := DidOpenTextDocumentParams{
TextDocument: TextDocumentItem{
URI: uri.File("/path/to/basic.go"),
LanguageID: GoLanguage,
Version: int32(10),
Text: "Go Language",
},
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field DidOpenTextDocumentParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want DidOpenTextDocumentParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got DidOpenTextDocumentParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestDidChangeTextDocumentParams(t *testing.T) {
t.Parallel()
const (
want = `{"textDocument":{"uri":"file:///path/to/test.go","version":10},"contentChanges":[{"range":{"start":{"line":25,"character":1},"end":{"line":25,"character":3}},"rangeLength":2,"text":"testText"}]}`
wantInvalid = `{"textDocument":{"uri":"file:///path/to/test.go","version":10},"contentChanges":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":4}},"rangeLength":3,"text":"invalidText"}]}`
)
wantType := DidChangeTextDocumentParams{
TextDocument: VersionedTextDocumentIdentifier{
TextDocumentIdentifier: TextDocumentIdentifier{
URI: uri.File("/path/to/test.go"),
},
Version: int32(10),
},
ContentChanges: []TextDocumentContentChangeEvent{
{
Range: &Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 25,
Character: 3,
},
},
RangeLength: 2,
Text: "testText",
},
},
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field DidChangeTextDocumentParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want DidChangeTextDocumentParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got DidChangeTextDocumentParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestTextDocumentSaveReason_String(t *testing.T) {
t.Parallel()
tests := []struct {
name string
k TextDocumentSaveReason
want string
}{
{
name: "Manual",
k: TextDocumentSaveReasonManual,
want: "Manual",
},
{
name: "AfterDelay",
k: TextDocumentSaveReasonAfterDelay,
want: "AfterDelay",
},
{
name: "FocusOut",
k: TextDocumentSaveReasonFocusOut,
want: "FocusOut",
},
{
name: "Unknown",
k: TextDocumentSaveReason(0),
want: "0",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := tt.k.String(); got != tt.want {
t.Errorf("TextDocumentSaveReason.String() = %v, want %v", tt.want, got)
}
})
}
}
func TestTextDocumentContentChangeEvent(t *testing.T) {
t.Parallel()
const (
want = `{"range":{"start":{"line":25,"character":1},"end":{"line":25,"character":3}},"rangeLength":2,"text":"testText"}`
wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":4}},"rangeLength":3,"text":"invalidText"}`
wantReplaceAll = `{"text":"replace all"}`
)
wantType := TextDocumentContentChangeEvent{
Range: &Range{
Start: Position{
Line: 25,
Character: 1,
},
End: Position{
Line: 25,
Character: 3,
},
},
RangeLength: 2,
Text: "testText",
}
wantReplaceAllType := TextDocumentContentChangeEvent{
Text: "replace all",
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field TextDocumentContentChangeEvent
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
{
name: "ReplaceAll",
field: wantReplaceAllType,
want: wantReplaceAll,
wantMarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want TextDocumentContentChangeEvent
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got TextDocumentContentChangeEvent
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestTextDocumentChangeRegistrationOptions(t *testing.T) {
t.Parallel()
const (
want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}],"syncKind":2}`
wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"syncKind":1}`
)
wantType := TextDocumentChangeRegistrationOptions{
TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{
DocumentSelector: DocumentSelector{
{
Language: "go",
Scheme: "file",
Pattern: "*.go",
},
},
},
SyncKind: 2,
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field TextDocumentChangeRegistrationOptions
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want TextDocumentChangeRegistrationOptions
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got TextDocumentChangeRegistrationOptions
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestWillSaveTextDocumentParams(t *testing.T) {
t.Parallel()
const (
want = `{"textDocument":{"uri":"file:///path/to/test.go"},"reason":3}`
wantNilAll = `{"textDocument":{"uri":"file:///path/to/test.go"}}`
wantInvalid = `{"textDocument":{"uri":"file:///path/to/invalid.go"},"reason":1}`
)
wantType := WillSaveTextDocumentParams{
TextDocument: TextDocumentIdentifier{
URI: uri.File("/path/to/test.go"),
},
Reason: TextDocumentSaveReasonFocusOut,
}
wantTypeNilAll := WillSaveTextDocumentParams{
TextDocument: TextDocumentIdentifier{
URI: uri.File("/path/to/test.go"),
},
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field WillSaveTextDocumentParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantTypeNilAll,
want: wantNilAll,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want WillSaveTextDocumentParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantNilAll,
want: wantTypeNilAll,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got WillSaveTextDocumentParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestDidSaveTextDocumentParams(t *testing.T) {
t.Parallel()
const (
want = `{"text":"testText","textDocument":{"uri":"file:///path/to/test.go"}}`
wantNilAll = `{"textDocument":{"uri":"file:///path/to/test.go"}}`
wantInvalid = `{"text":"invalidText","textDocument":{"uri":"file:///path/to/invalid.go"}}`
)
wantType := DidSaveTextDocumentParams{
Text: "testText",
TextDocument: TextDocumentIdentifier{
URI: uri.File("/path/to/test.go"),
},
}
wantTypeNilAll := DidSaveTextDocumentParams{
TextDocument: TextDocumentIdentifier{
URI: uri.File("/path/to/test.go"),
},
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field DidSaveTextDocumentParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantTypeNilAll,
want: wantNilAll,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want DidSaveTextDocumentParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantNilAll,
want: wantTypeNilAll,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got DidSaveTextDocumentParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestTextDocumentSaveRegistrationOptions(t *testing.T) {
t.Parallel()
const (
want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}],"includeText":true}`
wantNilAll = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}]}`
wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"includeText":false}`
)
wantType := TextDocumentSaveRegistrationOptions{
TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{
DocumentSelector: DocumentSelector{
{
Language: "go",
Scheme: "file",
Pattern: "*.go",
},
},
},
IncludeText: true,
}
wantTypeNilAll := TextDocumentSaveRegistrationOptions{
TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{
DocumentSelector: DocumentSelector{
{
Language: "go",
Scheme: "file",
Pattern: "*.go",
},
},
},
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field TextDocumentSaveRegistrationOptions
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantTypeNilAll,
want: wantNilAll,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want TextDocumentSaveRegistrationOptions
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "ValidNilAll",
field: wantNilAll,
want: wantTypeNilAll,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got TextDocumentSaveRegistrationOptions
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestDidCloseTextDocumentParams(t *testing.T) {
t.Parallel()
const (
want = `{"textDocument":{"uri":"file:///path/to/test.go"}}`
wantInvalid = `{"textDocument":{"uri":"file:///path/to/invalid.go"}}`
)
wantType := DidCloseTextDocumentParams{
TextDocument: TextDocumentIdentifier{
URI: uri.File("/path/to/test.go"),
},
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field DidCloseTextDocumentParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want DidCloseTextDocumentParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got DidCloseTextDocumentParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}

View File

@@ -0,0 +1,9 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
// NewVersion returns the int32 pointer converted i.
func NewVersion(i int32) *int32 {
return &i
}

View File

@@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2020 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"testing"
)
func TestNewVersion(t *testing.T) {
t.Parallel()
tests := []struct {
name string
i int32
}{
{
name: "Valid",
i: 5000,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
want := NewVersion(tt.i)
if got := NewVersion(tt.i); *got != *want {
t.Errorf("NewVersion(%v) = %v, want %v", tt.i, *got, *want)
}
})
}
}

View File

@@ -0,0 +1,7 @@
// SPDX-FileCopyrightText: 2018 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
// Version is the version of the language-server-protocol specification being implemented.
const Version = "3.15.3"

View File

@@ -0,0 +1,111 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import "strconv"
// ShowMessageParams params of ShowMessage notification.
type ShowMessageParams struct {
// Message is the actual message.
Message string `json:"message"`
// Type is the message type.
Type MessageType `json:"type"`
}
// MessageType type of ShowMessageParams type.
type MessageType float64
const (
// MessageTypeError an error message.
MessageTypeError MessageType = 1
// MessageTypeWarning a warning message.
MessageTypeWarning MessageType = 2
// MessageTypeInfo an information message.
MessageTypeInfo MessageType = 3
// MessageTypeLog a log message.
MessageTypeLog MessageType = 4
)
// String implements fmt.Stringer.
func (m MessageType) String() string {
switch m {
case MessageTypeError:
return "error"
case MessageTypeWarning:
return "warning"
case MessageTypeInfo:
return "info"
case MessageTypeLog:
return "log"
default:
return strconv.FormatFloat(float64(m), 'f', -10, 64)
}
}
// Enabled reports whether the level is enabled.
func (m MessageType) Enabled(level MessageType) bool {
return level > 0 && m >= level
}
// messageTypeMap map of MessageTypes.
var messageTypeMap = map[string]MessageType{
"error": MessageTypeError,
"warning": MessageTypeWarning,
"info": MessageTypeInfo,
"log": MessageTypeLog,
}
// ToMessageType converts level to the MessageType.
func ToMessageType(level string) MessageType {
mt, ok := messageTypeMap[level]
if !ok {
return MessageType(0) // unknown
}
return mt
}
// ShowMessageRequestParams params of ShowMessage request.
type ShowMessageRequestParams struct {
// Actions is the message action items to present.
Actions []MessageActionItem `json:"actions"`
// Message is the actual message
Message string `json:"message"`
// Type is the message type. See {@link MessageType}
Type MessageType `json:"type"`
}
// MessageActionItem item of ShowMessageRequestParams action.
type MessageActionItem struct {
// Title a short title like 'Retry', 'Open Log' etc.
Title string `json:"title"`
}
// LogMessageParams params of LogMessage notification.
type LogMessageParams struct {
// Message is the actual message
Message string `json:"message"`
// Type is the message type. See {@link MessageType}
Type MessageType `json:"type"`
}
// WorkDoneProgressCreateParams params of WorkDoneProgressCreate request.
//
// @since 3.15.0.
type WorkDoneProgressCreateParams struct {
// Token is the token to be used to report progress.
Token ProgressToken `json:"token"`
}
// WorkDoneProgressCreateParams params of WorkDoneProgressCancel request.
//
// @since 3.15.0.
type WorkDoneProgressCancelParams struct {
// Token is the token to be used to report progress.
Token ProgressToken `json:"token"`
}

View File

@@ -0,0 +1,793 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"fmt"
"strconv"
"testing"
"encoding/json"
"github.com/google/go-cmp/cmp"
)
func TestShowMessageParams(t *testing.T) {
t.Parallel()
const (
want = `{"message":"error message","type":1}`
wantUnknown = `{"message":"unknown message","type":0}`
)
wantType := ShowMessageParams{
Message: "error message",
Type: MessageTypeError,
}
wantTypeUnkonwn := ShowMessageParams{
Message: "unknown message",
Type: MessageType(0),
}
t.Run("Marshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field ShowMessageParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Unknown",
field: wantTypeUnkonwn,
want: wantUnknown,
wantMarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field string
want ShowMessageParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Unknown",
field: wantUnknown,
want: wantTypeUnkonwn,
wantUnmarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got ShowMessageParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestShowMessageRequestParams(t *testing.T) {
t.Parallel()
const (
want = `{"actions":[{"title":"Retry"}],"message":"error message","type":1}`
wantUnknown = `{"actions":[{"title":"Retry"}],"message":"unknown message","type":0}`
)
wantType := ShowMessageRequestParams{
Actions: []MessageActionItem{
{
Title: "Retry",
},
},
Message: "error message",
Type: MessageTypeError,
}
wantTypeUnkonwn := ShowMessageRequestParams{
Actions: []MessageActionItem{
{
Title: "Retry",
},
},
Message: "unknown message",
Type: MessageType(0),
}
t.Run("Marshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field ShowMessageRequestParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Unknown",
field: wantTypeUnkonwn,
want: wantUnknown,
wantMarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field string
want ShowMessageRequestParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Unknown",
field: wantUnknown,
want: wantTypeUnkonwn,
wantUnmarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got ShowMessageRequestParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestMessageActionItem(t *testing.T) {
t.Parallel()
const (
want = `{"title":"Retry"}`
wantOpenLog = `{"title":"Open Log"}`
)
wantType := MessageActionItem{
Title: "Retry",
}
wantTypeOpenLog := MessageActionItem{
Title: "Open Log",
}
t.Run("Marshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field MessageActionItem
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Unknown",
field: wantTypeOpenLog,
want: wantOpenLog,
wantMarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field string
want MessageActionItem
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Unknown",
field: wantOpenLog,
want: wantTypeOpenLog,
wantUnmarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got MessageActionItem
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestLogMessageParams(t *testing.T) {
t.Parallel()
const (
want = `{"message":"error message","type":1}`
wantUnknown = `{"message":"unknown message","type":0}`
)
wantType := LogMessageParams{
Message: "error message",
Type: MessageTypeError,
}
wantTypeUnknown := LogMessageParams{
Message: "unknown message",
Type: MessageType(0),
}
t.Run("Marshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field LogMessageParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Unknown",
field: wantTypeUnknown,
want: wantUnknown,
wantMarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field string
want LogMessageParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Unknown",
field: wantUnknown,
want: wantTypeUnknown,
wantUnmarshalErr: false,
wantErr: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got LogMessageParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestWorkDoneProgressCreateParams(t *testing.T) {
t.Parallel()
const (
wantToken = int32(1569)
invalidToken = int32(1348)
)
var (
wantString = `{"token":"` + strconv.FormatInt(int64(wantToken), 10) + `"}`
wantInvalidString = `{"token":"` + strconv.FormatInt(int64(invalidToken), 10) + `"}`
wantNumber = `{"token":` + strconv.FormatInt(int64(wantToken), 10) + `}`
wantInvalidNumber = `{"token":` + strconv.FormatInt(int64(invalidToken), 10) + `}`
)
token := NewProgressToken(strconv.FormatInt(int64(wantToken), 10))
wantTypeString := WorkDoneProgressCreateParams{
Token: *token,
}
numberToken := NewNumberProgressToken(wantToken)
wantTypeNumber := WorkDoneProgressCreateParams{
Token: *numberToken,
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field WorkDoneProgressCreateParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid/String",
field: wantTypeString,
want: wantString,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Valid/Number",
field: wantTypeNumber,
want: wantNumber,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid/String",
field: wantTypeString,
want: wantInvalidString,
wantMarshalErr: false,
wantErr: true,
},
{
name: "Invalid/Number",
field: wantTypeNumber,
want: wantInvalidNumber,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want WorkDoneProgressCreateParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid/String",
field: wantString,
want: wantTypeString,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Valid/Number",
field: wantNumber,
want: wantTypeNumber,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid/String",
field: wantInvalidString,
want: wantTypeString,
wantUnmarshalErr: false,
wantErr: true,
},
{
name: "Invalid/Number",
field: wantInvalidNumber,
want: wantTypeNumber,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got WorkDoneProgressCreateParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(fmt.Sprint(got.Token), strconv.FormatInt(int64(wantToken), 10)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestWorkDoneProgressCancelParams(t *testing.T) {
t.Parallel()
const (
wantToken = int32(1569)
invalidToken = int32(1348)
)
var (
want = `{"token":` + strconv.FormatInt(int64(wantToken), 10) + `}`
wantInvalid = `{"token":` + strconv.FormatInt(int64(invalidToken), 10) + `}`
)
token := NewNumberProgressToken(wantToken)
wantType := WorkDoneProgressCancelParams{
Token: *token,
}
t.Run("Marshal", func(t *testing.T) {
tests := []struct {
name string
field WorkDoneProgressCancelParams
want string
wantMarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: wantType,
want: want,
wantMarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantType,
want: wantInvalid,
wantMarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := json.Marshal(&tt.field)
if (err != nil) != tt.wantMarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
t.Run("Unmarshal", func(t *testing.T) {
tests := []struct {
name string
field string
want WorkDoneProgressCancelParams
wantUnmarshalErr bool
wantErr bool
}{
{
name: "Valid",
field: want,
want: wantType,
wantUnmarshalErr: false,
wantErr: false,
},
{
name: "Invalid",
field: wantInvalid,
want: wantType,
wantUnmarshalErr: false,
wantErr: true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var got WorkDoneProgressCancelParams
if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr {
t.Fatal(err)
}
if diff := cmp.Diff(fmt.Sprint(got.Token), strconv.FormatInt(int64(wantToken), 10)); (diff != "") != tt.wantErr {
t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff)
}
})
}
})
}
func TestMessageType_String(t *testing.T) {
t.Parallel()
tests := []struct {
name string
m MessageType
want string
}{
{
name: "Error",
m: MessageTypeError,
want: "error",
},
{
name: "Warning",
m: MessageTypeWarning,
want: "warning",
},
{
name: "Info",
m: MessageTypeInfo,
want: "info",
},
{
name: "Log",
m: MessageTypeLog,
want: "log",
},
{
name: "Unknown",
m: MessageType(0),
want: "0",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := tt.m.String(); got != tt.want {
t.Errorf("MessageType.String() = %v, want %v", tt.want, got)
}
})
}
}
func TestMessageType_Enabled(t *testing.T) {
t.Parallel()
tests := []struct {
name string
m MessageType
level MessageType
want bool
}{
{
name: "ErrorError",
m: MessageTypeError,
level: MessageTypeError,
want: true,
},
{
name: "ErrorInfo",
m: MessageTypeError,
level: MessageTypeInfo,
want: false,
},
{
name: "ErrorUnknown",
m: MessageTypeError,
level: MessageType(0),
want: false,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := tt.m.Enabled(tt.level); got != tt.want {
t.Errorf("MessageType.Enabled(%v) = %v, want %v", tt.level, tt.want, got)
}
})
}
}
func TestToMessageType(t *testing.T) {
t.Parallel()
tests := []struct {
name string
level string
want MessageType
}{
{
name: "Error",
level: "error",
want: MessageTypeError,
},
{
name: "Warning",
level: "warning",
want: MessageTypeWarning,
},
{
name: "Info",
level: "info",
want: MessageTypeInfo,
},
{
name: "Log",
level: "log",
want: MessageTypeLog,
},
{
name: "Unknown",
level: "0",
want: MessageType(0),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := ToMessageType(tt.level); got != tt.want {
t.Errorf("ToMessageType(%v) = %v, want %v", tt.level, tt.want, got)
}
})
}
}

View File

@@ -0,0 +1,213 @@
// SPDX-FileCopyrightText: 2019 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package protocol
import (
"strconv"
"github.com/a-h/templ/lsp/uri"
)
// WorkspaceFolder response of Workspace folders request.
type WorkspaceFolder struct {
// URI is the associated URI for this workspace folder.
URI string `json:"uri"`
// Name is the name of the workspace folder. Used to refer to this
// workspace folder in the user interface.
Name string `json:"name"`
}
// DidChangeWorkspaceFoldersParams params of DidChangeWorkspaceFolders notification.
type DidChangeWorkspaceFoldersParams struct {
// Event is the actual workspace folder change event.
Event WorkspaceFoldersChangeEvent `json:"event"`
}
// WorkspaceFoldersChangeEvent is the workspace folder change event.
type WorkspaceFoldersChangeEvent struct {
// Added is the array of added workspace folders
Added []WorkspaceFolder `json:"added"`
// Removed is the array of the removed workspace folders
Removed []WorkspaceFolder `json:"removed"`
}
// DidChangeConfigurationParams params of DidChangeConfiguration notification.
type DidChangeConfigurationParams struct {
// Settings is the actual changed settings
Settings any `json:"settings,omitempty"`
}
// ConfigurationParams params of Configuration request.
type ConfigurationParams struct {
Items []ConfigurationItem `json:"items"`
}
// ConfigurationItem a ConfigurationItem consists of the configuration section to ask for and an additional scope URI.
// The configuration section ask for is defined by the server and doesnt necessarily need to correspond to the configuration store used be the client.
// So a server might ask for a configuration cpp.formatterOptions but the client stores the configuration in a XML store layout differently.
// It is up to the client to do the necessary conversion. If a scope URI is provided the client should return the setting scoped to the provided resource.
// If the client for example uses EditorConfig to manage its settings the configuration should be returned for the passed resource URI. If the client cant provide a configuration setting for a given scope then null need to be present in the returned array.
type ConfigurationItem struct {
// ScopeURI is the scope to get the configuration section for.
ScopeURI uri.URI `json:"scopeUri,omitempty"`
// Section is the configuration section asked for.
Section string `json:"section,omitempty"`
}
// DidChangeWatchedFilesParams params of DidChangeWatchedFiles notification.
type DidChangeWatchedFilesParams struct {
// Changes is the actual file events.
Changes []*FileEvent `json:"changes,omitempty"`
}
// FileEvent an event describing a file change.
type FileEvent struct {
// Type is the change type.
Type FileChangeType `json:"type"`
// URI is the file's URI.
URI uri.URI `json:"uri"`
}
// FileChangeType is the file event type.
type FileChangeType float64
const (
// FileChangeTypeCreated is the file got created.
FileChangeTypeCreated FileChangeType = 1
// FileChangeTypeChanged is the file got changed.
FileChangeTypeChanged FileChangeType = 2
// FileChangeTypeDeleted is the file got deleted.
FileChangeTypeDeleted FileChangeType = 3
)
// String implements fmt.Stringer.
func (t FileChangeType) String() string {
switch t {
case FileChangeTypeCreated:
return "Created"
case FileChangeTypeChanged:
return "Changed"
case FileChangeTypeDeleted:
return "Deleted"
default:
return strconv.FormatFloat(float64(t), 'f', -10, 64)
}
}
// DidChangeWatchedFilesRegistrationOptions describe options to be used when registering for file system change events.
type DidChangeWatchedFilesRegistrationOptions struct {
// Watchers is the watchers to register.
Watchers []FileSystemWatcher `json:"watchers"`
}
// FileSystemWatcher watchers of DidChangeWatchedFiles Registration options.
type FileSystemWatcher struct {
// GlobPattern is 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"`
// Kind is the kind of events of interest. If omitted it defaults
// to WatchKind.Create | WatchKind.Change | WatchKind.Delete
// which is 7.
Kind WatchKind `json:"kind,omitempty"`
}
// WatchKind kind of FileSystemWatcher kind.
type WatchKind float64
const (
// WatchKindCreate interested in create events.
WatchKindCreate WatchKind = 1
// WatchKindChange interested in change events.
WatchKindChange WatchKind = 2
// WatchKindDelete interested in delete events.
WatchKindDelete WatchKind = 4
)
// String implements fmt.Stringer.
func (k WatchKind) String() string {
switch k {
case WatchKindCreate:
return "Create"
case WatchKindChange:
return "Change"
case WatchKindDelete:
return "Delete"
default:
return strconv.FormatFloat(float64(k), 'f', -10, 64)
}
}
// WorkspaceSymbolParams is the parameters of a Workspace Symbol request.
type WorkspaceSymbolParams struct {
WorkDoneProgressParams
PartialResultParams
// Query a query string to filter symbols by.
//
// Clients may send an empty string here to request all symbols.
Query string `json:"query"`
}
// ExecuteCommandParams params of Execute a command.
type ExecuteCommandParams struct {
WorkDoneProgressParams
// Command is the identifier of the actual command handler.
Command string `json:"command"`
// Arguments that the command should be invoked with.
Arguments []any `json:"arguments,omitempty"`
}
// ExecuteCommandRegistrationOptions execute command registration options.
type ExecuteCommandRegistrationOptions struct {
// Commands is the commands to be executed on the server
Commands []string `json:"commands"`
}
// ApplyWorkspaceEditParams params of Applies a WorkspaceEdit.
type ApplyWorkspaceEditParams struct {
// Label 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"`
// Edit is the edits to apply.
Edit WorkspaceEdit `json:"edit"`
}
// ApplyWorkspaceEditResponse response of Applies a WorkspaceEdit.
type ApplyWorkspaceEditResponse struct {
// Applied indicates whether the edit was applied or not.
Applied bool `json:"applied"`
// FailureReason 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.
//
// @since 3.16.0.
FailureReason string `json:"failureReason,omitempty"`
// FailedChange 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.
//
// @since 3.16.0.
FailedChange uint32 `json:"failedChange,omitempty"`
}

File diff suppressed because it is too large Load Diff