]> Sergey Matveev's repositories - vim-lsp.git/commitdiff
Add support for 24x7 completion and omni-completion
authorYegappan Lakshmanan <yegappan@yahoo.com>
Mon, 1 Feb 2021 01:12:43 +0000 (17:12 -0800)
committerYegappan Lakshmanan <yegappan@yahoo.com>
Mon, 1 Feb 2021 01:12:43 +0000 (17:12 -0800)
autoload/handlers.vim
autoload/lsp.vim
autoload/lspserver.vim
doc/lsp.txt
plugin/lsp.vim

index 944e51bde91fa2804d2074d0ed2662305c10bb53..d644c9985bf23fd9be1e634a74f8ccf4814d2122 100644 (file)
@@ -32,14 +32,9 @@ def s:processInitializeReply(lspserver: dict<any>, req: dict<any>, reply: dict<a
     endfor
   endif
 
-  # map characters that trigger insert mode completion
-  if caps->has_key('completionProvider')
+  if g:LSP_24x7_Complete && caps->has_key('completionProvider')
     var triggers = caps.completionProvider.triggerCharacters
-    for ch in triggers
-      exe 'inoremap <buffer> <silent> ' .. ch .. ' ' .. ch .. "<C-X><C-O>"
-    endfor
-    lspserver.completionTriggerChars =
-                               caps.completionProvider.triggerCharacters
+    lspserver.completionTriggerChars = triggers
   endif
 
 
@@ -106,7 +101,7 @@ def s:processSignaturehelpReply(lspserver: dict<any>, req: dict<any>, reply: dic
       startcol = text->stridx(label)
     endif
   endif
-  var popupID = text->popup_atcursor({})
+  var popupID = text->popup_atcursor({moved: 'any'})
   prop_type_add('signature', {bufnr: popupID->winbufnr(), highlight: 'LineNr'})
   if hllen > 0
     prop_add(1, startcol + 1, {bufnr: popupID->winbufnr(), length: hllen, type: 'signature'})
@@ -162,6 +157,7 @@ def s:processCompletionReply(lspserver: dict<any>, req: dict<any>, reply: dict<a
     items = reply.result.items
   endif
 
+  var completeItems: list<dict<any>> = []
   for item in items
     var d: dict<any> = {}
     if item->has_key('textEdit') && item.textEdit->has_key('newText')
@@ -188,10 +184,47 @@ def s:processCompletionReply(lspserver: dict<any>, req: dict<any>, reply: dict<a
        d.info = item.documentation.value
       endif
     endif
-    lspserver.completeItems->add(d)
+    completeItems->add(d)
   endfor
 
-  lspserver.completePending = false
+  if g:LSP_24x7_Complete
+    if completeItems->empty()
+      # no matches
+      return
+    endif
+
+    if completeItems->len() == 1
+       && matchstr(getline('.'), completeItems[0].word .. '\>') != ''
+      # only one complete match. No need to show the completion popup
+      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
+    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)
+  else
+    lspserver.completeItems = completeItems
+    lspserver.completePending = false
+  endif
 enddef
 
 # process the 'textDocument/hover' reply from the LSP server
index 0e04d61957ab3baf7481613f9ab8a7f336de31e0..4bd3d78716889f6b1427ddb5dfff5d8fcf56ed85 100644 (file)
@@ -268,16 +268,24 @@ def lsp#addFile(bnr: number): void
   endif
   lspserver.textdocDidOpen(bnr, ftype)
 
-  # Display hover information
-  autocmd CursorHold <buffer> call s:LspHover()
   # file saved notification handler
   autocmd BufWritePost <buffer> call s:lspSavedFile()
 
   # 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')
+
+  # set options for insert mode completion
+  if g:LSP_24x7_Complete
+    setbufvar(bnr, '&completeopt', 'menuone,popup,noinsert,noselect')
+    setbufvar(bnr, '&completepopup', 'border:off')
+    # autocmd for 24x7 insert mode completion
+    autocmd TextChangedI <buffer> call lsp#complete()
+    # <Enter> in insert mode stops completion and inserts a <Enter>
+    inoremap <expr> <buffer> <CR> pumvisible() ? "\<C-Y>\<CR>" : "\<CR>"
+  else
+    setbufvar(bnr, '&omnifunc', 'lsp#omniFunc')
+  endif
+
   setbufvar(bnr, '&balloonexpr', 'LspDiagExpr()')
   exe 'autocmd InsertLeave <buffer=' .. bnr .. '> call lsp#leftInsertMode()'
 
@@ -524,6 +532,39 @@ def lsp#jumpToDiag(which: string): void
   WarnMsg('Error: No more diagnostics found')
 enddef
 
+# Insert mode completion handler. Used when 24x7 completion is enabled
+# (default).
+def lsp#complete()
+  var cur_col: number = col('.')
+  var line: string = getline('.')
+
+  if cur_col == 0 || line->empty()
+    return
+  endif
+
+  var ftype: string = &filetype
+  var lspserver: dict<any> = s:lspGetServer(ftype)
+  if lspserver->empty() || !lspserver.running || lspserver.caps->empty()
+    return
+  endif
+
+  # If the character before the cursor is not a keyword character or is not
+  # one of the LSP completion trigger characters, then do nothing.
+  if line[cur_col - 2] !~ '\k'
+    if lspserver.completionTriggerChars->index(line[cur_col - 2]) == -1
+      return
+    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
+enddef
+
 # omni complete handler
 def lsp#omniFunc(findstart: number, base: string): any
   var ftype: string = &filetype
@@ -572,17 +613,14 @@ enddef
 
 # Display the hover message from the LSP server for the current cursor
 # location
-def LspHover()
+def lsp#hover()
   var ftype = &filetype
   if ftype == ''
     return
   endif
 
   var lspserver: dict<any> = s:lspGetServer(ftype)
-  if lspserver->empty()
-    return
-  endif
-  if !lspserver.running
+  if lspserver->empty() || !lspserver.running
     return
   endif
 
index 922c0b58ce3e5bf00d227070ea7a730b9dcdc98d..1c089d8e9b9003954daefd1bcfe04e8b0844d4d8 100644 (file)
@@ -58,6 +58,7 @@ def s:startServer(lspserver: dict<any>): number
   lspserver.nextID = 1
   lspserver.requests = {}
   lspserver.completePending = false
+  lspserver.completionTriggerChars = []
   lspserver.workspaceFolders = [getcwd()]
 
   var job = job_start(cmd, opts)
@@ -791,6 +792,7 @@ export def NewLspServer(path: string, args: list<string>): dict<any>
     caps: {},
     requests: {},
     completePending: false,
+    completionTriggerChars: [],
     diagsMap: {},
     workspaceSymbolPopup: 0,
     workspaceSymbolQuery: ''
index 2c0bb057084a475d9eece9ddb7ccc7b5f5150091..3aee08e78b7f61b57659a5a793c27be362bf85e3 100644 (file)
@@ -2,7 +2,7 @@
 
 Author: Yegappan Lakshmanan  (yegappan AT yahoo DOT com)
 For Vim version 8.2.2342 and above
-Last change: Jan 20, 2021
+Last change: Jan 31, 2021
 
 ==============================================================================
                                                *lsp-license*
@@ -173,14 +173,14 @@ accepts a list of LSP servers with the above information.
 ==============================================================================
 5. Commands                                            *lsp-commands*
 
-                                               |:LspShowServers|
+                                               *:LspShowServers*
 :LspShowServers                Displays the list of registered LSP servers and their
                        status. The LSP servers are registered using the
                        lsp#addServer() function. The output shows the Vim
                        file type, the corresponding LSP server status and the
                        path to the LSP server executable.
 
-                                               |:LspGotoDefinition|
+                                               *:LspGotoDefinition*
 :LspGotoDefinition     Jumps to the definition of the symbol under the
                        cursor. If the file is already present in a window,
                        then jumps to that window. Otherwise, opens the file
@@ -189,68 +189,68 @@ accepts a list of LSP servers with the above information.
                        Also the |``| mark is set to the position before the
                        jump.
 
-                                               |:LspGotoDefinition|
+                                               *:LspGotoDefinition*
 :LspGotoDeclaration    Jumps to the declaration of the symbol under the
                        cursor. The behavior of this command is similar to the
                        |:LspGotoDefinition| command.
 
-                                               |:LspGotoTypeDef|
+                                               *:LspGotoTypeDef*
 :LspGotoTypeDef                Jumps to the type definition of the symbol under the
                        cursor. The behavior of this command is similar to the
                        |:LspGotoDefinition| command. Note that not all the LSP
                        servers support this feature.
 
-                                               |:LspGotoImpl|
+                                               *:LspGotoImpl*
 :LspGotoImpl           Jumps to the implementation of the symbol under the
                        cursor. The behavior of this command is similar to the
                        |:LspGotoDefinition| command. Note that not all the LSP
                        servers support this feature.
 
-                                               |:LspShowSignature|
+                                               *:LspShowSignature*
 :LspShowSignature      Displays the signature of the symbol (e.g. a function
                        or method) before the cursor in a popup. The popup is
                        also automatically displayed in insert mode after
                        entering a symbol name followed by a separator (e.g. a
                        opening parenthesis).
 
-                                               |:LspDiagShow|
+                                               *:LspDiagShow*
 :LspDiagShow           Creates a new location list with the diagnostics
                        messages (if any) from the LSP server for the current
                        file and opens the location list window. You can use
                        the Vim location list commands to browse the list.
 
-                                               |:LspDiagFirst|
+                                               *:LspDiagFirst*
 :LspDiagFirst          Jumps to the location of the first diagnostic message
                        for the current file.
 
-                                               |:LspDiagNext|
+                                               *:LspDiagNext*
 :LspDiagNext           Jumps to the location of the diagnostic message after
                        the current cursor position.
 
-                                               |:LspDiagPrev|
+                                               *:LspDiagPrev*
 :LspDiagPrev           Jumps to the location of the diagnostic message before
                        the current cursor position.
 
-                                               |:LspDiagCurrent|
+                                               *:LspDiagCurrent*
 :LspDiagCurrent                Displays the diagnostic message (if any) for the
                        current line.
 
-                                               |:LspShowReferences|
+                                               *:LspShowReferences*
 :LspShowReferences     Creates a new location list with the list of locations
                        where the symbol under the cursor is referenced and
                        opens the location window.
 
-                                               |:LspHighlight|
+                                               *:LspHighlight*
 :LspHighlight          Highlights all the matches for the symbol under
                        cursor. The text, read and write references to the
                        symbol are highlighted using Search, DiffChange and
                        DiffDelete highlight groups respectively.
 
-                                               |:LspHighlightClear|
+                                               *:LspHighlightClear*
 :LspHighlightClear     Clears all the symbol matches highlighted by the
                        |:LspHighlight| command.
 
-                                               |:LspOutline|
+                                               *:LspOutline*
 :LspOutline            Opens a vertically split window with the list of
                        symbols defined in the current file. The current
                        symbol is highlighted. The symbols are grouped by
@@ -262,27 +262,27 @@ accepts a list of LSP servers with the above information.
                        the symbols in the new file.  Folds are created in the
                        outline window for the various group of symbols.
 
-                                               |:LspFormat|
+                                               *:LspFormat*
 :LspFormat             Format the current file using the LSP server.
 
 :{range}LspFormat      Format the specified range of lines in the current
                        file using the LSP server.
 
-                                               |:LspCalledBy|
+                                               *:LspCalledBy*
 :LspCalledBy           Display the list of symbols called by the current
                        symbol. (NOT IMPLEMENTED YET).
 
-                                               |:LspCalling|
+                                               *:LspCalling*
 :LspCalling            Display the list of symbols calling the current symbol
                        (NOT IMPLEMENTED YET).
 
-                                               |:LspRename|
+                                               *:LspRename*
 :LspRename             Rename the current symbol. You will be prompted to
                        enter the new name for the symbol. You can press <Esc>
                        or enter an empty string in the prompt to cancel the
                        operation.
 
-                                               |:LspCodeAction|
+                                               *:LspCodeAction*
 :LspCodeAction         Apply the code action supplied by the LSP server to
                        the diagnostic in the current line. This works only if
                        there is a diagnostic message for the current line.
@@ -291,7 +291,7 @@ accepts a list of LSP servers with the above information.
                        prompted to select one of the actions supplied by the
                        LSP server.
 
-                                               |:LspSymbolSearch|
+                                               *:LspSymbolSearch*
 :LspSymbolSearch <sym> Perform a workspace wide search for the symbol <sym>.
                        A popup window is opened with the list of matching
                        symbols.  You can enter a few characters to narrow
@@ -325,31 +325,45 @@ accepts a list of LSP servers with the above information.
                        You can enter a new search pattern to do a workspace
                        wide symbol search.
 
-                                               |:LspSelectionRange|
+                                               *:LspHover*
+:LspHover              Show the documentation for the symbol under the cursor
+                       in a popup window.
+
+                                               *:LspSelectionRange*
 :LspSelectionRange     Visually select the current symbol range.
 
-                                               |:LspFold|
+                                               *:LspFold*
 :LspFold               Fold the current file.
 
-                                               |:LspWorkspaceAddFolder|
+                                               *:LspWorkspaceAddFolder*
 :LspWorkspaceAddFolder {folder}
                        Add a folder to the workspace
 
-                                               |:LspWorkspaceRemoveFolder|
+                                               *:LspWorkspaceRemoveFolder*
 :LspWorkspaceRemoveFolder {folder}
                        Remove a folder from the workspace
 
-                                               |:LspWorkspaceListFolders|
+                                               *:LspWorkspaceListFolders*
 :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.
+By default, in insert mode, the LSP plugin automatically displays the matches
+for the symbol under the cursor in an insert-completion popup menu. You can
+use the keys described in |popupmenu-keys| with this menu.
+
+To disable the auto-compeltion, you can set the LSP_24x7_Complete variable
+to v:false in your .vimrc file: >
+
+       let g:LSP_24x7_Complete=v:false
+<
+If this variable is set, then the LSP plugin doesn't automatically start
+completion in insert mode and instead supports omni-completion (|compl-omni|).
+It sets the 'omnifunc' option for the buffers which have a registered LSP
+server. To complete a symbol in insert mode manually, you can press CTRL-X
+CTRL-O to invoke completion using the items suggested by the LSP server.
 
 ==============================================================================
 
index d1af460bb740de2922630f70a8f83f65fd3e407b..dbfd632e606c02236f2aa2ce7d62827d2406b6b1 100644 (file)
@@ -5,6 +5,12 @@ if v:version < 802 || !has('patch-8.2.2342')
   finish
 endif
 
+" Perform completion in insert mode automatically. Otherwise use
+" omni-complete.
+if !exists('g:LSP_24x7_Complete')
+  let g:LSP_24x7_Complete = v:true
+endif
+
 augroup LSPAutoCmds
   au!
   autocmd BufNewFile,BufReadPost *
@@ -40,8 +46,11 @@ command! -nargs=0 -bar LspCalling call lsp#outgoingCalls()
 command! -nargs=0 -bar LspRename call lsp#rename()
 command! -nargs=0 -bar LspCodeAction call lsp#codeAction()
 command! -nargs=? -bar LspSymbolSearch call lsp#symbolSearch(<q-args>)
+command! -nargs=0 -bar LspHover call lsp#hover()
 command! -nargs=0 -bar LspSelectionRange call lsp#selectionRange()
 command! -nargs=0 -bar LspFold call lsp#foldDocument()
 command! -nargs=0 -bar LspWorkspaceListFolders call lsp#listWorkspaceFolders()
 command! -nargs=1 -bar -complete=dir LspWorkspaceAddFolder call lsp#addWorkspaceFolder(<q-args>)
 command! -nargs=1 -bar -complete=dir LspWorkspaceRemoveFolder call lsp#removeWorkspaceFolder(<q-args>)
+
+" vim: shiftwidth=2 softtabstop=2