Description
Context
I maintain a markdown language server that is used by 6 different LSP clients. Sometimes I get bug reports like this (Neovim editor) or this (Helix editor) but getting a repro is very hard and debugging is very time consuming (especially, given that I don't personally use all 6 LSP clients on a daily basis).
Even when I can find a repro (like in this case with Emacs lsp-mode) this is just 1 client out of 6.
One thing that can simplify my life as a maintainer of an LSP sever is stronger validation.
The proposal
Update: Replace 'starting version' with 'content hash' below. The spirit of the proposal hasn't changed and is about enabling stronger validation for incremental text sync.
This is relevant for the incremental text sync. The protocol currently has the following in textDocument/didChange
:
/**
* The document that did change. The version number points
* to the version after all provided content changes have
* been applied.
*/
textDocument: VersionedTextDocumentIdentifier;
The version number there is "the version after all provided content changes have been applied".
I find this problematic because each LSP client (nvim lsp, emacs lsp-mode & eglot, sublime text, helix, etc.) has its own way of dealing with document versions:
- some increment by 1 on each change notifications,
- others increment by the number of content changes in the change notification,
- other just increment by a seemingly random number that is tied to their internal counters.
This means that if there's a bug in a client (or in the server), the state can subtly drift apart until the server receives a change that violates the state of the document that it has.
This prevents stronger validation on the server side, and makes triaging and debugging incremental text sync issues very painful.
Having both an starting and a final version in the document change notification would allow the server to check its current version with the notification's initial version and if there's a mismatch to abort early. Also, would simplify triaging: is it a client error? is it a race condition or some other bug in the server?
Perhaps I'm missing something in the spec that would allow me to do this type of stronger validation of the state?