LanguageClient-neovim
LanguageClient-neovim copied to clipboard
Support TextDocumentSyncKind.Incremental
Is your feature request related to a problem? Please describe.
Currently the LanguageClient sends the full text of the document to the server on change. This is okay for small documents, but for large documents, this gets pretty slow.
Describe the solution you'd like
If the server supports TextDocumentSyncKind.Incremental, send incremental changes (using the range
and rangeLength
params of TextDocumentContentChangeEvent
(https://microsoft.github.io/language-server-protocol/specification#textDocument_didChange)
Neovim can report changed lines. See :help api-buffer-updates
. This is more granular than the TextChanged autocmd event, as it only reports the changed lines.
This has been considered before, but I don't think this API can be make use of in this plugin, https://github.com/autozimu/LanguageClient-neovim/commit/96079a7e267a70098e1833407afa60765bf8fa2e#diff-0ff387c7e4dec76c01cb77aa4d338ee1
On the other hand, I'm not sure how much difference between sending whole buffer and delta changes will affect the language server. With sending delta change, the server would needs to
- apply patches to buffer in memory (this is extra step)
- compile(?) and analyse the new file (this is the same step)
The optimized part is merely transported message size, which happenly to be very fast for stdio and local tcp connection.
This is only my speculation without actual evidences. Maybe some language server can/will be capable of taking advantages of delta changes.
Support can't be made as stated in previous comment.
Where I work, our development environment looks like this:
- All of our services and tooling run in "dev boxes" (i.e., a remote server), one for each developer. This makes it easy to control for differences in environment. If something looks out of place, we can always replace the dev box with a fresh one as a last resort.
- To keep the editing experience fast, all text editing is still done locally, so there's no lag when editing. An rsync script takes care of moving files from laptop to dev box.
LSP is at this weird junction: it deals with text editing (locally) and needs to know about how to run the code (on the dev box).
As it turns out, we're writing a language server for Ruby right now. The process of interacting with it right now looks like this:
- Run a script called
scripts/bin/typecheck
locally. - This script launches the language server on the dev box (communicating over SSH).
- The local script waits for input over
stdin
and forwards that input over SSH.
Going back to your guess:
Maybe some language server can/will be capable of taking advantages of delta changes.
We've noticed that sending the file every time in this configuration was very expensive. It seems that every language server running in a configuration similar to ours will be able to benefit from incremental changes. Why?
- network communication is slow
- network connections are unreliable (LTE tethering on a train going through a tunnel?)
- using SSH means that messages have to be encrypted
- and then, if the boxes are behind a VPN, the message is encrypted twice
For our language server, we just implemented incremental mode, and noticed huge improvements when testing it under VS Code. We'd love to see feature parity when using Neovim!
So my question is: have I convinced you of the value of this feature? And if so, would you be either willing to implement it or to review a PR that implements it?
(Also: thanks so much for this plugin! It's been crazy how much it Just Works given only a few lines of config 🙂)
Thanks for pointing out delta changes being useful in this setup.
With that said, I might not be able to work on it in the following months. But I can probably share some lights how it could be implemented. PR is very welcome.
- Calculate the delta changes locally before sending changes to language servers. Of course, we should check server supports delta changes.
- Change the RPC approach between this plugin and neovim to take advantage of neovim's buffer update API. This might need substantial changes and is limited to only neovim API, thus I'd prefer approach 1 if possible.
I am working was solving this as it came up in https://github.com/haskell/haskell-ide-engine/issues/924.
How important is it that TextDocumentSyncKind.Incremental
adhere to LanguageClient_changeThrottle
?
I think I can make the implementation adhere, but will complicate the implementation.
Using a non null LanguageClient_changeThrottle
and LanguageClient_useNvimUpdateApi
together will result in extra allocation and many TextDocumentContentChangeEvent
being sent right before a request to the server is made.
Edit
I switched long ago to Coc, which uses neovims API to implement this and many other features.
This issue also demonstrates why it might be important to add support for this :arrow_right: https://github.com/castwide/solargraph/issues/75