The server advertises textDocument/sync.change: 1 (Full), and TextDocumentSyncHandler::handleDidChange reads the last contentChanges[] entry and passes a whole-file string to DocumentManager::update. DocumentManager has no ranged-edit API.
Consequences on every keystroke of an open document:
- The client sends the whole file text.
- The whole file is re-parsed through
SyntaxSource.
- The whole file is re-scanned by
DeclarationScanner.
- The write path re-registers every declared symbol into
OpenDocumentBackend.
For small files this is fine; for large files this is the dominant cost of typing. It also caps the size of file the server can serve responsively.
Direction
Support LSP's Incremental (change kind 2). Rough shape:
DocumentManager gains a ranged-edit API. applyChanges(uri, list<TextEdit>) (or similar) applies changes in the LSP-specified order, adjusting subsequent ranges as it goes. The stored text remains authoritative; the parse and scan still take the full text.
- Advertise
change: 2. CapabilityNegotiator reports incremental; the sync handler accepts either shape (some clients still send full).
- Consider deferring the parse. With incremental edits the parse is cheap to trigger but not necessarily cheap to run; a debounce or "reparse on first read after change" strategy would decouple keystroke cost from typing rate. Out of scope here unless it falls out naturally.
The parse and scan cost per keystroke is the dominant work today. Ranged edits alone reduce transport cost but not parse cost; a deferred/debounced parse is where the responsiveness win comes from. Filing this issue as the transport half; the debounce is worth a follow-up when the cost profile is visible.
Done
Related: #371 (position encoding), #444 (scheduler tier — a debounced re-parse would live there).
Issue body drafted by AI.
The server advertises
textDocument/sync.change: 1(Full), andTextDocumentSyncHandler::handleDidChangereads the lastcontentChanges[]entry and passes a whole-file string toDocumentManager::update.DocumentManagerhas no ranged-edit API.Consequences on every keystroke of an open document:
SyntaxSource.DeclarationScanner.OpenDocumentBackend.For small files this is fine; for large files this is the dominant cost of typing. It also caps the size of file the server can serve responsively.
Direction
Support LSP's
Incremental(change kind 2). Rough shape:DocumentManagergains a ranged-edit API.applyChanges(uri, list<TextEdit>)(or similar) applies changes in the LSP-specified order, adjusting subsequent ranges as it goes. The stored text remains authoritative; the parse and scan still take the full text.change: 2.CapabilityNegotiatorreports incremental; the sync handler accepts either shape (some clients still send full).The parse and scan cost per keystroke is the dominant work today. Ranged edits alone reduce transport cost but not parse cost; a deferred/debounced parse is where the responsiveness win comes from. Filing this issue as the transport half; the debounce is worth a follow-up when the cost profile is visible.
Done
DocumentManagersupports ranged edits, applied in LSP-specified order.TextDocumentSyncHandlerhandles bothFullandIncrementalchange kinds.CapabilityNegotiatoradvertisesIncremental.Related: #371 (position encoding), #444 (scheduler tier — a debounced re-parse would live there).
Issue body drafted by AI.