lsp

package
v0.32.0 Latest Latest
Warning

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

Go to latest
Published: Sep 5, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package lsp is memcode's resident Language Server Protocol client — the "give the agent eyes" layer. It speaks JSON-RPC 2.0 over a language server's stdio (gopls, typescript-language-server, pyright), holding the server RESIDENT for the session so diagnostics are incremental (milliseconds, not a full re-typecheck) and semantic queries (definition / references / hover) are available. This is the capability no amount of grep + build gives, and the only static type-error source for TS/Python.

Model (following Claude Code): DETECT AND CONNECT. A server is used only when its binary is on PATH; nothing is bundled or auto-installed. The valuable operations for an agent are diagnostics, definition, and references — completion is deliberately not implemented.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func PathToURI

func PathToURI(path string) string

PathToURI converts an absolute filesystem path to a file:// URI.

func ServerBins

func ServerBins() map[string]string

ServerBins reports the registry's language → server binary (for doctor's missing-server check). javascript shares typescript's binary; callers that want one row per binary can dedupe on the value.

func URIToPath

func URIToPath(uri string) string

URIToPath converts a file:// URI back to a filesystem path (best-effort).

Types

type Client

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

Client is a JSON-RPC 2.0 client over one language server's stdio. It is created by the manager per language and reused across a session. Safe for concurrent Requests; the write side is mutex-guarded and responses are demuxed by id.

func (*Client) Close

func (c *Client) Close()

Close shuts the server down (best-effort shutdown/exit, then kill).

func (*Client) Definition

func (c *Client) Definition(ctx context.Context, uri string, pos Position) ([]Location, error)

Definition returns where the symbol at pos is defined. Handles the server returning a single Location or an array (both are valid per the spec).

func (*Client) Diagnostics

func (c *Client) Diagnostics(uri string) []Diagnostic

Diagnostics returns the latest diagnostics the server pushed for uri. Callers that just opened/changed a file should give the server a moment to publish (see WaitDiagnostics).

func (*Client) DidChange

func (c *Client) DidChange(uri string, version int, text string) error

DidChange tells the server a document's full content changed (full-sync) — sent after an edit so its diagnostics reflect the new text. version must increase per document.

func (*Client) DidOpen

func (c *Client) DidOpen(uri, languageID, text string) error

DidOpen tells the server about a document's content — required before it will produce diagnostics or answer position queries for that file.

func (*Client) DocumentSymbol

func (c *Client) DocumentSymbol(ctx context.Context, uri string) ([]DocumentSymbol, error)

DocumentSymbol returns the file's symbol tree. Handles both the hierarchical DocumentSymbol[] result (gopls/tsserver/pyright) and the flat SymbolInformation[] fallback.

func (*Client) Hover

func (c *Client) Hover(ctx context.Context, uri string, pos Position) (string, error)

Hover returns the type/signature/doc for the symbol at pos, flattened to text.

func (*Client) Initialize

func (c *Client) Initialize(ctx context.Context, root string) error

Initialize runs the LSP handshake with the workspace root, then sends `initialized`. The declared client capabilities are the minimal set our operations use.

func (*Client) References

func (c *Client) References(ctx context.Context, uri string, pos Position) ([]Location, error)

References returns every use of the symbol at pos (including its declaration).

func (*Client) WaitDiagnostics

func (c *Client) WaitDiagnostics(ctx context.Context, uri string, timeout time.Duration) []Diagnostic

WaitDiagnostics polls for diagnostics on uri up to timeout — diagnostics arrive as an async push after didOpen, so a caller that needs them right after opening waits briefly. Returns whatever is present at the deadline (empty means "clean" once the server settled).

type Diagnostic

type Diagnostic struct {
	Range    Range  `json:"range"`
	Severity int    `json:"severity"` // 1 error, 2 warning, 3 info, 4 hint
	Code     any    `json:"code"`
	Source   string `json:"source"`
	Message  string `json:"message"`
}

Diagnostic is one problem the server reports for a document.

func (Diagnostic) SeverityLabel

func (d Diagnostic) SeverityLabel() string

SeverityLabel renders the numeric severity as text.

type DocumentSymbol

type DocumentSymbol struct {
	Name           string           `json:"name"`
	Kind           int              `json:"kind"`
	Range          Range            `json:"range"`
	SelectionRange Range            `json:"selectionRange"`
	Children       []DocumentSymbol `json:"children,omitempty"`
}

