LanguageServer Struct
LanguageServer
lsp.rs:99
pub struct LanguageServer {
server_id: LanguageServerId,
outbound_tx: channel::Sender<String>, // → server stdin
notification_tx: channel::Sender<NotificationSerializer>,
name: LanguageServerName,
capabilities: RwLock<ServerCapabilities>,
notification_handlers: Arc<Mutex<HashMap<&'static str, Handler>>>,
response_handlers: Arc<Mutex<Option<HashMap<RequestId, Handler>>>>,
server: Arc<Mutex<Option<Child>>>, // spawned process
workspace_folders: Option<Arc<Mutex<BTreeSet<Uri>>>>,
}
The server process is spawned with std::process::Command. Zed reads the server's stdout on a background thread, parses JSON-RPC messages, and dispatches them to the appropriate handler via the maps above.
Server Lifecycle
initialize
LspStore spawns the binary. Sends
initialize request with workspace folders and client capabilities. Server responds with its own ServerCapabilities.initialized (notification)
Client confirms it received capabilities. The server is now fully active.
textDocument/didOpen (per buffer)
When a buffer is first associated with this server, the full document content is sent. The server begins tracking changes.
textDocument/didChange (per edit)
After each buffer mutation, an incremental or full-content update is sent. The server re-analyzes and pushes fresh diagnostics via
textDocument/publishDiagnostics.shutdown / exit
When the project closes or the server crashes,
LspStore sends the shutdown sequence and kills the process.Edit → Diagnostics Round-Trip
Buffer
edit applied
← diagnostics stored
cx.notify() → re-render
→
LspStore
observes BufferEvent::Edited
receives publishDiagnostics
→
LanguageServer
sends didChange
← pushes diagnostics
Async boundary: diagnostics arrive on an arbitrary background thread. The JSON-RPC receiver posts a foreground task that updates
Buffer::diagnostics and calls cx.notify(), keeping all entity mutation single-threaded.
LSP Feature Coverage
| Method | Direction | What Zed does with the result |
|---|---|---|
| textDocument/publishDiagnostics | Server → Client (push) | Stores in Buffer::diagnostics; rendered as inline underlines and gutter icons |
| textDocument/completion | Request/response | Populates the completion menu; items include edits, documentation, and kind icons |
| textDocument/hover | Request/response | Shown in a floating popover with markdown-rendered documentation |
| textDocument/definition | Request/response | Opens target file and jumps to the definition location |
| textDocument/rename | Request/response | Applies the returned WorkspaceEdit across all affected files |
| textDocument/formatting | Request/response | Applies text edits to buffer on save or via the Format action |
| textDocument/inlayHint | Request/response | Passed to DisplayMap as virtual inlay text between buffer characters |