Errors, Stale Results, and Shutdown
Errors become editor-visible state
Job futures return anyhow::Result. A failed ordinary spawned job is reported
through the event/status system; a failed waited job becomes Async job failed
in the editor or propagates during final draining. The application loop remains
alive because one optional feature failed.
Versioning separates completion from validity
Documents increment an LSP version on each real change. Async commands commonly capture a document ID, version, selection, or rope snapshot. Their callbacks must re-find the document and decide whether a result still applies. Completion only means “the service answered”; it does not prove the answer describes the current buffer.
Redraw pressure is coalesced
request_redraw wakes the editor, but wait_event schedules a redraw timer
rather than rendering once for every producer notification. This converts a
potential event storm into a bounded frame rate while still allowing urgent
foreground event handling.
Shutdown distinguishes protocol courtesy from process control
close_language_servers
enqueues shutdown and exit for every server, then waits only until those bytes
are flushed to each server’s stdin. The wait has a timeout. It does not wait
indefinitely for an external process to behave; process handles are configured
to be reaped when dropped.
Jobs opt into wait_before_exiting. Final drain executes their callbacks when
the necessary mutable references still exist and can enqueue follow-up waited
jobs. Clean exit is therefore an explicit transitive obligation, not “sleep a
little and hope.”