lsp

package
v1.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 16, 2026 License: GPL-3.0 Imports: 15 Imported by: 0

Documentation

Overview

Package lsp provides a Language Server Protocol (LSP) client system for communicating with language servers using JSON-RPC 2.0 over stdio or TCP.

The package implements a layered architecture:

  • models.go: Core LSP data types (Diagnostic, Position, Range, Location, etc.)
  • protocol.go: JSON-RPC 2.0 transport and connection management
  • client.go: LSP client interface for single-server communication
  • server.go: ServerManager for multi-server lifecycle management

Basic usage:

mgr := lsp.NewServerManager(launcher, lsp.WithMaxParallel(4))
err := mgr.StartServer(ctx, "go")
client, err := mgr.GetClient("go")
diagnostics, err := client.Diagnostics(ctx, "file:///path/to/file.go")
err = mgr.StopServer(ctx, "go")

Error handling uses sentinel errors that can be checked with errors.Is:

if errors.Is(err, lsp.ErrServerNotRunning) {
    // server is not running
}

All long-running operations accept context.Context as the first parameter and respect cancellation and timeout signals.

Index

Constants

View Source
const (
	CodeParseError     = -32700
	CodeInvalidRequest = -32600
	CodeMethodNotFound = -32601
	CodeInvalidParams  = -32602
	CodeInternalError  = -32603
)

Standard JSON-RPC 2.0 error codes.

Variables

View Source
var (
	// ErrServerNotRunning indicates a request was made to a server that is not running.
	ErrServerNotRunning = errors.New("lsp: server not running")

	// ErrServerStartFailed indicates a language server process failed to start.
	ErrServerStartFailed = errors.New("lsp: server failed to start")

	// ErrInitializeFailed indicates the LSP initialize handshake failed.
	ErrInitializeFailed = errors.New("lsp: initialization failed")

	// ErrConnectionClosed indicates the connection to the language server was closed.
	ErrConnectionClosed = errors.New("lsp: connection closed")
)

Sentinel errors for LSP operations.

Functions

func EncodeMessage

func EncodeMessage(body []byte) []byte

EncodeMessage encodes a JSON body with LSP Content-Length headers. This is a utility function for testing and low-level protocol work.

Types

type Client

Client composes all LSP capabilities and communicates with a single Language Server over JSON-RPC 2.0. All methods accept a context.Context for cancellation and timeout control.

This interface composes the following focused interfaces for consumers that only need a subset of functionality:

  • Initializer: Server lifecycle (Initialize, Shutdown)
  • DiagnosticsProvider: Diagnostic retrieval
  • NavigationProvider: References and Definition
  • HoverProvider: Hover information
  • SymbolsProvider: Document symbols

Example usage:

client := lsp.NewClient(conn)
if err := client.Initialize(ctx, "file:///project"); err != nil { ... }
diagnostics, err := client.Diagnostics(ctx, "file:///project/main.go")
if err := client.Shutdown(ctx); err != nil { ... }

func NewClient

func NewClient(conn Conn) Client

NewClient creates a new LSP Client that communicates over the given connection.

type Conn

type Conn interface {
	// Call sends a JSON-RPC request and unmarshals the response result into result.
	// result must be a pointer to the expected response type, or nil.
	Call(ctx context.Context, method string, params any, result any) error

	// Notify sends a JSON-RPC notification (no response expected).
	Notify(ctx context.Context, method string, params any) error

	// Close closes the connection and releases resources.
	Close() error
}

Conn represents a JSON-RPC 2.0 connection that can send requests and notifications.

func NewConn

func NewConn(transport MessageTransport) Conn

NewConn creates a new JSON-RPC connection over the given transport. It starts a background goroutine to read and dispatch responses.

type Diagnostic

type Diagnostic struct {
	// Range is the range at which the message applies.
	Range Range `json:"range"`

	// Severity is the diagnostic's severity level.
	Severity DiagnosticSeverity `json:"severity"`

	// Code is the diagnostic's code (e.g., "E0001"). May be empty.
	Code string `json:"code,omitempty"`

	// Source identifies the tool that produced this diagnostic (e.g., "gopls").
	Source string `json:"source,omitempty"`

	// Message is the diagnostic's human-readable message.
	Message string `json:"message"`
}

