Documentation
¶
Overview ¶
Package proxy provides an LSP (Language Server Protocol) proxy manager that manages language server processes for workspace-aware code intelligence.
Manager Shutdown Contract:
The Manager must be cleaned up via its Cleanup() (or Close()) method when the server shuts down. Cleanup() cancels the internal context, waits for the cleanup loop goroutine to exit via sync.WaitGroup, and closes all managed LSP processes. The ReactWebServer calls lspManager.Cleanup() during shutdown in server_lifecycle.go.
Index ¶
- Variables
- func BridgeHandler(manager *Manager, upgrader websocket.Upgrader, workspaceRoot string) func(w http.ResponseWriter, r *http.Request)
- func NormalizeLanguageID(id string) string
- func ReadMessage(r io.Reader) (string, error)
- func ResolveBinaryPath(binary string) (string, error)
- func WriteMessage(w io.Writer, body string) error
- func WriteMessagef(w io.Writer, format string, args ...interface{}) error
- type Bridge
- type LSPProcess
- type LanguageServerConfig
- func DefaultLanguageServers() []LanguageServerConfig
- func FindLanguageServer(languageID string, configs []LanguageServerConfig) *LanguageServerConfig
- func FindLanguageServerByID(id string, configs []LanguageServerConfig) *LanguageServerConfig
- func MergeServers(defaults []LanguageServerConfig, ...) []LanguageServerConfig
- type Manager
- func (m *Manager) Cleanup()
- func (m *Manager) Close()
- func (m *Manager) Count() int
- func (m *Manager) EvictIdle(timeout time.Duration)
- func (m *Manager) GetConfig() []LanguageServerConfig
- func (m *Manager) GetOrCreate(workspacePath, languageID string) (*LSPProcess, func(), error)
- func (m *Manager) SetConfig(configs []LanguageServerConfig)
- type MessageReader
- type MessageWriter
- type ServerSuggestion
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidMessage = errors.New("invalid LSP message")
ErrInvalidMessage is returned when a message cannot be parsed.
Functions ¶
func BridgeHandler ¶
func BridgeHandler(manager *Manager, upgrader websocket.Upgrader, workspaceRoot string) func(w http.ResponseWriter, r *http.Request)
BridgeHandler creates a http.HandlerFunc that handles LSP WebSocket connections. It upgrades the WebSocket connection and bridges it to the LSP process from the manager. The upgrader parameter should have a proper CheckOrigin function configured by the caller. The workspaceRoot parameter is used to validate that requested workspaces are within the allowed root.
func NormalizeLanguageID ¶
NormalizeLanguageID normalizes a language ID string (lowercase, trim whitespace).
func ReadMessage ¶
ReadMessage reads a single LSP Content-Length framed message from the reader. Format: "Content-Length: <n>\r\n\r\n<body>" Returns the body as a string.
func ResolveBinaryPath ¶
ResolveBinaryPath resolves the full path to a binary on PATH. Returns an error if not found.
func WriteMessage ¶
WriteMessage writes a single LSP Content-Length framed message to the writer.
Types ¶
type Bridge ¶
type Bridge struct {
// contains filtered or unexported fields
}
Bridge handles a single WebSocket client connection, bridging it to an LSP process. It handles the JSON-RPC request routing: - LSP initialize/initialized flow is handled transparently - WebSocket sends raw JSON → bridge frames it and writes to LSP process stdin - LSP process stdout → bridge deframes and sends raw JSON to WebSocket - When WebSocket disconnects, the bridge unsubscribes from the process
func NewBridge ¶
func NewBridge(wsConn *websocket.Conn, process *LSPProcess) *Bridge
NewBridge creates a new bridge for the given WebSocket connection and LSP process.
func (*Bridge) Close ¶
func (b *Bridge) Close()
Close cleans up the bridge. Safe to call multiple times and from multiple goroutines — both shutdown paths (runWSToLSP defer + the BridgeHandler defer) invoke it. The previous version nilled wsConn, which raced with the still-running runLSPToWS reading wsConn.
func (*Bridge) Run ¶
Run starts the bridge. It should: 1. Subscribe to LSP process messages 2. Read from WebSocket in a loop, writing to LSP process 3. Read from process subscriber channel, writing to WebSocket 4. Handle graceful shutdown when either side closes 5. Use two goroutines (ws→lsp and lsp→ws)
type LSPProcess ¶
type LSPProcess struct {
// contains filtered or unexported fields
}
LSPProcess represents a running language server process.
func StartLSPProcess ¶
func StartLSPProcess(ctx context.Context, workspacePath, binary string, args []string) (*LSPProcess, error)
StartLSPProcess starts a language server process with the given binary and args. The process is started in the given workspace directory.
func (*LSPProcess) Close ¶
func (p *LSPProcess) Close() error
Close kills the process and cleans up resources.
func (*LSPProcess) Healthy ¶
func (p *LSPProcess) Healthy() bool
Healthy returns true if the process is still running.
func (*LSPProcess) Process ¶
func (p *LSPProcess) Process() *exec.Cmd
Process returns the underlying exec.Cmd for access to process info.
func (*LSPProcess) Send ¶
func (p *LSPProcess) Send(msg string) error
Send sends a raw JSON-RPC string to the LSP process (with Content-Length framing).
func (*LSPProcess) Subscribe ¶
func (p *LSPProcess) Subscribe() (<-chan string, func(), error)
Subscribe registers a channel to receive messages from the LSP server. The caller must read from the channel; close it when done. Returns the channel and an unsubscribe function.
func (*LSPProcess) Wait ¶
func (p *LSPProcess) Wait() error
Wait blocks until the process exits and returns the error.
type LanguageServerConfig ¶
type LanguageServerConfig struct {
LanguageIDs []string // e.g. ["go"], ["typescript", "typescript-jsx", "javascript", "javascript-jsx"]
Binary string // "gopls", "typescript-language-server", etc.
Args []string // e.g. ["--stdio"]
ID string // "go", "typescript"
InstallHint string // e.g. "pip install python-lsp-server"
}
LanguageServerConfig describes how to find and start a language server.
func DefaultLanguageServers ¶
func DefaultLanguageServers() []LanguageServerConfig
DefaultLanguageServers returns the built-in language server configurations. Covers Go, TypeScript/JS, Python, Rust, C/C++, C#, Java, Ruby, PHP, Swift, Kotlin, Dart, Lua, and Shell.
IMPORTANT: gopls v0.17+ requires `gopls` binary on PATH with `--listen` not used - use stdio. For typescript-language-server, it requires the binary on PATH + `--stdio`.
func FindLanguageServer ¶
func FindLanguageServer(languageID string, configs []LanguageServerConfig) *LanguageServerConfig
FindLanguageServer finds a language server configuration by language ID. Returns nil if not found.
func FindLanguageServerByID ¶
func FindLanguageServerByID(id string, configs []LanguageServerConfig) *LanguageServerConfig
FindLanguageServerByID finds a language server configuration by its unique ID. Returns nil if not found.
func MergeServers ¶
func MergeServers(defaults []LanguageServerConfig, overrides []configuration.LanguageServerOverride) []LanguageServerConfig
MergeServers merges default language server configurations with user overrides. User overrides take precedence by ID: if a user override has the same ID as a default, it replaces the default. If a user override has a new ID not in defaults, it is appended to the merged list.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager manages LSP server processes across workspaces and languages.
func NewManager ¶
NewManager creates a new LSP process manager. Call Cleanup() to stop it.
func (*Manager) Cleanup ¶
func (m *Manager) Cleanup()
Cleanup shuts down all LSP processes and removes them.
func (*Manager) Close ¶
func (m *Manager) Close()
Close is an alias for Cleanup for API compatibility.
func (*Manager) EvictIdle ¶
EvictIdle removes LSP processes that haven't been used recently. The timeout specifies how long a process must be idle to be evicted.
func (*Manager) GetConfig ¶
func (m *Manager) GetConfig() []LanguageServerConfig
GetConfig returns the configured language server configs.
func (*Manager) GetOrCreate ¶
func (m *Manager) GetOrCreate(workspacePath, languageID string) (*LSPProcess, func(), error)
GetOrCreate returns an existing LSP process for the workspace+language, or starts a new one. Returns the process and a release function that should be called when the connection is done.
func (*Manager) SetConfig ¶
func (m *Manager) SetConfig(configs []LanguageServerConfig)
SetConfig sets the language server configs.
type MessageReader ¶
type MessageReader struct {
// contains filtered or unexported fields
}
MessageReader provides a convenient interface for reading messages.
func NewMessageReader ¶
func NewMessageReader(r io.Reader) *MessageReader
NewMessageReader creates a new message reader.
func (*MessageReader) Read ¶
func (mr *MessageReader) Read() (string, error)
Read reads the next message.
type MessageWriter ¶
type MessageWriter struct {
// contains filtered or unexported fields
}
MessageWriter provides a convenient interface for writing messages.
func NewMessageWriter ¶
func NewMessageWriter(w io.Writer) *MessageWriter
NewMessageWriter creates a new message writer.
func (*MessageWriter) Write ¶
func (mw *MessageWriter) Write(body string) error
Write writes a message.
func (*MessageWriter) Writef ¶
func (mw *MessageWriter) Writef(format string, args ...interface{}) error
Writef writes a formatted message.
type ServerSuggestion ¶
type ServerSuggestion struct {
Language string // Language name (e.g. "go", "python")
ProjectFile string // Detected project file (e.g. "Cargo.toml")
ServerID string // Matching server ID from DefaultLanguageServers
InstallHint string // Installation instructions for the server
}
ServerSuggestion represents a recommended language server for a workspace.
func SuggestServers ¶
func SuggestServers(workspaceRoot string) []ServerSuggestion
Detect project files in the given workspace root and return suggestions.