From 23479367fcd6452f7c8b4e20fff8605cdfef326d Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Thu, 28 Jan 2021 21:28:01 -0800 Subject: [PATCH] Instead of always trying to complete symbols, use omni completion --- autoload/handlers.vim | 36 +++++------------------ autoload/lsp.vim | 67 +++++++++++++++++++++++++----------------- autoload/lspserver.vim | 3 +- doc/lsp.txt | 8 +++++ 4 files changed, 58 insertions(+), 56 deletions(-) diff --git a/autoload/handlers.vim b/autoload/handlers.vim index dd86f4a..944e51b 100644 --- a/autoload/handlers.vim +++ b/autoload/handlers.vim @@ -32,11 +32,17 @@ def s:processInitializeReply(lspserver: dict, req: dict, reply: dicthas_key('completionProvider') + var triggers = caps.completionProvider.triggerCharacters + for ch in triggers + exe 'inoremap ' .. ch .. ' ' .. ch .. "" + endfor lspserver.completionTriggerChars = caps.completionProvider.triggerCharacters endif + # send a "initialized" notification to server lspserver.sendInitializedNotif() @@ -156,7 +162,6 @@ def s:processCompletionReply(lspserver: dict, req: dict, reply: dict> = [] for item in items var d: dict = {} if item->has_key('textEdit') && item.textEdit->has_key('newText') @@ -183,35 +188,10 @@ def s:processCompletionReply(lspserver: dict, req: dict, reply: dictadd(d) - endfor - - if completeItems->empty() - return - endif - - # Find the start column for the completion. If any of the entries returned - # by the LSP server has a starting position, then use that. - var start_col: number = 0 - for item in items - if item->has_key('textEdit') - start_col = item.textEdit.range.start.character + 1 - break - endif + lspserver.completeItems->add(d) endfor - # LSP server didn't return a starting position for completion, search - # backwards from the current cursor position for a non-keyword character. - if start_col == 0 - var line: string = getline('.') - var start = col('.') - 1 - while start > 0 && line[start - 1] =~ '\k' - start -= 1 - endwhile - start_col = start + 1 - endif - - complete(start_col, completeItems) + lspserver.completePending = false enddef # process the 'textDocument/hover' reply from the LSP server diff --git a/autoload/lsp.vim b/autoload/lsp.vim index f551ca3..0e04d61 100644 --- a/autoload/lsp.vim +++ b/autoload/lsp.vim @@ -276,11 +276,9 @@ def lsp#addFile(bnr: number): void # add a listener to track changes to this buffer listener_add(function('lsp#bufchange_listener'), bnr) setbufvar(bnr, '&completeopt', 'menuone,popup,noinsert,noselect') + setbufvar(bnr, '&omnifunc', 'lsp#omniFunc') setbufvar(bnr, '&completepopup', 'border:off') setbufvar(bnr, '&balloonexpr', 'LspDiagExpr()') - # autocmd for insert mode completion - exe 'autocmd SafeState if mode() == "i" | call lsp#complete() | endif' exe 'autocmd InsertLeave call lsp#leftInsertMode()' # map characters that trigger signature help @@ -526,35 +524,50 @@ def lsp#jumpToDiag(which: string): void WarnMsg('Error: No more diagnostics found') enddef -# Insert mode completion handler -def lsp#complete(): string - var cur_col: number = col('.') - var line: string = getline('.') - - if cur_col == 0 || line->empty() - return '' - endif - +# omni complete handler +def lsp#omniFunc(findstart: number, base: string): any var ftype: string = &filetype var lspserver: dict = s:lspGetServer(ftype) - if lspserver->empty() || !lspserver.running || lspserver.caps->empty() - return '' - endif - - if line[cur_col - 2] !~ '\k' - if lspserver.completionTriggerChars->index(line[cur_col - 2]) == -1 - return '' + if findstart + if lspserver->empty() + ErrMsg('Error: LSP server for "' .. ftype .. '" filetype is not found') + return -2 + endif + if !lspserver.running + ErrMsg('Error: LSP server for "' .. ftype .. '" filetype is not running') + return -2 endif - endif - - # first send all the changes in the current buffer to the LSP server - listener_flush() - - # initiate a request to LSP server to get list of completions - lspserver.getCompletion() - return '' + # first send all the changes in the current buffer to the LSP server + listener_flush() + + lspserver.completePending = v:true + lspserver.completeItems = [] + # initiate a request to LSP server to get list of completions + lspserver.getCompletion() + + # locate the start of the word + var line = getline('.') + var start = charcol('.') - 1 + while start > 0 && line[start - 1] =~ '\k' + start -= 1 + endwhile + return start + else + var count: number = 0 + while !complete_check() && lspserver.completePending + && count < 1000 + sleep 2m + count += 1 + endwhile + + var res: list> = [] + for item in lspserver.completeItems + res->add(item) + endfor + return res->empty() ? v:none : res + endif enddef # Display the hover message from the LSP server for the current cursor diff --git a/autoload/lspserver.vim b/autoload/lspserver.vim index 3a24e6c..922c0b5 100644 --- a/autoload/lspserver.vim +++ b/autoload/lspserver.vim @@ -57,6 +57,7 @@ def s:startServer(lspserver: dict): number lspserver.caps = {} lspserver.nextID = 1 lspserver.requests = {} + lspserver.completePending = false lspserver.workspaceFolders = [getcwd()] var job = job_start(cmd, opts) @@ -789,8 +790,8 @@ export def NewLspServer(path: string, args: list): dict nextID: 1, caps: {}, requests: {}, + completePending: false, diagsMap: {}, - completionTriggerChars: [], workspaceSymbolPopup: 0, workspaceSymbolQuery: '' } diff --git a/doc/lsp.txt b/doc/lsp.txt index 0dd85b6..2c0bb05 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -343,6 +343,14 @@ accepts a list of LSP servers with the above information. :LspWorkspaceListFolders Show the list of folders in the workspace. +============================================================================== +6. Insert mode completion + +The LSP plugin sets the 'omnifunc' option for the buffers which have a +registered LSP server. To complete a symbol in insert mode, you can press +CTRL-X CTRL-O to invoke completion using the items suggested by the LSP +server. + ============================================================================== vim:tw=78:ts=8:noet:ft=help:norl: -- 2.48.1