lsp

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 2, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package lsp is a direct Language Server Protocol client: ZERO spawns the language server itself and speaks LSP JSON-RPC over stdio, so an unattended run (cron/CI, no open editor) can still see real compiler diagnostics. This file holds the minimal LSP data model and file<->URI helpers; client.go is the transport and server.go the process lifecycle.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Available

func Available(path string) bool

Available reports whether a configured server for the path exists on PATH.

func FormatDiagnostics

func FormatDiagnostics(path string, diags []Diagnostic) string

FormatDiagnostics renders diagnostics as compact, model-readable lines:

path:line:col: severity: message

Lines/columns are converted from LSP's zero-based positions to the one-based form editors and compilers print. The path is passed in because a Diagnostic carries only a range, not its document.

func LanguageID

func LanguageID(path string) (string, bool)

LanguageID returns the LSP languageId for a path's extension.

func PathToURI

func PathToURI(path string) string

PathToURI converts an absolute filesystem path to a file:// URI, handling the Windows drive-letter form (C:\x -> file:///C:/x). It is the inverse of URIToPath; the pair round-trips for any absolute path.

func ServerBinaries

func ServerBinaries() []string

ServerBinaries returns the unique set of language-server binaries ZERO may spawn, sorted for stable output. It is the canonical list `zero doctor` checks against PATH, so the configured commands stay the single source of truth.

func ServerFor

func ServerFor(path string) ([]string, bool)

ServerFor returns the server command for a path's extension, and whether one is configured. It does not check PATH (use Available for that).

func URIToPath

func URIToPath(uri string) string

URIToPath converts a file:// URI back to an OS-native absolute path. A non-file URI (or unparseable input) is returned unchanged.

Types

type Client

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

Client speaks JSON-RPC 2.0 with LSP framing (Content-Length headers) over a reader/writer pair. It is transport-agnostic: server.go wires it to a process's stdout/stdin, and tests wire it to in-memory pipes. Safe for concurrent Call / Notify from multiple goroutines.

func NewClient

func NewClient(r io.Reader, w io.Writer) *Client

NewClient starts a client reading framed messages from r and writing to w. It spawns a read-loop goroutine that lives until r returns an error (e.g. the server process exits); call Close to stop using the client.

func (*Client) Call

func (c *Client) Call(ctx context.Context, method string, params any) (json.RawMessage, error)

Call sends a request and blocks until the matching response arrives, the context is cancelled, or the connection closes.

func (*Client) Close

func (c *Client) Close() error

Close stops the client and fails any in-flight calls.

func (*Client) IsClosed

func (c *Client) IsClosed() bool

IsClosed reports whether the client's connection has been torn down — the server exited, a read error occurred, or Close was called (all close c.closed). A closed client can never serve another request, so the manager evicts and restarts its session rather than returning a permanently-dead one.

func (*Client) Notify

func (c *Client) Notify(_ context.Context, method string, params any) error

Notify sends a notification (no response expected).

func (*Client) SetNotificationHandler

func (c *Client) SetNotificationHandler(handler NotificationHandler)

SetNotificationHandler installs the handler for server->client notifications.

type Diagnostic

type Diagnostic struct {
	Range    Range              `json:"range"`
	Severity DiagnosticSeverity `json:"severity,omitempty"`
	Code     any                `json:"code,omitempty"`
	Source   string             `json:"source,omitempty"`
	Message  string             `json:"message"`
}

Diagnostic is one compiler/linter finding for a document.

func FilterBySeverity

func FilterBySeverity(diags []Diagnostic, minimum DiagnosticSeverity) []Diagnostic

FilterBySeverity returns only diagnostics at or above (numerically at or below, since Error=1 is most severe) the given severity.

type DiagnosticSeverity

type DiagnosticSeverity int

DiagnosticSeverity mirrors the LSP severity enum.

const (
	SeverityError       DiagnosticSeverity = 1
	SeverityWarning     DiagnosticSeverity = 2
	SeverityInformation DiagnosticSeverity = 3
	SeverityHint        DiagnosticSeverity = 4
)

type InitializeParams

type InitializeParams struct {
	ProcessID    int            `json:"processId"`
	RootURI      string         `json:"rootUri"`
	Capabilities map[string]any `json:"capabilities"`
}

InitializeParams is the (trimmed) payload for the LSP initialize request.

type InitializeResult

type InitializeResult struct {
	Capabilities map[string]any `json:"capabilities"`
}

InitializeResult is the (trimmed) initialize response; we only need the server's reported capabilities.

type Location

