From: Girish Palya Date: Thu, 1 Jun 2023 09:04:43 +0000 (+0200) Subject: Add support for hrsh7th/vim-vsnip snippets X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=f966fe88ec673dff2c51ed7274e91741bbc17f63;p=vim-lsp.git Add support for hrsh7th/vim-vsnip snippets 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: ( will expand the snippet) def! g:LspCleverTab(): string return pumvisible() ? "\" : vsnip#jumpable(1) ? \ "\(vsnip-jump-next)" : g:WhitespaceOnly() ? \ "\" : "\" enddef def! g:LspCleverSTab(): string return pumvisible() ? "\" : vsnip#jumpable(-1) ? \ "\(vsnip-jump-prev)" : g:WhitespaceOnly() ? \ "\" : "\" enddef autocmd FileType java,c,cpp,python \| iunmap \| iunmap \| inoremap g:LspCleverTab() \| snoremap g:LspCleverTab() \| inoremap g:LspCleverSTab() \| snoremap g:LspCleverSTab() M autoload/lsp/completion.vim M autoload/lsp/options.vim M doc/lsp.txt --- diff --git a/autoload/lsp/completion.vim b/autoload/lsp/completion.vim index fffc3e6..3119db3 100644 --- a/autoload/lsp/completion.vim +++ b/autoload/lsp/completion.vim @@ -137,6 +137,57 @@ def CompletionUltiSnips(prefix: string, items: list>) endfor enddef +# Integration with the vim-vsnip plugin +def CompletionVsnip(items: list>) + 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>) var words = {} @@ -190,6 +241,8 @@ export def CompletionReply(lspserver: dict, 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, 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') # in insert mode stops completion and inserts a if !opt.lspOptions.noNewlineInCompletion :inoremap pumvisible() ? "\\" : "\" diff --git a/autoload/lsp/options.vim b/autoload/lsp/options.vim index 9631a53..610631f 100644 --- a/autoload/lsp/options.vim +++ b/autoload/lsp/options.vim @@ -65,6 +65,8 @@ export var lspOptions: dict = { 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` diff --git a/doc/lsp.txt b/doc/lsp.txt index 47ddad3..5f13c9d 100644 --- a/doc/lsp.txt +++ b/doc/lsp.txt @@ -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