lsp

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Mar 11, 2026 License: AGPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

Package lsp provides Language Server Protocol integration for Trace.

The LSP layer provides accurate type information, references, and rename capabilities by communicating with external language servers (gopls, pyright, etc.).

Architecture

The package uses a hybrid approach where Tree-sitter handles fast graph building while LSP servers handle accuracy-critical queries like type resolution, references, and rename operations.

┌─────────────────────────────────────────────────────────────────────────────┐
│                           Trace Service                                 │
│                                                                             │
│  Graph Queries (Tree-sitter)  ◄──  Query Router  ──►  LSP Queries           │
│  Fast ~1ms, ~90% accuracy                            Accurate ~50ms, ~100%  │
└─────────────────────────────────────────────────────────────────────────────┘

Components

  • Manager: Orchestrates multiple language server instances
  • Server: Manages individual LSP server processes
  • Protocol: Handles JSON-RPC communication
  • Operations: Provides high-level LSP operations (definition, references, etc.)

Thread Safety

All exported types are safe for concurrent use.

Example

mgr := lsp.NewManager("/path/to/project", lsp.DefaultManagerConfig())
defer mgr.ShutdownAll(context.Background())

ops := lsp.NewOperations(mgr)
locs, err := ops.Definition(ctx, "/path/to/file.go", 10, 5)

Index

Constants

View Source
const JSONRPCVersion = "2.0"

JSONRPCVersion is the JSON-RPC version used by LSP.

Variables

View Source
var (
	// ErrServerNotRunning indicates the LSP server is not in a ready state.
	ErrServerNotRunning = errors.New("lsp server not running")

	// ErrServerNotInstalled indicates the LSP server binary was not found.
	ErrServerNotInstalled = errors.New("lsp server not installed")

	// ErrUnsupportedLanguage indicates no LSP configuration exists for the language.
	ErrUnsupportedLanguage = errors.New("no lsp configuration for language")

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

	// ErrRequestTimeout indicates the LSP request exceeded the timeout.
	ErrRequestTimeout = errors.New("lsp request timeout")

	// ErrServerCrashed indicates the LSP server process terminated unexpectedly.
	ErrServerCrashed = errors.New("lsp server crashed")

	// ErrInvalidResponse indicates the LSP response could not be parsed.
	ErrInvalidResponse = errors.New("invalid lsp response")

	// ErrServerAlreadyStarted indicates Start was called on an already running server.
	ErrServerAlreadyStarted = errors.New("server already started")
)

Sentinel errors for LSP operations.

Functions

func URIToPath

func URIToPath(uri string) string

URIToPath converts a file:// URI to an absolute file path.

Description:

Properly decodes URL-encoded characters in the URI path.
Exported for use by the graph package's LSP enrichment phase.

Types

type ClientCapabilities

type ClientCapabilities struct {
	// TextDocument describes text document capabilities.
	TextDocument TextDocumentClientCapabilities `json:"textDocument,omitempty"`

	// Workspace describes workspace capabilities.
	Workspace WorkspaceClientCapabilities `json:"workspace,omitempty"`
}

ClientCapabilities describes what the client supports.

type ConfigRegistry

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

ConfigRegistry manages LSP configurations for different languages.

Thread Safety: Safe for concurrent use.

func NewConfigRegistry

func NewConfigRegistry() *ConfigRegistry

NewConfigRegistry creates a registry with default configurations.

Description:

Creates a new configuration registry pre-populated with configurations
for common languages: Go (gopls), Python (pyright), TypeScript, and JavaScript.

Outputs:

*ConfigRegistry - The configured registry

func (*ConfigRegistry) Extensions

func (r *ConfigRegistry) Extensions() []string

Extensions returns all file extensions mapped to a language.

Description:

Returns a slice of all file extensions that have configurations.

Outputs:

[]string - File extensions including dots

Thread Safety:

Safe for concurrent use.

func (*ConfigRegistry) Get

func (r *ConfigRegistry) Get(language string) (LanguageConfig, bool)

Get returns the configuration for a language.

Description:

Looks up the configuration for the specified language identifier.

Inputs:

language - The language identifier (e.g., "go", "python")

Outputs:

LanguageConfig - The configuration (zero value if not found)
bool - True if the configuration was found

Thread Safety:

Safe for concurrent use.

func (*ConfigRegistry) GetByExtension

func (r *ConfigRegistry) GetByExtension(ext string) (LanguageConfig, bool)

GetByExtension returns the configuration for a file extension.

Description:

Looks up the configuration for the language that handles the given
file extension.

Inputs:

ext - The file extension including dot (e.g., ".go", ".py")

Outputs:

LanguageConfig - The configuration (zero value if not found)
bool - True if the configuration was found

Thread Safety:

Safe for concurrent use.

func (*ConfigRegistry) LanguageForExtension

func (r *ConfigRegistry) LanguageForExtension(ext string) (string, bool)

LanguageForExtension returns the language identifier for a file extension.

Description:

Maps a file extension to its language identifier.

Inputs:

ext - The file extension including dot (e.g., ".go")

Outputs:

string - The language identifier (empty if not found)
bool - True if a mapping was found

Thread Safety:

Safe for concurrent use.

func (*ConfigRegistry) Languages

func (r *ConfigRegistry) Languages() []string

Languages returns all registered language names.

Description:

Returns a slice of all language identifiers that have configurations.

Outputs:

[]string - Language identifiers

Thread Safety:

Safe for concurrent use.

func (*ConfigRegistry) Register

