Last active
June 28, 2019 09:12
-
-
Save rhizoome/62f0d3e04c2110dd2f4b0928e720e4a1 to your computer and use it in GitHub Desktop.
Completion-as-you-time with timer: not simple anymore, I had to workaround many vim/neovim bugs (works with neovim v0.4)
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
" Set the complete-options that are best for auto-completion as you type: | |
" * menuone: show the (pop-up-)menu even when there is only one entry | |
" * preview: show the documentation for the current completion if available | |
" * noinsert: only insert a completion if the user presses enter | |
" * also do not set noselect/longest, since we want vim to select the first entry, so | |
" enter is sufficient to insert the completion | |
set completeopt=menuone,preview,noinsert | |
" Enable dictionary completions | |
set complete+=k | |
" This is the workaround for the workaround for the workaround | |
set lazyredraw | |
" By default we do a keyword-completion. | |
let s:completion_keys = "\<C-n>" | |
" These variables pass the timer between functions. | |
let s:rtimer = -1 | |
let s:otimer = -1 | |
let s:ntimer = -1 | |
" If the pop-up-menu is not visible (!pumvisible()), and the cursor is at a | |
" keyword-character (regex \K), we feed the keys that activate the current completion. | |
" If the completion is an omni-completion (<C-x><C-o>), we start a timer that shows the | |
" keyword-completion if the omni-completion failed. If it is a keyword-completion, we | |
" check that the current word is at least two characters long, because the dictionary | |
" completion only works with two or more characters. | |
function! s:OpenCompletion(timer) | |
let s:otimer = -1 | |
if !pumvisible() | |
let l:col = col('.') | |
let l:line = getline('.') | |
if s:completion_keys == "\<C-x>\<C-o>" | |
if match(l:line[l:col - 2], '\K') == 0 | |
call feedkeys(s:completion_keys, 'n') | |
if s:ntimer == -1 | |
let s:ntimer = timer_start(0, function('s:NextCompletionFirst')) | |
endif | |
endif | |
else | |
let l:begin = l:line[l:col - 3 : l:col - 1] | |
if strchars(l:begin) < 2 | |
let l:begin = l:line[l:col - 4 : l:col - 1] | |
endif | |
if match(l:begin, '\K\k') == 0 | |
call feedkeys(s:completion_keys, 'n') | |
endif | |
endif | |
endif | |
endfunction | |
function! s:StartCompletion() | |
if !pumvisible() | |
if s:otimer == -1 | |
let s:otimer = timer_start(0, function('s:OpenCompletion')) | |
endif | |
endif | |
endfunction | |
" Call OpenCompletion() for every character we type. | |
autocmd InsertCharPre * call s:StartCompletion() | |
" The workaround for the workaround (this is all so racey) | |
function! s:FixSelection() | |
if pumvisible() | |
if !has_key(v:event['completed_item'], 'word') | |
call feedkeys("\<C-e>" . s:completion_keys, 'n') | |
endif | |
endif | |
endfunction | |
autocmd CompleteChanged * call s:FixSelection() | |
" If there is no language-based semantic-completion, we do the keyword-completion. | |
function! s:ChangeCompletionType() | |
if &omnifunc == "" | |
let s:completion_keys = "\<C-n>" | |
else | |
let s:completion_keys = "\<C-x>\<C-o>" | |
endif | |
endfunction | |
" Change the completion type as we change buffers. | |
autocmd BufEnter * call s:ChangeCompletionType() | |
" Stop the repeating the timer once the completion is done. | |
autocmd CompleteDone * call timer_stop(s:rtimer) | |
" I don't like ignorecase for completions, remove these lines if you prefer ignorecase. | |
autocmd InsertEnter * setlocal noignorecase | |
autocmd InsertLeave * setlocal ignorecase | |
" If two characters before the cursor are a keyword-characters, we show the | |
" keyword-completion. | |
function! s:NextCompletion() | |
if !pumvisible() | |
let l:curpos = col('.') | |
if match(getline('.')[l:curpos - 3:curpos - 1] . v:char, '\K\k') == 0 | |
call feedkeys("\<C-e>\<C-n>", 'n') | |
endif | |
endif | |
endfunction | |
" If the pop-up-menu is not visible, we have exhausted the semantic-completion, we stop | |
" the timer and check if should display the keyword-completion. | |
function! s:NextCompletionRepeat(timer) | |
if !pumvisible() | |
call timer_stop(a:timer) | |
call s:NextCompletion() | |
endif | |
endfunction | |
" The same as above but for the initial completion. After the initial completion, we | |
" check the pop-up-menu every 250ms. | |
function! s:NextCompletionFirst(timer) | |
let s:ntimer = -1 | |
if !pumvisible() | |
call s:NextCompletion() | |
else | |
call timer_stop(s:rtimer) | |
let s:rtimer = timer_start(250, function('s:NextCompletionRepeat'), {'repeat' : -1}) | |
endif | |
endfunction | |
" Not treating underscore as a keyword-character results in better | |
" dictionary-completions. | |
function! CompleteAsYouTypeSetUnderscoreIsKeyword() | |
redir => l:is_syntax_iskeyword_set | |
silent! syntax iskeyword | |
redir END | |
if l:is_syntax_iskeyword_set =~ 'syntax iskeyword not set' | |
exec 'syntax iskeyword ' . &iskeyword | |
endif | |
setlocal iskeyword-=_ | |
endfunction | |
function! s:ToggleUnderscoreIsKeyword() | |
if &iskeyword =~ "_" | |
call CompleteAsYouTypeSetUnderscoreIsKeyword() | |
echo "setlocal iskeyword-=_" | |
else | |
setlocal iskeyword+=_ | |
echo "setlocal iskeyword+=_" | |
endif | |
endfunction | |
" Bind toggling underscore_is_keyword to :Tu | |
command Tu call s:ToggleUnderscoreIsKeyword() |
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
" If you dislike case-insensitive-completion add this to your ftplugin/python.vim | |
PythonJedi import jedi; jedi.settings.case_insensitive_completion = False | |
" Use an augroup for the languages you want underscore not being a keyword during completion (ftplugin/python.vim) | |
augroup CompleteAsYouTypeGroup | |
autocmd! | |
autocmd InsertEnter * call CompleteAsYouTypeSetUnderscoreIsKeyword() | |
autocmd InsertLeave * setlocal iskeyword+=_ | |
augroup END |
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
" If you have the habit to paste into the terminal, instead of into vim use bracketed paste | |
Plugin 'ConradIrwin/vim-bracketed-paste' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment