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’sContent-Lengthheader 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, andResponseError. No transport assumptions.codec– glues framing + jsonrpc ontotokio::io::AsyncBufRead/AsyncWrite. Yields onejsonrpc::Messageperread_messagecall; encodes one perwrite_message.transport– spawns a child process and exposes its stdio as acodecreader / 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-facingLspHandleanalog ofRopeDocumentHandle.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/applyEditplumbing (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 byinitialize). - codec
- Tokio-async codec gluing
framing+jsonrpcontoAsyncBufRead/AsyncWrite. Oneread_message/write_messageper LSP message. - completion
- LSP completion source (CSM.8a / CSM.8b).
- config
- Per-language-server configuration.
- configuration
- Server-initiated
workspace/configurationplumbing (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’spublishDiagnosticsevents, 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::RecordEditfan-in. - features
- Typed wrappers around
crate::ServerHandle::request_with_cancelfor the LSP navigation features (DESIGN.md §5.4 + Phase 4.2). - file_
watcher - File-watcher subscription compilation + matching (4.4.l).
- framing
- LSP
Content-Lengthheader framing (Microsoft LSP base protocol). Pure parser – no IO, no allocations beyond the returnedFrameHeader. - 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) solattice-claude-codecan share them. Re-exported here aslattice_lsp::jsonrpcso existingcrate::jsonrpc::*paths, downstream callers, tests, and benches keep resolving unchanged. JSON-RPC 2.0 message types. Lifted out oflattice-lsp(IDE-protocol Risk 3) so a second peer-protocol crate (lattice-claude-code) can reuse the wire shape without anide -> lspcrate 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 throughserde_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. Mirrorslattice_runtime::Pending(DESIGN.md §5.2.1) but parameterised overLspErrorso 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/showDocumentplumbing (4.4.b; BC.8c reshape). - show_
message_ request - Server-initiated
window/showMessageRequestplumbing (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. OneDocSyncis owned per actor; it shadows every buffer the server cares about with a string mirror so we can translatePosition { 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.
- Diagnostic
Severity - The protocol currently supports the following diagnostic severities:
- Inlay
Hint - Inlay hint information.
- Inlay
Hint Label Part - 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.
paramsis optional per JSON-RPC; LSP methods that take no parameters should sendparams: null(or omit). We always include it asnullto keep the wire layout uniform. - Response
- One JSON-RPC response. Either
resultorerroris set; never both. - Response
Error - JSON-RPC error envelope.
codeis 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);messageis human-readable;datais whatever the server attaches. - Uri
- Newtype struct around
fluent_uri::Uri<String>with serialization implementations that useas_str()and ‘from_str()’ respectively.
Enums§
- Inlay
Hint Label - Message
- One incoming or outgoing JSON-RPC message. The codec yields
Messagefrom the wire; the actor matches on the variant. - Request
Id - 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
InlayHintLabelinto a single plainString.Stringvariants return as-is;LabelParts(Vec<LabelPart>)concatenates each part’svalue. Tooltip / command / location fields on label parts are ignored — they’re resolve / hover affordances, not a paint concern.