func (r *ConfigRegistry) Register(config LanguageConfig)

Register adds or updates a language configuration.

Description:

Registers a language server configuration. If a configuration already
exists for the language, it is replaced. Also updates the extension
mapping for quick lookups.

Inputs:

config - The language configuration to register

Thread Safety:

Safe for concurrent use.

type DefinitionCapabilities

type DefinitionCapabilities struct {
	// DynamicRegistration indicates dynamic registration is supported.
	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`

	// LinkSupport indicates LocationLink support.
	LinkSupport bool `json:"linkSupport,omitempty"`
}

DefinitionCapabilities describes go-to-definition support.

type DidChangeTextDocumentParams

type DidChangeTextDocumentParams struct {
	// TextDocument is the document that changed.
	TextDocument VersionedTextDocumentIdentifier `json:"textDocument"`

	// ContentChanges is the list of changes.
	ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"`
}

DidChangeTextDocumentParams contains params for textDocument/didChange.

type DidCloseTextDocumentParams

type DidCloseTextDocumentParams struct {
	// TextDocument is the document that was closed.
	TextDocument TextDocumentIdentifier `json:"textDocument"`
}

DidCloseTextDocumentParams contains params for textDocument/didClose.

type DidOpenTextDocumentParams

type DidOpenTextDocumentParams struct {
	// TextDocument is the document that was opened.
	TextDocument TextDocumentItem `json:"textDocument"`
}

DidOpenTextDocumentParams contains params for textDocument/didOpen.

type HoverCapabilities

type HoverCapabilities struct {
	// DynamicRegistration indicates dynamic registration is supported.
	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`

	// ContentFormat describes supported content formats.
	ContentFormat []string `json:"contentFormat,omitempty"`
}

HoverCapabilities describes hover support.

type HoverInfo

type HoverInfo struct {
	// Content is the hover text (documentation, type info, etc.)
	Content string `json:"content"`

	// Kind is the content format ("plaintext" or "markdown").
	Kind string `json:"kind"`

	// Range is the range this hover applies to (optional).
	Range *Range `json:"range,omitempty"`
}

HoverInfo contains parsed hover information.

type HoverResult

type HoverResult struct {
	// Contents is the hover content.
	Contents MarkupContent `json:"contents"`

	// Range is the range this hover applies to.
	Range *Range `json:"range,omitempty"`
}

HoverResult contains hover information.

type InitializeParams

type InitializeParams struct {
	// ProcessID is the process ID of the parent process.
	ProcessID int `json:"processId"`

	// RootURI is the root URI of the workspace (preferred over rootPath).
	RootURI string `json:"rootUri"`

	// RootPath is the root path of the workspace (deprecated).
	RootPath string `json:"rootPath,omitempty"`

	// Capabilities describes what the client supports.
	Capabilities ClientCapabilities `json:"capabilities"`

	// InitializationOptions are custom initialization options.
	InitializationOptions interface{} `json:"initializationOptions,omitempty"`

	// Trace sets the initial trace setting.
	Trace string `json:"trace,omitempty"`

	// WorkspaceFolders are the workspace folders if supported.
	WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders,omitempty"`
}

InitializeParams contains initialization parameters.

type InitializeResult

type InitializeResult struct {
	// Capabilities describes what the server supports.
	Capabilities ServerCapabilities `json:"capabilities"`

	// ServerInfo contains optional server information.
	ServerInfo *ServerInfo `json:"serverInfo,omitempty"`
}

InitializeResult contains the server's response to initialize.

type LSPError

type LSPError struct {
	// Code is the JSON-RPC error code.
	Code int

	// Message is the error message from the server.
	Message string

	// Data contains optional additional data about the error.
	Data interface{}
}

LSPError represents an error returned by the language server via JSON-RPC.

LSP error codes follow the JSON-RPC spec plus LSP-specific codes:

  • -32700: Parse error
  • -32600: Invalid request
  • -32601: Method not found
  • -32602: Invalid params
  • -32603: Internal error
  • -32099 to -32000: Server error (reserved)
  • -32802: Server not initialized
  • -32801: Unknown error code
  • -32800: Request cancelled

func (*LSPError) Error

func (e *LSPError) Error() string

Error implements the error interface.

func (*LSPError) IsMethodNotFound

func (e *LSPError) IsMethodNotFound() bool

IsMethodNotFound returns true if the method is not supported by the server.

func (*LSPError) IsParseError

func (e *LSPError) IsParseError() bool

IsParseError returns true if this is a JSON-RPC parse error.

func (*LSPError) IsRequestCancelled

func (e *LSPError) IsRequestCancelled() bool

IsRequestCancelled returns true if the request was cancelled.

func (*LSPError) IsServerNotInitialized

func (e *LSPError) IsServerNotInitialized() bool

IsServerNotInitialized returns true if the server is not initialized.

type LanguageConfig

type LanguageConfig struct {
	// Language is the language identifier (e.g., "go", "python").
	Language string

	// Command is the executable name or path.
	Command string

	// Args are command-line arguments to pass to the server.
	Args []string

	// Extensions are file extensions this server handles (e.g., ".go").
	Extensions []string

	// RootFiles are files that indicate a project root (e.g., "go.mod").
	RootFiles []string

	// InitializationOptions are custom options passed during initialize.
	InitializationOptions interface{}
}

LanguageConfig contains configuration for an LSP server.

type Location

