├── .gitignore ├── .vimrc ├── LICENSE ├── README.md ├── after └── plugin │ └── vsnip_integ.vim ├── autoload ├── vsnip_integ.vim └── vsnip_integ │ ├── detection.vim │ ├── integration.vim │ └── integration │ ├── asyncomplete.vim │ ├── easycomplete.vim │ ├── lcn.vim │ ├── lsc.vim │ ├── mucomplete.vim │ ├── vimlsp.vim │ └── yegappan_lsp.vim ├── doc └── vsnip_integ.txt └── plugin └── vsnip_integ.vim /.gitignore: -------------------------------------------------------------------------------- 1 | .mypy_cache 2 | __pycache__ 3 | /doc/tags 4 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hrsh7th/vim-vsnip-integ/90ae474e8b05ed41e36d6f58382a9fbfb4b672c4/.vimrc -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 hrsh7th 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-vsnip-integ 2 | 3 | This plugin provides some plugins integration. 4 | 5 | - Snippet completion 6 | - Snippet expansion 7 | 8 | 9 | # Requirements 10 | 11 | - [vim-vsnip](https://github.com/hrsh7th/vim-vsnip) 12 | - You should set [mapping](https://github.com/hrsh7th/vim-vsnip/blob/master/README.md#2-setting). 13 | 14 | 15 | # Integrations 16 | 17 | ### LSP 18 | 19 | #### [vim-lsp](https://github.com/prabirshrestha/vim-lsp) 20 | - Support snippet text expansion. 21 | 22 | #### [vim-lsc](https://github.com/natebosch/vim-lsc) 23 | - Support snippet text expansion. 24 | 25 | #### [yegappan/lsp](https://github.com/yegappan/lsp) 26 | - Support snippet text expansion. 27 | 28 | #### [LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim) 29 | - Support snippet text expansion. 30 | 31 | #### [nvim builtin-lsp omnifunc](https://github.com/neovim/neovim) 32 | - Support snippet text expansion. 33 | - Support textEdit/additionalTextEdits at CompleteDone. 34 | 35 | 36 | ### Completion 37 | 38 | #### [asyncomplete.vim](https://github.com/prabirshrestha/asyncomplete.vim) 39 | - Snippet completion. 40 | 41 | #### [vim-mucomplete](https://github.com/lifepillar/vim-mucomplete) 42 | - Snippet completion. 43 | 44 | #### [vim-easycompletion](https://github.com/jayli/vim-easycomplete) 45 | - Snippet completion. 46 | 47 | #### [ddc.vim](https://github.com/Shougo/ddc.vim) 48 | - This plugin doesn't support ddc.vim. 49 | - Users of ddc.vim should use [ddc-source-vsnip](https://github.com/uga-rosa/ddc-source-vsnip). 50 | -------------------------------------------------------------------------------- /after/plugin/vsnip_integ.vim: -------------------------------------------------------------------------------- 1 | call vsnip_integ#integration#attach() 2 | -------------------------------------------------------------------------------- /autoload/vsnip_integ.vim: -------------------------------------------------------------------------------- 1 | let s:TextEdit = vital#vsnip#import('VS.LSP.TextEdit') 2 | let s:Position = vital#vsnip#import('VS.LSP.Position') 3 | 4 | let s:stop_complete_done = v:false 5 | let s:stop_complete_done_after = v:false 6 | 7 | " 8 | " CompleteDone context. 9 | " 10 | " When completed LSP item, context will have `completion_item` key. 11 | " When completed snippet item, context will have `snippet` key. 12 | " 13 | let s:context = { 14 | \ 'done_line': '', 15 | \ 'done_pos': [], 16 | \ 'completed_item': v:null, 17 | \ 'sources': [], 18 | \ 19 | \ 'snippet': '', 20 | \ 21 | \ 'complete_position': {}, 22 | \ 'completion_item': v:null, 23 | \ } 24 | 25 | inoremap (vsnip_integ:on_complete_done_after) =on_complete_done_after() 26 | 27 | " 28 | " vsnip_integ#skip_complete_done_after 29 | " 30 | function! vsnip_integ#skip_complete_done_after() abort 31 | let s:stop_complete_done_after = v:true 32 | call timer_start(0, { -> execute('let s:stop_complete_done_after = v:false') }) 33 | endfunction 34 | 35 | " 36 | " vsnip_integ#do_complete_done 37 | " 38 | " @param context = { 39 | " completed_item: v:completed_item; 40 | " completion_item: LSP.CompletionItem; 41 | " complete_position?: LSP.Position; // that sent on `textDocument/completion` 42 | " apply_additional_text_edits: v:true | v:false; 43 | " } | { 44 | " completed_item: v:completed_item; 45 | " snippet: string; // that's format is LSP's snippet format 46 | " } 47 | " 48 | function! vsnip_integ#do_complete_done(context) abort 49 | if s:stop_complete_done | return | endif 50 | let s:stop_complete_done = v:true 51 | call timer_start(0, { -> execute('let s:stop_complete_done = v:false') }) 52 | 53 | let s:context = { 54 | \ 'done_line': getline('.'), 55 | \ 'done_pos': getcurpos(), 56 | \ 'completed_item': a:context.completed_item, 57 | \ 'sources': [], 58 | \ 59 | \ 'snippet': get(a:context, 'snippet', v:null), 60 | \ 61 | \ 'completion_item': get(a:context, 'completion_item', v:null), 62 | \ 'complete_position': get(a:context, 'complete_position', v:null), 63 | \ 'apply_additional_text_edits': get(a:context, 'apply_additional_text_edits', v:false), 64 | \ } 65 | call feedkeys("\(vsnip_integ:on_complete_done_after)") 66 | endfunction 67 | 68 | " 69 | " vsnip_integ#on_complete_done 70 | " 71 | function! vsnip_integ#on_complete_done(completed_item) abort 72 | let l:context = s:extract_user_data(a:completed_item) 73 | if !empty(l:context) 74 | if s:stop_complete_done | return | endif 75 | let s:stop_complete_done = v:true 76 | call timer_start(0, { -> execute('let s:stop_complete_done = v:false') }) 77 | 78 | let s:context = extend(l:context, { 79 | \ 'done_line': getline('.'), 80 | \ 'done_pos': getcurpos(), 81 | \ 'completed_item': a:completed_item, 82 | \ 'apply_additional_text_edits': v:true, 83 | \ }) 84 | call feedkeys("\(vsnip_integ:on_complete_done_after)") 85 | endif 86 | endfunction 87 | 88 | " 89 | " on_complete_done_after 90 | " 91 | function! s:on_complete_done_after() abort 92 | if s:stop_complete_done_after | return '' | endif 93 | 94 | " Fix lnum for external additionalTextEdits 95 | let s:context.done_pos[1] = getcurpos()[1] 96 | 97 | " Check or 98 | if strlen(getline('.')) < strlen(s:context.done_line) 99 | return '' 100 | endif 101 | 102 | " Remove completed text 103 | let l:expand_text = s:get_expand_text(s:context) 104 | if strlen(l:expand_text) > 0 105 | call s:remove_completed_text(s:context) 106 | endif 107 | 108 | " additionalTextEdits 109 | if get(s:context, 'apply_additional_text_edits', v:false) 110 | call s:apply_additional_text_edits(s:context) 111 | endif 112 | 113 | " Expand snippet. 114 | if strlen(l:expand_text) > 0 115 | call vsnip#anonymous(l:expand_text) 116 | endif 117 | 118 | return '' 119 | endfunction 120 | 121 | " 122 | " get_expand_text 123 | " 124 | function! s:get_expand_text(context) abort 125 | let l:done_line = a:context.done_line 126 | let l:done_pos = a:context.done_pos 127 | let l:completed_item = a:context.completed_item 128 | let l:snippet = get(a:context, 'snippet', v:null) 129 | let l:completion_item = get(a:context, 'completion_item', v:null) 130 | 131 | " Snippet body. 132 | if l:snippet isnot# v:null 133 | return type(l:snippet) == type([]) ? join(l:snippet, "\n") : l:snippet 134 | endif 135 | 136 | " LSP CompletionItem. 137 | if l:completion_item isnot# v:null 138 | let l:word = l:completed_item.word 139 | if has_key(l:completion_item, 'textEdit') && type(l:completion_item.textEdit) == type({}) 140 | let l:lsp_done_pos = s:Position.vim_to_lsp('%', [l:done_pos[1], l:done_pos[2] + l:done_pos[3]]) 141 | let l:text_edit = copy(l:completion_item.textEdit) 142 | let l:range = s:get_range(l:text_edit) 143 | let l:range.start.character = min([l:lsp_done_pos['character'] - strchars(l:word), l:range.start.character]) 144 | let l:range.end.character = max([l:lsp_done_pos['character'], l:range.end.character]) 145 | let l:text_edit_before = strcharpart(l:done_line, 0, l:range.start.character) 146 | let l:text_edit_after = strcharpart(l:done_line, l:range.end.character, strchars(l:done_line) - l:range.end.character) 147 | if l:done_line !=# l:text_edit_before . s:trim_unmeaning_tabstop(l:completion_item.textEdit.newText) . l:text_edit_after 148 | return l:completion_item.textEdit.newText 149 | endif 150 | elseif has_key(l:completion_item, 'insertText') && type(l:completion_item.insertText) == type('') 151 | if l:word !=# s:trim_unmeaning_tabstop(l:completion_item.insertText) 152 | return l:completion_item.insertText 153 | endif 154 | endif 155 | endif 156 | 157 | return '' 158 | endfunction 159 | 160 | function! s:get_range(text_edit) abort 161 | " TextEdit | InsertReplaceEdit 162 | return has_key(a:text_edit, 'range') 163 | \ ? a:text_edit.range 164 | \ : g:vsnip_integ_confirm_behavior ==# 'insert' 165 | \ ? a:text_edit.insert : a:text_edit.replace 166 | endfunction 167 | 168 | " 169 | " apply_additional_text_edits 170 | " 171 | function! s:apply_additional_text_edits(context) abort 172 | if type(get(a:context, 'completion_item', v:null)) != type({}) 173 | return 174 | endif 175 | if type(get(a:context.completion_item, 'additionalTextEdits', v:null)) != type([]) 176 | return 177 | endif 178 | if len(a:context.completion_item.additionalTextEdits) == 0 179 | return 180 | endif 181 | 182 | " Special ignore case (Some lsp clients will expand additionalTextEdits by itself). 183 | for l:id in ['lcn', 'vimlsp'] 184 | if index(s:context.sources, l:id) >= 0 && vsnip_integ#detection#exists(l:id) 185 | return 186 | endif 187 | endfor 188 | 189 | call s:TextEdit.apply(bufnr('%'), a:context.completion_item.additionalTextEdits) 190 | endfunction 191 | 192 | " 193 | " remove_completed_text 194 | " 195 | function! s:remove_completed_text(context) abort 196 | let l:done_line = a:context.done_line 197 | let l:done_pos = a:context.done_pos 198 | let l:completed_item = a:context.completed_item 199 | let l:completion_item = get(a:context, 'completion_item', v:null) 200 | let l:complete_position = get(a:context, 'complete_position', v:null) 201 | let l:lsp_done_pos = s:Position.vim_to_lsp('%', [l:done_pos[1], l:done_pos[2] + l:done_pos[3]]) 202 | 203 | " Remove trigger character. 204 | call setline('.', l:done_line) 205 | 206 | " Create range to remove. 207 | let l:range = { 208 | \ 'start': { 209 | \ 'line': l:lsp_done_pos['line'], 210 | \ 'character': l:lsp_done_pos['character'] - strchars(l:completed_item.word) 211 | \ }, 212 | \ 'end': l:lsp_done_pos 213 | \ } 214 | 215 | " Support `textEdit` range for LSP CompletionItem. 216 | if !empty(l:completion_item) && has_key(l:completion_item, 'textEdit') && type(l:completion_item.textEdit) == type({}) 217 | let l:lsp_range = s:get_range(l:completion_item.textEdit) 218 | let l:range.start.character = min([l:range.start.character, l:lsp_range.start.character]) 219 | let l:range.end.character = max([l:range.end.character, l:lsp_range.end.character]) 220 | endif 221 | 222 | " Remove range. 223 | call s:TextEdit.apply(bufnr('%'), [{ 224 | \ 'range': l:range, 225 | \ 'newText': '' 226 | \ }]) 227 | call cursor(s:Position.lsp_to_vim('%', l:range.start)) 228 | endfunction 229 | 230 | " 231 | " extract_user_data 232 | " 233 | function! s:extract_user_data(completed_item) abort 234 | try 235 | " Has no `user_data`. 236 | if !has_key(a:completed_item, 'user_data') 237 | return {} 238 | endif 239 | 240 | " Decode user_data. 241 | let l:user_data = a:completed_item.user_data 242 | if type(l:user_data) == type('') 243 | let l:user_data = json_decode(l:user_data) 244 | endif 245 | 246 | " Support dict only. 247 | if type(l:user_data) != type({}) 248 | return {} 249 | endif 250 | 251 | if vsnip_integ#detection#exists('yegappan_lsp') && has_key(l:user_data, 'label') 252 | return { 253 | \ 'sources': ['yegappan_lsp'], 254 | \ 'completion_item': l:user_data 255 | \ } 256 | endif 257 | 258 | " LanguageClient-neovim 259 | if s:has_key(l:user_data, 'lspitem') 260 | return { 261 | \ 'sources': ['lcn'], 262 | \ 'completion_item': l:user_data.lspitem 263 | \ } 264 | endif 265 | 266 | " neovim built-in 267 | if s:has_key(l:user_data, 'nvim') && s:has_key(l:user_data.nvim, 'lsp') && s:has_key(l:user_data.nvim.lsp, 'completion_item') 268 | return { 269 | \ 'sources': ['nvim'], 270 | \ 'completion_item': l:user_data.nvim.lsp.completion_item 271 | \ } 272 | endif 273 | 274 | " neovim built-in 275 | if s:has_key(l:user_data, 'lsp') && s:has_key(l:user_data.lsp, 'completion_item') 276 | return { 277 | \ 'sources': ['nvim'], 278 | \ 'completion_item': l:user_data.lsp.completion_item 279 | \ } 280 | endif 281 | 282 | " vim-lsc 283 | if s:has_key(l:user_data, 'snippet') && s:has_key(l:user_data, 'snippet_trigger') 284 | return { 285 | \ 'sources': ['lsc'], 286 | \ 'snippet': l:user_data.snippet 287 | \ } 288 | endif 289 | 290 | " vsnip 291 | if s:has_key(l:user_data, 'vsnip') 292 | return { 293 | \ 'sources': ['vsnip'], 294 | \ 'snippet': join(l:user_data.vsnip.snippet, "\n") 295 | \ } 296 | endif 297 | catch /.*/ 298 | if g:vsnip_integ_debug 299 | echomsg string([v:exception, v:throwpoint]) 300 | endif 301 | endtry 302 | 303 | return {} 304 | endfunction 305 | 306 | " 307 | " has_key 308 | " 309 | function! s:has_key(maybe_dict, key) abort 310 | if type(a:maybe_dict) != type({}) 311 | return v:false 312 | endif 313 | return has_key(a:maybe_dict, a:key) 314 | endfunction 315 | 316 | " 317 | " trim_unmeaning_tabstop 318 | " 319 | function! s:trim_unmeaning_tabstop(text) abort 320 | return substitute(a:text, '\%(\$0\|\${0}\)$', '', 'g') 321 | endfunction 322 | 323 | -------------------------------------------------------------------------------- /autoload/vsnip_integ/detection.vim: -------------------------------------------------------------------------------- 1 | let s:definition = { 2 | \ 'vimlsp': { -> exists('g:lsp_loaded') }, 3 | \ 'lsc': { -> exists('g:loaded_lsc') }, 4 | \ 'lcn': { -> exists('g:LanguageClient_serverCommands') }, 5 | \ 'asyncomplete': { -> exists('g:asyncomplete_loaded') }, 6 | \ 'mucomplete': { -> exists('g:loaded_mucomplete') }, 7 | \ 'easycomplete': { -> exists('g:easycomplete_default_plugin_init') }, 8 | \ 'yegappan_lsp': { -> s:runtimepath('autoload/lsp/lspserver.vim') }, 9 | \ } 10 | 11 | 12 | let s:cache = {} 13 | 14 | " 15 | " vsnip_integ#detection#definition 16 | " 17 | function! vsnip_integ#detection#definition() abort 18 | return copy(s:definition) 19 | endfunction 20 | 21 | " 22 | " vsnip_integ#detection#exists 23 | " 24 | function! vsnip_integ#detection#exists(id) abort 25 | if !has_key(s:cache, a:id) 26 | let s:cache[a:id] = s:definition[a:id]() 27 | endif 28 | return s:cache[a:id] 29 | endfunction 30 | 31 | " 32 | " runtimepath 33 | " 34 | function! s:runtimepath(path) abort 35 | return !empty(globpath(&runtimepath, a:path)) 36 | endfunction 37 | 38 | -------------------------------------------------------------------------------- /autoload/vsnip_integ/integration.vim: -------------------------------------------------------------------------------- 1 | let s:attached = v:false 2 | 3 | " 4 | " vsnip_integ#integration#attach 5 | " 6 | " TODO: improve initialization. 7 | " 8 | function! vsnip_integ#integration#attach() abort 9 | if s:attached 10 | return 11 | endif 12 | let s:attached = v:true 13 | 14 | for l:name in keys(vsnip_integ#detection#definition()) 15 | try 16 | if vsnip_integ#detection#exists(l:name) 17 | call vsnip_integ#integration#{l:name}#attach() 18 | endif 19 | catch /.*/ 20 | if g:vsnip_integ_debug 21 | echomsg string([v:exception, v:throwpoint]) 22 | endif 23 | endtry 24 | endfor 25 | endfunction 26 | 27 | -------------------------------------------------------------------------------- /autoload/vsnip_integ/integration/asyncomplete.vim: -------------------------------------------------------------------------------- 1 | function! vsnip_integ#integration#asyncomplete#attach() abort 2 | call asyncomplete#register_source( 3 | \ s:get_source_option({ 4 | \ 'name': 'vsnip', 5 | \ 'whitelist': ['*'], 6 | \ 'completor': function('s:completor'), 7 | \ }) 8 | \ ) 9 | endfunction 10 | 11 | " 12 | " get_source_option 13 | " 14 | function! s:get_source_option(opts) abort 15 | let l:defaults = { 16 | \ 'name': 'vsnip', 17 | \ 'completor': function('s:completor'), 18 | \ 'whitelist': ['*'] 19 | \ } 20 | return extend(l:defaults, a:opts) 21 | endfunction 22 | 23 | " 24 | " completor 25 | " 26 | function! s:completor(opts, ctx) abort 27 | let l:before_line = getline('.') 28 | let l:idx = min([strlen(l:before_line), col('.') - 2]) 29 | let l:idx = max([l:idx, 0]) 30 | let l:before_line = l:before_line[0 : l:idx] 31 | 32 | if len(matchstr(l:before_line, s:get_keyword_pattern() . '$')) < 1 33 | return 34 | endif 35 | 36 | 37 | call asyncomplete#complete( 38 | \ a:opts.name, 39 | \ a:ctx, 40 | \ a:ctx.col - strlen(matchstr(a:ctx.typed, '\k*$')), 41 | \ vsnip#get_complete_items(bufnr('%')) 42 | \ ) 43 | endfunction 44 | 45 | " 46 | " get_keyword_pattern 47 | " 48 | function! s:get_keyword_pattern() abort 49 | let l:keywords = split(&iskeyword, ',') 50 | let l:keywords = filter(l:keywords, { _, k -> match(k, '\d\+-\d\+') == -1 }) 51 | let l:keywords = filter(l:keywords, { _, k -> k !=# '@' }) 52 | let l:pattern = '\%(' . join(map(l:keywords, { _, v -> '\V' . escape(v, '\') . '\m' }), '\|') . '\|\w\)*' 53 | return l:pattern 54 | endfunction 55 | 56 | -------------------------------------------------------------------------------- /autoload/vsnip_integ/integration/easycomplete.vim: -------------------------------------------------------------------------------- 1 | function! vsnip_integ#integration#easycomplete#attach() abort 2 | call easycomplete#RegisterSource({ 3 | \ 'name': 'vsnip', 4 | \ 'whitelist': ['*'], 5 | \ 'completor': function('s:completor'), 6 | \ }) 7 | endfunction 8 | 9 | " 10 | " completor 11 | " 12 | function! s:completor(opt, ctx) abort 13 | if index(['.', '/', ':'], a:ctx['char']) >= 0 14 | call easycomplete#complete(a:opt['name'], a:ctx, a:ctx['startcol'], []) 15 | return v:true 16 | endif 17 | 18 | let l:typing = a:ctx['typing'] 19 | if strlen(l:typing) == 0 20 | call easycomplete#complete(a:opt['name'], a:ctx, a:ctx['startcol'], []) 21 | return v:true 22 | endif 23 | 24 | if len(matchstr(a:ctx['line'], s:get_keyword_pattern() . '$')) < 1 25 | call easycomplete#complete(a:opt['name'], a:ctx, a:ctx['startcol'], []) 26 | return v:true 27 | endif 28 | 29 | call easycomplete#util#AsyncRun( 30 | \ function('s:complete_handler'), 31 | \ [l:typing, a:opt['name'], a:ctx, a:ctx['startcol']], 32 | \ 1) 33 | return v:true 34 | endfunction 35 | 36 | let s:kindflag_vsnip = get(g:, 'easycomplete_kindflag_vsnip', 's') 37 | let s:menuflag_vsnip = get(g:, 'easycomplete_menuflag_vsnip', '[V]') 38 | 39 | function! s:complete_handler(typing, name, ctx, startcol) abort 40 | let suggestions = [] 41 | for snippet in vsnip#get_complete_items(a:ctx['bufnr']) 42 | let menu = substitute(snippet.menu, '^\[.*\] ', '', '') 43 | call add(suggestions, { 44 | \ 'word': snippet.word, 45 | \ 'abbr': snippet.abbr . '~', 46 | \ 'kind': s:kindflag_vsnip, 47 | \ 'menu': s:menuflag_vsnip . ' ' . menu, 48 | \ 'info': ['Snippet: ' . menu, '-----'] + json_decode(snippet.user_data).vsnip.snippet, 49 | \ }) 50 | endfor 51 | call easycomplete#complete(a:name, a:ctx, a:startcol, suggestions) 52 | endfunction 53 | 54 | " 55 | " get_keyword_pattern 56 | " 57 | function! s:get_keyword_pattern() abort 58 | let l:keywords = split(&iskeyword, ',') 59 | let l:keywords = filter(l:keywords, { _, k -> match(k, '\d\+-\d\+') == -1 }) 60 | let l:keywords = filter(l:keywords, { _, k -> k !=# '@' }) 61 | let l:pattern = '\%(' . join(map(l:keywords, { _, v -> '\V' . escape(v, '\') . '\m' }), '\|') . '\|\w\)*' 62 | return l:pattern 63 | endfunction 64 | -------------------------------------------------------------------------------- /autoload/vsnip_integ/integration/lcn.vim: -------------------------------------------------------------------------------- 1 | " 2 | " vsnip_integ#integration#lcn#attach 3 | " 4 | function! vsnip_integ#integration#lcn#attach() abort 5 | let g:LanguageClient_hasSnippetSupport = v:true 6 | endfunction 7 | 8 | -------------------------------------------------------------------------------- /autoload/vsnip_integ/integration/lsc.vim: -------------------------------------------------------------------------------- 1 | " 2 | " vsnip_integ#integration#lsc#attach 3 | " 4 | function! vsnip_integ#integration#lsc#attach() abort 5 | let g:lsc_enable_snippet_support = v:true 6 | endfunction 7 | 8 | -------------------------------------------------------------------------------- /autoload/vsnip_integ/integration/mucomplete.vim: -------------------------------------------------------------------------------- 1 | " 2 | " vsnip_integ#integration#mucomplete#attach 3 | " 4 | function! vsnip_integ#integration#mucomplete#attach() abort 5 | call mucomplete#add_user_mapping('vsnip', "\=vsnip_integ#integration#mucomplete#complete()\") 6 | endfunction 7 | 8 | " 9 | " vsnip_integ#integration#mucomplete#complete 10 | " 11 | function! vsnip_integ#integration#mucomplete#complete() abort 12 | let l:before_line = getline('.') 13 | let l:idx = min([strlen(l:before_line), col('.') - 2]) 14 | let l:idx = max([l:idx, 0]) 15 | let l:before_line = l:before_line[0 : l:idx] 16 | let l:keyword = matchstr(l:before_line, '\k\+$') 17 | 18 | if l:keyword == '' 19 | return '' 20 | endif 21 | 22 | let l:candidates = vsnip#get_complete_items(bufnr('%')) 23 | let l:match = map(l:candidates, { _, val -> (l:keyword == val["word"][0:strlen(l:keyword)-1]) ? val : ''}) 24 | 25 | if !empty(l:candidates) 26 | call complete(col('.') - strlen(l:keyword), l:match) 27 | endif 28 | 29 | return '' 30 | endfunction 31 | 32 | -------------------------------------------------------------------------------- /autoload/vsnip_integ/integration/vimlsp.vim: -------------------------------------------------------------------------------- 1 | " 2 | " vsnip_integ#integration#vimlsp#attach 3 | " 4 | function! vsnip_integ#integration#vimlsp#attach() abort 5 | let g:lsp_text_edit_enabled = v:true 6 | let g:lsp_get_supported_capabilities = [function('s:get_supported_capabilities')] 7 | let g:lsp_snippet_expand = [{ option -> vsnip#anonymous(option.snippet) }] 8 | endfunction 9 | 10 | " 11 | " get_supported_capabilities. 12 | " 13 | function! s:get_supported_capabilities(server_info) abort 14 | let l:capabilities = lsp#default_get_supported_capabilities(a:server_info) 15 | 16 | if !has_key(l:capabilities, 'textDocument') 17 | let l:capabilities.textDocument = {} 18 | endif 19 | 20 | if !has_key(l:capabilities.textDocument, 'completion') 21 | let l:capabilities.textDocument.completion = {} 22 | endif 23 | 24 | if !has_key(l:capabilities.textDocument.completion, 'completionItem') 25 | let l:capabilities.textDocument.completion.completionItem = {} 26 | endif 27 | 28 | let l:capabilities.textDocument.completion.completionItem.snippetSupport = v:true 29 | 30 | return l:capabilities 31 | endfunction 32 | 33 | -------------------------------------------------------------------------------- /autoload/vsnip_integ/integration/yegappan_lsp.vim: -------------------------------------------------------------------------------- 1 | " 2 | " vsnip_integ#integration#yegappan_lsp#attach 3 | " 4 | function! vsnip_integ#integration#yegappan_lsp#attach() abort 5 | call LspOptionsSet({ 'snippetSupport': v:true }) 6 | endfunction 7 | 8 | -------------------------------------------------------------------------------- /doc/vsnip_integ.txt: -------------------------------------------------------------------------------- 1 | *vim-vsnip-integ* *vsnip-integ* 2 | 3 | vim-vsnip integrations. 4 | 5 | 6 | ============================================================================== 7 | CONTENTS *vsnip-integ-contents* 8 | 9 | INSTALL |vsnip-integ-install| 10 | EXPAMPLE |vsnip-integ-example| 11 | VARIABLE |vsnip-integ-variable| 12 | 13 | 14 | ============================================================================== 15 | INSTALL *vsnip-integ-install* 16 | 17 | You can use your favorite plugin manager. 18 | 19 | > 20 | " dein.vim 21 | call dein#add('hrsh7th/vim-vsnip-integ') 22 | 23 | " vim-plug 24 | Plug 'hrsh7th/vim-vsnip-integ' 25 | 26 | " neobundle 27 | NeoBundle 'hrsh7th/vim-vsnip-integ' 28 | < 29 | 30 | ============================================================================== 31 | EXAMPLE *vsnip-integ-example* 32 | 33 | Using vnsip-integ with implemented completion engine by some plugin. 34 | 35 | 36 | ============================================================================== 37 | VARIABLE *vsnip-integ-variable* 38 | 39 | *g:vsnip_integ_confirm_behavior* 40 | g:vsnip_integ_confirm_behavior ("insert"|"replace") 41 | - "insert": Inserts the selected item and moves adjacent text to 42 | the right (default). 43 | - "replace": Replaces adjacent text with the selected item. 44 | 45 | *g:vsnip_integ_create_autocmd* 46 | g:vsnip_integ_create_autocmd (boolean) 47 | Creates autocmd to expand snippets in |CompleteDone| or |CompleteDonePre|. 48 | 49 | Default: v:true 50 | 51 | 52 | vim:tw=78:ts=8:ft=help:norl:noet:fen:noet: 53 | -------------------------------------------------------------------------------- /plugin/vsnip_integ.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_vsnip_integ') 2 | finish 3 | endif 4 | let g:loaded_vsnip_integ = v:true 5 | 6 | let g:vsnip_integ_debug = get(g:, 'vsnip_integ_debug', v:false) 7 | let g:vsnip_integ_confirm_behavior = get(g:, 'vsnip_integ_confirm_behavior', 'insert') 8 | let g:vsnip_integ_create_autocmd = get(g:, 'vsnip_integ_create_autocmd', v:true) 9 | 10 | augroup vsnip_integ 11 | autocmd! 12 | autocmd User vsnip#expand call vsnip_integ#skip_complete_done_after() 13 | " pun.vim do `User PumCompleteDone` 14 | if g:vsnip_integ_create_autocmd 15 | if has('#CompleteDonePre') 16 | autocmd CompleteDonePre * if complete_info(['mode']).mode !=? '' | call vsnip_integ#on_complete_done(v:completed_item) | endif 17 | else 18 | autocmd CompleteDone * call vsnip_integ#on_complete_done(v:completed_item) 19 | endif 20 | endif 21 | augroup END 22 | 23 | --------------------------------------------------------------------------------