proxy

package
v0.17.4 Latest Latest
Warning

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

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

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

Constants

This section is empty.

Variables

View Source
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.

func NormalizeLanguageID

func NormalizeLanguageID(id string) string

NormalizeLanguageID normalizes a language ID string (lowercase, trim whitespace).

func ReadMessage

func ReadMessage(r io.Reader) (string, error)

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

func ResolveBinaryPath(binary string) (string, error)

ResolveBinaryPath resolves the full path to a binary on PATH. Returns an error if not found.

func WriteMessage

func WriteMessage(w io.Writer, body string) error

WriteMessage writes a single LSP Content-Length framed message to the writer.

func WriteMessagef

func WriteMessagef(w io.Writer, format string, args ...interface{}) error

WriteMessagef writes a formatted LSP message.

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

func (b *Bridge) Run(ctx context.Context) error

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

func NewManager(ctx context.Context) *Manager

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) Count

func (m *Manager) Count() int

Count returns the number of active LSP processes.

func (*Manager) EvictIdle

func (m *Manager) EvictIdle(timeout time.Duration)

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.

Jump to

Keyboard shortcuts

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