diff --git a/coc-settings.json b/coc-settings.json
new file mode 100644
index 0000000..7bba792
--- /dev/null
+++ b/coc-settings.json
@@ -0,0 +1,10 @@
+{
+ "languageserver": {
+ "go": {
+ "command": "gopls",
+ "rootPatterns": ["go.mod"],
+ "trace.server": "verbose",
+ "filetypes": ["go"]
+ }
+ }
+}
diff --git a/pack/acp/start/coc.nvim/.gitignore b/pack/acp/start/coc.nvim/.gitignore
new file mode 100644
index 0000000..a151978
--- /dev/null
+++ b/pack/acp/start/coc.nvim/.gitignore
@@ -0,0 +1,12 @@
+lib
+*.map
+coverage
+__pycache__
+.pyc
+.log
+src
+publish.sh
+doc/tags
+doc/tags-cn
+node_modules
+src/__tests__/tags
diff --git a/pack/acp/start/coc.nvim/LICENSE.md b/pack/acp/start/coc.nvim/LICENSE.md
new file mode 100644
index 0000000..bee2bf1
--- /dev/null
+++ b/pack/acp/start/coc.nvim/LICENSE.md
@@ -0,0 +1,7 @@
+Copyright 2018-2018 by Qiming Zhao aaa
+
+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.
diff --git a/pack/acp/start/coc.nvim/Readme.md b/pack/acp/start/coc.nvim/Readme.md
new file mode 100644
index 0000000..3b53dd7
--- /dev/null
+++ b/pack/acp/start/coc.nvim/Readme.md
@@ -0,0 +1,283 @@
+
+
+
+
+
Make your Vim/Neovim as smart as VSCode.
+
+
+
+
+
+
+
+
+---
+
+
+
+_True snippet and additional text editing support_
+
+## Why?
+
+- 🚀 **Fast**: [instant increment completion](https://github.com/neoclide/coc.nvim/wiki/Completion-with-sources), increment buffer sync using buffer update events.
+- 💎 **Reliable**: typed language, tested with CI.
+- 🌟 **Featured**: [full LSP support](https://github.com/neoclide/coc.nvim/wiki/Language-servers#supported-features)
+- ❤️ **Flexible**: [configured like VSCode](https://github.com/neoclide/coc.nvim/wiki/Using-the-configuration-file), [extensions work like in VSCode](https://github.com/neoclide/coc.nvim/wiki/Using-coc-extensions)
+
+## Quick Start
+
+Install [nodejs](https://nodejs.org/en/download/) >= 10.12:
+
+```sh
+curl -sL install-node.now.sh/lts | bash
+```
+
+For [vim-plug](https://github.com/junegunn/vim-plug) users:
+
+```vim
+" Use release branch (recommend)
+Plug 'neoclide/coc.nvim', {'branch': 'release'}
+
+" Or build from source code by using yarn: https://yarnpkg.com
+Plug 'neoclide/coc.nvim', {'do': 'yarn install --frozen-lockfile'}
+```
+
+in your `.vimrc` or `init.vim`, then restart Vim and run `:PlugInstall`.
+
+Checkout [Install
+coc.nvim](https://github.com/neoclide/coc.nvim/wiki/Install-coc.nvim) for
+more info.
+
+You **have to** install coc extension or configure language servers for
+LSP support.
+
+Install extensions like:
+
+ :CocInstall coc-json coc-tsserver
+
+Or configure language server in `coc-settings.json` opened by
+`:CocConfig`, like:
+
+```json
+{
+ "languageserver": {
+ "go": {
+ "command": "gopls",
+ "rootPatterns": ["go.mod"],
+ "trace.server": "verbose",
+ "filetypes": ["go"]
+ }
+ }
+}
+```
+
+Checkout wiki for more details:
+
+- [Completion with sources](https://github.com/neoclide/coc.nvim/wiki/Completion-with-sources)
+- [Using the configuration file](https://github.com/neoclide/coc.nvim/wiki/Using-the-configuration-file)
+- [Using coc extensions](https://github.com/neoclide/coc.nvim/wiki/Using-coc-extensions)
+- [Configure language servers](https://github.com/neoclide/coc.nvim/wiki/Language-servers)
+- [F.A.Q](https://github.com/neoclide/coc.nvim/wiki/F.A.Q)
+
+Checkout `:h coc-nvim` for vim interface.
+
+## Example vim configuration
+
+Configuration is required to make coc.nvim easier to work with, since it
+doesn't change your key-mappings or Vim options. This is done as much as
+possible to avoid conflict with your other plugins.
+
+**❗️Important**: Some Vim plugins could change key mappings. Please use
+`:verbose imap ` to make sure that your keymap has taken effect.
+
+```vim
+" TextEdit might fail if hidden is not set.
+set hidden
+
+" Some servers have issues with backup files, see #649.
+set nobackup
+set nowritebackup
+
+" Give more space for displaying messages.
+set cmdheight=2
+
+" Having longer updatetime (default is 4000 ms = 4 s) leads to noticeable
+" delays and poor user experience.
+set updatetime=300
+
+" Don't pass messages to |ins-completion-menu|.
+set shortmess+=c
+
+" Always show the signcolumn, otherwise it would shift the text each time
+" diagnostics appear/become resolved.
+if has("patch-8.1.1564")
+ " Recently vim can merge signcolumn and number column into one
+ set signcolumn=number
+else
+ set signcolumn=yes
+endif
+
+" Use tab for trigger completion with characters ahead and navigate.
+" NOTE: Use command ':verbose imap ' to make sure tab is not mapped by
+" other plugin before putting this into your config.
+inoremap
+ \ pumvisible() ? "\" :
+ \ check_back_space() ? "\" :
+ \ coc#refresh()
+inoremap pumvisible() ? "\" : "\"
+
+function! s:check_back_space() abort
+ let col = col('.') - 1
+ return !col || getline('.')[col - 1] =~# '\s'
+endfunction
+
+" Use to trigger completion.
+if has('nvim')
+ inoremap coc#refresh()
+else
+ inoremap coc#refresh()
+endif
+
+" Make auto-select the first completion item and notify coc.nvim to
+" format on enter, could be remapped by other vim plugin
+inoremap pumvisible() ? coc#_select_confirm()
+ \: "\u\\=coc#on_enter()\"
+
+" Use `[g` and `]g` to navigate diagnostics
+" Use `:CocDiagnostics` to get all diagnostics of current buffer in location list.
+nmap [g (coc-diagnostic-prev)
+nmap ]g (coc-diagnostic-next)
+
+" GoTo code navigation.
+nmap gd (coc-definition)
+nmap gy (coc-type-definition)
+nmap gi (coc-implementation)
+nmap gr (coc-references)
+
+" Use K to show documentation in preview window.
+nnoremap K :call show_documentation()
+
+function! s:show_documentation()
+ if (index(['vim','help'], &filetype) >= 0)
+ execute 'h '.expand('')
+ elseif (coc#rpc#ready())
+ call CocActionAsync('doHover')
+ else
+ execute '!' . &keywordprg . " " . expand('')
+ endif
+endfunction
+
+" Highlight the symbol and its references when holding the cursor.
+autocmd CursorHold * silent call CocActionAsync('highlight')
+
+" Symbol renaming.
+nmap rn (coc-rename)
+
+" Formatting selected code.
+xmap f (coc-format-selected)
+nmap f (coc-format-selected)
+
+augroup mygroup
+ autocmd!
+ " Setup formatexpr specified filetype(s).
+ autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
+ " Update signature help on jump placeholder.
+ autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
+augroup end
+
+" Applying codeAction to the selected region.
+" Example: `aap` for current paragraph
+xmap a (coc-codeaction-selected)
+nmap a (coc-codeaction-selected)
+
+" Remap keys for applying codeAction to the current buffer.
+nmap ac (coc-codeaction)
+" Apply AutoFix to problem on the current line.
+nmap qf (coc-fix-current)
+
+" Map function and class text objects
+" NOTE: Requires 'textDocument.documentSymbol' support from the language server.
+xmap if (coc-funcobj-i)
+omap if (coc-funcobj-i)
+xmap af (coc-funcobj-a)
+omap af (coc-funcobj-a)
+xmap ic (coc-classobj-i)
+omap ic (coc-classobj-i)
+xmap ac (coc-classobj-a)
+omap ac (coc-classobj-a)
+
+" Remap and for scroll float windows/popups.
+" Note coc#float#scroll works on neovim >= 0.4.3 or vim >= 8.2.0750
+nnoremap coc#float#has_scroll() ? coc#float#scroll(1) : "\"
+nnoremap coc#float#has_scroll() ? coc#float#scroll(0) : "\"
+inoremap coc#float#has_scroll() ? "\=coc#float#scroll(1)\" : "\"
+inoremap coc#float#has_scroll() ? "\=coc#float#scroll(0)\" : "\"
+
+" Use CTRL-S for selections ranges.
+" Requires 'textDocument/selectionRange' support of language server.
+nmap (coc-range-select)
+xmap (coc-range-select)
+
+" Add `:Format` command to format current buffer.
+command! -nargs=0 Format :call CocAction('format')
+
+" Add `:Fold` command to fold current buffer.
+command! -nargs=? Fold :call CocAction('fold', )
+
+" Add `:OR` command for organize imports of the current buffer.
+command! -nargs=0 OR :call CocAction('runCommand', 'editor.action.organizeImport')
+
+" Add (Neo)Vim's native statusline support.
+" NOTE: Please see `:h coc-status` for integrations with external plugins that
+" provide custom statusline: lightline.vim, vim-airline.
+set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}
+
+" Mappings for CoCList
+" Show all diagnostics.
+nnoremap a :CocList diagnostics
+" Manage extensions.
+nnoremap e :CocList extensions
+" Show commands.
+nnoremap c :CocList commands
+" Find symbol of current document.
+nnoremap o :CocList outline
+" Search workspace symbols.
+nnoremap s :CocList -I symbols
+" Do default action for next item.
+nnoremap j :CocNext
+" Do default action for previous item.
+nnoremap k :CocPrev
+" Resume latest coc list.
+nnoremap p :CocListResume
+```
+
+## Articles
+
+- [coc.nvim 插件体系介绍](https://zhuanlan.zhihu.com/p/65524706)
+- [CocList 入坑指南](https://zhuanlan.zhihu.com/p/71846145)
+- [Create coc.nvim extension to improve Vim experience](https://medium.com/@chemzqm/create-coc-nvim-extension-to-improve-vim-experience-4461df269173)
+- [How to write a coc.nvim extension (and why)](https://samroeca.com/coc-plugin.html)
+
+## Trouble shooting
+
+Try these steps when you have problem with coc.nvim.
+
+- Make sure your Vim version >= 8.0 by command `:version`.
+- If service failed to start, use command `:CocInfo` or `:checkhealth` on Neovim.
+- Checkout the log of coc.nvim by command `:CocOpenLog`.
+- When you have issues with the language server, it's recommended to [checkout
+ the output](https://github.com/neoclide/coc.nvim/wiki/Debug-language-server#using-output-channel).
+
+## Feedback
+
+- If you think Coc is useful, consider giving it a star.
+- If you have a question, [ask on gitter](https://gitter.im/neoclide/coc.nvim)
+- 中文用户请到 [中文 gitter](https://gitter.im/neoclide/coc-cn) 讨论
+- If something is not working, [create an
+ issue](https://github.com/neoclide/coc.nvim/issues/new).
+
+
+
+## License
+
+MIT
diff --git a/pack/acp/start/coc.nvim/autoload/coc.vim b/pack/acp/start/coc.nvim/autoload/coc.vim
new file mode 100644
index 0000000..2e2f45f
--- /dev/null
+++ b/pack/acp/start/coc.nvim/autoload/coc.vim
@@ -0,0 +1,199 @@
+let g:coc#_context = {'start': 0, 'preselect': -1,'candidates': []}
+let g:coc_user_config = get(g:, 'coc_user_config', {})
+let g:coc_global_extensions = get(g:, 'coc_global_extensions', [])
+let g:coc_cygqwin_path_prefixes = get(g:, 'coc_cygqwin_path_prefixes', {})
+let g:coc_selected_text = ''
+let g:coc_vim_commands = []
+let s:watched_keys = []
+let s:is_vim = !has('nvim')
+let s:error_sign = get(g:, 'coc_status_error_sign', has('mac') ? '❌ ' : 'E')
+let s:warning_sign = get(g:, 'coc_status_warning_sign', has('mac') ? '⚠️ ' : 'W')
+let s:select_api = exists('*nvim_select_popupmenu_item')
+let s:callbacks = {}
+
+function! coc#expandable() abort
+ return coc#rpc#request('snippetCheck', [1, 0])
+endfunction
+
+function! coc#jumpable() abort
+ return coc#rpc#request('snippetCheck', [0, 1])
+endfunction
+
+function! coc#expandableOrJumpable() abort
+ return coc#rpc#request('snippetCheck', [1, 1])
+endfunction
+
+" add vim command to CocCommand list
+function! coc#add_command(id, cmd, ...)
+ let config = {'id':a:id, 'cmd':a:cmd, 'title': get(a:,1,'')}
+ call add(g:coc_vim_commands, config)
+ if !coc#rpc#ready() | return | endif
+ call coc#rpc#notify('addCommand', [config])
+endfunction
+
+function! coc#refresh() abort
+ return "\=coc#start()\"
+endfunction
+
+function! coc#on_enter()
+ if !coc#rpc#ready()
+ return ''
+ endif
+ if s:is_vim
+ call coc#rpc#notify('CocAutocmd', ['Enter', bufnr('%')])
+ else
+ call coc#rpc#request('CocAutocmd', ['Enter', bufnr('%')])
+ endif
+ return ''
+endfunction
+
+function! coc#_insert_key(method, key, ...) abort
+ if get(a:, 1, 1)
+ call coc#_cancel()
+ endif
+ return "\=coc#rpc#".a:method."('doKeymap', ['".a:key."'])\"
+endfunction
+
+function! coc#_complete() abort
+ let items = get(g:coc#_context, 'candidates', [])
+ let preselect = get(g:coc#_context, 'preselect', -1)
+ call complete(
+ \ g:coc#_context.start + 1,
+ \ items)
+ if s:select_api && len(items) && preselect != -1
+ call nvim_select_popupmenu_item(preselect, v:false, v:false, {})
+ endif
+ return ''
+endfunction
+
+function! coc#_do_complete(start, items, preselect)
+ let g:coc#_context = {
+ \ 'start': a:start,
+ \ 'candidates': a:items,
+ \ 'preselect': a:preselect
+ \}
+ if mode() =~# 'i' && &paste != 1
+ call feedkeys("\CocRefresh", 'i')
+ endif
+endfunction
+
+function! coc#_select_confirm() abort
+ if !exists('*complete_info')
+ throw 'coc#_select_confirm requires complete_info function to work'
+ endif
+ let selected = complete_info()['selected']
+ if selected != -1
+ return "\"
+ elseif pumvisible()
+ return "\\"
+ endif
+ return ''
+endfunction
+
+function! coc#_selected()
+ if !pumvisible() | return 0 | endif
+ return coc#rpc#request('hasSelected', [])
+endfunction
+
+function! coc#_hide() abort
+ if !pumvisible() | return | endif
+ call feedkeys("\", 'in')
+endfunction
+
+function! coc#_cancel()
+ " hack for close pum
+ if pumvisible() && &paste != 1
+ let g:coc#_context = {'start': 0, 'preselect': -1,'candidates': []}
+ call feedkeys("\CocRefresh", 'i')
+ endif
+endfunction
+
+function! coc#_select() abort
+ if !pumvisible() | return | endif
+ call feedkeys("\", 'in')
+endfunction
+
+function! coc#start(...)
+ let opt = coc#util#get_complete_option()
+ call CocActionAsync('startCompletion', extend(opt, get(a:, 1, {})))
+ return ''
+endfunction
+
+" used for statusline
+function! coc#status()
+ let info = get(b:, 'coc_diagnostic_info', {})
+ let msgs = []
+ if get(info, 'error', 0)
+ call add(msgs, s:error_sign . info['error'])
+ endif
+ if get(info, 'warning', 0)
+ call add(msgs, s:warning_sign . info['warning'])
+ endif
+ return s:trim(join(msgs, ' ') . ' ' . get(g:, 'coc_status', ''))
+endfunction
+
+function! s:trim(str)
+ if exists('*trim')
+ return trim(a:str)
+ endif
+ return substitute(a:str, '\s\+$', '', '')
+endfunction
+
+function! coc#config(section, value)
+ let g:coc_user_config[a:section] = a:value
+ call coc#rpc#notify('updateConfig', [a:section, a:value])
+endfunction
+
+function! coc#add_extension(...)
+ if a:0 == 0 | return | endif
+ call extend(g:coc_global_extensions, a:000)
+endfunction
+
+function! coc#_watch(key)
+ if s:is_vim | return | endif
+ if index(s:watched_keys, a:key) == -1
+ call add(s:watched_keys, a:key)
+ call dictwatcheradd(g:, a:key, function('s:GlobalChange'))
+ endif
+endfunction
+
+function! coc#_unwatch(key)
+ if s:is_vim | return | endif
+ let idx = index(s:watched_keys, a:key)
+ if idx != -1
+ call remove(s:watched_keys, idx)
+ call dictwatcherdel(g:, a:key, function('s:GlobalChange'))
+ endif
+endfunction
+
+function! s:GlobalChange(dict, key, val)
+ call coc#rpc#notify('GlobalChange', [a:key, get(a:val, 'old', v:null), get(a:val, 'new', v:null)])
+endfunction
+
+function! coc#_map()
+ if !s:select_api | return | endif
+ for i in range(1, 9)
+ exe 'inoremap '.i.' call nvim_select_popupmenu_item('.(i - 1).', v:true, v:true, {})'
+ endfor
+endfunction
+
+function! coc#_unmap()
+ if !s:select_api | return | endif
+ for i in range(1, 9)
+ exe 'silent! iunmap '.i
+ endfor
+endfunction
+
+function! coc#on_notify(id, method, Cb)
+ let key = a:id. '-'.a:method
+ let s:callbacks[key] = a:Cb
+ call coc#rpc#notify('registNotification', [a:id, a:method])
+endfunction
+
+function! coc#do_notify(id, method, result)
+ let key = a:id. '-'.a:method
+ let Fn = s:callbacks[key]
+ if !empty(Fn)
+ call Fn(a:result)
+ endif
+endfunction
diff --git a/pack/acp/start/coc.nvim/autoload/coc/api.vim b/pack/acp/start/coc.nvim/autoload/coc/api.vim
new file mode 100644
index 0000000..47bf03d
--- /dev/null
+++ b/pack/acp/start/coc.nvim/autoload/coc/api.vim
@@ -0,0 +1,580 @@
+" ============================================================================
+" Description: Client api used by vim8
+" Author: Qiming Zhao
+" Licence: MIT licence
+" Last Modified: June 28, 2019
+" ============================================================================
+if has('nvim') | finish | endif
+let s:funcs = {}
+let s:prop_id = 1000
+let s:namespace_id = 1
+let s:namespace_cache = {}
+
+" helper {{
+function! s:buf_line_count(bufnr) abort
+ if bufnr('%') == a:bufnr
+ return line('$')
+ endif
+ if exists('*getbufline')
+ let lines = getbufline(a:bufnr, 1, '$')
+ return len(lines)
+ endif
+ let curr = bufnr('%')
+ execute 'buffer '.a:bufnr
+ let n = line('$')
+ execute 'buffer '.curr
+ return n
+endfunction
+
+function! s:execute(cmd)
+ if a:cmd =~# '^echo'
+ execute a:cmd
+ else
+ silent! execute a:cmd
+ endif
+endfunction
+" }}"
+
+" nvim client methods {{
+function! s:funcs.set_current_dir(dir) abort
+ execute 'cd '.a:dir
+endfunction
+
+function! s:funcs.set_var(name, value) abort
+ execute 'let g:'.a:name.'= a:value'
+endfunction
+
+function! s:funcs.del_var(name) abort
+ execute 'unlet g:'.a:name
+endfunction
+
+function! s:funcs.set_option(name, value) abort
+ execute 'let &'.a:name.' = a:value'
+endfunction
+
+function! s:funcs.set_current_buf(bufnr) abort
+ if !bufexists(a:bufnr) | return | endif
+ execute 'buffer '.a:bufnr
+endfunction
+
+function! s:funcs.set_current_win(win_id) abort
+ let [tabnr, winnr] = win_id2tabwin(a:win_id)
+ if tabnr == 0 | return | endif
+ execute 'normal! '.tabnr.'gt'
+ execute winnr.' wincmd w'
+endfunction
+
+function! s:funcs.set_current_tabpage(tabnr) abort
+ execute 'normal! '.a:tabnr.'gt'
+endfunction
+
+function! s:funcs.list_wins() abort
+ return map(getwininfo(), 'v:val["winid"]')
+endfunction
+
+function! s:funcs.call_atomic(calls)
+ let res = []
+ for [key, arglist] in a:calls
+ let name = key[5:]
+ try
+ call add(res, call(s:funcs[name], arglist))
+ catch /.*/
+ return [res, v:exception]
+ endtry
+ endfor
+ return [res, v:null]
+endfunction
+
+function! s:funcs.set_client_info(...) abort
+endfunction
+
+function! s:funcs.subscribe(...) abort
+endfunction
+
+function! s:funcs.unsubscribe(...) abort
+endfunction
+
+function! s:funcs.call_function(method, args) abort
+ return call(a:method, a:args)
+endfunction
+
+function! s:funcs.call_dict_function(dict, method, args) abort
+ return call(a:method, a:args, a:dict)
+endfunction
+
+function! s:funcs.command(command) abort
+ " command that could cause cursor vanish
+ if a:command =~# '^echo' || a:command =~# '^redraw' || a:command =~# '^sign place'
+ call timer_start(0, {-> s:execute(a:command)})
+ else
+ execute a:command
+ endif
+endfunction
+
+function! s:funcs.eval(expr) abort
+ return eval(a:expr)
+endfunction
+
+function! s:funcs.get_api_info()
+ let names = coc#api#func_names()
+ return [1, {'functions': map(names, '{"name": "nvim_".v:val}')}]
+endfunction
+
+function! s:funcs.list_bufs()
+ return map(getbufinfo({'buflisted': 1}), 'v:val["bufnr"]')
+endfunction
+
+function! s:funcs.feedkeys(keys, mode, escape_csi)
+ call feedkeys(a:keys, a:mode)
+endfunction
+
+function! s:funcs.list_runtime_paths()
+ return split(&runtimepath, ',')
+endfunction
+
+function! s:funcs.command_output(cmd)
+ return execute(a:cmd)
+endfunction
+
+function! s:funcs.get_current_line()
+ return getline('.')
+endfunction
+
+function! s:funcs.set_current_line(line)
+ call setline('.', a:line)
+endfunction
+
+function! s:funcs.del_current_line(line)
+ execute 'normal! dd'
+endfunction
+
+function! s:funcs.get_var(var)
+ return get(g:, a:var, v:null)
+endfunction
+
+function! s:funcs.get_vvar(var)
+ return get(v:, a:var, v:null)
+endfunction
+
+function! s:funcs.get_option(name)
+ return eval('&'.a:name)
+endfunction
+
+function! s:funcs.get_current_buf()
+ return bufnr('%')
+endfunction
+
+function! s:funcs.get_current_win()
+ return win_getid()
+endfunction
+
+function! s:funcs.get_current_tabpage()
+ return tabpagenr()
+endfunction
+
+function! s:funcs.list_tabpages()
+ return range(1, tabpagenr('$'))
+endfunction
+
+function! s:funcs.get_mode()
+ return {'blocking': v:false, 'mode': mode()}
+endfunction
+
+function! s:funcs.strwidth(str)
+ return strwidth(a:str)
+endfunction
+
+function! s:funcs.out_write(str)
+ echon a:str
+endfunction
+
+function! s:funcs.err_write(str)
+ echoerr a:str
+endfunction
+
+function! s:funcs.err_writeln(str)
+ echoerr a:str
+endfunction
+
+function! s:funcs.create_namespace(name) abort
+ if empty(a:name)
+ let id = s:namespace_id
+ let s:namespace_id = s:namespace_id + 1
+ return id
+ endif
+ let id = get(s:namespace_cache, a:name, 0)
+ if !id
+ let id = s:namespace_id
+ let s:namespace_id = s:namespace_id + 1
+ let s:namespace_cache[a:name] = id
+ endif
+ return id
+endfunction
+" }}
+
+" buffer methods {{
+function! s:funcs.buf_set_option(bufnr, name, val)
+ let val = a:val
+ if val is v:true
+ let val = 1
+ elseif val is v:false
+ let val = 0
+ endif
+ return setbufvar(a:bufnr, '&'.a:name, val)
+endfunction
+
+function! s:funcs.buf_get_changedtick(bufnr)
+ return getbufvar(a:bufnr, 'changedtick')
+endfunction
+
+function! s:funcs.buf_is_valid(bufnr)
+ return bufloaded(a:bufnr) ? v:true : v:false
+endfunction
+
+function! s:funcs.buf_get_mark(bufnr, name)
+ let nr = bufnr('%')
+ if a:bufnr != 0 || a:bufnr != nr
+ throw 'buf_get_mark support current buffer only'
+ endif
+ return [line("'" . a:name), col("'" . a:name)]
+endfunction
+
+function! s:funcs.buf_add_highlight(bufnr, srcId, hlGroup, line, colStart, colEnd) abort
+ if !has('textprop')
+ return
+ endif
+ let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
+ let key = 'Coc'.a:hlGroup.(a:srcId != -1 ? a:srcId : '')
+ if empty(prop_type_get(key, {'bufnr': a:bufnr}))
+ call prop_type_add(key, {'highlight': a:hlGroup, 'combine': 1, 'bufnr': a:bufnr})
+ if a:srcId != -1
+ let cached = getbufvar(bufnr, 'prop_namespace_'.a:srcId, [])
+ call add(cached, key)
+ call setbufvar(bufnr, 'prop_namespace_'.a:srcId, cached)
+ endif
+ endif
+ let total = strlen(getbufline(bufnr, a:line + 1)[0])
+ let end = a:colEnd
+ if end == -1
+ let end = total
+ else
+ let end = min([end, total])
+ endif
+ if end <= a:colStart
+ return
+ endif
+ let id = s:prop_id
+ let s:prop_id = id + 1
+ try
+ call prop_add(a:line + 1, a:colStart + 1, {'length': end - a:colStart, 'bufnr': bufnr, 'type': key, 'id': id})
+ catch /^Vim\%((\a\+)\)\=:E967/
+ " ignore 967
+ endtry
+endfunction
+
+function! s:funcs.buf_clear_namespace(bufnr, srcId, startLine, endLine) abort
+ if !has('textprop')
+ return
+ endif
+ if a:srcId == -1
+ if a:endLine == -1
+ call prop_clear(a:startLine + 1, {'bufnr': a:bufnr})
+ else
+ call prop_clear(a:startLine + 1, a:endLine + 1, {'bufnr': a:bufnr})
+ endif
+ else
+ let cached = getbufvar(a:bufnr, 'prop_namespace_'.a:srcId, [])
+ if empty(cached)
+ return
+ endif
+ for key in cached
+ call prop_remove({'type': key, 'bufnr': a:bufnr, 'all': 1})
+ endfor
+ endif
+endfunction
+
+function! s:funcs.buf_line_count(bufnr) abort
+ return s:buf_line_count(a:bufnr)
+endfunction
+
+function! s:funcs.buf_attach(...)
+ " not supported
+ return 1
+endfunction
+
+function! s:funcs.buf_detach()
+ " not supported
+ return 1
+endfunction
+
+function! s:funcs.buf_get_lines(bufnr, start, end, strict) abort
+ let lines = getbufline(a:bufnr, 1, '$')
+ let start = a:start < 0 ? a:start + 1 : a:start
+ let end = a:end < 0 ? a:end + 1 : a:end
+ if a:strict && end > len(lines)
+ throw 'line number out of range: '. end
+ endif
+ return lines[start : end - 1]
+endfunction
+
+function! s:funcs.buf_set_lines(bufnr, start, end, strict, ...) abort
+ if !bufloaded(a:bufnr)
+ return
+ endif
+ let replacement = get(a:, 1, [])
+ let lineCount = s:buf_line_count(a:bufnr)
+ let startLnum = a:start >= 0 ? a:start + 1 : lineCount + a:start + 1
+ let end = a:end >= 0 ? a:end : lineCount + a:end + 1
+ if end == lineCount + 1
+ let end = lineCount
+ endif
+ let delCount = end - (startLnum - 1)
+ let changeBuffer = 0
+ let curr = bufnr('%')
+ if a:bufnr != curr && !exists('*setbufline')
+ let changeBuffer = 1
+ exe 'buffer '.a:bufnr
+ endif
+ if a:bufnr == curr || changeBuffer
+ " replace
+ let storeView = winsaveview()
+ if delCount == len(replacement)
+ call setline(startLnum, replacement)
+ else
+ if len(replacement)
+ call append(startLnum - 1, replacement)
+ endif
+ if delCount
+ let start = startLnum + len(replacement)
+ let saved_reg = @"
+ silent execute start . ','.(start + delCount - 1).'d'
+ let @" = saved_reg
+ endif
+ endif
+ call winrestview(storeView)
+ if changeBuffer
+ exe 'buffer '.curr
+ endif
+ elseif exists('*setbufline')
+ " replace
+ if delCount == len(replacement)
+ " 8.0.1039
+ call setbufline(a:bufnr, startLnum, replacement)
+ else
+ if len(replacement)
+ " 8.10037
+ call appendbufline(a:bufnr, startLnum - 1, replacement)
+ endif
+ if delCount
+ let start = startLnum + len(replacement)
+ "8.1.0039
+ call deletebufline(a:bufnr, start, start + delCount - 1)
+ endif
+ endif
+ endif
+endfunction
+
+function! s:funcs.buf_set_name(bufnr, name) abort
+ let nr = bufnr('%')
+ if a:bufnr != nr
+ throw 'buf_set_name support current buffer only'
+ else
+ execute '0f'
+ execute 'file '.fnameescape(a:name)
+ endif
+endfunction
+
+function! s:funcs.buf_get_var(bufnr, name)
+ return getbufvar(a:bufnr, a:name)
+endfunction
+
+function! s:funcs.buf_set_var(bufnr, name, val)
+ if !bufloaded(a:bufnr) | return | endif
+ call setbufvar(a:bufnr, a:name, a:val)
+endfunction
+
+function! s:funcs.buf_del_var(bufnr, name)
+ call setbufvar(a:bufnr, a:name, v:null)
+endfunction
+
+function! s:funcs.buf_get_option(bufnr, name)
+ return getbufvar(a:bufnr, '&'.a:name)
+endfunction
+
+function! s:funcs.buf_get_name(bufnr)
+ return bufname(a:bufnr)
+endfunction
+" }}
+
+" window methods {{
+function! s:funcs.win_get_buf(winid)
+ return winbufnr(a:winid)
+endfunction
+
+function! s:funcs.win_get_position(win_id) abort
+ let [row, col] = win_screenpos(a:win_id)
+ if row == 0 && col == 0
+ throw 'Invalid window '.a:win_id
+ endif
+ return [row - 1, col - 1]
+endfunction
+
+function! s:funcs.win_get_height(win_id) abort
+ return winheight(a:win_id)
+endfunction
+
+function! s:funcs.win_get_width(win_id) abort
+ return winwidth(a:win_id)
+endfunction
+
+if exists('*win_execute')
+ function! s:win_execute(win_id, cmd, ...) abort
+ let ref = get(a:000, 0, v:null)
+ let cmd = ref is v:null ? a:cmd : 'let ref["out"] = ' . a:cmd
+ call win_execute(a:win_id, cmd)
+ endfunction
+else
+ function! s:win_execute(win_id, cmd, ...) abort
+ let ref = get(a:000, 0, v:null)
+ let cmd = ref is v:null ? a:cmd : 'let ref["out"] = ' . a:cmd
+ let winid = win_getid()
+ if winid == a:win_id
+ execute cmd
+ else
+ let goto_status = win_gotoid(a:win_id)
+ if !goto_status
+ return
+ endif
+ execute cmd
+ call win_gotoid(winid)
+ endif
+ endfunction
+endif
+
+function! s:funcs.win_get_cursor(win_id) abort
+ let ref = {}
+ call s:win_execute(a:win_id, "[line('.'), col('.')-1]", ref)
+ return ref['out']
+endfunction
+
+function! s:funcs.win_get_var(win_id, name) abort
+ return gettabwinvar(0, a:win_id, a:name)
+endfunction
+
+function! s:funcs.win_set_width(win_id, width) abort
+ return s:win_execute(a:win_id, 'vertical resize '.a:width)
+endfunction
+
+function! s:funcs.win_set_buf(win_id, buf_id) abort
+ return s:win_execute(a:win_id, 'buffer '.a:buf_id)
+endfunction
+
+function! s:funcs.win_get_option(win_id, name) abort
+ return gettabwinvar(0, a:win_id, '&'.a:name)
+endfunction
+
+function! s:funcs.win_set_height(win_id, height) abort
+ return s:win_execute(a:win_id, 'resize '.a:height)
+endfunction
+
+function! s:funcs.win_set_option(win_id, name, value) abort
+ let val = a:value
+ if val is v:true
+ let val = 1
+ elseif val is v:false
+ let val = 0
+ endif
+ call setwinvar(a:win_id, '&'.a:name, val)
+endfunction
+
+function! s:funcs.win_set_var(win_id, name, value) abort
+ call setwinvar(a:win_id, a:name, a:value)
+endfunction
+
+function! s:funcs.win_del_var(win_id, name) abort
+ call settabwinvar(0, a:win_id, a:name, v:null)
+endfunction
+
+function! s:funcs.win_is_valid(win_id) abort
+ let info = getwininfo(a:win_id)
+ return !empty(info)
+endfunction
+
+function! s:funcs.win_get_number(win_id) abort
+ let info = getwininfo(a:win_id)
+ if empty(info)
+ throw 'Invalid window id '.a:win_id
+ endif
+ return info[0]['winnr']
+endfunction
+
+function! s:funcs.win_set_cursor(win_id, pos) abort
+ let [line, col] = a:pos
+ call s:win_execute(a:win_id, 'call cursor('.line.','.(col + 1).')')
+endfunction
+
+function! s:funcs.win_close(win_id, ...) abort
+ call s:win_execute(a:win_id, 'close!')
+endfunction
+
+function! s:funcs.win_get_tabpage(win_id) abort
+ let info = getwininfo(a:win_id)
+ if !info
+ throw 'Invalid window id '.a:win_id
+ endif
+ return info[0]['tabnr']
+endfunction
+" }}
+
+" tabpage methods {{
+function! s:funcs.tabpage_get_number(id)
+ return a:id
+endfunction
+
+function! s:funcs.tabpage_list_wins(tabnr)
+ let info = getwininfo()
+ return map(filter(info, 'v:val["tabnr"] == a:tabnr'), 'v:val["winid"]')
+endfunction
+
+function! s:funcs.tabpage_get_var(tabnr, name)
+ return gettabvar(a:tabnr, a:name, v:null)
+endfunction
+
+function! s:funcs.tabpage_set_var(tabnr, name, value)
+ call settabvar(a:tabnr, a:name, a:value)
+endfunction
+
+function! s:funcs.tabpage_del_var(tabnr, name)
+ call settabvar(a:tabnr, a:name, v:null)
+endfunction
+
+function! s:funcs.tabpage_is_valid(tabnr)
+ let max = tabpagenr('$')
+ return a:tabnr <= max
+endfunction
+
+function! s:funcs.tabpage_get_win(tabnr)
+ let wnr = tabpagewinnr(a:tabnr)
+ return win_getid(wnr, a:tabnr)
+endfunction
+" }}
+
+function! coc#api#func_names() abort
+ return keys(s:funcs)
+endfunction
+
+function! coc#api#call(method, args) abort
+ let err = v:null
+ let res = v:null
+ try
+ let res = call(s:funcs[a:method], a:args)
+ catch /.*/
+ let err = v:exception
+ endtry
+ return [err, res]
+endfunction
+
+function! coc#api#notify(method, args) abort
+ call call(s:funcs[a:method], a:args)
+endfunction
+" vim: set sw=2 ts=2 sts=2 et tw=78 foldmarker={{,}} foldmethod=marker foldlevel=0:
diff --git a/pack/acp/start/coc.nvim/autoload/coc/client.vim b/pack/acp/start/coc.nvim/autoload/coc/client.vim
new file mode 100644
index 0000000..3b945aa
--- /dev/null
+++ b/pack/acp/start/coc.nvim/autoload/coc/client.vim
@@ -0,0 +1,313 @@
+let s:root = expand(':h:h:h')
+let s:is_vim = !has('nvim')
+let s:is_win = has("win32") || has("win64")
+let s:clients = {}
+
+if get(g:, 'node_client_debug', 0)
+ let $NODE_CLIENT_LOG_LEVEL = 'debug'
+ if exists('$NODE_CLIENT_LOG_FILE')
+ let s:logfile = resolve($NODE_CLIENT_LOG_FILE)
+ else
+ let s:logfile = tempname()
+ let $NODE_CLIENT_LOG_FILE = s:logfile
+ endif
+endif
+
+" create a client
+function! coc#client#create(name, command)
+ let client = {}
+ let client['command'] = a:command
+ let client['name'] = a:name
+ let client['running'] = 0
+ let client['async_req_id'] = 1
+ let client['async_callbacks'] = {}
+ " vim only
+ let client['channel'] = v:null
+ " neovim only
+ let client['chan_id'] = 0
+ let client['start'] = function('s:start', [], client)
+ let client['request'] = function('s:request', [], client)
+ let client['notify'] = function('s:notify', [], client)
+ let client['request_async'] = function('s:request_async', [], client)
+ let client['on_async_response'] = function('s:on_async_response', [], client)
+ let s:clients[a:name] = client
+ return client
+endfunction
+
+function! s:start() dict
+ if self.running | return | endif
+ if !isdirectory(getcwd())
+ echohl Error | echon '[coc.nvim] Current cwd is not a valid directory.' | echohl None
+ return
+ endif
+ let timeout = string(get(g:, 'coc_channel_timeout', 30))
+ let disable_warning = string(get(g:, 'coc_disable_startup_warning', 0))
+ let tmpdir = fnamemodify(tempname(), ':p:h')
+ if s:is_vim
+ let options = {
+ \ 'in_mode': 'json',
+ \ 'out_mode': 'json',
+ \ 'err_mode': 'nl',
+ \ 'err_cb': {channel, message -> s:on_stderr(self.name, split(message, "\n"))},
+ \ 'exit_cb': {channel, code -> s:on_exit(self.name, code)},
+ \ 'env': {
+ \ 'NODE_NO_WARNINGS': '1',
+ \ 'VIM_NODE_RPC': '1',
+ \ 'COC_NVIM': '1',
+ \ 'COC_CHANNEL_TIMEOUT': timeout,
+ \ 'COC_NO_WARNINGS': disable_warning,
+ \ 'TMPDIR': tmpdir,
+ \ }
+ \}
+ if has("patch-8.1.350")
+ let options['noblock'] = 1
+ endif
+ let job = job_start(self.command, options)
+ let status = job_status(job)
+ if status !=# 'run'
+ let self.running = 0
+ echohl Error | echom 'Failed to start '.self.name.' service' | echohl None
+ return
+ endif
+ let self['running'] = 1
+ let self['channel'] = job_getchannel(job)
+ else
+ let original = {
+ \ 'NODE_NO_WARNINGS': getenv('NODE_NO_WARNINGS'),
+ \ 'COC_CHANNEL_TIMEOUT': getenv('COC_CHANNEL_TIMEOUT'),
+ \ 'COC_NO_WARNINGS': getenv('COC_NO_WARNINGS'),
+ \ 'TMPDIR': getenv('TMPDIR'),
+ \ }
+ " env option not work on neovim
+ call setenv('NODE_NO_WARNINGS', '1')
+ call setenv('COC_CHANNEL_TIMEOUT', timeout)
+ call setenv('COC_NO_WARNINGS', disable_warning)
+ call setenv('TMPDIR', tmpdir)
+ let chan_id = jobstart(self.command, {
+ \ 'rpc': 1,
+ \ 'on_stderr': {channel, msgs -> s:on_stderr(self.name, msgs)},
+ \ 'on_exit': {channel, code -> s:on_exit(self.name, code)},
+ \})
+ for key in keys(original)
+ call setenv(key, original[key])
+ endfor
+ if chan_id <= 0
+ echohl Error | echom 'Failed to start '.self.name.' service' | echohl None
+ return
+ endif
+ let self['chan_id'] = chan_id
+ let self['running'] = 1
+ endif
+endfunction
+
+function! s:on_stderr(name, msgs)
+ if get(g:, 'coc_vim_leaving', 0) | return | endif
+ if get(g:, 'coc_disable_uncaught_error', 0) | return | endif
+ let data = filter(copy(a:msgs), '!empty(v:val)')
+ if empty(data) | return | endif
+ let client = a:name ==# 'coc' ? '[coc.nvim]' : '['.a:name.']'
+ let data[0] = client.': '.data[0]
+ call coc#util#echo_messages('Error', data)
+endfunction
+
+function! s:on_exit(name, code) abort
+ if get(g:, 'coc_vim_leaving', 0) | return | endif
+ let client = get(s:clients, a:name, v:null)
+ if empty(client) | return | endif
+ if client['running'] != 1 | return | endif
+ let client['running'] = 0
+ let client['chan_id'] = 0
+ let client['channel'] = v:null
+ let client['async_req_id'] = 1
+ if a:code != 0 && a:code != 143
+ echohl Error | echom 'client '.a:name. ' abnormal exit with: '.a:code | echohl None
+ endif
+endfunction
+
+function! coc#client#get_client(name) abort
+ return get(s:clients, a:name, v:null)
+endfunction
+
+function! coc#client#get_channel(client)
+ if s:is_vim
+ return a:client['channel']
+ endif
+ return a:client['chan_id']
+endfunction
+
+function! s:request(method, args) dict
+ let channel = coc#client#get_channel(self)
+ if empty(channel) | return '' | endif
+ try
+ if s:is_vim
+ let res = ch_evalexpr(channel, [a:method, a:args], {'timeout': 60 * 1000})
+ if type(res) == 1 && res ==# ''
+ throw 'request '.a:method. ' '.string(a:args).' timeout after 60s'
+ endif
+ let [l:errmsg, res] = res
+ if !empty(l:errmsg)
+ throw l:errmsg
+ else
+ return res
+ endif
+ else
+ return call('rpcrequest', [channel, a:method] + a:args)
+ endif
+ catch /.*/
+ if v:exception =~# 'E475'
+ if get(g:, 'coc_vim_leaving', 0) | return | endif
+ echohl Error | echom '['.self.name.'] server connection lost' | echohl None
+ let name = self.name
+ call s:on_exit(name, 0)
+ execute 'silent do User ConnectionLost'.toupper(name[0]).name[1:]
+ elseif v:exception =~# 'E12'
+ " neovim's bug, ignore it
+ else
+ echohl Error | echo 'Error on request ('.a:method.'): '.v:exception | echohl None
+ endif
+ endtry
+endfunction
+
+function! s:notify(method, args) dict
+ let channel = coc#client#get_channel(self)
+ if empty(channel)
+ return ''
+ endif
+ try
+ if s:is_vim
+ call ch_sendraw(channel, json_encode([0, [a:method, a:args]])."\n")
+ else
+ call call('rpcnotify', [channel, a:method] + a:args)
+ endif
+ catch /.*/
+ if v:exception =~# 'E475'
+ if get(g:, 'coc_vim_leaving', 0)
+ return
+ endif
+ echohl Error | echom '['.self.name.'] server connection lost' | echohl None
+ let name = self.name
+ call s:on_exit(name, 0)
+ execute 'silent do User ConnectionLost'.toupper(name[0]).name[1:]
+ elseif v:exception =~# 'E12'
+ " neovim's bug, ignore it
+ else
+ echohl Error | echo 'Error on notify ('.a:method.'): '.v:exception | echohl None
+ endif
+ endtry
+endfunction
+
+function! s:request_async(method, args, cb) dict
+ let channel = coc#client#get_channel(self)
+ if empty(channel) | return '' | endif
+ if type(a:cb) != 2
+ echohl Error | echom '['.self['name'].'] Callback should be function' | echohl None
+ return
+ endif
+ let id = self.async_req_id
+ let self.async_req_id = id + 1
+ let self.async_callbacks[id] = a:cb
+ call self['notify']('nvim_async_request_event', [id, a:method, a:args])
+endfunction
+
+function! s:on_async_response(id, resp, isErr) dict
+ let Callback = get(self.async_callbacks, a:id, v:null)
+ if empty(Callback)
+ " should not happen
+ echohl Error | echom 'callback not found' | echohl None
+ return
+ endif
+ call remove(self.async_callbacks, a:id)
+ if a:isErr
+ call call(Callback, [a:resp, v:null])
+ else
+ call call(Callback, [v:null, a:resp])
+ endif
+endfunction
+
+function! coc#client#is_running(name) abort
+ let client = get(s:clients, a:name, v:null)
+ if empty(client) | return 0 | endif
+ if !client['running'] | return 0 | endif
+ if s:is_vim
+ let status = job_status(ch_getjob(client['channel']))
+ return status ==# 'run'
+ else
+ let chan_id = client['chan_id']
+ let [code] = jobwait([chan_id], 10)
+ return code == -1
+ endif
+endfunction
+
+function! coc#client#stop(name) abort
+ let client = get(s:clients, a:name, v:null)
+ if empty(client) | return 1 | endif
+ let running = coc#client#is_running(a:name)
+ if !running
+ echohl WarningMsg | echom 'client '.a:name. ' not running.' | echohl None
+ return 1
+ endif
+ if s:is_vim
+ call job_stop(ch_getjob(client['channel']), 'term')
+ else
+ call jobstop(client['chan_id'])
+ endif
+ sleep 200m
+ if coc#client#is_running(a:name)
+ echohl Error | echom 'client '.a:name. ' stop failed.' | echohl None
+ return 0
+ endif
+ call s:on_exit(a:name, 0)
+ echohl MoreMsg | echom 'client '.a:name.' stopped!' | echohl None
+ return 1
+endfunction
+
+function! coc#client#request(name, method, args)
+ let client = get(s:clients, a:name, v:null)
+ if !empty(client)
+ return client['request'](a:method, a:args)
+ endif
+endfunction
+
+function! coc#client#notify(name, method, args)
+ let client = get(s:clients, a:name, v:null)
+ if !empty(client)
+ call client['notify'](a:method, a:args)
+ endif
+endfunction
+
+function! coc#client#request_async(name, method, args, cb)
+ let client = get(s:clients, a:name, v:null)
+ if !empty(client)
+ call client['request_async'](a:method, a:args, a:cb)
+ endif
+endfunction
+
+function! coc#client#on_response(name, id, resp, isErr)
+ let client = get(s:clients, a:name, v:null)
+ if !empty(client)
+ call client['on_async_response'](a:id, a:resp, a:isErr)
+ endif
+endfunction
+
+function! coc#client#restart(name) abort
+ let stopped = coc#client#stop(a:name)
+ if !stopped | return | endif
+ let client = get(s:clients, a:name, v:null)
+ if !empty(client)
+ call client['start']()
+ endif
+endfunction
+
+function! coc#client#restart_all()
+ for key in keys(s:clients)
+ call coc#client#restart(key)
+ endfor
+endfunction
+
+function! coc#client#open_log()
+ if !get(g:, 'node_client_debug', 0)
+ echohl Error | echon '[coc.nvim] use let g:node_client_debug = 1 in your vimrc to enabled debug mode.' | echohl None
+ return
+ endif
+ execute 'vs '.s:logfile
+endfunction
diff --git a/pack/acp/start/coc.nvim/autoload/coc/float.vim b/pack/acp/start/coc.nvim/autoload/coc/float.vim
new file mode 100644
index 0000000..bb66324
--- /dev/null
+++ b/pack/acp/start/coc.nvim/autoload/coc/float.vim
@@ -0,0 +1,942 @@
+" Related to float window create
+let s:is_vim = !has('nvim')
+let s:borderchars = get(g:, 'coc_borderchars',
+ \ ['─', '│', '─', '│', '┌', '┐', '┘', '└'])
+let s:prompt_win_width = get(g:, 'coc_prompt_win_width', 32)
+let s:scrollbar_ns = exists('*nvim_create_namespace') ? nvim_create_namespace('coc-scrollbar') : 0
+" winvar: border array of numbers, button boolean
+
+" detect if there's float window/popup created by coc.nvim
+function! coc#float#has_float() abort
+ if s:is_vim
+ if !exists('*popup_list')
+ return 0
+ endif
+ let arr = filter(popup_list(), 'getwinvar(v:val,"float",0)&&popup_getpos(v:val)["visible"]')
+ return !empty(arr)
+ endif
+ for i in range(1, winnr('$'))
+ if getwinvar(i, 'float')
+ return 1
+ endif
+ endfor
+ return 0
+endfunction
+
+function! coc#float#close_all() abort
+ if !has('nvim') && exists('*popup_clear')
+ call popup_clear()
+ return
+ endif
+ let winids = coc#float#get_float_win_list()
+ for id in winids
+ call coc#float#close(id)
+ endfor
+endfunction
+
+function! coc#float#jump() abort
+ if s:is_vim
+ return
+ endif
+ let winids = coc#float#get_float_win_list()
+ if !empty(winids)
+ call win_gotoid(winids[0])
+ endif
+endfunction
+
+function! coc#float#get_float_mode(lines, config) abort
+ let allowSelection = get(a:config, 'allowSelection', 0)
+ let pumAlignTop = get(a:config, 'pumAlignTop', 0)
+ let mode = mode()
+ let checked = (mode == 's' && allowSelection) || index(['i', 'n', 'ic'], mode) != -1
+ if !checked
+ return v:null
+ endif
+ if !s:is_vim && mode ==# 'i'
+ " helps to fix undo issue, don't know why.
+ call feedkeys("\u", 'n')
+ endif
+ let dimension = coc#float#get_config_cursor(a:lines, a:config)
+ if empty(dimension)
+ return v:null
+ endif
+ if pumvisible() && ((pumAlignTop && dimension['row'] <0)|| (!pumAlignTop && dimension['row'] > 0))
+ return v:null
+ endif
+ return [mode, bufnr('%'), [line('.'), col('.')], dimension]
+endfunction
+
+" create/reuse float window for config position, config including:
+" - line: line count relative to cursor, nagetive number means abover cursor.
+" - col: column count relative to cursor, nagetive number means left of cursor.
+" - width: content width without border and title.
+" - height: content height without border and title.
+" - title: (optional) title.
+" - border: (optional) border as number list, like [1, 1, 1 ,1].
+" - cursorline: (optional) enable cursorline when is 1.
+" - autohide: (optional) window should be closed on CursorMoved when is 1.
+function! coc#float#create_float_win(winid, bufnr, config) abort
+ call coc#float#close_auto_hide_wins(a:winid)
+ " use exists
+ if a:winid && coc#float#valid(a:winid)
+ if s:is_vim
+ let [line, col] = s:popup_position(a:config)
+ call popup_move(a:winid, {
+ \ 'line': line,
+ \ 'col': col,
+ \ 'minwidth': a:config['width'],
+ \ 'minheight': a:config['height'],
+ \ 'maxwidth': a:config['width'],
+ \ 'maxheight': a:config['height'],
+ \ })
+ let opts = {
+ \ 'cursorline': get(a:config, 'cursorline', 0),
+ \ 'title': get(a:config, 'title', ''),
+ \ }
+ if !s:empty_border(get(a:config, 'border', []))
+ let opts['border'] = a:config['border']
+ endif
+ call popup_setoptions(a:winid, opts)
+ return [a:winid, winbufnr(a:winid)]
+ else
+ let config = s:convert_config_nvim(a:config)
+ " not reuse related windows
+ call coc#float#nvim_close_related(a:winid)
+ call nvim_win_set_config(a:winid, config)
+ call coc#float#nvim_create_related(a:winid, config, a:config)
+ return [a:winid, winbufnr(a:winid)]
+ endif
+ endif
+ let winid = 0
+ if s:is_vim
+ let [line, col] = s:popup_position(a:config)
+ let bufnr = coc#float#create_float_buf(a:bufnr)
+ let title = get(a:config, 'title', '')
+ let opts = {
+ \ 'title': title,
+ \ 'line': line,
+ \ 'col': col,
+ \ 'padding': empty(title) ? [0, 1, 0, 1] : [0, 0, 0, 0],
+ \ 'borderchars': s:borderchars,
+ \ 'highlight': 'CocFloating',
+ \ 'fixed': 1,
+ \ 'cursorline': get(a:config, 'cursorline', 0),
+ \ 'minwidth': a:config['width'],
+ \ 'minheight': a:config['height'],
+ \ 'maxwidth': a:config['width'],
+ \ 'maxheight': a:config['height']
+ \ }
+ if get(a:config, 'close', 0)
+ let opts['close'] = 'button'
+ endif
+ if !s:empty_border(get(a:config, 'border', []))
+ let opts['border'] = a:config['border']
+ endif
+ let winid = popup_create(bufnr, opts)
+ if winid == 0
+ return []
+ endif
+ if has("patch-8.1.2281")
+ call setwinvar(winid, '&showbreak', 'NONE')
+ endif
+ else
+ let config = s:convert_config_nvim(a:config)
+ let bufnr = coc#float#create_float_buf(a:bufnr)
+ let winid = nvim_open_win(bufnr, 0, config)
+ if winid == 0
+ return []
+ endif
+ call setwinvar(winid, '&winhl', 'Normal:CocFloating,NormalNC:CocFloating,FoldColumn:CocFloating,CursorLine:CocMenuSel')
+ call setwinvar(winid, '&signcolumn', 'no')
+ " no left border
+ if s:empty_border(get(a:config, 'border', [])) || a:config['border'][3] == 0
+ call setwinvar(winid, '&foldcolumn', 1)
+ endif
+ call coc#float#nvim_create_related(winid, config, a:config)
+ endif
+ if !s:is_vim
+ " change cursorline option affects vim's own highlight
+ call setwinvar(winid, '&cursorline', get(a:config, 'cursorline', 0))
+ call setwinvar(winid, 'border', get(a:config, 'border', []))
+ endif
+ if get(a:config, 'autohide', 0)
+ call setwinvar(winid, 'autohide', 1)
+ endif
+ if s:is_vim || has('nvim-0.5.0')
+ call setwinvar(winid, '&scrolloff', 0)
+ endif
+ call setwinvar(winid, '&list', 0)
+ call setwinvar(winid, '&number', 0)
+ call setwinvar(winid, '&relativenumber', 0)
+ call setwinvar(winid, '&cursorcolumn', 0)
+ call setwinvar(winid, '&colorcolumn', 0)
+ call setwinvar(winid, 'float', 1)
+ call setwinvar(winid, '&wrap', 1)
+ call setwinvar(winid, '&linebreak', 1)
+ call setwinvar(winid, '&conceallevel', 2)
+ let g:coc_last_float_win = winid
+ call coc#util#do_autocmd('CocOpenFloat')
+ return [winid, winbufnr(winid)]
+endfunction
+
+function! coc#float#valid(winid) abort
+ if a:winid == 0 || type(a:winid) != 0
+ return 0
+ endif
+ if s:is_vim
+ return s:popup_visible(a:winid)
+ endif
+ if exists('*nvim_win_is_valid') && nvim_win_is_valid(a:winid)
+ let config = nvim_win_get_config(a:winid)
+ return !empty(get(config, 'relative', ''))
+ endif
+ return 0
+endfunction
+
+" create buffer for popup/float window
+function! coc#float#create_float_buf(bufnr) abort
+ " reuse buffer cause error on vim8
+ if a:bufnr && bufloaded(a:bufnr)
+ return a:bufnr
+ endif
+ if s:is_vim
+ noa let bufnr = bufadd('')
+ noa call bufload(bufnr)
+ else
+ noa let bufnr = nvim_create_buf(v:false, v:true)
+ endif
+ " Don't use popup filetype, it would crash on reuse!
+ call setbufvar(bufnr, '&buftype', 'nofile')
+ call setbufvar(bufnr, '&bufhidden', 'hide')
+ call setbufvar(bufnr, '&swapfile', 0)
+ call setbufvar(bufnr, '&tabstop', 2)
+ call setbufvar(bufnr, '&undolevels', -1)
+ return bufnr
+endfunction
+
+" border window for neovim, content config with border
+function! coc#float#nvim_border_win(config, border, title, related) abort
+ if s:empty_border(a:border)
+ return
+ endif
+ " width height col row relative
+ noa let bufnr = nvim_create_buf(v:false, v:true)
+ call setbufvar(bufnr, '&bufhidden', 'wipe')
+ let row = a:border[0] ? a:config['row'] - 1 : a:config['row']
+ let col = a:border[3] ? a:config['col'] - 1 : a:config['col']
+ let width = a:config['width'] + a:border[1] + a:border[3]
+ let height = a:config['height'] + a:border[0] + a:border[2]
+ let opt = {
+ \ 'relative': a:config['relative'],
+ \ 'width': width,
+ \ 'height': height,
+ \ 'row': row,
+ \ 'col': col,
+ \ 'focusable': v:false,
+ \ 'style': 'minimal',
+ \ }
+ let winid = nvim_open_win(bufnr, 0, opt)
+ if !winid
+ return
+ endif
+ call setwinvar(winid, '&winhl', 'Normal:CocFloating,NormalNC:CocFloating')
+ let lines = coc#float#create_border_lines(a:border, a:title, a:config['width'], a:config['height'])
+ call nvim_buf_set_lines(bufnr, 0, -1, v:false, lines)
+ call add(a:related, winid)
+endfunction
+
+function! coc#float#create_border_lines(border, title, width, height) abort
+ let list = []
+ if a:border[0]
+ let top = (a:border[3] ? s:borderchars[4]: '')
+ \.repeat(s:borderchars[0], a:width)
+ \.(a:border[1] ? s:borderchars[5] : '')
+ if !empty(a:title)
+ let top = coc#helper#str_compose(top, 1, a:title.' ')
+ endif
+ call add(list, top)
+ endif
+ let mid = (a:border[3] ? s:borderchars[3]: '')
+ \.repeat(' ', a:width)
+ \.(a:border[1] ? s:borderchars[1] : '')
+ call extend(list, repeat([mid], a:height))
+ if a:border[2]
+ let bot = (a:border[3] ? s:borderchars[7]: '')
+ \.repeat(s:borderchars[2], a:width)
+ \.(a:border[1] ? s:borderchars[6] : '')
+ call add(list, bot)
+ endif
+ return list
+endfunction
+
+" Create float window for input
+function! coc#float#create_prompt_win(title, default) abort
+ call coc#float#close_auto_hide_wins()
+ noa let bufnr = nvim_create_buf(v:false, v:true)
+ call nvim_buf_set_lines(bufnr, 0, -1, v:false, [a:default])
+ call setbufvar(bufnr, '&bufhidden', 'wipe')
+ " Calculate col
+ let curr = win_screenpos(winnr())[1] + wincol() - 2
+ let width = min([max([strdisplaywidth(a:title) + 2, s:prompt_win_width]), &columns - 2])
+ if width == &columns - 2
+ let col = 0 - curr
+ else
+ let col = curr + width <= &columns - 2 ? 0 : &columns - s:prompt_win_width
+ endif
+ let config = {
+ \ 'relative': 'cursor',
+ \ 'width': width,
+ \ 'height': 1,
+ \ 'row': 0,
+ \ 'col': col,
+ \ 'style': 'minimal',
+ \ }
+ let winid = nvim_open_win(bufnr, 0, config)
+ if winid == 0
+ return []
+ endif
+ call setwinvar(winid, '&winhl', 'Normal:CocFloating,NormalNC:CocFloating')
+ let related = []
+ call coc#float#nvim_border_win(config, [1,1,1,1], a:title, related)
+ call setwinvar(winid, 'related', related)
+ call win_gotoid(winid)
+ inoremap
+ inoremap pumvisible() ? "\" : "\"
+ exe 'inoremap =coc#float#close_i('.winid.')'
+ exe 'nnoremap :call coc#float#close('.winid.')'
+ exe 'inoremap "\=coc#float#prompt_insert('.winid.')\\"'
+ call feedkeys('A', 'in')
+ return [bufnr, winid]
+endfunction
+
+function! coc#float#close_i(winid) abort
+ call coc#float#close(a:winid)
+ return ''
+endfunction
+
+function! coc#float#prompt_insert(winid) abort
+ let text = getline('.')
+ let bufnr = winbufnr(a:winid)
+ call coc#rpc#notify('PromptInsert',[text, bufnr])
+ call timer_start(50, { -> coc#float#close(a:winid)})
+ return ''
+endfunction
+
+" Position of cursor relative to editor
+function! s:win_position() abort
+ let nr = winnr()
+ let [row, col] = win_screenpos(nr)
+ return [row + winline() - 2, col + wincol() - 2]
+endfunction
+
+" get popup position for vim8 based on config of neovim float window
+function! s:popup_position(config) abort
+ let relative = get(a:config, 'relative', 'editor')
+ if relative ==# 'cursor'
+ return [s:popup_cursor(a:config['row']), s:popup_cursor(a:config['col'])]
+ endif
+ return [a:config['row'] + 1, a:config['col'] + 1]
+endfunction
+
+function! s:popup_cursor(n) abort
+ if a:n == 0
+ return 'cursor'
+ endif
+ if a:n < 0
+ return 'cursor'.a:n
+ endif
+ return 'cursor+'.a:n
+endfunction
+
+" Close float window by id
+function! coc#float#close(winid) abort
+ if !coc#float#valid(a:winid)
+ return 0
+ endif
+ if s:is_vim
+ call popup_close(a:winid)
+ return 1
+ else
+ call coc#float#nvim_close_related(a:winid)
+ call nvim_win_close(a:winid, 1)
+ return 1
+ endif
+ return 0
+endfunction
+
+" Float window id on current tab.
+" return 0 if not found
+function! coc#float#get_float_win() abort
+ if has('nvim')
+ for i in range(1, winnr('$'))
+ let id = win_getid(i)
+ let config = nvim_win_get_config(id)
+ if (!empty(config) && config['focusable'] == v:true && !empty(config['relative']))
+ if !getwinvar(id, 'button', 0)
+ return id
+ endif
+ endif
+ endfor
+ elseif exists('*popup_list')
+ let arr = filter(popup_list(), 'popup_getpos(v:val)["visible"]')
+ if !empty(arr)
+ return arr[0]
+ endif
+ endif
+ return 0
+endfunction
+
+function! coc#float#get_float_win_list() abort
+ if s:is_vim && exists('*popup_list')
+ return filter(popup_list(), 'popup_getpos(v:val)["visible"]')
+ elseif has('nvim') && exists('*nvim_win_get_config')
+ let res = []
+ for i in range(1, winnr('$'))
+ let id = win_getid(i)
+ let config = nvim_win_get_config(id)
+ " ignore border & button window
+ if (!empty(config) && config['focusable'] == v:true && !empty(config['relative']))
+ if !getwinvar(id, 'button', 0)
+ call add(res, id)
+ endif
+ endif
+ endfor
+ return res
+ endif
+ return []
+endfunction
+
+" Check if a float window is scrollable
+function! coc#float#scrollable(winid) abort
+ let bufnr = winbufnr(a:winid)
+ if bufnr == -1
+ return 0
+ endif
+ if s:is_vim
+ let pos = popup_getpos(a:winid)
+ " scrollbar enabled
+ if get(popup_getoptions(a:winid), 'scrollbar', 0)
+ return get(pos, 'scrollbar', 0)
+ endif
+ let ch = coc#float#content_height(bufnr, pos['core_width'], getwinvar(a:winid, '&wrap'))
+ return ch > pos['core_height']
+ else
+ let height = nvim_win_get_height(a:winid)
+ let width = nvim_win_get_width(a:winid)
+ if width > 1 && getwinvar(a:winid, '&foldcolumn', 0)
+ " since we use foldcolumn for left pading
+ let width = width - 1
+ endif
+ let ch = coc#float#content_height(bufnr, width, getwinvar(a:winid, '&wrap'))
+ return ch > height
+ endif
+endfunction
+
+function! coc#float#has_scroll() abort
+ let win_ids = filter(coc#float#get_float_win_list(), 'coc#float#scrollable(v:val)')
+ return !empty(win_ids)
+endfunction
+
+function! coc#float#scroll(forward, ...)
+ if !has('nvim-0.4.3') && !has('patch-8.2.0750')
+ throw 'coc#float#scroll() requires nvim >= 0.4.3 or vim >= 8.2.0750'
+ endif
+ let amount = get(a:, 1, 0)
+ let win_ids = filter(coc#float#get_float_win_list(), 'coc#float#scrollable(v:val)')
+ if empty(win_ids)
+ return ''
+ endif
+ if has('nvim')
+ call timer_start(10, { -> s:scroll_nvim(win_ids, a:forward, amount)})
+ else
+ call timer_start(10, { -> s:scroll_vim(win_ids, a:forward, amount)})
+ endif
+ return mode() =~ '^i' ? "" : "\"
+endfunction
+
+function! s:scroll_nvim(win_ids, forward, amount) abort
+ let curr = win_getid()
+ for id in a:win_ids
+ if nvim_win_is_valid(id)
+ let wrapped = 0
+ let width = nvim_win_get_width(id)
+ if getwinvar(id, '&wrap', 0)
+ if width > 1 && getwinvar(id, '&foldcolumn', 0)
+ let width = width - 1
+ endif
+ for line in nvim_buf_get_lines(winbufnr(id), 0, -1, v:false)
+ if strdisplaywidth(line) > width
+ let wrapped = 1
+ break
+ endif
+ endfor
+ endif
+ noa call win_gotoid(id)
+ let height = nvim_win_get_height(id)
+ let firstline = line('w0')
+ let lastline = line('w$')
+ let linecount = line('$')
+ let delta = a:amount ? a:amount : max([1, height - 1])
+ if a:forward
+ if lastline == linecount && strdisplaywidth(line('$')) <= width
+ continue
+ endif
+ if !a:amount && firstline != lastline
+ execute 'noa normal! Lzt'
+ else
+ execute 'noa normal! H'.delta.'jzt'
+ endif
+ let lnum = line('.')
+ while lnum < linecount && line('w0') == firstline && line('w$') == lastline
+ execute 'noa normal! jzt'
+ let lnum = lnum + 1
+ endwhile
+ else
+ if !a:amount && firstline != lastline
+ execute 'noa normal! Hzb'
+ else
+ execute 'noa normal! L'.delta.'kzb'
+ endif
+ let lnum = line('.')
+ while lnum > 1 && line('w0') == firstline && line('w$') == lastline
+ execute 'noa normal! kzb'
+ let lnum = lnum - 1
+ endwhile
+ endif
+ call coc#float#nvim_scrollbar(id)
+ endif
+ endfor
+ noa call win_gotoid(curr)
+ redraw
+endfunction
+
+function! s:scroll_vim(win_ids, forward, amount) abort
+ for id in a:win_ids
+ if s:popup_visible(id)
+ let pos = popup_getpos(id)
+ let bufnr = winbufnr(id)
+ let linecount = get(getbufinfo(bufnr)[0], 'linecount', 0)
+ " for forward use last line (or last line + 1) as first line
+ if a:forward
+ if pos['firstline'] == pos['lastline']
+ call popup_setoptions(id, {'firstline': min([pos['firstline'] + 1, linecount])})
+ else
+ if pos['lastline'] == linecount
+ let win_width = pos['core_width']
+ let text = getbufline(bufnr, '$')[0]
+ if strdisplaywidth(text) <= win_width
+ " last line shown
+ return
+ endif
+ endif
+ let lnum = a:amount ? min([linecount, pos['firstline'] + a:amount]) : pos['lastline']
+ call popup_setoptions(id, {'firstline': lnum})
+ endif
+ else
+ if pos['firstline'] == 1
+ call win_execute(id, 'normal! gg0')
+ return
+ endif
+ " we could only change firstline
+ " iterate lines before last lines to fill content height - 1
+ let total_height = a:amount ? min([a:amount, pos['core_height']]) : pos['core_height'] - 1
+ if total_height == 0
+ call popup_setoptions(id, {'firstline': pos['firstline'] - 1})
+ else
+ let lines = getbufline(bufnr, 1, '$')
+ let curr = pos['firstline'] - 1
+ let width = pos['core_width']
+ let used = 0
+ while v:true
+ if curr == 1
+ break
+ endif
+ let w = max([1, strdisplaywidth(lines[curr - 1])])
+ let used += float2nr(ceil(str2float(string(w))/width))
+ if used > total_height
+ let curr = curr == pos['firstline'] -1 ? curr : curr + 1
+ break
+ elseif used == total_height
+ break
+ endif
+ let curr = curr - 1
+ endwhile
+ call popup_setoptions(id, {'firstline': curr})
+ endif
+ endif
+ endif
+ endfor
+ redraw
+endfunction
+
+function! s:popup_visible(id) abort
+ let pos = popup_getpos(a:id)
+ if !empty(pos) && get(pos, 'visible', 0)
+ return 1
+ endif
+ return 0
+endfunction
+
+function! s:convert_config_nvim(config) abort
+ let result = coc#helper#dict_omit(a:config, ['title', 'border', 'cursorline', 'autohide', 'close'])
+ let border = get(a:config, 'border', [])
+ if !s:empty_border(border)
+ if result['relative'] ==# 'cursor' && result['row'] < 0
+ " move top when has bottom border
+ if get(border, 2, 0)
+ let result['row'] = result['row'] - 1
+ endif
+ else
+ " move down when has top border
+ if get(border, 0, 0)
+ let result['row'] = result['row'] + 1
+ endif
+ endif
+ " move right when has left border
+ if get(border, 3, 0)
+ let result['col'] = result['col'] + 1
+ endif
+ let result['width'] = result['width'] + 1 - get(border,3, 0)
+ else
+ let result['width'] = result['width'] + 1
+ endif
+ return result
+endfunction
+
+" Close windows that could auto hide
+function! coc#float#close_auto_hide_wins(...) abort
+ let winids = coc#float#get_float_win_list()
+ let except = get(a:, 1, 0)
+ for id in winids
+ if except && id == except
+ continue
+ endif
+ if getwinvar(id, 'autohide', 0)
+ call coc#float#close(id)
+ endif
+ endfor
+endfunction
+
+" neovim only
+function! coc#float#nvim_close_btn(config, winid, close, border, related) abort
+ if !a:close
+ return
+ endif
+ let config = {
+ \ 'relative': a:config['relative'],
+ \ 'width': 1,
+ \ 'height': 1,
+ \ 'row': get(a:border, 0, 0) ? a:config['row'] - 1 : a:config['row'],
+ \ 'col': a:config['col'] + a:config['width'],
+ \ 'focusable': v:true,
+ \ 'style': 'minimal',
+ \ }
+ noa let bufnr = nvim_create_buf(v:false, v:true)
+ call setbufvar(bufnr, '&bufhidden', 'wipe')
+ call nvim_buf_set_lines(bufnr, 0, -1, v:false, ['X'])
+ let winid = nvim_open_win(bufnr, 0, config)
+ " map for winid & close_winid
+ if winid
+ call setwinvar(winid, 'button', 1)
+ call setwinvar(a:winid, 'close_winid', winid)
+ call setwinvar(winid, '&winhl', 'Normal:CocFloating,NormalNC:CocFloating')
+ call add(a:related, winid)
+ endif
+endfunction
+
+function! coc#float#nvim_check_close(winid) abort
+ let target = getwinvar(a:winid, 'target_winid', 0)
+ if target
+ call coc#float#close(target)
+ endif
+endfunction
+
+" Create padding window by config of current window & border config
+function! coc#float#nvim_right_pad(config, border, related) abort
+ " Check right border
+ if !empty(a:border) && get(a:border, 1, 0)
+ return
+ endif
+ let config = {
+ \ 'relative': a:config['relative'],
+ \ 'width': 1,
+ \ 'height': a:config['height'],
+ \ 'row': a:config['row'],
+ \ 'col': a:config['col'] + a:config['width'],
+ \ 'focusable': v:false,
+ \ 'style': 'minimal',
+ \ }
+ noa let bufnr = nvim_create_buf(v:false, v:true)
+ call setbufvar(bufnr, '&bufhidden', 'wipe')
+ call nvim_buf_set_lines(bufnr, 0, -1, v:false, repeat([' '], a:config['height']))
+ let winid = nvim_open_win(bufnr, 0, config)
+ if winid
+ call setwinvar(winid, 'ispad', 1)
+ call setwinvar(winid, '&winhl', 'Normal:CocFloating,NormalNC:CocFloating')
+ call add(a:related, winid)
+ endif
+endfunction
+
+function! coc#float#content_height(bufnr, width, wrap) abort
+ if !bufloaded(a:bufnr)
+ return 0
+ endif
+ if !a:wrap
+ return has('nvim') ? nvim_buf_line_count(a:bufnr) : len(getbufline(a:bufnr, 1, '$'))
+ endif
+ let lines = has('nvim') ? nvim_buf_get_lines(a:bufnr, 0, -1, 0) : getbufline(a:bufnr, 1, '$')
+ let total = 0
+ for line in lines
+ let dw = max([1, strdisplaywidth(line)])
+ let total += float2nr(ceil(str2float(string(dw))/a:width))
+ endfor
+ return total
+endfunction
+
+function! s:add_related(winid, target) abort
+ let arr = getwinvar(a:target, 'related', [])
+ if index(arr, a:winid) >= 0
+ return
+ endif
+ call add(arr, a:winid)
+ call setwinvar(a:target, 'related', arr)
+endfunction
+
+function! coc#float#nvim_refresh_scrollbar() abort
+ let id = getwinvar(win_getid(), 'scrollbar', 0)
+ if coc#float#valid(id)
+ call coc#float#nvim_scrollbar(win_getid())
+ endif
+endfunction
+
+" Close related windows for neovim.
+function! coc#float#nvim_close_related(winid) abort
+ if !has('nvim') || !a:winid
+ return
+ endif
+ let winids = getwinvar(a:winid, 'related', [])
+ if !empty(winids)
+ call nvim_win_del_var(a:winid, 'related')
+ endif
+ for id in winids
+ if nvim_win_is_valid(id) && id != a:winid
+ call nvim_win_close(id, 1)
+ endif
+ endfor
+endfunction
+
+function! coc#float#nvim_create_related(winid, config, opts) abort
+ let related = []
+ call coc#float#nvim_close_btn(a:config, a:winid, get(a:opts, 'close', 0), get(a:opts, 'border', []), related)
+ call coc#float#nvim_border_win(a:config, get(a:opts, 'border', []), get(a:opts, 'title', ''), related)
+ call coc#float#nvim_right_pad(a:config, get(a:opts, 'border', []), related)
+ for id in related
+ call setwinvar(id, 'target_winid', a:winid)
+ endfor
+ call setwinvar(a:winid, 'related', related)
+endfunction
+
+" Create scrollbar for winid
+" Need called on create, config, buffer change, scrolled
+function! coc#float#nvim_scrollbar(winid) abort
+ if !has('nvim-0.4.3')
+ return
+ endif
+ if a:winid == 0 || !nvim_win_is_valid(a:winid) || getwinvar(a:winid, 'button', 0)
+ return
+ endif
+ let config = nvim_win_get_config(a:winid)
+ " ignore border & button window
+ if (!get(config, 'focusable', v:false) || empty(get(config, 'relative', '')))
+ return
+ endif
+ let [row, column] = nvim_win_get_position(a:winid)
+ let width = nvim_win_get_width(a:winid)
+ let height = nvim_win_get_height(a:winid)
+ let bufnr = winbufnr(a:winid)
+ let cw = getwinvar(a:winid, '&foldcolumn', 0) ? width - 1 : width
+ let ch = coc#float#content_height(bufnr, cw, getwinvar(a:winid, '&wrap'))
+ let close_winid = getwinvar(a:winid, 'close_winid', 0)
+ let border = getwinvar(a:winid, 'border', [])
+ let move_down = close_winid && !get(border, 0, 0)
+ if move_down
+ let height = height - 1
+ if height == 0
+ return
+ endif
+ endif
+ let id = 0
+ if nvim_win_is_valid(getwinvar(a:winid, 'scrollbar', 0))
+ let id = getwinvar(a:winid, 'scrollbar', 0)
+ endif
+ if ch <= height || height == 0
+ " no scrollbar, remove exists
+ if id
+ call nvim_win_del_var(a:winid, 'scrollbar')
+ call coc#float#close(id)
+ endif
+ return
+ endif
+ if height == 0
+ return
+ endif
+ if id && bufloaded(winbufnr(id))
+ let sbuf = winbufnr(id)
+ else
+ noa let sbuf = nvim_create_buf(v:false, v:true)
+ call setbufvar(sbuf, '&bufhidden', 'wipe')
+ endif
+ call nvim_buf_set_lines(sbuf, 0, -1, v:false, repeat([' '], height))
+ let opts = {
+ \ 'row': move_down ? row + 1 : row,
+ \ 'col': column + width,
+ \ 'relative': 'editor',
+ \ 'width': 1,
+ \ 'height': height,
+ \ 'focusable': v:false,
+ \ 'style': 'minimal',
+ \ }
+ if id
+ call nvim_win_set_config(id, opts)
+ else
+ let id = nvim_open_win(sbuf, 0 , opts)
+ call setwinvar(id, 'isscrollbar', 1)
+ call setwinvar(id, 'target_winid', a:winid)
+ endif
+ let thumb_height = max([1, float2nr(floor(height * (height + 0.0)/ch))])
+ let curr = win_getid()
+ if curr != a:winid
+ noa call win_gotoid(a:winid)
+ endif
+ let firstline = line('w0')
+ let lastline = line('w$')
+ let linecount = line('$')
+ if firstline == 1
+ let start = 0
+ elseif lastline == linecount
+ let start = height - thumb_height
+ else
+ let start = max([1, float2nr(round((height - thumb_height + 0.0)*(firstline - 1.0)/(ch - height)))])
+ endif
+ if curr != a:winid
+ noa call win_gotoid(curr)
+ endif
+ " add highlights
+ call nvim_buf_clear_namespace(sbuf, s:scrollbar_ns, 0, -1)
+ for idx in range(0, height - 1)
+ if idx >= start && idx < start + thumb_height
+ call nvim_buf_add_highlight(sbuf, s:scrollbar_ns, 'PmenuThumb', idx, 0, 1)
+ else
+ call nvim_buf_add_highlight(sbuf, s:scrollbar_ns, 'PmenuSbar', idx, 0, 1)
+ endif
+ endfor
+ " create scrollbar outside window
+ call setwinvar(a:winid, 'scrollbar', id)
+ call s:add_related(id, a:winid)
+endfunction
+
+function! coc#float#nvim_check_related() abort
+ if !has('nvim')
+ return
+ endif
+ let invalids = []
+ for i in range(1, winnr('$'))
+ let id = win_getid(i)
+ let target = getwinvar(id, 'target_winid', 0)
+ if target && !nvim_win_is_valid(target)
+ call add(invalids, id)
+ endif
+ endfor
+ for id in invalids
+ noa call nvim_win_close(id, 1)
+ endfor
+endfunction
+
+" Dimension of window with lines relative to cursor
+" Width & height excludes border & padding
+function! coc#float#get_config_cursor(lines, config) abort
+ let preferTop = get(a:config, 'preferTop', 0)
+ let title = get(a:config, 'title', '')
+ let border = get(a:config, 'border', [0, 0, 0, 0])
+ if s:empty_border(border) && len(title)
+ let border = [1, 1, 1, 1]
+ endif
+ let bh = get(border, 0, 0) + get(border, 2, 0)
+ let vh = &lines - &cmdheight - 1
+ if vh <= 0
+ return v:null
+ endif
+ let maxWidth = min([get(a:config, 'maxWidth', 80), &columns - 1])
+ if maxWidth < 3
+ return v:null
+ endif
+ let maxHeight = min([get(a:config, 'maxHeight', 80), vh])
+ let ch = 0
+ let width = min([40, strdisplaywidth(title)]) + 3
+ for line in a:lines
+ let dw = max([1, strdisplaywidth(line)])
+ let width = max([width, dw + 2])
+ let ch += float2nr(ceil(str2float(string(dw))/(maxWidth - 2)))
+ endfor
+ let width = min([maxWidth, width])
+ let [lineIdx, colIdx] = s:win_position()
+ " How much we should move left
+ let offsetX = min([get(a:config, 'offsetX', 0), colIdx])
+ let showTop = 0
+ let hb = vh - lineIdx -1
+ if lineIdx > bh + 2 && (preferTop || (lineIdx > hb && hb < ch + bh))
+ let showTop = 1
+ endif
+ let height = min([maxHeight, ch + bh, showTop ? lineIdx - 1 : hb])
+ if height <= bh
+ return v:null
+ endif
+ let col = - max([offsetX, colIdx - (&columns - 1 - width)])
+ let row = showTop ? - height : 1
+ return {
+ \ 'row': row,
+ \ 'col': col,
+ \ 'width': width - 2,
+ \ 'height': height - bh
+ \ }
+endfunction
+
+function! coc#float#get_config_pum(lines, pumconfig, maxwidth) abort
+ if !pumvisible()
+ return v:null
+ endif
+ let pw = a:pumconfig['width'] + get(a:pumconfig, 'scrollbar', 0)
+ let rp = &columns - a:pumconfig['col'] - pw
+ let showRight = a:pumconfig['col'] > rp ? 0 : 1
+ let maxWidth = showRight ? min([rp - 1, a:maxwidth]) : min([a:pumconfig['col'] - 1, a:maxwidth])
+ let maxHeight = &lines - a:pumconfig['row'] - &cmdheight - 1
+ if maxWidth <= 2 || maxHeight < 1
+ return v:null
+ endif
+ let ch = 0
+ let width = 0
+ for line in a:lines
+ let dw = max([1, strdisplaywidth(line)])
+ let width = max([width, dw + 2])
+ let ch += float2nr(ceil(str2float(string(dw))/(maxWidth - 2)))
+ endfor
+ let width = min([maxWidth, width])
+ let height = min([maxHeight, ch])
+ return {
+ \ 'col': showRight ? a:pumconfig['col'] + pw : a:pumconfig['col'] - width - 1,
+ \ 'row': a:pumconfig['row'],
+ \ 'height': height,
+ \ 'width': width - 2 + (s:is_vim && ch > height ? -1 : 0),
+ \ 'relative': 'editor'
+ \ }
+endfunction
+
+function! s:empty_border(border) abort
+ if empty(a:border)
+ return 1
+ endif
+ if a:border[0] == 0 && a:border[1] == 0 && a:border[2] == 0 && a:border[3] == 0
+ return 1
+ endif
+ return 0
+endfunction
diff --git a/pack/acp/start/coc.nvim/autoload/coc/helper.vim b/pack/acp/start/coc.nvim/autoload/coc/helper.vim
new file mode 100644
index 0000000..ae7eab2
--- /dev/null
+++ b/pack/acp/start/coc.nvim/autoload/coc/helper.vim
@@ -0,0 +1,56 @@
+" Helper methods for viml
+
+" insert inserted to line at position, use ... when result is too long
+" line should only contains character has strwidth equals 1
+function! coc#helper#str_compose(line, position, inserted) abort
+ let width = strwidth(a:line)
+ let text = a:inserted
+ let res = a:line
+ let need_truncate = a:position + strwidth(text) + 1 > width
+ if need_truncate
+ let remain = width - a:position - 3
+ if remain < 2
+ " use text for full line, use first & end of a:line, ignore position
+ let res = strcharpart(a:line, 0, 1)
+ let w = strwidth(res)
+ for i in range(strchars(text))
+ let c = strcharpart(text, i, 1)
+ let a = strwidth(c)
+ if w + a <= width - 1
+ let w = w + a
+ let res = res.c
+ endif
+ endfor
+ let res = res.strcharpart(a:line, w)
+ else
+ let res = strcharpart(a:line, 0, a:position)
+ let w = strwidth(res)
+ for i in range(strchars(text))
+ let c = strcharpart(text, i, 1)
+ let a = strwidth(c)
+ if w + a <= width - 3
+ let w = w + a
+ let res = res.c
+ endif
+ endfor
+ let res = res.'..'
+ let w = w + 2
+ let res = res.strcharpart(a:line, w)
+ endif
+ else
+ let first = strcharpart(a:line, 0, a:position)
+ let res = first.text.strcharpart(a:line, a:position + strwidth(text))
+ endif
+ return res
+endfunction
+
+" Return new dict with keys removed
+function! coc#helper#dict_omit(dict, keys) abort
+ let res = {}
+ for key in keys(a:dict)
+ if index(a:keys, key) == -1
+ let res[key] = a:dict[key]
+ endif
+ endfor
+ return res
+endfunction
diff --git a/pack/acp/start/coc.nvim/autoload/coc/list.vim b/pack/acp/start/coc.nvim/autoload/coc/list.vim
new file mode 100644
index 0000000..33eb067
--- /dev/null
+++ b/pack/acp/start/coc.nvim/autoload/coc/list.vim
@@ -0,0 +1,292 @@
+let s:activated = 0
+let s:is_vim = !has('nvim')
+let s:saved_ve = &t_ve
+let s:saved_cursor = &guicursor
+let s:gui = has('gui_running') || has('nvim')
+
+function! coc#list#get_chars()
+ return {
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '' : "\",
+ \ '' : "\",
+ \ '' : "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '<2-LeftMouse>': "\<2-LeftMouse>",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '': "\",
+ \ '