Created
December 6, 2020 23:39
-
-
Save brenopacheco/0c1cb9b58d478716a8345a7cf8689ca8 to your computer and use it in GitHub Desktop.
neovim vs-code like autocompletion for lsp buffer files/path and vsnip
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" =========================================================================== | |
" | |
" 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