Diagnostic represents a compiler error, warning, or informational message.

func (Diagnostic) IsError

func (d Diagnostic) IsError() bool

IsError reports whether this diagnostic is an error.

func (Diagnostic) IsWarning

func (d Diagnostic) IsWarning() bool

IsWarning reports whether this diagnostic is a warning.

type DiagnosticSeverity

type DiagnosticSeverity int

DiagnosticSeverity represents the severity level of a diagnostic. Values match the LSP 3.17 specification.

const (
	// SeverityError reports an error (severity 1).
	SeverityError DiagnosticSeverity = 1

	// SeverityWarning reports a warning (severity 2).
	SeverityWarning DiagnosticSeverity = 2

	// SeverityInfo reports an information message (severity 3).
	SeverityInfo DiagnosticSeverity = 3

	// SeverityHint reports a hint (severity 4).
	SeverityHint DiagnosticSeverity = 4
)

func (DiagnosticSeverity) String

func (s DiagnosticSeverity) String() string

String returns the human-readable name of the severity level.

type DiagnosticsProvider

type DiagnosticsProvider interface {
	// Diagnostics retrieves diagnostics for the given document URI.
	Diagnostics(ctx context.Context, uri string) ([]Diagnostic, error)
}

DiagnosticsProvider provides diagnostic information from the language server. Use this interface when you only need to retrieve diagnostics.

type DocumentSymbol

type DocumentSymbol struct {
	// Name is the symbol's name.
	Name string `json:"name"`

	// Kind is the symbol's kind (function, class, variable, etc.).
	Kind SymbolKind `json:"kind"`

	// Range is the range enclosing this symbol, not including leading/trailing whitespace.
	Range Range `json:"range"`

	// Children contains child symbols (e.g., struct fields, class methods).
	Children []DocumentSymbol `json:"children,omitempty"`
}

DocumentSymbol represents a programming construct like a variable, class, or function that appears in a document. Symbols can be hierarchical via Children.

type HoverProvider

type HoverProvider interface {
	// Hover returns hover information for the symbol at the given position.
	Hover(ctx context.Context, uri string, pos Position) (*HoverResult, error)
}

HoverProvider provides hover information for symbols. Use this interface when you only need hover documentation.

type HoverResult

type HoverResult struct {
	// Contents is the hover information content (may be markdown).
	Contents string `json:"contents"`

	// Range is the optional range for the symbol being hovered.
	Range *Range `json:"range,omitempty"`
}

HoverResult represents the result of a hover request.

type InitializeResult

type InitializeResult struct {
	// Capabilities describes the server's capabilities.
	Capabilities json.RawMessage `json:"capabilities"`
}

InitializeResult represents the result of an LSP initialize request.

type Initializer

type Initializer interface {
	// Initialize sends the LSP initialize request and initialized notification.
	Initialize(ctx context.Context, rootURI string) error

	// Shutdown sends the LSP shutdown request followed by an exit notification.
	Shutdown(ctx context.Context) error
}

Initializer handles LSP server lifecycle management. Use this interface when you only need to start or stop the server.

type JSONRPCError

type JSONRPCError struct {
	// Code is the error code.
	Code int `json:"code"`

	// Message is a short description of the error.
	Message string `json:"message"`

	// Data contains additional information about the error.
	Data json.RawMessage `json:"data,omitempty"`
}

JSONRPCError represents a JSON-RPC 2.0 error object.

func (*JSONRPCError) Error

func (e *JSONRPCError) Error() string

Error implements the error interface for JSONRPCError.

type Location

type Location struct {
	// URI is the resource identifier (e.g., "file:///path/to/file.go").
	URI string `json:"uri"`

	// Range is the range within the resource.
	Range Range `json:"range"`
}

Location represents a location inside a resource, such as a line in a text file.

type ManagerOption