type Location struct {
	// URI is the document URI (file:// scheme).
	URI string `json:"uri"`

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

Location represents a location in a document.

type LocationLink struct {
	// OriginSelectionRange is the span in the source that was used.
	OriginSelectionRange *Range `json:"originSelectionRange,omitempty"`

	// TargetURI is the target document URI.
	TargetURI string `json:"targetUri"`

	// TargetRange is the full range of the target (for highlighting).
	TargetRange Range `json:"targetRange"`

	// TargetSelectionRange is the precise range to reveal.
	TargetSelectionRange Range `json:"targetSelectionRange"`
}

LocationLink represents a link between a source and target location.

type Manager

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

Manager manages LSP server instances for multiple languages.

Description:

Provides lazy startup of language servers as needed, with idle
timeout and graceful shutdown. Each language has at most one
server instance per workspace.

Thread Safety:

Safe for concurrent use.

func NewManager

func NewManager(rootPath string, config ManagerConfig) *Manager

NewManager creates a new LSP manager.

Description:

Creates a manager for the given workspace root. The manager will
lazily start language servers as needed and shut them down after
the idle timeout.

Inputs:

rootPath - Absolute path to the workspace root
config - Manager configuration

Outputs:

*Manager - The configured manager

func (*Manager) Config

func (m *Manager) Config() ManagerConfig

Config returns the manager configuration.

func (*Manager) Configs

func (m *Manager) Configs() *ConfigRegistry

Configs returns the language configuration registry.

Description:

Returns the registry so callers can register custom language
configurations.

Thread Safety:

The returned registry is safe for concurrent use.

func (*Manager) Get

func (m *Manager) Get(language string) *Server

Get returns a server for the language if one is running.

Description:

Returns the server if it exists and is ready, otherwise returns nil.
Does not start a new server.

Inputs:

language - The language identifier

Outputs:

*Server - The server if running and ready, nil otherwise

Thread Safety:

Safe for concurrent use.

func (*Manager) GetOrSpawn

func (m *Manager) GetOrSpawn(ctx context.Context, language string) (*Server, error)

GetOrSpawn returns a server for the language, starting it if needed.

Description:

Returns an existing server if one is running and ready, otherwise
starts a new server. Uses double-check locking to ensure only one
server is started per language even under concurrent requests.

Inputs:

ctx - Context for cancellation and startup timeout
language - The language identifier (e.g., "go", "python")

Outputs:

*Server - The ready server
error - Non-nil if the language is unsupported or server failed to start

Errors:

ErrUnsupportedLanguage - No configuration for the language
ErrServerNotInstalled - Server binary not found
ErrInitializeFailed - Server initialization failed

Thread Safety:

Safe for concurrent use.

func (*Manager) IsAvailable

func (m *Manager) IsAvailable(language string) bool

IsAvailable checks if an LSP server is available for a language.

Description:

Checks if the language is supported and the server binary is installed.
Does not start the server.

Inputs:

language - The language identifier

Outputs:

bool - True if the language is supported and server is installed

Thread Safety:

Safe for concurrent use.

func (*Manager) ReleaseFile

func (m *Manager) ReleaseFile(ctx context.Context, filePath string) error

ReleaseFile notifies all running LSP servers to close a file.

Description:

Sends textDocument/didClose notifications to all running LSP servers
for the given file path. This is needed on Windows before atomic
file writes (os.Rename) because LSP servers may hold file handles open,
blocking the rename operation.

Inputs:

ctx - Context for cancellation and timeout
filePath - Absolute path to the file to release

Outputs:

error - Non-nil if any server notification failed (best-effort)

Thread Safety:

Safe for concurrent use.

func (*Manager) ReopenFile

func (m *Manager) ReopenFile(ctx context.Context, filePath string, content string, languageID string) error

ReopenFile notifies all running LSP servers to reopen a file.

Description:

Sends textDocument/didOpen notifications to all running LSP servers
for the given file path with the new content. This is called after
atomic file writes on Windows to restore LSP server awareness of the file.

Inputs:

ctx - Context for cancellation and timeout
filePath - Absolute path to the file to reopen
content - The new file content to send to servers
languageID - The language identifier (e.g., "go", "python")

Outputs:

error - Non-nil if any server notification failed (best-effort)

Thread Safety:

Safe for concurrent use.

func (*Manager) RootPath

func (m *Manager) RootPath() string

RootPath returns the workspace root path.

func (*Manager) RunningServers

func (m *Manager) RunningServers() []string

RunningServers returns languages with running servers.

Description:

Returns a list of language identifiers for servers that are
currently in the ready state.

Outputs:

[]string - Language identifiers

Thread Safety:

Safe for concurrent use.

func (*Manager) Shutdown

func (m *Manager) Shutdown(ctx context.Context, language string) error

Shutdown shuts down a specific language server.

Description:

Gracefully shuts down the server for the given language.
No-op if no server is running for the language.

Inputs:

ctx - Context for shutdown timeout
language - The language identifier

Outputs:

error - Non-nil if shutdown encountered errors

Thread Safety:

Safe for concurrent use.

func (*Manager) ShutdownAll

func (m *Manager) ShutdownAll(ctx context.Context) error

ShutdownAll shuts down all servers and stops the manager.

Description:

Gracefully shuts down all running servers. After this call,
GetOrSpawn will return an error.

Inputs:

ctx - Context for shutdown timeout

Outputs:

error - Non-nil if any shutdown encountered errors (last error returned)

Thread Safety:

Safe for concurrent use. Multiple calls are idempotent.

func (*Manager) StartIdleMonitor

func (m *Manager) StartIdleMonitor()

StartIdleMonitor starts the idle server cleanup goroutine.

Description:

Starts a background goroutine that periodically checks for idle
servers and shuts them down. The check interval is half the idle
timeout. Does nothing if IdleTimeout is 0.

Thread Safety:

Safe for concurrent use. Multiple calls start multiple monitors
(not recommended).

type ManagerConfig

type ManagerConfig struct {
	// IdleTimeout is how long a server can be idle before being shut down.
	// Set to 0 to disable idle shutdown.
	IdleTimeout time.Duration

	// StartupTimeout is the maximum time to wait for a server to start.
	StartupTimeout time.Duration

	// RequestTimeout is the default timeout for LSP requests.
	RequestTimeout time.Duration
}

ManagerConfig configures the LSP manager.

func DefaultManagerConfig

func DefaultManagerConfig() ManagerConfig

DefaultManagerConfig returns sensible defaults for the manager.

Description:

Returns a configuration with:
  - IdleTimeout: 10 minutes
  - StartupTimeout: 30 seconds
  - RequestTimeout: 10 seconds

type MarkupContent

type MarkupContent struct {
	// Kind is the type of markup: "plaintext" or "markdown".
	Kind string `json:"kind"`

	// Value is the actual content.
	Value string `json:"value"`
}

MarkupContent represents documentation content.

type Notification

type Notification struct {
	// JSONRPC is the protocol version, always "2.0".
	JSONRPC string `json:"jsonrpc"`

	// Method is the method to invoke.
	Method string `json:"method"`

	// Params contains the method parameters.
	Params interface{} `json:"params,omitempty"`
}

Notification represents a JSON-RPC notification (no ID, no response).

type Operations

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

Operations provides high-level LSP operations.

Description:

Wraps the Manager to provide convenient methods for common LSP
operations like go-to-definition, find-references, hover, and rename.
Automatically determines the language from file extensions and
handles server startup as needed.

Thread Safety:

Safe for concurrent use.

func NewOperations

func NewOperations(manager *Manager) *Operations

NewOperations creates an Operations instance.

Inputs:

manager - The LSP manager to use for server management

Outputs:

*Operations - The operations wrapper

func (*Operations) CloseDocument

func (o *Operations) CloseDocument(ctx context.Context, filePath string) error

CloseDocument notifies the server that a document was closed.

Description:

Sends a textDocument/didClose notification.

Inputs:

filePath - Absolute path to the file

Outputs:

error - Non-nil on failure

func (*Operations) Definition

func (o *Operations) Definition(ctx context.Context, filePath string, line, col int) ([]Location, error)

Definition returns the definition location(s) for a symbol.

Description:

Sends a textDocument/definition request to the appropriate language
server and returns the location(s) of the symbol's definition.

Inputs:

ctx - Context for cancellation and timeout
filePath - Absolute path to the file
line - 1-indexed line number
col - 0-indexed column number (character offset)

Outputs:

[]Location - Definition location(s), may be empty if not found
error - Non-nil on failure

Errors:

ErrUnsupportedLanguage - No LSP configuration for file extension
ErrServerNotInstalled - Server binary not found
ErrRequestTimeout - Request timed out

Example:

locs, err := ops.Definition(ctx, "/project/main.go", 10, 5)
if err != nil {
    return err
}
for _, loc := range locs {
    fmt.Printf("Definition at %s:%d\n", URIToPath(loc.URI), loc.Range.Start.Line+1)
}

func (*Operations) Hover

func (o *Operations) Hover(ctx context.Context, filePath string, line, col int) (*HoverInfo, error)

Hover returns type and documentation info for a symbol.

Description:

Sends a textDocument/hover request to get documentation and type
information for the symbol at the given position.

Inputs:

ctx - Context for cancellation and timeout
filePath - Absolute path to the file
line - 1-indexed line number
col - 0-indexed column number

Outputs:

*HoverInfo - Hover information, nil if no hover available
error - Non-nil on failure

Example:

info, err := ops.Hover(ctx, "/project/main.go", 10, 5)
if err != nil {
    return err
}
if info != nil {
    fmt.Println(info.Content)
}

func (*Operations) IsAvailable

func (o *Operations) IsAvailable(filePath string) bool

IsAvailable checks if LSP operations are available for a file.

Description:

Checks if the file extension is supported and the server binary
is installed.

Inputs:

filePath - Path to check (only extension is used)

Outputs:

bool - True if LSP operations are available

func (*Operations) Manager

func (o *Operations) Manager() *Manager

Manager returns the underlying manager.

func (*Operations) OpenDocument

func (o *Operations) OpenDocument(ctx context.Context, filePath, content string) error

OpenDocument notifies the server that a document was opened.

Description:

Sends a textDocument/didOpen notification. This is required before
most LSP operations will work on a file.

Inputs:

filePath - Absolute path to the file
content - The file content

Outputs:

error - Non-nil on failure

func (*Operations) PathToURI

func (o *Operations) PathToURI(path string) string

PathToURI converts a file path to a file:// URI.

Description:

Convenience method for converting file paths to LSP URIs.

func (*Operations) PrepareRename

func (o *Operations) PrepareRename(ctx context.Context, filePath string, line, col int) (*PrepareRenameResult, error)

PrepareRename checks if rename is valid at the given position.

Description:

Sends a textDocument/prepareRename request to check if the symbol
at the given position can be renamed and returns the range and
placeholder text.

Inputs:

ctx - Context for cancellation and timeout
filePath - Absolute path to the file
line - 1-indexed line number
col - 0-indexed column number

Outputs:

*PrepareRenameResult - The range and placeholder, nil if not renameable
error - Non-nil on failure

func (*Operations) References

func (o *Operations) References(ctx context.Context, filePath string, line, col int, includeDecl bool) ([]Location, error)

References returns all references to a symbol.

Description:

Sends a textDocument/references request to find all locations that
reference the symbol at the given position.

Inputs:

ctx - Context for cancellation and timeout
filePath - Absolute path to the file
line - 1-indexed line number
col - 0-indexed column number
includeDecl - Whether to include the declaration in results

Outputs:

[]Location - Reference locations, may be empty
error - Non-nil on failure

Example:

refs, err := ops.References(ctx, "/project/main.go", 10, 5, true)
if err != nil {
    return err
}
fmt.Printf("Found %d references\n", len(refs))

func (*Operations) Rename

func (o *Operations) Rename(ctx context.Context, filePath string, line, col int, newName string) (*WorkspaceEdit, error)

Rename computes edits for renaming a symbol.

Description:

Sends a textDocument/rename request to compute all edits needed to
rename the symbol at the given position. Returns the edits but does
NOT apply them - the caller is responsible for applying the edits.

Inputs:

ctx - Context for cancellation and timeout
filePath - Absolute path to the file
line - 1-indexed line number
col - 0-indexed column number
newName - The new name for the symbol

Outputs:

*WorkspaceEdit - Edits to apply for the rename
error - Non-nil on failure

Example:

edit, err := ops.Rename(ctx, "/project/main.go", 10, 5, "newName")
if err != nil {
    return err
}
for uri, edits := range edit.Changes {
    fmt.Printf("File %s: %d edits\n", URIToPath(uri), len(edits))
}

func (*Operations) SummarizeWorkspaceEdit

func (o *Operations) SummarizeWorkspaceEdit(edit *WorkspaceEdit) WorkspaceEditSummary

SummarizeWorkspaceEdit creates a summary of a workspace edit.

Description:

Analyzes a WorkspaceEdit returned by LSP Rename and produces a summary
showing which files are affected and how many edits each will receive.
This is useful for presenting rename previews to users.

Inputs:

edit - The workspace edit to summarize

Outputs:

WorkspaceEditSummary - Summary of the edit

Example:

edit, err := ops.Rename(ctx, "/project/main.go", 10, 5, "newName")
if err != nil {
    return err
}
summary := ops.SummarizeWorkspaceEdit(edit)
fmt.Printf("Rename will affect %d files with %d total edits\n",
    summary.FileCount, summary.TotalEdits)

func (*Operations) URIToPath

func (o *Operations) URIToPath(uri string) string

URIToPath converts a file:// URI to a file path.

Description:

Convenience method for converting LSP URIs to file paths.

func (*Operations) ValidateWorkspaceEdit

func (o *Operations) ValidateWorkspaceEdit(edit *WorkspaceEdit) error

ValidateWorkspaceEdit checks if a workspace edit can be safely applied.

Description:

Performs basic validation on a workspace edit to ensure it references
valid files and has reasonable edit ranges. This does NOT check if the
files actually exist or are writable.

Important:

The Rename operation returns edits but does NOT apply them. The caller
is responsible for:
  1. Reviewing the edits with the user
  2. Creating backups if needed
  3. Applying the edits atomically
  4. Handling any conflicts or errors

Inputs:

edit - The workspace edit to validate

Outputs:

error - Non-nil if the edit has obvious problems

func (*Operations) WorkspaceSymbol

func (o *Operations) WorkspaceSymbol(ctx context.Context, language, query string) ([]SymbolInformation, error)

WorkspaceSymbol finds symbols matching a query in the workspace.

Description:

Sends a workspace/symbol request to find symbols matching the query
across the entire workspace.

Inputs:

ctx - Context for cancellation and timeout
language - The language to query (determines which server to use)
query - The symbol query (empty string returns all symbols)

Outputs:

[]SymbolInformation - Matching symbols
error - Non-nil on failure

Example:

symbols, err := ops.WorkspaceSymbol(ctx, "go", "Handler")
if err != nil {
    return err
}
for _, sym := range symbols {
    fmt.Printf("%s (%s)\n", sym.Name, sym.Location.URI)
}

type Position

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

	// Character is the 0-indexed character offset within the line.
	Character int `json:"character"`
}

