Skip to main content

Crate lattice_lsp

Crate lattice_lsp 

Source
Expand description

lattice-lsp – the LSP client (DESIGN.md §5.4, Phase 4).

§Why hand-rolled

tower-lsp is server-side. async-lsp brings tower middleware that doesn’t fit our actor model (every server is one tokio task with a mailbox + oneshot replies, identical to lattice-runtime::RopeDocumentHandle). The wire protocol is a few hundred lines of framing + JSON-RPC; reusing our existing cancellation primitives (CancellationToken) is cleaner than adapting middleware.

§Layering

  • framing – LSP’s Content-Length header parser. Pure; stream-agnostic; tested against partial reads, malformed headers, and oversized bodies.
  • jsonrpc – typed JSON-RPC 2.0 messages: requests with id correlation, responses, notifications, and ResponseError. No transport assumptions.
  • codec – glues framing + jsonrpc onto tokio::io::AsyncBufRead / AsyncWrite. Yields one jsonrpc::Message per read_message call; encodes one per write_message.
  • transport – spawns a child process and exposes its stdio as a codec reader / writer pair. Per DESIGN.md §5.4 each (workspace, server-id) gets one transport.
  • Future modules (folded in across 4.1.b–4.4):
    • actor – the per-server tokio task (mailbox + dispatch).
    • client – the editor-facing LspHandle analog of RopeDocumentHandle.
    • sync – AppliedEdit ↔ TextDocumentContentChangeEvent.
    • position – utf-8 ↔ utf-16 column conversion.
    • capabilities – client capability advertisement + server capability gating.

§Performance discipline

All public methods that talk to a server return Pending<T> (matching §5.2.1’s dispatch envelope); nothing blocks the UI. LSP requests are §5.2.5 Background-class – they have no sync-prelude budget and may be cancelled / superseded freely. Per-call performance characteristics live in benches/lsp.rs and are mirrored in docs/dev/operations/benchmarks.md.

Re-exports§

pub use actor::ServerHandle;
pub use actor::spawn;
pub use actor::spawn_with_io;
pub use apply_edit::ApplyEditBus;
pub use apply_edit::ApplyEditOutcome;
pub use apply_edit::InboundApplyEdit;
pub use buffer_names::LSP_SUBSYSTEM_LOG_NAME;
pub use buffer_names::lsp_server_log_name;
pub use buffer_names::lsp_server_trace_log_name;
pub use buffer_names::parse_lsp_server_log_name;
pub use buffer_names::parse_lsp_trace_log_name;
pub use capabilities::Capabilities;
pub use capabilities::FileOpKind;
pub use capabilities::client_capabilities;
pub use codec::LspReader;
pub use codec::LspWriter;
pub use config::ServerConfig;
pub use config::builtin_servers;
pub use config::resolve_workspace_root;
pub use configuration::ConfigurationBus;
pub use configuration::InboundConfigurationRequest;
pub use diagnostics::DIAGNOSTICS_CHANNEL_CAPACITY;
pub use diagnostics::DiagnosticEvent;
pub use diagnostics::DiagnosticsBus;
pub use diagnostics_layer::DiagnosticsLayer;
pub use diagnostics_layer::InlineDiagnosticSummary;
pub use diagnostics_layer::SeverityCounts;
pub use diagnostics_layer::pump_diagnostics;
pub use dynamic_registration::DynamicRegistration;
pub use dynamic_registration::DynamicRegistry;
pub use error::LspError;
pub use error::LspResult;
pub use events::LspActorExitReason;
pub use events::LspActorExited;
pub use events::LspBufferAttached;
pub use events::LspBufferDetached;
pub use events::LspCodeLensRefresh;
pub use events::LspDiagnosticRefresh;
pub use events::LspDocumentChanged;
pub use events::LspInlayHintRefresh;
pub use events::LspLogPushed;
pub use events::LspProgressKind;
pub use events::LspProgressUpdate;
pub use events::LspSemanticTokensRefresh;
pub use events::LspServerHealth;
pub use events::LspServerStatusChanged;
pub use file_watcher::WatcherSubscriptions;
pub use file_watcher::compile_with_workspace_root;
pub use framing::FrameError;
pub use framing::FrameHeader;
pub use install::install;
pub use logging::InstanceKey;
pub use logging::LogLevel;
pub use logging::LogRecord;
pub use logging::LogRing;
pub use logging::LogSource;
pub use logging::LspLogger;
pub use logging::format_log_event_line;
pub use logging::level_tag as log_level_tag;
pub use pending::InvocationId;
pub use pending::Pending;
pub use show_document::InboundShowDocument;
pub use show_document::ShowDocumentBus;
pub use show_document::ShowDocumentOutcome;
pub use show_message_request::InboundShowMessageRequest;
pub use show_message_request::ShowMessageRequestBus;
pub use show_message_request::ShowMessageRequestOutcome;
pub use supervisor::ActorKey;
pub use supervisor::LspSupervisor;
pub use supervisor::LspSupervisorHandle;
pub use supervisor::RestartReport;
pub use supervisor::SupervisorSnapshot;
pub use sync::DocSync;
pub use sync::uri_from_str;
pub use transport::ChildTransport;
pub use transport::TransportError;
pub use lsp_types;

Modules§