type ManagerOption func(*serverManager)

ManagerOption configures a serverManager.

func WithMaxParallel

func WithMaxParallel(n int) ManagerOption

WithMaxParallel sets the maximum number of concurrent server startups. The default is 4.

type MessageTransport

type MessageTransport interface {
	// ReadMessage reads a complete LSP message and returns the JSON body.
	ReadMessage(ctx context.Context) (json.RawMessage, error)

	// WriteMessage writes a JSON body as a complete LSP message with headers.
	WriteMessage(ctx context.Context, data json.RawMessage) error

	// Close closes the transport connection.
	Close() error
}

MessageTransport handles reading and writing LSP base protocol messages (Content-Length headers + JSON body) over a byte stream.

type NavigationProvider interface {
	// References returns all reference locations for the symbol at the given position.
	References(ctx context.Context, uri string, pos Position) ([]Location, error)

	// Definition returns the definition location(s) for the symbol at the given position.
	Definition(ctx context.Context, uri string, pos Position) ([]Location, error)
}

NavigationProvider provides code navigation features. Use this interface when you only need references or go-to-definition.

type Position

type Position struct {
	// Line is the zero-based line number.
	Line int `json:"line"`

	// Character is the zero-based character offset on the line.
	Character int `json:"character"`
}

Position represents a zero-based position in a text document.

type ProcessHandle

type ProcessHandle interface {
	// Kill forcefully terminates the server process.
	Kill() error

	// Wait blocks until the server process exits.
	Wait() error

	// IsRunning reports whether the server process is still running.
	IsRunning() bool
}

ProcessHandle abstracts a language server process for lifecycle management.

type Range

type Range struct {
	// Start is the range's start position (inclusive).
	Start Position `json:"start"`

	// End is the range's end position (exclusive).
	End Position `json:"end"`
}

Range represents a range in a text document defined by start and end positions.

func (Range) Contains

func (r Range) Contains(pos Position) bool

Contains reports whether the given position is within this range.

type ServerLauncher

type ServerLauncher interface {
	// Launch starts a language server for the given language and returns
	// the initialized client and a handle to the server process.
	Launch(ctx context.Context, lang string) (Client, ProcessHandle, error)
}

ServerLauncher abstracts launching a language server process. Implementations handle process creation, transport setup, and LSP initialization.

Example implementation:

type stdioLauncher struct{}

func (l *stdioLauncher) Launch(ctx context.Context, lang string) (Client, ProcessHandle, error) {
    cmd := exec.CommandContext(ctx, serverPath, args...)
    stdin, _ := cmd.StdinPipe()
    stdout, _ := cmd.StdoutPipe()
    cmd.Start()
    transport := NewStreamTransport(stdout, stdin, cmd)
    conn := NewConn(transport)
    client := NewClient(conn)
    client.Initialize(ctx, rootURI)
    return client, &processHandle{cmd: cmd}, nil
}

type ServerManager

type ServerManager interface {
	// StartServer starts a language server for the given language.
	// Returns nil if the server is already running (idempotent).
	StartServer(ctx context.Context, lang string) error

	// StopServer stops the language server for the given language.
	// Returns nil if the server is not running (idempotent).
	StopServer(ctx context.Context, lang string) error

	// GetClient returns the LSP client for the given language.
	// Returns ErrServerNotRunning if the server is not running.
	GetClient(lang string) (Client, error)

	// ActiveServers returns a sorted list of languages with running servers.
	ActiveServers() []string

	// HealthCheck checks the health of all active servers.
	// Returns a map from language to error (nil means healthy).
	HealthCheck(ctx context.Context) map[string]error

	// StartAll starts servers for all given languages concurrently.
	// Individual failures are non-fatal (graceful degradation).
	StartAll(ctx context.Context, langs []string) error

	// StopAll stops all running servers.
	StopAll(ctx context.Context) error

	// CollectAllDiagnostics collects diagnostics from all active servers concurrently.
	// Individual server errors are non-fatal.
	CollectAllDiagnostics(ctx context.Context, uri string) ([]Diagnostic, error)
}