Position represents a position in a text document. Line and character are 0-indexed per LSP specification.

type PrepareRenameParams

type PrepareRenameParams struct {
	TextDocumentPositionParams
}

PrepareRenameParams contains prepare rename request parameters.

type PrepareRenameResult

type PrepareRenameResult struct {
	// Range is the range of the string to rename.
	Range Range `json:"range"`

	// Placeholder is the text of the string to rename.
	Placeholder string `json:"placeholder"`
}

PrepareRenameResult contains the result of a prepare rename request.

type Protocol

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

Protocol handles JSON-RPC communication over stdin/stdout.

Description:

Implements the LSP base protocol using Content-Length headers.
Manages request/response correlation and supports notifications.

Thread Safety:

Safe for concurrent use. Multiple goroutines can send requests
and notifications simultaneously.

func NewProtocol

func NewProtocol(r io.Reader, w io.Writer) *Protocol

NewProtocol creates a new protocol handler.

Description:

Creates a protocol handler that communicates over the provided
reader (server stdout) and writer (server stdin).

Inputs:

r - Reader for server responses (e.g., stdout pipe)
w - Writer for client requests (e.g., stdin pipe)

Outputs:

*Protocol - The protocol handler

func (*Protocol) Close

func (p *Protocol) Close()

Close marks the protocol as closed.

