From be56e330d8ac80321a3eb338d77f0ea6d2fdb52e Mon Sep 17 00:00:00 2001 From: Prabir Shrestha Date: Tue, 10 Jan 2017 23:26:27 -0800 Subject: [PATCH] initial commit * forked off from https://github.com/maralla/completor.vim d475b42c92a000ff9eeb6b4b311eb06f457e71a3 --- .gitattributes | 1 + README.md | 27 +++++++ autoload/asyncomplete.vim | 149 ++++++++++++++++++++++++++++++++++++++ plugin/asyncomplete.vim | 11 +++ 4 files changed, 188 insertions(+) create mode 100644 .gitattributes create mode 100644 README.md create mode 100644 autoload/asyncomplete.vim create mode 100644 plugin/asyncomplete.vim diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..176a458 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/README.md b/README.md new file mode 100644 index 0000000..63c0afd --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +asyncomplete.vim (exprimental) +============================== + +Provide async autocompletion for vim8 with `lambda` and `timers`. +This should work in Neovim once [lambda support](https://github.com/neovim/neovim/pull/5771) is merged in master. +This repository is fork of [https://github.com/maralla/completor.vim](https://github.com/maralla/completor.vim) in pure vim script with python dependency removed. + +**Do not depend on this repository. This is me trying out async completion in vim so I will be pushing random things that may break** + +### Installing + +```viml +Plug 'prabirshrestha/asyncomplete.vim' +``` + +### Example + +```viml +function! s:js_completor(args) + call timer_start(2000, {t->a:args.done([{'word': 'class'}, {'word': 'function'}, {'word': 'value'}])}) +endfunction + +call asyncomplete#register('javascript', ['.', ' '], function('s:js_completor')) +``` + +### Credits +All the credit goes to [https://github.com/maralla/completor.vim](https://github.com/maralla/completor.vim) diff --git a/autoload/asyncomplete.vim b/autoload/asyncomplete.vim new file mode 100644 index 0000000..9fa8814 --- /dev/null +++ b/autoload/asyncomplete.vim @@ -0,0 +1,149 @@ +let s:char_inserted = v:false +let s:completions = {'words': [], 'refresh': 'always'} +let s:status = {'pos': [], 'nr': -1, 'input': '', 'ft': ''} +let s:completors = {} + +function! s:completions.set(comps) abort + let self.words = a:comps +endfunction + +function! s:completions.clear() abort + let self.words = [] +endfunction + +function! s:completions.empty() abort + return empty(self.words) +endfunction + +function! s:get_start_column(findstart, findbase, triggers) + let l:line_string = getline('.') + let l:line = line('.') + let l:col = col('.') + let l:start = l:col - 1 + while l:start > 0 + let l:char = l:line_string[l:start - 1] + for l:trigger_char in a:triggers + if l:char == l:trigger_char + return l:start + endif + endfor + let l:start -= 1 + endwhile + return l:start +endfunction + +function! asyncomplete#completefunc(findstart, findbase) + if a:findstart + if s:completions.empty() + return -3 + endif + if has_key(s:completors, s:status.ft) && has_key(s:completors[s:status.ft], 'triggers') + return s:get_start_column(a:findstart, a:findbase, s:completors[s:status.ft].triggers) + else + return -3 + endif + endif + + let l:completions = copy(s:completions) + call s:completions.clear() + let l:results = [] + for l:item in l:completions.words + if l:item.word =~ '^' . a:findbase + call add(l:results, l:item) + endif + endfor + return l:results +endfunction + +function! s:consistent() abort + return s:status.nr == bufnr('') && s:status.pos == getcurpos() && s:status.ft == &ft +endfunction + +function! s:trigger(items) abort + if !s:consistent() + call s:completions.clear() + else + call s:completions.set(a:items) + endif + if s:completions.empty() | return | endif + setlocal completefunc=asyncomplete#completefunc + setlocal completeopt-=longest + setlocal completeopt+=menuone + setlocal completeopt-=menu + if &completeopt !~# 'noinsert\|noselect' + setlocal completeopt+=noselect + endif + call feedkeys("\\\", 'n') +endfunction + +function! s:reset() abort + call s:completions.clear() +endfunction + +function! s:complete() abort + call s:reset() + if !s:consistent() | return | endif + + if has_key(s:completors, s:status.ft) + call s:completors[s:status.ft].completor({'info': s:status, 'done': {items->s:trigger(items)}}) + endif +endfunction + +function! s:skip() abort + let l:buftype = &buftype + let l:skip = empty(&ft) || buftype == 'nofile' || buftype == 'quickfix' + return l:skip || !s:char_inserted +endfunction + +function! s:on_text_change() abort + if s:skip() | return | endif + let s:char_inserted = v:false + + if exists('s:timer') + let l:info = timer_info(s:timer) + if !empty(l:info) + call timer_stop(s:timer) + endif + endif + + let e = col('.') - 2 + let inputted = e >= 0 ? getline('.')[:e] : '' + + let s:status = {'input':inputted, 'pos': getcurpos(), 'nr': bufnr(''), 'ft': &ft} + let s:timer = timer_start(g:asyncomplete_completion_delay, {t->s:complete()}) +endfunction + +function! s:on_insert_char_pre() abort + let s:char_inserted = v:true +endfunction + +function! s:set_events() abort + augroup asyncomplete + autocmd! + autocmd TextChangedI * call s:on_text_change() + autocmd InsertCharPre * call s:on_insert_char_pre() + augroup END +endfunction + +" public apis {{{ + +function! asyncomplete#enable() abort + " remove this check when nvim supports lambda + if !has('nvim') + call s:set_events() + endif +endfunction + +function! asyncomplete#disable() abort + autocmd! asyncomplete +endfunction + +function! asyncomplete#register(filetype, triggers, completor) abort + let s:completors[a:filetype] = { 'triggers': a:triggers, 'completor': a:completor } +endfunction + +function! asyncomplete#unregister(filetype) abort + call remove(s:completors, a:filetype) +endfunction + +" }}} diff --git a/plugin/asyncomplete.vim b/plugin/asyncomplete.vim new file mode 100644 index 0000000..93dae9d --- /dev/null +++ b/plugin/asyncomplete.vim @@ -0,0 +1,11 @@ +if exists('g:asyncomplete_loaded') + finish +endif +let g:asyncomplete_loaded = 1 +let g:asyncomplete_completion_delay = get(g:, 'asyncomplete_completion_delay', 80) + +augroup asyncomplete + autocmd! + autocmd InsertEnter * call asyncomplete#enable() +augroup END +