Full-document didChange went out per keystroke: three O(file) copies,
O(file) JSON, and a BLOCKING pipe write on the daemon main thread
(Linux pipe buffers are 64KiB; a 240KB notification stalls the frame
loop until the langserver drains). The dominant daemon-side typing
cost on large files, and freeze-class when a server stops reading.
- lsp.lua: the after-edit hook now bumps the version, marks the
cached render families stale (new _mark_document_stale binding, so
stale suppression stays keystroke-accurate), and records the buffer
dirty. The coalesced send fires on the async tick after 75ms of
quiet, or at most 400ms behind during continuous typing. Anything
that consults the server flushes first (attached_for_active,
repull_for_attachments, pull_inlay_hints_quiet) so requests and
position-encoding conversion never see stale text. Versions may
skip values; LSP only requires they increase.
- Inlay hints re-pull at flush cadence: they're pull-model, nothing
re-requested them after edits, so hints died on the first
keystroke and never returned.
- process.rs StdinWriter: a per-generation writer thread owns the
child's stdin; write_stdin queues and never blocks (64MiB budget
converts a wedged child into an error); close_stdin drains then
EOFs, preserving the MCP flush-then-EOF contract.
- pmacs.editor.monotonic_ms + pmacs.lsp._flush_did_changes bindings;
acceptance test pins burst-coalescing, flush-on-demand, and the
quiet-window tick flush.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>