Description:

Marks the protocol as closed to prevent further sends. Cancels all
pending requests with an error response. Does not close underlying
readers/writers.

Thread Safety:

Safe for concurrent use.

func (*Protocol) ReadLoop

func (p *Protocol) ReadLoop(ctx context.Context) error

ReadLoop reads messages from the server and dispatches responses.

Description:

Continuously reads messages from the server. Responses are matched
to pending requests. Notifications are ignored. Call this in a
goroutine after starting the server.

Inputs:

ctx - Context for cancellation

Outputs:

error - Non-nil if reading fails or context is cancelled

Thread Safety:

Must be called from a single goroutine. Safe to run while other
goroutines call SendRequest/SendNotification.

func (*Protocol) SendNotification

func (p *Protocol) SendNotification(method string, params interface{}) error

SendNotification sends a notification (no response expected).

Description:

Sends a JSON-RPC notification to the server. Notifications do not
expect a response.

Inputs:

method - The LSP method to invoke (e.g., "initialized")
params - Method parameters (will be JSON-marshaled)

Outputs:

error - Non-nil if sending failed

Thread Safety:

Safe for concurrent use.

func (*Protocol) SendRequest

func (p *Protocol) SendRequest(ctx context.Context, method string, params interface{}) (*Response, error)

SendRequest sends a request and waits for the response.