DocumentSymbol is a named symbol in a file (LSP documentSymbol). Range is the full span (declaration + body); SelectionRange is the name token. Children nest (a method inside a type). Used to attribute a reference to the function/method that contains it.

type EnclosingSymbol

type EnclosingSymbol struct {
	Name    string
	Kind    int
	Path    string // absolute file path (as queried)
	DefLine int    // 1-based line of the symbol name (its selectionRange start)
	DefCol  int    // 1-based column
}

EnclosingSymbol is the named symbol whose body contains a position — used to attribute a reference to the function/method that contains it, for call-graph / impact analysis.

type FileSymbol

type FileSymbol struct {
	Name    string
	Kind    int // LSP SymbolKind
	Line    int // 1-based full-range start
	EndLine int // 1-based full-range end
	SelLine int // 1-based name-token line
	Depth   int // 0 = top level, 1 = member (a class's method), …
}

FileSymbol is one declaration from a file's LSP symbol tree, flattened for consumers that want a per-file symbol list (the repo map) rather than the enclosing-position query EnclosingSymbol answers.

type Location

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

Location is a range within a document (uri) — the shape definition/references return.

type Manager

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

Manager owns one resident language server per language for a workspace, started lazily and reused for the session. It is the session-facing surface (Diagnostics/Definition/ References/Hover by file path). Nil-safe: a zero Manager degrades to "no LSP".

func NewManager

func NewManager(root string) *Manager

NewManager returns a Manager rooted at the workspace. Servers are started on first use.

func (*Manager) Close

func (m *Manager) Close()

Close shuts every resident server down (call on session end).

func (*Manager) Definition

func (m *Manager) Definition(ctx context.Context, path string, line, col int) ([]Location, bool, error)

Definition/References/Hover resolve the symbol at a 1-based line/col (the human/editor convention) — converted to LSP's 0-based position here.

func (*Manager) DiagnoseAfterEdit

func (m *Manager) DiagnoseAfterEdit(ctx context.Context, path string) (diags []Diagnostic, ok bool, err error)

DiagnoseAfterEdit re-syncs a file that was just edited on disk (didChange with the new content, or didOpen if the server hasn't seen it yet), then waits for the server's fresh diagnostics. This is the "sees the error immediately, fixes it the same turn" loop. ok=false when no resident server serves the file.

func (*Manager) Diagnostics

func (m *Manager) Diagnostics(ctx context.Context, path string) (diags []Diagnostic, ok bool, err error)

Diagnostics returns the resident server's diagnostics for a file (opening it first and waiting briefly for the async push). ok=false means no server is available for it.

func (*Manager) EnclosingSymbol

func (m *Manager) EnclosingSymbol(ctx context.Context, path string, line, col int) (EnclosingSymbol, bool, error)

EnclosingSymbol resolves the most-specific symbol containing a 1-based line/col. ok=false when no resident server serves the file or nothing encloses the position.

func (*Manager) FileSymbols

func (m *Manager) FileSymbols(ctx context.Context, path string) ([]FileSymbol, bool, error)

FileSymbols returns the file's declarations via textDocument/documentSymbol, flattened two levels deep (top-level + members — grandchildren are locals and fields, noise for a repo overview). ok=false when no resident server serves the file's language.

func (*Manager) FormatLocations

func (m *Manager) FormatLocations(locs []Location) string

FormatLocations renders locations as repo-relative file:line references for the model.

func (*Manager) Hover

func (m *Manager) Hover(ctx context.Context, path string, line, col int) (string, bool, error)

Hover returns the type/signature/doc at a 1-based line/col.

func (*Manager) InstallHint

func (m *Manager) InstallHint(path string) string

InstallHint returns the binary a user must install to enable LSP for path's language.

func (*Manager) References

func (m *Manager) References(ctx context.Context, path string, line, col int) ([]Location, bool, error)

func (*Manager) Supported

func (m *Manager) Supported(path string) (lang string, ok bool)

Supported reports whether a resident server COULD serve this path (its language is known and its binary is on PATH). Used to decide whether to prefer LSP over a one-shot checker, and to give an actionable "install X" message otherwise.

type Position

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

Position is a zero-based line/character in a document (the LSP convention).

type Range

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

Range is a span in a document.

Jump to

Keyboard shortcuts

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