@MX:ANCHOR: [AUTO] ServerManager is the core interface managing concurrent lifecycle of multi-language servers. All methods are designed to be thread-safe. @MX:REASON: fan_in=10+, entry point for LSP server management, called from multiple locations ServerManager manages multiple language server lifecycles concurrently. All methods are safe for concurrent use.

Example usage:

mgr := lsp.NewServerManager(launcher, lsp.WithMaxParallel(4))
err := mgr.StartAll(ctx, []string{"go", "python", "typescript"})
diags, err := mgr.CollectAllDiagnostics(ctx, "file:///project/main.go")
err = mgr.StopAll(ctx)

func NewServerManager

func NewServerManager(launcher ServerLauncher, opts ...ManagerOption) ServerManager

NewServerManager creates a new ServerManager with the given launcher and options.

type StreamTransport

type StreamTransport struct {
	// contains filtered or unexported fields
}

StreamTransport implements MessageTransport over an io.ReadWriteCloser using the LSP base protocol (Content-Length headers).

func NewStreamTransport

func NewStreamTransport(reader io.Reader, writer io.Writer, closer io.Closer) *StreamTransport

NewStreamTransport creates a new StreamTransport from separate reader, writer, and closer. For stdio transport, reader is stdout pipe, writer is stdin pipe, closer closes both.

func TCPTransport

func TCPTransport(addr string) (*StreamTransport, error)

TCPTransport creates a MessageTransport over a TCP connection.

func (*StreamTransport) Close

func (t *StreamTransport) Close() error

Close closes the underlying stream.

func (*StreamTransport) ReadMessage

func (t *StreamTransport) ReadMessage(_ context.Context) (json.RawMessage, error)

ReadMessage reads a complete LSP message from the stream. It parses the Content-Length header and reads exactly that many bytes.

func (*StreamTransport) WriteMessage

func (t *StreamTransport) WriteMessage(_ context.Context, data json.RawMessage) error

WriteMessage writes a JSON body with Content-Length header to the stream.

type SymbolKind

type SymbolKind int

SymbolKind represents the kind of a document symbol. Values match the LSP 3.17 specification.

const (
	SymbolKindFile          SymbolKind = 1
	SymbolKindModule        SymbolKind = 2
	SymbolKindNamespace     SymbolKind = 3
	SymbolKindPackage       SymbolKind = 4
	SymbolKindClass         SymbolKind = 5
	SymbolKindMethod        SymbolKind = 6
	SymbolKindProperty      SymbolKind = 7
	SymbolKindField         SymbolKind = 8
	SymbolKindConstructor   SymbolKind = 9
	SymbolKindEnum          SymbolKind = 10
	SymbolKindInterface     SymbolKind = 11
	SymbolKindFunction      SymbolKind = 12
	SymbolKindVariable      SymbolKind = 13
	SymbolKindConstant      SymbolKind = 14
	SymbolKindString        SymbolKind = 15
	SymbolKindNumber        SymbolKind = 16
	SymbolKindBoolean       SymbolKind = 17
	SymbolKindArray         SymbolKind = 18
	SymbolKindObject        SymbolKind = 19
	SymbolKindKey           SymbolKind = 20
	SymbolKindNull          SymbolKind = 21
	SymbolKindEnumMember    SymbolKind = 22
	SymbolKindStruct        SymbolKind = 23
	SymbolKindEvent         SymbolKind = 24
	SymbolKindOperator      SymbolKind = 25
	SymbolKindTypeParameter SymbolKind = 26
)

LSP symbol kind constants.

type SymbolsProvider

type SymbolsProvider interface {
	// Symbols returns the document symbols for the given document URI.
	Symbols(ctx context.Context, uri string) ([]DocumentSymbol, error)
}

SymbolsProvider provides document symbol information. Use this interface when you only need to query document symbols.

Directories

Path Synopsis
Package hook provides LSP diagnostics integration for AE-ADK hooks.
Package hook provides LSP diagnostics integration for AE-ADK hooks.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL