I broke up with neovim....vim is my best friend now

This commit is contained in:
LinlyBoi
2023-04-30 08:14:07 +03:00
parent 0d185449c5
commit 4a4a6b1e81
5245 changed files with 468325 additions and 25 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Prabir Shrestha
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,245 @@
asyncomplete.vim
================
Async autocompletion for Vim 8 and Neovim with |timers|.
This is inspired by [nvim-complete-manager](https://github.com/roxma/nvim-complete-manager) but written
in pure Vim Script.
### Installing
```viml
Plug 'prabirshrestha/asyncomplete.vim'
```
#### Tab completion
```vim
inoremap <expr> <Tab> pumvisible() ? "\<C-n>" : "\<Tab>"
inoremap <expr> <S-Tab> pumvisible() ? "\<C-p>" : "\<S-Tab>"
inoremap <expr> <cr> pumvisible() ? asyncomplete#close_popup() : "\<cr>"
```
If you prefer the enter key to always insert a new line (even if the popup menu is visible) then
you can amend the above mapping as follows:
```vim
inoremap <expr> <cr> pumvisible() ? asyncomplete#close_popup() . "\<cr>" : "\<cr>"
```
### Force refresh completion
```vim
imap <c-space> <Plug>(asyncomplete_force_refresh)
" For Vim 8 (<c-@> corresponds to <c-space>):
" imap <c-@> <Plug>(asyncomplete_force_refresh)
```
### Auto popup
By default asyncomplete will automatically show the autocomplete popup menu as you start typing.
If you would like to disable the default behavior set `g:asyncomplete_auto_popup` to 0.
```vim
let g:asyncomplete_auto_popup = 0
```
You can use the above `<Plug>(asyncomplete_force_refresh)` to show the popup
or you can tab to show the autocomplete.
```vim
let g:asyncomplete_auto_popup = 0
function! s:check_back_space() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~ '\s'
endfunction
inoremap <silent><expr> <TAB>
\ pumvisible() ? "\<C-n>" :
\ <SID>check_back_space() ? "\<TAB>" :
\ asyncomplete#force_refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"
```
#### Preview Window
To enable preview window:
```vim
" allow modifying the completeopt variable, or it will
" be overridden all the time
let g:asyncomplete_auto_completeopt = 0
set completeopt=menuone,noinsert,noselect,preview
```
To auto close preview window when completion is done.
```vim
autocmd! CompleteDone * if pumvisible() == 0 | pclose | endif
```
### Sources
asyncomplete.vim deliberately does not contain any sources. Please use one of the following sources or create your own.
#### Language Server Protocol (LSP)
[Language Server Protocol](https://github.com/Microsoft/language-server-protocol) via [vim-lsp](https://github.com/prabirshrestha/vim-lsp) and [asyncomplete-lsp.vim](https://github.com/prabirshrestha/asyncomplete-lsp.vim)
**Please note** that vim-lsp setup for neovim requires neovim v0.2.0 or higher, since it uses lambda setup.
```vim
Plug 'prabirshrestha/asyncomplete.vim'
Plug 'prabirshrestha/vim-lsp'
Plug 'prabirshrestha/asyncomplete-lsp.vim'
if executable('pyls')
" pip install python-language-server
au User lsp_setup call lsp#register_server({
\ 'name': 'pyls',
\ 'cmd': {server_info->['pyls']},
\ 'allowlist': ['python'],
\ })
endif
```
**Refer to [vim-lsp wiki](https://github.com/prabirshrestha/vim-lsp/wiki/Servers) for configuring other language servers.** Besides auto-complete language server support other features such as go to definition, find references, renaming symbols, document symbols, find workspace symbols, formatting and so on.
*in alphabetical order*
| Languages/FileType/Source | Links |
|-------------------------------|----------------------------------------------------------------------------------------------------|
| [Ale][ale] | [asyncomplete-ale.vim](https://github.com/andreypopp/asyncomplete-ale.vim) |
| Buffer | [asyncomplete-buffer.vim](https://github.com/prabirshrestha/asyncomplete-buffer.vim) |
| C/C++ | [asyncomplete-clang.vim](https://github.com/keremc/asyncomplete-clang.vim) |
| Clojure | [async-clj-omni](https://github.com/clojure-vim/async-clj-omni) |
| Common Lisp (vlime) | [vlime](https://github.com/vlime/vlime) |
| Dictionary (look) | [asyncomplete-look](https://github.com/htlsne/asyncomplete-look) |
| [Emmet][emmet-vim] | [asyncomplete-emmet.vim](https://github.com/prabirshrestha/asyncomplete-emmet.vim) |
| English | [asyncomplete-nextword.vim](https://github.com/high-moctane/asyncomplete-nextword.vim) |
| Emoji | [asyncomplete-emoji.vim](https://github.com/prabirshrestha/asyncomplete-emoji.vim) |
| Filenames / directories | [asyncomplete-file.vim](https://github.com/prabirshrestha/asyncomplete-file.vim) |
| [NeoInclude][neoinclude] | [asyncomplete-neoinclude.vim](https://github.com/kyouryuukunn/asyncomplete-neoinclude.vim) |
| Go | [asyncomplete-gocode.vim](https://github.com/prabirshrestha/asyncomplete-gocode.vim) |
| Git commit message | [asyncomplete-gitcommit](https://github.com/laixintao/asyncomplete-gitcommit) |
| JavaScript (Flow) | [asyncomplete-flow.vim](https://github.com/prabirshrestha/asyncomplete-flow.vim) |
| [Neosnippet][neosnippet] | [asyncomplete-neosnippet.vim](https://github.com/prabirshrestha/asyncomplete-neosnippet.vim) |
| Omni | [asyncomplete-omni.vim](https://github.com/yami-beta/asyncomplete-omni.vim) |
| PivotalTracker stories | [asyncomplete-pivotaltracker.vim](https://github.com/hauleth/asyncomplete-pivotaltracker.vim) |
| Rust (racer) | [asyncomplete-racer.vim](https://github.com/keremc/asyncomplete-racer.vim) |
| [TabNine][TabNine] powered by AI | [asyncomplete-tabnine.vim](https://github.com/kitagry/asyncomplete-tabnine.vim) |
| [tmux complete][tmuxcomplete] | [tmux-complete.vim][tmuxcomplete] |
| Typescript | [asyncomplete-tscompletejob.vim](https://github.com/prabirshrestha/asyncomplete-tscompletejob.vim) |
| [UltiSnips][ultisnips] | [asyncomplete-ultisnips.vim](https://github.com/prabirshrestha/asyncomplete-ultisnips.vim) |
| User (compl-function) | [asyncomplete-user.vim](https://github.com/jsit/asyncomplete-user.vim) |
| Vim Syntax | [asyncomplete-necosyntax.vim](https://github.com/prabirshrestha/asyncomplete-necosyntax.vim) |
| Vim tags | [asyncomplete-tags.vim](https://github.com/prabirshrestha/asyncomplete-tags.vim) |
| Vim | [asyncomplete-necovim.vim](https://github.com/prabirshrestha/asyncomplete-necovim.vim) |
[ale]: https://github.com/dense-analysis/ale
[emmet-vim]: https://github.com/mattn/emmet-vim
[neosnippet]: https://github.com/Shougo/neosnippet.vim
[neoinclude]: https://github.com/Shougo/neoinclude.vim
[TabNine]: https://www.tabnine.com/
[tmuxcomplete]: https://github.com/wellle/tmux-complete.vim
[ultisnips]: https://github.com/SirVer/ultisnips
*can't find what you are looking for? write one instead an send a PR to be included here or search github topics tagged with asyncomplete at https://github.com/topics/asyncomplete.*
#### Using existing vim plugin sources
Rather than writing your own completion source from scratch you could also suggests other plugin authors to provide a async completion api that works for asyncomplete.vim or any other async autocomplete libraries without taking a dependency on asyncomplete.vim. The plugin can provide a function that takes a callback which returns the list of candidates and the startcol from where it must show the popup. Candidates can be list of words or vim's `complete-items`.
```vim
function s:completor(opt, ctx)
call mylanguage#get_async_completions({candidates, startcol -> asyncomplete#complete(a:opt['name'], a:ctx, startcol, candidates) })
endfunction
au User asyncomplete_setup call asyncomplete#register_source({
\ 'name': 'mylanguage',
\ 'allowlist': ['*'],
\ 'completor': function('s:completor'),
\ })
```
### Example
```vim
function! s:js_completor(opt, ctx) abort
let l:col = a:ctx['col']
let l:typed = a:ctx['typed']
let l:kw = matchstr(l:typed, '\v\S+$')
let l:kwlen = len(l:kw)
let l:startcol = l:col - l:kwlen
let l:matches = [
\ "do", "if", "in", "for", "let", "new", "try", "var", "case", "else", "enum", "eval", "null", "this", "true",
\ "void", "with", "await", "break", "catch", "class", "const", "false", "super", "throw", "while", "yield",
\ "delete", "export", "import", "public", "return", "static", "switch", "typeof", "default", "extends",
\ "finally", "package", "private", "continue", "debugger", "function", "arguments", "interface", "protected",
\ "implements", "instanceof"
\ ]
call asyncomplete#complete(a:opt['name'], a:ctx, l:startcol, l:matches)
endfunction
au User asyncomplete_setup call asyncomplete#register_source({
\ 'name': 'javascript',
\ 'allowlist': ['javascript'],
\ 'completor': function('s:js_completor'),
\ })
```
The above sample shows synchronous completion. If you would like to make it async just call `asyncomplete#complete` whenever you have the results ready.
```vim
call timer_start(2000, {timer-> asyncomplete#complete(a:opt['name'], a:ctx, l:startcol, l:matches)})
```
If you are returning incomplete results and would like to trigger completion on the next keypress pass `1` as the fifth parameter to `asyncomplete#complete`
which signifies the result is incomplete.
```vim
call asyncomplete#complete(a:opt['name'], a:ctx, l:startcol, l:matches, 1)
```
As a source author you do not have to worry about synchronization issues in case the server returns the async completion after the user has typed more
characters. asyncomplete.vim uses partial caching as well as ignores if the context changes when calling `asyncomplete#complete`.
This is one of the core reason why the original context must be passed when calling `asyncomplete#complete`.
### Credits
All the credit goes to the following projects
* [https://github.com/roxma/nvim-complete-manager](https://github.com/roxma/nvim-complete-manager)
* [https://github.com/maralla/completor.vim](https://github.com/maralla/completor.vim)
## Contributors
### Code Contributors
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/prabirshrestha/asyncomplete.vim/graphs/contributors"><img src="https://opencollective.com/asyncomplete/contributors.svg?width=890&button=false" /></a>
### Financial Contributors
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/asyncomplete/contribute)]
#### Individuals
<a href="https://opencollective.com/asyncomplete"><img src="https://opencollective.com/asyncomplete/individuals.svg?width=890"></a>
#### Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/asyncomplete/contribute)]
<a href="https://opencollective.com/asyncomplete/organization/0/website"><img src="https://opencollective.com/asyncomplete/organization/0/avatar.svg"></a>
<a href="https://opencollective.com/asyncomplete/organization/1/website"><img src="https://opencollective.com/asyncomplete/organization/1/avatar.svg"></a>
<a href="https://opencollective.com/asyncomplete/organization/2/website"><img src="https://opencollective.com/asyncomplete/organization/2/avatar.svg"></a>
<a href="https://opencollective.com/asyncomplete/organization/3/website"><img src="https://opencollective.com/asyncomplete/organization/3/avatar.svg"></a>
<a href="https://opencollective.com/asyncomplete/organization/4/website"><img src="https://opencollective.com/asyncomplete/organization/4/avatar.svg"></a>
<a href="https://opencollective.com/asyncomplete/organization/5/website"><img src="https://opencollective.com/asyncomplete/organization/5/avatar.svg"></a>
<a href="https://opencollective.com/asyncomplete/organization/6/website"><img src="https://opencollective.com/asyncomplete/organization/6/avatar.svg"></a>
<a href="https://opencollective.com/asyncomplete/organization/7/website"><img src="https://opencollective.com/asyncomplete/organization/7/avatar.svg"></a>
<a href="https://opencollective.com/asyncomplete/organization/8/website"><img src="https://opencollective.com/asyncomplete/organization/8/avatar.svg"></a>
<a href="https://opencollective.com/asyncomplete/organization/9/website"><img src="https://opencollective.com/asyncomplete/organization/9/avatar.svg"></a>

View File

@@ -0,0 +1,540 @@
function! asyncomplete#log(...) abort
if !empty(g:asyncomplete_log_file)
call writefile([json_encode(a:000)], g:asyncomplete_log_file, 'a')
endif
endfunction
" do nothing, place it here only to avoid the message
augroup asyncomplete_silence_messages
au!
autocmd User asyncomplete_setup silent
augroup END
if !has('timers')
echohl ErrorMsg
echomsg 'Vim/Neovim compiled with timers required for asyncomplete.vim.'
echohl NONE
if has('nvim')
call asyncomplete#log('neovim compiled with timers required.')
else
call asyncomplete#log('vim compiled with timers required.')
endif
" Clear augroup so this message is only displayed once.
au! asyncomplete_enable *
finish
endif
let s:already_setup = 0
let s:sources = {}
let s:matches = {} " { server_name: { incomplete: 1, startcol: 0, items: [], refresh: 0, status: 'idle|pending|success|failure', ctx: ctx } }
let s:has_complete_info = exists('*complete_info')
let s:has_matchfuzzypos = exists('*matchfuzzypos')
function! s:setup_if_required() abort
if !s:already_setup
" register asyncomplete change manager
for l:change_manager in g:asyncomplete_change_manager
call asyncomplete#log('core', 'initializing asyncomplete change manager', l:change_manager)
if type(l:change_manager) == type('')
execute 'let s:on_change_manager = function("'. l:change_manager .'")()'
else
let s:on_change_manager = l:change_manager()
endif
if has_key(s:on_change_manager, 'error')
call asyncomplete#log('core', 'initializing asyncomplete change manager failed', s:on_change_manager['name'], s:on_change_manager['error'])
else
call s:on_change_manager.register(function('s:on_change'))
call asyncomplete#log('core', 'initializing asyncomplete change manager complete', s:on_change_manager['name'])
break
endif
endfor
augroup asyncomplete
autocmd!
autocmd InsertEnter * call s:on_insert_enter()
autocmd InsertLeave * call s:on_insert_leave()
augroup END
doautocmd <nomodeline> User asyncomplete_setup
let s:already_setup = 1
endif
endfunction
function! asyncomplete#enable_for_buffer() abort
call s:setup_if_required()
let b:asyncomplete_enable = 1
endfunction
function! asyncomplete#disable_for_buffer() abort
let b:asyncomplete_enable = 0
endfunction
function! asyncomplete#get_source_names() abort
return keys(s:sources)
endfunction
function! asyncomplete#get_source_info(source_name) abort
return s:sources[a:source_name]
endfunction
function! asyncomplete#register_source(info) abort
if has_key(s:sources, a:info['name'])
call asyncomplete#log('core', 'duplicate asyncomplete#register_source', a:info['name'])
return -1
else
let s:sources[a:info['name']] = a:info
if has_key(a:info, 'events') && has_key(a:info, 'on_event')
execute 'augroup asyncomplete_source_event_' . a:info['name']
for l:event in a:info['events']
let l:exec = 'if get(b:,"asyncomplete_enable",0) | call s:notify_event_to_source("' . a:info['name'] . '", "'.l:event.'",asyncomplete#context()) | endif'
if type(l:event) == type('')
execute 'au ' . l:event . ' * ' . l:exec
elseif type(l:event) == type([])
execute 'au ' . join(l:event,' ') .' ' . l:exec
endif
endfor
execute 'augroup end'
endif
if exists('b:asyncomplete_active_sources')
unlet b:asyncomplete_active_sources
call s:get_active_sources_for_buffer()
endif
if exists('b:asyncomplete_triggers')
unlet b:asyncomplete_triggers
call s:update_trigger_characters()
endif
return 1
endif
endfunction
function! asyncomplete#unregister_source(info_or_server_name) abort
if type(a:info_or_server_name) == type({})
let l:server_name = a:info_or_server_name['name']
else
let l:server_name = a:info_or_server_name
endif
if has_key(s:sources, l:server_name)
let l:server = s:sources[l:server_name]
if has_key(l:server, 'unregister')
call l:server.unregister()
endif
unlet s:sources[l:server_name]
return 1
else
return -1
endif
endfunction
function! asyncomplete#context() abort
let l:ret = {'bufnr':bufnr('%'), 'curpos':getcurpos(), 'changedtick':b:changedtick}
let l:ret['lnum'] = l:ret['curpos'][1]
let l:ret['col'] = l:ret['curpos'][2]
let l:ret['filetype'] = &filetype
let l:ret['filepath'] = expand('%:p')
let l:ret['typed'] = strpart(getline(l:ret['lnum']),0,l:ret['col']-1)
return l:ret
endfunction
function! s:on_insert_enter() abort
call s:get_active_sources_for_buffer() " call to cache
call s:update_trigger_characters()
endfunction
function! s:on_insert_leave() abort
let s:matches = {}
if exists('s:update_pum_timer')
call timer_stop(s:update_pum_timer)
unlet s:update_pum_timer
endif
endfunction
function! s:get_active_sources_for_buffer() abort
if exists('b:asyncomplete_active_sources')
" active sources were cached for buffer
return b:asyncomplete_active_sources
endif
call asyncomplete#log('core', 'computing active sources for buffer', bufnr('%'))
let b:asyncomplete_active_sources = []
for [l:name, l:info] in items(s:sources)
let l:blocked = 0
if has_key(l:info, 'blocklist')
let l:blocklistkey = 'blocklist'
else
let l:blocklistkey = 'blacklist'
endif
if has_key(l:info, l:blocklistkey)
for l:filetype in l:info[l:blocklistkey]
if l:filetype == &filetype || l:filetype is# '*'
let l:blocked = 1
break
endif
endfor
endif
if l:blocked
continue
endif
if has_key(l:info, 'allowlist')
let l:allowlistkey = 'allowlist'
else
let l:allowlistkey = 'whitelist'
endif
if has_key(l:info, l:allowlistkey)
for l:filetype in l:info[l:allowlistkey]
if l:filetype == &filetype || l:filetype is# '*'
let b:asyncomplete_active_sources += [l:name]
break
endif
endfor
endif
endfor
call asyncomplete#log('core', 'active source for buffer', bufnr('%'), b:asyncomplete_active_sources)
return b:asyncomplete_active_sources
endfunction
function! s:update_trigger_characters() abort
if exists('b:asyncomplete_triggers')
" triggers were cached for buffer
return b:asyncomplete_triggers
endif
let b:asyncomplete_triggers = {} " { char: { 'sourcea': 1, 'sourceb': 2 } }
for l:source_name in s:get_active_sources_for_buffer()
let l:source_info = s:sources[l:source_name]
if has_key(l:source_info, 'triggers') && has_key(l:source_info['triggers'], &filetype)
let l:triggers = l:source_info['triggers'][&filetype]
elseif has_key(l:source_info, 'triggers') && has_key(l:source_info['triggers'], '*')
let l:triggers = l:source_info['triggers']['*']
elseif has_key(g:asyncomplete_triggers, &filetype)
let l:triggers = g:asyncomplete_triggers[&filetype]
elseif has_key(g:asyncomplete_triggers, '*')
let l:triggers = g:asyncomplete_triggers['*']
else
let l:triggers = []
endif
for l:trigger in l:triggers
let l:last_char = l:trigger[len(l:trigger) -1]
if !has_key(b:asyncomplete_triggers, l:last_char)
let b:asyncomplete_triggers[l:last_char] = {}
endif
if !has_key(b:asyncomplete_triggers[l:last_char], l:source_name)
let b:asyncomplete_triggers[l:last_char][l:source_name] = []
endif
call add(b:asyncomplete_triggers[l:last_char][l:source_name], l:trigger)
endfor
endfor
call asyncomplete#log('core', 'trigger characters for buffer', bufnr('%'), b:asyncomplete_triggers)
endfunction
function! s:should_skip() abort
if mode() isnot# 'i' || !get(b:, 'asyncomplete_enable', 0)
return 1
else
return 0
endif
endfunction
function! asyncomplete#close_popup() abort
return pumvisible() ? "\<C-y>" : ''
endfunction
function! asyncomplete#cancel_popup() abort
return pumvisible() ? "\<C-e>" : ''
endfunction
function! s:get_min_chars(source_name) abort
if exists('b:asyncomplete_min_chars')
return b:asyncomplete_min_chars
elseif has_key(s:sources, a:source_name)
return get(s:sources[a:source_name], 'min_chars', g:asyncomplete_min_chars)
endif
return g:asyncomplete_min_chars
endfunction
function! s:on_change() abort
if s:should_skip() | return | endif
if !g:asyncomplete_auto_popup
return
endif
let l:ctx = asyncomplete#context()
let l:last_char = l:ctx['typed'][l:ctx['col'] - 2] " col is 1-indexed, but str 0-indexed
if exists('b:asyncomplete_triggers')
let l:triggered_sources = get(b:asyncomplete_triggers, l:last_char, {})
else
let l:triggered_sources = {}
endif
let l:refresh_pattern = get(b:, 'asyncomplete_refresh_pattern', '\(\k\+$\)')
let [l:_, l:startidx, l:endidx] = asyncomplete#utils#matchstrpos(l:ctx['typed'], l:refresh_pattern)
for l:source_name in get(b:, 'asyncomplete_active_sources', [])
" match sources based on the last character if it is a trigger character
" TODO: also check for multiple chars instead of just last chars for
" languages such as cpp which uses -> and ::
if has_key(l:triggered_sources, l:source_name)
let l:startcol = l:ctx['col']
elseif l:startidx > -1
let l:startcol = l:startidx + 1 " col is 1-indexed, but str 0-indexed
endif
" here we use the existence of `l:startcol` to determine whether to
" use this completion source. If `l:startcol` exists, we use the
" source. If it does not exist, it means that we cannot get a
" meaningful starting point for the current source, and this implies
" that we cannot use this source for completion. Therefore, we remove
" the matches from the source.
if exists('l:startcol') && l:endidx - l:startidx >= s:get_min_chars(l:source_name)
if !has_key(s:matches, l:source_name) || s:matches[l:source_name]['ctx']['lnum'] !=# l:ctx['lnum'] || s:matches[l:source_name]['startcol'] !=# l:startcol
let s:matches[l:source_name] = { 'startcol': l:startcol, 'status': 'idle', 'items': [], 'refresh': 0, 'ctx': l:ctx }
endif
else
if has_key(s:matches, l:source_name)
unlet s:matches[l:source_name]
endif
endif
endfor
call s:trigger(l:ctx)
call s:update_pum()
endfunction
function! s:trigger(ctx) abort
" send cancellation request if supported
for [l:source_name, l:matches] in items(s:matches)
call asyncomplete#log('core', 's:trigger', l:matches)
if l:matches['refresh'] || l:matches['status'] ==# 'idle' || l:matches['status'] ==# 'failure'
let l:matches['status'] = 'pending'
try
" TODO: check for min chars
call asyncomplete#log('core', 's:trigger.completor()', l:source_name, s:matches[l:source_name], a:ctx)
call s:sources[l:source_name].completor(s:sources[l:source_name], a:ctx)
catch
let l:matches['status'] = 'failure'
call asyncomplete#log('core', 's:trigger', 'error', v:exception)
continue
endtry
endif
endfor
endfunction
function! asyncomplete#complete(name, ctx, startcol, items, ...) abort
let l:refresh = a:0 > 0 ? a:1 : 0
let l:ctx = asyncomplete#context()
if !has_key(s:matches, a:name) || l:ctx['lnum'] != a:ctx['lnum'] " TODO: handle more context changes
call asyncomplete#log('core', 'asyncomplete#log', 'ignoring due to context chnages', a:name, a:ctx, a:startcol, l:refresh, a:items)
call s:update_pum()
return
endif
call asyncomplete#log('asyncomplete#complete', a:name, a:ctx, a:startcol, l:refresh, a:items)
let l:matches = s:matches[a:name]
let l:matches['items'] = s:normalize_items(a:items)
let l:matches['refresh'] = l:refresh
let l:matches['startcol'] = a:startcol
let l:matches['status'] = 'success'
call s:update_pum()
endfunction
function! s:normalize_items(items) abort
if len(a:items) > 0 && type(a:items[0]) ==# type('')
let l:items = []
for l:item in a:items
let l:items += [{'word': l:item }]
endfor
return l:items
else
return a:items
endif
endfunction
function! asyncomplete#force_refresh() abort
return asyncomplete#menu_selected() ? "\<c-y>\<c-r>=asyncomplete#_force_refresh()\<CR>" : "\<c-r>=asyncomplete#_force_refresh()\<CR>"
endfunction
function! asyncomplete#_force_refresh() abort
if s:should_skip() | return | endif
let l:ctx = asyncomplete#context()
let l:startcol = l:ctx['col']
let l:last_char = l:ctx['typed'][l:startcol - 2]
" loop left and find the start of the word or trigger chars and set it as the startcol for the source instead of refresh_pattern
let l:refresh_pattern = get(b:, 'asyncomplete_refresh_pattern', '\(\k\+$\)')
let [l:_, l:startidx, l:endidx] = asyncomplete#utils#matchstrpos(l:ctx['typed'], l:refresh_pattern)
" When no word here, startcol is current col
let l:startcol = l:startidx == -1 ? col('.') : l:startidx + 1
let s:matches = {}
for l:source_name in get(b:, 'asyncomplete_active_sources', [])
let s:matches[l:source_name] = { 'startcol': l:startcol, 'status': 'idle', 'items': [], 'refresh': 0, 'ctx': l:ctx }
endfor
call s:trigger(l:ctx)
call s:update_pum()
return ''
endfunction
function! s:update_pum() abort
if exists('s:update_pum_timer')
call timer_stop(s:update_pum_timer)
unlet s:update_pum_timer
endif
call asyncomplete#log('core', 's:update_pum')
let s:update_pum_timer = timer_start(g:asyncomplete_popup_delay, function('s:recompute_pum'))
endfunction
function! s:recompute_pum(...) abort
if s:should_skip() | return | endif
" TODO: add support for remote recomputation of complete items,
" Ex: heavy computation such as fuzzy search can happen in a python thread
call asyncomplete#log('core', 's:recompute_pum')
if asyncomplete#menu_selected()
call asyncomplete#log('core', 's:recomputed_pum', 'ignorning refresh pum due to menu selection')
return
endif
let l:ctx = asyncomplete#context()
let l:startcols = []
let l:matches_to_filter = {}
for [l:source_name, l:match] in items(s:matches)
" ignore sources that have been unregistered
if !has_key(s:sources, l:source_name) | continue | endif
let l:startcol = l:match['startcol']
let l:startcols += [l:startcol]
let l:curitems = l:match['items']
if l:startcol > l:ctx['col']
call asyncomplete#log('core', 's:recompute_pum', 'ignoring due to wrong start col', l:startcol, l:ctx['col'])
continue
else
let l:matches_to_filter[l:source_name] = l:match
endif
endfor
let l:startcol = min(l:startcols)
let l:base = l:ctx['typed'][l:startcol - 1:] " col is 1-indexed, but str 0-indexed
let l:filter_ctx = extend({
\ 'base': l:base,
\ 'startcol': l:startcol,
\ }, l:ctx)
let l:mode = s:has_complete_info ? complete_info(['mode'])['mode'] : 'unknown'
if l:mode ==# '' || l:mode ==# 'eval' || l:mode ==# 'unknown'
let l:Preprocessor = empty(g:asyncomplete_preprocessor) ? function('s:default_preprocessor') : g:asyncomplete_preprocessor[0]
call l:Preprocessor(l:filter_ctx, l:matches_to_filter)
endif
endfunction
let s:pair = {
\ '"': '"',
\ '''': '''',
\}
function! s:default_preprocessor(options, matches) abort
let l:items = []
let l:startcols = []
for [l:source_name, l:matches] in items(a:matches)
let l:startcol = l:matches['startcol']
let l:base = a:options['typed'][l:startcol - 1:]
if has_key(s:sources[l:source_name], 'filter')
let l:result = s:sources[l:source_name].filter(l:matches, l:startcol, l:base)
let l:items += l:result[0]
let l:startcols += l:result[1]
else
if empty(l:base)
for l:item in l:matches['items']
call add(l:items, s:strip_pair_characters(l:base, l:item))
let l:startcols += [l:startcol]
endfor
elseif s:has_matchfuzzypos && g:asyncomplete_matchfuzzy
for l:item in matchfuzzypos(l:matches['items'], l:base, {'key':'word'})[0]
call add(l:items, s:strip_pair_characters(l:base, l:item))
let l:startcols += [l:startcol]
endfor
else
for l:item in l:matches['items']
if stridx(l:item['word'], l:base) == 0
call add(l:items, s:strip_pair_characters(l:base, l:item))
let l:startcols += [l:startcol]
endif
endfor
endif
endif
endfor
let a:options['startcol'] = min(l:startcols)
call asyncomplete#preprocess_complete(a:options, l:items)
endfunction
function! s:strip_pair_characters(base, item) abort
" Strip pair characters. If pre-typed text is '"', candidates
" should have '"' suffix.
let l:item = a:item
if has_key(s:pair, a:base[0])
let [l:lhs, l:rhs, l:str] = [a:base[0], s:pair[a:base[0]], l:item['word']]
if len(l:str) > 1 && l:str[0] ==# l:lhs && l:str[-1:] ==# l:rhs
let l:item = extend({}, l:item)
let l:item['word'] = l:str[:-2]
endif
endif
return l:item
endfunction
function! asyncomplete#preprocess_complete(ctx, items) abort
" TODO: handle cases where this is called asynchronsouly. Currently not supported
if s:should_skip() | return | endif
call asyncomplete#log('core', 'asyncomplete#preprocess_complete')
if asyncomplete#menu_selected()
call asyncomplete#log('core', 'asyncomplete#preprocess_complete', 'ignorning pum update due to menu selection')
return
endif
if (g:asyncomplete_auto_completeopt == 1)
setl completeopt=menuone,noinsert,noselect
endif
let l:startcol = a:ctx['startcol']
call asyncomplete#log('core', 'asyncomplete#preprocess_complete calling complete()', l:startcol, a:items)
if l:startcol > 0 " Prevent E578: Not allowed to change text here
call complete(l:startcol, a:items)
endif
endfunction
function! asyncomplete#menu_selected() abort
" when the popup menu is visible, v:completed_item will be the
" current_selected item
" if v:completed_item is empty, no item is selected
return pumvisible() && !empty(v:completed_item)
endfunction
function! s:notify_event_to_source(name, event, ctx) abort
try
if has_key(s:sources, a:name)
call s:sources[a:name].on_event(s:sources[a:name], a:ctx, a:event)
endif
catch
call asyncomplete#log('core', 's:notify_event_to_source', 'error', v:exception)
return
endtry
endfunction

View File

@@ -0,0 +1,21 @@
" Find a nearest to a `path` parent directory `directoryname` by traversing the
" filesystem upwards
function! asyncomplete#utils#find_nearest_parent_directory(path, directoryname) abort
let l:relative_path = finddir(a:directoryname, a:path . ';')
if !empty(l:relative_path)
return fnamemodify(l:relative_path, ':p')
else
return ''
endif
endfunction
if exists('*matchstrpos')
function! asyncomplete#utils#matchstrpos(expr, pattern) abort
return matchstrpos(a:expr, a:pattern)
endfunction
else
function! asyncomplete#utils#matchstrpos(expr, pattern) abort
return [matchstr(a:expr, a:pattern), match(a:expr, a:pattern), matchend(a:expr, a:pattern)]
endfunction
endif

View File

@@ -0,0 +1,81 @@
let s:callbacks = []
function! asyncomplete#utils#_on_change#textchangedp#init() abort
if exists('##TextChangedP')
call s:setup_if_required()
return {
\ 'name': 'TextChangedP',
\ 'register': function('s:register'),
\ 'unregister': function('s:unregister'),
\ }
else
return { 'name': 'TextChangedP', 'error': 'Requires vim with TextChangedP support' }
endif
endfunction
function! s:setup_if_required() abort
augroup asyncomplete_utils_on_change_text_changed_p
autocmd!
autocmd InsertEnter * call s:on_insert_enter()
autocmd InsertLeave * call s:on_insert_leave()
autocmd TextChangedI * call s:on_text_changed_i()
autocmd TextChangedP * call s:on_text_changed_p()
augroup END
endfunction
function! s:register(cb) abort
call add(s:callbacks , a:cb)
endfunction
function! s:unregister(obj, cb) abort
" TODO: remove from s:callbacks
endfunction
function! s:on_insert_enter() abort
let l:context = asyncomplete#context()
let s:previous_context = {
\ 'lnum': l:context['lnum'],
\ 'col': l:context['col'],
\ 'typed': l:context['typed'],
\ }
endfunction
function! s:on_insert_leave() abort
unlet! s:previous_context
endfunction
function! s:on_text_changed_i() abort
call s:maybe_notify_on_change()
endfunction
function! s:on_text_changed_p() abort
call s:maybe_notify_on_change()
endfunction
function! s:maybe_notify_on_change() abort
if !exists('s:previous_context')
return
endif
" We notify on_change callbacks only when the cursor position
" has changed.
" Unfortunatelly we need this check because in insert mode it
" is possible to have TextChangedI triggered when the completion
" context is not changed at all: When we close the completion
" popup menu via <C-e> or <C-y>. If we still let on_change
" do the completion in this case we never close the menu.
" Vim doesn't allow programmatically changing buffer content
" in insert mode, so by comparing the cursor's position and the
" completion base we know whether the context has changed.
let l:context = asyncomplete#context()
let l:previous_context = s:previous_context
let s:previous_context = {
\ 'lnum': l:context['lnum'],
\ 'col': l:context['col'],
\ 'typed': l:context['typed'],
\ }
if l:previous_context !=# s:previous_context
for l:Cb in s:callbacks
call l:Cb()
endfor
endif
endfunction

View File

@@ -0,0 +1,83 @@
let s:callbacks = []
let s:change_timer = -1
let s:last_tick = []
function! asyncomplete#utils#_on_change#timer#init() abort
call s:setup_if_required()
return {
\ 'name': 'timer',
\ 'register': function('s:register'),
\ 'unregister': function('s:unregister'),
\ }
endfunction
function! s:setup_if_required() abort
augroup asyncomplete_utils_on_change_timer
autocmd!
autocmd InsertEnter * call s:on_insert_enter()
autocmd InsertLeave * call s:on_insert_leave()
autocmd TextChangedI * call s:on_text_changed_i()
augroup END
endfunction
function! s:register(cb) abort
call add(s:callbacks , a:cb)
endfunction
function! s:unregister(obj, cb) abort
" TODO: remove from s:callbacks
endfunction
function! s:on_insert_enter() abort
let s:previous_position = getcurpos()
call s:change_tick_start()
endfunction
function! s:on_insert_leave() abort
unlet s:previous_position
call s:change_tick_stop()
endfunction
function! s:on_text_changed_i() abort
call s:check_changes()
endfunction
function! s:change_tick_start() abort
if !exists('s:change_timer')
let s:last_tick = s:change_tick()
" changes every 30ms, which is 0.03s, it should be fast enough
let s:change_timer = timer_start(30, function('s:check_changes'), { 'repeat': -1 })
endif
endfunction
function! s:change_tick_stop() abort
if exists('s:change_timer')
call timer_stop(s:change_timer)
unlet s:change_timer
let s:last_tick = []
endif
endfunction
function! s:check_changes(...) abort
let l:tick = s:change_tick()
if l:tick != s:last_tick
let s:last_tick = l:tick
call s:maybe_notify_on_change()
endif
endfunction
function! s:maybe_notify_on_change() abort
" enter to new line or backspace to previous line shouldn't cause change trigger
let l:previous_position = s:previous_position
let s:previous_position = getcurpos()
if l:previous_position[1] ==# getcurpos()[1]
for l:Cb in s:callbacks
call l:Cb()
endfor
endif
endfunction
function! s:change_tick() abort
return [b:changedtick, getcurpos()]
endfunction

View File

@@ -0,0 +1,191 @@
*asyncomplete.vim.txt* Async autocompletion for Vim 8 and Neovim.
*asyncomplete*
===============================================================================
CONTENTS *asyncomplete-contents*
1. Introduction |asyncomplete-introduction|
2. Options |asyncomplete-options|
3. Functions |asyncomplete-functions|
4. Global vim configuration |asyncomplete-global-config|
5. Known Issues |asyncomplete-known-issues|
===============================================================================
1. Introduction *asyncomplete-introduction*
Async autocompletion for Vim 8 and Neovim with |timers|.
This is inspired by https://github.com/roxma/nvim-complete-manager but written
in pure Vim Script.
===============================================================================
2. Options *asyncomplete-options*
g:asyncomplete_enable_for_all *g:asyncomplete_enable_for_all*
Type |Number|
Default: 1
Enable asyncomplete for all buffers. Can be overriden with
`b:asyncomplete_enable` on a per-buffer basis. Setting this to 0 prevents
asyncomplete from loading upon entering a buffer.
b:asyncomplete_enable *b:asyncomplete_enable*
Type |Number|
Default: 1
Setting this variable to 0 disables asyncomplete for the current buffer
and overrides `g:asyncomplete_enable_for_all` .
g:asyncomplete_auto_popup *g:asyncomplete_auto_popup*
Type: |Number|
Default: `1`
Automatically show the autocomplete popup menu as you start typing.
g:asyncomplete_log_file *g:asyncomplete_log_file*
Type: |String|
Default: null
Path to log file.
g:asyncomplete_popup_delay *g:asyncomplete_popup_delay*
Type: |Number|
Default: 30
Milliseconds to wait before opening the popup menu
g:asyncomplete_auto_completeopt *g:asyncomplete_auto_completeopt*
Type: |Number|
Default: 1
Set default `completeopt` options. These are `menuone,noinsert,noselect`.
This effectively overwrites what ever the user has in their config file.
Set to 0 to disable.
g:asyncomplete_preprocessor *g:asyncomplete_preprocessor*
Type: |Array| for zero or one |Function|
Default: []
Set a function to allow custom filtering or sorting.
Below example implements removing duplicates.
function! s:my_asyncomplete_preprocessor(options, matches) abort
let l:visited = {}
let l:items = []
for [l:source_name, l:matches] in items(a:matches)
for l:item in l:matches['items']
if stridx(l:item['word'], a:options['base']) == 0
if !has_key(l:visited, l:item['word'])
call add(l:items, l:item)
let l:visited[l:item['word']] = 1
endif
endif
endfor
endfor
call asyncomplete#preprocess_complete(a:options, l:items)
endfunction
let g:asyncomplete_preprocessor = [function('s:my_asyncomplete_preprocessor')]
Note:
asyncomplete#preprocess_complete() must be called synchronously.
Plans to support async preprocessing will be supported in the future.
context and matches in arguments in preprecessor function should be treated
as immutable.
g:asyncomplete_min_chars *g:asyncomplete_min_chars*
Type: |Number|
Default: 0
Minimum consecutive characters to trigger auto-popup. Overridden by buffer
variable if set (`b:asyncomplete_min_chars`)
g:asyncomplete_matchfuzzy *g:asyncomplete_matchfuzzy*
Type: |Number|
Default: `exists('*matchfuzzypos')`
Use |matchfuzzypos| to support fuzzy matching of 'word' when completing
items. Requires vim with `matchfuzzypos()` function to exists.
Set to `0` to disable fuzzy matching.
===============================================================================
3. Functions *asyncomplete-functions*
asyncomplete#close_popup() *asyncomplete#close_popup()*
Insert selected candidate and close popup menu.
Following example prevents popup menu from re-opening after insertion.
>
inoremap <expr> <C-y> pumvisible() ? asyncomplete#close_popup() : "\<C-y>"
<
asyncomplete#cancel_popup() *asyncomplete#cancel_popup()*
Cancel completion and close popup menu.
Following example prevents popup menu from re-opening after cancellation.
>
inoremap <expr> <C-e> pumvisible() ? asyncomplete#cancel_popup() : "\<C-e>"
<
asyncomplete#get_source_info({source-name}) *asyncomplete#get_source_info()*
Get the source configuration info as dict.
Below example implements a priority sort function.
>
function! s:sort_by_priority_preprocessor(options, matches) abort
let l:items = []
for [l:source_name, l:matches] in items(a:matches)
for l:item in l:matches['items']
if stridx(l:item['word'], a:options['base']) == 0
let l:item['priority'] =
\ get(asyncomplete#get_source_info(l:source_name),'priority',0)
call add(l:items, l:item)
endif
endfor
endfor
let l:items = sort(l:items, {a, b -> b['priority'] - a['priority']})
call asyncomplete#preprocess_complete(a:options, l:items)
endfunction
let g:asyncomplete_preprocessor = [function('s:sort_by_priority_preprocessor')]
<
asyncomplete#get_source_names() *asyncomplete#get_source_names()*
Get the registered source names list.
===============================================================================
4. Global vim configuration *asyncomplete-global-config*
If you notice messages like 'Pattern not found' or 'Match 1 of <N>' printed in
red colour in vim command line and in `:messages` history and you are annoyed
with them, try setting `shortmess` vim option in your `.vimrc` like so:
>
set shortmess+=c
<
See `:help shortmess` for details and description.
===============================================================================
5. Known Issues *asyncomplete-known-issues*
Builtin complete such as omni func, file func flickers and closes.
You need vim with patch v8.1.1068.
https://github.com/vim/vim/commit/fd133323d4e1cc9c0e61c0ce357df4d36ea148e3
===============================================================================
vim:tw=78:ts=4:sts=4:sw=4:ft=help:norl:

View File

@@ -0,0 +1,21 @@
asyncomplete asyncomplete.txt /*asyncomplete*
asyncomplete#cancel_popup() asyncomplete.txt /*asyncomplete#cancel_popup()*
asyncomplete#close_popup() asyncomplete.txt /*asyncomplete#close_popup()*
asyncomplete#get_source_info() asyncomplete.txt /*asyncomplete#get_source_info()*
asyncomplete#get_source_names() asyncomplete.txt /*asyncomplete#get_source_names()*
asyncomplete-contents asyncomplete.txt /*asyncomplete-contents*
asyncomplete-functions asyncomplete.txt /*asyncomplete-functions*
asyncomplete-global-config asyncomplete.txt /*asyncomplete-global-config*
asyncomplete-introduction asyncomplete.txt /*asyncomplete-introduction*
asyncomplete-known-issues asyncomplete.txt /*asyncomplete-known-issues*
asyncomplete-options asyncomplete.txt /*asyncomplete-options*
asyncomplete.vim.txt asyncomplete.txt /*asyncomplete.vim.txt*
b:asyncomplete_enable asyncomplete.txt /*b:asyncomplete_enable*
g:asyncomplete_auto_completeopt asyncomplete.txt /*g:asyncomplete_auto_completeopt*
g:asyncomplete_auto_popup asyncomplete.txt /*g:asyncomplete_auto_popup*
g:asyncomplete_enable_for_all asyncomplete.txt /*g:asyncomplete_enable_for_all*
g:asyncomplete_log_file asyncomplete.txt /*g:asyncomplete_log_file*
g:asyncomplete_matchfuzzy asyncomplete.txt /*g:asyncomplete_matchfuzzy*
g:asyncomplete_min_chars asyncomplete.txt /*g:asyncomplete_min_chars*
g:asyncomplete_popup_delay asyncomplete.txt /*g:asyncomplete_popup_delay*
g:asyncomplete_preprocessor asyncomplete.txt /*g:asyncomplete_preprocessor*

View File

@@ -0,0 +1 @@
ref: refs/heads/master

View File

@@ -0,0 +1,11 @@
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = https://github.com/prabirshrestha/asyncomplete.vim.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master

View File

@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.

View File

@@ -0,0 +1,15 @@
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit. The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".
. git-sh-setup
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
:

View File

@@ -0,0 +1,24 @@
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message. The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit. The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".
# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
# This example catches duplicate Signed-off-by lines.
test "" = "$(grep '^Signed-off-by: ' "$1" |
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
echo >&2 Duplicate Signed-off-by lines.
exit 1
}

View File

@@ -0,0 +1,174 @@
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open2;
# An example hook script to integrate Watchman
# (https://facebook.github.io/watchman/) with git to speed up detecting
# new and modified files.
#
# The hook is passed a version (currently 2) and last update token
# formatted as a string and outputs to stdout a new update token and
# all files that have been modified since the update token. Paths must
# be relative to the root of the working tree and separated by a single NUL.
#
# To enable this hook, rename this file to "query-watchman" and set
# 'git config core.fsmonitor .git/hooks/query-watchman'
#
my ($version, $last_update_token) = @ARGV;
# Uncomment for debugging
# print STDERR "$0 $version $last_update_token\n";
# Check the hook interface version
if ($version ne 2) {
die "Unsupported query-fsmonitor hook version '$version'.\n" .
"Falling back to scanning...\n";
}
my $git_work_tree = get_working_dir();
my $retry = 1;
my $json_pkg;
eval {
require JSON::XS;
$json_pkg = "JSON::XS";
1;
} or do {
require JSON::PP;
$json_pkg = "JSON::PP";
};
launch_watchman();
sub launch_watchman {
my $o = watchman_query();
if (is_work_tree_watched($o)) {
output_result($o->{clock}, @{$o->{files}});
}
}
sub output_result {
my ($clockid, @files) = @_;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# binmode $fh, ":utf8";
# print $fh "$clockid\n@files\n";
# close $fh;
binmode STDOUT, ":utf8";
print $clockid;
print "\0";
local $, = "\0";
print @files;
}
sub watchman_clock {
my $response = qx/watchman clock "$git_work_tree"/;
die "Failed to get clock id on '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
return $json_pkg->new->utf8->decode($response);
}
sub watchman_query {
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
or die "open2() failed: $!\n" .
"Falling back to scanning...\n";
# In the query expression below we're asking for names of files that
# changed since $last_update_token but not from the .git folder.
#
# To accomplish this, we're using the "since" generator to use the
# recency index to select candidate nodes and "fields" to limit the
# output to file names only. Then we're using the "expression" term to
# further constrain the results.
my $last_update_line = "";
if (substr($last_update_token, 0, 1) eq "c") {
$last_update_token = "\"$last_update_token\"";
$last_update_line = qq[\n"since": $last_update_token,];
}
my $query = <<" END";
["query", "$git_work_tree", {$last_update_line
"fields": ["name"],
"expression": ["not", ["dirname", ".git"]]
}]
END
# Uncomment for debugging the watchman query
# open (my $fh, ">", ".git/watchman-query.json");
# print $fh $query;
# close $fh;
print CHLD_IN $query;
close CHLD_IN;
my $response = do {local $/; <CHLD_OUT>};
# Uncomment for debugging the watch response
# open ($fh, ">", ".git/watchman-response.json");
# print $fh $response;
# close $fh;
die "Watchman: command returned no output.\n" .
"Falling back to scanning...\n" if $response eq "";
die "Watchman: command returned invalid output: $response\n" .
"Falling back to scanning...\n" unless $response =~ /^\{/;
return $json_pkg->new->utf8->decode($response);
}
sub is_work_tree_watched {
my ($output) = @_;
my $error = $output->{error};
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
$retry--;
my $response = qx/watchman watch "$git_work_tree"/;
die "Failed to make watchman watch '$git_work_tree'.\n" .
"Falling back to scanning...\n" if $? != 0;
$output = $json_pkg->new->utf8->decode($response);
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
# Uncomment for debugging watchman output
# open (my $fh, ">", ".git/watchman-output.out");
# close $fh;
# Watchman will always return all files on the first query so
# return the fast "everything is dirty" flag to git and do the
# Watchman query just to get it over with now so we won't pay
# the cost in git to look up each individual file.
my $o = watchman_clock();
$error = $output->{error};
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
output_result($o->{clock}, ("/"));
$last_update_token = $o->{clock};
eval { launch_watchman() };
return 0;
}
die "Watchman: $error.\n" .
"Falling back to scanning...\n" if $error;
return 1;
}
sub get_working_dir {
my $working_dir;
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
$working_dir = Win32::GetCwd();
$working_dir =~ tr/\\/\//;
} else {
require Cwd;
$working_dir = Cwd::cwd();
}
return $working_dir;
}

View File

@@ -0,0 +1,8 @@
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".
exec git update-server-info

View File

@@ -0,0 +1,14 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".
. git-sh-setup
precommit="$(git rev-parse --git-path hooks/pre-commit)"
test -x "$precommit" && exec "$precommit" ${1+"$@"}
:

View File

@@ -0,0 +1,49 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=$(git hash-object -t tree /dev/null)
fi
# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --type=bool hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
test $(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
cat <<\EOF
Error: Attempt to add a non-ASCII file name.
This can cause problems if you want to work with people on other platforms.
To be portable it is advisable to rename the file.
If you know what you are doing you can disable this check using:
git config hooks.allownonascii true
EOF
exit 1
fi
# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

View File

@@ -0,0 +1,13 @@
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git merge" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message to
# stderr if it wants to stop the merge commit.
#
# To enable this hook, rename this file to "pre-merge-commit".
. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
exec "$GIT_DIR/hooks/pre-commit"
:

View File

@@ -0,0 +1,53 @@
#!/bin/sh
# An example hook script to verify what is about to be pushed. Called by "git
# push" after it has checked the remote status, but before anything has been
# pushed. If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
# <local ref> <local oid> <remote ref> <remote oid>
#
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).
remote="$1"
url="$2"
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
while read local_ref local_oid remote_ref remote_oid
do
if test "$local_oid" = "$zero"
then
# Handle delete
:
else
if test "$remote_oid" = "$zero"
then
# New branch, examine all commits
range="$local_oid"
else
# Update to existing branch, examine new commits
range="$remote_oid..$local_oid"
fi
# Check for WIP commit
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
if test -n "$commit"
then
echo >&2 "Found WIP commit in $local_ref, not pushing"
exit 1
fi
fi
done
exit 0

View File

@@ -0,0 +1,169 @@
#!/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.
publish=next
basebranch="$1"
if test "$#" = 2
then
topic="refs/heads/$2"
else
topic=`git symbolic-ref HEAD` ||
exit 0 ;# we do not interrupt rebasing detached HEAD
fi
case "$topic" in
refs/heads/??/*)
;;
*)
exit 0 ;# we do not interrupt others.
;;
esac
# Now we are dealing with a topic branch being rebased
# on top of master. Is it OK to rebase it?
# Does the topic really exist?
git show-ref -q "$topic" || {
echo >&2 "No such branch $topic"
exit 1
}
# Is topic fully merged to master?
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
echo >&2 "$topic is fully merged to master; better remove it."
exit 1 ;# we could allow it, but there is no point.
fi
# Is topic ever merged to next? If so you should not be rebasing it.
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git rev-list ^master ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
not_in_topic=`git rev-list "^$topic" master`
if test -z "$not_in_topic"
then
echo >&2 "$topic is already up to date with master"
exit 1 ;# we could allow it, but there is no point.
else
exit 0
fi
else
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
/usr/bin/perl -e '
my $topic = $ARGV[0];
my $msg = "* $topic has commits already merged to public branch:\n";
my (%not_in_next) = map {
/^([0-9a-f]+) /;
($1 => 1);
} split(/\n/, $ARGV[1]);
for my $elem (map {
/^([0-9a-f]+) (.*)$/;
[$1 => $2];
} split(/\n/, $ARGV[2])) {
if (!exists $not_in_next{$elem->[0]}) {
if ($msg) {
print STDERR $msg;
undef $msg;
}
print STDERR " $elem->[1]\n";
}
}
' "$topic" "$not_in_next" "$not_in_master"
exit 1
fi
<<\DOC_END
This sample hook safeguards topic branches that have been
published from being rewound.
The workflow assumed here is:
* Once a topic branch forks from "master", "master" is never
merged into it again (either directly or indirectly).
* Once a topic branch is fully cooked and merged into "master",
it is deleted. If you need to build on top of it to correct
earlier mistakes, a new topic branch is created by forking at
the tip of the "master". This is not strictly necessary, but
it makes it easier to keep your history simple.
* Whenever you need to test or publish your changes to topic
branches, merge them into "next" branch.
The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.
With this workflow, you would want to know:
(1) ... if a topic branch has ever been merged to "next". Young
topic branches can have stupid mistakes you would rather
clean up before publishing, and things that have not been
merged into other branches can be easily rebased without
affecting other people. But once it is published, you would
not want to rewind it.
(2) ... if a topic branch has been fully merged to "master".
Then you can delete it. More importantly, you should not
build on top of it -- other people may already want to
change things related to the topic as patches against your
"master", so if you need further changes, it is better to
fork the topic (perhaps with the same name) afresh from the
tip of "master".
Let's look at this example:
o---o---o---o---o---o---o---o---o---o "next"
/ / / /
/ a---a---b A / /
/ / / /
/ / c---c---c---c B /
/ / / \ /
/ / / b---b C \ /
/ / / / \ /
---o---o---o---o---o---o---o---o---o---o---o "master"
A, B and C are topic branches.
* A has one fix since it was merged up to "next".
* B has finished. It has been fully merged up to "master" and "next",
and is ready to be deleted.
* C has not merged to "next" at all.
We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.
To compute (1):
git rev-list ^master ^topic next
git rev-list ^master next
if these match, topic has not merged in next at all.
To compute (2):
git rev-list master..topic
if this is empty, it is fully merged to "master".
DOC_END

View File

@@ -0,0 +1,24 @@
#!/bin/sh
#
# An example hook script to make use of push options.
# The example simply echoes all push options that start with 'echoback='
# and rejects all pushes when the "reject" push option is used.
#
# To enable this hook, rename this file to "pre-receive".
if test -n "$GIT_PUSH_OPTION_COUNT"
then
i=0
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
do
eval "value=\$GIT_PUSH_OPTION_$i"
case "$value" in
echoback=*)
echo "echo from the pre-receive-hook: ${value#*=}" >&2
;;
reject)
exit 1
esac
i=$((i + 1))
done
fi

View File

@@ -0,0 +1,42 @@
#!/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by "git commit" with the name of the file that has the
# commit message, followed by the description of the commit
# message's source. The hook's purpose is to edit the commit
# message file. If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".
# This hook includes three examples. The first one removes the
# "# Please enter the commit message..." help message.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output. It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited. This is rarely a good idea.
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2
SHA1=$3
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
# case "$COMMIT_SOURCE,$SHA1" in
# ,|template,)
# /usr/bin/perl -i.bak -pe '
# print "\n" . `git diff --cached --name-status -r`
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
# *) ;;
# esac
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
# if test -z "$COMMIT_SOURCE"
# then
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
# fi

View File

@@ -0,0 +1,78 @@
#!/bin/sh
# An example hook script to update a checked-out tree on a git push.
#
# This hook is invoked by git-receive-pack(1) when it reacts to git
# push and updates reference(s) in its repository, and when the push
# tries to update the branch that is currently checked out and the
# receive.denyCurrentBranch configuration variable is set to
# updateInstead.
#
# By default, such a push is refused if the working tree and the index
# of the remote repository has any difference from the currently
# checked out commit; when both the working tree and the index match
# the current commit, they are updated to match the newly pushed tip
# of the branch. This hook is to be used to override the default
# behaviour; however the code below reimplements the default behaviour
# as a starting point for convenient modification.
#
# The hook receives the commit with which the tip of the current
# branch is going to be updated:
commit=$1
# It can exit with a non-zero status to refuse the push (when it does
# so, it must not modify the index or the working tree).
die () {
echo >&2 "$*"
exit 1
}
# Or it can make any necessary changes to the working tree and to the
# index to bring them to the desired state when the tip of the current
# branch is updated to the new commit, and exit with a zero status.
#
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
# in order to emulate git fetch that is run in the reverse direction
# with git push, as the two-tree form of git read-tree -u -m is
# essentially the same as git switch or git checkout that switches
# branches while keeping the local changes in the working tree that do
# not interfere with the difference between the branches.
# The below is a more-or-less exact translation to shell of the C code
# for the default behaviour for git's push-to-checkout hook defined in
# the push_to_deploy() function in builtin/receive-pack.c.
#
# Note that the hook will be executed from the repository directory,
# not from the working tree, so if you want to perform operations on
# the working tree, you will have to adapt your code accordingly, e.g.
# by adding "cd .." or using relative paths.
if ! git update-index -q --ignore-submodules --refresh
then
die "Up-to-date check failed"
fi
if ! git diff-files --quiet --ignore-submodules --
then
die "Working directory has unstaged changes"
fi
# This is a rough translation of:
#
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
if git cat-file -e HEAD 2>/dev/null
then
head=HEAD
else
head=$(git hash-object -t tree --stdin </dev/null)
fi
if ! git diff-index --quiet --cached --ignore-submodules $head --
then
die "Working directory has staged changes"
fi
if ! git read-tree -u -m "$commit"
then
die "Could not update working tree to new HEAD"
fi

View File

@@ -0,0 +1,128 @@
#!/bin/sh
#
# An example hook script to block unannotated tags from entering.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
# This boolean sets whether unannotated tags will be allowed into the
# repository. By default they won't be.
# hooks.allowdeletetag
# This boolean sets whether deleting tags will be allowed in the
# repository. By default they won't be.
# hooks.allowmodifytag
# This boolean sets whether a tag may be modified after creation. By default
# it won't be.
# hooks.allowdeletebranch
# This boolean sets whether deleting branches will be allowed in the
# repository. By default they won't be.
# hooks.denycreatebranch
# This boolean sets whether remotely creating branches will be denied
# in the repository. By default this is allowed.
#
# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"
# --- Safety check
if [ -z "$GIT_DIR" ]; then
echo "Don't run this script from the command line." >&2
echo " (if you want, you could supply GIT_DIR then run" >&2
echo " $0 <ref> <oldrev> <newrev>)" >&2
exit 1
fi
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
exit 1
fi
# --- Config
allowunannotated=$(git config --type=bool hooks.allowunannotated)
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
echo "*** Project description file hasn't been set" >&2
exit 1
;;
esac
# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
if [ "$newrev" = "$zero" ]; then
newrev_type=delete
else
newrev_type=$(git cat-file -t $newrev)
fi
case "$refname","$newrev_type" in
refs/tags/*,commit)
# un-annotated tag
short_refname=${refname##refs/tags/}
if [ "$allowunannotated" != "true" ]; then
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
exit 1
fi
;;
refs/tags/*,delete)
# delete tag
if [ "$allowdeletetag" != "true" ]; then
echo "*** Deleting a tag is not allowed in this repository" >&2
exit 1
fi
;;
refs/tags/*,tag)
# annotated tag
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
then
echo "*** Tag '$refname' already exists." >&2
echo "*** Modifying a tag is not allowed in this repository." >&2
exit 1
fi
;;
refs/heads/*,commit)
# branch
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
echo "*** Creating a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/heads/*,delete)
# delete branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a branch is not allowed in this repository" >&2
exit 1
fi
;;
refs/remotes/*,commit)
# tracking branch
;;
refs/remotes/*,delete)
# delete tracking branch
if [ "$allowdeletebranch" != "true" ]; then
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
exit 1
fi
;;
*)
# Anything else (is there anything else?)
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
exit 1
;;
esac
# --- Finished
exit 0

Binary file not shown.

View File

@@ -0,0 +1,6 @@
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

View File

@@ -0,0 +1,2 @@
0000000000000000000000000000000000000000 9c7651894c2c6d656c0dc71e87cfabbbb71b9c78 LinlyBoi <libkyy@e.email> 1676062730 +0200 clone: from https://github.com/prabirshrestha/asyncomplete.vim.git
9c7651894c2c6d656c0dc71e87cfabbbb71b9c78 9c7651894c2c6d656c0dc71e87cfabbbb71b9c78 LinlyBoi <libkyy@e.email> 1676062732 +0200 checkout: moving from master to master

View File

@@ -0,0 +1 @@
0000000000000000000000000000000000000000 9c7651894c2c6d656c0dc71e87cfabbbb71b9c78 LinlyBoi <libkyy@e.email> 1676062730 +0200 clone: from https://github.com/prabirshrestha/asyncomplete.vim.git

View File

@@ -0,0 +1 @@
0000000000000000000000000000000000000000 9c7651894c2c6d656c0dc71e87cfabbbb71b9c78 LinlyBoi <libkyy@e.email> 1676062730 +0200 clone: from https://github.com/prabirshrestha/asyncomplete.vim.git

View File

@@ -0,0 +1,10 @@
# pack-refs with: peeled fully-peeled sorted
db79feef88f5c13480e4e3f385dfbfcb427f7b34 refs/remotes/origin/lua
9c7651894c2c6d656c0dc71e87cfabbbb71b9c78 refs/remotes/origin/master
b4813341eb73f09164655b4e510928c394cf96cf refs/tags/v1.0
79b060e2e9e1c59bdfdc97b44bcbf38dfce9dff9 refs/tags/v1.1
f4e70a975349a73e83e28e43171129eb92546c2a refs/tags/v1.5
08437a0f7c741ce6e870a70df30cb0bee6135c81 refs/tags/v1.6
08437a0f7c741ce6e870a70df30cb0bee6135c81 refs/tags/v1.7
27c245f8b422db5414d973ae4af73b79f754e32f refs/tags/v2.0.0
bb8a9924b703b3663d3be07d326055e44d22179a refs/tags/v2.1.0

View File

@@ -0,0 +1 @@
9c7651894c2c6d656c0dc71e87cfabbbb71b9c78

View File

@@ -0,0 +1 @@
ref: refs/remotes/origin/master

View File

@@ -0,0 +1,8 @@
08437a0f7c741ce6e870a70df30cb0bee6135c81
27c245f8b422db5414d973ae4af73b79f754e32f
79b060e2e9e1c59bdfdc97b44bcbf38dfce9dff9
9c7651894c2c6d656c0dc71e87cfabbbb71b9c78
b4813341eb73f09164655b4e510928c394cf96cf
bb8a9924b703b3663d3be07d326055e44d22179a
db79feef88f5c13480e4e3f385dfbfcb427f7b34
f4e70a975349a73e83e28e43171129eb92546c2a

View File

@@ -0,0 +1 @@
* text=auto

View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: asyncomplete
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@@ -0,0 +1,44 @@
name: linux_neovim
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
name: [neovim-v04-x64,neovim-nightly-x64]
include:
- name: neovim-v04-x64
os: ubuntu-latest
neovim_version: v0.4.3
- name: neovim-nightly-x64
os: ubuntu-latest
neovim_version: nightly
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v1
- name: Download neovim
shell: bash
run: |
mkdir -p ~/nvim/bin
curl -L https://github.com/neovim/neovim/releases/download/${{matrix.neovim_version}}/nvim.appimage -o ~/nvim/bin/nvim
chmod u+x ~/nvim/bin/nvim
- name: Download test runner
shell: bash
run: git clone --depth 1 --branch v1.5.4 --single-branch https://github.com/thinca/vim-themis ~/themis
- name: Run tests
shell: bash
run: |
export PATH=~/nvim/bin:$PATH
export PATH=~/themis/bin:$PATH
export THEMIS_VIM=nvim
nvim --version
themis --reporter spec

View File

@@ -0,0 +1,46 @@
name: linux_vim
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
name: [vim-v82-x64, vim-v81-x64]
include:
- name: vim-v82-x64
os: ubuntu-latest
vim_version: 8.2.0813
glibc_version: 2.15
- name: vim-v81-x64
os: ubuntu-latest
vim_version: 8.1.2414
glibc_version: 2.15
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v1
- name: Download vim
shell: bash
run: |
mkdir -p ~/vim/bin
curl -L https://github.com/vim/vim-appimage/releases/download/v${{matrix.vim_version}}/GVim-v${{matrix.vim_version}}.glibc${{matrix.glibc_version}}-x86_64.AppImage -o ~/vim/bin/vim
chmod u+x ~/vim/bin/vim
- name: Download test runner
shell: bash
run: git clone --depth 1 --branch v1.5.4 --single-branch https://github.com/thinca/vim-themis ~/themis
- name: Run tests
shell: bash
run: |
export PATH=~/vim/bin:$PATH
export PATH=~/themis/bin:$PATH
export THEMIS_VIM=vim
vim --version
themis --reporter spec

View File

@@ -0,0 +1,44 @@
name: mac_neovim
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [macos-latest]
name: [neovim-v04-x64,neovim-nightly-x64]
include:
- name: neovim-v04-x64
os: macos-latest
neovim_version: v0.4.3
- name: neovim-nightly-x64
os: macos-latest
neovim_version: nightly
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v1
- name: Download neovim
shell: bash
run: curl -L https://github.com/neovim/neovim/releases/download/${{matrix.neovim_version}}/nvim-macos.tar.gz -o ~/nvim.tar.gz
- name: Extract neovim
shell: bash
run: tar xzf ~/nvim.tar.gz -C ~/
- name: Download test runner
shell: bash
run: git clone --depth 1 --branch v1.5.4 --single-branch https://github.com/thinca/vim-themis ~/themis
- name: Run tests
shell: bash
run: |
export PATH=~/nvim-osx64/bin:$PATH
export PATH=~/themis/bin:$PATH
export THEMIS_VIM=nvim
nvim --version
themis --reporter spec

View File

@@ -0,0 +1,22 @@
name: reviewdog
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
vimlint:
name: runner / vint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: vint
uses: reviewdog/action-vint@v1
with:
github_token: ${{ secrets.github_token }}
level: error
reporter: github-pr-review

View File

@@ -0,0 +1,46 @@
name: windows_neovim
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [windows-latest]
name: [neovim-v04-x64,neovim-nightly-x64]
include:
- name: neovim-v04-x64
os: windows-latest
neovim_version: v0.4.3
neovim_arch: win64
- name: neovim-nightly-x64
os: windows-latest
neovim_version: nightly
neovim_arch: win64
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v1
- name: Download neovim
shell: PowerShell
run: Invoke-WebRequest -Uri https://github.com/neovim/neovim/releases/download/${{matrix.neovim_version}}/nvim-${{matrix.neovim_arch}}.zip -OutFile neovim.zip
- name: Extract neovim
shell: PowerShell
run: Expand-Archive -Path neovim.zip -DestinationPath $env:USERPROFILE
- name: Download test runner
shell: PowerShell
run: git clone --depth 1 --branch v1.5.4 --single-branch https://github.com/thinca/vim-themis $env:USERPROFILE\themis
- name: Run tests
shell: cmd
run: |
SET PATH=%USERPROFILE%\Neovim\bin;%PATH%;
SET PATH=%USERPROFILE%\themis\bin;%PATH%;
SET THEMIS_VIM=nvim
nvim --version
themis --reporter spec

View File

@@ -0,0 +1,52 @@
name: windows_vim
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [windows-latest]
name: [vim-v82-x64, vim-v81-x64, vim-v80-x64]
include:
- name: vim-v82-x64
os: windows-latest
vim_version: 8.2.0813
vim_arch: x64
vim_ver_path: vim82
- name: vim-v81-x64
os: windows-latest
vim_version: 8.1.2414
vim_arch: x64
vim_ver_path: vim81
- name: vim-v80-x64
os: windows-latest
vim_version: 8.0.1567
vim_arch: x64
vim_ver_path: vim80
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v1
- name: Download vim
shell: PowerShell
run: Invoke-WebRequest -Uri https://github.com/vim/vim-win32-installer/releases/download/v${{matrix.vim_version}}/gvim_${{matrix.vim_version}}_${{matrix.vim_arch}}.zip -OutFile vim.zip
- name: Extract vim
shell: PowerShell
run: Expand-Archive -Path vim.zip -DestinationPath $env:USERPROFILE
- name: Download test runner
shell: PowerShell
run: git clone --depth 1 --branch v1.5.4 --single-branch https://github.com/thinca/vim-themis $env:USERPROFILE\themis
- name: Run tests
shell: cmd
run: |
SET PATH=%USERPROFILE%\vim\${{matrix.vim_ver_path}};%PATH%;
SET PATH=%USERPROFILE%\themis\bin;%PATH%;
vim --version
themis --reporter spec

View File

@@ -0,0 +1 @@
tags

View File

@@ -0,0 +1,10 @@
cmdargs:
severity: style_problem
policies:
ProhibitUnusedVariable:
enabled: false
ProhibitImplicitScopeVariable:
enabled: true
ProhibitNoAbortFunction:
enabled: true

View File

@@ -0,0 +1,25 @@
if exists('g:asyncomplete_loaded')
finish
endif
let g:asyncomplete_loaded = 1
if get(g:, 'asyncomplete_enable_for_all', 1)
augroup asyncomplete_enable
au!
au BufEnter * if exists('b:asyncomplete_enable') == 0 | call asyncomplete#enable_for_buffer() | endif
augroup END
endif
let g:asyncomplete_manager = get(g:, 'asyncomplete_manager', 'asyncomplete#managers#vim#init')
let g:asyncomplete_change_manager = get(g:, 'asyncomplete_change_manager', ['asyncomplete#utils#_on_change#textchangedp#init', 'asyncomplete#utils#_on_change#timer#init'])
let g:asyncomplete_triggers = get(g:, 'asyncomplete_triggers', {'*': ['.', '>', ':'] })
let g:asyncomplete_min_chars = get(g:, 'asyncomplete_min_chars', 0)
let g:asyncomplete_auto_completeopt = get(g:, 'asyncomplete_auto_completeopt', 1)
let g:asyncomplete_auto_popup = get(g:, 'asyncomplete_auto_popup', 1)
let g:asyncomplete_popup_delay = get(g:, 'asyncomplete_popup_delay', 30)
let g:asyncomplete_log_file = get(g:, 'asyncomplete_log_file', '')
let g:asyncomplete_preprocessor = get(g:, 'asyncomplete_preprocessor', [])
let g:asyncomplete_matchfuzzy = get(g:, 'asyncomplete_matchfuzzy', exists('*matchfuzzypos'))
inoremap <silent> <expr> <Plug>(asyncomplete_force_refresh) asyncomplete#force_refresh()

View File

@@ -0,0 +1,2 @@
Describe asyncomplete
End

View File

@@ -0,0 +1,3 @@
set encoding=utf-8
call themis#option('recursive', 1)
call themis#helper('command').with(themis#helper('assert'))