type Location struct {
	URI   string `json:"uri"`
	Range Range  `json:"range"`
}

Location is a range within a specific document URI.

type Manager

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

Manager is the single entry point the rest of ZERO uses for LSP. It owns one long-lived server per language (lazily started, reused across calls — starting gopls per edit would be far too slow), routes a file to the right server, and degrades to "no diagnostics" when no server is available. Safe for concurrent use.

func NewManager

func NewManager(workspaceRoot string) *Manager

NewManager creates a Manager rooted at workspaceRoot.

func (*Manager) Check

func (m *Manager) Check(ctx context.Context, path, text string) ([]Diagnostic, error)

Check syncs the file's text to the right language server and returns the settled diagnostics. A file whose extension has no configured/available server returns (nil, nil): missing diagnostics are a graceful degrade, not an error.

func (*Manager) DiagnosticsFor

func (m *Manager) DiagnosticsFor(path string) []Diagnostic

DiagnosticsFor returns the most recently published diagnostics for a file without re-syncing. Empty when no server is running for it.

func (*Manager) HasErrors

func (m *Manager) HasErrors(path string) bool

HasErrors reports whether the file currently has any error-severity diagnostic.

func (*Manager) Navigate

func (m *Manager) Navigate(ctx context.Context, req NavRequest) (locations []Location, symbols []SymbolResult, ok bool, err error)

Navigate runs an LSP navigation request and returns the resulting locations (for the position ops) or symbols (for workspace_symbol). A file whose extension has no available server, or a server lacking the capability, degrades to an empty result with ok=false rather than an error — LSP is an opportunistic layer. A genuine protocol/transport failure returns an error.

func (*Manager) Shutdown

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

Shutdown stops every running server, returning the joined errors of any that failed to exit cleanly (a leaked language-server process is worth surfacing).

type NavOp string

NavOp is a supported LSP navigation operation.

const (
	NavDefinition      NavOp = "definition"
	NavReferences      NavOp = "references"
	NavImplementation  NavOp = "implementation"
	NavWorkspaceSymbol NavOp = "workspace_symbol"
)
type NavRequest struct {
	Op                 NavOp
	Path               string
	Line               int // 1-based
	Character          int // 1-based
	Query              string
	Text               string // current file content, for didOpen sync
	IncludeDeclaration bool
}

NavRequest describes a navigation query. For the position-based ops (definition/references/implementation) Path + Line + Character are required (1-based, as the agent sees file:line:col). For workspace_symbol only Query is used. IncludeDeclaration applies to references.

type NotificationHandler

type NotificationHandler func(method string, params json.RawMessage)

NotificationHandler receives server->client notifications (e.g. textDocument/publishDiagnostics). params is the raw JSON payload.

type Position

type Position struct {
	Line      int `json:"line"`
	Character int `json:"character"`
}

Position is a zero-based line/character offset in a document.

type PublishDiagnosticsParams

type PublishDiagnosticsParams struct {
	URI         string       `json:"uri"`
	Version     int          `json:"version,omitempty"`
	Diagnostics []Diagnostic `json:"diagnostics"`
}

PublishDiagnosticsParams is the payload of the textDocument/publishDiagnostics notification (consumed in stage 03).

type Range

type Range struct {
	Start Position `json:"start"`
	End   Position `json:"end"`
}

Range is an inclusive-start, exclusive-end span.

type Server

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

Server is a spawned language-server process plus the JSON-RPC client speaking to it over stdio, with the LSP initialize handshake already completed.

func StartServer

func StartServer(ctx context.Context, command []string, rootPath string) (*Server, error)

StartServer spawns the given command, wires a Client to its stdio, and performs the LSP initialize/initialized handshake rooted at rootPath. On any failure the process is torn down before returning.

func (*Server) Client

func (s *Server) Client() *Client

Client exposes the JSON-RPC client for document sync / diagnostics (stage 03).

func (*Server) Shutdown

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

Shutdown sends the LSP shutdown request + exit notification, then waits briefly for the process to exit and kills it otherwise. Best-effort: it never returns an error for a server that simply ignored the handshake.

type SymbolResult

type SymbolResult struct {
	Name     string
	Kind     string
	Location Location
}

SymbolResult is one workspace-symbol match (name + where it lives).

type TextDocumentItem

type TextDocumentItem struct {
	URI        string `json:"uri"`
	LanguageID string `json:"languageId"`
	Version    int    `json:"version"`
	Text       string `json:"text"`
}

TextDocumentItem is the payload for textDocument/didOpen.

Jump to

Keyboard shortcuts

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