LanguageClient-neovim icon indicating copy to clipboard operation
LanguageClient-neovim copied to clipboard

Support TextDocumentSyncKind.Incremental

Open Jesse-Bakker opened this issue 6 years ago • 7 comments

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)

Jesse-Bakker avatar Aug 06 '18 13:08 Jesse-Bakker

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.

Jesse-Bakker avatar Aug 06 '18 15:08 Jesse-Bakker

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

  1. apply patches to buffer in memory (this is extra step)
  2. 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.

autozimu avatar Aug 06 '18 16:08 autozimu

Support can't be made as stated in previous comment.

autozimu avatar Sep 04 '18 01:09 autozimu

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 🙂)

jez avatar Sep 07 '18 21:09 jez

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.

  1. Calculate the delta changes locally before sending changes to language servers. Of course, we should check server supports delta changes.
  2. 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.

autozimu avatar Sep 08 '18 01:09 autozimu

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.

Avi-D-coder avatar Nov 07 '18 03:11 Avi-D-coder

This issue also demonstrates why it might be important to add support for this :arrow_right: https://github.com/castwide/solargraph/issues/75

grzesiek avatar Jan 02 '20 12:01 grzesiek