Description:

Sends a JSON-RPC request to the server and blocks until a response
is received or the context is cancelled.

Inputs:

ctx - Context for cancellation and timeout
method - The LSP method to invoke (e.g., "textDocument/definition")
params - Method parameters (will be JSON-marshaled)

Outputs:

*Response - The server's response
error - Non-nil if sending failed, timeout, or server returned error

Thread Safety:

Safe for concurrent use.

type Range

type Range struct {
	// Start is the inclusive start position.
	Start Position `json:"start"`

	// End is the exclusive end position.
	End Position `json:"end"`
}

Range represents a range in a text document.

type ReferenceContext

type ReferenceContext struct {
	// IncludeDeclaration indicates whether to include the declaration.
	IncludeDeclaration bool `json:"includeDeclaration"`
}

ReferenceContext contains options for find references requests.

type ReferenceParams

type ReferenceParams struct {
	TextDocumentPositionParams

	// Context contains additional context for the request.
	Context ReferenceContext `json:"context"`
}

ReferenceParams extends TextDocumentPositionParams for find references.

type ReferencesCapabilities

type ReferencesCapabilities struct {
	// DynamicRegistration indicates dynamic registration is supported.
	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
}

ReferencesCapabilities describes find-references support.

type RenameCapabilities

type RenameCapabilities struct {
	// DynamicRegistration indicates dynamic registration is supported.
	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`

	// PrepareSupport indicates prepareRename is supported.
	PrepareSupport bool `json:"prepareSupport,omitempty"`
}

RenameCapabilities describes rename support.

type RenameParams

type RenameParams struct {
	TextDocumentPositionParams

	// NewName is the new name to rename the symbol to.
	NewName string `json:"newName"`
}

RenameParams contains rename request parameters.

type Request

type Request struct {
	// JSONRPC is the protocol version, always "2.0".
	JSONRPC string `json:"jsonrpc"`

	// ID is the request identifier. Omit for notifications.
	ID int64 `json:"id,omitempty"`

	// Method is the method to invoke.
	Method string `json:"method"`

	// Params contains the method parameters.
	Params interface{} `json:"params,omitempty"`
}

Request represents a JSON-RPC request.

type Response

type Response struct {
	// JSONRPC is the protocol version, always "2.0".
	JSONRPC string `json:"jsonrpc"`

	// ID is the request identifier this response corresponds to.
	ID int64 `json:"id"`

	// Result contains the method result (mutually exclusive with Error).
	Result json.RawMessage `json:"result,omitempty"`

	// Error contains error information (mutually exclusive with Result).
	Error *ResponseError `json:"error,omitempty"`
}

Response represents a JSON-RPC response.

type ResponseError

type ResponseError 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 error information.
	Data interface{} `json:"data,omitempty"`
}

ResponseError represents a JSON-RPC error.

type Server

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

Server represents a running LSP server process.

Description:

Manages the lifecycle of an LSP server process, including starting,
initializing, and shutting down. Provides methods for sending requests
and notifications to the server.

Thread Safety:

Safe for concurrent use after Start() returns successfully.

func NewServer

func NewServer(config LanguageConfig, rootPath string) *Server

NewServer creates a new server instance (not started).

Description:

Creates a server instance configured for the given language.
The server is not started; call Start to begin the process.

Inputs:

config - Language configuration for the server
rootPath - Absolute path to the workspace root

Outputs:

*Server - The configured (but not started) server

func (*Server) Capabilities

func (s *Server) Capabilities() ServerCapabilities

Capabilities returns the server's capabilities.

Description:

Returns the capabilities reported by the server during initialization.
Returns zero value if the server hasn't been initialized.

func (*Server) Language

func (s *Server) Language() string

Language returns the language this server handles.

func (*Server) LastUsed

func (s *Server) LastUsed() time.Time

LastUsed returns when the server was last used.

Thread Safety:

Safe for concurrent use.

func (*Server) Notify

func (s *Server) Notify(method string, params interface{}) error

Notify sends an LSP notification.

Description:

Sends a notification to the server. Notifications do not expect a
response. Updates the last-used timestamp.

Inputs:

method - The LSP method to invoke
params - Method parameters

Outputs:

error - Non-nil if server not ready or send failed

Thread Safety:

Safe for concurrent use.

func (*Server) Request

func (s *Server) Request(ctx context.Context, method string, params interface{}) (*Response, error)

Request sends an LSP request and waits for the response.

Description:

Sends a request to the server and blocks until a response is received
or the context is cancelled. Updates the last-used timestamp.

Inputs:

ctx - Context for cancellation and timeout
method - The LSP method to invoke
params - Method parameters

Outputs:

*Response - The server's response
error - Non-nil if server not ready, send failed, or timeout

Thread Safety:

Safe for concurrent use.

func (*Server) RootPath

func (s *Server) RootPath() string

RootPath returns the workspace root path.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the server.

Description:

Sends shutdown and exit messages to the server, then waits for the
process to terminate. If the server doesn't respond, it is killed.

Inputs:

ctx - Context for cancellation and timeout

Outputs:

error - Non-nil if shutdown encountered errors (server is still stopped)

Thread Safety:

Safe for concurrent use. Multiple calls are idempotent.

func (*Server) Start

func (s *Server) Start(ctx context.Context) error

Start starts the LSP server process and initializes it.

Description:

Starts the server process, establishes communication, and performs
the LSP initialize handshake. On success, the server is ready to
receive requests.

Inputs:

ctx - Context for cancellation and timeout

Outputs:

error - Non-nil if the server failed to start or initialize

Errors:

ErrServerNotInstalled - Server binary not found
ErrServerAlreadyStarted - Start called on a non-uninitialized server
ErrInitializeFailed - LSP initialize handshake failed

Thread Safety:

Safe for concurrent use, but only the first caller will start the server.

func (*Server) State

func (s *Server) State() ServerState

State returns the current server state.

Thread Safety:

Safe for concurrent use.

type ServerCapabilities

type ServerCapabilities struct {
	// TextDocumentSync describes how documents are synced.
	TextDocumentSync interface{} `json:"textDocumentSync,omitempty"`

	// DefinitionProvider indicates textDocument/definition is supported.
	DefinitionProvider interface{} `json:"definitionProvider,omitempty"`

	// ReferencesProvider indicates textDocument/references is supported.
	ReferencesProvider interface{} `json:"referencesProvider,omitempty"`

	// HoverProvider indicates textDocument/hover is supported.
	HoverProvider interface{} `json:"hoverProvider,omitempty"`

	// RenameProvider indicates textDocument/rename is supported.
	RenameProvider interface{} `json:"renameProvider,omitempty"`

	// WorkspaceSymbolProvider indicates workspace/symbol is supported.
	WorkspaceSymbolProvider interface{} `json:"workspaceSymbolProvider,omitempty"`
}

ServerCapabilities describes what the server supports.

func (*ServerCapabilities) HasDefinitionProvider

func (c *ServerCapabilities) HasDefinitionProvider() bool

HasDefinitionProvider returns true if definition is supported.

func (*ServerCapabilities) HasHoverProvider

func (c *ServerCapabilities) HasHoverProvider() bool

HasHoverProvider returns true if hover is supported.

func (*ServerCapabilities) HasReferencesProvider

func (c *ServerCapabilities) HasReferencesProvider() bool

HasReferencesProvider returns true if references is supported.

func (*ServerCapabilities) HasRenameProvider

func (c *ServerCapabilities) HasRenameProvider() bool

HasRenameProvider returns true if rename is supported.

func (*ServerCapabilities) HasWorkspaceSymbolProvider

func (c *ServerCapabilities) HasWorkspaceSymbolProvider() bool

HasWorkspaceSymbolProvider returns true if workspace/symbol is supported.

type ServerInfo

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

	// Version is the server's version.
	Version string `json:"version,omitempty"`
}

ServerInfo contains information about the server.

type ServerState

type ServerState int

ServerState represents the lifecycle state of an LSP server.

const (
	// ServerStateUninitialized is the initial state before Start is called.
	ServerStateUninitialized ServerState = iota

	// ServerStateStarting means the server process is starting.
	ServerStateStarting

	// ServerStateReady means the server is initialized and ready for requests.
	ServerStateReady

	// ServerStateStopping means the server is shutting down.
	ServerStateStopping

	// ServerStateStopped means the server has terminated.
	ServerStateStopped
)

func (ServerState) String

func (s ServerState) String() string

String returns a human-readable state name.

type SymbolInformation

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

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

	// Tags are additional attributes (deprecated, etc.).
	Tags []SymbolTag `json:"tags,omitempty"`

	// Location is where the symbol is defined.
	Location Location `json:"location"`

	// ContainerName is the name of the containing symbol.
	ContainerName string `json:"containerName,omitempty"`
}

SymbolInformation represents information about a symbol.

type SymbolKind

type SymbolKind int

SymbolKind represents the kind of a symbol.

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

Symbol kinds as defined by the LSP specification.

type SymbolTag

type SymbolTag int

SymbolTag represents additional symbol attributes.

const (
	SymbolTagDeprecated SymbolTag = 1
)

Symbol tags as defined by the LSP specification.

type TextDocumentClientCapabilities

type TextDocumentClientCapabilities struct {
	// Synchronization describes document sync capabilities.
	Synchronization *TextDocumentSyncClientCapabilities `json:"synchronization,omitempty"`

	// Definition describes go-to-definition support.
	Definition *DefinitionCapabilities `json:"definition,omitempty"`

	// References describes find-references support.
	References *ReferencesCapabilities `json:"references,omitempty"`

	// Hover describes hover support.
	Hover *HoverCapabilities `json:"hover,omitempty"`

	// Rename describes rename support.
	Rename *RenameCapabilities `json:"rename,omitempty"`
}

TextDocumentClientCapabilities describes text document capabilities.

type TextDocumentContentChangeEvent

type TextDocumentContentChangeEvent struct {
	// Range is the range that got replaced. Omit for full document sync.
	Range *Range `json:"range,omitempty"`

	// RangeLength is the length of the range that got replaced (deprecated).
	RangeLength *int `json:"rangeLength,omitempty"`

	// Text is the new text for the range or full document.
	Text string `json:"text"`
}

TextDocumentContentChangeEvent describes a content change event.

type TextDocumentEdit

type TextDocumentEdit struct {
	// TextDocument identifies the document.
	TextDocument VersionedTextDocumentIdentifier `json:"textDocument"`

	// Edits is the list of edits.
	Edits []TextEdit `json:"edits"`
}

TextDocumentEdit describes edits to a specific document version.

type TextDocumentIdentifier

type TextDocumentIdentifier struct {
	// URI is the document's URI.
	URI string `json:"uri"`
}

TextDocumentIdentifier identifies a text document by URI.

type TextDocumentItem

type TextDocumentItem struct {
	// URI is the document's URI.
	URI string `json:"uri"`

	// LanguageID is the language identifier (e.g., "go", "python").
	LanguageID string `json:"languageId"`

	// Version is the version number of this document.
	Version int `json:"version"`

	// Text is the content of the document.
	Text string `json:"text"`
}

TextDocumentItem represents a text document with its content.

type TextDocumentPositionParams

type TextDocumentPositionParams struct {
	// TextDocument is the document identifier.
	TextDocument TextDocumentIdentifier `json:"textDocument"`

	// Position is the position within the document.
	Position Position `json:"position"`
}

TextDocumentPositionParams identifies a position in a text document.

type TextDocumentSyncClientCapabilities

type TextDocumentSyncClientCapabilities struct {
	// DynamicRegistration indicates dynamic registration is supported.
	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`

	// WillSave indicates willSave notifications are supported.
	WillSave bool `json:"willSave,omitempty"`

	// WillSaveWaitUntil indicates willSaveWaitUntil requests are supported.
	WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"`

	// DidSave indicates didSave notifications are supported.
	DidSave bool `json:"didSave,omitempty"`
}

