A batteries-included Rust framework for building Language Server Protocol servers — the 1:1 Rust port of gossip (Go).
| Go package | Rust crate | Status |
|---|---|---|
gossip (root) |
crates/rumor |
✅ full: Server, all On* registrations (34 requests + 7 notifications), Context accessors + typed Config<T>, ClientProxy (14 server→client calls), capability auto-detection (triggers/legend/commands, prepareRename gating, legend warning), middleware wiring with default innermost recovery, initialize/shutdown/exit lifecycle (OnExit hook, exit codes 0/1), double-initialize rejection, FromArgs flag matrix incl. subprocess-verified exits, multi-root FolderFor (boundary-safe copies), Check/Analyze + hooks, TreeFor/TreeAt |
jsonrpc |
rumor-jsonrpc |
✅ Content-Length codec (16 KiB header cap, atomic max-size, negative-length rejection, zero-alloc steady-state writes), Conn with thread-per-request + FIFO notification dispatcher, $ /cancelRequest cancelling in-flight request contexts, connection-scoped cancel tokens, parse-error recovery, reqKey correlation |
protocol |
rumor-protocol |
✅ all LSP types (serde camelCase + omitempty semantics), METHOD constants, range predicates/Merge/Clamp, URI canonicalization (platform-independent drive letters, UNC hosts, dot segments, canonical fast path) |
document |
rumor-document |
✅ normalized-key store, incremental edits w/ EditRange intermediate frames, CRLF-aware UTF-16 position math with clamping and surrogate handling, nil-safe callbacks |
treesitter |
rumor-treesitter |
✅ parser-per-document manager (per-URI locks, eviction, progressive batch snapshots), diagnostic engine (checks auto-merge, analyzer Scope/InterestKinds gating, MergePrevious, transformer, user data, PublishDirect, invalidation), true UTF-16 ChangedRanges, symbol-table kind collection, query helpers, language matcher priority chain |
config |
rumor-config |
✅ TOML typed load w/ deep-copied defaults + undecoded-key warnings + Validatable hook, rename-safe debounced watcher (bounded re-add retry, Close joins in-flight), atomic-snapshot Store with panic-isolated listeners, per-folder WorkspaceBridge sharing one Store |
middleware |
rumor-middleware |
✅ Chain (first = outermost), Logging, Recovery (generic client message, stack logged), Telemetry snapshots, Tracing |
lspclient |
rumor-lspclient |
✅ child process client (30 s handshake, syncKind tracking + mismatch warn-once, generation-safe crash reset, shutdown→exit→kill ladder), DiagnosticAggregator (multi-source merge, debounce re-arm, Clear/ClearSource semantics) |
jsonschema |
rumor-jsonschema |
✅ strict Load (unresolved refs + bad patterns error), validator (oneOf multi-match, type arrays, tuple items, precompiled patternProperties, rune lengths, const-null), required-first deterministic completions, Levenshtein suggest with length pre-filter, adapter |
transport |
rumor-transport |
✅ stdio, TCP, Unix socket, pipe alias, WebSocket (single-client claim, second client cleanly rejected), Node IPC (fd 3), memory pipe; direction-capable split() for JSON-RPC's concurrent read/write |
gossiptest |
rumor-test |
✅ in-memory harness answering server→client requests, typed helpers (open/change/change_incremental/hover/completion/definition/save/close/shutdown), diagnostics polling, assertions (hover/completion contains, location count, newest-first diagnostic count, sorted-diff ranges), fixtures, tree helpers |
Go's goroutine/channel design maps to threads + crossbeam-channel +
parking_lot locks. No async runtime: handler code is plain synchronous
Rust, exactly like the Go original.
crates/
├── rumor/ root framework (server, handlers, serve, options)
├── rumor-protocol/ LSP wire types, methods, range + URI utilities
├── rumor-document/ document store, incremental edits, positions
├── rumor-treesitter/ tree-sitter integration + diagnostic engine
├── rumor-config/ typed TOML config with hot reload
├── rumormiddleware/ composable middleware
├── rumor-lspclient/ child LSP client + diagnostic aggregator
├── rumor-jsonrpc/ JSON-RPC framing + bidirectional connection
├── rumor-jsonschema/ schema validation + completions
├── rumor-transport/ transports behind one trait
└── rumor-test/ testing harness + assertions
use rumor::prelude::*;
let server = Server::new("my-lang", "0.1.0", vec![]);
server.on_hover(|_ctx, _params| {
Ok(Some(protocol::Hover {
contents: protocol::MarkupContent {
kind: protocol::MARKUP_PLAIN_TEXT.into(),
value: "hello".into(),
},
}))
});
rumor::serve(&server, vec![ServeOption::stdio()])?;cargo test --workspace — 412+ tests across 11 crates, all green.
See PARITY.md for the binding Go↔Rust contract used during the port.