← Overview Stage 6 / LSP Integration
Stage 6 of 7

LSP Integration

Zed spawns per-project language server processes and communicates over JSON-RPC 2.0. After each buffer edit, the server is notified; diagnostics, completions, and hover data flow back asynchronously.

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
Code References