]> Sergey Matveev's repositories - vim-lsp.git/commitdiff
Add support for hrsh7th/vim-vsnip snippets
authorGirish Palya <girishji@gmail.com>
Thu, 1 Jun 2023 09:04:43 +0000 (11:04 +0200)
committerGirish Palya <girishji@gmail.com>
Thu, 1 Jun 2023 09:04:43 +0000 (11:04 +0200)
Summary:

- Query vim-vsnip plugin for snippet completions and add the items
  to the completion list.
- Add a boolean flag to set vsnip completion option
- Update documentation
- Without this enhancement vsnip could only expand LSP provided
  snippets
- Inteface to vim-vsnip plugin is based on hrsh7th/cmp-vsnip

Following plugins need to be installed:

[required] hrsh7th/vim-vsnip
[required] hrsh7th/vim-vsnip-integ
[optional] rafamadriz/friendly-snippets

Options should be set as follows:

completionTextEdit: false,
snippetSupport: true,
vsnipSupport: true,
ultisnipsSupport: false,

Shortcoming:

Completion is not triggered for non-keyword characters like '#' (ex. #
before #if in C) even though vsnip is capable of such completion,
unless LSP server sets special characters as trigger characters. This
is not a major shortcoming since it will expand once a keyword
character is typed (say, #i in #if). To address this issue some code
reorganization is needed, and perhaps separation of completion
mechanism from the LSP client core.

User can define keymaps for Tab completion as follows:
(<Space> will expand the snippet)

def! g:LspCleverTab(): string
    return pumvisible() ? "\<c-n>" : vsnip#jumpable(1) ?
\ "\<Plug>(vsnip-jump-next)" : g:WhitespaceOnly() ?
\ "\<tab>" : "\<c-n>"
enddef
def! g:LspCleverSTab(): string
    return pumvisible() ? "\<c-p>" : vsnip#jumpable(-1) ?
\ "\<Plug>(vsnip-jump-prev)" : g:WhitespaceOnly() ?
\ "\<s-tab>" : "\<c-p>"
enddef
autocmd FileType java,c,cpp,python
            \| iunmap <silent> <tab>
            \| iunmap <silent> <s-tab>
            \| inoremap <expr> <tab> g:LspCleverTab()
            \| snoremap <expr> <tab> g:LspCleverTab()
            \| inoremap <expr> <S-Tab> g:LspCleverSTab()
            \| snoremap <expr> <S-Tab> g:LspCleverSTab()

M  autoload/lsp/completion.vim
M  autoload/lsp/options.vim
M  doc/lsp.txt

autoload/lsp/completion.vim
autoload/lsp/options.vim
doc/lsp.txt

index fffc3e69ddc8578b445236fcaabd8a2d54f356d6..3119db37212c70b8fdd5cc78f140f55f6fc5c24f 100644 (file)
@@ -137,6 +137,57 @@ def CompletionUltiSnips(prefix: string, items: list<dict<any>>)
   endfor
 enddef
 
+# Integration with the vim-vsnip plugin
+def CompletionVsnip(items: list<dict<any>>)
+  def Pattern(abbr: string): string
+    var chars = split(escape(abbr, '\/?'), '\zs')
+    var chars_pattern = '\%(\V' .. join(chars, '\m\|\V') .. '\m\)'
+    var separator = chars[0] =~ '\a' ? '\<' : ''
+    return separator .. '\V' .. chars[0] .. '\m' .. chars_pattern .. '*$'
+  enddef
+
+  if charcol('.') == 1
+    return
+  endif
+  var starttext = getline('.')->slice(0, charcol('.') - 1)
+  for item in vsnip#get_complete_items(bufnr('%'))
+    var match = starttext->matchstrpos(Pattern(item.abbr))
+    if match[0] != ''
+      var user_data = json_decode(item.user_data)
+      var documentation = []
+      for line in split(vsnip#to_string(user_data.vsnip.snippet), "\n")
+       documentation->add(line)
+      endfor
+      items->add({
+       label: item.abbr,
+       filterText: item.word,
+       insertTextFormat: 2,
+       textEdit: {
+         newText: join(user_data.vsnip.snippet, "\n"),
+         range: {
+           start: {
+             line: line('.'),
+             character: match[1],
+           },
+           ['end']: {
+             line: line('.'),
+             character: match[2],
+           },
+         },
+       },
+       data: {
+         entryNames: [item.word],
+       },
+       kind: 15,
+       documentation: {
+         kind: 'markdown',
+         value: documentation->join("\n"),
+       },
+      })
+    endif
+  endfor
+enddef
+
 # add completion from current buf
 def CompletionFromBuffer(items: list<dict<any>>)
     var words = {}
@@ -190,6 +241,8 @@ export def CompletionReply(lspserver: dict<any>, cItems: any)
 
   if opt.lspOptions.ultisnipsSupport
     CompletionUltiSnips(prefix, items)
+  elseif opt.lspOptions.vsnipSupport
+    CompletionVsnip(items)
   endif
 
   if opt.lspOptions.useBufferCompletion
@@ -604,10 +657,11 @@ export def BufferInit(lspserver: dict<any>, bnr: number, ftype: string)
   if opt.lspOptions.autoComplete
     if lspserver.completionLazyDoc
       setbufvar(bnr, '&completeopt', 'menuone,popuphidden,noinsert,noselect')
+      setbufvar(bnr, '&completepopup', 'width:80,highlight:Pmenu,align:item,border:off')
     else
       setbufvar(bnr, '&completeopt', 'menuone,popup,noinsert,noselect')
+      setbufvar(bnr, '&completepopup', 'border:off')
     endif
-    setbufvar(bnr, '&completepopup', 'width:80,highlight:Pmenu,align:item,border:off')
     # <Enter> in insert mode stops completion and inserts a <Enter>
     if !opt.lspOptions.noNewlineInCompletion
       :inoremap <expr> <buffer> <CR> pumvisible() ? "\<C-Y>\<CR>" : "\<CR>"
index 9631a5365381fd4f9d25dbbff1c9c640b9ef88ba..610631ffdafbb0bf8614fff2189240cc8a88f127 100644 (file)
@@ -65,6 +65,8 @@ export var lspOptions: dict<any> = {
   snippetSupport: false,
   # enable SirVer/ultisnips completion support
   ultisnipsSupport: false,
+  # enable hrsh7th/vim-vsnip completion support
+  vsnipSupport: false,
   # Use a floating menu to show the code action menu instead of asking for input
   usePopupInCodeAction: false,
   # ShowReferences in a quickfix list instead of a location list`
index 47ddad31edd5ba5eaec7b62ead67e928a9460164..5f13c9dfda6d5bd86da7d7e3befaa660b4104c51 100644 (file)
@@ -543,6 +543,11 @@ snippetSupport             |Boolean| option.  Enable snippet completion support.
 ultisnipsSupport       |Boolean| option.  Enable SirVer/ultisnips support.
                        Need a snippet completion plugin SirVer/ultisnips.
                        By default this is set to false.
+                                               *lsp-opt-vssnipSupport*
+vsnipSupport           |Boolean| option.  Enable hrsh7th/vim-vsnip support.
+                       Need snippet completion plugins hrsh7th/vim-vsnip
+                       and hrsh7th/vim-vsnip-integ. By default this is
+                       set to false.
                                                *lsp-opt-usePopupInCodeAction*
 usePopupInCodeAction    |Boolean| option.  When using the |:LspCodeAction|
                        command to display the code action for the current