From 2791a6f18dd2befe6b064d070d66ca08faae64fd Mon Sep 17 00:00:00 2001 From: Girish Palya Date: Sun, 25 Jun 2023 13:26:37 +0200 Subject: [PATCH] Make buffer completion responsive for large files Since buffer completion processes the current buffer everytime user types something, it will degrade the experience for large files. This change adds a timeout to buffer completor function. Processing current buffer is cut short when timeout is exceeded. Setting timeout to 0 will revert back to existing behaviour. Default is set to 100 ms, good for scanning 6000 lines on M1 macbook. It is possible to get fancy by scanning locality of cursor first but such complication may not be worth the complexity. Tested on >20k line files (I have to open these large C files filled with hw specs occasionally). M autoload/lsp/completion.vim M autoload/lsp/options.vim M doc/lsp.txt --- autoload/lsp/completion.vim | 38 ++++++++++++++++++++++--------------- autoload/lsp/options.vim | 2 ++ doc/lsp.txt | 13 ++++++++++--- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/autoload/lsp/completion.vim b/autoload/lsp/completion.vim index 66ea9c5..9b2d598 100644 --- a/autoload/lsp/completion.vim +++ b/autoload/lsp/completion.vim @@ -114,22 +114,30 @@ enddef # add completion from current buf def CompletionFromBuffer(items: list>) - var words = {} - for line in getline(1, '$') - for word in line->split('\W\+') - if !words->has_key(word) && word->len() > 1 - words[word] = 1 - items->add({ - label: word, - data: { - entryNames: [word], - }, - kind: 26, - documentation: "", - }) - endif - endfor + var words = {} + var start = reltime() + var linenr = 1 + for line in getline(1, '$') + for word in line->split('\W\+') + if !words->has_key(word) && word->len() > 1 + words[word] = 1 + items->add({ + label: word, + data: { + entryNames: [word], + }, + kind: 26, + documentation: "", + }) + endif endfor + # Check every 200 lines if timeout is exceeded + if opt.lspOptions.bufferCompletionTimeout > 0 && linenr % 200 == 0 && + start->reltime()->reltimefloat() * 1000 > opt.lspOptions.bufferCompletionTimeout + break + endif + linenr += 1 + endfor enddef # process the 'textDocument/completion' reply from the LSP server diff --git a/autoload/lsp/options.vim b/autoload/lsp/options.vim index 8ccf7e4..be55f05 100644 --- a/autoload/lsp/options.vim +++ b/autoload/lsp/options.vim @@ -77,6 +77,8 @@ export var lspOptions: dict = { useQuickfixForLocations: false, # add to autocomplition list current buffer words useBufferCompletion: false, + # Limit the time autocompletion searches for words in current buffer (in milliseconds) + bufferCompletionTimeout: 100, # Enable support for custom completion kinds customCompletionKinds: false, # A dictionary with all completion kinds that you want to customize diff --git a/doc/lsp.txt b/doc/lsp.txt index 910dcd1..3c212fb 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -589,10 +589,17 @@ useQuickfixForLocations |Boolean| option. Show |:LspShowReferences| in a *lsp-opt-useBufferCompletion* useBufferCompletion |Boolean| option. If enabled, the words from the current buffer are added to the auto completion list. - This may degrade Vim performance as the current buffer - contents are processed every time the completion menu - is displayed. By default this is set to false. + *lsp-opt-bufferCompletionTimeout* +bufferCompletionTimeout |Number| option. Specifies how long (in milliseconds) + to wait while processing current buffer for + autocompletion words. If set too high Vim performance + may degrade as the current buffer contents are + processed every time the completion menu is displayed. + If set to 0 the entire buffer is processed without + regard to timeout. + By default this is set to 100 ms (good for scanning + a file of about 6000 lines on M1 Macbook). For example, to disable the automatic placement of signs for the LSP diagnostic messages, you can add the following line to your .vimrc file: > -- 2.44.0