TextDocumentSyncClientCapabilities describes sync capabilities.

type TextEdit

type TextEdit struct {
	// Range is the range to replace.
	Range Range `json:"range"`

	// NewText is the replacement text.
	NewText string `json:"newText"`
}

TextEdit represents a single text change.

type VersionedTextDocumentIdentifier

type VersionedTextDocumentIdentifier struct {
	TextDocumentIdentifier

	// Version is the version number. Null means the version is known.
	Version *int `json:"version"`
}

VersionedTextDocumentIdentifier identifies a specific version of a document.

type WorkspaceClientCapabilities

type WorkspaceClientCapabilities struct {
	// ApplyEdit indicates applyEdit requests are supported.
	ApplyEdit bool `json:"applyEdit,omitempty"`

	// WorkspaceEdit describes workspace edit capabilities.
	WorkspaceEdit *WorkspaceEditClientCapabilities `json:"workspaceEdit,omitempty"`

	// Symbol describes workspace symbol capabilities.
	Symbol *WorkspaceSymbolClientCapabilities `json:"symbol,omitempty"`
}

WorkspaceClientCapabilities describes workspace capabilities.

type WorkspaceEdit

type WorkspaceEdit struct {
	// Changes is a map from URI to list of text edits.
	Changes map[string][]TextEdit `json:"changes,omitempty"`

	// DocumentChanges are versioned document edits (preferred over Changes).
	DocumentChanges []TextDocumentEdit `json:"documentChanges,omitempty"`
}

WorkspaceEdit represents changes to many resources.

type WorkspaceEditClientCapabilities

type WorkspaceEditClientCapabilities struct {
	// DocumentChanges indicates documentChanges are supported.
	DocumentChanges bool `json:"documentChanges,omitempty"`
}

WorkspaceEditClientCapabilities describes workspace edit capabilities.

type WorkspaceEditSummary

type WorkspaceEditSummary struct {
	// FileCount is the number of files affected by the edit.
	FileCount int

	// TotalEdits is the total number of text edits across all files.
	TotalEdits int

	// Files is a map from file path to the number of edits in that file.
	Files map[string]int
}

WorkspaceEditSummary provides a human-readable summary of a workspace edit.

type WorkspaceFolder

type WorkspaceFolder struct {
	// URI is the folder URI.
	URI string `json:"uri"`

	// Name is the name of the folder.
	Name string `json:"name"`
}

WorkspaceFolder represents a workspace folder.

type WorkspaceSymbolClientCapabilities

type WorkspaceSymbolClientCapabilities struct {
	// DynamicRegistration indicates dynamic registration is supported.
	DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
}

WorkspaceSymbolClientCapabilities describes workspace symbol capabilities.

type WorkspaceSymbolParams

type WorkspaceSymbolParams struct {
	// Query is a non-empty query string to filter symbols.
	Query string `json:"query"`
}

WorkspaceSymbolParams contains workspace symbol query parameters.

Jump to

Keyboard shortcuts

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