internal/lsp: the core lsp protocol

This is not intended to be a user friendly package, just the rawest correct
implemenation of the protocol as a building block

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