actor
Per-server actor (DESIGN.md §5.4 + §5.7). One tokio task owns the wire-side state for one (workspace, server-id) pair:
apply_edit
Server-initiated workspace/applyEdit plumbing (Phase 4.3; BC.8d reshape).
buffer_names
Canonical synthetic buffer names for the LSP log family.
cache
Per-buffer LSP response caches + outcome enums.
capabilities
Client capability advertisement (sent during initialize) and server capability storage (returned by initialize).
codec
Tokio-async codec gluing framing + jsonrpc onto AsyncBufRead / AsyncWrite. One read_message / write_message per LSP message.
completion
LSP completion source (CSM.8a / CSM.8b).
config
Per-language-server configuration.
configuration
Server-initiated workspace/configuration plumbing (Phase 4.1 follow-up; BC.8b reshape).
diagnostics
Diagnostics routing: textDocument/publishDiagnostics → editor subscribers (Phase 4.1.d.i).
diagnostics_layer
DiagnosticsLayer – the editor’s view of every server’s publishDiagnostics events, keyed for multi-server merging and version-gated against stale publishes (Phase 4.1.d.ii).
dynamic_registration
Dynamic capability tracking (LSP §3.18.10.3 / 4.4.n).
error
Error surface for the LSP client. Kept narrow and shape-rich so the editor can branch on the failure (UI surface) instead of pattern-matching error strings.
error_list_feed
EP.3 (2026-08-10): the language server as a second producer of the core error list.
events
LSP-owned editor-bus events (M.5.3.b).
fan_in
Per-actor LspDocumentChanged -> ActorCmd::RecordEdit fan-in.
features
Typed wrappers around crate::ServerHandle::request_with_cancel for the LSP navigation features (DESIGN.md §5.4 + Phase 4.2).
file_watcher
File-watcher subscription compilation + matching (4.4.l).
framing
LSP Content-Length header framing (Microsoft LSP base protocol). Pure parser – no IO, no allocations beyond the returned FrameHeader.
help_views
LSP-specific help-buffer factories (DESIGN.md §5.11).
install
BC.8a (2026-06-24): the crate-owned install(boot) entry point.
jsonrpc
JSON-RPC 2.0 message types now live in lattice-protocol (IDE-protocol Risk 3 lift) so lattice-claude-code can share them. Re-exported here as lattice_lsp::jsonrpc so existing crate::jsonrpc::* paths, downstream callers, tests, and benches keep resolving unchanged. JSON-RPC 2.0 message types. Lifted out of lattice-lsp (IDE-protocol Risk 3) so a second peer-protocol crate (lattice-claude-code) can reuse the wire shape without an ide -> lsp crate edge. The types are transport-agnostic; each peer’s codec writes the bytes. JSON-RPC 2.0 message types – the wire shape of every LSP exchange. Transport-agnostic: these types serialize through serde_json::to_string, the codec writes the bytes.
logging
LSP logging facade – the producer side of the *lsp* / *lsp:<server>* / *lsp:<server>:trace* buffer views (Phase 4.1.f).
modeline
LSP modeline element (ML.3c) + the shared progress/status store it is built from. Produced entirely in lattice-lsp (the owner) and pushed over the event bus.
modes
LSP modes.
pending
Pending<T> – the typed handle returned by every actor-side request. Mirrors lattice_runtime::Pending (DESIGN.md §5.2.1) but parameterised over LspError so server-side error codes survive on the way back to the caller.
position
Position-encoding conversion (LSP 3.17 §3.17 / §General).
providers
LR.1 (2026-08-11): multibuffer-backed LSP surfaces.
show_document
Server-initiated window/showDocument plumbing (4.4.b; BC.8c reshape).
show_message_request
Server-initiated window/showMessageRequest plumbing (4.4.b; BC.8e reshape).
supervisor
LspSupervisor – the per-buffer attachment manager (Phase 4.1.h).
sync
Document synchronisation: didOpen / didChange (incremental or full) / didClose. One DocSync is owned per actor; it shadows every buffer the server cares about with a string mirror so we can translate Position { line, byte } to the negotiated LSP encoding without re-querying the editor’s rope.
transport
Child-process transport for an LSP server.

Structs§

Diagnostic
Represents a diagnostic, such as a compiler error or warning. Diagnostic objects are only valid in the scope of a resource.
DiagnosticSeverity
The protocol currently supports the following diagnostic severities:
InlayHint
Inlay hint information.
InlayHintLabelPart
An inlay hint label part allows for interactive and composite labels of inlay hints.
LspPosition
Position in a text document expressed as zero-based line and character offset. A position is between two characters like an ‘insert’ cursor in a editor.
LspRange
A range in a text document expressed as (zero-based) start and end positions. A range is comparable to a selection in an editor. Therefore the end position is exclusive.
Notification
One JSON-RPC notification: fire-and-forget, no response. LSP uses these for textDocument/didChange, textDocument/publishDiagnostics, $/progress, and the like.
Request
One JSON-RPC request that expects a response. params is optional per JSON-RPC; LSP methods that take no parameters should send params: null (or omit). We always include it as null to keep the wire layout uniform.
Response
One JSON-RPC response. Either result or error is set; never both.
ResponseError
JSON-RPC error envelope. code is one of the standard integers from the JSON-RPC spec (error_codes), a JSON-RPC implementation-defined server error (-32099 ..= -32000), or one of LSP’s own codes (-32899 ..= -32800); message is human-readable; data is whatever the server attaches.
Uri
Newtype struct around fluent_uri::Uri<String> with serialization implementations that use as_str() and ‘from_str()’ respectively.

Enums§

InlayHintLabel
Message
One incoming or outgoing JSON-RPC message. The codec yields Message from the wire; the actor matches on the variant.
RequestId
Per JSON-RPC, an id is a string, a number, or null. LSP servers in the wild send all three; clients (us) only emit Number, but we accept all on the read path.

Functions§

inlay_hint_label_text
Flatten an LSP InlayHintLabel into a single plain String. String variants return as-is; LabelParts(Vec<LabelPart>) concatenates each part’s value. Tooltip / command / location fields on label parts are ignored — they’re resolve / hover affordances, not a paint concern.