Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
neovim vs-code like autocompletion for lsp buffer files/path and vsnip
" ===========================================================================
"
" GIST: snippet / buffer / lsp / snippet vs-code like autocompletion using
" vim-vsnip and neovim lsp plugin. synchronous completion. sorting
" is done by length and source priority. c-n/c-p cycles items, while
" tab select/expands/jump-next placeholder. what's missing is showing
" a popup preview
"
" date: 2020-12-06 22:34
"
" ===========================================================================
set noshowmode
set updatetime=300
set shortmess+=c
set completeopt=menu,menuone,noselect
set pumwidth=10
set pumheight=8
set completefunc=CustomComplete
au! CursorHoldI * if getline('.')[col('.')-2] =~ '\S'
\ && !pumvisible() | silent call feedkeys("\<c-x>\<c-u>") | endif
inoremap <expr> <tab>
\ pumvisible() ?
\ complete_info(['selected']).selected != -1 ?
\ "\<c-y>"
\ :
\ "\<c-n>\<c-y>"
\ :
\ "\<tab>"
imap <expr> <tab>
\ pumvisible() ?
\ complete_info()["selected"] != "-1" ?
\ "\<c-y>"
\ :
\ "\<c-n>\<c-y>" :
\ vsnip#jumpable(1) ?
\ "\<Plug>(vsnip-jump-next)" :
\ "\<tab>"
imap <expr> <S-Tab> vsnip#jumpable(-1) ? '<Plug>(vsnip-jump-prev)' : '<S-Tab>'
smap <expr> <Tab> vsnip#jumpable(1) ? '<Plug>(vsnip-jump-next)' : '<Tab>'
smap <expr> <S-Tab> vsnip#jumpable(-1) ? '<Plug>(vsnip-jump-prev)' : '<S-Tab>'
nmap <expr> <Tab> vsnip#jumpable(1) ? 'i<Plug>(vsnip-jump-next)' : '<Tab>'
nmap <expr> <S-Tab> vsnip#jumpable(1) ? 'i<Plug>(vsnip-jump-prev)' : '<Tab>'
xmap s <Plug>(vsnip-cut-text)
" ====================== User completefunc
fun! CustomComplete(findstart, base) abort
if a:findstart
let keywordregex = '\k\|\(\.\?\/\?\)\+'
let regex = '\(' . keywordregex . '\)\+\%' . col(".") . 'c'
return match(getline("."), regex)
endif
echo a:base
let limit = 4
let buffers = s:sort(BufferSources(a:base))[0:limit]
let snippets = s:sort(SnippetSources(a:base))[0:limit]
let lsp = s:sort(LspSources(a:base))[0:limit]
let files = s:sort(FileSources(a:base))[0:2*limit]
let lists = [
\ { 'list': buffers, 'priority': 1 },
\ { 'list': snippets, 'priority': 3 },
\ { 'list': files, 'priority': 2 },
\ { 'list': lsp, 'priority': 4 }
\ ]
return s:mix(lists)
endfun
fun! s:sort(list)
return sort(a:list, { a,b -> len(a.word) > len(b.word) })
endf
fun! s:mix(lists)
let res = []
for group in a:lists
for item in group.list
let item.priority = group.priority
let res += [item]
endfor
endfor
return sort(res, { a,b -> len(a.word) > len(b.word) ? 1 :
\ len(a.word) < len(b.word) ? 0 :
\ a.priority < b.priority })
endfun
" priorities -> [ 1, 5, 2, 3 ]
fun! s:best(priorities)
let best = 0
for i in a:priorities
let best = i > best ? i : best
endfor
endfun
" ================================== COMPLETION SOURCES
" 1. BUFFER
fun! BufferSources(word)
return
\ map(
\ uniq(
\ sort(
\ filter(
\ split(
\ join(
\ getline(1,'$'),
\ "\n"),
\ '\<\|\>'),
\ { _,s -> s =~ '^\(\k\+\)$'
\ && s !~ '[#_\-1-9]'
\ && len(s) > 1
\ && s =~ '^'.a:word.'.*'}))),
\ { _,s -> { 'word': s, 'kind': 'buffer' } })
endf
" 2. SNIPPETS
fun! SnippetSources(word)
try
return
\ filter(
\ vsnip#get_complete_items(bufnr()),
\ { _,s -> s.word =~ '^'.a:word.'.*' })
catch /.*/
return []
endtry
endf
" 3. FILES
func! FileSources(word)
let files = filter(getcompletion(a:word, "file"), 'match(v:val, "//") < 0')
return map(files, { _,file -> { "kind": "file", "word": file } })
endfunc
" 4. LSP
fun! LspSources(word)
try
return v:lua.omnifunc_sync(a:word)
catch /.*/
return []
endtry
endf
lua << EOF
function _G.omnifunc_sync(base)
local params = vim.lsp.util.make_position_params()
local result = vim.lsp.buf_request_sync(bufnr, 'textDocument/completion', params, 2000)
local items = {}
if result then
for _, item in ipairs(result) do
if not item.err then
local matches = vim.lsp.util.text_document_completion_list_to_complete_items(item.result, base)
vim.list_extend(items, matches)
end
end
end
return items
end
EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment