1

I have implemented a LSP for a VSCode extension that provides a series of diagnostics for the opened document(s).

The execution of the function that evaluates the document occurs in the onDidChangeContent event (server side):

documents.onDidChangeContent(async event => {
    await validateTextDocument(event.document)
})

Now the issue comes when the document is quite long and you start typing or making changes rapidly. The validateTextDocument() can take a few seconds for these long documents and since documents.onDidChangeContent() will fire on each keystroke, the computer starts overloading with too many requests.

Is there any way to prevent the client from making any more requests until the server has responded? or even cancel the onDidChangeContent altogether?

Thanks in advance

Fran Casadome
  • 508
  • 4
  • 15

2 Answers2

1
  • use the Document link provider vscode.languages.registerDocumentLinkProvider
  • return an empty list of links

it will only call you when you haven't typed for a while

rioV8
  • 24,506
  • 3
  • 32
  • 49
  • Thank you for your answer: Use it in the client? because in the server side i don't have access to the VSCode api, only to vscode-languageserver. Also, do you have any link for documentation or examples on this? – Fran Casadome Sep 03 '22 at 23:37
  • @FranCasadome Have you looked at the VSC extension samples – rioV8 Sep 04 '22 at 02:24
  • I'm reviewing https://github.com/microsoft/vscode-extension-samples/blob/main/contentprovider-sample/src/provider.ts but i don't see the connection of a link provider in relation to the events fired by document changes? – Fran Casadome Sep 04 '22 at 03:34
  • @FranCasadome the document link provider gets called some time after the user stops typing, just register the provider and see when it gets called – rioV8 Sep 04 '22 at 10:03
  • @FranCasadome You could use a timer to determine when the user has stopped typing and only then do the validate call, this will reduce the calls, reset timer on each change event when it exists – rioV8 Sep 04 '22 at 10:11
  • I can't do any of those things in the client because is a language server protocol implementation (https://microsoft.github.io/language-server-protocol/). The client controls the document changes and notifies the server, but i don't have any control over that, only when the notification arrives to the event handler on the server side – Fran Casadome Sep 04 '22 at 15:04
  • 1
    @FranCasadome then do the timer trick to reduce "calls" – rioV8 Sep 04 '22 at 15:44
  • I tried blocking the event handler while executing, but the events are still executed in order, only with a delay that increases the more you type. For large documents you type 10 characters and ~30secs later all the 10 "changed" events finish executing. But like I said, I don't have any control over the LSP client sending events (that I'm aware of), only on how to deal with them on the server with the onDidChangeContent() function. – Fran Casadome Sep 04 '22 at 15:57
  • @FranCasadome then ignore the change event when you are calculating a previous event, that is done in the timer handler – rioV8 Sep 04 '22 at 19:40
0

I'll take this approach as the final solution. I haven't found anything on the LSP client's side that will allow me to limit the number of events fired.

This is the best solution I've come up with on the server side. Just store all the received events and only execute last one every interval of 1 second discarding the rest. It works more or less OK

let eventBuffer: TextDocumentChangeEvent<TextDocument>[] = []
documents.onDidChangeContent(event => eventBuffer.push(event))

setInterval(async () => {
    if (eventBuffer.length > 0) {
        const event = eventBuffer.pop()
        eventBuffer = []
        await validateTextDocument(event!.document)
    }
}, 1000);
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Fran Casadome
  • 508
  • 4
  • 15