Clean up Vim, make much simpler
This commit is contained in:
parent
0fc2aa3f1e
commit
5f21cf445c
301 changed files with 0 additions and 61555 deletions
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"clangd.arguments": [
|
|
||||||
"--header-insertion=iwyu",
|
|
||||||
"--header-insertion-decorators",
|
|
||||||
"--suggest-missing-includes",
|
|
||||||
"--clang-tidy"
|
|
||||||
],
|
|
||||||
"coc.preferences.jumpCommand": "vsplit",
|
|
||||||
"powershell.integratedConsole.showOnStartup": false
|
|
||||||
}
|
|
13
pack/acp/opt/coc.nvim/.gitignore
vendored
13
pack/acp/opt/coc.nvim/.gitignore
vendored
|
@ -1,13 +0,0 @@
|
||||||
lib
|
|
||||||
*.map
|
|
||||||
coverage
|
|
||||||
__pycache__
|
|
||||||
.pyc
|
|
||||||
.log
|
|
||||||
src
|
|
||||||
publish.sh
|
|
||||||
doc/tags
|
|
||||||
doc/tags-cn
|
|
||||||
node_modules
|
|
||||||
src/__tests__/tags
|
|
||||||
typings
|
|
|
@ -1,7 +0,0 @@
|
||||||
Copyright 2018-2018 by Qiming Zhao <chemzqm@gmail.com>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.
|
|
|
@ -1,845 +0,0 @@
|
||||||
<p align="center">
|
|
||||||
<a href="https://www.vim.org/scripts/script.php?script_id=5779">
|
|
||||||
<img alt="Logo" src="https://alfs.chigua.cn/dianyou/data/platform/default/20220525/coc.png" height="240" />
|
|
||||||
</a>
|
|
||||||
<p align="center">Make your Vim/Neovim as smart as VSCode</p>
|
|
||||||
<p align="center">
|
|
||||||
<a href="LICENSE.md"><img alt="Software License" src="https://img.shields.io/badge/license-Anti%20996-brightgreen.svg?style=flat-square"></a>
|
|
||||||
<a href="https://github.com/neoclide/coc.nvim/actions"><img alt="Actions" src="https://img.shields.io/github/actions/workflow/status/neoclide/coc.nvim/ci.yml?style=flat-square&branch=master"></a>
|
|
||||||
<a href="https://codecov.io/gh/neoclide/coc.nvim"><img alt="Codecov Coverage Status" src="https://img.shields.io/codecov/c/github/neoclide/coc.nvim.svg?style=flat-square"></a>
|
|
||||||
<a href="doc/coc.txt"><img alt="Doc" src="https://img.shields.io/badge/doc-%3Ah%20coc.txt-brightgreen.svg?style=flat-square"></a>
|
|
||||||
<a href="https://gitter.im/neoclide/coc.nvim"><img alt="Gitter" src="https://img.shields.io/gitter/room/neoclide/coc.nvim.svg?style=flat-square"></a>
|
|
||||||
</p>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<img alt="Gif" src="https://alfs.chigua.cn/dianyou/data/platform/default/20220801/2022-08-01%2002-14-03.2022-08-01%2002_15_16.gif" width="60%" />
|
|
||||||
|
|
||||||
_Custom popup menu with snippet support_
|
|
||||||
|
|
||||||
## Why?
|
|
||||||
|
|
||||||
- 🚀 **Fast**: separated NodeJS process that does not slow down Vim most of the time.
|
|
||||||
- 💎 **Reliable**: typed language, tested with CI.
|
|
||||||
- 🌟 **Featured**: all LSP 3.16 features are supported, see `:h coc-lsp`.
|
|
||||||
- ❤️ **Flexible**: [configured like VS Code](https://github.com/neoclide/coc.nvim/wiki/Using-the-configuration-file), [Coc extensions function similarly to VS Code extensions](https://github.com/neoclide/coc.nvim/wiki/Using-coc-extensions)
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
Make sure use Vim >= 8.1.1719 or Neovim >= 0.4.0.
|
|
||||||
|
|
||||||
Install [nodejs](https://nodejs.org/en/download/) >= 14.14:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -sL install-node.vercel.app/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', {'branch': 'master', '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 the 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
|
|
||||||
command like`:verbose imap <tab>` to make sure that your keymap has taken effect.
|
|
||||||
|
|
||||||
```vim
|
|
||||||
|
|
||||||
" May need for Vim (not Neovim) since coc.nvim calculates byte offset by count
|
|
||||||
" utf-8 byte sequence
|
|
||||||
set encoding=utf-8
|
|
||||||
" Some servers have issues with backup files, see #649
|
|
||||||
set nobackup
|
|
||||||
set nowritebackup
|
|
||||||
|
|
||||||
" Having longer updatetime (default is 4000 ms = 4s) leads to noticeable
|
|
||||||
" delays and poor user experience
|
|
||||||
set updatetime=300
|
|
||||||
|
|
||||||
" Always show the signcolumn, otherwise it would shift the text each time
|
|
||||||
" diagnostics appear/become resolved
|
|
||||||
set signcolumn=yes
|
|
||||||
|
|
||||||
" Use tab for trigger completion with characters ahead and navigate
|
|
||||||
" NOTE: There's always complete item selected by default, you may want to enable
|
|
||||||
" no select by `"suggest.noselect": true` in your configuration file
|
|
||||||
" NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
|
|
||||||
" other plugin before putting this into your config
|
|
||||||
inoremap <silent><expr> <TAB>
|
|
||||||
\ coc#pum#visible() ? coc#pum#next(1) :
|
|
||||||
\ CheckBackspace() ? "\<Tab>" :
|
|
||||||
\ coc#refresh()
|
|
||||||
inoremap <expr><S-TAB> coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"
|
|
||||||
|
|
||||||
" Make <CR> to accept selected completion item or notify coc.nvim to format
|
|
||||||
" <C-g>u breaks current undo, please make your own choice
|
|
||||||
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
|
|
||||||
\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
|
|
||||||
|
|
||||||
function! CheckBackspace() abort
|
|
||||||
let col = col('.') - 1
|
|
||||||
return !col || getline('.')[col - 1] =~# '\s'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Use <c-space> to trigger completion
|
|
||||||
if has('nvim')
|
|
||||||
inoremap <silent><expr> <c-space> coc#refresh()
|
|
||||||
else
|
|
||||||
inoremap <silent><expr> <c-@> coc#refresh()
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Use `[g` and `]g` to navigate diagnostics
|
|
||||||
" Use `:CocDiagnostics` to get all diagnostics of current buffer in location list
|
|
||||||
nmap <silent> [g <Plug>(coc-diagnostic-prev)
|
|
||||||
nmap <silent> ]g <Plug>(coc-diagnostic-next)
|
|
||||||
|
|
||||||
" GoTo code navigation
|
|
||||||
nmap <silent> gd <Plug>(coc-definition)
|
|
||||||
nmap <silent> gy <Plug>(coc-type-definition)
|
|
||||||
nmap <silent> gi <Plug>(coc-implementation)
|
|
||||||
nmap <silent> gr <Plug>(coc-references)
|
|
||||||
|
|
||||||
" Use K to show documentation in preview window
|
|
||||||
nnoremap <silent> K :call ShowDocumentation()<CR>
|
|
||||||
|
|
||||||
function! ShowDocumentation()
|
|
||||||
if CocAction('hasProvider', 'hover')
|
|
||||||
call CocActionAsync('doHover')
|
|
||||||
else
|
|
||||||
call feedkeys('K', 'in')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Highlight the symbol and its references when holding the cursor
|
|
||||||
autocmd CursorHold * silent call CocActionAsync('highlight')
|
|
||||||
|
|
||||||
" Symbol renaming
|
|
||||||
nmap <leader>rn <Plug>(coc-rename)
|
|
||||||
|
|
||||||
" Formatting selected code
|
|
||||||
xmap <leader>f <Plug>(coc-format-selected)
|
|
||||||
nmap <leader>f <Plug>(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 code actions to the selected code block
|
|
||||||
" Example: `<leader>aap` for current paragraph
|
|
||||||
xmap <leader>a <Plug>(coc-codeaction-selected)
|
|
||||||
nmap <leader>a <Plug>(coc-codeaction-selected)
|
|
||||||
|
|
||||||
" Remap keys for applying code actions at the cursor position
|
|
||||||
nmap <leader>ac <Plug>(coc-codeaction-cursor)
|
|
||||||
" Remap keys for apply code actions affect whole buffer
|
|
||||||
nmap <leader>as <Plug>(coc-codeaction-source)
|
|
||||||
" Apply the most preferred quickfix action to fix diagnostic on the current line
|
|
||||||
nmap <leader>qf <Plug>(coc-fix-current)
|
|
||||||
|
|
||||||
" Remap keys for applying refactor code actions
|
|
||||||
nmap <silent> <leader>re <Plug>(coc-codeaction-refactor)
|
|
||||||
xmap <silent> <leader>r <Plug>(coc-codeaction-refactor-selected)
|
|
||||||
nmap <silent> <leader>r <Plug>(coc-codeaction-refactor-selected)
|
|
||||||
|
|
||||||
" Run the Code Lens action on the current line
|
|
||||||
nmap <leader>cl <Plug>(coc-codelens-action)
|
|
||||||
|
|
||||||
" Map function and class text objects
|
|
||||||
" NOTE: Requires 'textDocument.documentSymbol' support from the language server
|
|
||||||
xmap if <Plug>(coc-funcobj-i)
|
|
||||||
omap if <Plug>(coc-funcobj-i)
|
|
||||||
xmap af <Plug>(coc-funcobj-a)
|
|
||||||
omap af <Plug>(coc-funcobj-a)
|
|
||||||
xmap ic <Plug>(coc-classobj-i)
|
|
||||||
omap ic <Plug>(coc-classobj-i)
|
|
||||||
xmap ac <Plug>(coc-classobj-a)
|
|
||||||
omap ac <Plug>(coc-classobj-a)
|
|
||||||
|
|
||||||
" Remap <C-f> and <C-b> to scroll float windows/popups
|
|
||||||
if has('nvim-0.4.0') || has('patch-8.2.0750')
|
|
||||||
nnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
|
|
||||||
nnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
|
|
||||||
inoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(1)\<cr>" : "\<Right>"
|
|
||||||
inoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? "\<c-r>=coc#float#scroll(0)\<cr>" : "\<Left>"
|
|
||||||
vnoremap <silent><nowait><expr> <C-f> coc#float#has_scroll() ? coc#float#scroll(1) : "\<C-f>"
|
|
||||||
vnoremap <silent><nowait><expr> <C-b> coc#float#has_scroll() ? coc#float#scroll(0) : "\<C-b>"
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Use CTRL-S for selections ranges
|
|
||||||
" Requires 'textDocument/selectionRange' support of language server
|
|
||||||
nmap <silent> <C-s> <Plug>(coc-range-select)
|
|
||||||
xmap <silent> <C-s> <Plug>(coc-range-select)
|
|
||||||
|
|
||||||
" Add `:Format` command to format current buffer
|
|
||||||
command! -nargs=0 Format :call CocActionAsync('format')
|
|
||||||
|
|
||||||
" Add `:Fold` command to fold current buffer
|
|
||||||
command! -nargs=? Fold :call CocAction('fold', <f-args>)
|
|
||||||
|
|
||||||
" Add `:OR` command for organize imports of the current buffer
|
|
||||||
command! -nargs=0 OR :call CocActionAsync('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 <silent><nowait> <space>a :<C-u>CocList diagnostics<cr>
|
|
||||||
" Manage extensions
|
|
||||||
nnoremap <silent><nowait> <space>e :<C-u>CocList extensions<cr>
|
|
||||||
" Show commands
|
|
||||||
nnoremap <silent><nowait> <space>c :<C-u>CocList commands<cr>
|
|
||||||
" Find symbol of current document
|
|
||||||
nnoremap <silent><nowait> <space>o :<C-u>CocList outline<cr>
|
|
||||||
" Search workspace symbols
|
|
||||||
nnoremap <silent><nowait> <space>s :<C-u>CocList -I symbols<cr>
|
|
||||||
" Do default action for next item
|
|
||||||
nnoremap <silent><nowait> <space>j :<C-u>CocNext<CR>
|
|
||||||
" Do default action for previous item
|
|
||||||
nnoremap <silent><nowait> <space>k :<C-u>CocPrev<CR>
|
|
||||||
" Resume latest coc list
|
|
||||||
nnoremap <silent><nowait> <space>p :<C-u>CocListResume<CR>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Example Lua configuration
|
|
||||||
|
|
||||||
NOTE: This only works in Neovim 0.7.0dev+.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
-- Some servers have issues with backup files, see #649
|
|
||||||
vim.opt.backup = false
|
|
||||||
vim.opt.writebackup = false
|
|
||||||
|
|
||||||
-- Having longer updatetime (default is 4000 ms = 4s) leads to noticeable
|
|
||||||
-- delays and poor user experience
|
|
||||||
vim.opt.updatetime = 300
|
|
||||||
|
|
||||||
-- Always show the signcolumn, otherwise it would shift the text each time
|
|
||||||
-- diagnostics appeared/became resolved
|
|
||||||
vim.opt.signcolumn = "yes"
|
|
||||||
|
|
||||||
local keyset = vim.keymap.set
|
|
||||||
-- Autocomplete
|
|
||||||
function _G.check_back_space()
|
|
||||||
local col = vim.fn.col('.') - 1
|
|
||||||
return col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') ~= nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Use Tab for trigger completion with characters ahead and navigate
|
|
||||||
-- NOTE: There's always a completion item selected by default, you may want to enable
|
|
||||||
-- no select by setting `"suggest.noselect": true` in your configuration file
|
|
||||||
-- NOTE: Use command ':verbose imap <tab>' to make sure Tab is not mapped by
|
|
||||||
-- other plugins before putting this into your config
|
|
||||||
local opts = {silent = true, noremap = true, expr = true, replace_keycodes = false}
|
|
||||||
keyset("i", "<TAB>", 'coc#pum#visible() ? coc#pum#next(1) : v:lua.check_back_space() ? "<TAB>" : coc#refresh()', opts)
|
|
||||||
keyset("i", "<S-TAB>", [[coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"]], opts)
|
|
||||||
|
|
||||||
-- Make <CR> to accept selected completion item or notify coc.nvim to format
|
|
||||||
-- <C-g>u breaks current undo, please make your own choice
|
|
||||||
keyset("i", "<cr>", [[coc#pum#visible() ? coc#pum#confirm() : "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"]], opts)
|
|
||||||
|
|
||||||
-- Use <c-j> to trigger snippets
|
|
||||||
keyset("i", "<c-j>", "<Plug>(coc-snippets-expand-jump)")
|
|
||||||
-- Use <c-space> to trigger completion
|
|
||||||
keyset("i", "<c-space>", "coc#refresh()", {silent = true, expr = true})
|
|
||||||
|
|
||||||
-- Use `[g` and `]g` to navigate diagnostics
|
|
||||||
-- Use `:CocDiagnostics` to get all diagnostics of current buffer in location list
|
|
||||||
keyset("n", "[g", "<Plug>(coc-diagnostic-prev)", {silent = true})
|
|
||||||
keyset("n", "]g", "<Plug>(coc-diagnostic-next)", {silent = true})
|
|
||||||
|
|
||||||
-- GoTo code navigation
|
|
||||||
keyset("n", "gd", "<Plug>(coc-definition)", {silent = true})
|
|
||||||
keyset("n", "gy", "<Plug>(coc-type-definition)", {silent = true})
|
|
||||||
keyset("n", "gi", "<Plug>(coc-implementation)", {silent = true})
|
|
||||||
keyset("n", "gr", "<Plug>(coc-references)", {silent = true})
|
|
||||||
|
|
||||||
|
|
||||||
-- Use K to show documentation in preview window
|
|
||||||
function _G.show_docs()
|
|
||||||
local cw = vim.fn.expand('<cword>')
|
|
||||||
if vim.fn.index({'vim', 'help'}, vim.bo.filetype) >= 0 then
|
|
||||||
vim.api.nvim_command('h ' .. cw)
|
|
||||||
elseif vim.api.nvim_eval('coc#rpc#ready()') then
|
|
||||||
vim.fn.CocActionAsync('doHover')
|
|
||||||
else
|
|
||||||
vim.api.nvim_command('!' .. vim.o.keywordprg .. ' ' .. cw)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
keyset("n", "K", '<CMD>lua _G.show_docs()<CR>', {silent = true})
|
|
||||||
|
|
||||||
|
|
||||||
-- Highlight the symbol and its references on a CursorHold event(cursor is idle)
|
|
||||||
vim.api.nvim_create_augroup("CocGroup", {})
|
|
||||||
vim.api.nvim_create_autocmd("CursorHold", {
|
|
||||||
group = "CocGroup",
|
|
||||||
command = "silent call CocActionAsync('highlight')",
|
|
||||||
desc = "Highlight symbol under cursor on CursorHold"
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
-- Symbol renaming
|
|
||||||
keyset("n", "<leader>rn", "<Plug>(coc-rename)", {silent = true})
|
|
||||||
|
|
||||||
|
|
||||||
-- Formatting selected code
|
|
||||||
keyset("x", "<leader>f", "<Plug>(coc-format-selected)", {silent = true})
|
|
||||||
keyset("n", "<leader>f", "<Plug>(coc-format-selected)", {silent = true})
|
|
||||||
|
|
||||||
|
|
||||||
-- Setup formatexpr specified filetype(s)
|
|
||||||
vim.api.nvim_create_autocmd("FileType", {
|
|
||||||
group = "CocGroup",
|
|
||||||
pattern = "typescript,json",
|
|
||||||
command = "setl formatexpr=CocAction('formatSelected')",
|
|
||||||
desc = "Setup formatexpr specified filetype(s)."
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Update signature help on jump placeholder
|
|
||||||
vim.api.nvim_create_autocmd("User", {
|
|
||||||
group = "CocGroup",
|
|
||||||
pattern = "CocJumpPlaceholder",
|
|
||||||
command = "call CocActionAsync('showSignatureHelp')",
|
|
||||||
desc = "Update signature help on jump placeholder"
|
|
||||||
})
|
|
||||||
|
|
||||||
-- Apply codeAction to the selected region
|
|
||||||
-- Example: `<leader>aap` for current paragraph
|
|
||||||
local opts = {silent = true, nowait = true}
|
|
||||||
keyset("x", "<leader>a", "<Plug>(coc-codeaction-selected)", opts)
|
|
||||||
keyset("n", "<leader>a", "<Plug>(coc-codeaction-selected)", opts)
|
|
||||||
|
|
||||||
-- Remap keys for apply code actions at the cursor position.
|
|
||||||
keyset("n", "<leader>ac", "<Plug>(coc-codeaction-cursor)", opts)
|
|
||||||
-- Remap keys for apply code actions affect whole buffer.
|
|
||||||
keyset("n", "<leader>as", "<Plug>(coc-codeaction-source)", opts)
|
|
||||||
-- Remap keys for applying codeActions to the current buffer
|
|
||||||
keyset("n", "<leader>ac", "<Plug>(coc-codeaction)", opts)
|
|
||||||
-- Apply the most preferred quickfix action on the current line.
|
|
||||||
keyset("n", "<leader>qf", "<Plug>(coc-fix-current)", opts)
|
|
||||||
|
|
||||||
-- Remap keys for apply refactor code actions.
|
|
||||||
keyset("n", "<leader>re", "<Plug>(coc-codeaction-refactor)", { silent = true })
|
|
||||||
keyset("x", "<leader>r", "<Plug>(coc-codeaction-refactor-selected)", { silent = true })
|
|
||||||
keyset("n", "<leader>r", "<Plug>(coc-codeaction-refactor-selected)", { silent = true })
|
|
||||||
|
|
||||||
-- Run the Code Lens actions on the current line
|
|
||||||
keyset("n", "<leader>cl", "<Plug>(coc-codelens-action)", opts)
|
|
||||||
|
|
||||||
|
|
||||||
-- Map function and class text objects
|
|
||||||
-- NOTE: Requires 'textDocument.documentSymbol' support from the language server
|
|
||||||
keyset("x", "if", "<Plug>(coc-funcobj-i)", opts)
|
|
||||||
keyset("o", "if", "<Plug>(coc-funcobj-i)", opts)
|
|
||||||
keyset("x", "af", "<Plug>(coc-funcobj-a)", opts)
|
|
||||||
keyset("o", "af", "<Plug>(coc-funcobj-a)", opts)
|
|
||||||
keyset("x", "ic", "<Plug>(coc-classobj-i)", opts)
|
|
||||||
keyset("o", "ic", "<Plug>(coc-classobj-i)", opts)
|
|
||||||
keyset("x", "ac", "<Plug>(coc-classobj-a)", opts)
|
|
||||||
keyset("o", "ac", "<Plug>(coc-classobj-a)", opts)
|
|
||||||
|
|
||||||
|
|
||||||
-- Remap <C-f> and <C-b> to scroll float windows/popups
|
|
||||||
---@diagnostic disable-next-line: redefined-local
|
|
||||||
local opts = {silent = true, nowait = true, expr = true}
|
|
||||||
keyset("n", "<C-f>", 'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"', opts)
|
|
||||||
keyset("n", "<C-b>", 'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"', opts)
|
|
||||||
keyset("i", "<C-f>",
|
|
||||||
'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(1)<cr>" : "<Right>"', opts)
|
|
||||||
keyset("i", "<C-b>",
|
|
||||||
'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(0)<cr>" : "<Left>"', opts)
|
|
||||||
keyset("v", "<C-f>", 'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"', opts)
|
|
||||||
keyset("v", "<C-b>", 'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"', opts)
|
|
||||||
|
|
||||||
|
|
||||||
-- Use CTRL-S for selections ranges
|
|
||||||
-- Requires 'textDocument/selectionRange' support of language server
|
|
||||||
keyset("n", "<C-s>", "<Plug>(coc-range-select)", {silent = true})
|
|
||||||
keyset("x", "<C-s>", "<Plug>(coc-range-select)", {silent = true})
|
|
||||||
|
|
||||||
|
|
||||||
-- Add `:Format` command to format current buffer
|
|
||||||
vim.api.nvim_create_user_command("Format", "call CocAction('format')", {})
|
|
||||||
|
|
||||||
-- " Add `:Fold` command to fold current buffer
|
|
||||||
vim.api.nvim_create_user_command("Fold", "call CocAction('fold', <f-args>)", {nargs = '?'})
|
|
||||||
|
|
||||||
-- Add `:OR` command for organize imports of the current buffer
|
|
||||||
vim.api.nvim_create_user_command("OR", "call CocActionAsync('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
|
|
||||||
vim.opt.statusline:prepend("%{coc#status()}%{get(b:,'coc_current_function','')}")
|
|
||||||
|
|
||||||
-- Mappings for CoCList
|
|
||||||
-- code actions and coc stuff
|
|
||||||
---@diagnostic disable-next-line: redefined-local
|
|
||||||
local opts = {silent = true, nowait = true}
|
|
||||||
-- Show all diagnostics
|
|
||||||
keyset("n", "<space>a", ":<C-u>CocList diagnostics<cr>", opts)
|
|
||||||
-- Manage extensions
|
|
||||||
keyset("n", "<space>e", ":<C-u>CocList extensions<cr>", opts)
|
|
||||||
-- Show commands
|
|
||||||
keyset("n", "<space>c", ":<C-u>CocList commands<cr>", opts)
|
|
||||||
-- Find symbol of current document
|
|
||||||
keyset("n", "<space>o", ":<C-u>CocList outline<cr>", opts)
|
|
||||||
-- Search workspace symbols
|
|
||||||
keyset("n", "<space>s", ":<C-u>CocList -I symbols<cr>", opts)
|
|
||||||
-- Do default action for next item
|
|
||||||
keyset("n", "<space>j", ":<C-u>CocNext<cr>", opts)
|
|
||||||
-- Do default action for previous item
|
|
||||||
keyset("n", "<space>k", ":<C-u>CocPrev<cr>", opts)
|
|
||||||
-- Resume latest coc list
|
|
||||||
keyset("n", "<space>p", ":<C-u>CocListResume<cr>", opts)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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)
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
Try these steps if you experience problems with coc.nvim:
|
|
||||||
|
|
||||||
- Ensure your Vim version >= 8.0 using `:version`
|
|
||||||
- If a service failed to start, use `:CocInfo` or `:checkhealth` if you use Neovim
|
|
||||||
- Checkout the log of coc.nvim with `:CocOpenLog`
|
|
||||||
- If you have issues with the language server, it's recommended to [checkout
|
|
||||||
the language server output](https://github.com/neoclide/coc.nvim/wiki/Debug-language-server#using-output-channel)
|
|
||||||
|
|
||||||
## Feedback
|
|
||||||
|
|
||||||
- Have a question? Start a discussion on [GitHub Discussions](https://github.com/neoclide/coc.nvim/discussions).
|
|
||||||
- File a bug in [GitHub Issues](https://github.com/neoclide/coc.nvim/issues).
|
|
||||||
- Chat with us on [Gitter](https://gitter.im/neoclide/coc.nvim).
|
|
||||||
- 中文用户请到 [中文 gitter](https://gitter.im/neoclide/coc-cn) 讨论
|
|
||||||
|
|
||||||
## Backers
|
|
||||||
|
|
||||||
[Become a backer](https://opencollective.com/cocnvim#backer) and get your image on our README on GitHub with a link to your site.
|
|
||||||
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/0/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/0/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/1/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/1/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/2/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/2/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/3/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/3/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/4/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/4/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/5/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/5/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/6/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/6/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/7/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/7/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/8/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/8/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/9/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/9/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/10/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/10/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/11/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/11/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/12/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/12/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/13/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/13/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/14/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/14/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/15/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/15/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/16/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/16/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/17/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/17/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/18/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/18/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/19/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/19/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/20/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/20/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/21/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/21/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/22/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/22/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/23/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/23/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/24/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/24/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/25/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/25/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/26/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/26/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/27/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/27/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/28/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/28/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/29/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/29/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/30/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/30/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/31/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/31/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/32/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/32/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/33/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/33/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/34/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/34/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/35/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/35/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/36/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/36/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/37/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/37/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/38/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/38/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/39/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/39/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/40/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/40/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/41/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/41/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/42/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/42/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/43/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/43/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/44/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/44/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/45/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/45/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/46/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/46/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/47/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/47/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/48/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/48/avatar.svg?requireActive=false"></a>
|
|
||||||
<a href="https://opencollective.com/cocnvim/backer/49/website?requireActive=false" target="_blank"><img src="https://opencollective.com/cocnvim/backer/49/avatar.svg?requireActive=false"></a>
|
|
||||||
|
|
||||||
<a href="https://opencollective.com/cocnvim#backer" target="_blank"><img src="https://images.opencollective.com/static/images/become_backer.svg"></a>
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
||||||
<!-- prettier-ignore-start -->
|
|
||||||
<!-- markdownlint-disable -->
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chemzqm"><img src="https://avatars.githubusercontent.com/u/251450?v=4?s=50" width="50px;" alt="Qiming zhao"/><br /><sub><b>Qiming zhao</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=chemzqm" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://fann.im/"><img src="https://avatars.githubusercontent.com/u/345274?v=4?s=50" width="50px;" alt="Heyward Fann"/><br /><sub><b>Heyward Fann</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=fannheyward" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/weirongxu"><img src="https://avatars.githubusercontent.com/u/1709861?v=4?s=50" width="50px;" alt="Raidou"/><br /><sub><b>Raidou</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=weirongxu" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kevinhwang91"><img src="https://avatars.githubusercontent.com/u/17562139?v=4?s=50" width="50px;" alt="kevinhwang91"/><br /><sub><b>kevinhwang91</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=kevinhwang91" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://yuuko.cn/"><img src="https://avatars.githubusercontent.com/u/5492542?v=4?s=50" width="50px;" alt="年糕小豆汤"/><br /><sub><b>年糕小豆汤</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=iamcco" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Avi-D-coder"><img src="https://avatars.githubusercontent.com/u/29133776?v=4?s=50" width="50px;" alt="Avi Dessauer"/><br /><sub><b>Avi Dessauer</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Avi-D-coder" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/voldikss"><img src="https://avatars.githubusercontent.com/u/20282795?v=4?s=50" width="50px;" alt="最上川"/><br /><sub><b>最上川</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=voldikss" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.microsoft.com/en-us/research/people/yatli/"><img src="https://avatars.githubusercontent.com/u/20684720?v=4?s=50" width="50px;" alt="Yatao Li"/><br /><sub><b>Yatao Li</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=yatli" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xiyaowong"><img src="https://avatars.githubusercontent.com/u/47070852?v=4?s=50" width="50px;" alt="wongxy"/><br /><sub><b>wongxy</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=xiyaowong" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sam-mccall"><img src="https://avatars.githubusercontent.com/u/548993?v=4?s=50" width="50px;" alt="Sam McCall"/><br /><sub><b>Sam McCall</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=sam-mccall" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://samroeca.com/pages/about.html#about"><img src="https://avatars.githubusercontent.com/u/3723671?v=4?s=50" width="50px;" alt="Samuel Roeca"/><br /><sub><b>Samuel Roeca</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=pappasam" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/amiralies"><img src="https://avatars.githubusercontent.com/u/13261088?v=4?s=50" width="50px;" alt="Amirali Esmaeili"/><br /><sub><b>Amirali Esmaeili</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=amiralies" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://bit.ly/3cLKGE4"><img src="https://avatars.githubusercontent.com/u/3051781?v=4?s=50" width="50px;" alt="Jack Rowlingson"/><br /><sub><b>Jack Rowlingson</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=jrowlingson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tomtomjhj"><img src="https://avatars.githubusercontent.com/u/19489738?v=4?s=50" width="50px;" alt="Jaehwang Jung"/><br /><sub><b>Jaehwang Jung</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=tomtomjhj" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/antoinemadec"><img src="https://avatars.githubusercontent.com/u/10830594?v=4?s=50" width="50px;" alt="Antoine"/><br /><sub><b>Antoine</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=antoinemadec" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cosminadrianpopescu"><img src="https://avatars.githubusercontent.com/u/5187873?v=4?s=50" width="50px;" alt="Cosmin Popescu"/><br /><sub><b>Cosmin Popescu</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=cosminadrianpopescu" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://ducnx.com/"><img src="https://avatars.githubusercontent.com/u/1186411?v=4?s=50" width="50px;" alt="Duc Nghiem Xuan"/><br /><sub><b>Duc Nghiem Xuan</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=xuanduc987" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://nosubstance.me/"><img src="https://avatars.githubusercontent.com/u/1269815?v=4?s=50" width="50px;" alt="Francisco Lopes"/><br /><sub><b>Francisco Lopes</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=oblitum" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/daquexian"><img src="https://avatars.githubusercontent.com/u/11607199?v=4?s=50" width="50px;" alt="daquexian"/><br /><sub><b>daquexian</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=daquexian" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/apps/dependabot"><img src="https://avatars.githubusercontent.com/in/29110?v=4?s=50" width="50px;" alt="dependabot[bot]"/><br /><sub><b>dependabot[bot]</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=dependabot[bot]" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/apps/greenkeeper"><img src="https://avatars.githubusercontent.com/in/505?v=4?s=50" width="50px;" alt="greenkeeper[bot]"/><br /><sub><b>greenkeeper[bot]</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=greenkeeper[bot]" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://chris-kipp.io/"><img src="https://avatars.githubusercontent.com/u/13974112?v=4?s=50" width="50px;" alt="Chris Kipp"/><br /><sub><b>Chris Kipp</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=ckipp01" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://dmitmel.github.io/"><img src="https://avatars.githubusercontent.com/u/15367354?v=4?s=50" width="50px;" alt="Dmytro Meleshko"/><br /><sub><b>Dmytro Meleshko</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=dmitmel" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kirillbobyrev"><img src="https://avatars.githubusercontent.com/u/3352968?v=4?s=50" width="50px;" alt="Kirill Bobyrev"/><br /><sub><b>Kirill Bobyrev</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=kirillbobyrev" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gbcreation"><img src="https://avatars.githubusercontent.com/u/454315?v=4?s=50" width="50px;" alt="Gontran Baerts"/><br /><sub><b>Gontran Baerts</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=gbcreation" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://andys8.de/"><img src="https://avatars.githubusercontent.com/u/13085980?v=4?s=50" width="50px;" alt="Andy"/><br /><sub><b>Andy</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=andys8" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.alexcj96.com/"><img src="https://avatars.githubusercontent.com/u/33961674?v=4?s=50" width="50px;" alt="Cheng JIANG"/><br /><sub><b>Cheng JIANG</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=GopherJ" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cpearce-py"><img src="https://avatars.githubusercontent.com/u/53532946?v=4?s=50" width="50px;" alt="Corin"/><br /><sub><b>Corin</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=cpearce-py" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wodesuck"><img src="https://avatars.githubusercontent.com/u/3124581?v=4?s=50" width="50px;" alt="Daniel Zhang"/><br /><sub><b>Daniel Zhang</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=wodesuck" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Ferdi265"><img src="https://avatars.githubusercontent.com/u/4077106?v=4?s=50" width="50px;" alt="Ferdinand Bachmann"/><br /><sub><b>Ferdinand Bachmann</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Ferdi265" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://goushi.me/"><img src="https://avatars.githubusercontent.com/u/16915589?v=4?s=50" width="50px;" alt="Guangqing Chen"/><br /><sub><b>Guangqing Chen</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=gou4shi1" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://jademeskill.com/"><img src="https://avatars.githubusercontent.com/u/2108?v=4?s=50" width="50px;" alt="Jade Meskill"/><br /><sub><b>Jade Meskill</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=iamruinous" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jpoppe"><img src="https://avatars.githubusercontent.com/u/65505?v=4?s=50" width="50px;" alt="Jasper Poppe"/><br /><sub><b>Jasper Poppe</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=jpoppe" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jean"><img src="https://avatars.githubusercontent.com/u/84800?v=4?s=50" width="50px;" alt="Jean Jordaan"/><br /><sub><b>Jean Jordaan</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=jean" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://xuann.wang/"><img src="https://avatars.githubusercontent.com/u/44045911?v=4?s=50" width="50px;" alt="Kid"/><br /><sub><b>Kid</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=kidonng" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Kavantix"><img src="https://avatars.githubusercontent.com/u/6243755?v=4?s=50" width="50px;" alt="Pieter van Loon"/><br /><sub><b>Pieter van Loon</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Kavantix" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rliebz"><img src="https://avatars.githubusercontent.com/u/5321575?v=4?s=50" width="50px;" alt="Robert Liebowitz"/><br /><sub><b>Robert Liebowitz</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=rliebz" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://megalithic.io/"><img src="https://avatars.githubusercontent.com/u/3678?v=4?s=50" width="50px;" alt="Seth Messer"/><br /><sub><b>Seth Messer</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=megalithic" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/UncleBill"><img src="https://avatars.githubusercontent.com/u/1141198?v=4?s=50" width="50px;" alt="UncleBill"/><br /><sub><b>UncleBill</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=UncleBill" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://zsaber.com/"><img src="https://avatars.githubusercontent.com/u/6846867?v=4?s=50" width="50px;" alt="ZERO"/><br /><sub><b>ZERO</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=ZSaberLv0" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://fsouza.blog/"><img src="https://avatars.githubusercontent.com/u/108725?v=4?s=50" width="50px;" alt="fsouza"/><br /><sub><b>fsouza</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=fsouza" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://onichandame.com/"><img src="https://avatars.githubusercontent.com/u/23728505?v=4?s=50" width="50px;" alt="XiaoZhang"/><br /><sub><b>XiaoZhang</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=onichandame" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/whyreal"><img src="https://avatars.githubusercontent.com/u/2084642?v=4?s=50" width="50px;" alt="whyreal"/><br /><sub><b>whyreal</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=whyreal" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yehuohan"><img src="https://avatars.githubusercontent.com/u/17680752?v=4?s=50" width="50px;" alt="yehuohan"/><br /><sub><b>yehuohan</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=yehuohan" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.bakudan.farm/"><img src="https://avatars.githubusercontent.com/u/4504807?v=4?s=50" width="50px;" alt="バクダンくん"/><br /><sub><b>バクダンくん</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Bakudankun" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://blog.gopherhub.org/"><img src="https://avatars.githubusercontent.com/u/41671631?v=4?s=50" width="50px;" alt="Raphael"/><br /><sub><b>Raphael</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=glepnir" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://tbodt.com/"><img src="https://avatars.githubusercontent.com/u/5678977?v=4?s=50" width="50px;" alt="tbodt"/><br /><sub><b>tbodt</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=tbodt" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://aaronmcdaid.github.io/"><img src="https://avatars.githubusercontent.com/u/64350?v=4?s=50" width="50px;" alt="Aaron McDaid"/><br /><sub><b>Aaron McDaid</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=aaronmcdaid" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/versi786"><img src="https://avatars.githubusercontent.com/u/7347942?v=4?s=50" width="50px;" alt="Aasif Versi"/><br /><sub><b>Aasif Versi</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=versi786" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/abnerf"><img src="https://avatars.githubusercontent.com/u/56300?v=4?s=50" width="50px;" alt="Abner Silva"/><br /><sub><b>Abner Silva</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=abnerf" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://sheerun.net/"><img src="https://avatars.githubusercontent.com/u/292365?v=4?s=50" width="50px;" alt="Adam Stankiewicz"/><br /><sub><b>Adam Stankiewicz</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=sheerun" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://wirow.io/"><img src="https://avatars.githubusercontent.com/u/496683?v=4?s=50" width="50px;" alt="Adamansky Anton"/><br /><sub><b>Adamansky Anton</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=adamansky" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://gabri.me/"><img src="https://avatars.githubusercontent.com/u/63876?v=4?s=50" width="50px;" alt="Ahmed El Gabri"/><br /><sub><b>Ahmed El Gabri</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=ahmedelgabri" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://theg4sh.ru/"><img src="https://avatars.githubusercontent.com/u/5094691?v=4?s=50" width="50px;" alt="Alexandr Kondratev"/><br /><sub><b>Alexandr Kondratev</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=theg4sh" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/andrewkshim"><img src="https://avatars.githubusercontent.com/u/1403410?v=4?s=50" width="50px;" alt="Andrew Shim"/><br /><sub><b>Andrew Shim</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=andrewkshim" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://andylindeman.com/"><img src="https://avatars.githubusercontent.com/u/395621?v=4?s=50" width="50px;" alt="Andy Lindeman"/><br /><sub><b>Andy Lindeman</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=alindeman" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Augustin82"><img src="https://avatars.githubusercontent.com/u/2370810?v=4?s=50" width="50px;" alt="Augustin"/><br /><sub><b>Augustin</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Augustin82" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://bananium.fr/"><img src="https://avatars.githubusercontent.com/u/3650385?v=4?s=50" width="50px;" alt="Bastien Orivel"/><br /><sub><b>Bastien Orivel</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Eijebong" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ayroblu"><img src="https://avatars.githubusercontent.com/u/4915682?v=4?s=50" width="50px;" alt="Ben Lu"/><br /><sub><b>Ben Lu</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=ayroblu" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vantreeseba"><img src="https://avatars.githubusercontent.com/u/316782?v=4?s=50" width="50px;" alt="Ben"/><br /><sub><b>Ben</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=vantreeseba" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bmon"><img src="https://avatars.githubusercontent.com/u/2115272?v=4?s=50" width="50px;" alt="Brendan Roy"/><br /><sub><b>Brendan Roy</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=bmon" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/brianembry"><img src="https://avatars.githubusercontent.com/u/35347666?v=4?s=50" width="50px;" alt="brianembry"/><br /><sub><b>brianembry</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=brianembry" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://keybase.io/bri_"><img src="https://avatars.githubusercontent.com/u/284789?v=4?s=50" width="50px;" alt="br"/><br /><sub><b>br</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=b-" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/casonadams"><img src="https://avatars.githubusercontent.com/u/17597548?v=4?s=50" width="50px;" alt="Cason Adams"/><br /><sub><b>Cason Adams</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=casonadams" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/y9c"><img src="https://avatars.githubusercontent.com/u/5415510?v=4?s=50" width="50px;" alt="Chang Y"/><br /><sub><b>Chang Y</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=y9c" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://yous.be/"><img src="https://avatars.githubusercontent.com/u/853977?v=4?s=50" width="50px;" alt="Chayoung You"/><br /><sub><b>Chayoung You</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=yous" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chenlijun99"><img src="https://avatars.githubusercontent.com/u/20483759?v=4?s=50" width="50px;" alt="Chen Lijun"/><br /><sub><b>Chen Lijun</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=chenlijun99" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/beeender"><img src="https://avatars.githubusercontent.com/u/449296?v=4?s=50" width="50px;" alt="Chen Mulong"/><br /><sub><b>Chen Mulong</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=beeender" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://weyl.io/"><img src="https://avatars.githubusercontent.com/u/59620?v=4?s=50" width="50px;" alt="Chris Weyl"/><br /><sub><b>Chris Weyl</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=rsrchboy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dezza"><img src="https://avatars.githubusercontent.com/u/402927?v=4?s=50" width="50px;" alt="dezza"/><br /><sub><b>dezza</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=dezza" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ceedubs"><img src="https://avatars.githubusercontent.com/u/977929?v=4?s=50" width="50px;" alt="Cody Allen"/><br /><sub><b>Cody Allen</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=ceedubs" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.25.wf/"><img src="https://avatars.githubusercontent.com/u/145502?v=4?s=50" width="50px;" alt="Damien Rajon"/><br /><sub><b>Damien Rajon</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=pyrho" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/daern91"><img src="https://avatars.githubusercontent.com/u/6084427?v=4?s=50" width="50px;" alt="Daniel Eriksson"/><br /><sub><b>Daniel Eriksson</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=daern91" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/danjenson"><img src="https://avatars.githubusercontent.com/u/4793438?v=4?s=50" width="50px;" alt="Daniel Jenson"/><br /><sub><b>Daniel Jenson</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=danjenson" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/davidmh"><img src="https://avatars.githubusercontent.com/u/594302?v=4?s=50" width="50px;" alt="David Mejorado"/><br /><sub><b>David Mejorado</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=davidmh" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pderichai"><img src="https://avatars.githubusercontent.com/u/13430946?v=4?s=50" width="50px;" alt="Deric Pang"/><br /><sub><b>Deric Pang</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=pderichai" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.dingtao.org/blog"><img src="https://avatars.githubusercontent.com/u/12852587?v=4?s=50" width="50px;" alt="Ding Tao"/><br /><sub><b>Ding Tao</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=miyatsu" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/doronbehar"><img src="https://avatars.githubusercontent.com/u/10998835?v=4?s=50" width="50px;" alt="Doron Behar"/><br /><sub><b>Doron Behar</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=doronbehar" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kovetskiy"><img src="https://avatars.githubusercontent.com/u/8445924?v=4?s=50" width="50px;" alt="Egor Kovetskiy"/><br /><sub><b>Egor Kovetskiy</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=kovetskiy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/elkowar"><img src="https://avatars.githubusercontent.com/u/5300871?v=4?s=50" width="50px;" alt="ElKowar"/><br /><sub><b>ElKowar</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=elkowar" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/demelev"><img src="https://avatars.githubusercontent.com/u/3952209?v=4?s=50" width="50px;" alt="Emeliov Dmitrii"/><br /><sub><b>Emeliov Dmitrii</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=demelev" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sawmurai"><img src="https://avatars.githubusercontent.com/u/6454986?v=4?s=50" width="50px;" alt="Fabian Becker"/><br /><sub><b>Fabian Becker</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=sawmurai" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FallenWarrior2k"><img src="https://avatars.githubusercontent.com/u/20320149?v=4?s=50" width="50px;" alt="FallenWarrior2k"/><br /><sub><b>FallenWarrior2k</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=FallenWarrior2k" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://fnune.com/"><img src="https://avatars.githubusercontent.com/u/16181067?v=4?s=50" width="50px;" alt="Fausto Núñez Alberro"/><br /><sub><b>Fausto Núñez Alberro</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=fnune" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FelipeCRamos"><img src="https://avatars.githubusercontent.com/u/7572843?v=4?s=50" width="50px;" alt="Felipe Ramos"/><br /><sub><b>Felipe Ramos</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=FelipeCRamos" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/frbor"><img src="https://avatars.githubusercontent.com/u/2320183?v=4?s=50" width="50px;" alt="Fredrik Borg"/><br /><sub><b>Fredrik Borg</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=frbor" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.gavinsim.co.uk/"><img src="https://avatars.githubusercontent.com/u/812273?v=4?s=50" width="50px;" alt="Gavin Sim"/><br /><sub><b>Gavin Sim</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=gavsim" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://fahn.co/"><img src="https://avatars.githubusercontent.com/u/15943089?v=4?s=50" width="50px;" alt="Gibson Fahnestock"/><br /><sub><b>Gibson Fahnestock</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=gibfahn" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/giovannigiordano"><img src="https://avatars.githubusercontent.com/u/15145952?v=4?s=50" width="50px;" alt="Giovanni Giordano"/><br /><sub><b>Giovanni Giordano</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=giovannigiordano" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/qubbit"><img src="https://avatars.githubusercontent.com/u/1987473?v=4?s=50" width="50px;" alt="Gopal Adhikari"/><br /><sub><b>Gopal Adhikari</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=qubbit" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hanh090"><img src="https://avatars.githubusercontent.com/u/3643657?v=4?s=50" width="50px;" alt="Hanh Le"/><br /><sub><b>Hanh Le</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=hanh090" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hedyhli"><img src="https://avatars.githubusercontent.com/u/50042066?v=4?s=50" width="50px;" alt="hedy"/><br /><sub><b>hedy</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=hedyhli" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.hendriklammers.com/"><img src="https://avatars.githubusercontent.com/u/754556?v=4?s=50" width="50px;" alt="Hendrik Lammers"/><br /><sub><b>Hendrik Lammers</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=hendriklammers" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/henrybarreto"><img src="https://avatars.githubusercontent.com/u/23109089?v=4?s=50" width="50px;" alt="Henry Barreto"/><br /><sub><b>Henry Barreto</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=henrybarreto" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://hugo.barrera.io/"><img src="https://avatars.githubusercontent.com/u/730811?v=4?s=50" width="50px;" alt="Hugo"/><br /><sub><b>Hugo</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=WhyNotHugo" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jackieli-tes"><img src="https://avatars.githubusercontent.com/u/64778297?v=4?s=50" width="50px;" alt="Jackie Li"/><br /><sub><b>Jackie Li</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=jackieli-tes" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MrQubo"><img src="https://avatars.githubusercontent.com/u/16545322?v=4?s=50" width="50px;" alt="Jakub Nowak"/><br /><sub><b>Jakub Nowak</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=MrQubo" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/euoia"><img src="https://avatars.githubusercontent.com/u/1271216?v=4?s=50" width="50px;" alt="James Pickard"/><br /><sub><b>James Pickard</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=euoia" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jsfaint"><img src="https://avatars.githubusercontent.com/u/571829?v=4?s=50" width="50px;" alt="Jia Sui"/><br /><sub><b>Jia Sui</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=jsfaint" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/expipiplus1"><img src="https://avatars.githubusercontent.com/u/857308?v=4?s=50" width="50px;" alt="Ellie Hermaszewska"/><br /><sub><b>Ellie Hermaszewska</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=expipiplus1" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://cincodenada.com/"><img src="https://avatars.githubusercontent.com/u/479715?v=4?s=50" width="50px;" alt="Joel Bradshaw"/><br /><sub><b>Joel Bradshaw</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=cincodenada" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/irizwaririz"><img src="https://avatars.githubusercontent.com/u/10111643?v=4?s=50" width="50px;" alt="John Carlo Roberto"/><br /><sub><b>John Carlo Roberto</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=irizwaririz" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Jomik"><img src="https://avatars.githubusercontent.com/u/699655?v=4?s=50" width="50px;" alt="Jonas Holst Damtoft"/><br /><sub><b>Jonas Holst Damtoft</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Jomik" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://inlehmansterms.net/"><img src="https://avatars.githubusercontent.com/u/3144695?v=4?s=50" width="50px;" alt="Jonathan Lehman"/><br /><sub><b>Jonathan Lehman</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=jdlehman" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://joosep.xyz/"><img src="https://avatars.githubusercontent.com/u/9450943?v=4?s=50" width="50px;" alt="Joosep Alviste"/><br /><sub><b>Joosep Alviste</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=JoosepAlviste" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/josa42"><img src="https://avatars.githubusercontent.com/u/423234?v=4?s=50" width="50px;" alt="Josa Gesell"/><br /><sub><b>Josa Gesell</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=josa42" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://jawa.dev/"><img src="https://avatars.githubusercontent.com/u/194275?v=4?s=50" width="50px;" alt="Joshua Rubin"/><br /><sub><b>Joshua Rubin</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=joshuarubin" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/perrin4869"><img src="https://avatars.githubusercontent.com/u/5774716?v=4?s=50" width="50px;" alt="Julian Grinblat"/><br /><sub><b>Julian Grinblat</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=perrin4869" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://valentjn.github.io/"><img src="https://avatars.githubusercontent.com/u/19839841?v=4?s=50" width="50px;" alt="Julian Valentin"/><br /><sub><b>Julian Valentin</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=valentjn" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://kabbamine.github.io/"><img src="https://avatars.githubusercontent.com/u/5658084?v=4?s=50" width="50px;" alt="KabbAmine"/><br /><sub><b>KabbAmine</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=KabbAmine" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://moncargo.io/"><img src="https://avatars.githubusercontent.com/u/10719495?v=4?s=50" width="50px;" alt="Kay Gosho"/><br /><sub><b>Kay Gosho</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=acro5piano" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://kennyvh.com/"><img src="https://avatars.githubusercontent.com/u/29909203?v=4?s=50" width="50px;" alt="Kenny Huynh"/><br /><sub><b>Kenny Huynh</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=hkennyv" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kevinrambaud"><img src="https://avatars.githubusercontent.com/u/7501477?v=4?s=50" width="50px;" alt="Kevin Rambaud"/><br /><sub><b>Kevin Rambaud</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=kevinrambaud" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kiancross"><img src="https://avatars.githubusercontent.com/u/11011464?v=4?s=50" width="50px;" alt="Kian Cross"/><br /><sub><b>Kian Cross</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=kiancross" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://ko-fi.com/kristijanhusak"><img src="https://avatars.githubusercontent.com/u/1782860?v=4?s=50" width="50px;" alt="Kristijan Husak"/><br /><sub><b>Kristijan Husak</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=kristijanhusak" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NullVoxPopuli"><img src="https://avatars.githubusercontent.com/u/199018?v=4?s=50" width="50px;" alt="NullVoxPopuli"/><br /><sub><b>NullVoxPopuli</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=NullVoxPopuli" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lassepe"><img src="https://avatars.githubusercontent.com/u/10076790?v=4?s=50" width="50px;" alt="Lasse Peters"/><br /><sub><b>Lasse Peters</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=lassepe" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Linerre"><img src="https://avatars.githubusercontent.com/u/49512984?v=4?s=50" width="50px;" alt="Noel Errenil"/><br /><sub><b>Noel Errenil</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Linerre" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LinArcX"><img src="https://avatars.githubusercontent.com/u/10884422?v=4?s=50" width="50px;" alt="LinArcX"/><br /><sub><b>LinArcX</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=LinArcX" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://paypal.me/liuchengxu"><img src="https://avatars.githubusercontent.com/u/8850248?v=4?s=50" width="50px;" alt="Liu-Cheng Xu"/><br /><sub><b>Liu-Cheng Xu</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=liuchengxu" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://malloc.me/"><img src="https://avatars.githubusercontent.com/u/4153572?v=4?s=50" width="50px;" alt="Marc"/><br /><sub><b>Marc</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=foxtrot" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mgaw"><img src="https://avatars.githubusercontent.com/u/2177016?v=4?s=50" width="50px;" alt="Marius Gawrisch"/><br /><sub><b>Marius Gawrisch</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=mgaw" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://www.markhz.com/"><img src="https://avatars.githubusercontent.com/u/2789742?v=4?s=50" width="50px;" alt="Mark Hintz"/><br /><sub><b>Mark Hintz</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=mhintz" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MatElGran"><img src="https://avatars.githubusercontent.com/u/1052778?v=4?s=50" width="50px;" alt="Mathieu Le Tiec"/><br /><sub><b>Mathieu Le Tiec</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=MatElGran" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://matt-w.net/"><img src="https://avatars.githubusercontent.com/u/8656127?v=4?s=50" width="50px;" alt="Matt White"/><br /><sub><b>Matt White</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=matt-fff" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ml-evs"><img src="https://avatars.githubusercontent.com/u/7916000?v=4?s=50" width="50px;" alt="Matthew Evans"/><br /><sub><b>Matthew Evans</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=ml-evs" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Me1onRind"><img src="https://avatars.githubusercontent.com/u/19531270?v=4?s=50" width="50px;" alt="Me1onRind"/><br /><sub><b>Me1onRind</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Me1onRind" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Qyriad"><img src="https://avatars.githubusercontent.com/u/1542224?v=4?s=50" width="50px;" alt="Qyriad"/><br /><sub><b>Qyriad</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Qyriad" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://leo.is-a.dev/"><img src="https://avatars.githubusercontent.com/u/35312043?v=4?s=50" width="50px;" alt="Narcis B."/><br /><sub><b>Narcis B.</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=leonardssh" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Neur1n"><img src="https://avatars.githubusercontent.com/u/17579247?v=4?s=50" width="50px;" alt="Neur1n"/><br /><sub><b>Neur1n</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Neur1n" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nicoder"><img src="https://avatars.githubusercontent.com/u/365210?v=4?s=50" width="50px;" alt="Nicolas Dermine"/><br /><sub><b>Nicolas Dermine</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=nicoder" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NoahTheDuke"><img src="https://avatars.githubusercontent.com/u/603677?v=4?s=50" width="50px;" alt="Noah"/><br /><sub><b>Noah</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=NoahTheDuke" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/IndexXuan"><img src="https://avatars.githubusercontent.com/u/6322673?v=4?s=50" width="50px;" alt="PENG Rui"/><br /><sub><b>PENG Rui</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=IndexXuan" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://liaoph.com/"><img src="https://avatars.githubusercontent.com/u/6123425?v=4?s=50" width="50px;" alt="Paco"/><br /><sub><b>Paco</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=paco0x" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/peng1999"><img src="https://avatars.githubusercontent.com/u/12483662?v=4?s=50" width="50px;" alt="Peng Guanwen"/><br /><sub><b>Peng Guanwen</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=peng1999" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.twitter.com/badeip"><img src="https://avatars.githubusercontent.com/u/1106732?v=4?s=50" width="50px;" alt="Petter Wahlman"/><br /><sub><b>Petter Wahlman</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=ilAYAli" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pvonmoradi"><img src="https://avatars.githubusercontent.com/u/1058151?v=4?s=50" width="50px;" alt="Pooya Moradi"/><br /><sub><b>Pooya Moradi</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=pvonmoradi" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/QuadeMorrison"><img src="https://avatars.githubusercontent.com/u/10917383?v=4?s=50" width="50px;" alt="Quade Morrison"/><br /><sub><b>Quade Morrison</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=QuadeMorrison" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vogler"><img src="https://avatars.githubusercontent.com/u/493741?v=4?s=50" width="50px;" alt="Ralf Vogler"/><br /><sub><b>Ralf Vogler</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=vogler" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/crccw"><img src="https://avatars.githubusercontent.com/u/41463?v=4?s=50" width="50px;" alt="Ran Chen"/><br /><sub><b>Ran Chen</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=crccw" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://bigardone.dev/"><img src="https://avatars.githubusercontent.com/u/1090272?v=4?s=50" width="50px;" alt="Ricardo García Vega"/><br /><sub><b>Ricardo García Vega</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=bigardone" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nomasprime"><img src="https://avatars.githubusercontent.com/u/140855?v=4?s=50" width="50px;" alt="Rick Jones"/><br /><sub><b>Rick Jones</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=nomasprime" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rschristian"><img src="https://avatars.githubusercontent.com/u/33403762?v=4?s=50" width="50px;" alt="Ryan Christian"/><br /><sub><b>Ryan Christian</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=rschristian" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://salo.so/"><img src="https://avatars.githubusercontent.com/u/4694263?v=4?s=50" width="50px;" alt="Salo"/><br /><sub><b>Salo</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=winterbesos" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Hazelfire"><img src="https://avatars.githubusercontent.com/u/13807753?v=4?s=50" width="50px;" alt="Sam Nolan"/><br /><sub><b>Sam Nolan</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Hazelfire" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rickysaurav"><img src="https://avatars.githubusercontent.com/u/13986039?v=4?s=50" width="50px;" alt="Saurav"/><br /><sub><b>Saurav</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=rickysaurav" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/smackesey"><img src="https://avatars.githubusercontent.com/u/1531373?v=4?s=50" width="50px;" alt="Sean Mackesey"/><br /><sub><b>Sean Mackesey</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=smackesey" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sheeldotme"><img src="https://avatars.githubusercontent.com/u/6991406?v=4?s=50" width="50px;" alt="Sheel Patel"/><br /><sub><b>Sheel Patel</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=sheeldotme" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/solomonwzs"><img src="https://avatars.githubusercontent.com/u/907942?v=4?s=50" width="50px;" alt="Solomon Ng"/><br /><sub><b>Solomon Ng</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=solomonwzs" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kadimisetty"><img src="https://avatars.githubusercontent.com/u/535947?v=4?s=50" width="50px;" alt="Sri Kadimisetty"/><br /><sub><b>Sri Kadimisetty</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=kadimisetty" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/stephenprater"><img src="https://avatars.githubusercontent.com/u/149870?v=4?s=50" width="50px;" alt="Stephen Prater"/><br /><sub><b>Stephen Prater</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=stephenprater" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://kibs.dk/"><img src="https://avatars.githubusercontent.com/u/14085?v=4?s=50" width="50px;" alt="Sune Kibsgaard"/><br /><sub><b>Sune Kibsgaard</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=kibs" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Aquaakuma"><img src="https://avatars.githubusercontent.com/u/31891793?v=4?s=50" width="50px;" alt="Aquaakuma"/><br /><sub><b>Aquaakuma</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Aquaakuma" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/coil398"><img src="https://avatars.githubusercontent.com/u/7694377?v=4?s=50" width="50px;" alt="Takumi Kawase"/><br /><sub><b>Takumi Kawase</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=coil398" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/theblobscp"><img src="https://avatars.githubusercontent.com/u/81673375?v=4?s=50" width="50px;" alt="The Blob SCP"/><br /><sub><b>The Blob SCP</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=theblobscp" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/przepompownia"><img src="https://avatars.githubusercontent.com/u/11404453?v=4?s=50" width="50px;" alt="Tomasz N"/><br /><sub><b>Tomasz N</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=przepompownia" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/gasuketsu"><img src="https://avatars.githubusercontent.com/u/15703757?v=4?s=50" width="50px;" alt="Tomoyuki Harada"/><br /><sub><b>Tomoyuki Harada</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=gasuketsu" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tonyfettes"><img src="https://avatars.githubusercontent.com/u/29998228?v=4?s=50" width="50px;" alt="Tony Fettes"/><br /><sub><b>Tony Fettes</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=tonyfettes" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.git-pull.com/"><img src="https://avatars.githubusercontent.com/u/26336?v=4?s=50" width="50px;" alt="Tony Narlock"/><br /><sub><b>Tony Narlock</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=tony" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://blog.wwwjfy.net/"><img src="https://avatars.githubusercontent.com/u/126527?v=4?s=50" width="50px;" alt="Tony Wang"/><br /><sub><b>Tony Wang</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=wwwjfy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Varal7"><img src="https://avatars.githubusercontent.com/u/8019486?v=4?s=50" width="50px;" alt="Victor Quach"/><br /><sub><b>Victor Quach</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=Varal7" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/whisperity"><img src="https://avatars.githubusercontent.com/u/1969470?v=4?s=50" width="50px;" alt="Whisperity"/><br /><sub><b>Whisperity</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=whisperity" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/willtrnr"><img src="https://avatars.githubusercontent.com/u/1878110?v=4?s=50" width="50px;" alt="William Turner"/><br /><sub><b>William Turner</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=willtrnr" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://drafts.damnever.com/"><img src="https://avatars.githubusercontent.com/u/6223594?v=4?s=50" width="50px;" alt="Xiaochao Dong"/><br /><sub><b>Xiaochao Dong</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=damnever" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hyhugh"><img src="https://avatars.githubusercontent.com/u/16500351?v=4?s=50" width="50px;" alt="Hugh Hou"/><br /><sub><b>Hugh Hou</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=hyhugh" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jackielii"><img src="https://avatars.githubusercontent.com/u/360983?v=4?s=50" width="50px;" alt="Jackie Li"/><br /><sub><b>Jackie Li</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=jackielii" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TheConfuZzledDude"><img src="https://avatars.githubusercontent.com/u/3160203?v=4?s=50" width="50px;" alt="Zachary Freed"/><br /><sub><b>Zachary Freed</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=TheConfuZzledDude" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/akiyosi"><img src="https://avatars.githubusercontent.com/u/8478977?v=4?s=50" width="50px;" alt="akiyosi"/><br /><sub><b>akiyosi</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=akiyosi" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/alexjg"><img src="https://avatars.githubusercontent.com/u/224635?v=4?s=50" width="50px;" alt="alexjg"/><br /><sub><b>alexjg</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=alexjg" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aste4"><img src="https://avatars.githubusercontent.com/u/47511385?v=4?s=50" width="50px;" alt="aste4"/><br /><sub><b>aste4</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=aste4" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/clyfish"><img src="https://avatars.githubusercontent.com/u/541215?v=4?s=50" width="50px;" alt="clyfish"/><br /><sub><b>clyfish</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=clyfish" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dev7ba"><img src="https://avatars.githubusercontent.com/u/93706552?v=4?s=50" width="50px;" alt="dev7ba"/><br /><sub><b>dev7ba</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=dev7ba" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/diartyz"><img src="https://avatars.githubusercontent.com/u/4486152?v=4?s=50" width="50px;" alt="diartyz"/><br /><sub><b>diartyz</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=diartyz" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/doza-daniel"><img src="https://avatars.githubusercontent.com/u/13752683?v=4?s=50" width="50px;" alt="doza-daniel"/><br /><sub><b>doza-daniel</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=doza-daniel" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/equal-l2"><img src="https://avatars.githubusercontent.com/u/8597717?v=4?s=50" width="50px;" alt="equal-l2"/><br /><sub><b>equal-l2</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=equal-l2" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/FongHou"><img src="https://avatars.githubusercontent.com/u/13973254?v=4?s=50" width="50px;" alt="fong"/><br /><sub><b>fong</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=FongHou" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://blog.hexuhua.vercel.app/"><img src="https://avatars.githubusercontent.com/u/26080416?v=4?s=50" width="50px;" alt="hexh"/><br /><sub><b>hexh</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=hexh250786313" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hhiraba"><img src="https://avatars.githubusercontent.com/u/4624806?v=4?s=50" width="50px;" alt="hhiraba"/><br /><sub><b>hhiraba</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=hhiraba" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ic-768"><img src="https://avatars.githubusercontent.com/u/83115125?v=4?s=50" width="50px;" alt="ic-768"/><br /><sub><b>ic-768</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=ic-768" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/javiertury"><img src="https://avatars.githubusercontent.com/u/1520320?v=4?s=50" width="50px;" alt="javiertury"/><br /><sub><b>javiertury</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=javiertury" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/seiyeah78"><img src="https://avatars.githubusercontent.com/u/6185139?v=4?s=50" width="50px;" alt="karasu"/><br /><sub><b>karasu</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=seiyeah78" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kevineato"><img src="https://avatars.githubusercontent.com/u/13666221?v=4?s=50" width="50px;" alt="kevineato"/><br /><sub><b>kevineato</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=kevineato" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/m4c0"><img src="https://avatars.githubusercontent.com/u/1664510?v=4?s=50" width="50px;" alt="Eduardo Costa"/><br /><sub><b>Eduardo Costa</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=m4c0" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/micchy326"><img src="https://avatars.githubusercontent.com/u/23257067?v=4?s=50" width="50px;" alt="micchy326"/><br /><sub><b>micchy326</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=micchy326" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://keybase.io/midchildan"><img src="https://avatars.githubusercontent.com/u/7343721?v=4?s=50" width="50px;" alt="midchildan"/><br /><sub><b>midchildan</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=midchildan" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/minefuto"><img src="https://avatars.githubusercontent.com/u/46558834?v=4?s=50" width="50px;" alt="minefuto"/><br /><sub><b>minefuto</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=minefuto" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/robokomy"><img src="https://avatars.githubusercontent.com/u/20733354?v=4?s=50" width="50px;" alt="miyanokomiya"/><br /><sub><b>miyanokomiya</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=miyanokomiya" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/miyaviee"><img src="https://avatars.githubusercontent.com/u/15247561?v=4?s=50" width="50px;" alt="miyaviee"/><br /><sub><b>miyaviee</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=miyaviee" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/monkoose"><img src="https://avatars.githubusercontent.com/u/6261276?v=4?s=50" width="50px;" alt="monkoose"/><br /><sub><b>monkoose</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=monkoose" title="Code">💻</a> <a href="https://github.com/neoclide/coc.nvim/issues?q=author%3Amonkoose" title="Bug reports">🐛</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mujx"><img src="https://avatars.githubusercontent.com/u/6430350?v=4?s=50" width="50px;" alt="mujx"/><br /><sub><b>mujx</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=mujx" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mvilim"><img src="https://avatars.githubusercontent.com/u/40682862?v=4?s=50" width="50px;" alt="mvilim"/><br /><sub><b>mvilim</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=mvilim" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://naruaway.com/"><img src="https://avatars.githubusercontent.com/u/2931577?v=4?s=50" width="50px;" alt="naruaway"/><br /><sub><b>naruaway</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=naruaway" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/piersy"><img src="https://avatars.githubusercontent.com/u/5087847?v=4?s=50" width="50px;" alt="piersy"/><br /><sub><b>piersy</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=piersy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ryantig"><img src="https://avatars.githubusercontent.com/u/324810?v=4?s=50" width="50px;" alt="ryantig"/><br /><sub><b>ryantig</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=ryantig" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://catcat.cc/"><img src="https://avatars.githubusercontent.com/u/19602440?v=4?s=50" width="50px;" alt="rydesun"/><br /><sub><b>rydesun</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=rydesun" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/sc00ter"><img src="https://avatars.githubusercontent.com/u/1271025?v=4?s=50" width="50px;" alt="sc00ter"/><br /><sub><b>sc00ter</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=sc00ter" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/smhc"><img src="https://avatars.githubusercontent.com/u/6404304?v=4?s=50" width="50px;" alt="smhc"/><br /><sub><b>smhc</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=smhc" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/stkaplan"><img src="https://avatars.githubusercontent.com/u/594990?v=4?s=50" width="50px;" alt="Sam Kaplan"/><br /><sub><b>Sam Kaplan</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=stkaplan" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tasuten"><img src="https://avatars.githubusercontent.com/u/1623176?v=4?s=50" width="50px;" alt="tasuten"/><br /><sub><b>tasuten</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=tasuten" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://todesking.com/"><img src="https://avatars.githubusercontent.com/u/112881?v=4?s=50" width="50px;" alt="todesking"/><br /><sub><b>todesking</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=todesking" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/typicode"><img src="https://avatars.githubusercontent.com/u/5502029?v=4?s=50" width="50px;" alt="typicode"/><br /><sub><b>typicode</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=typicode" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://limingfei56.github.io/"><img src="https://avatars.githubusercontent.com/u/8553407?v=4?s=50" width="50px;" alt="李鸣飞"/><br /><sub><b>李鸣飞</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=LiMingFei56" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://bandism.net/"><img src="https://avatars.githubusercontent.com/u/22633385?v=4?s=50" width="50px;" alt="Ikko Ashimine"/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=eltociear" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rammiah"><img src="https://avatars.githubusercontent.com/u/26727562?v=4?s=50" width="50px;" alt="Rammiah"/><br /><sub><b>Rammiah</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/issues?q=author%3Arammiah" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://keybase.io/lambdalisue"><img src="https://avatars.githubusercontent.com/u/546312?v=4?s=50" width="50px;" alt="Alisue"/><br /><sub><b>Alisue</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/issues?q=author%3Alambdalisue" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://bigshans.github.io"><img src="https://avatars.githubusercontent.com/u/26884666?v=4?s=50" width="50px;" alt="bigshans"/><br /><sub><b>bigshans</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=bigshans" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rob-3"><img src="https://avatars.githubusercontent.com/u/24816247?v=4?s=50" width="50px;" alt="Robert Boyd III"/><br /><sub><b>Robert Boyd III</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/issues?q=author%3Arob-3" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://creasty.com"><img src="https://avatars.githubusercontent.com/u/1695538?v=4?s=50" width="50px;" alt="Yuki Iwanaga"/><br /><sub><b>Yuki Iwanaga</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=creasty" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://www.dosk.win/"><img src="https://avatars.githubusercontent.com/u/2389889?v=4?s=50" width="50px;" alt="SpringHack"/><br /><sub><b>SpringHack</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/issues?q=author%3Aspringhack" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://git.lmburns.com"><img src="https://avatars.githubusercontent.com/u/44355502?v=4?s=50" width="50px;" alt="Lucas Burns"/><br /><sub><b>Lucas Burns</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=lmburns" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://qiqi.boy.im"><img src="https://avatars.githubusercontent.com/u/3774036?v=4?s=50" width="50px;" alt="qiqiboy"/><br /><sub><b>qiqiboy</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=qiqiboy" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/timsu92"><img src="https://avatars.githubusercontent.com/u/33785401?v=4?s=50" width="50px;" alt="timsu92"/><br /><sub><b>timsu92</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=timsu92" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://sartak.org"><img src="https://avatars.githubusercontent.com/u/45430?v=4?s=50" width="50px;" alt="Shawn M Moore"/><br /><sub><b>Shawn M Moore</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=sartak" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/aauren"><img src="https://avatars.githubusercontent.com/u/1392295?v=4?s=50" width="50px;" alt="Aaron U'Ren"/><br /><sub><b>Aaron U'Ren</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/issues?q=author%3Aaauren" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SirCharlieMars"><img src="https://avatars.githubusercontent.com/u/31679231?v=4?s=50" width="50px;" alt="SeniorMars"/><br /><sub><b>SeniorMars</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=SirCharlieMars" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/CollieIsCute"><img src="https://avatars.githubusercontent.com/u/43088530?v=4?s=50" width="50px;" alt="牧羊犬真Q"/><br /><sub><b>牧羊犬真Q</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=CollieIsCute" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://geraldspreer.com"><img src="https://avatars.githubusercontent.com/u/1745692?v=4?s=50" width="50px;" alt="geraldspreer"/><br /><sub><b>geraldspreer</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=geraldspreer" title="Documentation">📖</a></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="http://3ximus.github.io/cv"><img src="https://avatars.githubusercontent.com/u/9083012?v=4?s=50" width="50px;" alt="Fabio"/><br /><sub><b>Fabio</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=3ximus" title="Documentation">📖</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/skysky97"><img src="https://avatars.githubusercontent.com/u/18086458?v=4?s=50" width="50px;" alt="Li Yunting"/><br /><sub><b>Li Yunting</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/issues?q=author%3Askysky97" title="Bug reports">🐛</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LebJe"><img src="https://avatars.githubusercontent.com/u/51171427?v=4?s=50" width="50px;" alt="Jeff L."/><br /><sub><b>Jeff L.</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=LebJe" title="Code">💻</a></td>
|
|
||||||
<td align="center" valign="top" width="14.28%"><a href="https://hachyderm.io/@mcmire"><img src="https://avatars.githubusercontent.com/u/7371?v=4?s=50" width="50px;" alt="Elliot Winkler"/><br /><sub><b>Elliot Winkler</b></sub></a><br /><a href="https://github.com/neoclide/coc.nvim/commits?author=mcmire" title="Code">💻</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<!-- markdownlint-restore -->
|
|
||||||
<!-- prettier-ignore-end -->
|
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
||||||
<!-- prettier-ignore-start -->
|
|
||||||
<!-- markdownlint-disable -->
|
|
||||||
<!-- markdownlint-restore -->
|
|
||||||
<!-- prettier-ignore-end -->
|
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
||||||
|
|
||||||
This project follows the [all-contributors](https://allcontributors.org) specification.
|
|
||||||
Contributions of any kind are welcome!
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
[Anti 996](./LICENSE.md)
|
|
|
@ -1,157 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let g:coc_user_config = get(g:, 'coc_user_config', {})
|
|
||||||
let g:coc_global_extensions = get(g:, 'coc_global_extensions', [])
|
|
||||||
let g:coc_selected_text = ''
|
|
||||||
let g:coc_vim_commands = []
|
|
||||||
let s:watched_keys = []
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:utf = has('nvim') || &encoding =~# '^utf'
|
|
||||||
let s:error_sign = get(g:, 'coc_status_error_sign', has('mac') && s:utf ? "\u274c " : 'E ')
|
|
||||||
let s:warning_sign = get(g:, 'coc_status_warning_sign', has('mac') && s:utf ? "\u26a0\ufe0f " : 'W ')
|
|
||||||
let s:select_api = exists('*nvim_select_popupmenu_item')
|
|
||||||
let s:callbacks = {}
|
|
||||||
let s:hide_pum = has('nvim-0.6.1') || has('patch-8.2.3389')
|
|
||||||
|
|
||||||
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#on_enter()
|
|
||||||
call coc#rpc#notify('CocAutocmd', ['Enter', bufnr('%')])
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#_insert_key(method, key, ...) abort
|
|
||||||
let prefix = ''
|
|
||||||
if get(a:, 1, 1)
|
|
||||||
if coc#pum#visible()
|
|
||||||
let prefix = "\<C-r>=coc#pum#close()\<CR>"
|
|
||||||
elseif pumvisible() && s:hide_pum
|
|
||||||
let prefix = "\<C-x>\<C-z>"
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return prefix."\<c-r>=coc#rpc#".a:method."('doKeymap', ['".a:key."'])\<CR>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" used for statusline
|
|
||||||
function! coc#status(...)
|
|
||||||
let info = get(b:, 'coc_diagnostic_info', {})
|
|
||||||
let msgs = []
|
|
||||||
if !empty(info) && get(info, 'error', 0)
|
|
||||||
call add(msgs, s:error_sign . info['error'])
|
|
||||||
endif
|
|
||||||
if !empty(info) && get(info, 'warning', 0)
|
|
||||||
call add(msgs, s:warning_sign . info['warning'])
|
|
||||||
endif
|
|
||||||
let status = get(g:, 'coc_status', '')
|
|
||||||
if get(a:, 1, 0)
|
|
||||||
let status = substitute(status, '%', '%%', 'g')
|
|
||||||
endif
|
|
||||||
return coc#compat#trim(join(msgs, ' ') . ' ' . status)
|
|
||||||
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
|
|
||||||
|
|
||||||
" Deprecated, use variable instead.
|
|
||||||
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#on_notify(id, method, Cb)
|
|
||||||
let key = a:id. '-'.a:method
|
|
||||||
let s:callbacks[key] = a:Cb
|
|
||||||
call coc#rpc#notify('registerNotification', [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
|
|
||||||
|
|
||||||
function! coc#start(...)
|
|
||||||
call CocActionAsync('startCompletion', get(a:, 1, {}))
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Could be used by coc extensions
|
|
||||||
function! coc#_cancel(...)
|
|
||||||
call coc#pum#close()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#refresh() abort
|
|
||||||
return "\<c-r>=coc#start()\<CR>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#_select_confirm() abort
|
|
||||||
return "\<C-r>=coc#pum#select_confirm()\<CR>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#_suggest_variables() abort
|
|
||||||
return {
|
|
||||||
\ 'disable': get(b:, 'coc_suggest_disable', 0),
|
|
||||||
\ 'disabled_sources': get(b:, 'coc_disabled_sources', []),
|
|
||||||
\ 'blacklist': get(b:, 'coc_suggest_blacklist', []),
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#_remote_fns(name)
|
|
||||||
let fns = ['init', 'complete', 'should_complete', 'refresh', 'get_startcol', 'on_complete', 'on_enter']
|
|
||||||
let res = []
|
|
||||||
for fn in fns
|
|
||||||
if exists('*coc#source#'.a:name.'#'.fn)
|
|
||||||
call add(res, fn)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return res
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#_do_complete(name, opt, cb) abort
|
|
||||||
let handler = 'coc#source#'.a:name.'#complete'
|
|
||||||
let l:Cb = {res -> a:cb(v:null, res)}
|
|
||||||
let args = [a:opt, l:Cb]
|
|
||||||
call call(handler, args)
|
|
||||||
endfunction
|
|
|
@ -1,898 +0,0 @@
|
||||||
" ============================================================================
|
|
||||||
" Description: Client api used by vim8
|
|
||||||
" Author: Qiming Zhao <chemzqm@gmail.com>
|
|
||||||
" Licence: Anti 996 licence
|
|
||||||
" Last Modified: 2022-12-20
|
|
||||||
" ============================================================================
|
|
||||||
if has('nvim')
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
scriptencoding utf-8
|
|
||||||
let s:funcs = {}
|
|
||||||
let s:prop_offset = get(g:, 'coc_text_prop_offset', 1000)
|
|
||||||
let s:namespace_id = 1
|
|
||||||
let s:namespace_cache = {}
|
|
||||||
let s:max_src_id = 1000
|
|
||||||
" bufnr => max textprop id
|
|
||||||
let s:buffer_id = {}
|
|
||||||
" srcId => list of types
|
|
||||||
let s:id_types = {}
|
|
||||||
let s:tab_id = 1
|
|
||||||
let s:keymap_arguments = ['nowait', 'silent', 'script', 'expr', 'unique']
|
|
||||||
|
|
||||||
" helper {{
|
|
||||||
" Create a window with bufnr for execute win_execute
|
|
||||||
function! s:create_popup(bufnr) abort
|
|
||||||
noa let id = popup_create(1, {
|
|
||||||
\ 'line': 1,
|
|
||||||
\ 'col': &columns,
|
|
||||||
\ 'maxwidth': 1,
|
|
||||||
\ 'maxheight': 1,
|
|
||||||
\ })
|
|
||||||
call popup_hide(id)
|
|
||||||
return id
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:check_bufnr(bufnr) abort
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
throw 'Invalid buffer id: '.a:bufnr
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" TextChanged not fired when using channel on vim.
|
|
||||||
function! s:on_textchange(bufnr) abort
|
|
||||||
let event = mode() ==# 'i' ? 'TextChangedI' : 'TextChanged'
|
|
||||||
exe 'doautocmd <nomodeline> '.event.' '.bufname(a:bufnr)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" execute command for bufnr
|
|
||||||
function! s:buf_execute(bufnr, cmds) abort
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
let winid = get(win_findbuf(a:bufnr), 0, -1)
|
|
||||||
let close = 0
|
|
||||||
if winid == -1
|
|
||||||
let winid = s:create_popup(a:bufnr)
|
|
||||||
let close = 1
|
|
||||||
endif
|
|
||||||
for cmd in a:cmds
|
|
||||||
call win_execute(winid, cmd, 'silent')
|
|
||||||
endfor
|
|
||||||
if close
|
|
||||||
noa call popup_close(winid)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:check_winid(winid) abort
|
|
||||||
if empty(getwininfo(a:winid)) && empty(popup_getpos(a:winid))
|
|
||||||
throw 'Invalid window id: '.a:winid
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:is_popup(winid) abort
|
|
||||||
try
|
|
||||||
return !empty(popup_getpos(a:winid))
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E993/
|
|
||||||
return 0
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:tabid_nr(tid) abort
|
|
||||||
for nr in range(1, tabpagenr('$'))
|
|
||||||
if gettabvar(nr, '__tid', v:null) is a:tid
|
|
||||||
return nr
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
throw 'Invalid tabpage id: '.a:tid
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:tabnr_id(nr) abort
|
|
||||||
let tid = gettabvar(a:nr, '__tid', -1)
|
|
||||||
if tid == -1
|
|
||||||
let tid = s:tab_id
|
|
||||||
call settabvar(a:nr, '__tid', tid)
|
|
||||||
let s:tab_id = s:tab_id + 1
|
|
||||||
endif
|
|
||||||
return tid
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:generate_id(bufnr) abort
|
|
||||||
let max = get(s:buffer_id, a:bufnr, s:prop_offset)
|
|
||||||
let id = max + 1
|
|
||||||
let s:buffer_id[a:bufnr] = id
|
|
||||||
return id
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:win_execute(winid, 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:winid, cmd)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:win_tabnr(winid) abort
|
|
||||||
let ref = {}
|
|
||||||
call win_execute(a:winid, 'let ref["out"] = tabpagenr()')
|
|
||||||
let tabnr = get(ref, 'out', -1)
|
|
||||||
if tabnr == -1
|
|
||||||
throw 'Invalid window id: '.a:winid
|
|
||||||
endif
|
|
||||||
return tabnr
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:buf_line_count(bufnr) abort
|
|
||||||
if bufnr('%') == a:bufnr
|
|
||||||
return line('$')
|
|
||||||
endif
|
|
||||||
if exists('*getbufinfo')
|
|
||||||
let info = getbufinfo(a:bufnr)
|
|
||||||
if empty(info)
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
" vim 8.1 has getbufinfo but no linecount
|
|
||||||
if has_key(info[0], 'linecount')
|
|
||||||
return info[0]['linecount']
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return len(getbufline(a:bufnr, 1, '$'))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:execute(cmd)
|
|
||||||
if a:cmd =~# '^echo'
|
|
||||||
execute a:cmd
|
|
||||||
else
|
|
||||||
silent! execute a:cmd
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function s:inspect_type(v) abort
|
|
||||||
let types = ['Number', 'String', 'Funcref', 'List', 'Dictionary', 'Float', 'Boolean', 'Null']
|
|
||||||
return get(types, type(a:v), 'Unknown')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:escape_space(text) abort
|
|
||||||
return substitute(a:text, ' ', '<space>', 'g')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:create_mode_prefix(mode, opts) abort
|
|
||||||
if a:mode ==# '!'
|
|
||||||
return 'map!'
|
|
||||||
endif
|
|
||||||
return get(a:opts, 'noremap', 0) ? a:mode . 'noremap' : a:mode . 'map'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:create_arguments(opts) abort
|
|
||||||
let arguments = ''
|
|
||||||
for key in keys(a:opts)
|
|
||||||
if a:opts[key] && index(s:keymap_arguments, key) != -1
|
|
||||||
let arguments .= '<'.key.'>'
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return arguments
|
|
||||||
endfunction
|
|
||||||
" }}"
|
|
||||||
|
|
||||||
" nvim client methods {{
|
|
||||||
function! s:funcs.set_current_dir(dir) abort
|
|
||||||
execute 'cd '.fnameescape(a:dir)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.set_var(name, value) abort
|
|
||||||
execute 'let g:'.a:name.'= a:value'
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.del_var(name) abort
|
|
||||||
if !has_key(g:, a:name)
|
|
||||||
throw 'Key not found: '.a:name
|
|
||||||
endif
|
|
||||||
execute 'unlet g:'.a:name
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.set_option(name, value) abort
|
|
||||||
execute 'let &'.a:name.' = a:value'
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.get_option(name)
|
|
||||||
return eval('&'.a:name)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.set_current_buf(bufnr) abort
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
execute 'buffer '.a:bufnr
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.set_current_win(winid) abort
|
|
||||||
call s:win_tabnr(a:winid)
|
|
||||||
call win_gotoid(a:winid)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.set_current_tabpage(tid) abort
|
|
||||||
let nr = s:tabid_nr(a:tid)
|
|
||||||
execute 'normal! '.nr.'gt'
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.list_wins() abort
|
|
||||||
return map(getwininfo(), 'v:val["winid"]')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.call_atomic(calls)
|
|
||||||
let results = []
|
|
||||||
for i in range(len(a:calls))
|
|
||||||
let [key, arglist] = a:calls[i]
|
|
||||||
let name = key[5:]
|
|
||||||
try
|
|
||||||
call add(results, call(s:funcs[name], arglist))
|
|
||||||
catch /.*/
|
|
||||||
return [results, [i, "VimException(".s:inspect_type(v:exception).")", v:exception . ' on function "'.name.'"']]
|
|
||||||
endtry
|
|
||||||
endfor
|
|
||||||
return [results, v:null]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.set_client_info(...) abort
|
|
||||||
" not supported
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.subscribe(...) abort
|
|
||||||
" not supported
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.unsubscribe(...) abort
|
|
||||||
" not supported
|
|
||||||
return v:null
|
|
||||||
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
|
|
||||||
if type(a:dict) == v:t_string
|
|
||||||
return call(a:method, a:args, eval(a:dict))
|
|
||||||
endif
|
|
||||||
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
|
|
||||||
let err = get(g:, 'errmsg', '')
|
|
||||||
" get error from python script run.
|
|
||||||
if !empty(err)
|
|
||||||
unlet g:errmsg
|
|
||||||
throw err
|
|
||||||
endif
|
|
||||||
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()
|
|
||||||
let channel = coc#rpc#get_channel()
|
|
||||||
if empty(channel)
|
|
||||||
throw 'Unable to get channel'
|
|
||||||
endif
|
|
||||||
return [ch_info(channel)['id'], {'functions': map(names, '{"name": "nvim_".v:val}')}]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.list_bufs()
|
|
||||||
return map(getbufinfo(), 'v:val["bufnr"]')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.feedkeys(keys, mode, escape_csi)
|
|
||||||
call feedkeys(a:keys, a:mode)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.list_runtime_paths()
|
|
||||||
return globpath(&runtimepath, '', 0, 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.command_output(cmd)
|
|
||||||
return execute(a:cmd)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.exec(code, output) abort
|
|
||||||
let cmds = split(a:code, '\n')
|
|
||||||
if a:output
|
|
||||||
return substitute(execute(cmds, 'silent!'), '^\n', '', '')
|
|
||||||
endif
|
|
||||||
call execute(cmds)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Queues raw user-input, <" is special. To input a literal "<", send <LT>.
|
|
||||||
function! s:funcs.input(keys) abort
|
|
||||||
let escaped = substitute(a:keys, '<', '\\<', 'g')
|
|
||||||
call feedkeys(eval('"'.escaped.'"'), 't')
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.create_buf(listed, scratch) abort
|
|
||||||
let bufnr = bufadd('')
|
|
||||||
call setbufvar(bufnr, '&buflisted', a:listed ? 1 : 0)
|
|
||||||
if a:scratch
|
|
||||||
call setbufvar(bufnr, '&modeline', 0)
|
|
||||||
call setbufvar(bufnr, '&buftype', 'nofile')
|
|
||||||
call setbufvar(bufnr, '&swapfile', 0)
|
|
||||||
endif
|
|
||||||
call bufload(bufnr)
|
|
||||||
return bufnr
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.get_current_line()
|
|
||||||
return getline('.')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.set_current_line(line)
|
|
||||||
call setline('.', a:line)
|
|
||||||
call s:on_textchange(bufnr('%'))
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.del_current_line()
|
|
||||||
call deletebufline('%', line('.'))
|
|
||||||
call s:on_textchange(bufnr('%'))
|
|
||||||
return v:null
|
|
||||||
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_current_buf()
|
|
||||||
return bufnr('%')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.get_current_win()
|
|
||||||
return win_getid()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.get_current_tabpage()
|
|
||||||
return s:tabnr_id(tabpagenr())
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.list_tabpages()
|
|
||||||
let ids = []
|
|
||||||
for nr in range(1, tabpagenr('$'))
|
|
||||||
call add(ids, s:tabnr_id(nr))
|
|
||||||
endfor
|
|
||||||
return ids
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.get_mode()
|
|
||||||
let m = mode()
|
|
||||||
return {'blocking': m ==# 'r' ? v:true : v:false, 'mode': m}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.strwidth(str)
|
|
||||||
return strwidth(a:str)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.out_write(str)
|
|
||||||
echon a:str
|
|
||||||
call timer_start(0, {-> s:execute('redraw')})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.err_write(str)
|
|
||||||
"echoerr a:str
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.err_writeln(str)
|
|
||||||
echohl ErrorMsg
|
|
||||||
echom a:str
|
|
||||||
echohl None
|
|
||||||
call timer_start(0, {-> s:execute('redraw')})
|
|
||||||
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
|
|
||||||
|
|
||||||
function! s:funcs.set_keymap(mode, lhs, rhs, opts) abort
|
|
||||||
let modekey = s:create_mode_prefix(a:mode, a:opts)
|
|
||||||
let arguments = s:create_arguments(a:opts)
|
|
||||||
let lhs = s:escape_space(a:lhs)
|
|
||||||
let rhs = empty(a:rhs) ? '<Nop>' : s:escape_space(a:rhs)
|
|
||||||
let cmd = modekey . ' ' . arguments .' '.lhs. ' '.rhs
|
|
||||||
execute cmd
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.del_keymap(mode, lhs) abort
|
|
||||||
let lhs = substitute(a:lhs, ' ', '<space>', 'g')
|
|
||||||
execute 'silent '.a:mode.'unmap '.lhs
|
|
||||||
return v:null
|
|
||||||
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
|
|
||||||
call setbufvar(a:bufnr, '&'.a:name, val)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_get_option(bufnr, name)
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
return getbufvar(a:bufnr, '&'.a:name)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_get_changedtick(bufnr)
|
|
||||||
return getbufvar(a:bufnr, 'changedtick')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_is_valid(bufnr)
|
|
||||||
return bufexists(a:bufnr) ? v:true : v:false
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_is_loaded(bufnr)
|
|
||||||
return bufloaded(a:bufnr) ? v:true : v:false
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_get_mark(bufnr, name)
|
|
||||||
if a:bufnr != 0 && a:bufnr != bufnr('%')
|
|
||||||
throw 'buf_get_mark support current buffer only'
|
|
||||||
endif
|
|
||||||
return [line("'" . a:name), col("'" . a:name) - 1]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_add_highlight(bufnr, srcId, hlGroup, line, colStart, colEnd, ...) abort
|
|
||||||
if a:srcId == 0
|
|
||||||
let srcId = s:max_src_id + 1
|
|
||||||
let s:max_src_id = srcId
|
|
||||||
else
|
|
||||||
let srcId = a:srcId
|
|
||||||
endif
|
|
||||||
let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
|
|
||||||
let type = srcId == -1 ? a:hlGroup : a:hlGroup.'_'.srcId
|
|
||||||
let types = get(s:id_types, srcId, [])
|
|
||||||
if index(types, type) == -1
|
|
||||||
call add(types, type)
|
|
||||||
let s:id_types[srcId] = types
|
|
||||||
if empty(prop_type_get(type))
|
|
||||||
call prop_type_add(type, extend({'highlight': a:hlGroup}, get(a:, 1, {})))
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let end = a:colEnd == -1 ? strlen(get(getbufline(bufnr, a:line + 1), 0, '')) + 1 : a:colEnd + 1
|
|
||||||
if end < a:colStart + 1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let id = s:generate_id(a:bufnr)
|
|
||||||
try
|
|
||||||
call prop_add(a:line + 1, a:colStart + 1, {'bufnr': bufnr, 'type': type, 'id': id, 'end_col': end})
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E967/
|
|
||||||
" ignore 967
|
|
||||||
endtry
|
|
||||||
if a:srcId == 0
|
|
||||||
" return generated srcId
|
|
||||||
return srcId
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_clear_namespace(bufnr, srcId, startLine, endLine) abort
|
|
||||||
let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
|
|
||||||
let start = a:startLine + 1
|
|
||||||
let end = a:endLine == -1 ? len(getbufline(bufnr, 1, '$')) : a:endLine
|
|
||||||
if a:srcId == -1
|
|
||||||
if has_key(s:buffer_id, a:bufnr)
|
|
||||||
unlet s:buffer_id[a:bufnr]
|
|
||||||
endif
|
|
||||||
call prop_clear(start, end, {'bufnr' : bufnr})
|
|
||||||
else
|
|
||||||
for type in get(s:id_types, a:srcId, [])
|
|
||||||
try
|
|
||||||
call prop_remove({'bufnr': bufnr, 'all': 1, 'type': type}, start, end)
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E968/
|
|
||||||
" ignore 968
|
|
||||||
endtry
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_line_count(bufnr) abort
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
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
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
let len = s:buf_line_count(a:bufnr)
|
|
||||||
let start = a:start < 0 ? len + a:start + 2 : a:start + 1
|
|
||||||
let end = a:end < 0 ? len + a:end + 1 : a:end
|
|
||||||
if a:strict && end > len
|
|
||||||
throw 'Index out of bounds '. end
|
|
||||||
endif
|
|
||||||
return getbufline(a:bufnr, start, end)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_set_lines(bufnr, start, end, strict, ...) abort
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
|
|
||||||
let len = s:buf_line_count(bufnr)
|
|
||||||
let startLnum = a:start < 0 ? len + a:start + 2 : a:start + 1
|
|
||||||
let endLnum = a:end < 0 ? len + a:end + 1 : a:end
|
|
||||||
if endLnum > len
|
|
||||||
if a:strict
|
|
||||||
throw 'Index out of bounds '. end
|
|
||||||
else
|
|
||||||
let endLnum = len
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let delCount = endLnum - (startLnum - 1)
|
|
||||||
let view = bufnr == bufnr('%') ? winsaveview() : v:null
|
|
||||||
let replacement = get(a:, 1, [])
|
|
||||||
if delCount == len(replacement)
|
|
||||||
call setbufline(bufnr, startLnum, replacement)
|
|
||||||
else
|
|
||||||
if len(replacement)
|
|
||||||
call appendbufline(bufnr, startLnum - 1, replacement)
|
|
||||||
endif
|
|
||||||
if delCount
|
|
||||||
let start = startLnum + len(replacement)
|
|
||||||
silent call deletebufline(bufnr, start, start + delCount - 1)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if view isnot v:null
|
|
||||||
call winrestview(view)
|
|
||||||
endif
|
|
||||||
call s:on_textchange(a:bufnr)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_set_name(bufnr, name) abort
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
call s:buf_execute(a:bufnr, [
|
|
||||||
\ 'noa 0f',
|
|
||||||
\ 'file '.fnameescape(a:name)
|
|
||||||
\ ])
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_get_name(bufnr)
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
return bufname(a:bufnr)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_get_var(bufnr, name)
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
if !has_key(b:, a:name)
|
|
||||||
throw 'Key not found: '.a:name
|
|
||||||
endif
|
|
||||||
return getbufvar(a:bufnr, a:name)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_set_var(bufnr, name, val)
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
call setbufvar(a:bufnr, a:name, a:val)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_del_var(bufnr, name)
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
if a:bufnr == bufnr('%')
|
|
||||||
execute 'unlet! b:'.a:name
|
|
||||||
else
|
|
||||||
call s:buf_execute(a:bufnr, ['unlet! b:'.a:name])
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_set_keymap(bufnr, mode, lhs, rhs, opts) abort
|
|
||||||
let modekey = s:create_mode_prefix(a:mode, a:opts)
|
|
||||||
let arguments = s:create_arguments(a:opts)
|
|
||||||
let lhs = s:escape_space(a:lhs)
|
|
||||||
let rhs = empty(a:rhs) ? '<Nop>' : s:escape_space(a:rhs)
|
|
||||||
let cmd = modekey . ' ' . arguments .'<buffer> '.lhs. ' '.rhs
|
|
||||||
if bufnr('%') == a:bufnr || a:bufnr == 0
|
|
||||||
execute cmd
|
|
||||||
else
|
|
||||||
call s:buf_execute(a:bufnr, [cmd])
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.buf_del_keymap(bufnr, mode, lhs) abort
|
|
||||||
let lhs = substitute(a:lhs, ' ', '<space>', 'g')
|
|
||||||
let cmd = 'silent '.a:mode.'unmap <buffer> '.lhs
|
|
||||||
if bufnr('%') == a:bufnr || a:bufnr == 0
|
|
||||||
execute cmd
|
|
||||||
else
|
|
||||||
call s:buf_execute(a:bufnr, [cmd])
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
" }}
|
|
||||||
|
|
||||||
" window methods {{
|
|
||||||
function! s:funcs.win_get_buf(winid)
|
|
||||||
call s:check_winid(a:winid)
|
|
||||||
return winbufnr(a:winid)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_set_buf(winid, bufnr) abort
|
|
||||||
call s:check_winid(a:winid)
|
|
||||||
call s:check_bufnr(a:bufnr)
|
|
||||||
call s:win_execute(a:winid, 'buffer '.a:bufnr)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_get_position(winid) abort
|
|
||||||
let [row, col] = win_screenpos(a:winid)
|
|
||||||
if row == 0 && col == 0
|
|
||||||
throw 'Invalid window '.a:winid
|
|
||||||
endif
|
|
||||||
return [row - 1, col - 1]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_set_height(winid, height) abort
|
|
||||||
call s:check_winid(a:winid)
|
|
||||||
if s:is_popup(a:winid)
|
|
||||||
call popup_move(a:winid, {'maxheight': a:height, 'minheight': a:height})
|
|
||||||
else
|
|
||||||
call s:win_execute(a:winid, 'resize '.a:height)
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_get_height(winid) abort
|
|
||||||
call s:check_winid(a:winid)
|
|
||||||
if s:is_popup(a:winid)
|
|
||||||
return popup_getpos(a:winid)['height']
|
|
||||||
endif
|
|
||||||
return winheight(a:winid)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_set_width(winid, width) abort
|
|
||||||
call s:check_winid(a:winid)
|
|
||||||
if s:is_popup(a:winid)
|
|
||||||
call popup_move(a:winid, {'maxwidth': a:width, 'minwidth': a:width})
|
|
||||||
else
|
|
||||||
call s:win_execute(a:winid, 'vertical resize '.a:width)
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_get_width(winid) abort
|
|
||||||
call s:check_winid(a:winid)
|
|
||||||
if s:is_popup(a:winid)
|
|
||||||
return popup_getpos(a:winid)['width']
|
|
||||||
endif
|
|
||||||
return winwidth(a:winid)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_set_cursor(winid, pos) abort
|
|
||||||
call s:check_winid(a:winid)
|
|
||||||
let [line, col] = a:pos
|
|
||||||
call s:win_execute(a:winid, 'call cursor('.line.','.(col + 1).')')
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_get_cursor(winid) abort
|
|
||||||
call s:check_winid(a:winid)
|
|
||||||
let ref = {}
|
|
||||||
call s:win_execute(a:winid, "[line('.'), col('.')-1]", ref)
|
|
||||||
return get(ref, 'out', [1, 0])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_set_option(winid, name, value) abort
|
|
||||||
let tabnr = s:win_tabnr(a:winid)
|
|
||||||
let val = a:value
|
|
||||||
if val is v:true
|
|
||||||
let val = 1
|
|
||||||
elseif val is v:false
|
|
||||||
let val = 0
|
|
||||||
endif
|
|
||||||
call settabwinvar(tabnr, a:winid, '&'.a:name, val)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_get_option(winid, name, ...) abort
|
|
||||||
let tabnr = s:win_tabnr(a:winid)
|
|
||||||
let result = gettabwinvar(tabnr, a:winid, '&'.a:name, get(a:, 1, v:null))
|
|
||||||
if result is v:null
|
|
||||||
throw "Invalid option name: '".a:name."'"
|
|
||||||
endif
|
|
||||||
return result
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_get_var(winid, name, ...) abort
|
|
||||||
let tabnr = s:win_tabnr(a:winid)
|
|
||||||
return gettabwinvar(tabnr, a:winid, a:name, get(a:, 1, v:null))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_set_var(winid, name, value) abort
|
|
||||||
let tabnr = s:win_tabnr(a:winid)
|
|
||||||
call settabwinvar(tabnr, a:winid, a:name, a:value)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_del_var(winid, name) abort
|
|
||||||
call s:check_winid(a:winid)
|
|
||||||
call win_execute(a:winid, 'unlet! w:'.a:name)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_is_valid(winid) abort
|
|
||||||
let invalid = empty(getwininfo(a:winid)) && empty(popup_getpos(a:winid))
|
|
||||||
return invalid ? v:false : v:true
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Not work for popup
|
|
||||||
function! s:funcs.win_get_number(winid) abort
|
|
||||||
if s:is_popup(a:winid)
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
let info = getwininfo(a:winid)
|
|
||||||
if empty(info)
|
|
||||||
throw 'Invalid window id '.a:winid
|
|
||||||
endif
|
|
||||||
return info[0]['winnr']
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_get_tabpage(winid) abort
|
|
||||||
let nr = s:win_tabnr(a:winid)
|
|
||||||
return s:tabnr_id(nr)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.win_close(winid, ...) abort
|
|
||||||
call s:check_winid(a:winid)
|
|
||||||
let force = get(a:, 1, 0)
|
|
||||||
if s:is_popup(a:winid)
|
|
||||||
call popup_close(a:winid)
|
|
||||||
else
|
|
||||||
call s:win_execute(a:winid, 'close'.(force ? '!' : ''))
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
" }}
|
|
||||||
|
|
||||||
" tabpage methods {{
|
|
||||||
function! s:funcs.tabpage_get_number(tid)
|
|
||||||
return s:tabid_nr(a:tid)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.tabpage_list_wins(tid)
|
|
||||||
let nr = s:tabid_nr(a:tid)
|
|
||||||
return gettabinfo(nr)[0]['windows']
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.tabpage_get_var(tid, name)
|
|
||||||
let nr = s:tabid_nr(a:tid)
|
|
||||||
return gettabvar(nr, a:name, v:null)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.tabpage_set_var(tid, name, value)
|
|
||||||
let nr = s:tabid_nr(a:tid)
|
|
||||||
call settabvar(nr, a:name, a:value)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.tabpage_del_var(tid, name)
|
|
||||||
let nr = s:tabid_nr(a:tid)
|
|
||||||
call settabvar(nr, a:name, v:null)
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.tabpage_is_valid(tid)
|
|
||||||
for nr in range(1, tabpagenr('$'))
|
|
||||||
if gettabvar(nr, '__tid', -1) == a:tid
|
|
||||||
return v:true
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return v:false
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:funcs.tabpage_get_win(tid)
|
|
||||||
let nr = s:tabid_nr(a:tid)
|
|
||||||
return win_getid(tabpagewinnr(nr), nr)
|
|
||||||
endfunction
|
|
||||||
" }}
|
|
||||||
|
|
||||||
function! coc#api#get_types(srcId) abort
|
|
||||||
return get(s:id_types, a:srcId, [])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#api#get_id_types() abort
|
|
||||||
return s:id_types
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#api#create_type(srcId, hlGroup, opts) abort
|
|
||||||
let type = a:hlGroup.'_'.a:srcId
|
|
||||||
let types = get(s:id_types, a:srcId, [])
|
|
||||||
if index(types, type) == -1
|
|
||||||
call add(types, type)
|
|
||||||
let s:id_types[a:srcId] = types
|
|
||||||
let combine = get(a:opts, 'hl_mode', 'combine') ==# 'combine'
|
|
||||||
call prop_type_add(type, {'highlight': a:hlGroup, 'combine': combine})
|
|
||||||
endif
|
|
||||||
return type
|
|
||||||
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 .' on api "'.a:method.'" '.json_encode(a:args)
|
|
||||||
endtry
|
|
||||||
return [err, res]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#api#exec(method, args) abort
|
|
||||||
return call(s:funcs[a:method], a:args)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#api#notify(method, args) abort
|
|
||||||
try
|
|
||||||
call call(s:funcs[a:method], a:args)
|
|
||||||
catch /.*/
|
|
||||||
call coc#rpc#notify('nvim_error_event', [0, v:exception.' on api "'.a:method.'" '.json_encode(a:args)])
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" create id for all tabpages
|
|
||||||
function! coc#api#tabpage_ids() abort
|
|
||||||
for nr in range(1, tabpagenr('$'))
|
|
||||||
if gettabvar(nr, '__tid', -1) == -1
|
|
||||||
call settabvar(nr, '__tid', s:tab_id)
|
|
||||||
let s:tab_id = s:tab_id + 1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#api#get_tabid(nr) abort
|
|
||||||
return s:tabnr_id(a:nr)
|
|
||||||
endfunction
|
|
||||||
" vim: set sw=2 ts=2 sts=2 et tw=78 foldmarker={{,}} foldmethod=marker foldlevel=0:
|
|
|
@ -1,386 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:root = expand('<sfile>: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)
|
|
||||||
echohl WarningMsg | echo '[coc.nvim] Enable g:node_client_debug could impact your vim experience' | echohl None
|
|
||||||
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())
|
|
||||||
echoerr '[coc.nvim] Current cwd is not a valid directory.'
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let tmpdir = fnamemodify(tempname(), ':p:h')
|
|
||||||
if s:is_vim
|
|
||||||
if get(g:, 'node_client_debug', 0)
|
|
||||||
let file = tmpdir . '/coc.log'
|
|
||||||
call ch_logfile(file, 'w')
|
|
||||||
echohl MoreMsg | echo '[coc.nvim] channel log to '.file | echohl None
|
|
||||||
endif
|
|
||||||
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',
|
|
||||||
\ '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 = {}
|
|
||||||
let opts = {
|
|
||||||
\ 'rpc': 1,
|
|
||||||
\ 'on_stderr': {channel, msgs -> s:on_stderr(self.name, msgs)},
|
|
||||||
\ 'on_exit': {channel, code -> s:on_exit(self.name, code)},
|
|
||||||
\ }
|
|
||||||
if has('nvim-0.5.0')
|
|
||||||
" could use env option
|
|
||||||
let opts['env'] = {
|
|
||||||
\ 'NODE_NO_WARNINGS': '1',
|
|
||||||
\ 'TMPDIR': tmpdir
|
|
||||||
\ }
|
|
||||||
else
|
|
||||||
let original = {
|
|
||||||
\ 'NODE_NO_WARNINGS': getenv('NODE_NO_WARNINGS'),
|
|
||||||
\ 'TMPDIR': getenv('TMPDIR'),
|
|
||||||
\ }
|
|
||||||
call setenv('NODE_NO_WARNINGS', '1')
|
|
||||||
call setenv('TMPDIR', tmpdir)
|
|
||||||
endif
|
|
||||||
let chan_id = jobstart(self.command, opts)
|
|
||||||
if !empty(original)
|
|
||||||
for key in keys(original)
|
|
||||||
call setenv(key, original[key])
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
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
|
|
||||||
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]
|
|
||||||
if a:name ==# 'coc' && len(filter(copy(data), 'v:val =~# "SyntaxError: "'))
|
|
||||||
call coc#client#check_version()
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if get(g:, 'coc_disable_uncaught_error', 0) | return | endif
|
|
||||||
call s:on_error(a:name, data)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#client#check_version() abort
|
|
||||||
if (has_key(g:, 'coc_node_path'))
|
|
||||||
let node = expand(g:coc_node_path)
|
|
||||||
else
|
|
||||||
let node = $COC_NODE_PATH == '' ? 'node' : $COC_NODE_PATH
|
|
||||||
endif
|
|
||||||
let cmd = node . ' --version'
|
|
||||||
let output = system(cmd)
|
|
||||||
let msgs = []
|
|
||||||
if v:shell_error
|
|
||||||
let msgs = ['Unexpected result from "'.cmd.'"'] + split(output, '\n')
|
|
||||||
else
|
|
||||||
let ms = matchlist(output, 'v\(\d\+\).\(\d\+\).\(\d\+\)')
|
|
||||||
if empty(ms)
|
|
||||||
let msgs = ['Unable to get node version by "'.cmd.'" please install NodeJS from https://nodejs.org/en/download/']
|
|
||||||
elseif str2nr(ms[1]) < 14 || (str2nr(ms[1]) == 14 && str2nr(ms[2]) < 14)
|
|
||||||
let msgs = ['Current Node.js version '.trim(output).' < 14.14.0 ', 'Please upgrade your .js']
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if !empty(msgs)
|
|
||||||
call s:on_error('coc', msgs)
|
|
||||||
endif
|
|
||||||
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 'Error on "'.a:method.'" request: '.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
|
|
||||||
if s:is_vim
|
|
||||||
throw v:exception
|
|
||||||
else
|
|
||||||
throw 'Error on request: '.v:exception
|
|
||||||
endif
|
|
||||||
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
|
|
||||||
try
|
|
||||||
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
|
|
||||||
catch /.*/
|
|
||||||
return 0
|
|
||||||
endtry
|
|
||||||
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#kill(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 empty(client) || exists('$COC_NVIM_REMOTE_ADDRESS')
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
if running
|
|
||||||
if s:is_vim
|
|
||||||
call job_stop(ch_getjob(client['channel']), 'kill')
|
|
||||||
else
|
|
||||||
call jobstop(client['chan_id'])
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
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 enable debug mode.' | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
execute 'vs '.s:logfile
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:on_error(name, msgs) abort
|
|
||||||
echohl ErrorMsg
|
|
||||||
echo join(a:msgs, "\n")
|
|
||||||
echohl None
|
|
||||||
let client = get(s:clients, a:name, v:null)
|
|
||||||
if !empty(client)
|
|
||||||
let errors = get(client, 'stderr', [])
|
|
||||||
call extend(errors, a:msgs)
|
|
||||||
let client['stderr'] = errors
|
|
||||||
endif
|
|
||||||
endfunction
|
|
|
@ -1,610 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
|
|
||||||
let s:activate = ""
|
|
||||||
let s:quit = ""
|
|
||||||
if has("gui_macvim") && has('gui_running')
|
|
||||||
let s:app = "MacVim"
|
|
||||||
elseif $TERM_PROGRAM ==# "Apple_Terminal"
|
|
||||||
let s:app = "Terminal"
|
|
||||||
elseif $TERM_PROGRAM ==# "iTerm.app"
|
|
||||||
let s:app = "iTerm2"
|
|
||||||
elseif has('mac')
|
|
||||||
let s:app = "System Events"
|
|
||||||
let s:quit = "quit"
|
|
||||||
let s:activate = 'activate'
|
|
||||||
endif
|
|
||||||
|
|
||||||
let s:patterns = {}
|
|
||||||
let s:patterns['hex'] = '\v#?(\x{2})(\x{2})(\x{2})'
|
|
||||||
let s:patterns['shortHex'] = '\v#(\x{1})(\x{1})(\x{1})'
|
|
||||||
|
|
||||||
let s:xterm_colors = {
|
|
||||||
\ '0': '#000000', '1': '#800000', '2': '#008000', '3': '#808000', '4': '#000080',
|
|
||||||
\ '5': '#800080', '6': '#008080', '7': '#c0c0c0', '8': '#808080', '9': '#ff0000',
|
|
||||||
\ '10': '#00ff00', '11': '#ffff00', '12': '#0000ff', '13': '#ff00ff', '14': '#00ffff',
|
|
||||||
\ '15': '#ffffff', '16': '#000000', '17': '#00005f', '18': '#000087', '19': '#0000af',
|
|
||||||
\ '20': '#0000df', '21': '#0000ff', '22': '#005f00', '23': '#005f5f', '24': '#005f87',
|
|
||||||
\ '25': '#005faf', '26': '#005fdf', '27': '#005fff', '28': '#008700', '29': '#00875f',
|
|
||||||
\ '30': '#008787', '31': '#0087af', '32': '#0087df', '33': '#0087ff', '34': '#00af00',
|
|
||||||
\ '35': '#00af5f', '36': '#00af87', '37': '#00afaf', '38': '#00afdf', '39': '#00afff',
|
|
||||||
\ '40': '#00df00', '41': '#00df5f', '42': '#00df87', '43': '#00dfaf', '44': '#00dfdf',
|
|
||||||
\ '45': '#00dfff', '46': '#00ff00', '47': '#00ff5f', '48': '#00ff87', '49': '#00ffaf',
|
|
||||||
\ '50': '#00ffdf', '51': '#00ffff', '52': '#5f0000', '53': '#5f005f', '54': '#5f0087',
|
|
||||||
\ '55': '#5f00af', '56': '#5f00df', '57': '#5f00ff', '58': '#5f5f00', '59': '#5f5f5f',
|
|
||||||
\ '60': '#5f5f87', '61': '#5f5faf', '62': '#5f5fdf', '63': '#5f5fff', '64': '#5f8700',
|
|
||||||
\ '65': '#5f875f', '66': '#5f8787', '67': '#5f87af', '68': '#5f87df', '69': '#5f87ff',
|
|
||||||
\ '70': '#5faf00', '71': '#5faf5f', '72': '#5faf87', '73': '#5fafaf', '74': '#5fafdf',
|
|
||||||
\ '75': '#5fafff', '76': '#5fdf00', '77': '#5fdf5f', '78': '#5fdf87', '79': '#5fdfaf',
|
|
||||||
\ '80': '#5fdfdf', '81': '#5fdfff', '82': '#5fff00', '83': '#5fff5f', '84': '#5fff87',
|
|
||||||
\ '85': '#5fffaf', '86': '#5fffdf', '87': '#5fffff', '88': '#870000', '89': '#87005f',
|
|
||||||
\ '90': '#870087', '91': '#8700af', '92': '#8700df', '93': '#8700ff', '94': '#875f00',
|
|
||||||
\ '95': '#875f5f', '96': '#875f87', '97': '#875faf', '98': '#875fdf', '99': '#875fff',
|
|
||||||
\ '100': '#878700', '101': '#87875f', '102': '#878787', '103': '#8787af', '104': '#8787df',
|
|
||||||
\ '105': '#8787ff', '106': '#87af00', '107': '#87af5f', '108': '#87af87', '109': '#87afaf',
|
|
||||||
\ '110': '#87afdf', '111': '#87afff', '112': '#87df00', '113': '#87df5f', '114': '#87df87',
|
|
||||||
\ '115': '#87dfaf', '116': '#87dfdf', '117': '#87dfff', '118': '#87ff00', '119': '#87ff5f',
|
|
||||||
\ '120': '#87ff87', '121': '#87ffaf', '122': '#87ffdf', '123': '#87ffff', '124': '#af0000',
|
|
||||||
\ '125': '#af005f', '126': '#af0087', '127': '#af00af', '128': '#af00df', '129': '#af00ff',
|
|
||||||
\ '130': '#af5f00', '131': '#af5f5f', '132': '#af5f87', '133': '#af5faf', '134': '#af5fdf',
|
|
||||||
\ '135': '#af5fff', '136': '#af8700', '137': '#af875f', '138': '#af8787', '139': '#af87af',
|
|
||||||
\ '140': '#af87df', '141': '#af87ff', '142': '#afaf00', '143': '#afaf5f', '144': '#afaf87',
|
|
||||||
\ '145': '#afafaf', '146': '#afafdf', '147': '#afafff', '148': '#afdf00', '149': '#afdf5f',
|
|
||||||
\ '150': '#afdf87', '151': '#afdfaf', '152': '#afdfdf', '153': '#afdfff', '154': '#afff00',
|
|
||||||
\ '155': '#afff5f', '156': '#afff87', '157': '#afffaf', '158': '#afffdf', '159': '#afffff',
|
|
||||||
\ '160': '#df0000', '161': '#df005f', '162': '#df0087', '163': '#df00af', '164': '#df00df',
|
|
||||||
\ '165': '#df00ff', '166': '#df5f00', '167': '#df5f5f', '168': '#df5f87', '169': '#df5faf',
|
|
||||||
\ '170': '#df5fdf', '171': '#df5fff', '172': '#df8700', '173': '#df875f', '174': '#df8787',
|
|
||||||
\ '175': '#df87af', '176': '#df87df', '177': '#df87ff', '178': '#dfaf00', '179': '#dfaf5f',
|
|
||||||
\ '180': '#dfaf87', '181': '#dfafaf', '182': '#dfafdf', '183': '#dfafff', '184': '#dfdf00',
|
|
||||||
\ '185': '#dfdf5f', '186': '#dfdf87', '187': '#dfdfaf', '188': '#dfdfdf', '189': '#dfdfff',
|
|
||||||
\ '190': '#dfff00', '191': '#dfff5f', '192': '#dfff87', '193': '#dfffaf', '194': '#dfffdf',
|
|
||||||
\ '195': '#dfffff', '196': '#ff0000', '197': '#ff005f', '198': '#ff0087', '199': '#ff00af',
|
|
||||||
\ '200': '#ff00df', '201': '#ff00ff', '202': '#ff5f00', '203': '#ff5f5f', '204': '#ff5f87',
|
|
||||||
\ '205': '#ff5faf', '206': '#ff5fdf', '207': '#ff5fff', '208': '#ff8700', '209': '#ff875f',
|
|
||||||
\ '210': '#ff8787', '211': '#ff87af', '212': '#ff87df', '213': '#ff87ff', '214': '#ffaf00',
|
|
||||||
\ '215': '#ffaf5f', '216': '#ffaf87', '217': '#ffafaf', '218': '#ffafdf', '219': '#ffafff',
|
|
||||||
\ '220': '#ffdf00', '221': '#ffdf5f', '222': '#ffdf87', '223': '#ffdfaf', '224': '#ffdfdf',
|
|
||||||
\ '225': '#ffdfff', '226': '#ffff00', '227': '#ffff5f', '228': '#ffff87', '229': '#ffffaf',
|
|
||||||
\ '230': '#ffffdf', '231': '#ffffff', '232': '#080808', '233': '#121212', '234': '#1c1c1c',
|
|
||||||
\ '235': '#262626', '236': '#303030', '237': '#3a3a3a', '238': '#444444', '239': '#4e4e4e',
|
|
||||||
\ '240': '#585858', '241': '#606060', '242': '#666666', '243': '#767676', '244': '#808080',
|
|
||||||
\ '245': '#8a8a8a', '246': '#949494', '247': '#9e9e9e', '248': '#a8a8a8', '249': '#b2b2b2',
|
|
||||||
\ '250': '#bcbcbc', '251': '#c6c6c6', '252': '#d0d0d0', '253': '#dadada', '254': '#e4e4e4',
|
|
||||||
\ '255': '#eeeeee'}
|
|
||||||
|
|
||||||
let s:xterm_16colors = {
|
|
||||||
\ 'black': '#000000',
|
|
||||||
\ 'darkblue': '#00008B',
|
|
||||||
\ 'darkgreen': '#00CD00',
|
|
||||||
\ 'darkcyan': '#00CDCD',
|
|
||||||
\ 'darkred': '#CD0000',
|
|
||||||
\ 'darkmagenta': '#8B008B',
|
|
||||||
\ 'brown': '#CDCD00',
|
|
||||||
\ 'darkyellow': '#CDCD00',
|
|
||||||
\ 'lightgrey': '#E5E5E5',
|
|
||||||
\ 'lightgray': '#E5E5E5',
|
|
||||||
\ 'gray': '#E5E5E5',
|
|
||||||
\ 'grey': '#E5E5E5',
|
|
||||||
\ 'darkgrey': '#7F7F7F',
|
|
||||||
\ 'darkgray': '#7F7F7F',
|
|
||||||
\ 'blue': '#5C5CFF',
|
|
||||||
\ 'lightblue': '#5C5CFF',
|
|
||||||
\ 'green': '#00FF00',
|
|
||||||
\ 'lightgreen': '#00FF00',
|
|
||||||
\ 'cyan': '#00FFFF',
|
|
||||||
\ 'lightcyan': '#00FFFF',
|
|
||||||
\ 'red': '#FF0000',
|
|
||||||
\ 'lightred': '#FF0000',
|
|
||||||
\ 'magenta': '#FF00FF',
|
|
||||||
\ 'lightmagenta': '#FF00FF',
|
|
||||||
\ 'yellow': '#FFFF00',
|
|
||||||
\ 'lightyellow': '#FFFF00',
|
|
||||||
\ 'white': '#FFFFFF',
|
|
||||||
\ }
|
|
||||||
|
|
||||||
let s:w3c_color_names = {
|
|
||||||
\ 'aliceblue': '#F0F8FF',
|
|
||||||
\ 'antiquewhite': '#FAEBD7',
|
|
||||||
\ 'aqua': '#00FFFF',
|
|
||||||
\ 'aquamarine': '#7FFFD4',
|
|
||||||
\ 'azure': '#F0FFFF',
|
|
||||||
\ 'beige': '#F5F5DC',
|
|
||||||
\ 'bisque': '#FFE4C4',
|
|
||||||
\ 'black': '#000000',
|
|
||||||
\ 'blanchedalmond': '#FFEBCD',
|
|
||||||
\ 'blue': '#0000FF',
|
|
||||||
\ 'blueviolet': '#8A2BE2',
|
|
||||||
\ 'brown': '#A52A2A',
|
|
||||||
\ 'burlywood': '#DEB887',
|
|
||||||
\ 'cadetblue': '#5F9EA0',
|
|
||||||
\ 'chartreuse': '#7FFF00',
|
|
||||||
\ 'chocolate': '#D2691E',
|
|
||||||
\ 'coral': '#FF7F50',
|
|
||||||
\ 'cornflowerblue': '#6495ED',
|
|
||||||
\ 'cornsilk': '#FFF8DC',
|
|
||||||
\ 'crimson': '#DC143C',
|
|
||||||
\ 'cyan': '#00FFFF',
|
|
||||||
\ 'darkblue': '#00008B',
|
|
||||||
\ 'darkcyan': '#008B8B',
|
|
||||||
\ 'darkgoldenrod': '#B8860B',
|
|
||||||
\ 'darkgray': '#A9A9A9',
|
|
||||||
\ 'darkgreen': '#006400',
|
|
||||||
\ 'darkkhaki': '#BDB76B',
|
|
||||||
\ 'darkmagenta': '#8B008B',
|
|
||||||
\ 'darkolivegreen': '#556B2F',
|
|
||||||
\ 'darkorange': '#FF8C00',
|
|
||||||
\ 'darkorchid': '#9932CC',
|
|
||||||
\ 'darkred': '#8B0000',
|
|
||||||
\ 'darksalmon': '#E9967A',
|
|
||||||
\ 'darkseagreen': '#8FBC8F',
|
|
||||||
\ 'darkslateblue': '#483D8B',
|
|
||||||
\ 'darkslategray': '#2F4F4F',
|
|
||||||
\ 'darkturquoise': '#00CED1',
|
|
||||||
\ 'darkviolet': '#9400D3',
|
|
||||||
\ 'deeppink': '#FF1493',
|
|
||||||
\ 'deepskyblue': '#00BFFF',
|
|
||||||
\ 'dimgray': '#696969',
|
|
||||||
\ 'dodgerblue': '#1E90FF',
|
|
||||||
\ 'firebrick': '#B22222',
|
|
||||||
\ 'floralwhite': '#FFFAF0',
|
|
||||||
\ 'forestgreen': '#228B22',
|
|
||||||
\ 'fuchsia': '#FF00FF',
|
|
||||||
\ 'gainsboro': '#DCDCDC',
|
|
||||||
\ 'ghostwhite': '#F8F8FF',
|
|
||||||
\ 'gold': '#FFD700',
|
|
||||||
\ 'goldenrod': '#DAA520',
|
|
||||||
\ 'gray': '#808080',
|
|
||||||
\ 'green': '#008000',
|
|
||||||
\ 'greenyellow': '#ADFF2F',
|
|
||||||
\ 'honeydew': '#F0FFF0',
|
|
||||||
\ 'hotpink': '#FF69B4',
|
|
||||||
\ 'indianred': '#CD5C5C',
|
|
||||||
\ 'indigo': '#4B0082',
|
|
||||||
\ 'ivory': '#FFFFF0',
|
|
||||||
\ 'khaki': '#F0E68C',
|
|
||||||
\ 'lavender': '#E6E6FA',
|
|
||||||
\ 'lavenderblush': '#FFF0F5',
|
|
||||||
\ 'lawngreen': '#7CFC00',
|
|
||||||
\ 'lemonchiffon': '#FFFACD',
|
|
||||||
\ 'lightblue': '#ADD8E6',
|
|
||||||
\ 'lightcoral': '#F08080',
|
|
||||||
\ 'lightcyan': '#E0FFFF',
|
|
||||||
\ 'lightgoldenrodyellow': '#FAFAD2',
|
|
||||||
\ 'lightgray': '#D3D3D3',
|
|
||||||
\ 'lightgreen': '#90EE90',
|
|
||||||
\ 'lightpink': '#FFB6C1',
|
|
||||||
\ 'lightsalmon': '#FFA07A',
|
|
||||||
\ 'lightseagreen': '#20B2AA',
|
|
||||||
\ 'lightskyblue': '#87CEFA',
|
|
||||||
\ 'lightslategray': '#778899',
|
|
||||||
\ 'lightsteelblue': '#B0C4DE',
|
|
||||||
\ 'lightyellow': '#FFFFE0',
|
|
||||||
\ 'lime': '#00FF00',
|
|
||||||
\ 'limegreen': '#32CD32',
|
|
||||||
\ 'linen': '#FAF0E6',
|
|
||||||
\ 'magenta': '#FF00FF',
|
|
||||||
\ 'maroon': '#800000',
|
|
||||||
\ 'mediumaquamarine': '#66CDAA',
|
|
||||||
\ 'mediumblue': '#0000CD',
|
|
||||||
\ 'mediumorchid': '#BA55D3',
|
|
||||||
\ 'mediumpurple': '#9370D8',
|
|
||||||
\ 'mediumseagreen': '#3CB371',
|
|
||||||
\ 'mediumslateblue': '#7B68EE',
|
|
||||||
\ 'mediumspringgreen': '#00FA9A',
|
|
||||||
\ 'mediumturquoise': '#48D1CC',
|
|
||||||
\ 'mediumvioletred': '#C71585',
|
|
||||||
\ 'midnightblue': '#191970',
|
|
||||||
\ 'mintcream': '#F5FFFA',
|
|
||||||
\ 'mistyrose': '#FFE4E1',
|
|
||||||
\ 'moccasin': '#FFE4B5',
|
|
||||||
\ 'navajowhite': '#FFDEAD',
|
|
||||||
\ 'navy': '#000080',
|
|
||||||
\ 'oldlace': '#FDF5E6',
|
|
||||||
\ 'olive': '#808000',
|
|
||||||
\ 'olivedrab': '#6B8E23',
|
|
||||||
\ 'orange': '#FFA500',
|
|
||||||
\ 'orangered': '#FF4500',
|
|
||||||
\ 'orchid': '#DA70D6',
|
|
||||||
\ 'palegoldenrod': '#EEE8AA',
|
|
||||||
\ 'palegreen': '#98FB98',
|
|
||||||
\ 'paleturquoise': '#AFEEEE',
|
|
||||||
\ 'palevioletred': '#D87093',
|
|
||||||
\ 'papayawhip': '#FFEFD5',
|
|
||||||
\ 'peachpuff': '#FFDAB9',
|
|
||||||
\ 'peru': '#CD853F',
|
|
||||||
\ 'pink': '#FFC0CB',
|
|
||||||
\ 'plum': '#DDA0DD',
|
|
||||||
\ 'powderblue': '#B0E0E6',
|
|
||||||
\ 'purple': '#800080',
|
|
||||||
\ 'red': '#FF0000',
|
|
||||||
\ 'rosybrown': '#BC8F8F',
|
|
||||||
\ 'royalblue': '#4169E1',
|
|
||||||
\ 'saddlebrown': '#8B4513',
|
|
||||||
\ 'salmon': '#FA8072',
|
|
||||||
\ 'sandybrown': '#F4A460',
|
|
||||||
\ 'seagreen': '#2E8B57',
|
|
||||||
\ 'seashell': '#FFF5EE',
|
|
||||||
\ 'sienna': '#A0522D',
|
|
||||||
\ 'silver': '#C0C0C0',
|
|
||||||
\ 'skyblue': '#87CEEB',
|
|
||||||
\ 'slateblue': '#6A5ACD',
|
|
||||||
\ 'slategray': '#708090',
|
|
||||||
\ 'snow': '#FFFAFA',
|
|
||||||
\ 'springgreen': '#00FF7F',
|
|
||||||
\ 'steelblue': '#4682B4',
|
|
||||||
\ 'tan': '#D2B48C',
|
|
||||||
\ 'teal': '#008080',
|
|
||||||
\ 'thistle': '#D8BFD8',
|
|
||||||
\ 'tomato': '#FF6347',
|
|
||||||
\ 'turquoise': '#40E0D0',
|
|
||||||
\ 'violet': '#EE82EE',
|
|
||||||
\ 'wheat': '#F5DEB3',
|
|
||||||
\ 'white': '#FFFFFF',
|
|
||||||
\ 'whitesmoke': '#F5F5F5',
|
|
||||||
\ 'yellow': '#FFFF00',
|
|
||||||
\ 'yellowgreen': '#9ACD32'
|
|
||||||
\ }
|
|
||||||
|
|
||||||
" Returns an approximate grey index for the given grey level
|
|
||||||
fun! s:grey_number(x)
|
|
||||||
if &t_Co == 88
|
|
||||||
if a:x < 23
|
|
||||||
return 0
|
|
||||||
elseif a:x < 69
|
|
||||||
return 1
|
|
||||||
elseif a:x < 103
|
|
||||||
return 2
|
|
||||||
elseif a:x < 127
|
|
||||||
return 3
|
|
||||||
elseif a:x < 150
|
|
||||||
return 4
|
|
||||||
elseif a:x < 173
|
|
||||||
return 5
|
|
||||||
elseif a:x < 196
|
|
||||||
return 6
|
|
||||||
elseif a:x < 219
|
|
||||||
return 7
|
|
||||||
elseif a:x < 243
|
|
||||||
return 8
|
|
||||||
else
|
|
||||||
return 9
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if a:x < 14
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
let l:n = (a:x - 8) / 10
|
|
||||||
let l:m = (a:x - 8) % 10
|
|
||||||
if l:m < 5
|
|
||||||
return l:n
|
|
||||||
else
|
|
||||||
return l:n + 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfun
|
|
||||||
|
|
||||||
" Returns the actual grey level represented by the grey index
|
|
||||||
fun! s:grey_level(n)
|
|
||||||
if &t_Co == 88
|
|
||||||
if a:n == 0
|
|
||||||
return 0
|
|
||||||
elseif a:n == 1
|
|
||||||
return 46
|
|
||||||
elseif a:n == 2
|
|
||||||
return 92
|
|
||||||
elseif a:n == 3
|
|
||||||
return 115
|
|
||||||
elseif a:n == 4
|
|
||||||
return 139
|
|
||||||
elseif a:n == 5
|
|
||||||
return 162
|
|
||||||
elseif a:n == 6
|
|
||||||
return 185
|
|
||||||
elseif a:n == 7
|
|
||||||
return 208
|
|
||||||
elseif a:n == 8
|
|
||||||
return 231
|
|
||||||
else
|
|
||||||
return 255
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if a:n == 0
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 8 + (a:n * 10)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfun
|
|
||||||
|
|
||||||
" Returns the palette index for the given grey index
|
|
||||||
fun! s:grey_colour(n)
|
|
||||||
if &t_Co == 88
|
|
||||||
if a:n == 0
|
|
||||||
return 16
|
|
||||||
elseif a:n == 9
|
|
||||||
return 79
|
|
||||||
else
|
|
||||||
return 79 + a:n
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if a:n == 0
|
|
||||||
return 16
|
|
||||||
elseif a:n == 25
|
|
||||||
return 231
|
|
||||||
else
|
|
||||||
return 231 + a:n
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfun
|
|
||||||
|
|
||||||
" Returns an approximate colour index for the given colour level
|
|
||||||
fun! s:rgb_number(x)
|
|
||||||
if &t_Co == 88
|
|
||||||
if a:x < 69
|
|
||||||
return 0
|
|
||||||
elseif a:x < 172
|
|
||||||
return 1
|
|
||||||
elseif a:x < 230
|
|
||||||
return 2
|
|
||||||
else
|
|
||||||
return 3
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if a:x < 75
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
let l:n = (a:x - 55) / 40
|
|
||||||
let l:m = (a:x - 55) % 40
|
|
||||||
if l:m < 20
|
|
||||||
return l:n
|
|
||||||
else
|
|
||||||
return l:n + 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfun
|
|
||||||
|
|
||||||
" Returns the palette index for the given R/G/B colour indices
|
|
||||||
fun! s:rgb_colour(x, y, z)
|
|
||||||
if &t_Co == 88
|
|
||||||
return 16 + (a:x * 16) + (a:y * 4) + a:z
|
|
||||||
else
|
|
||||||
return 16 + (a:x * 36) + (a:y * 6) + a:z
|
|
||||||
endif
|
|
||||||
endfun
|
|
||||||
|
|
||||||
" Returns the actual colour level for the given colour index
|
|
||||||
fun! s:rgb_level(n)
|
|
||||||
if &t_Co == 88
|
|
||||||
if a:n == 0
|
|
||||||
return 0
|
|
||||||
elseif a:n == 1
|
|
||||||
return 139
|
|
||||||
elseif a:n == 2
|
|
||||||
return 205
|
|
||||||
else
|
|
||||||
return 255
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if a:n == 0
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 55 + (a:n * 40)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfun
|
|
||||||
|
|
||||||
" Returns the palette index to approximate the given R/G/B colour levels
|
|
||||||
fun! s:colour(r, g, b)
|
|
||||||
" Get the closest grey
|
|
||||||
let l:gx = s:grey_number(a:r)
|
|
||||||
let l:gy = s:grey_number(a:g)
|
|
||||||
let l:gz = s:grey_number(a:b)
|
|
||||||
|
|
||||||
" Get the closest colour
|
|
||||||
let l:x = s:rgb_number(a:r)
|
|
||||||
let l:y = s:rgb_number(a:g)
|
|
||||||
let l:z = s:rgb_number(a:b)
|
|
||||||
|
|
||||||
if l:gx == l:gy && l:gy == l:gz
|
|
||||||
" There are two possibilities
|
|
||||||
let l:dgr = s:grey_level(l:gx) - a:r
|
|
||||||
let l:dgg = s:grey_level(l:gy) - a:g
|
|
||||||
let l:dgb = s:grey_level(l:gz) - a:b
|
|
||||||
let l:dgrey = (l:dgr * l:dgr) + (l:dgg * l:dgg) + (l:dgb * l:dgb)
|
|
||||||
let l:dr = s:rgb_level(l:gx) - a:r
|
|
||||||
let l:dg = s:rgb_level(l:gy) - a:g
|
|
||||||
let l:db = s:rgb_level(l:gz) - a:b
|
|
||||||
let l:drgb = (l:dr * l:dr) + (l:dg * l:dg) + (l:db * l:db)
|
|
||||||
if l:dgrey < l:drgb
|
|
||||||
" Use the grey
|
|
||||||
return s:grey_colour(l:gx)
|
|
||||||
else
|
|
||||||
" Use the colour
|
|
||||||
return s:rgb_colour(l:x, l:y, l:z)
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
" Only one possibility
|
|
||||||
return s:rgb_colour(l:x, l:y, l:z)
|
|
||||||
endif
|
|
||||||
endfun
|
|
||||||
|
|
||||||
function! coc#color#term2rgb(term) abort
|
|
||||||
if a:term < 0 || a:term > 255
|
|
||||||
return '#000000'
|
|
||||||
endif
|
|
||||||
return s:xterm_colors[a:term]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#color#rgb2term(rgb)
|
|
||||||
let l:r = ("0x" . strpart(a:rgb, 0, 2)) + 0
|
|
||||||
let l:g = ("0x" . strpart(a:rgb, 2, 2)) + 0
|
|
||||||
let l:b = ("0x" . strpart(a:rgb, 4, 2)) + 0
|
|
||||||
return s:colour(l:r, l:g, l:b)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#color#rgbToHex(...)
|
|
||||||
let [r, g, b] = ( a:0==1 ? a:1 : a:000 )
|
|
||||||
let num = printf('%02x', float2nr(r)) . ''
|
|
||||||
\ . printf('%02x', float2nr(g)) . ''
|
|
||||||
\ . printf('%02x', float2nr(b)) . ''
|
|
||||||
return '#' . num
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#color#hexToRgb(color)
|
|
||||||
if type(a:color) == 2
|
|
||||||
let color = printf('%x', a:color)
|
|
||||||
else
|
|
||||||
let color = a:color
|
|
||||||
end
|
|
||||||
let matches = matchlist(color, s:patterns['hex'])
|
|
||||||
let factor = 0x1
|
|
||||||
if empty(matches)
|
|
||||||
let matches = matchlist(color, s:patterns['shortHex'])
|
|
||||||
let factor = 0x10
|
|
||||||
end
|
|
||||||
if len(matches) < 4
|
|
||||||
echohl Error
|
|
||||||
echom 'Couldnt parse ' . string(color) . ' ' . string(matches)
|
|
||||||
echohl None
|
|
||||||
return
|
|
||||||
end
|
|
||||||
let r = str2nr(matches[1], 16) * factor
|
|
||||||
let g = str2nr(matches[2], 16) * factor
|
|
||||||
let b = str2nr(matches[3], 16) * factor
|
|
||||||
return [r, g, b]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#color#lighten(color, ...)
|
|
||||||
let amount = a:0 ?
|
|
||||||
\(type(a:1) < 2 ?
|
|
||||||
\str2float(a:1) : a:1 )
|
|
||||||
\: 5
|
|
||||||
let rgb = coc#color#hexToRgb(a:color)
|
|
||||||
let rgb = map(rgb, 'v:val + amount*(255 - v:val)/255')
|
|
||||||
let rgb = map(rgb, 'v:val > 255.0 ? 255.0 : v:val')
|
|
||||||
let rgb = map(rgb, 'float2nr(v:val)')
|
|
||||||
let hex = coc#color#rgbToHex(rgb)
|
|
||||||
return hex
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#color#darken(color, ...)
|
|
||||||
let amount = a:0 ?
|
|
||||||
\(type(a:1) < 2 ?
|
|
||||||
\str2float(a:1) : a:1 )
|
|
||||||
\: 5.0
|
|
||||||
let rgb = coc#color#hexToRgb(a:color)
|
|
||||||
let rgb = map(rgb, 'v:val - amount*v:val/255')
|
|
||||||
let rgb = map(rgb, 'v:val < 0.0 ? 0.0 : v:val')
|
|
||||||
let rgb = map(rgb, 'float2nr(v:val)')
|
|
||||||
let hex = coc#color#rgbToHex(rgb)
|
|
||||||
return hex
|
|
||||||
endfu
|
|
||||||
|
|
||||||
function! coc#color#luminance(rgb) abort
|
|
||||||
let vals = []
|
|
||||||
for val in a:rgb
|
|
||||||
let val = (val + 0.0)/255
|
|
||||||
if val <= 0.03928
|
|
||||||
call add(vals, val/12.92)
|
|
||||||
else
|
|
||||||
call add(vals, pow((val + 0.055)/1.055, 2.4))
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return vals[0] * 0.2126 + vals[1] * 0.7152 + vals[2] * 0.0722
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#color#contrast(rgb1, rgb2) abort
|
|
||||||
let lnum1 = coc#color#luminance(a:rgb1)
|
|
||||||
let lnum2 = coc#color#luminance(a:rgb2)
|
|
||||||
let brightest = lnum1 > lnum2 ? lnum1 : lnum2
|
|
||||||
let darkest = lnum1 < lnum2 ? lnum1 : lnum2
|
|
||||||
return (brightest + 0.05) / (darkest + 0.05)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#color#hex_contrast(hex1, hex2) abort
|
|
||||||
return coc#color#contrast(coc#color#hexToRgb(a:hex1), coc#color#hexToRgb(a:hex2))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#color#nameToHex(name, term) abort
|
|
||||||
if a:term
|
|
||||||
return has_key(s:xterm_16colors, a:name) ? s:xterm_16colors[a:name] : v:null
|
|
||||||
endif
|
|
||||||
return has_key(s:w3c_color_names, a:name) ? s:w3c_color_names[a:name] : v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" [r, g, b] ['255', '255', '255']
|
|
||||||
" return ['65535', '65535', '65535'] or return v:false to cancel
|
|
||||||
function! coc#color#pick_color(default_color)
|
|
||||||
if has('mac')
|
|
||||||
let default_color = map(a:default_color, {idx, val -> str2nr(val) * 65535 / 255 })
|
|
||||||
" This is the AppleScript magic:
|
|
||||||
let ascrpt = ['-e "tell application \"' . s:app . '\""',
|
|
||||||
\ '-e "' . s:activate . '"',
|
|
||||||
\ "-e \"set AppleScript's text item delimiters to {\\\",\\\"}\"",
|
|
||||||
\ '-e "set theColor to (choose color default color {' . default_color[0] . ", " . default_color[1] . ", " . default_color[2] . '}) as text"',
|
|
||||||
\ '-e "' . s:quit . '"',
|
|
||||||
\ '-e "end tell"',
|
|
||||||
\ '-e "return theColor"']
|
|
||||||
let res = trim(system("osascript " . join(ascrpt, ' ') . " 2>/dev/null"))
|
|
||||||
if empty(res)
|
|
||||||
return v:false
|
|
||||||
else
|
|
||||||
return split(trim(res), ',')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
let hex_color = printf('#%02x%02x%02x', a:default_color[0], a:default_color[1], a:default_color[2])
|
|
||||||
|
|
||||||
if has('unix')
|
|
||||||
if executable('zenity')
|
|
||||||
let res = trim(system('zenity --title="Select a color" --color-selection --color="' . hex_color . '" 2> /dev/null'))
|
|
||||||
if empty(res)
|
|
||||||
return v:false
|
|
||||||
else
|
|
||||||
" res format is rgb(255,255,255)
|
|
||||||
return map(split(res[4:-2], ','), {idx, val -> string(str2nr(trim(val)) * 65535 / 255)})
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
let rgb = v:false
|
|
||||||
if !has('python')
|
|
||||||
echohl Error | echom 'python support required, checkout :echo has(''python'')' | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
try
|
|
||||||
execute 'py import gtk'
|
|
||||||
catch /.*/
|
|
||||||
echohl Error | echom 'python gtk module not found' | echohl None
|
|
||||||
return
|
|
||||||
endtry
|
|
||||||
python << endpython
|
|
||||||
|
|
||||||
import vim
|
|
||||||
import gtk, sys
|
|
||||||
|
|
||||||
# message strings
|
|
||||||
wnd_title_insert = "Insert a color"
|
|
||||||
|
|
||||||
csd = gtk.ColorSelectionDialog(wnd_title_insert)
|
|
||||||
cs = csd.colorsel
|
|
||||||
|
|
||||||
cs.set_current_color(gtk.gdk.color_parse(vim.eval("hex_color")))
|
|
||||||
|
|
||||||
cs.set_current_alpha(65535)
|
|
||||||
cs.set_has_opacity_control(False)
|
|
||||||
# cs.set_has_palette(int(vim.eval("s:display_palette")))
|
|
||||||
|
|
||||||
if csd.run()==gtk.RESPONSE_OK:
|
|
||||||
c = cs.get_current_color()
|
|
||||||
s = [str(int(c.red)),',',str(int(c.green)),',',str(int(c.blue))]
|
|
||||||
thecolor = ''.join(s)
|
|
||||||
vim.command(":let rgb = split('%s',',')" % thecolor)
|
|
||||||
|
|
||||||
csd.destroy()
|
|
||||||
|
|
||||||
endpython
|
|
||||||
return rgb
|
|
||||||
endfunction
|
|
|
@ -1,203 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
|
|
||||||
" first window id for bufnr
|
|
||||||
" builtin bufwinid returns window of current tab only
|
|
||||||
function! coc#compat#buf_win_id(bufnr) abort
|
|
||||||
let info = filter(getwininfo(), 'v:val["bufnr"] =='.a:bufnr)
|
|
||||||
if empty(info)
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
return info[0]['winid']
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#compat#buf_set_lines(bufnr, start, end, replacement) abort
|
|
||||||
if s:is_vim
|
|
||||||
call coc#api#exec('buf_set_lines', [a:bufnr, a:start, a:end, 0, a:replacement])
|
|
||||||
else
|
|
||||||
call nvim_buf_set_lines(a:bufnr, a:start, a:end, 0, a:replacement)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#compat#buf_line_count(bufnr) abort
|
|
||||||
if exists('*nvim_buf_line_count')
|
|
||||||
return nvim_buf_line_count(a:bufnr)
|
|
||||||
endif
|
|
||||||
if bufnr('%') == a:bufnr
|
|
||||||
return line('$')
|
|
||||||
endif
|
|
||||||
if exists('*getbufinfo')
|
|
||||||
let info = getbufinfo(a:bufnr)
|
|
||||||
if empty(info)
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
" vim 8.1 has getbufinfo but no linecount
|
|
||||||
if has_key(info[0], 'linecount')
|
|
||||||
return info[0]['linecount']
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if exists('*getbufline')
|
|
||||||
let lines = getbufline(a:bufnr, 1, '$')
|
|
||||||
return len(lines)
|
|
||||||
endif
|
|
||||||
let curr = bufnr('%')
|
|
||||||
execute 'noa buffer '.a:bufnr
|
|
||||||
let n = line('$')
|
|
||||||
execute 'noa buffer '.curr
|
|
||||||
return n
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#compat#prepend_lines(bufnr, replacement) abort
|
|
||||||
if exists('*appendbufline')
|
|
||||||
call appendbufline(a:bufnr, 0, a:replacement)
|
|
||||||
elseif !s:is_vim
|
|
||||||
call nvim_buf_set_lines(a:bufnr, 0, 0, 0, a:replacement)
|
|
||||||
else
|
|
||||||
throw 'appendbufline() required for prepend lines.'
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#compat#win_is_valid(winid) abort
|
|
||||||
if exists('*nvim_win_is_valid')
|
|
||||||
return nvim_win_is_valid(a:winid)
|
|
||||||
endif
|
|
||||||
return !empty(getwininfo(a:winid))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" clear matches by window id, not throw on none exists window.
|
|
||||||
" may not work on vim < 8.1.1084 & neovim < 0.4.0
|
|
||||||
function! coc#compat#clear_matches(winid) abort
|
|
||||||
if !coc#compat#win_is_valid(a:winid)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let curr = win_getid()
|
|
||||||
if curr == a:winid
|
|
||||||
call clearmatches()
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
if has('patch-8.1.1084')
|
|
||||||
call clearmatches(a:winid)
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if exists('*nvim_set_current_win')
|
|
||||||
noa call nvim_set_current_win(a:winid)
|
|
||||||
call clearmatches()
|
|
||||||
noa call nvim_set_current_win(curr)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#compat#matchaddpos(group, pos, priority, winid) abort
|
|
||||||
let curr = win_getid()
|
|
||||||
if curr == a:winid
|
|
||||||
call matchaddpos(a:group, a:pos, a:priority, -1)
|
|
||||||
else
|
|
||||||
if s:is_vim
|
|
||||||
if has('patch-8.1.0218')
|
|
||||||
call matchaddpos(a:group, a:pos, a:priority, -1, {'window': a:winid})
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call matchaddpos(a:group, a:pos, a:priority, -1, {'window': a:winid})
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#compat#buf_del_var(bufnr, name) abort
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if exists('*nvim_buf_del_var')
|
|
||||||
silent! call nvim_buf_del_var(a:bufnr, a:name)
|
|
||||||
else
|
|
||||||
if a:bufnr == bufnr('%')
|
|
||||||
execute 'unlet! b:'.a:name
|
|
||||||
elseif exists('*win_execute')
|
|
||||||
let winid = coc#compat#buf_win_id(a:bufnr)
|
|
||||||
if winid != -1
|
|
||||||
call win_execute(winid, 'unlet! b:'.a:name)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" hlGroup, pos, priority
|
|
||||||
function! coc#compat#matchaddgroups(winid, groups) abort
|
|
||||||
for group in a:groups
|
|
||||||
call matchaddpos(group['hlGroup'], [group['pos']], group['priority'], -1, {'window': a:winid})
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#compat#del_var(name) abort
|
|
||||||
if exists('*nvim_del_var')
|
|
||||||
silent! call nvim_del_var(a:name)
|
|
||||||
else
|
|
||||||
execute 'unlet! '.a:name
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" remove keymap for specific buffer
|
|
||||||
function! coc#compat#buf_del_keymap(bufnr, mode, lhs) abort
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if exists('*nvim_buf_del_keymap')
|
|
||||||
try
|
|
||||||
call nvim_buf_del_keymap(a:bufnr, a:mode, a:lhs)
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E5555/
|
|
||||||
" ignore keymap doesn't exist
|
|
||||||
endtry
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
try
|
|
||||||
call coc#api#exec('buf_del_keymap', [a:bufnr, a:mode, a:lhs])
|
|
||||||
catch /E31/
|
|
||||||
" ignore keymap doesn't exist
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#compat#buf_add_keymap(bufnr, mode, lhs, rhs, opts) abort
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if exists('*nvim_buf_set_keymap')
|
|
||||||
call nvim_buf_set_keymap(a:bufnr, a:mode, a:lhs, a:rhs, a:opts)
|
|
||||||
else
|
|
||||||
call coc#api#exec('buf_set_keymap', [a:bufnr, a:mode, a:lhs, a:rhs, a:opts])
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" execute command or list of commands in window
|
|
||||||
function! coc#compat#execute(winid, command, ...) abort
|
|
||||||
if exists('*win_execute')
|
|
||||||
if type(a:command) == v:t_string
|
|
||||||
keepalt call win_execute(a:winid, a:command, get(a:, 1, ''))
|
|
||||||
elseif type(a:command) == v:t_list
|
|
||||||
keepalt call win_execute(a:winid, join(a:command, "\n"), get(a:, 1, ''))
|
|
||||||
endif
|
|
||||||
elseif has('nvim')
|
|
||||||
if !nvim_win_is_valid(a:winid)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let curr = nvim_get_current_win()
|
|
||||||
noa keepalt call nvim_set_current_win(a:winid)
|
|
||||||
if type(a:command) == v:t_string
|
|
||||||
exe get(a:, 1, '').' '.a:command
|
|
||||||
elseif type(a:command) == v:t_list
|
|
||||||
for cmd in a:command
|
|
||||||
exe get(a:, 1, '').' '.cmd
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
noa keepalt call nvim_set_current_win(curr)
|
|
||||||
else
|
|
||||||
throw 'win_execute does not exist, please upgrade vim.'
|
|
||||||
endif
|
|
||||||
endfunc
|
|
||||||
|
|
||||||
function! coc#compat#trim(str)
|
|
||||||
if exists('*trim')
|
|
||||||
return trim(a:str)
|
|
||||||
endif
|
|
||||||
" TODO trim from beginning
|
|
||||||
return substitute(a:str, '\s\+$', '', '')
|
|
||||||
endfunction
|
|
|
@ -1,59 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
|
|
||||||
" Position of cursor relative to screen cell
|
|
||||||
function! coc#cursor#screen_pos() abort
|
|
||||||
let nr = winnr()
|
|
||||||
let [row, col] = win_screenpos(nr)
|
|
||||||
return [row + winline() - 2, col + wincol() - 2]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#cursor#move_by_col(delta)
|
|
||||||
let pos = getcurpos()
|
|
||||||
call cursor(pos[1], pos[2] + a:delta)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Get cursor position.
|
|
||||||
function! coc#cursor#position()
|
|
||||||
let line = getline('.')
|
|
||||||
return [line('.') - 1, coc#string#character_index(line, col('.') - 1)]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Move cursor to position.
|
|
||||||
function! coc#cursor#move_to(line, character) abort
|
|
||||||
let content = getline(a:line + 1)
|
|
||||||
call cursor(a:line + 1, coc#string#byte_index(content, a:character) + 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Character offset of current cursor, vim provide bytes offset only.
|
|
||||||
function! coc#cursor#char_offset() abort
|
|
||||||
let offset = 0
|
|
||||||
let lnum = line('.')
|
|
||||||
for i in range(1, lnum)
|
|
||||||
if i == lnum
|
|
||||||
let offset += strchars(strpart(getline('.'), 0, col('.')-1))
|
|
||||||
else
|
|
||||||
let offset += strchars(getline(i)) + 1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return offset
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Returns latest selection range
|
|
||||||
function! coc#cursor#get_selection(char) abort
|
|
||||||
let m = a:char ? 'char' : visualmode()
|
|
||||||
if empty(m)
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let [_, sl, sc, soff] = getpos(m ==# 'char' ? "'[" : "'<")
|
|
||||||
let [_, el, ec, eoff] = getpos(m ==# 'char' ? "']" : "'>")
|
|
||||||
let start_idx = coc#string#character_index(getline(sl), sc - 1)
|
|
||||||
if m ==# 'V'
|
|
||||||
return [sl - 1, start_idx, el, 0]
|
|
||||||
endif
|
|
||||||
let line = getline(el)
|
|
||||||
let end_idx = coc#string#character_index(line, ec - 1)
|
|
||||||
if m !=# 'char'
|
|
||||||
let end_idx = end_idx == coc#string#character_length(line) ? end_idx : end_idx + 1
|
|
||||||
endif
|
|
||||||
return [sl - 1, start_idx, el - 1, end_idx]
|
|
||||||
endfunction
|
|
|
@ -1,753 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:root = expand('<sfile>:h:h:h')
|
|
||||||
let s:prompt_win_bufnr = 0
|
|
||||||
let s:list_win_bufnr = 0
|
|
||||||
let s:prompt_win_width = get(g:, 'coc_prompt_win_width', 32)
|
|
||||||
let s:frames = ['· ', '·· ', '···', ' ··', ' ·', ' ']
|
|
||||||
let s:sign_group = 'PopUpCocDialog'
|
|
||||||
let s:detail_bufnr = 0
|
|
||||||
|
|
||||||
" Float window aside pum
|
|
||||||
function! coc#dialog#create_pum_float(lines, config) abort
|
|
||||||
let winid = coc#float#get_float_by_kind('pumdetail')
|
|
||||||
if empty(a:lines) || !coc#pum#visible()
|
|
||||||
if winid
|
|
||||||
call coc#float#close(winid)
|
|
||||||
endif
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let pumbounding = coc#pum#info()
|
|
||||||
let border = get(a:config, 'border', [])
|
|
||||||
let pw = pumbounding['width'] + (pumbounding['border'] ? 0 : get(pumbounding, 'scrollbar', 0))
|
|
||||||
let rp = &columns - pumbounding['col'] - pw
|
|
||||||
let showRight = pumbounding['col'] > rp ? 0 : 1
|
|
||||||
let maxWidth = showRight ? coc#math#min(rp - 1, a:config['maxWidth']) : coc#math#min(pumbounding['col'] - 1, a:config['maxWidth'])
|
|
||||||
let bh = get(border, 0 ,0) + get(border, 2, 0)
|
|
||||||
let maxHeight = &lines - pumbounding['row'] - &cmdheight - 1 - bh
|
|
||||||
if maxWidth <= 2 || maxHeight < 1
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let width = 0
|
|
||||||
for line in a:lines
|
|
||||||
let dw = max([1, strdisplaywidth(line)])
|
|
||||||
let width = max([width, dw + 2])
|
|
||||||
endfor
|
|
||||||
let width = float2nr(coc#math#min(maxWidth, width))
|
|
||||||
let ch = coc#string#content_height(a:lines, width - 2)
|
|
||||||
let height = float2nr(coc#math#min(maxHeight, ch))
|
|
||||||
let lines = map(a:lines, {_, s -> s =~# '^─' ? repeat('─', width - 2 + (s:is_vim && ch > height ? -1 : 0)) : s})
|
|
||||||
let opts = {
|
|
||||||
\ 'lines': lines,
|
|
||||||
\ 'highlights': get(a:config, 'highlights', []),
|
|
||||||
\ 'relative': 'editor',
|
|
||||||
\ 'col': showRight ? pumbounding['col'] + pw : pumbounding['col'] - width,
|
|
||||||
\ 'row': pumbounding['row'],
|
|
||||||
\ 'height': height,
|
|
||||||
\ 'width': width - 2 + (s:is_vim && ch > height ? -1 : 0),
|
|
||||||
\ 'scrollinside': showRight ? 0 : 1,
|
|
||||||
\ 'codes': get(a:config, 'codes', []),
|
|
||||||
\ }
|
|
||||||
for key in ['border', 'highlight', 'borderhighlight', 'winblend', 'focusable', 'shadow', 'rounded']
|
|
||||||
if has_key(a:config, key)
|
|
||||||
let opts[key] = a:config[key]
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
call s:close_auto_hide_wins(winid)
|
|
||||||
let result = coc#float#create_float_win(winid, s:detail_bufnr, opts)
|
|
||||||
if empty(result)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let s:detail_bufnr = result[1]
|
|
||||||
call setwinvar(result[0], 'kind', 'pumdetail')
|
|
||||||
if !s:is_vim
|
|
||||||
call coc#float#nvim_scrollbar(result[0])
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Float window below/above cursor
|
|
||||||
function! coc#dialog#create_cursor_float(winid, bufnr, lines, config) abort
|
|
||||||
if coc#prompt#activated()
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let pumAlignTop = get(a:config, 'pumAlignTop', 0)
|
|
||||||
let modes = get(a:config, 'modes', ['n', 'i', 'ic', 's'])
|
|
||||||
let mode = mode()
|
|
||||||
let currbuf = bufnr('%')
|
|
||||||
let pos = [line('.'), col('.')]
|
|
||||||
if index(modes, mode) == -1
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
if !s:is_vim && !has('nvim-0.5.0') && mode ==# 'i'
|
|
||||||
" helps to fix undo issue, don't know why.
|
|
||||||
call feedkeys("\<C-g>u", 'n')
|
|
||||||
endif
|
|
||||||
if mode ==# 's' && has('patch-8.2.4969') && !has('patch-8.2.4996')
|
|
||||||
echohl WarningMsg | echon 'Popup not created to avoid issue #10466 on vim >= 8.2.4969' | echohl None
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let dimension = coc#dialog#get_config_cursor(a:lines, a:config)
|
|
||||||
if empty(dimension)
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
if coc#pum#visible() && ((pumAlignTop && dimension['row'] <0)|| (!pumAlignTop && dimension['row'] > 0))
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let width = dimension['width']
|
|
||||||
let lines = map(a:lines, {_, s -> s =~# '^─' ? repeat('─', width) : s})
|
|
||||||
let config = extend(extend({'lines': lines, 'relative': 'cursor'}, a:config), dimension)
|
|
||||||
call s:close_auto_hide_wins(a:winid)
|
|
||||||
let res = coc#float#create_float_win(a:winid, a:bufnr, config)
|
|
||||||
if empty(res)
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let alignTop = dimension['row'] < 0
|
|
||||||
let winid = res[0]
|
|
||||||
let bufnr = res[1]
|
|
||||||
redraw
|
|
||||||
if has('nvim')
|
|
||||||
call coc#float#nvim_scrollbar(winid)
|
|
||||||
endif
|
|
||||||
return [currbuf, pos, winid, bufnr, alignTop]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Use terminal buffer
|
|
||||||
function! coc#dialog#_create_prompt_vim(title, default, opts) abort
|
|
||||||
if !has('patch-8.2.0750')
|
|
||||||
throw 'Input box not supported on vim < 8.2.0750'
|
|
||||||
endif
|
|
||||||
execute 'hi link CocPopupTerminal '.get(a:opts, 'highlight', 'CocFloating')
|
|
||||||
let node = expand(get(g:, 'coc_node_path', 'node'))
|
|
||||||
let placeHolder = get(a:opts, 'placeHolder', '')
|
|
||||||
let opt = {
|
|
||||||
\ 'term_rows': 1,
|
|
||||||
\ 'hidden': 1,
|
|
||||||
\ 'term_finish': 'close',
|
|
||||||
\ 'norestore': 1,
|
|
||||||
\ 'term_highlight': 'CocPopupTerminal'
|
|
||||||
\ }
|
|
||||||
let bufnr = term_start([node, s:root . '/bin/prompt.js', a:default, empty(placeHolder) ? '' : placeHolder], opt)
|
|
||||||
call term_setapi(bufnr, 'Coc')
|
|
||||||
call setbufvar(bufnr, 'current', type(a:default) == v:t_string ? a:default : '')
|
|
||||||
let res = s:create_prompt_win(bufnr, a:title, a:default, a:opts)
|
|
||||||
if empty(res)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let winid = res[0]
|
|
||||||
" call win_gotoid(winid)
|
|
||||||
call coc#util#do_autocmd('CocOpenFloatPrompt')
|
|
||||||
let pos = popup_getpos(winid)
|
|
||||||
" width height row col
|
|
||||||
let dimension = [pos['width'], pos['height'], pos['line'] - 1, pos['col'] - 1]
|
|
||||||
return [bufnr, winid, dimension]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Use normal buffer on neovim
|
|
||||||
function! coc#dialog#_create_prompt_nvim(title, default, opts) abort
|
|
||||||
let result = s:create_prompt_win(s:prompt_win_bufnr, a:title, a:default, a:opts)
|
|
||||||
if empty(result)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let winid = result[0]
|
|
||||||
let s:prompt_win_bufnr = result[1]
|
|
||||||
let bufnr = s:prompt_win_bufnr
|
|
||||||
call sign_unplace(s:sign_group, { 'buffer': s:prompt_win_bufnr })
|
|
||||||
call nvim_set_current_win(winid)
|
|
||||||
inoremap <buffer> <C-a> <Home>
|
|
||||||
inoremap <buffer><expr><C-e> pumvisible() ? "\<C-e>" : "\<End>"
|
|
||||||
exe 'imap <silent><nowait><buffer> <esc> <esc><esc>'
|
|
||||||
exe 'nnoremap <silent><buffer> <esc> :call coc#float#close('.winid.')<CR>'
|
|
||||||
exe 'inoremap <silent><expr><nowait><buffer> <cr> "\<C-r>=coc#dialog#prompt_insert()\<cr>\<esc>"'
|
|
||||||
if get(a:opts, 'list', 0)
|
|
||||||
for key in ['<C-j>', '<C-k>', '<C-n>', '<C-p>', '<up>', '<down>', '<C-f>', '<C-b>', '<C-space>']
|
|
||||||
let escaped = key ==# '<C-space>' ? '\<C-@\>' : substitute(key, '\(<\|>\)', '\\\1', 'g')
|
|
||||||
exe 'inoremap <nowait><buffer> '.key.' <Cmd>call coc#rpc#notify("PromptKeyPress", ['.bufnr.', "'.escaped.'"])<CR>'
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
let mode = mode()
|
|
||||||
if mode ==# 'n'
|
|
||||||
call feedkeys('A', 'int')
|
|
||||||
elseif mode ==# 'i'
|
|
||||||
call feedkeys("\<end>", 'int')
|
|
||||||
endif
|
|
||||||
let placeHolder = get(a:opts, 'placeHolder', '')
|
|
||||||
if empty(a:default) && !empty(placeHolder) && has('nvim-0.5.0')
|
|
||||||
let src_id = coc#highlight#create_namespace('input-box')
|
|
||||||
call nvim_buf_set_extmark(bufnr, src_id, 0, 0, {
|
|
||||||
\ 'virt_text': [[placeHolder, 'CocInputBoxVirtualText']],
|
|
||||||
\ 'virt_text_pos': 'overlay',
|
|
||||||
\ })
|
|
||||||
endif
|
|
||||||
call coc#util#do_autocmd('CocOpenFloatPrompt')
|
|
||||||
if !has('nvim-0.6.0')
|
|
||||||
redraw
|
|
||||||
endif
|
|
||||||
let id = coc#float#get_related(winid, 'border')
|
|
||||||
let pos = nvim_win_get_position(id)
|
|
||||||
let dimension = [nvim_win_get_width(id), nvim_win_get_height(id), pos[0], pos[1]]
|
|
||||||
return [bufnr, winid, dimension]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Create float window for input
|
|
||||||
function! coc#dialog#create_prompt_win(title, default, opts) abort
|
|
||||||
call s:close_auto_hide_wins()
|
|
||||||
if s:is_vim
|
|
||||||
return coc#dialog#_create_prompt_vim(a:title, a:default, a:opts)
|
|
||||||
endif
|
|
||||||
return coc#dialog#_create_prompt_nvim(a:title, a:default, a:opts)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Create list window under target window
|
|
||||||
function! coc#dialog#create_list(target, dimension, opts) abort
|
|
||||||
let maxHeight = get(a:opts, 'maxHeight', 30)
|
|
||||||
let height = get(a:opts, 'linecount', 1)
|
|
||||||
let height = min([maxHeight, height, &lines - &cmdheight - 1 - a:dimension['row'] + a:dimension['height']])
|
|
||||||
let chars = get(a:opts, 'rounded', 1) ? ['╯', '╰'] : ['┘', '└']
|
|
||||||
let width = a:dimension['width'] - 2
|
|
||||||
let config = extend(copy(a:opts), {
|
|
||||||
\ 'relative': 'editor',
|
|
||||||
\ 'row': a:dimension['row'] + a:dimension['height'],
|
|
||||||
\ 'col': a:dimension['col'],
|
|
||||||
\ 'width': width,
|
|
||||||
\ 'height': height,
|
|
||||||
\ 'border': [1, 1, 1, 1],
|
|
||||||
\ 'scrollinside': 1,
|
|
||||||
\ 'borderchars': extend(['─', '│', '─', '│', '├', '┤'], chars)
|
|
||||||
\ })
|
|
||||||
let bufnr = 0
|
|
||||||
let result = coc#float#create_float_win(0, s:list_win_bufnr, config)
|
|
||||||
if empty(result)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let winid = result[0]
|
|
||||||
call coc#float#add_related(winid, a:target)
|
|
||||||
call setwinvar(winid, 'auto_height', get(a:opts, 'autoHeight', 1))
|
|
||||||
call setwinvar(winid, 'core_width', width)
|
|
||||||
call setwinvar(winid, 'max_height', maxHeight)
|
|
||||||
call setwinvar(winid, 'target_winid', a:target)
|
|
||||||
call setwinvar(winid, 'kind', 'list')
|
|
||||||
call coc#dialog#check_scroll_vim(a:target)
|
|
||||||
return result
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Create menu picker for pick single item
|
|
||||||
function! coc#dialog#create_menu(lines, config) abort
|
|
||||||
call s:close_auto_hide_wins()
|
|
||||||
let highlight = get(a:config, 'highlight', 'CocFloating')
|
|
||||||
let borderhighlight = get(a:config, 'borderhighlight', [highlight])
|
|
||||||
let relative = get(a:config, 'relative', 'cursor')
|
|
||||||
let lines = a:lines
|
|
||||||
let content = get(a:config, 'content', '')
|
|
||||||
let maxWidth = get(a:config, 'maxWidth', 80)
|
|
||||||
let highlights = get(a:config, 'highlights', [])
|
|
||||||
let contentCount = 0
|
|
||||||
if !empty(content)
|
|
||||||
let contentLines = coc#string#reflow(split(content, '\r\?\n'), maxWidth)
|
|
||||||
let contentCount = len(contentLines)
|
|
||||||
let lines = extend(contentLines, lines)
|
|
||||||
if !empty(highlights)
|
|
||||||
for item in highlights
|
|
||||||
let item['lnum'] = item['lnum'] + contentCount
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let opts = {
|
|
||||||
\ 'lines': lines,
|
|
||||||
\ 'highlight': highlight,
|
|
||||||
\ 'title': get(a:config, 'title', ''),
|
|
||||||
\ 'borderhighlight': borderhighlight,
|
|
||||||
\ 'maxWidth': maxWidth,
|
|
||||||
\ 'maxHeight': get(a:config, 'maxHeight', 80),
|
|
||||||
\ 'rounded': get(a:config, 'rounded', 0),
|
|
||||||
\ 'border': [1, 1, 1, 1],
|
|
||||||
\ 'highlights': highlights,
|
|
||||||
\ 'relative': relative,
|
|
||||||
\ }
|
|
||||||
if relative ==# 'editor'
|
|
||||||
let dimension = coc#dialog#get_config_editor(lines, opts)
|
|
||||||
else
|
|
||||||
let dimension = coc#dialog#get_config_cursor(lines, opts)
|
|
||||||
endif
|
|
||||||
call extend(opts, dimension)
|
|
||||||
let ids = coc#float#create_float_win(0, s:prompt_win_bufnr, opts)
|
|
||||||
if empty(ids)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let s:prompt_win_bufnr = ids[1]
|
|
||||||
call coc#dialog#set_cursor(ids[0], ids[1], contentCount + 1)
|
|
||||||
redraw
|
|
||||||
if has('nvim')
|
|
||||||
call coc#float#nvim_scrollbar(ids[0])
|
|
||||||
endif
|
|
||||||
return [ids[0], ids[1], contentCount]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Create dialog at center of screen
|
|
||||||
function! coc#dialog#create_dialog(lines, config) abort
|
|
||||||
call s:close_auto_hide_wins()
|
|
||||||
" dialog always have borders
|
|
||||||
let title = get(a:config, 'title', '')
|
|
||||||
let buttons = get(a:config, 'buttons', [])
|
|
||||||
let highlight = get(a:config, 'highlight', 'CocFloating')
|
|
||||||
let borderhighlight = get(a:config, 'borderhighlight', [highlight])
|
|
||||||
let opts = {
|
|
||||||
\ 'title': title,
|
|
||||||
\ 'rounded': get(a:config, 'rounded', 0),
|
|
||||||
\ 'relative': 'editor',
|
|
||||||
\ 'border': [1,1,1,1],
|
|
||||||
\ 'close': get(a:config, 'close', 1),
|
|
||||||
\ 'highlight': highlight,
|
|
||||||
\ 'highlights': get(a:config, 'highlights', []),
|
|
||||||
\ 'buttons': buttons,
|
|
||||||
\ 'borderhighlight': borderhighlight,
|
|
||||||
\ 'getchar': get(a:config, 'getchar', 0)
|
|
||||||
\ }
|
|
||||||
call extend(opts, coc#dialog#get_config_editor(a:lines, a:config))
|
|
||||||
let bufnr = coc#float#create_buf(0, a:lines)
|
|
||||||
let res = coc#float#create_float_win(0, bufnr, opts)
|
|
||||||
if empty(res)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if get(a:config, 'cursorline', 0)
|
|
||||||
call coc#dialog#place_sign(bufnr, 1)
|
|
||||||
endif
|
|
||||||
if has('nvim')
|
|
||||||
redraw
|
|
||||||
call coc#float#nvim_scrollbar(res[0])
|
|
||||||
endif
|
|
||||||
return res
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#dialog#prompt_confirm(title, cb) abort
|
|
||||||
call s:close_auto_hide_wins()
|
|
||||||
if s:is_vim && exists('*popup_dialog')
|
|
||||||
try
|
|
||||||
call popup_dialog(a:title. ' (y/n)?', {
|
|
||||||
\ 'highlight': 'Normal',
|
|
||||||
\ 'filter': 'popup_filter_yesno',
|
|
||||||
\ 'callback': {id, res -> a:cb(v:null, res)},
|
|
||||||
\ 'borderchars': get(g:, 'coc_borderchars', ['─', '│', '─', '│', '╭', '╮', '╯', '╰']),
|
|
||||||
\ 'borderhighlight': ['MoreMsg']
|
|
||||||
\ })
|
|
||||||
catch /.*/
|
|
||||||
call a:cb(v:exception)
|
|
||||||
endtry
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let text = ' '. a:title . ' (y/n)? '
|
|
||||||
let maxWidth = coc#math#min(78, &columns - 2)
|
|
||||||
let width = coc#math#min(maxWidth, strdisplaywidth(text))
|
|
||||||
let maxHeight = &lines - &cmdheight - 1
|
|
||||||
let height = coc#math#min(maxHeight, float2nr(ceil(str2float(string(strdisplaywidth(text)))/width)))
|
|
||||||
let arr = coc#float#create_float_win(0, s:prompt_win_bufnr, {
|
|
||||||
\ 'col': &columns/2 - width/2 - 1,
|
|
||||||
\ 'row': maxHeight/2 - height/2 - 1,
|
|
||||||
\ 'width': width,
|
|
||||||
\ 'height': height,
|
|
||||||
\ 'border': [1,1,1,1],
|
|
||||||
\ 'focusable': v:false,
|
|
||||||
\ 'relative': 'editor',
|
|
||||||
\ 'highlight': 'Normal',
|
|
||||||
\ 'borderhighlight': 'MoreMsg',
|
|
||||||
\ 'style': 'minimal',
|
|
||||||
\ 'lines': [text],
|
|
||||||
\ })
|
|
||||||
if empty(arr)
|
|
||||||
call a:cb('Window create failed!')
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let winid = arr[0]
|
|
||||||
let s:prompt_win_bufnr = arr[1]
|
|
||||||
call sign_unplace(s:sign_group, { 'buffer': s:prompt_win_bufnr })
|
|
||||||
let res = 0
|
|
||||||
redraw
|
|
||||||
" same result as vim
|
|
||||||
while 1
|
|
||||||
let key = nr2char(getchar())
|
|
||||||
if key == "\<C-c>"
|
|
||||||
let res = -1
|
|
||||||
break
|
|
||||||
elseif key == "\<esc>" || key == 'n' || key == 'N'
|
|
||||||
let res = 0
|
|
||||||
break
|
|
||||||
elseif key == 'y' || key == 'Y'
|
|
||||||
let res = 1
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endw
|
|
||||||
call coc#float#close(winid)
|
|
||||||
call a:cb(v:null, res)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" works on neovim only
|
|
||||||
function! coc#dialog#get_prompt_win() abort
|
|
||||||
if s:prompt_win_bufnr == 0
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
return get(win_findbuf(s:prompt_win_bufnr), 0, -1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#dialog#get_config_editor(lines, config) abort
|
|
||||||
let title = get(a:config, 'title', '')
|
|
||||||
let maxheight = min([get(a:config, 'maxHeight', 78), &lines - &cmdheight - 6])
|
|
||||||
let maxwidth = min([get(a:config, 'maxWidth', 78), &columns - 2])
|
|
||||||
let buttons = get(a:config, 'buttons', [])
|
|
||||||
let minwidth = s:min_btns_width(buttons)
|
|
||||||
if maxheight <= 0 || maxwidth <= 0 || minwidth > maxwidth
|
|
||||||
throw 'Not enough spaces for float window'
|
|
||||||
endif
|
|
||||||
let ch = 0
|
|
||||||
let width = min([strdisplaywidth(title) + 1, maxwidth])
|
|
||||||
for line in a:lines
|
|
||||||
let dw = max([1, strdisplaywidth(line)])
|
|
||||||
if dw < maxwidth && dw > width
|
|
||||||
let width = dw
|
|
||||||
elseif dw >= maxwidth
|
|
||||||
let width = maxwidth
|
|
||||||
endif
|
|
||||||
let ch += float2nr(ceil(str2float(string(dw))/maxwidth))
|
|
||||||
endfor
|
|
||||||
let width = max([minwidth, width])
|
|
||||||
let height = coc#math#min(ch ,maxheight)
|
|
||||||
return {
|
|
||||||
\ 'row': &lines/2 - (height + 4)/2,
|
|
||||||
\ 'col': &columns/2 - (width + 2)/2,
|
|
||||||
\ 'width': width,
|
|
||||||
\ 'height': height,
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#dialog#prompt_insert() abort
|
|
||||||
let value = getline('.')
|
|
||||||
call coc#rpc#notify('PromptInsert', [value, bufnr('%')])
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Dimension of window with lines relative to cursor
|
|
||||||
" Width & height excludes border & padding
|
|
||||||
function! coc#dialog#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', [])
|
|
||||||
if empty(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 = coc#math#min(get(a:config, 'maxWidth', &columns - 1), &columns - 1)
|
|
||||||
if maxWidth < 3
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let maxHeight = coc#math#min(get(a:config, 'maxHeight', vh), vh)
|
|
||||||
let width = coc#math#min(40, strdisplaywidth(title)) + 3
|
|
||||||
for line in a:lines
|
|
||||||
let dw = max([1, strdisplaywidth(line)])
|
|
||||||
let width = max([width, dw + 2])
|
|
||||||
endfor
|
|
||||||
let width = coc#math#min(maxWidth, width)
|
|
||||||
let ch = coc#string#content_height(a:lines, width - 2)
|
|
||||||
let [lineIdx, colIdx] = coc#cursor#screen_pos()
|
|
||||||
" How much we should move left
|
|
||||||
let offsetX = coc#math#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 = coc#math#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 + bh : 1
|
|
||||||
return {
|
|
||||||
\ 'row': row,
|
|
||||||
\ 'col': col,
|
|
||||||
\ 'width': width - 2,
|
|
||||||
\ 'height': height - bh
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#dialog#change_border_hl(winid, hlgroup) abort
|
|
||||||
if !hlexists(a:hlgroup)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
if coc#float#valid(a:winid)
|
|
||||||
call popup_setoptions(a:winid, {'borderhighlight': repeat([a:hlgroup], 4)})
|
|
||||||
redraw
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let winid = coc#float#get_related(a:winid, 'border')
|
|
||||||
if winid > 0
|
|
||||||
call setwinvar(winid, '&winhl', 'Normal:'.a:hlgroup)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#dialog#change_title(winid, title) abort
|
|
||||||
if s:is_vim
|
|
||||||
if coc#float#valid(a:winid)
|
|
||||||
call popup_setoptions(a:winid, {'title': a:title})
|
|
||||||
redraw
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let winid = coc#float#get_related(a:winid, 'border')
|
|
||||||
if winid > 0
|
|
||||||
let bufnr = winbufnr(winid)
|
|
||||||
let line = getbufline(bufnr, 1)[0]
|
|
||||||
let top = strcharpart(line, 0, 1)
|
|
||||||
\.repeat('─', strchars(line) - 2)
|
|
||||||
\.strcharpart(line, strchars(line) - 1, 1)
|
|
||||||
if !empty(a:title)
|
|
||||||
let top = coc#string#compose(top, 1, a:title.' ')
|
|
||||||
endif
|
|
||||||
call nvim_buf_set_lines(bufnr, 0, 1, v:false, [top])
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#dialog#change_input_value(winid, bufnr, value) abort
|
|
||||||
if !coc#float#valid(a:winid)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if win_getid() != a:winid
|
|
||||||
call win_gotoid(a:winid)
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
" call timer_start(3000, { -> term_sendkeys(bufnr, "\<C-u>\<C-k>abcd")})
|
|
||||||
call term_sendkeys(a:bufnr, "\<C-u>\<C-k>".a:value)
|
|
||||||
else
|
|
||||||
let mode = mode()
|
|
||||||
if mode ==# 'i'
|
|
||||||
call feedkeys("\<end>", 'int')
|
|
||||||
else
|
|
||||||
call feedkeys("\<esc>A", 'int')
|
|
||||||
endif
|
|
||||||
" Use complete to replace text before
|
|
||||||
let saved_completeopt = &completeopt
|
|
||||||
if saved_completeopt =~ 'menuone'
|
|
||||||
noa set completeopt=menu
|
|
||||||
endif
|
|
||||||
noa call complete(1, [{ 'empty': 1, 'word': a:value }])
|
|
||||||
if has('nvim-0.6.1')
|
|
||||||
call feedkeys("\<C-x>\<C-z>", 'in')
|
|
||||||
else
|
|
||||||
let g:coc_disable_space_report = 1
|
|
||||||
call feedkeys("\<space>\<bs>", 'in')
|
|
||||||
endif
|
|
||||||
execute 'noa set completeopt='.saved_completeopt
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#dialog#change_loading(winid, loading) abort
|
|
||||||
if coc#float#valid(a:winid)
|
|
||||||
let winid = coc#float#get_related(a:winid, 'loading')
|
|
||||||
if !a:loading && winid > 0
|
|
||||||
call coc#float#close(winid)
|
|
||||||
endif
|
|
||||||
if a:loading && winid == 0
|
|
||||||
let bufnr = s:create_loading_buf()
|
|
||||||
if s:is_vim
|
|
||||||
let pos = popup_getpos(a:winid)
|
|
||||||
let winid = popup_create(bufnr, {
|
|
||||||
\ 'line': pos['line'] + 1,
|
|
||||||
\ 'col': pos['col'] + pos['width'] - 4,
|
|
||||||
\ 'maxheight': 1,
|
|
||||||
\ 'maxwidth': 3,
|
|
||||||
\ 'zindex': 999,
|
|
||||||
\ 'highlight': get(popup_getoptions(a:winid), 'highlight', 'CocFloating')
|
|
||||||
\ })
|
|
||||||
else
|
|
||||||
let pos = nvim_win_get_position(a:winid)
|
|
||||||
let width = nvim_win_get_width(a:winid)
|
|
||||||
let opts = {
|
|
||||||
\ 'relative': 'editor',
|
|
||||||
\ 'row': pos[0],
|
|
||||||
\ 'col': pos[1] + width - 3,
|
|
||||||
\ 'focusable': v:false,
|
|
||||||
\ 'width': 3,
|
|
||||||
\ 'height': 1,
|
|
||||||
\ 'style': 'minimal',
|
|
||||||
\ }
|
|
||||||
if has('nvim-0.5.1')
|
|
||||||
let opts['zindex'] = 900
|
|
||||||
endif
|
|
||||||
let winid = nvim_open_win(bufnr, v:false, opts)
|
|
||||||
call setwinvar(winid, '&winhl', getwinvar(a:winid, '&winhl'))
|
|
||||||
endif
|
|
||||||
call setwinvar(winid, 'kind', 'loading')
|
|
||||||
call setbufvar(bufnr, 'target_winid', a:winid)
|
|
||||||
call setbufvar(bufnr, 'popup', winid)
|
|
||||||
call coc#float#add_related(winid, a:winid)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Update list with new lines and highlights
|
|
||||||
function! coc#dialog#update_list(winid, bufnr, lines, highlights) abort
|
|
||||||
if coc#window#tabnr(a:winid) == tabpagenr()
|
|
||||||
if getwinvar(a:winid, 'auto_height', 0)
|
|
||||||
let row = coc#float#get_row(a:winid)
|
|
||||||
let width = getwinvar(a:winid, 'core_width', 80)
|
|
||||||
let height = s:get_height(a:lines, width)
|
|
||||||
let height = min([getwinvar(a:winid, 'max_height', 10), height, &lines - &cmdheight - 1 - row])
|
|
||||||
let curr = s:is_vim ? popup_getpos(a:winid)['core_height'] : nvim_win_get_height(a:winid)
|
|
||||||
let delta = height - curr
|
|
||||||
if delta != 0
|
|
||||||
call coc#float#change_height(a:winid, delta)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call coc#compat#buf_set_lines(a:bufnr, 0, -1, a:lines)
|
|
||||||
call coc#highlight#add_highlights(a:winid, [], a:highlights)
|
|
||||||
if s:is_vim
|
|
||||||
let target = getwinvar(a:winid, 'target_winid', -1)
|
|
||||||
if target != -1
|
|
||||||
call coc#dialog#check_scroll_vim(target)
|
|
||||||
endif
|
|
||||||
call win_execute(a:winid, 'exe 1')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Fix width of prompt window same as list window on scrollbar change
|
|
||||||
function! coc#dialog#check_scroll_vim(winid) abort
|
|
||||||
if s:is_vim && coc#float#valid(a:winid)
|
|
||||||
let winid = coc#float#get_related(a:winid, 'list')
|
|
||||||
if winid
|
|
||||||
redraw
|
|
||||||
let pos = popup_getpos(winid)
|
|
||||||
let width = pos['width'] + (pos['scrollbar'] ? 1 : 0)
|
|
||||||
if width != popup_getpos(a:winid)['width']
|
|
||||||
call popup_move(a:winid, {
|
|
||||||
\ 'minwidth': width - 2,
|
|
||||||
\ 'maxwidth': width - 2,
|
|
||||||
\ })
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#dialog#set_cursor(winid, bufnr, line) abort
|
|
||||||
if s:is_vim
|
|
||||||
call coc#compat#execute(a:winid, 'exe '.max([a:line, 1]), 'silent!')
|
|
||||||
call popup_setoptions(a:winid, {'cursorline' : 1})
|
|
||||||
call popup_setoptions(a:winid, {'cursorline' : 0})
|
|
||||||
else
|
|
||||||
call nvim_win_set_cursor(a:winid, [max([a:line, 1]), 0])
|
|
||||||
endif
|
|
||||||
call coc#dialog#place_sign(a:bufnr, a:line)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#dialog#place_sign(bufnr, line) abort
|
|
||||||
call sign_unplace(s:sign_group, { 'buffer': a:bufnr })
|
|
||||||
if a:line > 0
|
|
||||||
call sign_place(6, s:sign_group, 'CocCurrentLine', a:bufnr, {'lnum': a:line})
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:create_prompt_win(bufnr, title, default, opts) abort
|
|
||||||
let config = s:get_prompt_dimension(a:title, a:default, a:opts)
|
|
||||||
return coc#float#create_float_win(0, a:bufnr, extend(config, {
|
|
||||||
\ 'style': 'minimal',
|
|
||||||
\ 'border': get(a:opts, 'border', [1,1,1,1]),
|
|
||||||
\ 'rounded': get(a:opts, 'rounded', 1),
|
|
||||||
\ 'prompt': 1,
|
|
||||||
\ 'title': a:title,
|
|
||||||
\ 'lines': s:is_vim ? v:null : [a:default],
|
|
||||||
\ 'highlight': get(a:opts, 'highlight', 'CocFloating'),
|
|
||||||
\ 'borderhighlight': [get(a:opts, 'borderhighlight', 'CocFloating')],
|
|
||||||
\ }))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Could be center(with optional marginTop) or cursor
|
|
||||||
function! s:get_prompt_dimension(title, default, opts) abort
|
|
||||||
let relative = get(a:opts, 'position', 'cursor') ==# 'cursor' ? 'cursor' : 'editor'
|
|
||||||
let curr = win_screenpos(winnr())[1] + wincol() - 2
|
|
||||||
let minWidth = get(a:opts, 'minWidth', s:prompt_win_width)
|
|
||||||
let width = min([max([strwidth(a:default) + 2, strwidth(a:title) + 2, minWidth]), &columns - 2])
|
|
||||||
if get(a:opts, 'maxWidth', 0)
|
|
||||||
let width = min([width, a:opts['maxWidth']])
|
|
||||||
endif
|
|
||||||
if relative ==# 'cursor'
|
|
||||||
let [lineIdx, colIdx] = coc#cursor#screen_pos()
|
|
||||||
if width == &columns - 2
|
|
||||||
let col = 0 - curr
|
|
||||||
else
|
|
||||||
let col = curr + width <= &columns - 2 ? 0 : curr + width - &columns + 2
|
|
||||||
endif
|
|
||||||
let config = {
|
|
||||||
\ 'row': lineIdx == 0 ? 1 : 0,
|
|
||||||
\ 'col': colIdx == 0 ? 0 : col - 1,
|
|
||||||
\ }
|
|
||||||
else
|
|
||||||
let marginTop = get(a:opts, 'marginTop', v:null)
|
|
||||||
if marginTop is v:null
|
|
||||||
let row = (&lines - &cmdheight - 2) / 2
|
|
||||||
else
|
|
||||||
let row = marginTop < 2 ? 1 : min([marginTop, &columns - &cmdheight])
|
|
||||||
endif
|
|
||||||
let config = {
|
|
||||||
\ 'col': float2nr((&columns - width) / 2),
|
|
||||||
\ 'row': row - s:is_vim,
|
|
||||||
\ }
|
|
||||||
endif
|
|
||||||
return extend(config, {'relative': relative, 'width': width, 'height': 1})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:min_btns_width(buttons) abort
|
|
||||||
if empty(a:buttons)
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
let minwidth = len(a:buttons)*3 - 1
|
|
||||||
for txt in a:buttons
|
|
||||||
let minwidth = minwidth + strdisplaywidth(txt)
|
|
||||||
endfor
|
|
||||||
return minwidth
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Close windows that should auto hide
|
|
||||||
function! s: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
|
|
||||||
|
|
||||||
function! s:create_loading_buf() abort
|
|
||||||
let bufnr = coc#float#create_buf(0)
|
|
||||||
call s:change_loading_buf(bufnr, 0)
|
|
||||||
return bufnr
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_height(lines, width) abort
|
|
||||||
let height = 0
|
|
||||||
for line in a:lines
|
|
||||||
let height += float2nr(strdisplaywidth(line) / a:width) + 1
|
|
||||||
endfor
|
|
||||||
return max([1, height])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:change_loading_buf(bufnr, idx) abort
|
|
||||||
if bufloaded(a:bufnr)
|
|
||||||
let target = getbufvar(a:bufnr, 'target_winid', v:null)
|
|
||||||
if !empty(target) && !coc#float#valid(target)
|
|
||||||
call coc#float#close(getbufvar(a:bufnr, 'popup'))
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let line = get(s:frames, a:idx, ' ')
|
|
||||||
call setbufline(a:bufnr, 1, line)
|
|
||||||
call coc#highlight#add_highlight(a:bufnr, -1, 'CocNotificationProgress', 0, 0, -1)
|
|
||||||
let idx = a:idx == len(s:frames) - 1 ? 0 : a:idx + 1
|
|
||||||
call timer_start(100, { -> s:change_loading_buf(a:bufnr, idx)})
|
|
||||||
endif
|
|
||||||
endfunction
|
|
|
@ -1,32 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
|
|
||||||
function! coc#dict#equal(one, two) abort
|
|
||||||
for key in keys(a:one)
|
|
||||||
if a:one[key] != a:two[key]
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Return new dict with keys removed
|
|
||||||
function! coc#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
|
|
||||||
|
|
||||||
" Return new dict with keys only
|
|
||||||
function! coc#dict#pick(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
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,148 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
" Helper methods for viml
|
|
||||||
|
|
||||||
function! coc#helper#get_charactor(line, col) abort
|
|
||||||
return strchars(strpart(a:line, 0, a:col - 1))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#helper#last_character(line) abort
|
|
||||||
return strcharpart(a:line, strchars(a:line) - 1, 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#helper#obj_equal(one, two) abort
|
|
||||||
for key in keys(a:one)
|
|
||||||
if a:one[key] != a:two[key]
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" get change between two lines
|
|
||||||
function! coc#helper#str_diff(curr, previous, col) abort
|
|
||||||
let end = strpart(a:curr, a:col - 1)
|
|
||||||
let start = strpart(a:curr, 0, a:col -1)
|
|
||||||
let endOffset = 0
|
|
||||||
let startOffset = 0
|
|
||||||
let currLen = strchars(a:curr)
|
|
||||||
let prevLen = strchars(a:previous)
|
|
||||||
if len(end)
|
|
||||||
let endLen = strchars(end)
|
|
||||||
for i in range(min([prevLen, endLen]))
|
|
||||||
if strcharpart(end, endLen - 1 - i, 1) ==# strcharpart(a:previous, prevLen -1 -i, 1)
|
|
||||||
let endOffset = endOffset + 1
|
|
||||||
else
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
let remain = endOffset == 0 ? a:previous : strcharpart(a:previous, 0, prevLen - endOffset)
|
|
||||||
if len(remain)
|
|
||||||
for i in range(min([strchars(remain), strchars(start)]))
|
|
||||||
if strcharpart(remain, i, 1) ==# strcharpart(start, i ,1)
|
|
||||||
let startOffset = startOffset + 1
|
|
||||||
else
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
return {
|
|
||||||
\ 'start': startOffset,
|
|
||||||
\ 'end': prevLen - endOffset,
|
|
||||||
\ 'text': strcharpart(a:curr, startOffset, currLen - startOffset - endOffset)
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#helper#str_apply(content, diff) abort
|
|
||||||
let totalLen = strchars(a:content)
|
|
||||||
let endLen = totalLen - a:diff['end']
|
|
||||||
return strcharpart(a:content, 0, a:diff['start']).a:diff['text'].strcharpart(a:content, a:diff['end'], endLen)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" 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
|
|
||||||
|
|
||||||
" Return new dict with keys only
|
|
||||||
function! coc#helper#dict_pick(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
|
|
||||||
|
|
||||||
" support for float values
|
|
||||||
function! coc#helper#min(first, ...) abort
|
|
||||||
let val = a:first
|
|
||||||
for i in range(0, len(a:000) - 1)
|
|
||||||
if a:000[i] < val
|
|
||||||
let val = a:000[i]
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return val
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" support for float values
|
|
||||||
function! coc#helper#max(first, ...) abort
|
|
||||||
let val = a:first
|
|
||||||
for i in range(0, len(a:000) - 1)
|
|
||||||
if a:000[i] > val
|
|
||||||
let val = a:000[i]
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return val
|
|
||||||
endfunction
|
|
|
@ -1,811 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:nvim_50 = has('nvim-0.5.0')
|
|
||||||
let s:nvim_60 = has('nvim-0.6.0')
|
|
||||||
let s:clear_match_by_window = s:nvim_60 || s:is_vim
|
|
||||||
let s:set_extmark = has('nvim') && exists('*nvim_buf_set_extmark')
|
|
||||||
let s:namespace_map = {}
|
|
||||||
let s:ns_id = 1
|
|
||||||
let s:diagnostic_hlgroups = ['CocErrorHighlight', 'CocWarningHighlight', 'CocInfoHighlight', 'CocHintHighlight', 'CocDeprecatedHighlight', 'CocUnusedHighlight']
|
|
||||||
" Maximum count to highlight each time.
|
|
||||||
let g:coc_highlight_maximum_count = get(g:, 'coc_highlight_maximum_count', 100)
|
|
||||||
let s:term = &termguicolors == 0 && !has('gui_running')
|
|
||||||
|
|
||||||
if has('nvim-0.5.0') && s:clear_match_by_window == 0
|
|
||||||
try
|
|
||||||
call getmatches(0)
|
|
||||||
let s:clear_match_by_window = 1
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E118/
|
|
||||||
" ignored
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Update buffer region by region.
|
|
||||||
function! coc#highlight#buffer_update(bufnr, key, highlights, ...) abort
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if empty(a:highlights)
|
|
||||||
call coc#highlight#clear_highlight(a:bufnr, a:key, 0, -1)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let priority = get(a:, 1, v:null)
|
|
||||||
let changedtick = getbufvar(a:bufnr, 'changedtick', 0)
|
|
||||||
if type(get(a:, 2, v:null)) == 0 && changedtick > a:2
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let hls = map(copy(a:highlights), "{'hlGroup':v:val[0],'lnum':v:val[1],'colStart':v:val[2],'colEnd':v:val[3],'combine':get(v:val,4,1),'start_incl':get(v:val,5,0),'end_incl':get(v:val,6,0)}")
|
|
||||||
if len(hls) <= g:coc_highlight_maximum_count
|
|
||||||
call coc#highlight#update_highlights(a:bufnr, a:key, hls, 0, -1, priority)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let linecount = coc#compat#buf_line_count(a:bufnr)
|
|
||||||
let groups = s:group_hls(hls, linecount)
|
|
||||||
call s:update_highlights_timer(a:bufnr, changedtick, a:key, priority, groups, 0)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Update highlights by check exists highlights.
|
|
||||||
" 0 based, end exclusive start and end
|
|
||||||
function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort
|
|
||||||
let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
|
|
||||||
if !bufloaded(bufnr)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let start = get(a:, 1, 0)
|
|
||||||
let end = get(a:, 2, -1)
|
|
||||||
if end == 0
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let linecount = coc#compat#buf_line_count(a:bufnr)
|
|
||||||
if end >= linecount
|
|
||||||
let end = -1
|
|
||||||
endif
|
|
||||||
if empty(a:highlights)
|
|
||||||
call coc#highlight#clear_highlight(bufnr, a:key, start, end)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let priority = get(a:, 3, v:null)
|
|
||||||
let total = len(a:highlights)
|
|
||||||
" index list that exists with current highlights
|
|
||||||
let exists = []
|
|
||||||
let ns = coc#highlight#create_namespace(a:key)
|
|
||||||
if has('nvim-0.5.0') || exists('*prop_list')
|
|
||||||
let endLnum = end < 0 ? linecount - 1 : end - 1
|
|
||||||
let firstLnum = a:highlights[0]['lnum']
|
|
||||||
if firstLnum > start
|
|
||||||
call coc#highlight#clear_highlight(bufnr, a:key, start, firstLnum)
|
|
||||||
let start = firstLnum
|
|
||||||
endif
|
|
||||||
let lastLnum = a:highlights[total - 1]['lnum']
|
|
||||||
if lastLnum < endLnum
|
|
||||||
call coc#highlight#clear_highlight(bufnr, a:key, lastLnum + 1, endLnum + 1)
|
|
||||||
let endLnum = lastLnum
|
|
||||||
endif
|
|
||||||
let current = coc#highlight#get_highlights(bufnr, a:key, start, endLnum)
|
|
||||||
let currIndex = 0
|
|
||||||
if !empty(current)
|
|
||||||
for [lnum, items] in s:to_group(current)
|
|
||||||
let indexes = []
|
|
||||||
let currIndexes = range(0, len(items) - 1)
|
|
||||||
let removeIndexes = []
|
|
||||||
while currIndex != total
|
|
||||||
let hi = a:highlights[currIndex]
|
|
||||||
if hi['lnum'] == lnum
|
|
||||||
let findIndex = -1
|
|
||||||
for idx in currIndexes
|
|
||||||
let item = items[idx]
|
|
||||||
if hi['hlGroup'] ==# item[0] && hi['colStart'] == item[2] && hi['colEnd'] == item[3]
|
|
||||||
call add(indexes, currIndex)
|
|
||||||
let findIndex = idx
|
|
||||||
break
|
|
||||||
elseif item[2] > hi['colStart']
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
if findIndex != -1
|
|
||||||
call filter(currIndexes, 'v:val != '.findIndex)
|
|
||||||
endif
|
|
||||||
elseif hi['lnum'] > lnum
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
let currIndex = currIndex + 1
|
|
||||||
endwhile
|
|
||||||
for idx in currIndexes
|
|
||||||
if s:is_vim
|
|
||||||
call prop_remove({'bufnr': bufnr, 'id': items[idx][4]})
|
|
||||||
else
|
|
||||||
call nvim_buf_del_extmark(bufnr, ns, items[idx][4])
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
call extend(exists, indexes)
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call coc#highlight#clear_highlight(bufnr, a:key, start, end)
|
|
||||||
endif
|
|
||||||
let indexes = range(0, total - 1)
|
|
||||||
if !empty(exists)
|
|
||||||
let indexes = filter(indexes, 'index(exists, v:val) == -1')
|
|
||||||
endif
|
|
||||||
for idx in indexes
|
|
||||||
let hi = a:highlights[idx]
|
|
||||||
let opts = {
|
|
||||||
\ 'combine': get(hi, 'combine', 0),
|
|
||||||
\ 'start_incl': get(hi, 'start_incl', 0),
|
|
||||||
\ 'end_incl': get(hi, 'end_incl', 0),
|
|
||||||
\ }
|
|
||||||
if type(priority) == 0
|
|
||||||
let opts['priority'] = s:get_priority(a:key, hi['hlGroup'], priority)
|
|
||||||
endif
|
|
||||||
call coc#highlight#add_highlight(bufnr, ns, hi['hlGroup'], hi['lnum'], hi['colStart'], hi['colEnd'], opts)
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Get list of highlights by range or all buffer.
|
|
||||||
" 0 based line, start_col and end_col
|
|
||||||
" 0 based start & end line, end inclusive.
|
|
||||||
function! coc#highlight#get_highlights(bufnr, key, ...) abort
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
if !has_key(s:namespace_map, a:key)
|
|
||||||
return []
|
|
||||||
endif
|
|
||||||
let start = get(a:, 1, 0)
|
|
||||||
let end = get(a:, 2, -1)
|
|
||||||
if s:nvim_60
|
|
||||||
return v:lua.require('coc.highlight').getHighlights(a:bufnr, a:key, start, end)
|
|
||||||
elseif s:nvim_50
|
|
||||||
return luaeval(
|
|
||||||
\ 'require("coc.highlight").getHighlights(_A[1],_A[2],_A[3],_A[4])',
|
|
||||||
\ [a:bufnr, a:key, start, end]
|
|
||||||
\ )
|
|
||||||
endif
|
|
||||||
let res = []
|
|
||||||
let ns = s:namespace_map[a:key]
|
|
||||||
if exists('*prop_list')
|
|
||||||
let types = coc#api#get_types(ns)
|
|
||||||
if empty(types)
|
|
||||||
return res
|
|
||||||
endif
|
|
||||||
" Could filter by end_lnum and types
|
|
||||||
if has('patch-8.2.3652')
|
|
||||||
let endLnum = end == -1 ? -1 : end + 1
|
|
||||||
for prop in prop_list(start + 1, {'bufnr': a:bufnr, 'types': types, 'end_lnum': endLnum})
|
|
||||||
if prop['start'] == 0 || prop['end'] == 0
|
|
||||||
" multi line textprop are not supported, simply ignore it
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
let startCol = prop['col'] - 1
|
|
||||||
let endCol = startCol + prop['length']
|
|
||||||
call add(res, [s:prop_type_hlgroup(prop['type']), prop['lnum'] - 1, startCol, endCol, prop['id']])
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
if end == -1
|
|
||||||
let end = coc#compat#buf_line_count(a:bufnr)
|
|
||||||
else
|
|
||||||
let end = end + 1
|
|
||||||
endif
|
|
||||||
for line in range(start + 1, end)
|
|
||||||
for prop in prop_list(line, {'bufnr': a:bufnr})
|
|
||||||
if index(types, prop['type']) == -1 || prop['start'] == 0 || prop['end'] == 0
|
|
||||||
" multi line textprop are not supported, simply ignore it
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
let startCol = prop['col'] - 1
|
|
||||||
let endCol = startCol + prop['length']
|
|
||||||
call add(res, [s:prop_type_hlgroup(prop['type']), line - 1, startCol, endCol, prop['id']])
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
throw 'Get highlights requires neovim 0.5.0 or vim support prop_list'
|
|
||||||
endif
|
|
||||||
return res
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Add multiple highlights to buffer.
|
|
||||||
" type HighlightItem = [hlGroup, lnum, colStart, colEnd, combine?, start_incl?, end_incl?]
|
|
||||||
function! coc#highlight#set(bufnr, key, highlights, priority) abort
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let ns = coc#highlight#create_namespace(a:key)
|
|
||||||
let g:c = 1
|
|
||||||
if s:nvim_60
|
|
||||||
call v:lua.require('coc.highlight').set(a:bufnr, ns, a:highlights, a:priority)
|
|
||||||
elseif s:nvim_50
|
|
||||||
call luaeval(
|
|
||||||
\ 'require("coc.highlight").set(_A[1],_A[2],_A[3],_A[4])',
|
|
||||||
\ [a:bufnr, ns, a:highlights, a:priority]
|
|
||||||
\ )
|
|
||||||
else
|
|
||||||
if len(a:highlights) > g:coc_highlight_maximum_count
|
|
||||||
call s:add_highlights_timer(a:bufnr, ns, a:highlights, a:priority)
|
|
||||||
else
|
|
||||||
call s:add_highlights(a:bufnr, ns, a:highlights, a:priority)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Clear highlights by 0 based line numbers.
|
|
||||||
function! coc#highlight#clear(bufnr, key, lnums) abort
|
|
||||||
if !bufloaded(a:bufnr) || empty(a:lnums)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let ns = coc#highlight#create_namespace(a:key)
|
|
||||||
for lnum in a:lnums
|
|
||||||
if has('nvim')
|
|
||||||
call nvim_buf_clear_namespace(a:bufnr, ns, lnum, lnum + 1)
|
|
||||||
else
|
|
||||||
call coc#api#exec('buf_clear_namespace', [a:bufnr, ns, lnum, lnum + 1])
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
" clear highlights in invalid line.
|
|
||||||
if has('nvim')
|
|
||||||
let linecount = nvim_buf_line_count(a:bufnr)
|
|
||||||
call nvim_buf_clear_namespace(a:bufnr, ns, linecount, -1)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#del_markers(bufnr, key, ids) abort
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let ns = coc#highlight#create_namespace(a:key)
|
|
||||||
for id in a:ids
|
|
||||||
if s:is_vim
|
|
||||||
call prop_remove({'bufnr': a:bufnr, 'id': id})
|
|
||||||
else
|
|
||||||
call nvim_buf_del_extmark(a:bufnr, ns, id)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" highlight LSP range, opts contains 'combine' 'priority' 'start_incl' 'end_incl'
|
|
||||||
function! coc#highlight#ranges(bufnr, key, hlGroup, ranges, ...) abort
|
|
||||||
let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
|
|
||||||
if !bufloaded(bufnr) || !exists('*getbufline')
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let opts = get(a:, 1, {})
|
|
||||||
let synmaxcol = getbufvar(a:bufnr, '&synmaxcol', 1000)
|
|
||||||
if synmaxcol == 0
|
|
||||||
let synmaxcol = 1000
|
|
||||||
endif
|
|
||||||
let synmaxcol = min([synmaxcol, 1000])
|
|
||||||
let srcId = coc#highlight#create_namespace(a:key)
|
|
||||||
for range in a:ranges
|
|
||||||
let start = range['start']
|
|
||||||
let end = range['end']
|
|
||||||
for lnum in range(start['line'] + 1, end['line'] + 1)
|
|
||||||
let arr = getbufline(bufnr, lnum)
|
|
||||||
let line = empty(arr) ? '' : arr[0]
|
|
||||||
if empty(line)
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
if start['character'] > synmaxcol || end['character'] > synmaxcol
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
let colStart = lnum == start['line'] + 1 ? coc#string#byte_index(line, start['character']) : 0
|
|
||||||
let colEnd = lnum == end['line'] + 1 ? coc#string#byte_index(line, end['character']) : strlen(line)
|
|
||||||
if colStart == colEnd
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
call coc#highlight#add_highlight(bufnr, srcId, a:hlGroup, lnum - 1, colStart, colEnd, opts)
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#add_highlight(bufnr, src_id, hl_group, line, col_start, col_end, ...) abort
|
|
||||||
let opts = get(a:, 1, {})
|
|
||||||
let priority = get(opts, 'priority', v:null)
|
|
||||||
if !s:is_vim
|
|
||||||
if s:set_extmark && a:src_id != -1
|
|
||||||
" get(opts, 'start_incl', 0) ? v:true : v:false,
|
|
||||||
try
|
|
||||||
call nvim_buf_set_extmark(a:bufnr, a:src_id, a:line, a:col_start, {
|
|
||||||
\ 'end_col': a:col_end,
|
|
||||||
\ 'hl_group': a:hl_group,
|
|
||||||
\ 'hl_mode': get(opts, 'combine', 1) ? 'combine' : 'replace',
|
|
||||||
\ 'right_gravity': v:true,
|
|
||||||
\ 'end_right_gravity': v:false,
|
|
||||||
\ 'priority': type(priority) == 0 ? min([priority, 4096]) : 4096,
|
|
||||||
\ })
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E5555/
|
|
||||||
" the end_col could be invalid, ignore this error
|
|
||||||
endtry
|
|
||||||
else
|
|
||||||
call nvim_buf_add_highlight(a:bufnr, a:src_id, a:hl_group, a:line, a:col_start, a:col_end)
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call coc#api#exec('buf_add_highlight', [a:bufnr, a:src_id, a:hl_group, a:line, a:col_start, a:col_end, opts])
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#clear_highlight(bufnr, key, start_line, end_line) abort
|
|
||||||
let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
|
|
||||||
if !bufloaded(bufnr)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let src_id = coc#highlight#create_namespace(a:key)
|
|
||||||
if has('nvim')
|
|
||||||
call nvim_buf_clear_namespace(a:bufnr, src_id, a:start_line, a:end_line)
|
|
||||||
else
|
|
||||||
call coc#api#exec('buf_clear_namespace', [a:bufnr, src_id, a:start_line, a:end_line])
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" highlight buffer in winid with CodeBlock &HighlightItems
|
|
||||||
" export interface HighlightItem {
|
|
||||||
" lnum: number // 0 based
|
|
||||||
" hlGroup: string
|
|
||||||
" colStart: number // 0 based
|
|
||||||
" colEnd: number
|
|
||||||
" }
|
|
||||||
" export interface CodeBlock {
|
|
||||||
" filetype?: string
|
|
||||||
" hlGroup?: string
|
|
||||||
" startLine: number // 0 based
|
|
||||||
" endLine: number
|
|
||||||
" }
|
|
||||||
function! coc#highlight#add_highlights(winid, codes, highlights) abort
|
|
||||||
if get(g:, 'coc_node_env', '') ==# 'test'
|
|
||||||
call setwinvar(a:winid, 'highlights', a:highlights)
|
|
||||||
endif
|
|
||||||
" clear highlights
|
|
||||||
call coc#compat#execute(a:winid, 'syntax clear')
|
|
||||||
let bufnr = winbufnr(a:winid)
|
|
||||||
call coc#highlight#clear_highlight(bufnr, -1, 0, -1)
|
|
||||||
if !empty(a:codes)
|
|
||||||
call coc#highlight#highlight_lines(a:winid, a:codes)
|
|
||||||
endif
|
|
||||||
if !empty(a:highlights)
|
|
||||||
for item in a:highlights
|
|
||||||
let hlGroup = item['hlGroup']
|
|
||||||
let opts = hlGroup =~# 'Search$' ? {'priority': 999, 'combine': 1} : {}
|
|
||||||
call coc#highlight#add_highlight(bufnr, -1, hlGroup, item['lnum'], item['colStart'], item['colEnd'])
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
|
|
||||||
" Add highlights to line groups of winid, support hlGroup and filetype
|
|
||||||
" config should have startLine, endLine (0 based, end excluded) and filetype or hlGroup
|
|
||||||
" endLine should > startLine and endLine is excluded
|
|
||||||
"
|
|
||||||
" export interface CodeBlock {
|
|
||||||
" filetype?: string
|
|
||||||
" hlGroup?: string
|
|
||||||
" startLine: number // 0 based
|
|
||||||
" endLine: number
|
|
||||||
" }
|
|
||||||
function! coc#highlight#highlight_lines(winid, blocks) abort
|
|
||||||
let region_id = 1
|
|
||||||
let defined = []
|
|
||||||
let cmds = []
|
|
||||||
for config in a:blocks
|
|
||||||
let start = config['startLine'] + 1
|
|
||||||
let end = config['endLine'] == -1 ? len(getbufline(winbufnr(a:winid), 1, '$')) + 1 : config['endLine'] + 1
|
|
||||||
let filetype = get(config, 'filetype', '')
|
|
||||||
let hlGroup = get(config, 'hlGroup', '')
|
|
||||||
if !empty(hlGroup)
|
|
||||||
call add(cmds, 'syntax region '.hlGroup.' start=/\%'.start.'l/ end=/\%'.end.'l/')
|
|
||||||
else
|
|
||||||
let filetype = matchstr(filetype, '\v^\w+')
|
|
||||||
if empty(filetype) || filetype == 'txt' || index(get(g:, 'coc_markdown_disabled_languages', []), filetype) != -1
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
if index(defined, filetype) == -1
|
|
||||||
call add(cmds, 'syntax include @'.toupper(filetype).' syntax/'.filetype.'.vim')
|
|
||||||
call add(cmds, 'unlet! b:current_syntax')
|
|
||||||
call add(defined, filetype)
|
|
||||||
endif
|
|
||||||
call add(cmds, 'syntax region CodeBlock'.region_id.' start=/\%'.start.'l/ end=/\%'.end.'l/ contains=@'.toupper(filetype).' keepend')
|
|
||||||
let region_id = region_id + 1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
if !empty(cmds)
|
|
||||||
call coc#compat#execute(a:winid, cmds, 'silent!')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#compose(fg, bg) abort
|
|
||||||
let fgId = synIDtrans(hlID(a:fg))
|
|
||||||
let bgId = synIDtrans(hlID(a:bg))
|
|
||||||
let isGuiReversed = synIDattr(fgId, 'reverse', 'gui') !=# '1' || synIDattr(bgId, 'reverse', 'gui') !=# '1'
|
|
||||||
let guifg = isGuiReversed ? synIDattr(fgId, 'fg', 'gui') : synIDattr(fgId, 'bg', 'gui')
|
|
||||||
let guibg = isGuiReversed ? synIDattr(bgId, 'bg', 'gui') : synIDattr(bgId, 'fg', 'gui')
|
|
||||||
let isCtermReversed = synIDattr(fgId, 'reverse', 'cterm') !=# '1' || synIDattr(bgId, 'reverse', 'cterm') !=# '1'
|
|
||||||
let ctermfg = isCtermReversed ? synIDattr(fgId, 'fg', 'cterm') : synIDattr(fgId, 'bg', 'cterm')
|
|
||||||
let ctermbg = isCtermReversed ? synIDattr(bgId, 'bg', 'cterm') : synIDattr(bgId, 'fg', 'cterm')
|
|
||||||
let bold = synIDattr(fgId, 'bold') ==# '1'
|
|
||||||
let italic = synIDattr(fgId, 'italic') ==# '1'
|
|
||||||
let underline = synIDattr(fgId, 'underline') ==# '1'
|
|
||||||
let cmd = ''
|
|
||||||
if !empty(guifg)
|
|
||||||
let cmd .= ' guifg=' . guifg
|
|
||||||
endif
|
|
||||||
if !empty(ctermfg)
|
|
||||||
let cmd .= ' ctermfg=' . ctermfg
|
|
||||||
elseif guifg =~# '^#'
|
|
||||||
let cmd .= ' ctermfg=' . coc#color#rgb2term(strpart(guifg, 1))
|
|
||||||
endif
|
|
||||||
if !empty(guibg)
|
|
||||||
let cmd .= ' guibg=' . guibg
|
|
||||||
endif
|
|
||||||
if !empty(ctermbg)
|
|
||||||
let cmd .= ' ctermbg=' . ctermbg
|
|
||||||
elseif guibg =~# '^#'
|
|
||||||
let cmd .= ' ctermbg=' . coc#color#rgb2term(strpart(guibg, 1))
|
|
||||||
endif
|
|
||||||
if bold
|
|
||||||
let cmd .= ' cterm=bold gui=bold'
|
|
||||||
elseif italic
|
|
||||||
let cmd .= ' cterm=italic gui=italic'
|
|
||||||
elseif underline
|
|
||||||
let cmd .= ' cterm=underline gui=underline'
|
|
||||||
endif
|
|
||||||
return cmd
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#valid(hlGroup) abort
|
|
||||||
return hlexists(a:hlGroup) && execute('hi '.a:hlGroup, 'silent!') !~# ' cleared$'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Compose hlGroups with foreground and background colors.
|
|
||||||
function! coc#highlight#compose_hlgroup(fgGroup, bgGroup) abort
|
|
||||||
let hlGroup = 'Fg'.a:fgGroup.'Bg'.a:bgGroup
|
|
||||||
if a:fgGroup ==# a:bgGroup
|
|
||||||
return a:fgGroup
|
|
||||||
endif
|
|
||||||
if coc#highlight#valid(hlGroup)
|
|
||||||
return hlGroup
|
|
||||||
endif
|
|
||||||
let cmd = coc#highlight#compose(a:fgGroup, a:bgGroup)
|
|
||||||
if empty(cmd)
|
|
||||||
return 'Normal'
|
|
||||||
endif
|
|
||||||
execute 'silent hi ' . hlGroup . cmd
|
|
||||||
return hlGroup
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" hlGroup id, key => 'fg' | 'bg', kind => 'cterm' | 'gui'
|
|
||||||
function! coc#highlight#get_color(id, key, kind) abort
|
|
||||||
if synIDattr(a:id, 'reverse', a:kind) !=# '1'
|
|
||||||
return synIDattr(a:id, a:key, a:kind)
|
|
||||||
endif
|
|
||||||
return synIDattr(a:id, a:key ==# 'bg' ? 'fg' : 'bg', a:kind)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#get_hl_command(id, key, cterm, gui) abort
|
|
||||||
let cterm = coc#highlight#get_color(a:id, a:key, 'cterm')
|
|
||||||
let gui = coc#highlight#get_color(a:id, a:key, 'gui')
|
|
||||||
let cmd = ' cterm'.a:key.'=' . (empty(cterm) ? a:cterm : cterm)
|
|
||||||
let cmd .= ' gui'.a:key.'=' . (empty(gui) ? a:gui : gui)
|
|
||||||
return cmd
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#reversed(id) abort
|
|
||||||
let gui = has('gui_running') || &termguicolors == 1
|
|
||||||
if synIDattr(synIDtrans(a:id), 'reverse', gui ? 'gui' : 'cterm') == '1'
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#get_contrast(group1, group2) abort
|
|
||||||
let normal = coc#highlight#get_hex_color(synIDtrans(hlID('Normal')), 'bg', '#000000')
|
|
||||||
let bg1 = coc#highlight#get_hex_color(synIDtrans(hlID(a:group1)), 'bg', normal)
|
|
||||||
let bg2 = coc#highlight#get_hex_color(synIDtrans(hlID(a:group2)), 'bg', normal)
|
|
||||||
return coc#color#hex_contrast(bg1, bg2)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Darken or lighten background
|
|
||||||
function! coc#highlight#create_bg_command(group, amount) abort
|
|
||||||
let id = synIDtrans(hlID(a:group))
|
|
||||||
let normal = coc#highlight#get_hex_color(synIDtrans(hlID('Normal')), 'bg', &background ==# 'dark' ? '#282828' : '#fefefe')
|
|
||||||
let bg = coc#highlight#get_hex_color(id, 'bg', normal)
|
|
||||||
let hex = a:amount > 0 ? coc#color#darken(bg, a:amount) : coc#color#lighten(bg, -a:amount)
|
|
||||||
|
|
||||||
let ctermbg = coc#color#rgb2term(strpart(hex, 1))
|
|
||||||
if s:term && !s:check_ctermbg(id, ctermbg) && abs(a:amount) < 20.0
|
|
||||||
return coc#highlight#create_bg_command(a:group, a:amount * 2)
|
|
||||||
endif
|
|
||||||
return 'ctermbg=' . ctermbg.' guibg=' . hex
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#get_hex_color(id, kind, fallback) abort
|
|
||||||
let attr = coc#highlight#get_color(a:id, a:kind, s:term ? 'cterm' : 'gui')
|
|
||||||
let hex = s:to_hex_color(attr, s:term)
|
|
||||||
if empty(hex) && !s:term
|
|
||||||
let attr = coc#highlight#get_color(a:id, a:kind, 'cterm')
|
|
||||||
let hex = s:to_hex_color(attr, 1)
|
|
||||||
endif
|
|
||||||
return empty(hex) ? a:fallback : hex
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:check_ctermbg(id, cterm) abort
|
|
||||||
let attr = coc#highlight#get_color(a:id, 'bg', 'cterm')
|
|
||||||
if empty(attr)
|
|
||||||
let attr = coc#highlight#get_color(synIDtrans(hlID('Normal')), 'bg', 'cterm')
|
|
||||||
endif
|
|
||||||
if attr ==# a:cterm
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:to_hex_color(color, term) abort
|
|
||||||
if empty(a:color)
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
if a:color =~# '^#\x\+$'
|
|
||||||
return a:color
|
|
||||||
endif
|
|
||||||
if a:term && a:color =~# '^\d\+$'
|
|
||||||
return coc#color#term2rgb(a:color)
|
|
||||||
endif
|
|
||||||
let hex = coc#color#nameToHex(tolower(a:color), a:term)
|
|
||||||
return empty(hex) ? '' : hex
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" add matches for winid, use 0 for current window.
|
|
||||||
function! coc#highlight#match_ranges(winid, bufnr, ranges, hlGroup, priority) abort
|
|
||||||
let winid = a:winid == 0 ? win_getid() : a:winid
|
|
||||||
let bufnr = a:bufnr == 0 ? winbufnr(winid) : a:bufnr
|
|
||||||
if empty(getwininfo(winid)) || (a:bufnr != 0 && winbufnr(a:winid) != a:bufnr)
|
|
||||||
" not valid
|
|
||||||
return []
|
|
||||||
endif
|
|
||||||
if !s:clear_match_by_window
|
|
||||||
let curr = win_getid()
|
|
||||||
noa call win_gotoid(winid)
|
|
||||||
endif
|
|
||||||
let ids = []
|
|
||||||
for range in a:ranges
|
|
||||||
let pos = []
|
|
||||||
let start = range['start']
|
|
||||||
let end = range['end']
|
|
||||||
for lnum in range(start['line'] + 1, end['line'] + 1)
|
|
||||||
let arr = getbufline(bufnr, lnum)
|
|
||||||
let line = empty(arr) ? '' : arr[0]
|
|
||||||
if empty(line)
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
let colStart = lnum == start['line'] + 1 ? coc#string#byte_index(line, start['character']) + 1 : 1
|
|
||||||
let colEnd = lnum == end['line'] + 1 ? coc#string#byte_index(line, end['character']) + 1 : strlen(line) + 1
|
|
||||||
if colStart == colEnd
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
call add(pos, [lnum, colStart, colEnd - colStart])
|
|
||||||
endfor
|
|
||||||
if !empty(pos)
|
|
||||||
let opts = s:clear_match_by_window ? {'window': a:winid} : {}
|
|
||||||
let i = 1
|
|
||||||
let l = []
|
|
||||||
for p in pos
|
|
||||||
call add(l, p)
|
|
||||||
if i % 8 == 0
|
|
||||||
let id = matchaddpos(a:hlGroup, l, a:priority, -1, opts)
|
|
||||||
call add(ids, id)
|
|
||||||
let l = []
|
|
||||||
endif
|
|
||||||
let i += 1
|
|
||||||
endfor
|
|
||||||
if !empty(l)
|
|
||||||
let id = matchaddpos(a:hlGroup, l, a:priority, -1, opts)
|
|
||||||
call add(ids, id)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
if !s:clear_match_by_window
|
|
||||||
noa call win_gotoid(curr)
|
|
||||||
endif
|
|
||||||
return ids
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Clear matches by hlGroup regexp.
|
|
||||||
function! coc#highlight#clear_match_group(winid, match) abort
|
|
||||||
let winid = a:winid == 0 ? win_getid() : a:winid
|
|
||||||
if empty(getwininfo(winid))
|
|
||||||
" not valid
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if s:clear_match_by_window
|
|
||||||
let arr = filter(getmatches(winid), 'v:val["group"] =~# "'.a:match.'"')
|
|
||||||
for item in arr
|
|
||||||
call matchdelete(item['id'], winid)
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
let curr = win_getid()
|
|
||||||
let switch = exists('*nvim_set_current_win') && curr != winid
|
|
||||||
if switch
|
|
||||||
noa call nvim_set_current_win(a:winid)
|
|
||||||
endif
|
|
||||||
if win_getid() == winid
|
|
||||||
let arr = filter(getmatches(), 'v:val["group"] =~# "'.a:match.'"')
|
|
||||||
for item in arr
|
|
||||||
call matchdelete(item['id'])
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
if switch
|
|
||||||
noa call nvim_set_current_win(curr)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Clear matches by match ids, use 0 for current win.
|
|
||||||
function! coc#highlight#clear_matches(winid, ids)
|
|
||||||
let winid = a:winid == 0 ? win_getid() : a:winid
|
|
||||||
if empty(getwininfo(winid))
|
|
||||||
" not valid
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if s:clear_match_by_window
|
|
||||||
for id in a:ids
|
|
||||||
try
|
|
||||||
call matchdelete(id, winid)
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E803/
|
|
||||||
" ignore
|
|
||||||
endtry
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
let curr = win_getid()
|
|
||||||
let switch = exists('*nvim_set_current_win') && curr != winid
|
|
||||||
if switch
|
|
||||||
noa call nvim_set_current_win(a:winid)
|
|
||||||
endif
|
|
||||||
if win_getid() == winid
|
|
||||||
for id in a:ids
|
|
||||||
try
|
|
||||||
call matchdelete(id)
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E803/
|
|
||||||
" ignore
|
|
||||||
endtry
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
if switch
|
|
||||||
noa call nvim_set_current_win(curr)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#clear_all() abort
|
|
||||||
for src_id in values(s:namespace_map)
|
|
||||||
for bufnr in map(getbufinfo({'bufloaded': 1}), 'v:val["bufnr"]')
|
|
||||||
if has('nvim')
|
|
||||||
call nvim_buf_clear_namespace(bufnr, src_id, 0, -1)
|
|
||||||
else
|
|
||||||
call coc#api#exec('buf_clear_namespace', [bufnr, src_id, 0, -1])
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#create_namespace(key) abort
|
|
||||||
if type(a:key) == 0
|
|
||||||
return a:key
|
|
||||||
endif
|
|
||||||
if has_key(s:namespace_map, a:key)
|
|
||||||
return s:namespace_map[a:key]
|
|
||||||
endif
|
|
||||||
if has('nvim')
|
|
||||||
let s:namespace_map[a:key] = nvim_create_namespace('coc-'.a:key)
|
|
||||||
else
|
|
||||||
let s:namespace_map[a:key] = s:ns_id
|
|
||||||
let s:ns_id = s:ns_id + 1
|
|
||||||
endif
|
|
||||||
return s:namespace_map[a:key]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#highlight#get_syntax_name(lnum, col)
|
|
||||||
return synIDattr(synIDtrans(synID(a:lnum,a:col,1)),"name")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:prop_type_hlgroup(type) abort
|
|
||||||
return substitute(a:type, '_\d\+$', '', '')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:update_highlights_timer(bufnr, changedtick, key, priority, groups, idx) abort
|
|
||||||
if getbufvar(a:bufnr, 'changedtick', 0) != a:changedtick
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let group = get(a:groups, a:idx, v:null)
|
|
||||||
if empty(group)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if empty(group['highlights'])
|
|
||||||
call coc#highlight#clear_highlight(a:bufnr, a:key, group['start'], group['end'])
|
|
||||||
else
|
|
||||||
call coc#highlight#update_highlights(a:bufnr, a:key, group['highlights'], group['start'], group['end'], a:priority)
|
|
||||||
endif
|
|
||||||
if a:idx < len(a:groups) - 1
|
|
||||||
call timer_start(50, { -> s:update_highlights_timer(a:bufnr, a:changedtick, a:key, a:priority, a:groups, a:idx + 1)})
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:add_highlights_timer(bufnr, ns, highlights, priority) abort
|
|
||||||
let hls = []
|
|
||||||
let next = []
|
|
||||||
for i in range(0, len(a:highlights) - 1)
|
|
||||||
if i < g:coc_highlight_maximum_count
|
|
||||||
call add(hls, a:highlights[i])
|
|
||||||
else
|
|
||||||
call add(next, a:highlights[i])
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
call s:add_highlights(a:bufnr, a:ns, hls, a:priority)
|
|
||||||
if len(next)
|
|
||||||
call timer_start(30, {->s:add_highlights_timer(a:bufnr, a:ns, next, a:priority)})
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:add_highlights(bufnr, ns, highlights, priority) abort
|
|
||||||
for item in a:highlights
|
|
||||||
let opts = {
|
|
||||||
\ 'priority': a:priority,
|
|
||||||
\ 'combine': get(item, 4, 1) ? 1 : 0,
|
|
||||||
\ 'start_incl': get(item, 5, 0) ? 1 : 0,
|
|
||||||
\ 'end_incl': get(item, 6, 0) ? 1 : 0,
|
|
||||||
\ }
|
|
||||||
call coc#highlight#add_highlight(a:bufnr, a:ns, item[0], item[1], item[2], item[3], opts)
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:to_group(items) abort
|
|
||||||
let res = []
|
|
||||||
let before = v:null
|
|
||||||
for item in a:items
|
|
||||||
if empty(before) || before[0] != item[1]
|
|
||||||
let before = [item[1], [item]]
|
|
||||||
call add(res, before)
|
|
||||||
else
|
|
||||||
call add(before[1], item)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return res
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_priority(key, hlGroup, priority) abort
|
|
||||||
if a:hlGroup ==# 'CocListSearch'
|
|
||||||
return 2048
|
|
||||||
endif
|
|
||||||
if a:hlGroup ==# 'CocSearch'
|
|
||||||
return 999
|
|
||||||
endif
|
|
||||||
if strpart(a:key, 0, 10) !=# 'diagnostic'
|
|
||||||
return a:priority
|
|
||||||
endif
|
|
||||||
return a:priority - index(s:diagnostic_hlgroups, a:hlGroup)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:group_hls(hls, linecount) abort
|
|
||||||
" start, end, highlights
|
|
||||||
let groups = []
|
|
||||||
if empty(a:hls)
|
|
||||||
call add(groups, {'start': 0, 'end': a:linecount, 'highlights': []})
|
|
||||||
return groups
|
|
||||||
endif
|
|
||||||
let start = 0
|
|
||||||
let highlights = []
|
|
||||||
let lastLnum = -1
|
|
||||||
for item in a:hls
|
|
||||||
let lnum = item['lnum']
|
|
||||||
if lnum >= a:linecount
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
if len(highlights) < g:coc_highlight_maximum_count || lnum == lastLnum
|
|
||||||
call add(highlights, item)
|
|
||||||
let lastLnum = lnum
|
|
||||||
else
|
|
||||||
call add(groups, {'start': start, 'end': lastLnum + 1, 'highlights': highlights})
|
|
||||||
let highlights = []
|
|
||||||
let start = lastLnum + 1
|
|
||||||
call add(highlights, item)
|
|
||||||
let lastLnum = lnum
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
call add(groups, {'start': start, 'end': a:linecount, 'highlights': highlights})
|
|
||||||
return groups
|
|
||||||
endfunction
|
|
|
@ -1,466 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:prefix = '[List Preview]'
|
|
||||||
let s:sign_group = 'CocList'
|
|
||||||
" filetype detect could be slow.
|
|
||||||
let s:filetype_map = {
|
|
||||||
\ 'c': 'c',
|
|
||||||
\ 'py': 'python',
|
|
||||||
\ 'vim': 'vim',
|
|
||||||
\ 'ts': 'typescript',
|
|
||||||
\ 'js': 'javascript',
|
|
||||||
\ 'html': 'html',
|
|
||||||
\ 'css': 'css'
|
|
||||||
\ }
|
|
||||||
let s:pwinid = -1
|
|
||||||
let s:pbufnr = -1
|
|
||||||
let s:match_ns = coc#highlight#create_namespace('list-match')
|
|
||||||
let s:sign_range = 'CocCursorLine'
|
|
||||||
let s:sign_popup_range = 'PopUpCocList'
|
|
||||||
let s:current_line_hl = 'CocListCurrent'
|
|
||||||
|
|
||||||
function! coc#list#getchar() abort
|
|
||||||
return coc#prompt#getchar()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#setlines(bufnr, lines, append)
|
|
||||||
if a:append
|
|
||||||
silent call appendbufline(a:bufnr, '$', a:lines)
|
|
||||||
else
|
|
||||||
if exists('*deletebufline')
|
|
||||||
silent call deletebufline(a:bufnr, len(a:lines) + 1, '$')
|
|
||||||
else
|
|
||||||
let n = len(a:lines) + 1
|
|
||||||
let saved_reg = @"
|
|
||||||
silent execute n.',$d'
|
|
||||||
let @" = saved_reg
|
|
||||||
endif
|
|
||||||
silent call setbufline(a:bufnr, 1, a:lines)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#options(...)
|
|
||||||
let list = ['--top', '--tab', '--normal', '--no-sort', '--input=', '--strict',
|
|
||||||
\ '--regex', '--interactive', '--number-select', '--auto-preview',
|
|
||||||
\ '--ignore-case', '--no-quit', '--first', '--reverse', '--height=']
|
|
||||||
if get(g:, 'coc_enabled', 0)
|
|
||||||
let names = coc#rpc#request('listNames', [])
|
|
||||||
call extend(list, names)
|
|
||||||
endif
|
|
||||||
return join(list, "\n")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#names(...) abort
|
|
||||||
let names = coc#rpc#request('listNames', [])
|
|
||||||
return join(names, "\n")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#status(name)
|
|
||||||
if !exists('b:list_status') | return '' | endif
|
|
||||||
return get(b:list_status, a:name, '')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#create(position, height, name, numberSelect)
|
|
||||||
if a:position ==# 'tab'
|
|
||||||
call coc#ui#safe_open('silent tabe', 'list:///'.a:name)
|
|
||||||
else
|
|
||||||
call s:save_views(-1)
|
|
||||||
let height = max([1, a:height])
|
|
||||||
let cmd = 'silent keepalt '.(a:position ==# 'top' ? '' : 'botright').height.'sp'
|
|
||||||
call coc#ui#safe_open(cmd, 'list:///'.a:name)
|
|
||||||
call s:set_height(height)
|
|
||||||
call s:restore_views()
|
|
||||||
endif
|
|
||||||
if a:numberSelect
|
|
||||||
setl norelativenumber
|
|
||||||
setl number
|
|
||||||
else
|
|
||||||
setl nonumber
|
|
||||||
setl norelativenumber
|
|
||||||
endif
|
|
||||||
setl colorcolumn=""
|
|
||||||
return [bufnr('%'), win_getid(), tabpagenr()]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" close list windows
|
|
||||||
function! coc#list#clean_up() abort
|
|
||||||
for i in range(1, winnr('$'))
|
|
||||||
let bufname = bufname(winbufnr(i))
|
|
||||||
if bufname =~# 'list://'
|
|
||||||
execute i.'close!'
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#setup(source)
|
|
||||||
let b:list_status = {}
|
|
||||||
setl buftype=nofile nobuflisted nofen nowrap
|
|
||||||
setl norelativenumber bufhidden=wipe nocursorline winfixheight
|
|
||||||
setl tabstop=1 nolist nocursorcolumn undolevels=-1
|
|
||||||
setl signcolumn=auto
|
|
||||||
if exists('&cursorlineopt')
|
|
||||||
setl cursorlineopt=both
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
setl nocursorline
|
|
||||||
else
|
|
||||||
setl cursorline
|
|
||||||
setl winhighlight=CursorLine:CocListLine
|
|
||||||
endif
|
|
||||||
if has('nvim-0.5.0') || has('patch-8.1.0864')
|
|
||||||
setl scrolloff=0
|
|
||||||
endif
|
|
||||||
setl filetype=list
|
|
||||||
syntax case ignore
|
|
||||||
let source = a:source[8:]
|
|
||||||
let name = toupper(source[0]).source[1:]
|
|
||||||
execute 'syntax match Coc'.name.'Line /\v^.*$/'
|
|
||||||
if !s:is_vim
|
|
||||||
" Repeat press <C-f> and <C-b> would invoke <esc> on vim
|
|
||||||
nnoremap <silent><nowait><buffer> <esc> <C-w>c
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#close(winid, position, target_win, saved_height) abort
|
|
||||||
let tabnr = coc#window#tabnr(a:winid)
|
|
||||||
if a:position ==# 'tab'
|
|
||||||
if tabnr != -1
|
|
||||||
call coc#list#close_preview(tabnr, 0)
|
|
||||||
endif
|
|
||||||
call coc#window#close(a:winid)
|
|
||||||
else
|
|
||||||
call s:save_views(a:winid)
|
|
||||||
if tabnr != -1
|
|
||||||
call coc#list#close_preview(tabnr, 0)
|
|
||||||
endif
|
|
||||||
if type(a:target_win) == v:t_number
|
|
||||||
call win_gotoid(a:target_win)
|
|
||||||
endif
|
|
||||||
call coc#window#close(a:winid)
|
|
||||||
call s:restore_views()
|
|
||||||
if type(a:saved_height) == v:t_number
|
|
||||||
call coc#window#set_height(a:target_win, a:saved_height)
|
|
||||||
endif
|
|
||||||
" call coc#rpc#notify('Log', ["close", a:target_win, v])
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#select(bufnr, line) abort
|
|
||||||
if s:is_vim && !empty(a:bufnr) && bufloaded(a:bufnr)
|
|
||||||
call sign_unplace(s:sign_group, { 'buffer': a:bufnr })
|
|
||||||
if a:line > 0
|
|
||||||
call sign_place(6, s:sign_group, s:current_line_hl, a:bufnr, {'lnum': a:line})
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Check if previewwindow exists on current tab.
|
|
||||||
function! coc#list#has_preview()
|
|
||||||
if s:pwinid != -1 && coc#window#visible(s:pwinid)
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
for i in range(1, winnr('$'))
|
|
||||||
let preview = getwinvar(i, 'previewwindow', getwinvar(i, '&previewwindow', 0))
|
|
||||||
if preview
|
|
||||||
return i
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Get previewwindow from tabnr, use 0 for current tab
|
|
||||||
function! coc#list#get_preview(...) abort
|
|
||||||
if s:pwinid != -1 && coc#window#visible(s:pwinid)
|
|
||||||
return s:pwinid
|
|
||||||
endif
|
|
||||||
let tabnr = get(a:, 1, 0) == 0 ? tabpagenr() : a:1
|
|
||||||
let info = gettabinfo(tabnr)
|
|
||||||
if !empty(info)
|
|
||||||
for win in info[0]['windows']
|
|
||||||
if gettabwinvar(tabnr, win, 'previewwindow', 0)
|
|
||||||
return win
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
return -1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#scroll_preview(dir) abort
|
|
||||||
let winid = coc#list#get_preview()
|
|
||||||
if winid == -1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if exists('*win_execute')
|
|
||||||
call win_execute(winid, "normal! ".(a:dir ==# 'up' ? "\<C-u>" : "\<C-d>"))
|
|
||||||
else
|
|
||||||
let id = win_getid()
|
|
||||||
noa call win_gotoid(winid)
|
|
||||||
execute "normal! ".(a:dir ==# 'up' ? "\<C-u>" : "\<C-d>")
|
|
||||||
noa call win_gotoid(id)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#close_preview(...) abort
|
|
||||||
let tabnr = get(a:, 1, tabpagenr())
|
|
||||||
let winid = coc#list#get_preview(tabnr)
|
|
||||||
if winid != -1
|
|
||||||
let keep = get(a:, 2, 1) && tabnr == tabpagenr() && !coc#window#is_float(winid)
|
|
||||||
if keep
|
|
||||||
call s:save_views(winid)
|
|
||||||
endif
|
|
||||||
call coc#window#close(winid)
|
|
||||||
if keep
|
|
||||||
call s:restore_views()
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_preview_lines(lines, config) abort
|
|
||||||
if empty(a:lines)
|
|
||||||
if get(a:config, 'scheme', 'file') !=# 'file'
|
|
||||||
let bufnr = s:load_buffer(get(a:config, 'name', ''))
|
|
||||||
return bufnr == 0 ? [''] : getbufline(bufnr, 1, '$')
|
|
||||||
else
|
|
||||||
return ['']
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return a:lines
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#list#float_preview(lines, config) abort
|
|
||||||
let position = get(a:config, 'position', 'bottom')
|
|
||||||
if position ==# 'tab'
|
|
||||||
throw 'unable to use float preview'
|
|
||||||
endif
|
|
||||||
let remain = 0
|
|
||||||
let winrow = win_screenpos(winnr())[0]
|
|
||||||
if position ==# 'bottom'
|
|
||||||
let remain = winrow - 2
|
|
||||||
else
|
|
||||||
let winbottom = winrow + winheight(winnr())
|
|
||||||
let remain = &lines - &cmdheight - 1 - winbottom
|
|
||||||
endif
|
|
||||||
let lines = s:get_preview_lines(a:lines, a:config)
|
|
||||||
let height = s:get_preview_height(lines, a:config)
|
|
||||||
let height = min([remain, height + 2])
|
|
||||||
if height < 0
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let row = position ==# 'bottom' ? winrow - 3 - height : winrow + winheight(winnr())
|
|
||||||
let title = fnamemodify(get(a:config, 'name', ''), ':.')
|
|
||||||
let total = get(get(b:, 'list_status', {}), 'total', 0)
|
|
||||||
if !empty(total)
|
|
||||||
let title .= ' ('.line('.').'/'.total.')'
|
|
||||||
endif
|
|
||||||
let lnum = min([get(a:config, 'lnum', 1), len(lines)])
|
|
||||||
let opts = {
|
|
||||||
\ 'relative': 'editor',
|
|
||||||
\ 'width': winwidth(winnr()) - 2,
|
|
||||||
\ 'borderhighlight': 'MoreMsg',
|
|
||||||
\ 'highlight': 'Normal',
|
|
||||||
\ 'height': height,
|
|
||||||
\ 'col': 0,
|
|
||||||
\ 'index': lnum - 1,
|
|
||||||
\ 'row': row,
|
|
||||||
\ 'border': [1,1,1,1],
|
|
||||||
\ 'rounded': 1,
|
|
||||||
\ 'lines': lines,
|
|
||||||
\ 'scrollinside': 1,
|
|
||||||
\ 'title': title,
|
|
||||||
\ }
|
|
||||||
let result = coc#float#create_float_win(s:pwinid, s:pbufnr, opts)
|
|
||||||
if empty(result)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let s:pwinid = result[0]
|
|
||||||
let s:pbufnr = result[1]
|
|
||||||
call setwinvar(s:pwinid, 'previewwindow', 1)
|
|
||||||
let topline = s:get_topline(a:config, lnum, height)
|
|
||||||
call coc#window#restview(s:pwinid, lnum, topline)
|
|
||||||
call s:preview_highlights(s:pwinid, s:pbufnr, a:config, 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Improve preview performance by reused window & buffer.
|
|
||||||
" lines - list of lines
|
|
||||||
" config.position - could be 'bottom' 'top' 'tab'.
|
|
||||||
" config.winid - id of original window.
|
|
||||||
" config.name - (optional )name of preview buffer.
|
|
||||||
" config.splitRight - (optional) split to right when 1.
|
|
||||||
" config.lnum - (optional) current line number
|
|
||||||
" config.filetype - (optional) filetype of lines.
|
|
||||||
" config.range - (optional) highlight range. with hlGroup.
|
|
||||||
" config.hlGroup - (optional) highlight group.
|
|
||||||
" config.maxHeight - (optional) max height of window, valid for 'bottom' & 'top' position.
|
|
||||||
function! coc#list#preview(lines, config) abort
|
|
||||||
let lines = s:get_preview_lines(a:lines, a:config)
|
|
||||||
let winid = coc#list#get_preview(0)
|
|
||||||
let bufnr = winid == -1 ? 0 : winbufnr(winid)
|
|
||||||
" Try reuse buffer & window
|
|
||||||
let bufnr = coc#float#create_buf(bufnr, lines)
|
|
||||||
if bufnr == 0
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let lnum = get(a:config, 'lnum', 1)
|
|
||||||
let position = get(a:config, 'position', 'bottom')
|
|
||||||
let original = get(a:config, 'winid', -1)
|
|
||||||
if winid == -1
|
|
||||||
let change = position != 'tab' && get(a:config, 'splitRight', 0)
|
|
||||||
let curr = win_getid()
|
|
||||||
if change
|
|
||||||
if original && win_id2win(original)
|
|
||||||
noa call win_gotoid(original)
|
|
||||||
else
|
|
||||||
noa wincmd t
|
|
||||||
endif
|
|
||||||
execute 'noa belowright vert sb '.bufnr
|
|
||||||
let winid = win_getid()
|
|
||||||
elseif position == 'tab' || get(a:config, 'splitRight', 0)
|
|
||||||
execute 'noa belowright vert sb '.bufnr
|
|
||||||
let winid = win_getid()
|
|
||||||
else
|
|
||||||
let mod = position == 'top' ? 'below' : 'above'
|
|
||||||
let height = s:get_preview_height(lines, a:config)
|
|
||||||
call s:save_views(-1)
|
|
||||||
execute 'noa '.mod.' sb +resize\ '.height.' '.bufnr
|
|
||||||
call s:restore_views()
|
|
||||||
let winid = win_getid()
|
|
||||||
endif
|
|
||||||
call setbufvar(bufnr, '&synmaxcol', 500)
|
|
||||||
noa call winrestview({"lnum": lnum ,"topline":s:get_topline(a:config, lnum, winheight(winid))})
|
|
||||||
call s:set_preview_options(winid)
|
|
||||||
noa call win_gotoid(curr)
|
|
||||||
else
|
|
||||||
let height = s:get_preview_height(lines, a:config)
|
|
||||||
if height > 0
|
|
||||||
if s:is_vim
|
|
||||||
let curr = win_getid()
|
|
||||||
noa call win_gotoid(winid)
|
|
||||||
execute 'silent! noa resize '.height
|
|
||||||
noa call win_gotoid(curr)
|
|
||||||
else
|
|
||||||
call s:save_views(winid)
|
|
||||||
call nvim_win_set_height(winid, height)
|
|
||||||
call s:restore_views()
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call coc#window#restview(winid, lnum, s:get_topline(a:config, lnum, height))
|
|
||||||
endif
|
|
||||||
call s:preview_highlights(winid, bufnr, a:config, 0)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:preview_highlights(winid, bufnr, config, float) abort
|
|
||||||
let name = fnamemodify(get(a:config, 'name', ''), ':.')
|
|
||||||
let newname = s:prefix.' '.name
|
|
||||||
if newname !=# bufname(a:bufnr)
|
|
||||||
if s:is_vim
|
|
||||||
call win_execute(a:winid, 'noa file '.fnameescape(newname), 'silent!')
|
|
||||||
else
|
|
||||||
silent! noa call nvim_buf_set_name(a:bufnr, newname)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
let filetype = get(a:config, 'filetype', '')
|
|
||||||
let extname = matchstr(name, '\.\zs[^.]\+$')
|
|
||||||
if empty(filetype) && !empty(extname)
|
|
||||||
let filetype = get(s:filetype_map, extname, '')
|
|
||||||
endif
|
|
||||||
" highlights
|
|
||||||
let sign_group = s:is_vim && a:float ? s:sign_popup_range : s:sign_range
|
|
||||||
call coc#compat#execute(a:winid, ['syntax clear', 'call clearmatches()'])
|
|
||||||
call sign_unplace(sign_group, {'buffer': a:bufnr})
|
|
||||||
let lnum = get(a:config, 'lnum', 1)
|
|
||||||
if !empty(filetype)
|
|
||||||
let start = max([0, lnum - 300])
|
|
||||||
let end = min([coc#compat#buf_line_count(a:bufnr), lnum + 300])
|
|
||||||
call coc#highlight#highlight_lines(a:winid, [{'filetype': filetype, 'startLine': start, 'endLine': end}])
|
|
||||||
call coc#compat#execute(a:winid, 'syn sync fromstart')
|
|
||||||
else
|
|
||||||
call coc#compat#execute(a:winid, 'filetype detect')
|
|
||||||
let ft = getbufvar(a:bufnr, '&filetype', '')
|
|
||||||
if !empty(extname) && !empty(ft)
|
|
||||||
let s:filetype_map[extname] = ft
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
" selection range
|
|
||||||
let targetRange = get(a:config, 'targetRange', v:null)
|
|
||||||
if !empty(targetRange)
|
|
||||||
for lnum in range(targetRange['start']['line'] + 1, targetRange['end']['line'] + 1)
|
|
||||||
call sign_place(0, sign_group, s:current_line_hl, a:bufnr, {'lnum': lnum})
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
let range = get(a:config, 'range', v:null)
|
|
||||||
if !empty(range)
|
|
||||||
let hlGroup = get(a:config, 'hlGroup', 'Search')
|
|
||||||
call coc#highlight#match_ranges(a:winid, a:bufnr, [range], hlGroup, 10)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_preview_height(lines, config) abort
|
|
||||||
if get(a:config, 'splitRight', 0) || get(a:config, 'position', 'bottom') == 'tab'
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
let height = min([get(a:config, 'maxHeight', 10), len(a:lines), &lines - &cmdheight - 2])
|
|
||||||
return height
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:load_buffer(name) abort
|
|
||||||
if exists('*bufadd') && exists('*bufload')
|
|
||||||
let bufnr = bufadd(a:name)
|
|
||||||
call bufload(bufnr)
|
|
||||||
return bufnr
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_topline(config, lnum, winheight) abort
|
|
||||||
let toplineStyle = get(a:config, 'toplineStyle', 'offset')
|
|
||||||
if toplineStyle == 'middle'
|
|
||||||
return max([1, a:lnum - a:winheight/2])
|
|
||||||
endif
|
|
||||||
let toplineOffset = get(a:config, 'toplineOffset', 3)
|
|
||||||
return max([1, a:lnum - toplineOffset])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:set_preview_options(winid) abort
|
|
||||||
call setwinvar(a:winid, '&foldmethod', 'manual')
|
|
||||||
call setwinvar(a:winid, '&foldenable', 0)
|
|
||||||
call setwinvar(a:winid, '&signcolumn', 'no')
|
|
||||||
call setwinvar(a:winid, '&number', 1)
|
|
||||||
call setwinvar(a:winid, '&cursorline', 0)
|
|
||||||
call setwinvar(a:winid, '&relativenumber', 0)
|
|
||||||
call setwinvar(a:winid, 'previewwindow', 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" save views on current tabpage
|
|
||||||
function! s:save_views(exclude) abort
|
|
||||||
" Not work as expected when cursor becomes hidden
|
|
||||||
if s:is_vim
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
for nr in range(1, winnr('$'))
|
|
||||||
let winid = win_getid(nr)
|
|
||||||
if winid != a:exclude && getwinvar(nr, 'previewwindow', 0) == 0 && !coc#window#is_float(winid)
|
|
||||||
call coc#compat#execute(winid, 'let w:coc_list_saved_view = winsaveview()')
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:restore_views() abort
|
|
||||||
if s:is_vim
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
for nr in range(1, winnr('$'))
|
|
||||||
let saved = getwinvar(nr, 'coc_list_saved_view', v:null)
|
|
||||||
if !empty(saved)
|
|
||||||
let winid = win_getid(nr)
|
|
||||||
call coc#compat#execute(winid, 'noa call winrestview(w:coc_list_saved_view) | unlet w:coc_list_saved_view')
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:set_height(height) abort
|
|
||||||
let curr = winheight(0)
|
|
||||||
if curr != a:height
|
|
||||||
execute 'resize '.a:height
|
|
||||||
endif
|
|
||||||
endfunction
|
|
|
@ -1,11 +0,0 @@
|
||||||
|
|
||||||
" support for float values
|
|
||||||
function! coc#math#min(first, ...) abort
|
|
||||||
let val = a:first
|
|
||||||
for i in range(0, len(a:000) - 1)
|
|
||||||
if a:000[i] < val
|
|
||||||
let val = a:000[i]
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return val
|
|
||||||
endfunction
|
|
|
@ -1,539 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:utf = has('nvim') || &encoding =~# '^utf'
|
|
||||||
let s:error_icon = get(g:, 'coc_notify_error_icon', s:utf ? "\uf057" : 'E')
|
|
||||||
let s:warning_icon = get(g:, 'coc_notify_warning_icon', s:utf ? "\u26a0" : 'W')
|
|
||||||
let s:info_icon = get(g:, 'coc_notify_info_icon', s:utf ? "\uf06a" : 'I')
|
|
||||||
let s:interval = get(g:, 'coc_notify_interval', s:is_vim ? 50 : 20)
|
|
||||||
let s:phl = 'CocNotificationProgress'
|
|
||||||
let s:progress_char = '─'
|
|
||||||
let s:duration = 300.0
|
|
||||||
let s:winids = []
|
|
||||||
|
|
||||||
" Valid notify winids on current tab
|
|
||||||
function! coc#notify#win_list() abort
|
|
||||||
call filter(s:winids, 'coc#float#valid(v:val)')
|
|
||||||
return filter(copy(s:winids), '!empty(getwinvar(v:val,"float"))')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#notify#close_all() abort
|
|
||||||
for winid in coc#notify#win_list()
|
|
||||||
call coc#notify#close(winid)
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Do action for winid or first notify window with actions.
|
|
||||||
function! coc#notify#do_action(...) abort
|
|
||||||
let winids = a:0 > 0 ? a:000 : coc#notify#win_list()
|
|
||||||
for winid in winids
|
|
||||||
if coc#float#valid(winid) && getwinvar(winid, 'closing', 0) != 1
|
|
||||||
let actions = getwinvar(winid, 'actions', [])
|
|
||||||
if !empty(actions)
|
|
||||||
let items = map(copy(actions), '(v:key + 1).". ".v:val')
|
|
||||||
let msg = join(getbufline(winbufnr(winid), 1, '$'), ' ')
|
|
||||||
call coc#ui#quickpick(msg, items, {err, res -> s:on_action(err, res, winid) })
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Copy notification contents
|
|
||||||
function! coc#notify#copy() abort
|
|
||||||
let lines = []
|
|
||||||
for winid in coc#notify#win_list()
|
|
||||||
let key = getwinvar(winid, 'key', v:null)
|
|
||||||
if type(key) == v:t_string
|
|
||||||
call extend(lines, json_decode(key)['lines'])
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
if empty(lines)
|
|
||||||
echohl WarningMsg | echon 'No content to copy' | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call setreg('*', join(lines, "\n"))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Show source name in window
|
|
||||||
function! coc#notify#show_sources() abort
|
|
||||||
if !exists('*getbufline') || !exists('*appendbufline')
|
|
||||||
throw "getbufline and appendbufline functions required, please upgrade your vim."
|
|
||||||
endif
|
|
||||||
let winids = filter(coc#notify#win_list(), 'coc#window#get_var(v:val,"closing") != 1')
|
|
||||||
for winid in winids
|
|
||||||
let key = getwinvar(winid, 'key', v:null)
|
|
||||||
if type(key) == v:t_string
|
|
||||||
let bufnr = winbufnr(winid)
|
|
||||||
let obj = json_decode(key)
|
|
||||||
let sourcename = get(obj, 'source', '')
|
|
||||||
let lnum = get(obj, 'kind', '') ==# 'progress' ? 1 : 0
|
|
||||||
let content = get(getbufline(bufnr, lnum + 1), 0, '')
|
|
||||||
if empty(sourcename) || content ==# sourcename
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
call appendbufline(bufnr, lnum, sourcename)
|
|
||||||
call coc#highlight#add_highlight(bufnr, -1, 'Title', lnum, 0, -1)
|
|
||||||
call coc#float#scroll_win(winid, 0, 1)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
redra
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#notify#close_by_source(source) abort
|
|
||||||
let winids = filter(coc#notify#win_list(), 'coc#window#get_var(v:val,"closing") != 1')
|
|
||||||
for winid in winids
|
|
||||||
let key = getwinvar(winid, 'key', v:null)
|
|
||||||
if type(key) == v:t_string
|
|
||||||
let obj = json_decode(key)
|
|
||||||
if get(obj, 'source', '') ==# a:source
|
|
||||||
call coc#notify#close(winid)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Cancel auto hide
|
|
||||||
function! coc#notify#keep() abort
|
|
||||||
for winid in coc#notify#win_list()
|
|
||||||
call s:cancel(winid, 'close_timer')
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" borderhighlight - border highlight [string]
|
|
||||||
" maxWidth - max content width, default 60 [number]
|
|
||||||
" minWidth - minimal width [number]
|
|
||||||
" maxHeight - max content height, default 10 [number]
|
|
||||||
" highlight - default highlight [string]
|
|
||||||
" winblend - winblend [number]
|
|
||||||
" timeout - auto close timeout, default 5000 [number]
|
|
||||||
" title - title text
|
|
||||||
" marginRight - margin right, default 10 [number]
|
|
||||||
" focusable - focusable [number]
|
|
||||||
" source - source name [string]
|
|
||||||
" kind - kind for create icon [string]
|
|
||||||
" actions - action names [string[]]
|
|
||||||
" close - close button [boolean]
|
|
||||||
function! coc#notify#create(lines, config) abort
|
|
||||||
let actions = get(a:config, 'actions', [])
|
|
||||||
let key = json_encode(extend({'lines': a:lines}, a:config))
|
|
||||||
let winid = s:find_win(key)
|
|
||||||
let kind = get(a:config, 'kind', '')
|
|
||||||
let row = 0
|
|
||||||
if winid != -1
|
|
||||||
let row = getwinvar(winid, 'top', 0)
|
|
||||||
call filter(s:winids, 'v:val != '.winid)
|
|
||||||
call coc#float#close(winid, 1)
|
|
||||||
let winid = v:null
|
|
||||||
endif
|
|
||||||
let opts = coc#dict#pick(a:config, ['highlight', 'borderhighlight', 'focusable', 'shadow', 'close'])
|
|
||||||
let border = has_key(opts, 'borderhighlight') ? [1, 1, 1, 1] : []
|
|
||||||
let icon = s:get_icon(kind, get(a:config, 'highlight', 'CocFloating'))
|
|
||||||
let margin = get(a:config, 'marginRight', 10)
|
|
||||||
let maxWidth = min([&columns - margin - 2, get(a:config, 'maxWidth', 80)])
|
|
||||||
if maxWidth <= 0
|
|
||||||
throw 'No enough spaces for notification'
|
|
||||||
endif
|
|
||||||
let lines = map(copy(a:lines), 'tr(v:val, "\t", " ")')
|
|
||||||
if has_key(a:config, 'title')
|
|
||||||
if !empty(border)
|
|
||||||
let opts['title'] = a:config['title']
|
|
||||||
else
|
|
||||||
let lines = [a:config['title']] + lines
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let width = max(map(copy(lines), 'strwidth(v:val)')) + (empty(icon) ? 1 : 3)
|
|
||||||
if width > maxWidth
|
|
||||||
let lines = coc#string#reflow(lines, maxWidth)
|
|
||||||
let width = max(map(copy(lines), 'strwidth(v:val)')) + (empty(icon) ? 1 : 3)
|
|
||||||
endif
|
|
||||||
let highlights = []
|
|
||||||
if !empty(icon)
|
|
||||||
let ic = icon['text']
|
|
||||||
if empty(lines)
|
|
||||||
call add(lines, ic)
|
|
||||||
else
|
|
||||||
let lines[0] = ic.' '.lines[0]
|
|
||||||
endif
|
|
||||||
call add(highlights, {'lnum': 0, 'hlGroup': icon['hl'], 'colStart': 0, 'colEnd': strlen(ic)})
|
|
||||||
endif
|
|
||||||
let actionText = join(actions, ' ')
|
|
||||||
call map(lines, 'v:key == 0 ? v:val : repeat(" ", '.(empty(icon) ? 0 : 2).').v:val')
|
|
||||||
let minWidth = get(a:config, 'minWidth', kind ==# 'progress' ? 30 : 10)
|
|
||||||
let width = max(extend(map(lines + [get(opts, 'title', '').' '], 'strwidth(v:val)'), [minWidth, strwidth(actionText) + 1]))
|
|
||||||
let width = min([maxWidth, width])
|
|
||||||
let height = min([get(a:config, 'maxHeight', 3), len(lines)])
|
|
||||||
if kind ==# 'progress'
|
|
||||||
let lines = [repeat(s:progress_char, width)] + lines
|
|
||||||
let height = height + 1
|
|
||||||
endif
|
|
||||||
if !empty(actions)
|
|
||||||
let before = max([width - strwidth(actionText), 0])
|
|
||||||
let lines = lines + [repeat(' ', before).actionText]
|
|
||||||
let height = height + 1
|
|
||||||
call s:add_action_highlights(before, height - 1, highlights, actions)
|
|
||||||
endif
|
|
||||||
if row == 0
|
|
||||||
let wintop = coc#notify#get_top()
|
|
||||||
let row = wintop - height - (empty(border) ? 0 : 2) - 1
|
|
||||||
if !s:is_vim && !empty(border)
|
|
||||||
let row = row + 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let col = &columns - margin - width
|
|
||||||
if s:is_vim && !empty(border)
|
|
||||||
let col = col - 2
|
|
||||||
endif
|
|
||||||
let winblend = 60
|
|
||||||
" Avoid animate for transparent background.
|
|
||||||
if get(a:config, 'winblend', 30) == 0 && empty(synIDattr(synIDtrans(hlID(get(opts, 'highlight', 'CocFloating'))), 'bg', 'gui'))
|
|
||||||
let winblend = 0
|
|
||||||
endif
|
|
||||||
call extend(opts, {
|
|
||||||
\ 'relative': 'editor',
|
|
||||||
\ 'width': width,
|
|
||||||
\ 'height': height,
|
|
||||||
\ 'col': col,
|
|
||||||
\ 'row': row + 1,
|
|
||||||
\ 'lines': lines,
|
|
||||||
\ 'rounded': 1,
|
|
||||||
\ 'highlights': highlights,
|
|
||||||
\ 'winblend': winblend,
|
|
||||||
\ 'border': border,
|
|
||||||
\ })
|
|
||||||
let result = coc#float#create_float_win(0, 0, opts)
|
|
||||||
if empty(result)
|
|
||||||
throw 'Unable to create notify window'
|
|
||||||
endif
|
|
||||||
let winid = result[0]
|
|
||||||
let bufnr = result[1]
|
|
||||||
call setwinvar(winid, 'right', 1)
|
|
||||||
call setwinvar(winid, 'kind', 'notification')
|
|
||||||
call setwinvar(winid, 'top', row)
|
|
||||||
call setwinvar(winid, 'key', key)
|
|
||||||
call setwinvar(winid, 'actions', actions)
|
|
||||||
call setwinvar(winid, 'source', get(a:config, 'source', ''))
|
|
||||||
call setwinvar(winid, 'borders', !empty(border))
|
|
||||||
call coc#float#nvim_scrollbar(winid)
|
|
||||||
call add(s:winids, winid)
|
|
||||||
let from = {'row': opts['row'], 'winblend': opts['winblend']}
|
|
||||||
let to = {'row': row, 'winblend': get(a:config, 'winblend', 30)}
|
|
||||||
call timer_start(s:interval, { -> s:animate(winid, from, to, 0)})
|
|
||||||
if kind ==# 'progress'
|
|
||||||
call timer_start(s:interval, { -> s:progress(winid, width, 0, -1)})
|
|
||||||
endif
|
|
||||||
if !s:is_vim
|
|
||||||
call coc#compat#buf_add_keymap(bufnr, 'n', '<LeftRelease>', ':call coc#notify#nvim_click('.winid.')<CR>', {
|
|
||||||
\ 'silent': v:true,
|
|
||||||
\ 'nowait': v:true
|
|
||||||
\ })
|
|
||||||
endif
|
|
||||||
" Enable auto close
|
|
||||||
if empty(actions) && kind !=# 'progress'
|
|
||||||
let timer = timer_start(get(a:config, 'timeout', 10000), { -> coc#notify#close(winid)})
|
|
||||||
call setwinvar(winid, 'close_timer', timer)
|
|
||||||
endif
|
|
||||||
return [winid, bufnr]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#notify#nvim_click(winid) abort
|
|
||||||
if getwinvar(a:winid, 'closing', 0)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call s:cancel(a:winid, 'close_timer')
|
|
||||||
let actions = getwinvar(a:winid, 'actions', [])
|
|
||||||
if !empty(actions)
|
|
||||||
let character = strpart(getline('.'), col('.') - 1, 1)
|
|
||||||
if character =~# '^\k'
|
|
||||||
let word = expand('<cword>')
|
|
||||||
let idx = index(actions, word)
|
|
||||||
if idx != -1
|
|
||||||
call coc#rpc#notify('FloatBtnClick', [winbufnr(a:winid), idx])
|
|
||||||
call coc#notify#close(a:winid)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#notify#on_close(winid) abort
|
|
||||||
if index(s:winids, a:winid) >= 0
|
|
||||||
call filter(s:winids, 'v:val != '.a:winid)
|
|
||||||
call coc#notify#reflow()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#notify#get_top() abort
|
|
||||||
let mintop = min(map(coc#notify#win_list(), 'coc#notify#get_win_top(v:val)'))
|
|
||||||
if mintop != 0
|
|
||||||
return mintop
|
|
||||||
endif
|
|
||||||
return &lines - &cmdheight - (&laststatus == 0 ? 0 : 1 )
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#notify#get_win_top(winid) abort
|
|
||||||
let row = getwinvar(a:winid, 'top', 0)
|
|
||||||
if row == 0
|
|
||||||
return row
|
|
||||||
endif
|
|
||||||
return row - (s:is_vim ? 0 : getwinvar(a:winid, 'borders', 0))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Close with timer
|
|
||||||
function! coc#notify#close(winid) abort
|
|
||||||
if !coc#float#valid(a:winid) || coc#window#get_var(a:winid, 'closing', 0) == 1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if !coc#window#visible(a:winid)
|
|
||||||
call coc#float#close(a:winid, 1)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let row = coc#window#get_var(a:winid, 'top')
|
|
||||||
if type(row) != v:t_number
|
|
||||||
call coc#float#close(a:winid)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call coc#window#set_var(a:winid, 'closing', 1)
|
|
||||||
call s:cancel(a:winid)
|
|
||||||
let winblend = coc#window#get_var(a:winid, 'winblend', 0)
|
|
||||||
let curr = s:is_vim ? {'row': row} : {'winblend': winblend}
|
|
||||||
let dest = s:is_vim ? {'row': row + 1} : {'winblend': winblend == 0 ? 0 : 60}
|
|
||||||
call s:animate(a:winid, curr, dest, 0, 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:add_action_highlights(before, lnum, highlights, actions) abort
|
|
||||||
let colStart = a:before
|
|
||||||
for text in a:actions
|
|
||||||
let w = strwidth(text)
|
|
||||||
call add(a:highlights, {
|
|
||||||
\ 'lnum': a:lnum,
|
|
||||||
\ 'hlGroup': 'CocNotificationButton',
|
|
||||||
\ 'colStart': colStart,
|
|
||||||
\ 'colEnd': colStart + w
|
|
||||||
\ })
|
|
||||||
let colStart = colStart + w + 1
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:on_action(err, idx, winid) abort
|
|
||||||
if !empty(a:err)
|
|
||||||
throw a:err
|
|
||||||
endif
|
|
||||||
if a:idx > 0
|
|
||||||
call coc#rpc#notify('FloatBtnClick', [winbufnr(a:winid), a:idx - 1])
|
|
||||||
call coc#notify#close(a:winid)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:cancel(winid, ...) abort
|
|
||||||
let name = get(a:, 1, 'timer')
|
|
||||||
let timer = coc#window#get_var(a:winid, name)
|
|
||||||
if !empty(timer)
|
|
||||||
call timer_stop(timer)
|
|
||||||
call coc#window#set_var(a:winid, name, v:null)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:progress(winid, total, curr, index) abort
|
|
||||||
if !coc#float#valid(a:winid)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if coc#window#visible(a:winid)
|
|
||||||
let total = a:total
|
|
||||||
let idx = float2nr(a:curr/5.0)%total
|
|
||||||
let option = coc#float#get_options(a:winid)
|
|
||||||
let width = option['width']
|
|
||||||
if idx != a:index
|
|
||||||
" update percent & message
|
|
||||||
let bufnr = winbufnr(a:winid)
|
|
||||||
let percent = coc#window#get_var(a:winid, 'percent')
|
|
||||||
let lines = []
|
|
||||||
if !empty(percent)
|
|
||||||
let line = repeat(s:progress_char, width - 4).printf('%4s', percent)
|
|
||||||
let total = width - 4
|
|
||||||
call add(lines, line)
|
|
||||||
else
|
|
||||||
call add(lines, repeat(s:progress_char, width))
|
|
||||||
endif
|
|
||||||
let message = coc#window#get_var(a:winid, 'message')
|
|
||||||
if !empty(message)
|
|
||||||
let lines = lines + coc#string#reflow(split(message, '\v\r?\n'), width)
|
|
||||||
endif
|
|
||||||
noa call setbufline(bufnr, 1, lines)
|
|
||||||
noa call deletebufline(bufnr, len(lines) + 1, '$')
|
|
||||||
let height = option['height']
|
|
||||||
let delta = len(lines) - height
|
|
||||||
if delta > 0 && height < 3
|
|
||||||
call coc#float#change_height(a:winid, min([delta, 3 - height]))
|
|
||||||
let tabnr = coc#window#tabnr(a:winid)
|
|
||||||
call coc#notify#reflow(tabnr)
|
|
||||||
if len(lines) > 3
|
|
||||||
call coc#float#nvim_scrollbar(a:winid)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let bytes = strlen(s:progress_char)
|
|
||||||
call coc#highlight#clear_highlight(bufnr, -1, 0, 1)
|
|
||||||
let colStart = bytes * idx
|
|
||||||
if idx + 4 <= total
|
|
||||||
let colEnd = bytes * (idx + 4)
|
|
||||||
call coc#highlight#add_highlight(bufnr, -1, s:phl, 0, colStart, colEnd)
|
|
||||||
else
|
|
||||||
let colEnd = bytes * total
|
|
||||||
call coc#highlight#add_highlight(bufnr, -1, s:phl, 0, colStart, colEnd)
|
|
||||||
call coc#highlight#add_highlight(bufnr, -1, s:phl, 0, 0, bytes * (idx + 4 - total))
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call timer_start(s:interval, { -> s:progress(a:winid, total, a:curr + 1, idx)})
|
|
||||||
else
|
|
||||||
" Not block CursorHold event
|
|
||||||
call timer_start(&updatetime + 100, { -> s:progress(a:winid, a:total, a:curr, a:index)})
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Optional row & winblend
|
|
||||||
function! s:config_win(winid, props) abort
|
|
||||||
let change_row = has_key(a:props, 'row')
|
|
||||||
if s:is_vim
|
|
||||||
if change_row
|
|
||||||
call popup_move(a:winid, {'line': a:props['row'] + 1})
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if change_row
|
|
||||||
let [row, column] = nvim_win_get_position(a:winid)
|
|
||||||
call nvim_win_set_config(a:winid, {
|
|
||||||
\ 'row': a:props['row'],
|
|
||||||
\ 'col': column,
|
|
||||||
\ 'relative': 'editor',
|
|
||||||
\ })
|
|
||||||
call s:nvim_move_related(a:winid, a:props['row'])
|
|
||||||
endif
|
|
||||||
call coc#float#nvim_set_winblend(a:winid, get(a:props, 'winblend', v:null))
|
|
||||||
call coc#float#nvim_refresh_scrollbar(a:winid)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:nvim_move_related(winid, row) abort
|
|
||||||
let winids = coc#window#get_var(a:winid, 'related')
|
|
||||||
if empty(winids)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
for winid in winids
|
|
||||||
if nvim_win_is_valid(winid)
|
|
||||||
let [row, column] = nvim_win_get_position(winid)
|
|
||||||
let delta = coc#window#get_var(winid, 'delta', 0)
|
|
||||||
call nvim_win_set_config(winid, {
|
|
||||||
\ 'row': a:row + delta,
|
|
||||||
\ 'col': column,
|
|
||||||
\ 'relative': 'editor',
|
|
||||||
\ })
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:animate(winid, from, to, prev, ...) abort
|
|
||||||
if !coc#float#valid(a:winid)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let curr = a:prev + s:interval
|
|
||||||
let percent = coc#math#min(curr / s:duration, 1)
|
|
||||||
let props = s:get_props(a:from, a:to, percent)
|
|
||||||
call s:config_win(a:winid, props)
|
|
||||||
let close = get(a:, 1, 0)
|
|
||||||
if percent < 1
|
|
||||||
call timer_start(s:interval, { -> s:animate(a:winid, a:from, a:to, curr, close)})
|
|
||||||
elseif close
|
|
||||||
call filter(s:winids, 'v:val != '.a:winid)
|
|
||||||
let tabnr = coc#window#tabnr(a:winid)
|
|
||||||
if tabnr != -1
|
|
||||||
call coc#float#close(a:winid, 1)
|
|
||||||
call coc#notify#reflow(tabnr)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#notify#reflow(...) abort
|
|
||||||
let tabnr = get(a:, 1, tabpagenr())
|
|
||||||
let winids = filter(copy(s:winids), 'coc#window#tabnr(v:val) == '.tabnr.' && coc#window#get_var(v:val,"closing") != 1')
|
|
||||||
if empty(winids)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let animate = tabnr == tabpagenr()
|
|
||||||
let wins = map(copy(winids), {_, val -> {
|
|
||||||
\ 'winid': val,
|
|
||||||
\ 'row': coc#window#get_var(val,'top',0),
|
|
||||||
\ 'top': coc#window#get_var(val,'top',0) - (s:is_vim ? 0 : coc#window#get_var(val, 'borders', 0)),
|
|
||||||
\ 'height': coc#float#get_height(val),
|
|
||||||
\ }})
|
|
||||||
call sort(wins, {a, b -> b['top'] - a['top']})
|
|
||||||
let bottom = &lines - &cmdheight - (&laststatus == 0 ? 0 : 1 )
|
|
||||||
let moved = 0
|
|
||||||
for item in wins
|
|
||||||
let winid = item['winid']
|
|
||||||
let delta = bottom - (item['top'] + item['height'] + 1)
|
|
||||||
if delta != 0
|
|
||||||
call s:cancel(winid)
|
|
||||||
let dest = item['row'] + delta
|
|
||||||
call coc#window#set_var(winid, 'top', dest)
|
|
||||||
if animate
|
|
||||||
call s:move_win_timer(winid, {'row': item['row']}, {'row': dest}, 0)
|
|
||||||
else
|
|
||||||
call s:config_win(winid, {'row': dest})
|
|
||||||
endif
|
|
||||||
let moved = moved + delta
|
|
||||||
endif
|
|
||||||
let bottom = item['top'] + delta
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:move_win_timer(winid, from, to, curr) abort
|
|
||||||
if !coc#float#valid(a:winid)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if coc#window#get_var(a:winid, 'closing', 0) == 1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let percent = coc#math#min(a:curr / s:duration, 1)
|
|
||||||
let next = a:curr + s:interval
|
|
||||||
if a:curr > 0
|
|
||||||
call s:config_win(a:winid, s:get_props(a:from, a:to, percent))
|
|
||||||
endif
|
|
||||||
if percent < 1
|
|
||||||
let timer = timer_start(s:interval, { -> s:move_win_timer(a:winid, a:from, a:to, next)})
|
|
||||||
call coc#window#set_var(a:winid, 'timer', timer)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:find_win(key) abort
|
|
||||||
for winid in coc#notify#win_list()
|
|
||||||
if getwinvar(winid, 'key', '') ==# a:key
|
|
||||||
return winid
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return -1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_icon(kind, bg) abort
|
|
||||||
if a:kind ==# 'info'
|
|
||||||
return {'text': s:info_icon, 'hl': coc#highlight#compose_hlgroup('CocInfoSign', a:bg)}
|
|
||||||
endif
|
|
||||||
if a:kind ==# 'warning'
|
|
||||||
return {'text': s:warning_icon, 'hl': coc#highlight#compose_hlgroup('CocWarningSign', a:bg)}
|
|
||||||
endif
|
|
||||||
if a:kind ==# 'error'
|
|
||||||
return {'text': s:error_icon, 'hl': coc#highlight#compose_hlgroup('CocErrorSign', a:bg)}
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" percent should be float
|
|
||||||
function! s:get_props(from, to, percent) abort
|
|
||||||
let obj = {}
|
|
||||||
for key in keys(a:from)
|
|
||||||
let changed = a:to[key] - a:from[key]
|
|
||||||
if !s:is_vim && key ==# 'row'
|
|
||||||
" Could be float
|
|
||||||
let obj[key] = a:from[key] + changed * a:percent
|
|
||||||
else
|
|
||||||
let obj[key] = a:from[key] + float2nr(round(changed * a:percent))
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return obj
|
|
||||||
endfunction
|
|
|
@ -1,216 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:activated = 0
|
|
||||||
let s:session_names = []
|
|
||||||
let s:saved_ve = &t_ve
|
|
||||||
let s:saved_cursor = &guicursor
|
|
||||||
let s:gui = has('gui_running') || has('nvim')
|
|
||||||
|
|
||||||
let s:char_map = {
|
|
||||||
\ "\<Plug>": '<plug>',
|
|
||||||
\ "\<Esc>": '<esc>',
|
|
||||||
\ "\<Tab>": '<tab>',
|
|
||||||
\ "\<S-Tab>": '<s-tab>',
|
|
||||||
\ "\<bs>": '<bs>',
|
|
||||||
\ "\<right>": '<right>',
|
|
||||||
\ "\<left>": '<left>',
|
|
||||||
\ "\<up>": '<up>',
|
|
||||||
\ "\<down>": '<down>',
|
|
||||||
\ "\<home>": '<home>',
|
|
||||||
\ "\<end>": '<end>',
|
|
||||||
\ "\<cr>": '<cr>',
|
|
||||||
\ "\<PageUp>":'<PageUp>' ,
|
|
||||||
\ "\<PageDown>":'<PageDown>' ,
|
|
||||||
\ "\<FocusGained>":'<FocusGained>',
|
|
||||||
\ "\<FocusLost>":'<FocusLost>',
|
|
||||||
\ "\<ScrollWheelUp>": '<ScrollWheelUp>',
|
|
||||||
\ "\<ScrollWheelDown>": '<ScrollWheelDown>',
|
|
||||||
\ "\<LeftMouse>": '<LeftMouse>',
|
|
||||||
\ "\<LeftDrag>": '<LeftDrag>',
|
|
||||||
\ "\<LeftRelease>": '<LeftRelease>',
|
|
||||||
\ "\<2-LeftMouse>": '<2-LeftMouse>',
|
|
||||||
\ "\<C-a>": '<C-a>',
|
|
||||||
\ "\<C-b>": '<C-b>',
|
|
||||||
\ "\<C-c>": '<C-c>',
|
|
||||||
\ "\<C-d>": '<C-d>',
|
|
||||||
\ "\<C-e>": '<C-e>',
|
|
||||||
\ "\<C-f>": '<C-f>',
|
|
||||||
\ "\<C-g>": '<C-g>',
|
|
||||||
\ "\<C-h>": '<C-h>',
|
|
||||||
\ "\<C-j>": '<C-j>',
|
|
||||||
\ "\<C-k>": '<C-k>',
|
|
||||||
\ "\<C-l>": '<C-l>',
|
|
||||||
\ "\<C-n>": '<C-n>',
|
|
||||||
\ "\<C-o>": '<C-o>',
|
|
||||||
\ "\<C-p>": '<C-p>',
|
|
||||||
\ "\<C-q>": '<C-q>',
|
|
||||||
\ "\<C-r>": '<C-r>',
|
|
||||||
\ "\<C-s>": '<C-s>',
|
|
||||||
\ "\<C-t>": '<C-t>',
|
|
||||||
\ "\<C-u>": '<C-u>',
|
|
||||||
\ "\<C-v>": '<C-v>',
|
|
||||||
\ "\<C-w>": '<C-w>',
|
|
||||||
\ "\<C-x>": '<C-x>',
|
|
||||||
\ "\<C-y>": '<C-y>',
|
|
||||||
\ "\<C-z>": '<C-z>',
|
|
||||||
\ "\<A-a>": '<A-a>',
|
|
||||||
\ "\<A-b>": '<A-b>',
|
|
||||||
\ "\<A-c>": '<A-c>',
|
|
||||||
\ "\<A-d>": '<A-d>',
|
|
||||||
\ "\<A-e>": '<A-e>',
|
|
||||||
\ "\<A-f>": '<A-f>',
|
|
||||||
\ "\<A-g>": '<A-g>',
|
|
||||||
\ "\<A-h>": '<A-h>',
|
|
||||||
\ "\<A-i>": '<A-i>',
|
|
||||||
\ "\<A-j>": '<A-j>',
|
|
||||||
\ "\<A-k>": '<A-k>',
|
|
||||||
\ "\<A-l>": '<A-l>',
|
|
||||||
\ "\<A-m>": '<A-m>',
|
|
||||||
\ "\<A-n>": '<A-n>',
|
|
||||||
\ "\<A-o>": '<A-o>',
|
|
||||||
\ "\<A-p>": '<A-p>',
|
|
||||||
\ "\<A-q>": '<A-q>',
|
|
||||||
\ "\<A-r>": '<A-r>',
|
|
||||||
\ "\<A-s>": '<A-s>',
|
|
||||||
\ "\<A-t>": '<A-t>',
|
|
||||||
\ "\<A-u>": '<A-u>',
|
|
||||||
\ "\<A-v>": '<A-v>',
|
|
||||||
\ "\<A-w>": '<A-w>',
|
|
||||||
\ "\<A-x>": '<A-x>',
|
|
||||||
\ "\<A-y>": '<A-y>',
|
|
||||||
\ "\<A-z>": '<A-z>',
|
|
||||||
\ }
|
|
||||||
|
|
||||||
function! coc#prompt#getc() abort
|
|
||||||
let c = getchar()
|
|
||||||
return type(c) is 0 ? nr2char(c) : c
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#prompt#getchar() abort
|
|
||||||
let input = coc#prompt#getc()
|
|
||||||
if 1 != &iminsert
|
|
||||||
return input
|
|
||||||
endif
|
|
||||||
"a language keymap is activated, so input must be resolved to the mapped values.
|
|
||||||
let partial_keymap = mapcheck(input, 'l')
|
|
||||||
while partial_keymap !=# ''
|
|
||||||
let dict = maparg(input, 'l', 0, 1)
|
|
||||||
if empty(dict) || get(dict, 'expr', 0)
|
|
||||||
return input
|
|
||||||
endif
|
|
||||||
let full_keymap = get(dict, 'rhs', '')
|
|
||||||
if full_keymap ==# "" && len(input) >= 3 "HACK: assume there are no keymaps longer than 3.
|
|
||||||
return input
|
|
||||||
elseif full_keymap ==# partial_keymap
|
|
||||||
return full_keymap
|
|
||||||
endif
|
|
||||||
let c = coc#prompt#getc()
|
|
||||||
if c ==# "\<Esc>" || c ==# "\<CR>"
|
|
||||||
"if the short sequence has a valid mapping, return that.
|
|
||||||
if !empty(full_keymap)
|
|
||||||
return full_keymap
|
|
||||||
endif
|
|
||||||
return input
|
|
||||||
endif
|
|
||||||
let input .= c
|
|
||||||
let partial_keymap = mapcheck(input, 'l')
|
|
||||||
endwhile
|
|
||||||
return input
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#prompt#start_prompt(session) abort
|
|
||||||
let s:session_names = s:filter(s:session_names, a:session)
|
|
||||||
call add(s:session_names, a:session)
|
|
||||||
if s:activated | return | endif
|
|
||||||
if s:is_vim
|
|
||||||
call s:start_prompt_vim()
|
|
||||||
else
|
|
||||||
call s:start_prompt()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:start_prompt_vim() abort
|
|
||||||
call timer_start(10, {-> s:start_prompt()})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:start_prompt()
|
|
||||||
if s:activated | return | endif
|
|
||||||
if !get(g:, 'coc_disable_transparent_cursor', 0)
|
|
||||||
if s:gui
|
|
||||||
if has('nvim-0.5.0') && !empty(s:saved_cursor)
|
|
||||||
set guicursor+=a:ver1-CocCursorTransparent/lCursor
|
|
||||||
endif
|
|
||||||
elseif s:is_vim
|
|
||||||
set t_ve=
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let s:activated = 1
|
|
||||||
try
|
|
||||||
while s:activated
|
|
||||||
let ch = coc#prompt#getchar()
|
|
||||||
if ch ==# "\<FocusLost>" || ch ==# "\<FocusGained>" || ch ==# "\<CursorHold>"
|
|
||||||
continue
|
|
||||||
else
|
|
||||||
let curr = s:current_session()
|
|
||||||
let mapped = get(s:char_map, ch, ch)
|
|
||||||
if !empty(curr)
|
|
||||||
call coc#rpc#notify('InputChar', [curr, mapped, getcharmod()])
|
|
||||||
endif
|
|
||||||
if mapped == '<esc>'
|
|
||||||
let s:session_names = []
|
|
||||||
call s:reset()
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
catch /^Vim:Interrupt$/
|
|
||||||
let s:activated = 0
|
|
||||||
call coc#rpc#notify('InputChar', [s:current_session(), '<esc>', 0])
|
|
||||||
let s:session_names = []
|
|
||||||
call s:reset()
|
|
||||||
return
|
|
||||||
endtry
|
|
||||||
let s:activated = 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#prompt#stop_prompt(session)
|
|
||||||
let s:session_names = s:filter(s:session_names, a:session)
|
|
||||||
if len(s:session_names)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if s:activated
|
|
||||||
let s:activated = 0
|
|
||||||
call s:reset()
|
|
||||||
call feedkeys("\<esc>", 'int')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#prompt#activated() abort
|
|
||||||
return s:activated
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:reset() abort
|
|
||||||
if !get(g:, 'coc_disable_transparent_cursor',0)
|
|
||||||
" neovim has bug with revert empty &guicursor
|
|
||||||
if s:gui && !empty(s:saved_cursor)
|
|
||||||
if has('nvim-0.5.0')
|
|
||||||
set guicursor+=a:ver1-Cursor/lCursor
|
|
||||||
let &guicursor = s:saved_cursor
|
|
||||||
endif
|
|
||||||
elseif s:is_vim
|
|
||||||
let &t_ve = s:saved_ve
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
echo ""
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:current_session() abort
|
|
||||||
if empty(s:session_names)
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
return s:session_names[len(s:session_names) - 1]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:filter(list, id) abort
|
|
||||||
return filter(copy(a:list), 'v:val !=# a:id')
|
|
||||||
endfunction
|
|
|
@ -1,622 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:pum_bufnr = 0
|
|
||||||
let s:pum_winid = -1
|
|
||||||
let s:pum_index = -1
|
|
||||||
let s:pum_size = 0
|
|
||||||
let s:inserted = 0
|
|
||||||
let s:virtual_text = 0
|
|
||||||
let s:virtual_text_ns = coc#highlight#create_namespace('pum-virtual')
|
|
||||||
let s:ignore = s:is_vim || has('nvim-0.5.0') ? "\<Ignore>" : "\<space>\<bs>"
|
|
||||||
let s:hide_pum = has('nvim-0.6.1') || has('patch-8.2.3389')
|
|
||||||
let s:virtual_text_support = has('nvim-0.5.0') || has('patch-9.0.0067')
|
|
||||||
" bufnr, &indentkeys
|
|
||||||
let s:saved_indenetkeys = []
|
|
||||||
let s:saved_textwidth = []
|
|
||||||
let s:prop_id = 0
|
|
||||||
let s:reversed = 0
|
|
||||||
let s:check_hl_group = 0
|
|
||||||
let s:start_col = -1
|
|
||||||
|
|
||||||
if s:is_vim && s:virtual_text_support
|
|
||||||
if empty(prop_type_get('CocPumVirtualText'))
|
|
||||||
call prop_type_add('CocPumVirtualText', {'highlight': 'CocPumVirtualText'})
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
function! coc#pum#visible() abort
|
|
||||||
if s:pum_winid == -1
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
" getwinvar check current tab only.
|
|
||||||
return getwinvar(s:pum_winid, 'float', 0) == 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#winid() abort
|
|
||||||
return s:pum_winid
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#close_detail() abort
|
|
||||||
let winid = coc#float#get_float_by_kind('pumdetail')
|
|
||||||
if winid
|
|
||||||
call coc#float#close(winid, 1)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#close(...) abort
|
|
||||||
if coc#pum#visible()
|
|
||||||
let kind = get(a:, 1, '')
|
|
||||||
if kind ==# 'cancel'
|
|
||||||
let input = getwinvar(s:pum_winid, 'input', '')
|
|
||||||
let s:pum_index = -1
|
|
||||||
call s:insert_word(input, 1)
|
|
||||||
call s:on_pum_change(0)
|
|
||||||
doautocmd <nomodeline> TextChangedI
|
|
||||||
elseif kind ==# 'confirm'
|
|
||||||
let words = getwinvar(s:pum_winid, 'words', [])
|
|
||||||
if s:pum_index >= 0
|
|
||||||
let word = get(words, s:pum_index, '')
|
|
||||||
call s:insert_word(word, 1)
|
|
||||||
" have to restore here, so that TextChangedI can trigger indent.
|
|
||||||
call s:restore_indentkeys()
|
|
||||||
endif
|
|
||||||
doautocmd <nomodeline> TextChangedI
|
|
||||||
endif
|
|
||||||
call s:close_pum()
|
|
||||||
if !get(a:, 2, 0)
|
|
||||||
call coc#rpc#notify('CompleteStop', [kind])
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#select_confirm() abort
|
|
||||||
if coc#pum#visible()
|
|
||||||
if s:pum_index < 0
|
|
||||||
let s:pum_index = 0
|
|
||||||
call s:on_pum_change(0)
|
|
||||||
endif
|
|
||||||
call coc#pum#close('confirm')
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#_close() abort
|
|
||||||
if coc#pum#visible()
|
|
||||||
call s:close_pum()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#_one_more() abort
|
|
||||||
if coc#pum#visible()
|
|
||||||
let parts = getwinvar(s:pum_winid, 'parts', [])
|
|
||||||
let start = strlen(parts[0])
|
|
||||||
let input = strpart(getline('.'), start, col('.') - 1 - start)
|
|
||||||
let words = getwinvar(s:pum_winid, 'words', [])
|
|
||||||
let word = get(words, s:pum_index == -1 ? 0 : s:pum_index, '')
|
|
||||||
if !empty(word) && strcharpart(word, 0, strchars(input)) ==# input
|
|
||||||
let ch = strcharpart(word, strchars(input), 1)
|
|
||||||
if !empty(ch)
|
|
||||||
call feedkeys(ch, "int")
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#_insert() abort
|
|
||||||
if coc#pum#visible()
|
|
||||||
if s:pum_index >= 0
|
|
||||||
let words = getwinvar(s:pum_winid, 'words', [])
|
|
||||||
let word = get(words, s:pum_index, '')
|
|
||||||
call s:insert_word(word, 1)
|
|
||||||
call s:restore_indentkeys()
|
|
||||||
endif
|
|
||||||
doautocmd <nomodeline> TextChangedI
|
|
||||||
call s:close_pum()
|
|
||||||
call coc#rpc#notify('CompleteStop', [''])
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#insert() abort
|
|
||||||
return "\<C-r>=coc#pum#_insert()\<CR>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Add one more character from the matched complete item(or first one),
|
|
||||||
" the word should starts with input, the same as vim's CTRL-L behavior.
|
|
||||||
function! coc#pum#one_more() abort
|
|
||||||
return "\<C-r>=coc#pum#_one_more()\<CR>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#next(insert) abort
|
|
||||||
return "\<C-r>=coc#pum#_navigate(1,".a:insert.")\<CR>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#prev(insert) abort
|
|
||||||
return "\<C-r>=coc#pum#_navigate(0,".a:insert.")\<CR>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#stop() abort
|
|
||||||
return "\<C-r>=coc#pum#close()\<CR>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#cancel() abort
|
|
||||||
return "\<C-r>=coc#pum#close('cancel')\<CR>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#confirm() abort
|
|
||||||
return "\<C-r>=coc#pum#close('confirm')\<CR>"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#select(index, insert, confirm) abort
|
|
||||||
if coc#pum#visible()
|
|
||||||
if a:index == -1
|
|
||||||
call coc#pum#close('cancel')
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
if a:index < 0 || a:index >= s:pum_size
|
|
||||||
throw 'index out of range ' . a:index
|
|
||||||
endif
|
|
||||||
call s:select_by_index(a:index, a:insert)
|
|
||||||
if a:confirm
|
|
||||||
call coc#pum#close('confirm')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#info() abort
|
|
||||||
let bufnr = winbufnr(s:pum_winid)
|
|
||||||
let words = getwinvar(s:pum_winid, 'words', [])
|
|
||||||
let word = s:pum_index < 0 ? '' : get(words, s:pum_index, '')
|
|
||||||
let base = {
|
|
||||||
\ 'word': word,
|
|
||||||
\ 'index': s:pum_index,
|
|
||||||
\ 'size': s:pum_size,
|
|
||||||
\ 'startcol': s:start_col,
|
|
||||||
\ 'inserted': s:pum_index >=0 && s:inserted ? v:true : v:false,
|
|
||||||
\ 'reversed': s:reversed ? v:true : v:false,
|
|
||||||
\ }
|
|
||||||
if s:is_vim
|
|
||||||
let pos = popup_getpos(s:pum_winid)
|
|
||||||
let border = has_key(popup_getoptions(s:pum_winid), 'border')
|
|
||||||
let add = pos['scrollbar'] && border ? 1 : 0
|
|
||||||
return extend(base, {
|
|
||||||
\ 'scrollbar': pos['scrollbar'],
|
|
||||||
\ 'row': pos['line'] - 1,
|
|
||||||
\ 'col': pos['col'] - 1,
|
|
||||||
\ 'width': pos['width'] + add,
|
|
||||||
\ 'height': pos['height'],
|
|
||||||
\ 'border': border,
|
|
||||||
\ })
|
|
||||||
else
|
|
||||||
let scrollbar = coc#float#get_related(s:pum_winid, 'scrollbar')
|
|
||||||
let winid = coc#float#get_related(s:pum_winid, 'border', s:pum_winid)
|
|
||||||
let pos = nvim_win_get_position(winid)
|
|
||||||
return extend(base, {
|
|
||||||
\ 'scrollbar': scrollbar && nvim_win_is_valid(scrollbar) ? 1 : 0,
|
|
||||||
\ 'row': pos[0],
|
|
||||||
\ 'col': pos[1],
|
|
||||||
\ 'width': nvim_win_get_width(winid),
|
|
||||||
\ 'height': nvim_win_get_height(winid),
|
|
||||||
\ 'border': winid != s:pum_winid,
|
|
||||||
\ })
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#scroll(forward) abort
|
|
||||||
if coc#pum#visible()
|
|
||||||
let height = s:get_height(s:pum_winid)
|
|
||||||
if s:pum_size > height
|
|
||||||
call timer_start(1, { -> s:scroll_pum(a:forward, height, s:pum_size)})
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
" Required on old version vim/neovim.
|
|
||||||
return s:ignore
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_height(winid) abort
|
|
||||||
if has('nvim')
|
|
||||||
return nvim_win_get_height(a:winid)
|
|
||||||
endif
|
|
||||||
return get(popup_getpos(a:winid), 'core_height', 0)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:scroll_pum(forward, height, size) abort
|
|
||||||
let topline = s:get_topline(s:pum_winid)
|
|
||||||
if !a:forward && topline == 1
|
|
||||||
if s:pum_index >= 0
|
|
||||||
call s:select_line(s:pum_winid, 1)
|
|
||||||
call s:on_pum_change(1)
|
|
||||||
endif
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if a:forward && topline + a:height - 1 >= a:size
|
|
||||||
if s:pum_index >= 0
|
|
||||||
call s:select_line(s:pum_winid, a:size)
|
|
||||||
call s:on_pum_change(1)
|
|
||||||
endif
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call coc#float#scroll_win(s:pum_winid, a:forward, a:height)
|
|
||||||
if s:pum_index >= 0
|
|
||||||
let lnum = s:pum_index + 1
|
|
||||||
let topline = s:get_topline(s:pum_winid)
|
|
||||||
if lnum >= topline && lnum <= topline + a:height - 1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call s:select_line(s:pum_winid, topline)
|
|
||||||
call s:on_pum_change(1)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_topline(winid) abort
|
|
||||||
if has('nvim')
|
|
||||||
let info = getwininfo(a:winid)[0]
|
|
||||||
return info['topline']
|
|
||||||
else
|
|
||||||
let pos = popup_getpos(a:winid)
|
|
||||||
return pos['firstline']
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#pum#_navigate(next, insert) abort
|
|
||||||
if coc#pum#visible()
|
|
||||||
call s:save_indentkeys()
|
|
||||||
let index = s:get_index(a:next)
|
|
||||||
call s:select_by_index(index, a:insert)
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:select_by_index(index, insert) abort
|
|
||||||
let lnum = a:index == -1 ? 0 : s:index_to_lnum(a:index)
|
|
||||||
call s:set_cursor(s:pum_winid, lnum)
|
|
||||||
if !s:is_vim
|
|
||||||
call coc#float#nvim_scrollbar(s:pum_winid)
|
|
||||||
endif
|
|
||||||
if a:insert
|
|
||||||
let s:inserted = 1
|
|
||||||
if a:index < 0
|
|
||||||
let input = getwinvar(s:pum_winid, 'input', '')
|
|
||||||
call s:insert_word(input, 0)
|
|
||||||
call coc#pum#close_detail()
|
|
||||||
else
|
|
||||||
let words = getwinvar(s:pum_winid, 'words', [])
|
|
||||||
let word = get(words, a:index, '')
|
|
||||||
call s:insert_word(word, 0)
|
|
||||||
endif
|
|
||||||
" The current line is wrong when use feedkeys.
|
|
||||||
if !s:is_vim
|
|
||||||
doautocmd <nomodeline> TextChangedP
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call s:on_pum_change(1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_index(next) abort
|
|
||||||
if a:next
|
|
||||||
let index = s:pum_index + 1 == s:pum_size ? -1 : s:pum_index + 1
|
|
||||||
else
|
|
||||||
let index = s:pum_index == -1 ? s:pum_size - 1 : s:pum_index - 1
|
|
||||||
endif
|
|
||||||
return index
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:insert_word(word, finish) abort
|
|
||||||
if s:start_col != -1 && mode() ==# 'i'
|
|
||||||
" avoid auto wrap using 'textwidth'
|
|
||||||
if !a:finish && &textwidth > 0
|
|
||||||
let textwidth = &textwidth
|
|
||||||
noa setl textwidth=0
|
|
||||||
call timer_start(0, { -> execute('noa setl textwidth='.textwidth)})
|
|
||||||
endif
|
|
||||||
" should not be used on finish to have correct line.
|
|
||||||
if s:is_vim && !a:finish
|
|
||||||
call coc#pum#repalce(s:start_col + 1, a:word, 1)
|
|
||||||
else
|
|
||||||
let saved_completeopt = &completeopt
|
|
||||||
noa set completeopt=menu
|
|
||||||
noa call complete(s:start_col + 1, [{ 'empty': v:true, 'word': a:word }])
|
|
||||||
" exit complete state
|
|
||||||
if s:hide_pum
|
|
||||||
call feedkeys("\<C-x>\<C-z>", 'in')
|
|
||||||
else
|
|
||||||
let g:coc_disable_space_report = 1
|
|
||||||
call feedkeys("\<space>\<bs>", 'in')
|
|
||||||
endif
|
|
||||||
execute 'noa set completeopt='.saved_completeopt
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Replace from col to cursor col with new characters
|
|
||||||
function! coc#pum#repalce(col, insert, ...) abort
|
|
||||||
let insert = a:insert
|
|
||||||
let curr = getline('.')
|
|
||||||
let removed = strpart(curr, a:col - 1, col('.') - a:col)
|
|
||||||
let n = strchars(removed)
|
|
||||||
let start = coc#string#common_start(insert, removed)
|
|
||||||
let event = get(a:, 1, 0)
|
|
||||||
if start > 0
|
|
||||||
let n = n - start
|
|
||||||
let insert = strcharpart(a:insert, start)
|
|
||||||
if empty(insert) && n == 0 && !event
|
|
||||||
let n = 1
|
|
||||||
let insert = coc#string#last_character(a:insert)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let keys = repeat("\<bs>", n).insert
|
|
||||||
if len(keys)
|
|
||||||
if event
|
|
||||||
let previous =strpart(curr, 0, a:col - 1)
|
|
||||||
call coc#rpc#notify('PumInsert', [previous.a:insert])
|
|
||||||
let g:coc_feeding_keys = 1
|
|
||||||
endif
|
|
||||||
call feedkeys(keys, 'int')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" create or update pum with lines, CompleteOption and config.
|
|
||||||
" return winid & dimension
|
|
||||||
function! coc#pum#create(lines, opt, config) abort
|
|
||||||
if mode() !=# 'i' || a:opt['line'] != line('.')
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let len = col('.') - a:opt['col'] - 1
|
|
||||||
if len < 0
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let input = len == 0 ? '' : strpart(getline('.'), a:opt['col'], len)
|
|
||||||
if input !=# a:opt['input']
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let config = s:get_pum_dimension(a:lines, a:opt['col'], a:config)
|
|
||||||
if empty(config)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let s:reversed = get(a:config, 'reverse', 0) && config['row'] < 0
|
|
||||||
let s:virtual_text = s:virtual_text_support && a:opt['virtualText']
|
|
||||||
let s:pum_size = len(a:lines)
|
|
||||||
let s:pum_index = a:opt['index']
|
|
||||||
let lnum = s:index_to_lnum(s:pum_index)
|
|
||||||
call extend(config, {
|
|
||||||
\ 'lines': s:reversed ? reverse(copy(a:lines)) : a:lines,
|
|
||||||
\ 'relative': 'cursor',
|
|
||||||
\ 'nopad': 1,
|
|
||||||
\ 'cursorline': 1,
|
|
||||||
\ 'index': lnum - 1,
|
|
||||||
\ 'focusable': v:false
|
|
||||||
\ })
|
|
||||||
call extend(config, coc#dict#pick(a:config, ['highlight', 'rounded', 'highlights', 'winblend', 'shadow', 'border', 'borderhighlight']))
|
|
||||||
if s:reversed
|
|
||||||
for item in config['highlights']
|
|
||||||
let item['lnum'] = s:pum_size - item['lnum'] - 1
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
if empty(get(config, 'winblend', 0)) && exists('&pumblend')
|
|
||||||
let config['winblend'] = &pumblend
|
|
||||||
endif
|
|
||||||
let result = coc#float#create_float_win(s:pum_winid, s:pum_bufnr, config)
|
|
||||||
if empty(result)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let s:inserted = 0
|
|
||||||
let s:pum_winid = result[0]
|
|
||||||
let s:pum_bufnr = result[1]
|
|
||||||
let s:start_col = a:opt['startcol']
|
|
||||||
call setwinvar(s:pum_winid, 'above', config['row'] < 0)
|
|
||||||
let firstline = s:get_firstline(lnum, s:pum_size, config['height'])
|
|
||||||
if s:is_vim
|
|
||||||
call popup_setoptions(s:pum_winid, { 'firstline': firstline })
|
|
||||||
else
|
|
||||||
call coc#compat#execute(s:pum_winid, 'call winrestview({"lnum":'.lnum.',"topline":'.firstline.'})')
|
|
||||||
endif
|
|
||||||
call coc#dialog#place_sign(s:pum_bufnr, s:pum_index == -1 ? 0 : lnum)
|
|
||||||
" content before col and content after cursor
|
|
||||||
let linetext = getline('.')
|
|
||||||
let parts = [strpart(linetext, 0, s:start_col), strpart(linetext, col('.') - 1)]
|
|
||||||
let input = strpart(getline('.'), s:start_col, col('.') - 1 - s:start_col)
|
|
||||||
call setwinvar(s:pum_winid, 'input', input)
|
|
||||||
call setwinvar(s:pum_winid, 'parts', parts)
|
|
||||||
call setwinvar(s:pum_winid, 'words', a:opt['words'])
|
|
||||||
call setwinvar(s:pum_winid, 'kind', 'pum')
|
|
||||||
if !s:is_vim
|
|
||||||
if s:pum_size > config['height']
|
|
||||||
redraw
|
|
||||||
call coc#float#nvim_scrollbar(s:pum_winid)
|
|
||||||
else
|
|
||||||
call coc#float#close_related(s:pum_winid, 'scrollbar')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call s:on_pum_change(0)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:save_indentkeys() abort
|
|
||||||
let bufnr = bufnr('%')
|
|
||||||
if !empty(&indentexpr) && get(s:saved_indenetkeys, 0, 0) != bufnr
|
|
||||||
let s:saved_indenetkeys = [bufnr, &indentkeys]
|
|
||||||
execute 'setl indentkeys='
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_firstline(lnum, total, height) abort
|
|
||||||
if a:lnum <= a:height
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
return min([a:total - a:height + 1, a:lnum - (a:height*2/3)])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:on_pum_change(move) abort
|
|
||||||
if s:virtual_text
|
|
||||||
if s:inserted
|
|
||||||
call s:clear_virtual_text()
|
|
||||||
else
|
|
||||||
call s:insert_virtual_text()
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let ev = extend(coc#pum#info(), {'move': a:move ? v:true : v:false})
|
|
||||||
call coc#rpc#notify('CocAutocmd', ['MenuPopupChanged', ev, win_screenpos(winnr())[0] + winline() - 2])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:index_to_lnum(index) abort
|
|
||||||
if s:reversed
|
|
||||||
if a:index <= 0
|
|
||||||
return s:pum_size
|
|
||||||
endif
|
|
||||||
return s:pum_size - a:index
|
|
||||||
endif
|
|
||||||
return max([1, a:index + 1])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_pum_dimension(lines, col, config) abort
|
|
||||||
let linecount = len(a:lines)
|
|
||||||
let [lineIdx, colIdx] = coc#cursor#screen_pos()
|
|
||||||
let bh = empty(get(a:config, 'border', [])) ? 0 : 2
|
|
||||||
let columns = &columns
|
|
||||||
let pumwidth = max([15, exists('&pumwidth') ? &pumwidth : 0])
|
|
||||||
let width = min([columns, max([pumwidth, a:config['width']])])
|
|
||||||
let vh = &lines - &cmdheight - 1 - !empty(&tabline)
|
|
||||||
if vh <= 0
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let pumheight = empty(&pumheight) ? vh : &pumheight
|
|
||||||
let showTop = getwinvar(s:pum_winid, 'above', v:null)
|
|
||||||
if type(showTop) != v:t_number
|
|
||||||
if vh - lineIdx - bh - 1 < min([pumheight, linecount]) && vh - lineIdx < min([10, vh/2])
|
|
||||||
let showTop = 1
|
|
||||||
else
|
|
||||||
let showTop = 0
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let height = showTop ? min([lineIdx - bh - !empty(&tabline), linecount, pumheight]) : min([vh - lineIdx - bh - 1, linecount, pumheight])
|
|
||||||
if height <= 0
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
" should use strdiplaywidth here
|
|
||||||
let text = strpart(getline('.'), a:col, col('.') - 1 - a:col)
|
|
||||||
let col = - strdisplaywidth(text, a:col) - 1
|
|
||||||
let row = showTop ? - height : 1
|
|
||||||
let delta = colIdx + col
|
|
||||||
if width > pumwidth && delta + width > columns
|
|
||||||
let width = max([columns - delta, pumwidth])
|
|
||||||
endif
|
|
||||||
if delta < 0
|
|
||||||
let col = col - delta
|
|
||||||
elseif delta + width > columns
|
|
||||||
let col = max([-colIdx, col - (delta + width - columns)])
|
|
||||||
endif
|
|
||||||
return {
|
|
||||||
\ 'row': row,
|
|
||||||
\ 'col': col,
|
|
||||||
\ 'width': width,
|
|
||||||
\ 'height': height
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" can't use coc#dialog#set_cursor on vim8, don't know why
|
|
||||||
function! s:set_cursor(winid, line) abort
|
|
||||||
if s:is_vim
|
|
||||||
let pos = popup_getpos(a:winid)
|
|
||||||
let core_height = pos['core_height']
|
|
||||||
let lastline = pos['firstline'] + core_height - 1
|
|
||||||
if a:line > lastline
|
|
||||||
call popup_setoptions(a:winid, {
|
|
||||||
\ 'firstline': pos['firstline'] + a:line - lastline,
|
|
||||||
\ })
|
|
||||||
elseif a:line < pos['firstline']
|
|
||||||
if s:reversed
|
|
||||||
call popup_setoptions(a:winid, {
|
|
||||||
\ 'firstline': a:line == 0 ? s:pum_size - core_height + 1 : a:line - core_height + 1,
|
|
||||||
\ })
|
|
||||||
else
|
|
||||||
call popup_setoptions(a:winid, {
|
|
||||||
\ 'firstline': max([1, a:line]),
|
|
||||||
\ })
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call s:select_line(a:winid, a:line)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:select_line(winid, line) abort
|
|
||||||
let s:pum_index = s:reversed ? (a:line == 0 ? -1 : s:pum_size - a:line) : a:line - 1
|
|
||||||
let lnum = s:reversed ? (a:line == 0 ? s:pum_size : a:line) : max([1, a:line])
|
|
||||||
if s:is_vim
|
|
||||||
call coc#compat#execute(a:winid, 'exe '.lnum)
|
|
||||||
else
|
|
||||||
call nvim_win_set_cursor(a:winid, [lnum, 0])
|
|
||||||
endif
|
|
||||||
call coc#dialog#place_sign(s:pum_bufnr, a:line == 0 ? 0 : lnum)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:insert_virtual_text() abort
|
|
||||||
let bufnr = bufnr('%')
|
|
||||||
if !s:virtual_text || s:pum_index < 0
|
|
||||||
call s:clear_virtual_text()
|
|
||||||
else
|
|
||||||
" Check if could create
|
|
||||||
let insert = ''
|
|
||||||
let line = line('.') - 1
|
|
||||||
let words = getwinvar(s:pum_winid, 'words', [])
|
|
||||||
let word = get(words, s:pum_index, '')
|
|
||||||
let input = strpart(getline('.'), s:start_col, col('.') - 1 - s:start_col)
|
|
||||||
if strlen(word) > strlen(input) && strcharpart(word, 0, strchars(input)) ==# input
|
|
||||||
let insert = strcharpart(word, strchars(input))
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
if s:prop_id != 0
|
|
||||||
call prop_remove({'id': s:prop_id}, line + 1, line + 1)
|
|
||||||
endif
|
|
||||||
if !empty(insert)
|
|
||||||
let s:prop_id = prop_add(line + 1, col('.'), {
|
|
||||||
\ 'text': insert,
|
|
||||||
\ 'type': 'CocPumVirtualText'
|
|
||||||
\ })
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call nvim_buf_clear_namespace(bufnr, s:virtual_text_ns, line, line + 1)
|
|
||||||
if !empty(insert)
|
|
||||||
let opts = {
|
|
||||||
\ 'hl_mode': 'combine',
|
|
||||||
\ 'virt_text': [[insert, 'CocPumVirtualText']],
|
|
||||||
\ 'virt_text_pos': 'overlay',
|
|
||||||
\ 'virt_text_win_col': virtcol('.') - 1,
|
|
||||||
\ }
|
|
||||||
call nvim_buf_set_extmark(bufnr, s:virtual_text_ns, line, col('.') - 1, opts)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:clear_virtual_text() abort
|
|
||||||
if s:virtual_text_support
|
|
||||||
if s:is_vim
|
|
||||||
if s:prop_id != 0
|
|
||||||
call prop_remove({'id': s:prop_id})
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call nvim_buf_clear_namespace(bufnr('%'), s:virtual_text_ns, 0, -1)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:close_pum() abort
|
|
||||||
call s:clear_virtual_text()
|
|
||||||
call coc#float#close(s:pum_winid, 1)
|
|
||||||
let s:pum_winid = 0
|
|
||||||
let s:pum_size = 0
|
|
||||||
let winid = coc#float#get_float_by_kind('pumdetail')
|
|
||||||
if winid
|
|
||||||
call coc#float#close(winid, 1)
|
|
||||||
endif
|
|
||||||
call s:restore_indentkeys()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:restore_indentkeys() abort
|
|
||||||
if get(s:saved_indenetkeys, 0, 0) == bufnr('%')
|
|
||||||
call setbufvar(s:saved_indenetkeys[0], '&indentkeys', get(s:saved_indenetkeys, 1, ''))
|
|
||||||
let s:saved_indenetkeys = []
|
|
||||||
endif
|
|
||||||
endfunction
|
|
|
@ -1,236 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:is_win = has("win32") || has("win64")
|
|
||||||
let s:client = v:null
|
|
||||||
let s:name = 'coc'
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:chan_id = 0
|
|
||||||
let s:root = expand('<sfile>:h:h:h')
|
|
||||||
|
|
||||||
function! coc#rpc#start_server()
|
|
||||||
let test = get(g:, 'coc_node_env', '') ==# 'test'
|
|
||||||
if test && !s:is_vim && !exists('$COC_NVIM_REMOTE_ADDRESS')
|
|
||||||
" server already started, chan_id could be available later
|
|
||||||
let s:client = coc#client#create(s:name, [])
|
|
||||||
let s:client['running'] = s:chan_id != 0
|
|
||||||
let s:client['chan_id'] = s:chan_id
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if exists('$COC_NVIM_REMOTE_ADDRESS')
|
|
||||||
let address = $COC_NVIM_REMOTE_ADDRESS
|
|
||||||
if s:is_vim
|
|
||||||
let s:client = coc#client#create(s:name, [])
|
|
||||||
" TODO don't know if vim support named pipe on windows.
|
|
||||||
let address = address =~# ':\d\+$' ? address : 'unix:'.address
|
|
||||||
let channel = ch_open(address, {
|
|
||||||
\ 'mode': 'json',
|
|
||||||
\ 'close_cb': {channel -> s:on_channel_close()},
|
|
||||||
\ 'noblock': 1,
|
|
||||||
\ 'timeout': 1000,
|
|
||||||
\ })
|
|
||||||
if ch_status(channel) == 'open'
|
|
||||||
let s:client['running'] = 1
|
|
||||||
let s:client['channel'] = channel
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let s:client = coc#client#create(s:name, [])
|
|
||||||
try
|
|
||||||
let mode = address =~# ':\d\+$' ? 'tcp' : 'pipe'
|
|
||||||
let chan_id = sockconnect(mode, address, { 'rpc': 1 })
|
|
||||||
if chan_id > 0
|
|
||||||
let s:client['running'] = 1
|
|
||||||
let s:client['chan_id'] = chan_id
|
|
||||||
endif
|
|
||||||
catch /connection\ refused/
|
|
||||||
" ignroe
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
if !s:client['running']
|
|
||||||
echohl Error | echom '[coc.nvim] Unable connect to '.address.' from variable $COC_NVIM_REMOTE_ADDRESS' | echohl None
|
|
||||||
elseif !test
|
|
||||||
let logfile = exists('$NVIM_COC_LOG_FILE') ? $NVIM_COC_LOG_FILE : ''
|
|
||||||
let loglevel = exists('$NVIM_COC_LOG_LEVEL') ? $NVIM_COC_LOG_LEVEL : ''
|
|
||||||
let runtimepath = join(globpath(&runtimepath, "", 0, 1), ",")
|
|
||||||
let data = [s:root, coc#util#get_data_home(), coc#util#get_config_home(), logfile, loglevel, runtimepath]
|
|
||||||
if s:is_vim
|
|
||||||
call ch_sendraw(s:client['channel'], json_encode(data)."\n")
|
|
||||||
else
|
|
||||||
call call('rpcnotify', [s:client['chan_id'], 'init'] + data)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if empty(s:client)
|
|
||||||
let cmd = coc#util#job_command()
|
|
||||||
if empty(cmd) | return | endif
|
|
||||||
let $COC_VIMCONFIG = coc#util#get_config_home()
|
|
||||||
let $COC_DATA_HOME = coc#util#get_data_home()
|
|
||||||
let s:client = coc#client#create(s:name, cmd)
|
|
||||||
endif
|
|
||||||
if !coc#client#is_running('coc')
|
|
||||||
call s:client['start']()
|
|
||||||
endif
|
|
||||||
call s:check_vim_enter()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#started() abort
|
|
||||||
return !empty(s:client)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#ready()
|
|
||||||
if empty(s:client) || s:client['running'] == 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Used for test on neovim only
|
|
||||||
function! coc#rpc#set_channel(chan_id) abort
|
|
||||||
let s:chan_id = a:chan_id
|
|
||||||
let s:client['running'] = a:chan_id != 0
|
|
||||||
let s:client['chan_id'] = a:chan_id
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#get_channel() abort
|
|
||||||
if empty(s:client)
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
return coc#client#get_channel(s:client)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#kill()
|
|
||||||
let pid = get(g:, 'coc_process_pid', 0)
|
|
||||||
if !pid | return | endif
|
|
||||||
if s:is_win
|
|
||||||
call system('taskkill /PID '.pid)
|
|
||||||
else
|
|
||||||
call system('kill -9 '.pid)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#show_errors()
|
|
||||||
let client = coc#client#get_client('coc')
|
|
||||||
if !empty(client)
|
|
||||||
let lines = get(client, 'stderr', [])
|
|
||||||
keepalt new +setlocal\ buftype=nofile [Stderr of coc.nvim]
|
|
||||||
setl noswapfile wrap bufhidden=wipe nobuflisted nospell
|
|
||||||
call append(0, lines)
|
|
||||||
exe "normal! z" . len(lines) . "\<cr>"
|
|
||||||
exe "normal! gg"
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#stop()
|
|
||||||
if empty(s:client)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
try
|
|
||||||
if s:is_vim
|
|
||||||
call job_stop(ch_getjob(s:client['channel']), 'term')
|
|
||||||
else
|
|
||||||
call jobstop(s:client['chan_id'])
|
|
||||||
endif
|
|
||||||
catch /.*/
|
|
||||||
" ignore
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#restart()
|
|
||||||
if empty(s:client)
|
|
||||||
call coc#rpc#start_server()
|
|
||||||
else
|
|
||||||
call coc#highlight#clear_all()
|
|
||||||
call coc#ui#sign_unplace()
|
|
||||||
call coc#float#close_all()
|
|
||||||
autocmd! coc_dynamic_autocmd
|
|
||||||
autocmd! coc_dynamic_content
|
|
||||||
autocmd! coc_dynamic_option
|
|
||||||
call coc#rpc#request('detach', [])
|
|
||||||
let g:coc_service_initialized = 0
|
|
||||||
sleep 100m
|
|
||||||
if exists('$COC_NVIM_REMOTE_ADDRESS')
|
|
||||||
call coc#rpc#close_connection()
|
|
||||||
sleep 100m
|
|
||||||
call coc#rpc#start_server()
|
|
||||||
else
|
|
||||||
let s:client['command'] = coc#util#job_command()
|
|
||||||
call coc#client#restart(s:name)
|
|
||||||
call s:check_vim_enter()
|
|
||||||
endif
|
|
||||||
echohl MoreMsg | echom 'starting coc.nvim service' | echohl None
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#close_connection() abort
|
|
||||||
let channel = coc#rpc#get_channel()
|
|
||||||
if channel == v:null
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
" Unlike neovim, vim not close the socket as expected.
|
|
||||||
call ch_close(channel)
|
|
||||||
else
|
|
||||||
call chanclose(channel)
|
|
||||||
endif
|
|
||||||
let s:client['running'] = 0
|
|
||||||
let s:client['channel'] = v:null
|
|
||||||
let s:client['chan_id'] = 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#request(method, args) abort
|
|
||||||
if !coc#rpc#ready()
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
return s:client['request'](a:method, a:args)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#notify(method, args) abort
|
|
||||||
if !coc#rpc#ready()
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
call s:client['notify'](a:method, a:args)
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#rpc#request_async(method, args, cb) abort
|
|
||||||
if !coc#rpc#ready()
|
|
||||||
return cb('coc.nvim service not started.')
|
|
||||||
endif
|
|
||||||
call s:client['request_async'](a:method, a:args, a:cb)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" receive async response
|
|
||||||
function! coc#rpc#async_response(id, resp, isErr) abort
|
|
||||||
if empty(s:client)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call coc#client#on_response(s:name, a:id, a:resp, a:isErr)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" send async response to server
|
|
||||||
function! coc#rpc#async_request(id, method, args)
|
|
||||||
let l:Cb = {err, ... -> coc#rpc#notify('nvim_async_response_event', [a:id, err, get(a:000, 0, v:null)])}
|
|
||||||
let args = a:args + [l:Cb]
|
|
||||||
try
|
|
||||||
call call(a:method, args)
|
|
||||||
catch /.*/
|
|
||||||
call coc#rpc#notify('nvim_async_response_event', [a:id, v:exception, v:null])
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:check_vim_enter() abort
|
|
||||||
if s:client['running'] && v:vim_did_enter
|
|
||||||
call coc#rpc#notify('VimEnter', [coc#util#path_replace_patterns(), join(globpath(&runtimepath, "", 0, 1), ",")])
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Used on vim and remote address only
|
|
||||||
function! s:on_channel_close() abort
|
|
||||||
if get(g:, 'coc_node_env', '') !=# 'test'
|
|
||||||
echohl Error | echom '[coc.nvim] channel closed' | echohl None
|
|
||||||
endif
|
|
||||||
if !empty(s:client)
|
|
||||||
let s:client['running'] = 0
|
|
||||||
let s:client['channel'] = v:null
|
|
||||||
let s:client['async_req_id'] = 1
|
|
||||||
endif
|
|
||||||
endfunction
|
|
|
@ -1,155 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:map_next = 1
|
|
||||||
let s:map_prev = 1
|
|
||||||
let s:cmd_mapping = has('nvim') || has('patch-8.2.1978')
|
|
||||||
|
|
||||||
function! coc#snippet#_select_mappings()
|
|
||||||
if !get(g:, 'coc_selectmode_mapping', 1)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
redir => mappings
|
|
||||||
silent! smap
|
|
||||||
redir END
|
|
||||||
|
|
||||||
for map in map(filter(split(mappings, '\n'),
|
|
||||||
\ "v:val !~# '^s' && v:val !~# '^\\a*\\s*<\\S\\+>'"),
|
|
||||||
\ "matchstr(v:val, '^\\a*\\s*\\zs\\S\\+')")
|
|
||||||
silent! execute 'sunmap' map
|
|
||||||
silent! execute 'sunmap <buffer>' map
|
|
||||||
endfor
|
|
||||||
|
|
||||||
" same behaviour of ultisnips
|
|
||||||
snoremap <silent> <BS> <c-g>c
|
|
||||||
snoremap <silent> <DEL> <c-g>c
|
|
||||||
snoremap <silent> <c-h> <c-g>c
|
|
||||||
snoremap <c-r> <c-g>"_c<c-r>
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#snippet#show_choices(lnum, col, position, input) abort
|
|
||||||
call coc#snippet#move(a:position)
|
|
||||||
call CocActionAsync('startCompletion', { 'source': '$words' })
|
|
||||||
redraw
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#snippet#enable(...)
|
|
||||||
if get(b:, 'coc_snippet_active', 0) == 1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let complete = get(a:, 1, 0)
|
|
||||||
let b:coc_snippet_active = 1
|
|
||||||
call coc#snippet#_select_mappings()
|
|
||||||
let nextkey = get(g:, 'coc_snippet_next', '<C-j>')
|
|
||||||
let prevkey = get(g:, 'coc_snippet_prev', '<C-k>')
|
|
||||||
if maparg(nextkey, 'i') =~# 'snippet'
|
|
||||||
let s:map_next = 0
|
|
||||||
endif
|
|
||||||
if maparg(prevkey, 'i') =~# 'snippet'
|
|
||||||
let s:map_prev = 0
|
|
||||||
endif
|
|
||||||
if !empty(nextkey)
|
|
||||||
if s:map_next
|
|
||||||
execute 'inoremap <buffer><nowait><silent>'.nextkey." <C-R>=coc#snippet#jump(1, ".complete.")<cr>"
|
|
||||||
endif
|
|
||||||
execute 'snoremap <buffer><nowait><silent>'.nextkey." <Esc>:call coc#snippet#jump(1, ".complete.")<cr>"
|
|
||||||
endif
|
|
||||||
if !empty(prevkey)
|
|
||||||
if s:map_prev
|
|
||||||
execute 'inoremap <buffer><nowait><silent>'.prevkey." <C-R>=coc#snippet#jump(0, ".complete.")<cr>"
|
|
||||||
endif
|
|
||||||
execute 'snoremap <buffer><nowait><silent>'.prevkey." <Esc>:call coc#snippet#jump(0, ".complete.")<cr>"
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#snippet#prev() abort
|
|
||||||
call coc#rpc#request('snippetPrev', [])
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#snippet#next() abort
|
|
||||||
call coc#rpc#request('snippetNext', [])
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#snippet#jump(direction, complete) abort
|
|
||||||
if a:direction == 1 && a:complete
|
|
||||||
if pumvisible()
|
|
||||||
let pre = exists('*complete_info') && complete_info()['selected'] == -1 ? "\<C-n>" : ''
|
|
||||||
call feedkeys(pre."\<C-y>", 'in')
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
if coc#pum#visible()
|
|
||||||
" Discard the return value, otherwise weird characters will be inserted
|
|
||||||
call coc#pum#confirm()
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call coc#rpc#request(a:direction == 1 ? 'snippetNext' : 'snippetPrev', [])
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#snippet#disable()
|
|
||||||
if get(b:, 'coc_snippet_active', 0) == 0
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let b:coc_snippet_active = 0
|
|
||||||
let nextkey = get(g:, 'coc_snippet_next', '<C-j>')
|
|
||||||
let prevkey = get(g:, 'coc_snippet_prev', '<C-k>')
|
|
||||||
if s:map_next
|
|
||||||
silent! execute 'iunmap <buffer> <silent> '.nextkey
|
|
||||||
endif
|
|
||||||
if s:map_prev
|
|
||||||
silent! execute 'iunmap <buffer> <silent> '.prevkey
|
|
||||||
endif
|
|
||||||
silent! execute 'sunmap <buffer> <silent> '.prevkey
|
|
||||||
silent! execute 'sunmap <buffer> <silent> '.nextkey
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#snippet#select(start, end, text) abort
|
|
||||||
if coc#pum#visible()
|
|
||||||
call coc#pum#close()
|
|
||||||
endif
|
|
||||||
if mode() == 's'
|
|
||||||
call feedkeys("\<Esc>", 'in')
|
|
||||||
endif
|
|
||||||
if &selection ==# 'exclusive'
|
|
||||||
let cursor = coc#snippet#to_cursor(a:start)
|
|
||||||
call cursor([cursor[0], cursor[1]])
|
|
||||||
let cmd = ''
|
|
||||||
let cmd .= mode()[0] ==# 'i' ? "\<Esc>".(col('.') == 1 ? '' : 'l') : ''
|
|
||||||
let cmd .= printf('v%s', strchars(a:text) . 'l')
|
|
||||||
let cmd .= "\<C-g>"
|
|
||||||
else
|
|
||||||
let cursor = coc#snippet#to_cursor(a:end)
|
|
||||||
call cursor([cursor[0], cursor[1] - 1])
|
|
||||||
let len = strchars(a:text) - 1
|
|
||||||
let cmd = ''
|
|
||||||
let cmd .= mode()[0] ==# 'i' ? "\<Esc>l" : ''
|
|
||||||
let cmd .= printf('v%s', len > 0 ? len . 'h' : '')
|
|
||||||
let cmd .= "o\<C-g>"
|
|
||||||
endif
|
|
||||||
call feedkeys(cmd, 'n')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#snippet#move(position) abort
|
|
||||||
let m = mode()
|
|
||||||
if m == 's'
|
|
||||||
call feedkeys("\<Esc>", 'in')
|
|
||||||
endif
|
|
||||||
let pos = coc#snippet#to_cursor(a:position)
|
|
||||||
call cursor(pos)
|
|
||||||
if pos[1] > strlen(getline(pos[0]))
|
|
||||||
startinsert!
|
|
||||||
else
|
|
||||||
startinsert
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#snippet#to_cursor(position) abort
|
|
||||||
let line = getline(a:position.line + 1)
|
|
||||||
if line is v:null
|
|
||||||
return [a:position.line + 1, a:position.character + 1]
|
|
||||||
endif
|
|
||||||
return [a:position.line + 1, coc#string#byte_index(line, a:position.character) + 1]
|
|
||||||
endfunction
|
|
|
@ -1,210 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
|
|
||||||
function! coc#string#last_character(line) abort
|
|
||||||
return strcharpart(a:line, strchars(a:line) - 1, 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Get utf16 code unit index from col (0 based)
|
|
||||||
function! coc#string#character_index(line, byteIdx) abort
|
|
||||||
if a:byteIdx <= 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
let i = 0
|
|
||||||
for char in split(strpart(a:line, 0, a:byteIdx), '\zs')
|
|
||||||
let i += char2nr(char) > 65535 ? 2 : 1
|
|
||||||
endfor
|
|
||||||
return i
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#string#common_start(text, other) abort
|
|
||||||
let arr = split(a:text, '\zs')
|
|
||||||
let other = split(a:other, '\zs')
|
|
||||||
let total = min([len(arr), len(other)])
|
|
||||||
if total == 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
for i in range(0, total - 1)
|
|
||||||
if arr[i] !=# other[i]
|
|
||||||
return i
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return total
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Convert utf16 character index to byte index
|
|
||||||
function! coc#string#byte_index(line, character) abort
|
|
||||||
if a:character <= 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
" code unit index
|
|
||||||
let i = 0
|
|
||||||
let len = 0
|
|
||||||
for char in split(a:line, '\zs')
|
|
||||||
let i += char2nr(char) > 65535 ? 2 : 1
|
|
||||||
let len += strlen(char)
|
|
||||||
if i >= a:character
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return len
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Get character count from start col and end col, 1 based
|
|
||||||
function! coc#string#get_char_count(text, start_col, end_col) abort
|
|
||||||
return strchars(strpart(a:text, a:start_col - 1, a:end_col - a:start_col))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#string#character_length(text) abort
|
|
||||||
let i = 0
|
|
||||||
for char in split(a:text, '\zs')
|
|
||||||
let i += char2nr(char) > 65535 ? 2 : 1
|
|
||||||
endfor
|
|
||||||
return i
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#string#reflow(lines, width) abort
|
|
||||||
let lines = []
|
|
||||||
let currlen = 0
|
|
||||||
let parts = []
|
|
||||||
for line in a:lines
|
|
||||||
for part in split(line, '\s\+')
|
|
||||||
let w = strwidth(part)
|
|
||||||
if currlen + w + 1 >= a:width
|
|
||||||
if len(parts) > 0
|
|
||||||
call add(lines, join(parts, ' '))
|
|
||||||
endif
|
|
||||||
if w >= a:width
|
|
||||||
call add(lines, part)
|
|
||||||
let currlen = 0
|
|
||||||
let parts = []
|
|
||||||
else
|
|
||||||
let currlen = w
|
|
||||||
let parts = [part]
|
|
||||||
endif
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
call add(parts, part)
|
|
||||||
let currlen = currlen + w + 1
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
if len(parts) > 0
|
|
||||||
call add(lines, join(parts, ' '))
|
|
||||||
endif
|
|
||||||
return empty(lines) ? [''] : lines
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Used when 'wrap' and 'linebreak' is enabled
|
|
||||||
function! coc#string#content_height(lines, width) abort
|
|
||||||
let len = 0
|
|
||||||
let pattern = empty(&breakat) ? '.\zs' : '['.substitute(&breakat, '\([\[\]]\)', '\\\1', 'g').']\zs'
|
|
||||||
for line in a:lines
|
|
||||||
if strwidth(line) <= a:width
|
|
||||||
let len += 1
|
|
||||||
else
|
|
||||||
let currlen = 0
|
|
||||||
for part in split(line, pattern)
|
|
||||||
let wl = strwidth(part)
|
|
||||||
if currlen == 0 && wl > 0
|
|
||||||
let len += 1
|
|
||||||
endif
|
|
||||||
let delta = currlen + wl - a:width
|
|
||||||
if delta >= 0
|
|
||||||
let len = len + (delta > 0)
|
|
||||||
let currlen = delta == 0 ? 0 : wl
|
|
||||||
if wl >= a:width
|
|
||||||
let currlen = wl%a:width
|
|
||||||
let len += float2nr(ceil(wl/(a:width + 0.0))) - (currlen == 0)
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let currlen = currlen + wl
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return len
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" get change between two lines
|
|
||||||
function! coc#string#diff(curr, previous, col) abort
|
|
||||||
let end = strpart(a:curr, a:col - 1)
|
|
||||||
let start = strpart(a:curr, 0, a:col -1)
|
|
||||||
let endOffset = 0
|
|
||||||
let startOffset = 0
|
|
||||||
let currLen = strchars(a:curr)
|
|
||||||
let prevLen = strchars(a:previous)
|
|
||||||
if len(end)
|
|
||||||
let endLen = strchars(end)
|
|
||||||
for i in range(min([prevLen, endLen]))
|
|
||||||
if strcharpart(end, endLen - 1 - i, 1) ==# strcharpart(a:previous, prevLen -1 -i, 1)
|
|
||||||
let endOffset = endOffset + 1
|
|
||||||
else
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
let remain = endOffset == 0 ? a:previous : strcharpart(a:previous, 0, prevLen - endOffset)
|
|
||||||
if len(remain)
|
|
||||||
for i in range(min([strchars(remain), strchars(start)]))
|
|
||||||
if strcharpart(remain, i, 1) ==# strcharpart(start, i ,1)
|
|
||||||
let startOffset = startOffset + 1
|
|
||||||
else
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
return {
|
|
||||||
\ 'start': startOffset,
|
|
||||||
\ 'end': prevLen - endOffset,
|
|
||||||
\ 'text': strcharpart(a:curr, startOffset, currLen - startOffset - endOffset)
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#string#apply(content, diff) abort
|
|
||||||
let totalLen = strchars(a:content)
|
|
||||||
let endLen = totalLen - a:diff['end']
|
|
||||||
return strcharpart(a:content, 0, a:diff['start']).a:diff['text'].strcharpart(a:content, a:diff['end'], endLen)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" insert inserted to line at position, use ... when result is too long
|
|
||||||
" line should only contains character has strwidth equals 1
|
|
||||||
function! coc#string#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
|
|
|
@ -1,179 +0,0 @@
|
||||||
" ============================================================================
|
|
||||||
" Description: Manage long running tasks.
|
|
||||||
" Author: Qiming Zhao <chemzqm@gmail.com>
|
|
||||||
" Licence: Anti 966 licence
|
|
||||||
" Version: 0.1
|
|
||||||
" Last Modified: Dec 12, 2020
|
|
||||||
" ============================================================================
|
|
||||||
scriptencoding utf-8
|
|
||||||
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:running_task = {}
|
|
||||||
" neovim emit strings that part of lines.
|
|
||||||
let s:out_remain_text = {}
|
|
||||||
let s:err_remain_text = {}
|
|
||||||
|
|
||||||
function! coc#task#start(id, opts)
|
|
||||||
if coc#task#running(a:id)
|
|
||||||
call coc#task#stop(a:id)
|
|
||||||
endif
|
|
||||||
let cmd = [a:opts['cmd']] + get(a:opts, 'args', [])
|
|
||||||
let cwd = get(a:opts, 'cwd', getcwd())
|
|
||||||
let env = get(a:opts, 'env', {})
|
|
||||||
" cmd args cwd pty
|
|
||||||
if s:is_vim
|
|
||||||
let options = {
|
|
||||||
\ 'cwd': cwd,
|
|
||||||
\ 'err_mode': 'nl',
|
|
||||||
\ 'out_mode': 'nl',
|
|
||||||
\ 'err_cb': {channel, message -> s:on_stderr(a:id, [message])},
|
|
||||||
\ 'out_cb': {channel, message -> s:on_stdout(a:id, [message])},
|
|
||||||
\ 'exit_cb': {channel, code -> s:on_exit(a:id, code)},
|
|
||||||
\ 'env': env,
|
|
||||||
\}
|
|
||||||
if has("patch-8.1.350")
|
|
||||||
let options['noblock'] = 1
|
|
||||||
endif
|
|
||||||
if get(a:opts, 'pty', 0)
|
|
||||||
let options['pty'] = 1
|
|
||||||
endif
|
|
||||||
let job = job_start(cmd, options)
|
|
||||||
let status = job_status(job)
|
|
||||||
if status !=# 'run'
|
|
||||||
echohl Error | echom 'Failed to start '.a:id.' task' | echohl None
|
|
||||||
return v:false
|
|
||||||
endif
|
|
||||||
let s:running_task[a:id] = job
|
|
||||||
else
|
|
||||||
let options = {
|
|
||||||
\ 'cwd': cwd,
|
|
||||||
\ 'on_stderr': {channel, msgs -> s:on_stderr(a:id, msgs)},
|
|
||||||
\ 'on_stdout': {channel, msgs -> s:on_stdout(a:id, msgs)},
|
|
||||||
\ 'on_exit': {channel, code -> s:on_exit(a:id, code)},
|
|
||||||
\ 'detach': get(a:opts, 'detach', 0),
|
|
||||||
\}
|
|
||||||
let original = {}
|
|
||||||
if !empty(env)
|
|
||||||
if has('nvim-0.5.0')
|
|
||||||
let options['env'] = env
|
|
||||||
elseif exists('*setenv') && exists('*getenv')
|
|
||||||
for key in keys(env)
|
|
||||||
let original[key] = getenv(key)
|
|
||||||
call setenv(key, env[key])
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if get(a:opts, 'pty', 0)
|
|
||||||
let options['pty'] = 1
|
|
||||||
endif
|
|
||||||
let chan_id = jobstart(cmd, options)
|
|
||||||
if !empty(original)
|
|
||||||
for key in keys(original)
|
|
||||||
call setenv(key, original[key])
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
if chan_id <= 0
|
|
||||||
echohl Error | echom 'Failed to start '.a:id.' task' | echohl None
|
|
||||||
return v:false
|
|
||||||
endif
|
|
||||||
let s:running_task[a:id] = chan_id
|
|
||||||
endif
|
|
||||||
return v:true
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#task#stop(id)
|
|
||||||
let job = get(s:running_task, a:id, v:null)
|
|
||||||
if !job | return | endif
|
|
||||||
if s:is_vim
|
|
||||||
call job_stop(job, 'term')
|
|
||||||
else
|
|
||||||
call jobstop(job)
|
|
||||||
endif
|
|
||||||
sleep 50m
|
|
||||||
let running = coc#task#running(a:id)
|
|
||||||
if running
|
|
||||||
echohl Error | echom 'job '.a:id. ' stop failed.' | echohl None
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:on_exit(id, code) abort
|
|
||||||
if get(g:, 'coc_vim_leaving', 0) | return | endif
|
|
||||||
if has('nvim')
|
|
||||||
let s:out_remain_text[a:id] = ''
|
|
||||||
let s:err_remain_text[a:id] = ''
|
|
||||||
endif
|
|
||||||
if has_key(s:running_task, a:id)
|
|
||||||
call remove(s:running_task, a:id)
|
|
||||||
endif
|
|
||||||
call coc#rpc#notify('TaskExit', [a:id, a:code])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:on_stderr(id, msgs)
|
|
||||||
if get(g:, 'coc_vim_leaving', 0) | return | endif
|
|
||||||
if empty(a:msgs)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
call coc#rpc#notify('TaskStderr', [a:id, a:msgs])
|
|
||||||
else
|
|
||||||
let remain = get(s:err_remain_text, a:id, '')
|
|
||||||
let eof = (a:msgs == [''])
|
|
||||||
let msgs = copy(a:msgs)
|
|
||||||
if len(remain) > 0
|
|
||||||
if msgs[0] == ''
|
|
||||||
let msgs[0] = remain
|
|
||||||
else
|
|
||||||
let msgs[0] = remain . msgs[0]
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let last = msgs[len(msgs) - 1]
|
|
||||||
let s:err_remain_text[a:id] = len(last) > 0 ? last : ''
|
|
||||||
" all lines from 0 to n - 2
|
|
||||||
if len(msgs) > 1
|
|
||||||
call coc#rpc#notify('TaskStderr', [a:id, msgs[:len(msgs)-2]])
|
|
||||||
elseif eof && len(msgs[0]) > 0
|
|
||||||
call coc#rpc#notify('TaskStderr', [a:id, msgs])
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:on_stdout(id, msgs)
|
|
||||||
if empty(a:msgs)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
call coc#rpc#notify('TaskStdout', [a:id, a:msgs])
|
|
||||||
else
|
|
||||||
let remain = get(s:out_remain_text, a:id, '')
|
|
||||||
let eof = (a:msgs == [''])
|
|
||||||
let msgs = copy(a:msgs)
|
|
||||||
if len(remain) > 0
|
|
||||||
if msgs[0] == ''
|
|
||||||
let msgs[0] = remain
|
|
||||||
else
|
|
||||||
let msgs[0] = remain . msgs[0]
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let last = msgs[len(msgs) - 1]
|
|
||||||
let s:out_remain_text[a:id] = len(last) > 0 ? last : ''
|
|
||||||
" all lines from 0 to n - 2
|
|
||||||
if len(msgs) > 1
|
|
||||||
call coc#rpc#notify('TaskStdout', [a:id, msgs[:len(msgs)-2]])
|
|
||||||
elseif eof && len(msgs[0]) > 0
|
|
||||||
call coc#rpc#notify('TaskStdout', [a:id, msgs])
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#task#running(id)
|
|
||||||
if !has_key(s:running_task, a:id) == 1
|
|
||||||
return v:false
|
|
||||||
endif
|
|
||||||
let job = s:running_task[a:id]
|
|
||||||
if s:is_vim
|
|
||||||
let status = job_status(job)
|
|
||||||
return status ==# 'run'
|
|
||||||
endif
|
|
||||||
let [code] = jobwait([job], 10)
|
|
||||||
return code == -1
|
|
||||||
endfunction
|
|
|
@ -1,115 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:channel_map = {}
|
|
||||||
let s:is_win = has('win32') || has('win64')
|
|
||||||
|
|
||||||
" start terminal, return [bufnr, pid]
|
|
||||||
function! coc#terminal#start(cmd, cwd, env, strict) abort
|
|
||||||
if s:is_vim && !has('terminal')
|
|
||||||
throw 'terminal feature not supported by current vim.'
|
|
||||||
endif
|
|
||||||
let cwd = empty(a:cwd) ? getcwd() : a:cwd
|
|
||||||
execute 'belowright '.get(g:, 'coc_terminal_height', 8).'new +setl\ buftype=nofile'
|
|
||||||
setl winfixheight
|
|
||||||
setl norelativenumber
|
|
||||||
setl nonumber
|
|
||||||
setl bufhidden=hide
|
|
||||||
if exists('#User#CocTerminalOpen')
|
|
||||||
exe 'doautocmd <nomodeline> User CocTerminalOpen'
|
|
||||||
endif
|
|
||||||
let bufnr = bufnr('%')
|
|
||||||
let env = {}
|
|
||||||
let original = {}
|
|
||||||
if !empty(a:env)
|
|
||||||
" use env option when possible
|
|
||||||
if s:is_vim
|
|
||||||
let env = copy(a:env)
|
|
||||||
elseif exists('*setenv')
|
|
||||||
for key in keys(a:env)
|
|
||||||
let original[key] = getenv(key)
|
|
||||||
call setenv(key, a:env[key])
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
function! s:OnExit(status) closure
|
|
||||||
call coc#rpc#notify('CocAutocmd', ['TermExit', bufnr, a:status])
|
|
||||||
if a:status == 0
|
|
||||||
execute 'silent! bd! '.bufnr
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
if has('nvim')
|
|
||||||
let job_id = termopen(a:cmd, {
|
|
||||||
\ 'cwd': cwd,
|
|
||||||
\ 'pty': v:true,
|
|
||||||
\ 'on_exit': {job, status -> s:OnExit(status)},
|
|
||||||
\ 'env': env,
|
|
||||||
\ 'clear_env': a:strict ? v:true : v:false
|
|
||||||
\ })
|
|
||||||
if !empty(original) && exists('*setenv')
|
|
||||||
for key in keys(original)
|
|
||||||
call setenv(key, original[key])
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
if job_id == 0
|
|
||||||
throw 'create terminal job failed'
|
|
||||||
endif
|
|
||||||
wincmd p
|
|
||||||
let s:channel_map[bufnr] = job_id
|
|
||||||
return [bufnr, jobpid(job_id)]
|
|
||||||
else
|
|
||||||
let cmd = s:is_win ? join(a:cmd, ' ') : a:cmd
|
|
||||||
let res = term_start(cmd, {
|
|
||||||
\ 'cwd': cwd,
|
|
||||||
\ 'term_kill': s:is_win ? 'kill' : 'term',
|
|
||||||
\ 'term_finish': 'close',
|
|
||||||
\ 'exit_cb': {job, status -> s:OnExit(status)},
|
|
||||||
\ 'curwin': 1,
|
|
||||||
\ 'env': env,
|
|
||||||
\})
|
|
||||||
if res == 0
|
|
||||||
throw 'create terminal job failed'
|
|
||||||
endif
|
|
||||||
let job = term_getjob(bufnr)
|
|
||||||
let s:channel_map[bufnr] = job_getchannel(job)
|
|
||||||
wincmd p
|
|
||||||
return [bufnr, job_info(job).process]
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#terminal#send(bufnr, text, add_new_line) abort
|
|
||||||
let chan = get(s:channel_map, a:bufnr, v:null)
|
|
||||||
if empty(chan) | return| endif
|
|
||||||
if has('nvim')
|
|
||||||
let lines = split(a:text, '\v\r?\n')
|
|
||||||
if a:add_new_line && !empty(lines[len(lines) - 1])
|
|
||||||
if s:is_win
|
|
||||||
call add(lines, "\r\n")
|
|
||||||
else
|
|
||||||
call add(lines, '')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call chansend(chan, lines)
|
|
||||||
let winid = bufwinid(a:bufnr)
|
|
||||||
if winid != -1
|
|
||||||
call coc#compat#execute(winid, 'noa normal! G')
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if !a:add_new_line
|
|
||||||
call ch_sendraw(chan, a:text)
|
|
||||||
else
|
|
||||||
call ch_sendraw(chan, a:text.(s:is_win ? "\r\n" : "\n"))
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#terminal#close(bufnr) abort
|
|
||||||
if has('nvim')
|
|
||||||
let job_id = get(s:channel_map, a:bufnr, 0)
|
|
||||||
if !empty(job_id)
|
|
||||||
silent! call chanclose(job_id)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
exe 'silent! bd! '.a:bufnr
|
|
||||||
endfunction
|
|
|
@ -1,567 +0,0 @@
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:is_win = has('win32') || has('win64')
|
|
||||||
let s:is_mac = has('mac')
|
|
||||||
let s:sign_api = exists('*sign_getplaced') && exists('*sign_place')
|
|
||||||
let s:sign_groups = []
|
|
||||||
let s:outline_preview_bufnr = 0
|
|
||||||
|
|
||||||
" Check <Tab> and <CR>
|
|
||||||
function! coc#ui#check_pum_keymappings(trigger) abort
|
|
||||||
if a:trigger !=# 'none'
|
|
||||||
for key in ['<cr>', '<tab>', '<c-y>', '<s-tab>']
|
|
||||||
let arg = maparg(key, 'i', 0, 1)
|
|
||||||
if get(arg, 'expr', 0)
|
|
||||||
let rhs = get(arg, 'rhs', '')
|
|
||||||
if rhs =~# '\<pumvisible()' && rhs !~# '\<coc#pum#visible()'
|
|
||||||
let rhs = substitute(rhs, '\Cpumvisible()', 'coc#pum#visible()', 'g')
|
|
||||||
let rhs = substitute(rhs, '\c"\\<C-n>"', 'coc#pum#next(1)', '')
|
|
||||||
let rhs = substitute(rhs, '\c"\\<C-p>"', 'coc#pum#prev(1)', '')
|
|
||||||
let rhs = substitute(rhs, '\c"\\<C-y>"', 'coc#pum#confirm()', '')
|
|
||||||
execute 'inoremap <silent><nowait><expr> '.arg['lhs'].' '.rhs
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#quickpick(title, items, cb) abort
|
|
||||||
if exists('*popup_menu')
|
|
||||||
function! s:QuickpickHandler(id, result) closure
|
|
||||||
call a:cb(v:null, a:result)
|
|
||||||
endfunction
|
|
||||||
function! s:QuickpickFilter(id, key) closure
|
|
||||||
for i in range(1, len(a:items))
|
|
||||||
if a:key == string(i)
|
|
||||||
call popup_close(a:id, i)
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
" No shortcut, pass to generic filter
|
|
||||||
return popup_filter_menu(a:id, a:key)
|
|
||||||
endfunction
|
|
||||||
try
|
|
||||||
call popup_menu(a:items, {
|
|
||||||
\ 'title': a:title,
|
|
||||||
\ 'filter': function('s:QuickpickFilter'),
|
|
||||||
\ 'callback': function('s:QuickpickHandler'),
|
|
||||||
\ })
|
|
||||||
redraw
|
|
||||||
catch /.*/
|
|
||||||
call a:cb(v:exception)
|
|
||||||
endtry
|
|
||||||
else
|
|
||||||
let res = inputlist([a:title] + a:items)
|
|
||||||
call a:cb(v:null, res)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" cmd, cwd
|
|
||||||
function! coc#ui#open_terminal(opts) abort
|
|
||||||
if s:is_vim && !exists('*term_start')
|
|
||||||
echohl WarningMsg | echon "Your vim doesn't have terminal support!" | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if get(a:opts, 'position', 'bottom') ==# 'bottom'
|
|
||||||
let p = '5new'
|
|
||||||
else
|
|
||||||
let p = 'vnew'
|
|
||||||
endif
|
|
||||||
execute 'belowright '.p.' +setl\ buftype=nofile '
|
|
||||||
setl buftype=nofile
|
|
||||||
setl winfixheight
|
|
||||||
setl norelativenumber
|
|
||||||
setl nonumber
|
|
||||||
setl bufhidden=wipe
|
|
||||||
if exists('#User#CocTerminalOpen')
|
|
||||||
exe 'doautocmd <nomodeline> User CocTerminalOpen'
|
|
||||||
endif
|
|
||||||
let cmd = get(a:opts, 'cmd', '')
|
|
||||||
let autoclose = get(a:opts, 'autoclose', 1)
|
|
||||||
if empty(cmd)
|
|
||||||
throw 'command required!'
|
|
||||||
endif
|
|
||||||
let cwd = get(a:opts, 'cwd', getcwd())
|
|
||||||
let keepfocus = get(a:opts, 'keepfocus', 0)
|
|
||||||
let bufnr = bufnr('%')
|
|
||||||
let Callback = get(a:opts, 'Callback', v:null)
|
|
||||||
|
|
||||||
function! s:OnExit(status) closure
|
|
||||||
let content = join(getbufline(bufnr, 1, '$'), "\n")
|
|
||||||
if a:status == 0 && autoclose == 1
|
|
||||||
execute 'silent! bd! '.bufnr
|
|
||||||
endif
|
|
||||||
if !empty(Callback)
|
|
||||||
call call(Callback, [a:status, bufnr, content])
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
if has('nvim')
|
|
||||||
call termopen(cmd, {
|
|
||||||
\ 'cwd': cwd,
|
|
||||||
\ 'on_exit': {job, status -> s:OnExit(status)},
|
|
||||||
\})
|
|
||||||
else
|
|
||||||
if s:is_win
|
|
||||||
let cmd = 'cmd.exe /C "'.cmd.'"'
|
|
||||||
endif
|
|
||||||
call term_start(cmd, {
|
|
||||||
\ 'cwd': cwd,
|
|
||||||
\ 'exit_cb': {job, status -> s:OnExit(status)},
|
|
||||||
\ 'curwin': 1,
|
|
||||||
\})
|
|
||||||
endif
|
|
||||||
if keepfocus
|
|
||||||
wincmd p
|
|
||||||
endif
|
|
||||||
return bufnr
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" run command in terminal
|
|
||||||
function! coc#ui#run_terminal(opts, cb)
|
|
||||||
let cmd = get(a:opts, 'cmd', '')
|
|
||||||
if empty(cmd)
|
|
||||||
return a:cb('command required for terminal')
|
|
||||||
endif
|
|
||||||
let opts = {
|
|
||||||
\ 'cmd': cmd,
|
|
||||||
\ 'cwd': empty(get(a:opts, 'cwd', '')) ? getcwd() : a:opts['cwd'],
|
|
||||||
\ 'keepfocus': get(a:opts, 'keepfocus', 0),
|
|
||||||
\ 'Callback': {status, bufnr, content -> a:cb(v:null, {'success': status == 0 ? v:true : v:false, 'bufnr': bufnr, 'content': content})}
|
|
||||||
\}
|
|
||||||
call coc#ui#open_terminal(opts)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#echo_hover(msg)
|
|
||||||
echohl MoreMsg
|
|
||||||
echo a:msg
|
|
||||||
echohl None
|
|
||||||
let g:coc_last_hover_message = a:msg
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#echo_messages(hl, msgs)
|
|
||||||
if a:hl !~# 'Error' && (mode() !~# '\v^(i|n)$')
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let msgs = filter(copy(a:msgs), '!empty(v:val)')
|
|
||||||
if empty(msgs)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
execute 'echohl '.a:hl
|
|
||||||
echo join(msgs, "\n")
|
|
||||||
echohl None
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#preview_info(lines, filetype, ...) abort
|
|
||||||
pclose
|
|
||||||
keepalt new +setlocal\ previewwindow|setlocal\ buftype=nofile|setlocal\ noswapfile|setlocal\ wrap [Document]
|
|
||||||
setl bufhidden=wipe
|
|
||||||
setl nobuflisted
|
|
||||||
setl nospell
|
|
||||||
exe 'setl filetype='.a:filetype
|
|
||||||
setl conceallevel=0
|
|
||||||
setl nofoldenable
|
|
||||||
for command in a:000
|
|
||||||
execute command
|
|
||||||
endfor
|
|
||||||
call append(0, a:lines)
|
|
||||||
exe "normal! z" . len(a:lines) . "\<cr>"
|
|
||||||
exe "normal! gg"
|
|
||||||
wincmd p
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#open_files(files)
|
|
||||||
let bufnrs = []
|
|
||||||
" added on latest vim8
|
|
||||||
if exists('*bufadd') && exists('*bufload')
|
|
||||||
for file in a:files
|
|
||||||
let file = fnamemodify(file, ':.')
|
|
||||||
if bufloaded(file)
|
|
||||||
call add(bufnrs, bufnr(file))
|
|
||||||
else
|
|
||||||
let bufnr = bufadd(file)
|
|
||||||
call bufload(file)
|
|
||||||
call add(bufnrs, bufnr)
|
|
||||||
call setbufvar(bufnr, '&buflisted', 1)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
noa keepalt 1new +setl\ bufhidden=wipe
|
|
||||||
for file in a:files
|
|
||||||
let file = fnamemodify(file, ':.')
|
|
||||||
execute 'noa edit +setl\ bufhidden=hide '.fnameescape(file)
|
|
||||||
if &filetype ==# ''
|
|
||||||
filetype detect
|
|
||||||
endif
|
|
||||||
call add(bufnrs, bufnr('%'))
|
|
||||||
endfor
|
|
||||||
noa close
|
|
||||||
endif
|
|
||||||
doautocmd BufEnter
|
|
||||||
return bufnrs
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#echo_lines(lines)
|
|
||||||
echo join(a:lines, "\n")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#echo_signatures(signatures) abort
|
|
||||||
if pumvisible() | return | endif
|
|
||||||
echo ""
|
|
||||||
for i in range(len(a:signatures))
|
|
||||||
call s:echo_signature(a:signatures[i])
|
|
||||||
if i != len(a:signatures) - 1
|
|
||||||
echon "\n"
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:echo_signature(parts)
|
|
||||||
for part in a:parts
|
|
||||||
let hl = get(part, 'type', 'Normal')
|
|
||||||
let text = get(part, 'text', '')
|
|
||||||
if !empty(text)
|
|
||||||
execute 'echohl '.hl
|
|
||||||
execute "echon '".substitute(text, "'", "''", 'g')."'"
|
|
||||||
echohl None
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#iterm_open(dir)
|
|
||||||
return s:osascript(
|
|
||||||
\ 'if application "iTerm2" is not running',
|
|
||||||
\ 'error',
|
|
||||||
\ 'end if') && s:osascript(
|
|
||||||
\ 'tell application "iTerm2"',
|
|
||||||
\ 'tell current window',
|
|
||||||
\ 'create tab with default profile',
|
|
||||||
\ 'tell current session',
|
|
||||||
\ 'write text "cd ' . a:dir . '"',
|
|
||||||
\ 'write text "clear"',
|
|
||||||
\ 'activate',
|
|
||||||
\ 'end tell',
|
|
||||||
\ 'end tell',
|
|
||||||
\ 'end tell')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:osascript(...) abort
|
|
||||||
let args = join(map(copy(a:000), '" -e ".shellescape(v:val)'), '')
|
|
||||||
call s:system('osascript'. args)
|
|
||||||
return !v:shell_error
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:system(cmd)
|
|
||||||
let output = system(a:cmd)
|
|
||||||
if v:shell_error && output !=# ""
|
|
||||||
echohl Error | echom output | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
return output
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#set_lines(bufnr, changedtick, original, replacement, start, end, changes, cursor, col) abort
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let delta = 0
|
|
||||||
if !empty(a:col)
|
|
||||||
let delta = col('.') - a:col
|
|
||||||
endif
|
|
||||||
if getbufvar(a:bufnr, 'changedtick') > a:changedtick && bufnr('%') == a:bufnr
|
|
||||||
" try apply current line change
|
|
||||||
let lnum = line('.')
|
|
||||||
" change for current line
|
|
||||||
if a:end - a:start == 1 && a:end == lnum && len(a:replacement) == 1
|
|
||||||
let idx = a:start - lnum + 1
|
|
||||||
let previous = get(a:original, idx, 0)
|
|
||||||
if type(previous) == 1
|
|
||||||
let content = getline('.')
|
|
||||||
if previous !=# content
|
|
||||||
let diff = coc#string#diff(content, previous, col('.'))
|
|
||||||
let changed = get(a:replacement, idx, 0)
|
|
||||||
if type(changed) == 1 && strcharpart(previous, 0, diff['end']) ==# strcharpart(changed, 0, diff['end'])
|
|
||||||
let applied = coc#string#apply(changed, diff)
|
|
||||||
let replacement = copy(a:replacement)
|
|
||||||
let replacement[idx] = applied
|
|
||||||
call coc#compat#buf_set_lines(a:bufnr, a:start, a:end, replacement)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if exists('*nvim_buf_set_text') && !empty(a:changes)
|
|
||||||
for item in reverse(copy(a:changes))
|
|
||||||
call nvim_buf_set_text(a:bufnr, item[1], item[2], item[3], item[4], item[0])
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
call coc#compat#buf_set_lines(a:bufnr, a:start, a:end, a:replacement)
|
|
||||||
endif
|
|
||||||
if !empty(a:cursor)
|
|
||||||
call cursor(a:cursor[0], a:cursor[1] + delta)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#change_lines(bufnr, list) abort
|
|
||||||
if !bufloaded(a:bufnr) | return v:null | endif
|
|
||||||
undojoin
|
|
||||||
if exists('*setbufline')
|
|
||||||
for [lnum, line] in a:list
|
|
||||||
call setbufline(a:bufnr, lnum + 1, line)
|
|
||||||
endfor
|
|
||||||
elseif a:bufnr == bufnr('%')
|
|
||||||
for [lnum, line] in a:list
|
|
||||||
call setline(lnum + 1, line)
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
let bufnr = bufnr('%')
|
|
||||||
exe 'noa buffer '.a:bufnr
|
|
||||||
for [lnum, line] in a:list
|
|
||||||
call setline(lnum + 1, line)
|
|
||||||
endfor
|
|
||||||
exe 'noa buffer '.bufnr
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#open_url(url)
|
|
||||||
if isdirectory(a:url) && $TERM_PROGRAM ==# "iTerm.app"
|
|
||||||
call coc#ui#iterm_open(a:url)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if !empty(get(g:, 'coc_open_url_command', ''))
|
|
||||||
call system(g:coc_open_url_command.' '.a:url)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if has('mac') && executable('open')
|
|
||||||
call system('open '.a:url)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if executable('xdg-open')
|
|
||||||
call system('xdg-open '.a:url)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call system('cmd /c start "" /b '. substitute(a:url, '&', '^&', 'g'))
|
|
||||||
if v:shell_error
|
|
||||||
echohl Error | echom 'Failed to open '.a:url | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#rename_file(oldPath, newPath, write) abort
|
|
||||||
let bufnr = bufnr(a:oldPath)
|
|
||||||
if bufnr == -1
|
|
||||||
throw 'Unable to get bufnr of '.a:oldPath
|
|
||||||
endif
|
|
||||||
if a:oldPath =~? a:newPath && (s:is_mac || s:is_win)
|
|
||||||
return coc#ui#safe_rename(bufnr, a:oldPath, a:newPath, a:write)
|
|
||||||
endif
|
|
||||||
if bufloaded(a:newPath)
|
|
||||||
execute 'silent bdelete! '.bufnr(a:newPath)
|
|
||||||
endif
|
|
||||||
let current = bufnr == bufnr('%')
|
|
||||||
let bufname = fnamemodify(a:newPath, ":~:.")
|
|
||||||
let filepath = fnamemodify(bufname(bufnr), '%:p')
|
|
||||||
let winid = coc#compat#buf_win_id(bufnr)
|
|
||||||
let curr = -1
|
|
||||||
if winid == -1
|
|
||||||
let curr = win_getid()
|
|
||||||
let file = fnamemodify(bufname(bufnr), ':.')
|
|
||||||
execute 'keepalt tab drop '.fnameescape(bufname(bufnr))
|
|
||||||
let winid = win_getid()
|
|
||||||
endif
|
|
||||||
call coc#compat#execute(winid, 'keepalt file '.fnameescape(bufname), 'silent')
|
|
||||||
call coc#compat#execute(winid, 'doautocmd BufEnter')
|
|
||||||
if a:write
|
|
||||||
call coc#compat#execute(winid, 'noa write!', 'silent')
|
|
||||||
call delete(filepath, '')
|
|
||||||
endif
|
|
||||||
if curr != -1
|
|
||||||
call win_gotoid(curr)
|
|
||||||
endif
|
|
||||||
return bufnr
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" System is case in sensitive and newPath have different case.
|
|
||||||
function! coc#ui#safe_rename(bufnr, oldPath, newPath, write) abort
|
|
||||||
let winid = win_getid()
|
|
||||||
let lines = getbufline(a:bufnr, 1, '$')
|
|
||||||
execute 'keepalt tab drop '.fnameescape(fnamemodify(a:oldPath, ':.'))
|
|
||||||
let view = winsaveview()
|
|
||||||
execute 'keepalt bwipeout! '.a:bufnr
|
|
||||||
if a:write
|
|
||||||
call delete(a:oldPath, '')
|
|
||||||
endif
|
|
||||||
execute 'keepalt edit '.fnameescape(fnamemodify(a:newPath, ':~:.'))
|
|
||||||
let bufnr = bufnr('%')
|
|
||||||
call coc#compat#buf_set_lines(bufnr, 0, -1, lines)
|
|
||||||
if a:write
|
|
||||||
execute 'noa write'
|
|
||||||
endif
|
|
||||||
call winrestview(view)
|
|
||||||
call win_gotoid(winid)
|
|
||||||
return bufnr
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#sign_unplace() abort
|
|
||||||
if exists('*sign_unplace')
|
|
||||||
for group in s:sign_groups
|
|
||||||
call sign_unplace(group)
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#update_signs(bufnr, group, signs) abort
|
|
||||||
if !s:sign_api || !bufloaded(a:bufnr)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call sign_unplace(a:group, {'buffer': a:bufnr})
|
|
||||||
for def in a:signs
|
|
||||||
let opts = {'lnum': def['lnum']}
|
|
||||||
if has_key(def, 'priority')
|
|
||||||
let opts['priority'] = def['priority']
|
|
||||||
endif
|
|
||||||
call sign_place(0, a:group, def['name'], a:bufnr, opts)
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#outline_preview(config) abort
|
|
||||||
let view_id = get(w:, 'cocViewId', '')
|
|
||||||
if view_id !=# 'OUTLINE'
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let wininfo = get(getwininfo(win_getid()), 0, v:null)
|
|
||||||
if empty(wininfo)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let border = get(a:config, 'border', v:true)
|
|
||||||
let th = &lines - &cmdheight - 2
|
|
||||||
let range = a:config['range']
|
|
||||||
let height = min([range['end']['line'] - range['start']['line'] + 1, th - 4])
|
|
||||||
let to_left = &columns - wininfo['wincol'] - wininfo['width'] < wininfo['wincol']
|
|
||||||
let start_lnum = range['start']['line'] + 1
|
|
||||||
let end_lnum = range['end']['line'] + 1 - start_lnum > &lines ? start_lnum + &lines : range['end']['line'] + 1
|
|
||||||
let lines = getbufline(a:config['bufnr'], start_lnum, end_lnum)
|
|
||||||
let content_width = max(map(copy(lines), 'strdisplaywidth(v:val)'))
|
|
||||||
let width = min([content_width, a:config['maxWidth'], to_left ? wininfo['wincol'] - 3 : &columns - wininfo['wincol'] - wininfo['width']])
|
|
||||||
let filetype = getbufvar(a:config['bufnr'], '&filetype')
|
|
||||||
let cursor_row = coc#cursor#screen_pos()[0]
|
|
||||||
let config = {
|
|
||||||
\ 'relative': 'editor',
|
|
||||||
\ 'row': cursor_row - 1 + height < th ? cursor_row - (border ? 1 : 0) : th - height - (border ? 1 : -1),
|
|
||||||
\ 'col': to_left ? wininfo['wincol'] - 4 - width : wininfo['wincol'] + wininfo['width'],
|
|
||||||
\ 'width': width,
|
|
||||||
\ 'height': height,
|
|
||||||
\ 'lines': lines,
|
|
||||||
\ 'border': border ? [1,1,1,1] : v:null,
|
|
||||||
\ 'rounded': get(a:config, 'rounded', 1) ? 1 : 0,
|
|
||||||
\ 'winblend': a:config['winblend'],
|
|
||||||
\ 'highlight': a:config['highlight'],
|
|
||||||
\ 'borderhighlight': a:config['borderhighlight'],
|
|
||||||
\ }
|
|
||||||
let winid = coc#float#get_float_by_kind('outline-preview')
|
|
||||||
let result = coc#float#create_float_win(winid, s:outline_preview_bufnr, config)
|
|
||||||
if empty(result)
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
call setwinvar(result[0], 'kind', 'outline-preview')
|
|
||||||
let s:outline_preview_bufnr = result[1]
|
|
||||||
if !empty(filetype)
|
|
||||||
call coc#compat#execute(result[0], 'setfiletype '.filetype)
|
|
||||||
endif
|
|
||||||
return result[1]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#outline_close_preview() abort
|
|
||||||
let winid = coc#float#get_float_by_kind('outline-preview')
|
|
||||||
if winid
|
|
||||||
call coc#float#close(winid)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Ignore error from autocmd when file opened
|
|
||||||
function! coc#ui#safe_open(cmd, file) abort
|
|
||||||
let bufname = fnameescape(a:file)
|
|
||||||
try
|
|
||||||
execute a:cmd.' 'bufname
|
|
||||||
catch /.*/
|
|
||||||
if bufname('%') != bufname
|
|
||||||
throw v:exception
|
|
||||||
endif
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Use noa to setloclist, avoid BufWinEnter autocmd
|
|
||||||
function! coc#ui#setloclist(nr, items, action, title) abort
|
|
||||||
if a:action ==# ' '
|
|
||||||
let title = get(getloclist(a:nr, {'title': 1}), 'title', '')
|
|
||||||
let action = title ==# a:title ? 'r' : ' '
|
|
||||||
noa call setloclist(a:nr, [], action, {'title': a:title, 'items': a:items})
|
|
||||||
else
|
|
||||||
noa call setloclist(a:nr, [], a:action, {'title': a:title, 'items': a:items})
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#ui#get_mouse() abort
|
|
||||||
if get(g:, 'coc_node_env', '') ==# 'test'
|
|
||||||
return get(g:, 'mouse_position', [win_getid(), line('.'), col('.')])
|
|
||||||
endif
|
|
||||||
return [v:mouse_winid,v:mouse_lnum,v:mouse_col]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" viewId - identifier of tree view
|
|
||||||
" bufnr - bufnr tree view
|
|
||||||
" winid - winid of tree view
|
|
||||||
" bufname - bufname of tree view
|
|
||||||
" command - split command
|
|
||||||
" optional options - bufhidden, canSelectMany, winfixwidth
|
|
||||||
function! coc#ui#create_tree(opts) abort
|
|
||||||
let viewId = a:opts['viewId']
|
|
||||||
let bufname = a:opts['bufname']
|
|
||||||
let tabid = coc#util#tabnr_id(tabpagenr())
|
|
||||||
let winid = s:get_tree_winid(a:opts)
|
|
||||||
let bufnr = a:opts['bufnr']
|
|
||||||
if !bufloaded(bufnr)
|
|
||||||
let bufnr = -1
|
|
||||||
endif
|
|
||||||
if winid != -1
|
|
||||||
call win_gotoid(winid)
|
|
||||||
if bufnr('%') == bufnr
|
|
||||||
return [bufnr, winid, tabid]
|
|
||||||
elseif bufnr != -1
|
|
||||||
execute 'silent keepalt buffer '.bufnr
|
|
||||||
else
|
|
||||||
execute 'silent keepalt edit +setl\ buftype=nofile '.bufname
|
|
||||||
call s:set_tree_defaults(a:opts)
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
" need to split
|
|
||||||
let cmd = get(a:opts, 'command', 'belowright 30vs')
|
|
||||||
execute 'silent keepalt '.cmd.' +setl\ buftype=nofile '.bufname
|
|
||||||
call s:set_tree_defaults(a:opts)
|
|
||||||
let winid = win_getid()
|
|
||||||
endif
|
|
||||||
let w:cocViewId = viewId
|
|
||||||
return [winbufnr(winid), winid, tabid]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" valid window id or -1
|
|
||||||
function! s:get_tree_winid(opts) abort
|
|
||||||
let viewId = a:opts['viewId']
|
|
||||||
let winid = a:opts['winid']
|
|
||||||
if winid != -1 && coc#window#visible(winid)
|
|
||||||
return winid
|
|
||||||
endif
|
|
||||||
if winid != -1
|
|
||||||
call coc#compat#execute(winid, 'noa close!', 'silent!')
|
|
||||||
endif
|
|
||||||
return coc#window#find('cocViewId', viewId)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:set_tree_defaults(opts) abort
|
|
||||||
let bufhidden = get(a:opts, 'bufhidden', 'wipe')
|
|
||||||
let signcolumn = get(a:opts, 'canSelectMany', v:false) ? 'yes' : 'no'
|
|
||||||
let winfixwidth = get(a:opts, 'winfixwidth', v:false) ? ' winfixwidth' : ''
|
|
||||||
execute 'setl bufhidden='.bufhidden.' signcolumn='.signcolumn.winfixwidth
|
|
||||||
setl nolist nonumber norelativenumber foldcolumn=0
|
|
||||||
setl nocursorline nobuflisted wrap undolevels=-1 filetype=coctree nomodifiable noswapfile
|
|
||||||
endfunction
|
|
|
@ -1,659 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:root = expand('<sfile>:h:h:h')
|
|
||||||
let s:is_win = has('win32') || has('win64')
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:vim_api_version = 34
|
|
||||||
|
|
||||||
function! coc#util#merge_winhl(curr, hls) abort
|
|
||||||
let highlightMap = {}
|
|
||||||
for parts in map(split(a:curr, ','), 'split(v:val, ":")')
|
|
||||||
if len(parts) == 2
|
|
||||||
let highlightMap[parts[0]] = parts[1]
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
for item in a:hls
|
|
||||||
let highlightMap[item[0]] = item[1]
|
|
||||||
endfor
|
|
||||||
return join(map(items(highlightMap), 'v:val[0].":".v:val[1]'), ',')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#api_version() abort
|
|
||||||
return s:vim_api_version
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#semantic_hlgroups() abort
|
|
||||||
let res = split(execute('hi'), "\n")
|
|
||||||
let filtered = filter(res, "v:val =~# '^CocSem' && v:val !~# ' cleared$'")
|
|
||||||
return map(filtered, "matchstr(v:val,'\\v^CocSem\\w+')")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" get cursor position
|
|
||||||
function! coc#util#cursor()
|
|
||||||
return [line('.') - 1, coc#string#character_length(strpart(getline('.'), 0, col('.') - 1))]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#change_info() abort
|
|
||||||
return {'lnum': line('.'), 'col': col('.'), 'line': getline('.'), 'changedtick': b:changedtick}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#jumpTo(line, character) abort
|
|
||||||
echohl WarningMsg | echon 'coc#util#jumpTo is deprecated, use coc#cursor#move_to instead.' | echohl None
|
|
||||||
call coc#cursor#move_to(a:line, a:character)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#root_patterns() abort
|
|
||||||
return coc#rpc#request('rootPatterns', [bufnr('%')])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#get_config(key) abort
|
|
||||||
return coc#rpc#request('getConfig', [a:key])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#open_terminal(opts) abort
|
|
||||||
return coc#ui#open_terminal(a:opts)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#synname() abort
|
|
||||||
return synIDattr(synID(line('.'), col('.') - 1, 1), 'name')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#setline(lnum, line)
|
|
||||||
keepjumps call setline(a:lnum, a:line)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#path_replace_patterns() abort
|
|
||||||
if has('win32unix') && exists('g:coc_cygqwin_path_prefixes')
|
|
||||||
echohl WarningMsg
|
|
||||||
echon 'g:coc_cygqwin_path_prefixes is deprecated, use g:coc_uri_prefix_replace_patterns instead'
|
|
||||||
echohl None
|
|
||||||
return g:coc_cygqwin_path_prefixes
|
|
||||||
endif
|
|
||||||
if exists('g:coc_uri_prefix_replace_patterns')
|
|
||||||
return g:coc_uri_prefix_replace_patterns
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#version()
|
|
||||||
if s:is_vim
|
|
||||||
return string(v:versionlong)
|
|
||||||
endif
|
|
||||||
let c = execute('silent version')
|
|
||||||
let lines = split(matchstr(c, 'NVIM v\zs[^\n-]*'))
|
|
||||||
return lines[0]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#check_refresh(bufnr)
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
if getbufvar(a:bufnr, 'coc_diagnostic_disable', 0)
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#diagnostic_info(bufnr, checkInsert) abort
|
|
||||||
let checked = coc#util#check_refresh(a:bufnr)
|
|
||||||
if !checked
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
if a:checkInsert && mode() =~# '^i'
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let locationlist = ''
|
|
||||||
let winid = -1
|
|
||||||
for info in getwininfo()
|
|
||||||
if info['bufnr'] == a:bufnr
|
|
||||||
let winid = info['winid']
|
|
||||||
let locationlist = get(getloclist(winid, {'title': 1}), 'title', '')
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return {
|
|
||||||
\ 'bufnr': bufnr('%'),
|
|
||||||
\ 'winid': winid,
|
|
||||||
\ 'lnum': winid == -1 ? -1 : coc#window#get_cursor(winid)[0],
|
|
||||||
\ 'locationlist': locationlist
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#open_file(cmd, file)
|
|
||||||
execute a:cmd .' '.fnameescape(fnamemodify(a:file, ':~:.'))
|
|
||||||
return bufnr('%')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#job_command()
|
|
||||||
if (has_key(g:, 'coc_node_path'))
|
|
||||||
let node = expand(g:coc_node_path)
|
|
||||||
else
|
|
||||||
let node = $COC_NODE_PATH == '' ? 'node' : $COC_NODE_PATH
|
|
||||||
endif
|
|
||||||
if !executable(node)
|
|
||||||
echohl Error | echom '[coc.nvim] "'.node.'" is not executable, checkout https://nodejs.org/en/download/' | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if !filereadable(s:root.'/build/index.js')
|
|
||||||
if isdirectory(s:root.'/src')
|
|
||||||
echohl Error | echom '[coc.nvim] build/index.js not found, please install dependencies and compile coc.nvim by: yarn install' | echohl None
|
|
||||||
else
|
|
||||||
echohl Error | echon '[coc.nvim] your coc.nvim is broken.' | echohl None
|
|
||||||
endif
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
return [node] + get(g:, 'coc_node_args', ['--no-warnings']) + [s:root.'/build/index.js']
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#jump(cmd, filepath, ...) abort
|
|
||||||
if a:cmd != 'pedit'
|
|
||||||
silent! normal! m'
|
|
||||||
endif
|
|
||||||
let path = a:filepath
|
|
||||||
if has('win32unix')
|
|
||||||
let path = substitute(a:filepath, '\v\\', '/', 'g')
|
|
||||||
endif
|
|
||||||
let file = fnamemodify(path, ":~:.")
|
|
||||||
if a:cmd ==# 'pedit'
|
|
||||||
let extra = empty(get(a:, 1, [])) ? '' : '+'.(a:1[0] + 1)
|
|
||||||
exe 'pedit '.extra.' '.fnameescape(file)
|
|
||||||
return
|
|
||||||
elseif a:cmd ==# 'drop'
|
|
||||||
let dstbuf = bufadd(path)
|
|
||||||
let binfo = getbufinfo(dstbuf)
|
|
||||||
if len(binfo) == 1 && empty(binfo[0].windows)
|
|
||||||
execute 'buffer '.dstbuf
|
|
||||||
let &buflisted = 1
|
|
||||||
else
|
|
||||||
let saved = &wildignore
|
|
||||||
set wildignore=
|
|
||||||
execute 'drop '.fnameescape(file)
|
|
||||||
execute 'set wildignore='.saved
|
|
||||||
endif
|
|
||||||
elseif a:cmd ==# 'edit' && bufloaded(file)
|
|
||||||
exe 'b '.bufnr(file)
|
|
||||||
else
|
|
||||||
call s:safer_open(a:cmd, file)
|
|
||||||
endif
|
|
||||||
if !empty(get(a:, 1, []))
|
|
||||||
let line = getline(a:1[0] + 1)
|
|
||||||
let col = coc#string#byte_index(line, a:1[1]) + 1
|
|
||||||
call cursor(a:1[0] + 1, col)
|
|
||||||
endif
|
|
||||||
if &filetype ==# ''
|
|
||||||
filetype detect
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
redraw
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:safer_open(cmd, file) abort
|
|
||||||
" How to support :pedit and :drop?
|
|
||||||
let is_supported_cmd = index(["edit", "split", "vsplit", "tabe"], a:cmd) >= 0
|
|
||||||
|
|
||||||
" Use special handling only for URI.
|
|
||||||
let looks_like_uri = match(a:file, "^.*://") >= 0
|
|
||||||
|
|
||||||
if looks_like_uri && is_supported_cmd && has('win32') && exists('*bufadd')
|
|
||||||
" Workaround a bug for Win32 paths.
|
|
||||||
"
|
|
||||||
" reference:
|
|
||||||
" - https://github.com/vim/vim/issues/541
|
|
||||||
" - https://github.com/neoclide/coc-java/issues/82
|
|
||||||
" - https://github.com/vim-jp/issues/issues/6
|
|
||||||
let buf = bufadd(a:file)
|
|
||||||
if a:cmd != 'edit'
|
|
||||||
" Open split, tab, etc. by a:cmd.
|
|
||||||
execute a:cmd
|
|
||||||
endif
|
|
||||||
" Set current buffer to the file
|
|
||||||
exe 'keepjumps buffer ' . buf
|
|
||||||
else
|
|
||||||
if a:cmd =~# 'drop'
|
|
||||||
let saved = &wildignore
|
|
||||||
set wildignore=
|
|
||||||
execute a:cmd.' '.fnameescape(a:file)
|
|
||||||
execute 'set wildignore='.saved
|
|
||||||
else
|
|
||||||
execute a:cmd.' '.fnameescape(a:file)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#variables(bufnr) abort
|
|
||||||
let info = getbufinfo(a:bufnr)
|
|
||||||
let variables = empty(info) ? {} : copy(info[0]['variables'])
|
|
||||||
for key in keys(variables)
|
|
||||||
if key !~# '\v^coc'
|
|
||||||
unlet variables[key]
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return variables
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#with_callback(method, args, cb)
|
|
||||||
function! s:Cb() closure
|
|
||||||
try
|
|
||||||
let res = call(a:method, a:args)
|
|
||||||
call a:cb(v:null, res)
|
|
||||||
catch /.*/
|
|
||||||
call a:cb(v:exception)
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
let timeout = s:is_vim ? 10 : 0
|
|
||||||
call timer_start(timeout, {-> s:Cb() })
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#timer(method, args)
|
|
||||||
call timer_start(0, { -> s:Call(a:method, a:args)})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:Call(method, args)
|
|
||||||
try
|
|
||||||
call call(a:method, a:args)
|
|
||||||
redraw
|
|
||||||
catch /.*/
|
|
||||||
return 0
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#vim_info()
|
|
||||||
return {
|
|
||||||
\ 'root': s:root,
|
|
||||||
\ 'apiversion': s:vim_api_version,
|
|
||||||
\ 'mode': mode(),
|
|
||||||
\ 'config': get(g:, 'coc_user_config', {}),
|
|
||||||
\ 'floating': has('nvim') && exists('*nvim_open_win') ? v:true : v:false,
|
|
||||||
\ 'extensionRoot': coc#util#extension_root(),
|
|
||||||
\ 'globalExtensions': get(g:, 'coc_global_extensions', []),
|
|
||||||
\ 'lines': &lines,
|
|
||||||
\ 'columns': &columns,
|
|
||||||
\ 'cmdheight': &cmdheight,
|
|
||||||
\ 'pid': coc#util#getpid(),
|
|
||||||
\ 'filetypeMap': get(g:, 'coc_filetype_map', {}),
|
|
||||||
\ 'version': coc#util#version(),
|
|
||||||
\ 'pumevent': 1,
|
|
||||||
\ 'isVim': has('nvim') ? v:false : v:true,
|
|
||||||
\ 'isCygwin': has('win32unix') ? v:true : v:false,
|
|
||||||
\ 'isMacvim': has('gui_macvim') ? v:true : v:false,
|
|
||||||
\ 'isiTerm': $TERM_PROGRAM ==# "iTerm.app",
|
|
||||||
\ 'colorscheme': get(g:, 'colors_name', ''),
|
|
||||||
\ 'workspaceFolders': get(g:, 'WorkspaceFolders', v:null),
|
|
||||||
\ 'background': &background,
|
|
||||||
\ 'runtimepath': join(globpath(&runtimepath, '', 0, 1), ','),
|
|
||||||
\ 'locationlist': get(g:,'coc_enable_locationlist', 1),
|
|
||||||
\ 'progpath': v:progpath,
|
|
||||||
\ 'guicursor': &guicursor,
|
|
||||||
\ 'pumwidth': exists('&pumwidth') ? &pumwidth : 15,
|
|
||||||
\ 'tabCount': tabpagenr('$'),
|
|
||||||
\ 'updateHighlight': has('nvim-0.5.0') || has('textprop') ? v:true : v:false,
|
|
||||||
\ 'vimCommands': get(g:, 'coc_vim_commands', []),
|
|
||||||
\ 'sign': exists('*sign_place') && exists('*sign_unplace'),
|
|
||||||
\ 'ambiguousIsNarrow': &ambiwidth ==# 'single' ? v:true : v:false,
|
|
||||||
\ 'textprop': has('textprop') ? v:true : v:false,
|
|
||||||
\ 'virtualText': has('nvim-0.5.0') || has('patch-9.0.0067') ? v:true : v:false,
|
|
||||||
\ 'dialog': 1,
|
|
||||||
\ 'semanticHighlights': coc#util#semantic_hlgroups()
|
|
||||||
\}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#all_state()
|
|
||||||
return {
|
|
||||||
\ 'bufnr': bufnr('%'),
|
|
||||||
\ 'winid': win_getid(),
|
|
||||||
\ 'bufnrs': map(getbufinfo({'bufloaded': 1}),'v:val["bufnr"]'),
|
|
||||||
\ 'winids': map(getwininfo(),'v:val["winid"]'),
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#install() abort
|
|
||||||
let yarncmd = get(g:, 'coc_install_yarn_cmd', executable('yarnpkg') ? 'yarnpkg' : 'yarn')
|
|
||||||
call coc#ui#open_terminal({
|
|
||||||
\ 'cwd': s:root,
|
|
||||||
\ 'cmd': yarncmd.' install --frozen-lockfile --ignore-engines',
|
|
||||||
\ 'autoclose': 0,
|
|
||||||
\ })
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#extension_root() abort
|
|
||||||
return coc#util#get_data_home().'/extensions'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#update_extensions(...) abort
|
|
||||||
let async = get(a:, 1, 0)
|
|
||||||
if async
|
|
||||||
call coc#rpc#notify('updateExtensions', [])
|
|
||||||
else
|
|
||||||
call coc#rpc#request('updateExtensions', [v:true])
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#install_extension(args) abort
|
|
||||||
let names = filter(copy(a:args), 'v:val !~# "^-"')
|
|
||||||
let isRequest = index(a:args, '-sync') != -1
|
|
||||||
if isRequest
|
|
||||||
call coc#rpc#request('installExtensions', names)
|
|
||||||
else
|
|
||||||
call coc#rpc#notify('installExtensions', names)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#do_autocmd(name) abort
|
|
||||||
if exists('#User#'.a:name)
|
|
||||||
exe 'doautocmd <nomodeline> User '.a:name
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#unmap(bufnr, keys) abort
|
|
||||||
if bufnr('%') == a:bufnr
|
|
||||||
for key in a:keys
|
|
||||||
exe 'silent! nunmap <buffer> '.key
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#refactor_foldlevel(lnum) abort
|
|
||||||
if a:lnum <= 2 | return 0 | endif
|
|
||||||
let line = getline(a:lnum)
|
|
||||||
if line =~# '^\%u3000\s*$' | return 0 | endif
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#refactor_fold_text(lnum) abort
|
|
||||||
let range = ''
|
|
||||||
let info = get(b:line_infos, a:lnum, [])
|
|
||||||
if !empty(info)
|
|
||||||
let range = info[0].':'.info[1]
|
|
||||||
endif
|
|
||||||
return trim(getline(a:lnum)[3:]).' '.range
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" get tabsize & expandtab option
|
|
||||||
function! coc#util#get_format_opts(bufnr) abort
|
|
||||||
let bufnr = a:bufnr && bufloaded(a:bufnr) ? a:bufnr : bufnr('%')
|
|
||||||
let tabsize = getbufvar(bufnr, '&shiftwidth')
|
|
||||||
if tabsize == 0
|
|
||||||
let tabsize = getbufvar(bufnr, '&tabstop')
|
|
||||||
endif
|
|
||||||
return {
|
|
||||||
\ 'tabsize': tabsize,
|
|
||||||
\ 'expandtab': getbufvar(bufnr, '&expandtab'),
|
|
||||||
\ 'insertFinalNewline': getbufvar(bufnr, '&eol'),
|
|
||||||
\ 'trimTrailingWhitespace': getbufvar(bufnr, 'coc_trim_trailing_whitespace', 0),
|
|
||||||
\ 'trimFinalNewlines': getbufvar(bufnr, 'coc_trim_final_newlines', 0)
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#get_editoroption(winid) abort
|
|
||||||
let info = get(getwininfo(a:winid), 0, v:null)
|
|
||||||
if empty(info) || coc#window#is_float(a:winid)
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let bufnr = info['bufnr']
|
|
||||||
let buftype = getbufvar(bufnr, '&buftype')
|
|
||||||
" avoid window for other purpose.
|
|
||||||
if buftype !=# '' && buftype !=# 'acwrite'
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let tabSize = getbufvar(bufnr, '&shiftwidth')
|
|
||||||
if tabSize == 0
|
|
||||||
let tabSize = getbufvar(bufnr, '&tabstop')
|
|
||||||
endif
|
|
||||||
return {
|
|
||||||
\ 'bufnr': bufnr,
|
|
||||||
\ 'winid': a:winid,
|
|
||||||
\ 'tabpageid': coc#util#tabnr_id(info['tabnr']),
|
|
||||||
\ 'winnr': winnr(),
|
|
||||||
\ 'visibleRanges': s:visible_ranges(a:winid),
|
|
||||||
\ 'tabSize': tabSize,
|
|
||||||
\ 'insertSpaces': getbufvar(bufnr, '&expandtab') ? v:true : v:false
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#tabnr_id(tabnr) abort
|
|
||||||
return s:is_vim ? coc#api#get_tabid(a:tabnr) : nvim_list_tabpages()[a:tabnr - 1]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#get_loaded_bufs() abort
|
|
||||||
return map(getbufinfo({'bufloaded': 1}),'v:val["bufnr"]')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#editor_infos() abort
|
|
||||||
let result = []
|
|
||||||
for info in getwininfo()
|
|
||||||
if !coc#window#is_float(info['winid'])
|
|
||||||
let bufnr = info['bufnr']
|
|
||||||
let buftype = getbufvar(bufnr, '&buftype')
|
|
||||||
if buftype !=# '' && buftype !=# 'acwrite'
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
let bufname = bufname(bufnr)
|
|
||||||
call add(result, {
|
|
||||||
\ 'winid': info['winid'],
|
|
||||||
\ 'bufnr': bufnr,
|
|
||||||
\ 'tabid': coc#util#tabnr_id(info['tabnr']),
|
|
||||||
\ 'fullpath': empty(bufname) ? '' : fnamemodify(bufname, ':p'),
|
|
||||||
\ })
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return result
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#tabpages() abort
|
|
||||||
if s:is_vim
|
|
||||||
return coc#api#exec('list_tabpages', [])
|
|
||||||
endif
|
|
||||||
return nvim_list_tabpages()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#getpid()
|
|
||||||
if !has('win32unix')
|
|
||||||
return getpid()
|
|
||||||
endif
|
|
||||||
let cmd = 'cat /proc/' . getpid() . '/winpid'
|
|
||||||
return substitute(system(cmd), '\v\n', '', 'gi')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Get indentkeys for indent on TextChangedP, consider = for word indent only.
|
|
||||||
function! coc#util#get_indentkeys() abort
|
|
||||||
if empty(&indentexpr)
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
if &indentkeys !~# '='
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
return &indentkeys
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#get_bufoptions(bufnr, max) abort
|
|
||||||
if !bufloaded(a:bufnr) | return v:null | endif
|
|
||||||
let bufname = bufname(a:bufnr)
|
|
||||||
let buftype = getbufvar(a:bufnr, '&buftype')
|
|
||||||
let size = coc#util#bufsize(a:bufnr)
|
|
||||||
let lines = v:null
|
|
||||||
if getbufvar(a:bufnr, 'coc_enabled', 1)
|
|
||||||
\ && (buftype == '' || buftype == 'acwrite' || getbufvar(a:bufnr, 'coc_force_attach', 0))
|
|
||||||
\ && size != -2
|
|
||||||
\ && size < a:max
|
|
||||||
let lines = getbufline(a:bufnr, 1, '$')
|
|
||||||
endif
|
|
||||||
return {
|
|
||||||
\ 'bufnr': a:bufnr,
|
|
||||||
\ 'size': size,
|
|
||||||
\ 'lines': lines,
|
|
||||||
\ 'winid': bufwinid(a:bufnr),
|
|
||||||
\ 'bufname': bufname,
|
|
||||||
\ 'buftype': buftype,
|
|
||||||
\ 'previewwindow': v:false,
|
|
||||||
\ 'eol': getbufvar(a:bufnr, '&eol'),
|
|
||||||
\ 'variables': coc#util#variables(a:bufnr),
|
|
||||||
\ 'filetype': getbufvar(a:bufnr, '&filetype'),
|
|
||||||
\ 'lisp': getbufvar(a:bufnr, '&lisp'),
|
|
||||||
\ 'iskeyword': getbufvar(a:bufnr, '&iskeyword'),
|
|
||||||
\ 'changedtick': getbufvar(a:bufnr, 'changedtick'),
|
|
||||||
\ 'fullpath': empty(bufname) ? '' : fnamemodify(bufname, ':p'),
|
|
||||||
\}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#bufsize(bufnr) abort
|
|
||||||
if bufnr('%') == a:bufnr
|
|
||||||
return line2byte(line("$") + 1)
|
|
||||||
endif
|
|
||||||
let bufname = bufname(a:bufnr)
|
|
||||||
if !getbufvar(a:bufnr, '&modified') && filereadable(bufname)
|
|
||||||
return getfsize(bufname)
|
|
||||||
endif
|
|
||||||
return strlen(join(getbufline(a:bufnr, 1, '$'), '\n'))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#get_config_home()
|
|
||||||
if !empty(get(g:, 'coc_config_home', ''))
|
|
||||||
return resolve(expand(g:coc_config_home))
|
|
||||||
endif
|
|
||||||
if exists('$VIMCONFIG')
|
|
||||||
return resolve($VIMCONFIG)
|
|
||||||
endif
|
|
||||||
if has('nvim')
|
|
||||||
if exists('$XDG_CONFIG_HOME')
|
|
||||||
return resolve($XDG_CONFIG_HOME."/nvim")
|
|
||||||
endif
|
|
||||||
if s:is_win
|
|
||||||
return resolve($HOME.'/AppData/Local/nvim')
|
|
||||||
endif
|
|
||||||
return resolve($HOME.'/.config/nvim')
|
|
||||||
else
|
|
||||||
if s:is_win
|
|
||||||
return resolve($HOME."/vimfiles")
|
|
||||||
endif
|
|
||||||
return resolve($HOME.'/.vim')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#get_data_home()
|
|
||||||
if get(g:, 'coc_node_env', '') ==# 'test'
|
|
||||||
return $COC_DATA_HOME
|
|
||||||
endif
|
|
||||||
if !empty(get(g:, 'coc_data_home', ''))
|
|
||||||
let dir = resolve(expand(g:coc_data_home))
|
|
||||||
else
|
|
||||||
if exists('$XDG_CONFIG_HOME')
|
|
||||||
let dir = resolve($XDG_CONFIG_HOME."/coc")
|
|
||||||
else
|
|
||||||
if s:is_win
|
|
||||||
let dir = resolve(expand('~/AppData/Local/coc'))
|
|
||||||
else
|
|
||||||
let dir = resolve(expand('~/.config/coc'))
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if !isdirectory(dir)
|
|
||||||
call coc#notify#create(['creating coc.nvim data directory: '.dir], {
|
|
||||||
\ 'borderhighlight': 'CocInfoSign',
|
|
||||||
\ 'timeout': 5000,
|
|
||||||
\ 'kind': 'info',
|
|
||||||
\ })
|
|
||||||
call mkdir(dir, "p", 0755)
|
|
||||||
endif
|
|
||||||
return dir
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#util#get_complete_option()
|
|
||||||
let pos = getcurpos()
|
|
||||||
let line = getline(pos[1])
|
|
||||||
let input = matchstr(strpart(line, 0, pos[2] - 1), '\k*$')
|
|
||||||
let col = pos[2] - strlen(input)
|
|
||||||
let position = {
|
|
||||||
\ 'line': line('.')-1,
|
|
||||||
\ 'character': coc#string#character_length(strpart(getline('.'), 0, col('.') - 1))
|
|
||||||
\ }
|
|
||||||
let word = matchstr(strpart(line, col - 1), '^\k\+')
|
|
||||||
let followWord = len(word) > 0 ? strcharpart(word, strchars(input)) : ''
|
|
||||||
return {
|
|
||||||
\ 'word': word,
|
|
||||||
\ 'followWord': followWord,
|
|
||||||
\ 'position': position,
|
|
||||||
\ 'input': empty(input) ? '' : input,
|
|
||||||
\ 'line': line,
|
|
||||||
\ 'filetype': &filetype,
|
|
||||||
\ 'filepath': expand('%:p'),
|
|
||||||
\ 'bufnr': bufnr('%'),
|
|
||||||
\ 'linenr': pos[1],
|
|
||||||
\ 'colnr' : pos[2],
|
|
||||||
\ 'col': col - 1,
|
|
||||||
\ 'changedtick': b:changedtick,
|
|
||||||
\}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" used by vim
|
|
||||||
function! coc#util#get_buf_lines(bufnr, changedtick)
|
|
||||||
if !bufloaded(a:bufnr)
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let changedtick = getbufvar(a:bufnr, 'changedtick')
|
|
||||||
if changedtick == a:changedtick
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
return {
|
|
||||||
\ 'lines': getbufline(a:bufnr, 1, '$'),
|
|
||||||
\ 'changedtick': getbufvar(a:bufnr, 'changedtick')
|
|
||||||
\ }
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" used for TextChangedI with InsertCharPre
|
|
||||||
function! coc#util#get_changeinfo(bufnr)
|
|
||||||
if bufnr('%') == a:bufnr
|
|
||||||
return {
|
|
||||||
\ 'lnum': line('.'),
|
|
||||||
\ 'line': getline('.'),
|
|
||||||
\ 'changedtick': b:changedtick,
|
|
||||||
\}
|
|
||||||
endif
|
|
||||||
let winid = bufwinid(a:bufnr)
|
|
||||||
if winid != -1
|
|
||||||
let ref = {}
|
|
||||||
call win_execute(winid, 'let ref = {"lnum": line("."), "line": getline("."), "changedtick": b:changedtick}')
|
|
||||||
return ref
|
|
||||||
endif
|
|
||||||
return v:null
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Get the valid position from line, character of current buffer
|
|
||||||
function! coc#util#valid_position(line, character) abort
|
|
||||||
let total = line('$') - 1
|
|
||||||
if a:line > total
|
|
||||||
return [total, 0]
|
|
||||||
endif
|
|
||||||
let max = max([0, coc#string#character_length(getline(a:line + 1)) - (mode() ==# 'n' ? 1 : 0)])
|
|
||||||
return a:character > max ? [a:line, max] : [a:line, a:character]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:visible_ranges(winid) abort
|
|
||||||
let info = getwininfo(a:winid)[0]
|
|
||||||
let res = []
|
|
||||||
if !has_key(info, 'topline') || !has_key(info, 'botline')
|
|
||||||
return res
|
|
||||||
endif
|
|
||||||
let begin = 0
|
|
||||||
let curr = info['topline']
|
|
||||||
let max = info['botline']
|
|
||||||
if win_getid() != a:winid
|
|
||||||
return [[curr, max]]
|
|
||||||
endif
|
|
||||||
while curr <= max
|
|
||||||
let closedend = foldclosedend(curr)
|
|
||||||
if closedend == -1
|
|
||||||
let begin = begin == 0 ? curr : begin
|
|
||||||
if curr == max
|
|
||||||
call add(res, [begin, curr])
|
|
||||||
endif
|
|
||||||
let curr = curr + 1
|
|
||||||
else
|
|
||||||
if begin != 0
|
|
||||||
call add(res, [begin, curr - 1])
|
|
||||||
let begin = closedend + 1
|
|
||||||
endif
|
|
||||||
let curr = closedend + 1
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
return res
|
|
||||||
endfunction
|
|
|
@ -1,91 +0,0 @@
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:virtual_text_support = has('nvim-0.5.0') || has('patch-9.0.0067')
|
|
||||||
let s:text_options = has('patch-9.0.0121') || has('nvim-0.6.0')
|
|
||||||
let s:vim_above = has('patch-9.0.0438')
|
|
||||||
|
|
||||||
" This function is called by buffer.setVirtualText
|
|
||||||
" opts.hl_mode default to 'combine'.
|
|
||||||
" opts.col vim only, no support on neovim, default to 0.
|
|
||||||
" opts.virt_text_win_col neovim only.
|
|
||||||
" opts.text_align could be 'after' 'right' 'below' 'above', converted on neovim.
|
|
||||||
" opts.text_wrap could be 'wrap' and 'truncate', vim9 only.
|
|
||||||
" opts.indent add indent when using 'above' and 'below' as text_align
|
|
||||||
function! coc#vtext#add(bufnr, src_id, line, blocks, opts) abort
|
|
||||||
if !s:virtual_text_support
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let align = get(a:opts, 'text_align', 'after')
|
|
||||||
let indent = ''
|
|
||||||
if get(a:opts, 'indent', 0)
|
|
||||||
let indent = matchstr(getline(a:line + 1), '^\s\+')
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
let column = get(a:opts, 'col', 0)
|
|
||||||
if !has_key(a:opts, 'col') && align ==# 'after'
|
|
||||||
" add a whitespace, same as neovim.
|
|
||||||
let indent = ' '
|
|
||||||
endif
|
|
||||||
let blocks = a:blocks
|
|
||||||
if !empty(a:blocks) && (align ==# 'above' || align ==# 'below')
|
|
||||||
" only first highlight can be used
|
|
||||||
let hl = a:blocks[0][1]
|
|
||||||
let text = join(map(copy(a:blocks), "v:val[0]"), '')
|
|
||||||
let blocks = [[text, hl]]
|
|
||||||
let column = 0
|
|
||||||
endif
|
|
||||||
let first = 1
|
|
||||||
let base = s:get_option_vim(align, column, get(a:opts, 'text_wrap', 'truncate'))
|
|
||||||
for [text, hl] in blocks
|
|
||||||
let type = coc#api#create_type(a:src_id, hl, a:opts)
|
|
||||||
let opts = extend({ 'text': text, 'type': type }, base)
|
|
||||||
if first && !empty(indent)
|
|
||||||
let opts['text'] = indent . text
|
|
||||||
endif
|
|
||||||
call prop_add(a:line + 1, column, opts)
|
|
||||||
let first = 0
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
let opts = { 'hl_mode': get(a:opts, 'hl_mode', 'combine') }
|
|
||||||
if s:text_options
|
|
||||||
if align ==# 'above' || align ==# 'below'
|
|
||||||
let blocks = empty(indent) ? a:blocks : [[indent, 'Normal']] + a:blocks
|
|
||||||
let opts['virt_lines'] = [blocks]
|
|
||||||
if align ==# 'above'
|
|
||||||
let opts['virt_lines_above'] = v:true
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let opts['virt_text'] = a:blocks
|
|
||||||
if align ==# 'right'
|
|
||||||
let opts['virt_text_pos'] = 'right_align'
|
|
||||||
else
|
|
||||||
if type(get(a:opts, 'virt_text_win_col', v:null)) == 0
|
|
||||||
let opts['virt_text_win_col'] = a:opts['virt_text_win_col']
|
|
||||||
let opts['virt_text_pos'] = 'overlay'
|
|
||||||
else
|
|
||||||
" default to 'after'
|
|
||||||
let opts['virt_text_pos'] = 'eol'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if has('nvim-0.5.1') && type(get(a:opts, 'virt_text_win_col', v:null)) == 0
|
|
||||||
let opts['virt_text_win_col'] = a:opts['virt_text_win_col']
|
|
||||||
let opts['virt_text_pos'] = 'overlay'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call nvim_buf_set_extmark(a:bufnr, a:src_id, a:line, 0, opts)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_option_vim(align, column, wrap) abort
|
|
||||||
let opts = {}
|
|
||||||
if s:text_options && a:column == 0
|
|
||||||
if a:align ==# 'top' && !s:vim_above
|
|
||||||
let opts['text_align'] = 'right'
|
|
||||||
else
|
|
||||||
let opts['text_align'] = a:align
|
|
||||||
endif
|
|
||||||
let opts['text_wrap'] = a:wrap
|
|
||||||
endif
|
|
||||||
return opts
|
|
||||||
endfunction
|
|
|
@ -1,210 +0,0 @@
|
||||||
let g:coc_max_treeview_width = get(g:, 'coc_max_treeview_width', 40)
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
|
|
||||||
" Get tabpagenr of winid, return -1 if window doesn't exist
|
|
||||||
function! coc#window#tabnr(winid) abort
|
|
||||||
" getwininfo not work with popup on vim
|
|
||||||
if exists('*win_execute')
|
|
||||||
let ref = {}
|
|
||||||
call win_execute(a:winid, 'let ref["out"] = tabpagenr()')
|
|
||||||
return get(ref, 'out', -1)
|
|
||||||
endif
|
|
||||||
let info = getwininfo(a:winid)
|
|
||||||
return empty(info) ? -1 : info[0]['tabnr']
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" (1, 0) based line, column
|
|
||||||
function! coc#window#get_cursor(winid) abort
|
|
||||||
if exists('*nvim_win_get_cursor')
|
|
||||||
return nvim_win_get_cursor(a:winid)
|
|
||||||
endif
|
|
||||||
if has('patch-8.2.1727')
|
|
||||||
let pos = getcurpos(a:winid)
|
|
||||||
return [pos[1], pos[2] - 1]
|
|
||||||
endif
|
|
||||||
return coc#api#exec('win_get_cursor', [a:winid])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Check if winid visible on current tabpage
|
|
||||||
function! coc#window#visible(winid) abort
|
|
||||||
if s:is_vim
|
|
||||||
if coc#window#tabnr(a:winid) != tabpagenr()
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
" Check possible hidden popup
|
|
||||||
try
|
|
||||||
return get(popup_getpos(a:winid), 'visible', 0) == 1
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E993/
|
|
||||||
return 1
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
if !nvim_win_is_valid(a:winid)
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
return coc#window#tabnr(a:winid) == tabpagenr()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" winid is popup and shown
|
|
||||||
function! s:visible_popup(winid) abort
|
|
||||||
let popups = popup_list()
|
|
||||||
if index(popups, a:winid) != -1
|
|
||||||
return get(popup_getpos(a:winid), 'visible', 0) == 1
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Return v:null when name or window doesn't exist,
|
|
||||||
" 'getwinvar' only works on window of current tab
|
|
||||||
function! coc#window#get_var(winid, name, ...) abort
|
|
||||||
if !s:is_vim
|
|
||||||
try
|
|
||||||
if a:name =~# '^&'
|
|
||||||
return nvim_win_get_option(a:winid, a:name[1:])
|
|
||||||
else
|
|
||||||
return nvim_win_get_var(a:winid, a:name)
|
|
||||||
endif
|
|
||||||
catch /E5555/
|
|
||||||
return get(a:, 1, v:null)
|
|
||||||
endtry
|
|
||||||
else
|
|
||||||
try
|
|
||||||
return coc#api#exec('win_get_var', [a:winid, a:name, get(a:, 1, v:null)])
|
|
||||||
catch /Invalid window id/
|
|
||||||
return get(a:, 1, v:null)
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Not throw like setwinvar
|
|
||||||
function! coc#window#set_var(winid, name, value) abort
|
|
||||||
try
|
|
||||||
if !s:is_vim
|
|
||||||
if a:name =~# '^&'
|
|
||||||
call nvim_win_set_option(a:winid, a:name[1:], a:value)
|
|
||||||
else
|
|
||||||
call nvim_win_set_var(a:winid, a:name, a:value)
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call coc#api#exec('win_set_var', [a:winid, a:name, a:value])
|
|
||||||
endif
|
|
||||||
catch /Invalid window id/
|
|
||||||
" ignore
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#window#is_float(winid) abort
|
|
||||||
if s:is_vim
|
|
||||||
try
|
|
||||||
return !empty(popup_getpos(a:winid))
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E993/
|
|
||||||
return 0
|
|
||||||
endtry
|
|
||||||
else
|
|
||||||
let config = nvim_win_get_config(a:winid)
|
|
||||||
return !empty(config) && !empty(get(config, 'relative', ''))
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Reset current lnum & topline of window
|
|
||||||
function! coc#window#restview(winid, lnum, topline) abort
|
|
||||||
if empty(getwininfo(a:winid))
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if s:is_vim && s:visible_popup(a:winid)
|
|
||||||
call popup_setoptions(a:winid, {'firstline': a:topline})
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call coc#compat#execute(a:winid, ['noa call winrestview({"lnum":'.a:lnum.',"topline":'.a:topline.'})'])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#window#set_height(winid, height) abort
|
|
||||||
if empty(getwininfo(a:winid))
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if exists('*nvim_win_set_height')
|
|
||||||
call nvim_win_set_height(a:winid, a:height)
|
|
||||||
else
|
|
||||||
call coc#compat#execute(a:winid, 'noa resize '.a:height, 'silent')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#window#adjust_width(winid) abort
|
|
||||||
let bufnr = winbufnr(a:winid)
|
|
||||||
if bufloaded(bufnr)
|
|
||||||
let maxwidth = 0
|
|
||||||
let lines = getbufline(bufnr, 1, '$')
|
|
||||||
if len(lines) > 2
|
|
||||||
call coc#compat#execute(a:winid, 'setl nowrap')
|
|
||||||
for line in lines
|
|
||||||
let w = strwidth(line)
|
|
||||||
if w > maxwidth
|
|
||||||
let maxwidth = w
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
if maxwidth > winwidth(a:winid)
|
|
||||||
call coc#compat#execute(a:winid, 'vertical resize '.min([maxwidth, g:coc_max_treeview_width]))
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Get single window by window variable, current tab only
|
|
||||||
function! coc#window#find(key, val) abort
|
|
||||||
for i in range(1, winnr('$'))
|
|
||||||
let res = getwinvar(i, a:key)
|
|
||||||
if res == a:val
|
|
||||||
return win_getid(i)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return -1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Visible buffer numbers
|
|
||||||
function! coc#window#bufnrs() abort
|
|
||||||
let winids = []
|
|
||||||
if exists('*nvim_list_wins')
|
|
||||||
let winids = nvim_list_wins()
|
|
||||||
else
|
|
||||||
let winids = map(getwininfo(), 'v:val["winid"]')
|
|
||||||
endif
|
|
||||||
return uniq(map(winids, 'winbufnr(v:val)'))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Avoid errors
|
|
||||||
function! coc#window#close(winid) abort
|
|
||||||
if empty(a:winid) || a:winid == -1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if coc#float#valid(a:winid)
|
|
||||||
call coc#float#close(a:winid)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if exists('*nvim_win_is_valid') && exists('*nvim_win_close')
|
|
||||||
if nvim_win_is_valid(a:winid)
|
|
||||||
call nvim_win_close(a:winid, 1)
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call coc#compat#execute(a:winid, 'noa close!', 'silent!')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#window#visible_range(bufnr) abort
|
|
||||||
let winid = bufwinid(a:bufnr)
|
|
||||||
if winid == -1
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
let info = getwininfo(winid)[0]
|
|
||||||
return [info['topline'], info['botline']]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#window#visible_ranges(bufnr) abort
|
|
||||||
let wins = gettabinfo(tabpagenr())[0]['windows']
|
|
||||||
let res = []
|
|
||||||
for id in wins
|
|
||||||
let info = getwininfo(id)[0]
|
|
||||||
if info['bufnr'] == a:bufnr
|
|
||||||
call add(res, [info['topline'], info['botline']])
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return res
|
|
||||||
endfunction
|
|
|
@ -1,100 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
let s:root = expand('<sfile>:h:h:h')
|
|
||||||
|
|
||||||
function! s:checkVim(test, name, patchlevel) abort
|
|
||||||
if a:test
|
|
||||||
if !has(a:patchlevel)
|
|
||||||
call health#report_error(a:name . ' version not satisfied, ' . a:patchlevel . ' and above required')
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
call health#report_ok(a:name . ' version satisfied')
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:checkEnvironment() abort
|
|
||||||
let valid
|
|
||||||
\ = s:checkVim(has('nvim'), 'nvim', 'nvim-0.4.0')
|
|
||||||
\ + s:checkVim(!has('nvim'), 'vim', 'patch-8.1.1719')
|
|
||||||
let node = get(g:, 'coc_node_path', $COC_NODE_PATH == '' ? 'node' : $COC_NODE_PATH)
|
|
||||||
if !executable(node)
|
|
||||||
let valid = 0
|
|
||||||
call health#report_error('Executable node.js not found, install node.js from http://nodejs.org/')
|
|
||||||
endif
|
|
||||||
let output = system(node . ' --version')
|
|
||||||
if v:shell_error && output !=# ""
|
|
||||||
let valid = 0
|
|
||||||
call health#report_error(output)
|
|
||||||
endif
|
|
||||||
let ms = matchlist(output, 'v\(\d\+\).\(\d\+\).\(\d\+\)')
|
|
||||||
if empty(ms)
|
|
||||||
let valid = 0
|
|
||||||
call health#report_error('Unable to detect version of node, make sure your node executable is http://nodejs.org/')
|
|
||||||
elseif str2nr(ms[1]) < 14 || (str2nr(ms[1]) == 14 && str2nr(ms[2]) < 14)
|
|
||||||
let valid = 0
|
|
||||||
call health#report_warn('Node.js version '.trim(output).' < 14.14.0, please upgrade node.js')
|
|
||||||
endif
|
|
||||||
if valid
|
|
||||||
call health#report_ok('Environment check passed')
|
|
||||||
endif
|
|
||||||
if has('pythonx')
|
|
||||||
try
|
|
||||||
silent pyx print("")
|
|
||||||
catch /.*/
|
|
||||||
call health#report_warn('pyx command not work, some extensions may fail to work, checkout ":h pythonx"')
|
|
||||||
if has('nvim')
|
|
||||||
call health#report_warn('Install pynvim by command: pip install pynvim --upgrade')
|
|
||||||
endif
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
return valid
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:checkCommand()
|
|
||||||
let file = s:root.'/build/index.js'
|
|
||||||
if filereadable(file)
|
|
||||||
call health#report_ok('Javascript bundle build/index.js found')
|
|
||||||
else
|
|
||||||
call health#report_error('Javascript entry not found, please compile coc.nvim by esbuild.')
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:checkAutocmd()
|
|
||||||
let cmds = ['CursorHold', 'CursorHoldI', 'CursorMovedI', 'InsertCharPre', 'TextChangedI']
|
|
||||||
for cmd in cmds
|
|
||||||
let lines = split(execute('verbose autocmd '.cmd), '\n')
|
|
||||||
let n = 0
|
|
||||||
for line in lines
|
|
||||||
if line =~# 'CocAction(' && n < len(lines) - 1
|
|
||||||
let next = lines[n + 1]
|
|
||||||
let ms = matchlist(next, 'Last set from \(.*\)')
|
|
||||||
if !empty(ms)
|
|
||||||
call health#report_warn('Use CocActionAsync to replace CocAction for better performance on '.cmd)
|
|
||||||
call health#report_warn('Checkout the file '.ms[1])
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let n = n + 1
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:checkInitialize() abort
|
|
||||||
if coc#client#is_running('coc')
|
|
||||||
call health#report_ok('Service started')
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
call health#report_error('service could not be initialized', [
|
|
||||||
\ 'Use command ":messages" to get error messages.',
|
|
||||||
\ 'Open a issue at https://github.com/neoclide/coc.nvim/issues for feedback.'
|
|
||||||
\])
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! health#coc#check() abort
|
|
||||||
call s:checkEnvironment()
|
|
||||||
call s:checkCommand()
|
|
||||||
call s:checkInitialize()
|
|
||||||
call s:checkAutocmd()
|
|
||||||
endfunction
|
|
Binary file not shown.
|
@ -1,108 +0,0 @@
|
||||||
/*
|
|
||||||
* Used for prompt popup on vim
|
|
||||||
*/
|
|
||||||
const readline = require("readline")
|
|
||||||
const rl = readline.createInterface({
|
|
||||||
input: process.stdin,
|
|
||||||
output: process.stdout,
|
|
||||||
terminal: true,
|
|
||||||
escapeCodeTimeout: 0,
|
|
||||||
prompt: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
let value = process.argv[2]
|
|
||||||
let placeholder = process.argv[3]
|
|
||||||
let clear = false
|
|
||||||
if (value) {
|
|
||||||
rl.write(value)
|
|
||||||
} else if (placeholder) {
|
|
||||||
clear = true
|
|
||||||
rl.write('\x1B[90m' + placeholder + '\x1B[39m')
|
|
||||||
rl.write('', {ctrl: true, name: 'a'})
|
|
||||||
}
|
|
||||||
rl.on('line', input => {
|
|
||||||
send(['confirm', clear ? '' : input])
|
|
||||||
process.exit()
|
|
||||||
})
|
|
||||||
|
|
||||||
let original_ttyWrite = rl._ttyWrite
|
|
||||||
rl._ttyWrite = function (code, key) {
|
|
||||||
if (key.name === 'enter') {
|
|
||||||
send(['send', '<C-j>'])
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
original_ttyWrite.apply(rl, arguments)
|
|
||||||
if (clear && rl.line.includes('\x1B')) {
|
|
||||||
clear = false
|
|
||||||
rl.write('', {ctrl: true, name: 'k'})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
send(['change', rl.line])
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSequences(str) {
|
|
||||||
return '\033]51;' + str + '\x07'
|
|
||||||
}
|
|
||||||
|
|
||||||
function send(args) {
|
|
||||||
process.stdout.write(createSequences(JSON.stringify(['call', 'CocPopupCallback', args])))
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdin.on('keypress', (e, key) => {
|
|
||||||
if (key) {
|
|
||||||
let k = getKey(key)
|
|
||||||
if (k == '<bs>') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (k == '<esc>') {
|
|
||||||
send(['exit', ''])
|
|
||||||
process.exit()
|
|
||||||
}
|
|
||||||
if (k) {
|
|
||||||
send(['send', k])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function getKey(key) {
|
|
||||||
if (key.ctrl === true) {
|
|
||||||
if (key.name == 'n') {
|
|
||||||
return '<C-n>'
|
|
||||||
}
|
|
||||||
if (key.name == 'p') {
|
|
||||||
return '<C-p>'
|
|
||||||
}
|
|
||||||
if (key.name == 'j') {
|
|
||||||
return '<C-j>'
|
|
||||||
}
|
|
||||||
if (key.name == 'k') {
|
|
||||||
return '<C-k>'
|
|
||||||
}
|
|
||||||
if (key.name == 'f') {
|
|
||||||
return '<C-f>'
|
|
||||||
}
|
|
||||||
if (key.name == 'b') {
|
|
||||||
return '<C-b>'
|
|
||||||
}
|
|
||||||
if (key.sequence == '\x00') {
|
|
||||||
return '<C-@>'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (key.sequence == '\u001b') {
|
|
||||||
return '<esc>'
|
|
||||||
}
|
|
||||||
if (key.sequence == '\r') {
|
|
||||||
return '<cr>'
|
|
||||||
}
|
|
||||||
if (key.sequence == '\t') {
|
|
||||||
return key.shift ? '<s-tab>' : '<tab>'
|
|
||||||
}
|
|
||||||
if (key.name == 'up') {
|
|
||||||
return '<up>'
|
|
||||||
}
|
|
||||||
if (key.name == 'down') {
|
|
||||||
return '<down>'
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
}
|
|
Binary file not shown.
|
@ -1,12 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
terminateTree() {
|
|
||||||
for cpid in $(pgrep -P $1); do
|
|
||||||
terminateTree $cpid
|
|
||||||
done
|
|
||||||
kill -9 $1 > /dev/null 2>&1
|
|
||||||
}
|
|
||||||
|
|
||||||
for pid in $*; do
|
|
||||||
terminateTree $pid
|
|
||||||
done
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,414 +0,0 @@
|
||||||
*coc-api.txt* NodeJS client for Vim & Neovim.
|
|
||||||
|
|
||||||
CONTENTS
|
|
||||||
|
|
||||||
Vim sources |coc-api-vim-source|
|
|
||||||
Extension introduction |coc-api-intro|
|
|
||||||
Extension package json |coc-api-json|
|
|
||||||
Single file extensions |coc-api-single|
|
|
||||||
Create custom Extensions |coc-api-extension|
|
|
||||||
Debug extensions |coc-api-debug|
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
|
|
||||||
This is the guide for extend coc.nvim by create vim completion sources and
|
|
||||||
coc.nvim extensions.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
VIM SOURCES *coc-api-vim-source*
|
|
||||||
|
|
||||||
During initialization, coc.nvim searches vim's |runtimepath| for file pattern
|
|
||||||
`autoload/coc/source/${name}.vim`, matched files would be loaded as vim
|
|
||||||
completion sources.
|
|
||||||
|
|
||||||
Note: LSP completion features like `TextEdit`, `additionalTextEdits`,
|
|
||||||
`command` are not supported by vim sources, use the NodeJS API
|
|
||||||
`languages.registerCompletionItemProvider` for LSP completion.
|
|
||||||
|
|
||||||
For example, create a file `autoload/coc/source/email.vim` inside your plugin
|
|
||||||
folder. With code:
|
|
||||||
>
|
|
||||||
" vim source for emails
|
|
||||||
function! coc#source#email#init() abort
|
|
||||||
return {
|
|
||||||
\ 'priority': 9,
|
|
||||||
\ 'shortcut': 'Email',
|
|
||||||
\ 'triggerCharacters': ['@']
|
|
||||||
\}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! coc#source#email#complete(option, cb) abort
|
|
||||||
let items = ['foo@gmail.com', 'bar@yahoo.com']
|
|
||||||
call a:cb(items)
|
|
||||||
endfunction
|
|
||||||
<
|
|
||||||
`init` and `complete` are required functions for vim sources, error message
|
|
||||||
will be shown when not exists.
|
|
||||||
|
|
||||||
Source option:~
|
|
||||||
|
|
||||||
The source option object is returned by `coc#source#{name}#init`
|
|
||||||
function, available properties:
|
|
||||||
|
|
||||||
• shortcut: The shortcut characters shown in popup menu, first three
|
|
||||||
characters from the source name would be used when not exists.
|
|
||||||
• priority: The priority of source, default to `9`.
|
|
||||||
• filetypes: Array of filetype names this source should be triggered
|
|
||||||
by. Available for all filetypes when not exists.
|
|
||||||
• firstMatch: When is truthy value, only the completion item that has the
|
|
||||||
first letter matching the user input will be shown.
|
|
||||||
• triggerCharacters: Trigger characters for this source, default to `[]`.
|
|
||||||
• triggerOnly: The source should only be triggered by trigger characters,
|
|
||||||
when trigger characters is false or empty, the source would only be
|
|
||||||
triggered by api |coc#start()|.
|
|
||||||
• isSnippet: All complete items returned by `complete` are snippets,
|
|
||||||
which would have snippet indicator text added to the label in popup
|
|
||||||
menu. The "isSnippet" property of completion item override this
|
|
||||||
option.
|
|
||||||
|
|
||||||
All options are optional.
|
|
||||||
|
|
||||||
Source configurations:~
|
|
||||||
|
|
||||||
Vim sources register |coc-configuration| for allow the user to customize the
|
|
||||||
source behavior.
|
|
||||||
|
|
||||||
• `coc.source.${name}.enable` Enable the source, default to `true`.
|
|
||||||
• `coc.source.${name}.disableSyntaxes` Disabled syntax names when trigger
|
|
||||||
completion.
|
|
||||||
• `coc.source.${name}.firstMatch` Default to "firstMatch" of source option.
|
|
||||||
• `coc.source.${name}.priority` Default to "priority" of source option.
|
|
||||||
• `coc.source.${name}.shortcut` Default to "shortcut" of source option.
|
|
||||||
• `coc.source.${name}.filetypes` Default to "filetypes" of source option.
|
|
||||||
|
|
||||||
Complete function:~
|
|
||||||
|
|
||||||
The complete function is called with complete option as the first argument
|
|
||||||
and a callback function as the second argument, the callback function should
|
|
||||||
be called with list of complete item or `v:null` synchronously or
|
|
||||||
asynchronously.
|
|
||||||
|
|
||||||
Note: synchronously compute complete items blocks vim's operation.
|
|
||||||
Note: Error during completion is not thrown, use |:CocOpenLog| to check the
|
|
||||||
error log.
|
|
||||||
|
|
||||||
Complete option have following properties:
|
|
||||||
|
|
||||||
• bufnr: Current buffer number.
|
|
||||||
• line: Content line when trigger completion.
|
|
||||||
• col: Start col of completion, start col of the keywords before cursor by
|
|
||||||
default, 0 based.
|
|
||||||
• input: Input text between start col and curosr col.
|
|
||||||
• filetype: Filetype of current buffer.
|
|
||||||
• filepath: Fullpath of current buffer.
|
|
||||||
• changedtick: b:changedtick value when trigger completion.
|
|
||||||
• triggerCharacter: The character which trigger the completion, could be
|
|
||||||
empty string.
|
|
||||||
• colnr: Cursor col when trigger completion, 1 based.
|
|
||||||
• linenr: Line number of curosr, 1 based.
|
|
||||||
|
|
||||||
Complete items extends vim's |complete-items| with the following properties:
|
|
||||||
|
|
||||||
• deprecated: The complete item would be rendered with strike through
|
|
||||||
highlight when truthy.
|
|
||||||
• labelDetails: Additional details for a completion item label, which have
|
|
||||||
optional `detail` and/or `description` text.
|
|
||||||
• sortText: A string that should be used when comparing this item with other
|
|
||||||
items, word is used when not exists.
|
|
||||||
• filterText: A string that should be used when filtering a set of
|
|
||||||
complete items, word is used when not exists.
|
|
||||||
• insertText: The text to insert, could be snippet text, word is used when
|
|
||||||
not exists.
|
|
||||||
• isSnippet: The text to insert is snippet when is truthy value, when
|
|
||||||
truthy and `on_complete` not provided by vim source, the `insertText` is
|
|
||||||
expanded as textmate snippet when confirm completion.
|
|
||||||
• documentation: Array of `Documentation`, which provide `filetype` and
|
|
||||||
`content` text to be displayed in preview window.
|
|
||||||
|
|
||||||
Only the "word" property is mandatory for complete items.
|
|
||||||
|
|
||||||
Optional functions:~
|
|
||||||
|
|
||||||
The vim source could provide some optional functions which would be invoked
|
|
||||||
by coc.nvim:
|
|
||||||
|
|
||||||
• `coc#source#{name}#get_startcol(option)` Used to alter the start col of
|
|
||||||
completion, the returned col must <= current curosr col.
|
|
||||||
• `coc#source#{name}#on_complete(item)` Called with selected complete item
|
|
||||||
when user confirm the completion by |coc#pum#confirm()| or
|
|
||||||
|coc#_select_confirm()|. Normally used for apply nesessary edits to the
|
|
||||||
buffer.
|
|
||||||
• `coc#source#{name}#on_enter(option)` Called on |BufEnter| with option
|
|
||||||
contains:
|
|
||||||
• bufnr: The buffer number.
|
|
||||||
• uri: The uri text of buffer.
|
|
||||||
• languageId: The mapped filetype of buffer, see |coc-document-filetype|.
|
|
||||||
• `coc#source#{name}#refresh()` Called when the user trigger refresh action
|
|
||||||
for the source.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
EXTENSION INTRODUCTION *coc-api-intro*
|
|
||||||
|
|
||||||
Every extension of coc.nvim has a JavaScript entry file, that file is loaded
|
|
||||||
by NodeJS API `vm.runInContext` with an identical global context (like iframe
|
|
||||||
in browser).
|
|
||||||
|
|
||||||
The JavaScript entry file should be a CommonJS module with `activate` method
|
|
||||||
exported, and `require('coc.nvim')` can be used to access modules exported by
|
|
||||||
coc.nvim, for example:
|
|
||||||
>
|
|
||||||
const {window} = require('coc.nvim')
|
|
||||||
exports.activate = async context => {
|
|
||||||
window.showInformationMessage('extension activated')
|
|
||||||
}
|
|
||||||
<
|
|
||||||
When `exports.deactivate` is exported from the JavaScript entry file as a
|
|
||||||
function, it would be called on extension deactivate.
|
|
||||||
|
|
||||||
Limitation of extension context:~
|
|
||||||
|
|
||||||
Some methods/properties provided by NodeJS can't be used inside extension
|
|
||||||
context, including:
|
|
||||||
|
|
||||||
• `process.reallyExit()`
|
|
||||||
• `process.abort()`
|
|
||||||
• `process.setuid()`
|
|
||||||
• `process.setgid()`
|
|
||||||
• `process.setgroups()`
|
|
||||||
• `process._fatalException()`
|
|
||||||
• `process.exit()`
|
|
||||||
• `process.kill()`
|
|
||||||
• `process.umask()` Could only be used to get umask value.
|
|
||||||
• `process.chdir()` Could be called, but no effect at all.
|
|
||||||
|
|
||||||
Some globals may can't be accessed directly, for example `TextDecoder`,
|
|
||||||
`TextEncoder`, use `globalThis` like `globalThis.TextDecoder` to access them.
|
|
||||||
|
|
||||||
*coc-api-console*
|
|
||||||
|
|
||||||
Stdin and stdout of the NodeJS process is used for communication between vim
|
|
||||||
and NodeJS process, use the methods related to `process.stdin` and
|
|
||||||
`process.stdout` may cause unexpected behavior. However, some methods of
|
|
||||||
`console` are provided for debugging purpose.
|
|
||||||
|
|
||||||
Messages from `console` of extension would be redirected to the log file
|
|
||||||
|:CocOpenLog|. Available methods:
|
|
||||||
|
|
||||||
• `debug(...args: any[])` Write debug message to the log file.
|
|
||||||
• `log(...args: any[])` Write info message to the log file.
|
|
||||||
• `info(...args: any[])` Write info message to the log file.
|
|
||||||
• `error(...args: any[])` Write error message to the log file.
|
|
||||||
• `warn(...args: any[])` Write warning message to the log file.
|
|
||||||
|
|
||||||
Check the full NodeJS API interfaces at:
|
|
||||||
https://github.com/neoclide/coc.nvim/blob/master/typings/index.d.ts
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
EXTENSION PACKAGE JSON *coc-api-json*
|
|
||||||
|
|
||||||
The package.json file inside extension root defines the meta data of the
|
|
||||||
extension. For example:
|
|
||||||
>
|
|
||||||
{
|
|
||||||
"name": "coc-my-extension",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"main": "lib/index.js",
|
|
||||||
"engines": {
|
|
||||||
"coc": "^0.0.82"
|
|
||||||
},
|
|
||||||
"activationEvents": [
|
|
||||||
"*",
|
|
||||||
],
|
|
||||||
"contributes": {
|
|
||||||
"rootPatterns": [{
|
|
||||||
"filetype": "myfiletype",
|
|
||||||
"patterns": [
|
|
||||||
"project_root.json"
|
|
||||||
]
|
|
||||||
}],
|
|
||||||
"commands": [{
|
|
||||||
"title": "My command",
|
|
||||||
"category": "myextension",
|
|
||||||
"id": "myextension.myCommand"
|
|
||||||
}],
|
|
||||||
"configuration": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"myextension.enable": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": true,
|
|
||||||
"scope": "resource",
|
|
||||||
"description": "Enable running of my extension."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<
|
|
||||||
Required properties of package.json:
|
|
||||||
|
|
||||||
• name: The unique name of extension, to publish the extension, the name
|
|
||||||
should not be taken by exists packages at https://www.npmjs.com/
|
|
||||||
• version: The semver version of extension.
|
|
||||||
• engines: Should have `coc` property with minimal required coc.nvim version.
|
|
||||||
|
|
||||||
The `main` property contains the relative filepath of the javascript entry
|
|
||||||
file, `index.js` would be used when not exists.
|
|
||||||
|
|
||||||
The `activationEvents` property tell coc.nvim when to activate the extension,
|
|
||||||
when the property not exists or `*` is included, the extension would be
|
|
||||||
activated during coc.nvim initialize. Other possible events:
|
|
||||||
|
|
||||||
• onLanguage: Activate the extension when document of specific languageId
|
|
||||||
exists, ex: `"onLanguage:vim"` activate the extension when there's buffer with
|
|
||||||
languageId as vim loaded.
|
|
||||||
• onFileSystem: Activate the extension when document with custom schema
|
|
||||||
loaded, ex: `"onFileSystem:fugitive"` activate the extension when there's
|
|
||||||
buffer with schema `fugitive` loaded.
|
|
||||||
• onCommand: activate the extension when specific command invoked by user,
|
|
||||||
ex: `"onCommand:tsserver.reloadProjects"`
|
|
||||||
• workspaceContains: activate the extension when the glob pattern match one
|
|
||||||
of the file in current workspace folder, ex:
|
|
||||||
`"workspaceContains:**/package.json"`
|
|
||||||
|
|
||||||
Optional `contributes` property contains the meta data that contributed to
|
|
||||||
coc.nvim, inclduing:
|
|
||||||
|
|
||||||
• rootPatterns: The patterns to resolve |coc-workspace-folders| for
|
|
||||||
associated filetype.
|
|
||||||
• commands: List of commands with `id` and `title` that can be invoked by
|
|
||||||
|:CocCommand|.
|
|
||||||
• configuration: Contains `properties` object or a list of configurations
|
|
||||||
that each one provide `properties` objects which define the configuration
|
|
||||||
properties contributed by this extension.
|
|
||||||
|
|
||||||
The `contributes` property could also contains other properties that used by
|
|
||||||
other extensions, for example: the `jsonValidation` property could be used by
|
|
||||||
coc-json.
|
|
||||||
|
|
||||||
It's recommended to install `coc-json` for json intellisense support.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
SINGLE FILE EXTENSIONS *coc-api-single*
|
|
||||||
|
|
||||||
The easiest way to access the NodeJS API is make use of single file
|
|
||||||
extensions.
|
|
||||||
|
|
||||||
All Javascript files that ends with `.js` inside the folder "coc-extensions"
|
|
||||||
under |g:coc_config_home| are considered as coc extensions.
|
|
||||||
|
|
||||||
The javascript files would be loaded during coc.nvim initialize by default.
|
|
||||||
|
|
||||||
To contribute extension meta data, create file `${name}.json` aside with
|
|
||||||
`${name}.js`, the json file works the same as package.json of extension
|
|
||||||
|coc-api-json|, except that only `activationEvents` and `contributes`
|
|
||||||
properties are used.
|
|
||||||
|
|
||||||
Single file extensions can't be managed by extensions list.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
CREATE CUSTOM EXTENSIONS *coc-api-extension*
|
|
||||||
|
|
||||||
To make an extension installable by |:CocInstall|, the easiest way is make use
|
|
||||||
of https://github.com/fannheyward/create-coc-extension. Simply run command
|
|
||||||
>
|
|
||||||
npm init coc-extension [extension-name]
|
|
||||||
<
|
|
||||||
or
|
|
||||||
>
|
|
||||||
yarn create coc-extension [extension-name]
|
|
||||||
<
|
|
||||||
in terminal and you will be prompted for create a javascript/typescript
|
|
||||||
extension step by step.
|
|
||||||
|
|
||||||
To manually create an extension, follow these step:
|
|
||||||
|
|
||||||
• Create an empty folder and goto that folder.
|
|
||||||
• Create the package.json file |coc-api-json|.
|
|
||||||
• Create a javascript file with name `index.js` and write code.
|
|
||||||
• Add the created folder to your vim's runtimepath by
|
|
||||||
add `set runtimepath^=/path/to/folder` in your vimrc.
|
|
||||||
|
|
||||||
Recommended steps:
|
|
||||||
|
|
||||||
• Install types of NodeJS and coc.nvim by terminal command
|
|
||||||
`yarn install @types/node@14.14 coc.nvim` in extension folder.
|
|
||||||
• Bundle the javascript files when using multiple node dependencies by
|
|
||||||
esbuild to save the time of installation. A typical build script looks
|
|
||||||
like:
|
|
||||||
>
|
|
||||||
async function start() {
|
|
||||||
await require('esbuild').build({
|
|
||||||
entryPoints: ['src/index.ts'],
|
|
||||||
bundle: true,
|
|
||||||
minify: process.env.NODE_ENV === 'production',
|
|
||||||
sourcemap: process.env.NODE_ENV === 'development',
|
|
||||||
mainFields: ['module', 'main'],
|
|
||||||
external: ['coc.nvim'],
|
|
||||||
platform: 'node',
|
|
||||||
target: 'node14.14',
|
|
||||||
outfile: 'lib/index.js'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
start().catch(e => {
|
|
||||||
console.error(e)
|
|
||||||
})
|
|
||||||
<
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
DEBUG EXTENSIONS *coc-api-debug*
|
|
||||||
|
|
||||||
Uncaught errors:~
|
|
||||||
|
|
||||||
When an uncaught error raised on the NodeJS process, the error message would
|
|
||||||
be send to vim through stderr, and echoed by vim (unless
|
|
||||||
|g:coc_disable_uncaught_error| is enabeld).
|
|
||||||
|
|
||||||
The error messages are not stored by vim's message history, use
|
|
||||||
|:CocPrintErrors| to show previous errors.
|
|
||||||
|
|
||||||
When error happens on the vim side, the promise would be rejected when sending
|
|
||||||
request to vim, for notifications, vim would send `nvim_error_event` to the
|
|
||||||
NodeJS process, and the node-client would create error log for it.
|
|
||||||
|
|
||||||
Use the log file:~
|
|
||||||
|
|
||||||
• Configure `NVIM_COC_LOG_LEVEL` to `trace` in vimrc:
|
|
||||||
`let $NVIM_COC_LOG_LEVEL='trace'`
|
|
||||||
• Configure `NVIM_COC_LOG_FILE` to a fixed in vimrc:
|
|
||||||
`let $NVIM_COC_LOG_FILE=/tmp/coc.log`, otherwise it would be different for
|
|
||||||
each vim instance.
|
|
||||||
• Use |coc-api-console| to add console statements in javascript/typescript
|
|
||||||
code and compile the extension when needed.
|
|
||||||
• Tail the log file by `tail` command and make the issue happen.
|
|
||||||
|
|
||||||
Add source map support:~
|
|
||||||
|
|
||||||
When the javascript code is bundled by esbuild, it would be useful to have
|
|
||||||
correct source map support for the error stack.
|
|
||||||
|
|
||||||
• Install global source-map-support by `npm install -g source-map-support`
|
|
||||||
• Find out the npm root by `npm root -g`
|
|
||||||
• Load source-map-support with coc.nvim by append arguments to node in vimrc:
|
|
||||||
`let g:coc_node_args = ['-r', '/path/to/npm/root/source-map-support/register']`
|
|
||||||
Repalce the part `/path/to/npm/root` with result from `npm root -g` terminal
|
|
||||||
command.
|
|
||||||
|
|
||||||
Note: the source-map-support module slows down the coc.nvim initialization.
|
|
||||||
|
|
||||||
Debug javascript code in chrome:~
|
|
||||||
|
|
||||||
• Add `let g:coc_node_args = ['--nolazy', '--inspect-brk=5858']`
|
|
||||||
• Open vim and you will get the error message indicate that the debugger is
|
|
||||||
listening.
|
|
||||||
• Open Chrome browser with url chrome://inspect/#devices, configure
|
|
||||||
the `Target discovery settings` and you will get the remote target to
|
|
||||||
inspect.
|
|
||||||
• Click the inspect link to open the devtools.
|
|
||||||
• Click the sources label to debug javascript code.
|
|
||||||
|
|
||||||
Other debugger clients can be used as well, see:
|
|
||||||
https://nodejs.org/en/docs/guides/debugging-getting-started/
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
vim:tw=78:sta:noet:ts=8:sts=0:ft=help:fen:
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,85 +0,0 @@
|
||||||
local api = vim.api
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
-- Get single line extmarks
|
|
||||||
function M.getHighlights(bufnr, key, s, e)
|
|
||||||
if not api.nvim_buf_is_loaded(bufnr) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
s = s or 0
|
|
||||||
e = e or -1
|
|
||||||
local max = e == -1 and api.nvim_buf_line_count(bufnr) or e + 1
|
|
||||||
local ns = api.nvim_create_namespace('coc-' .. key)
|
|
||||||
local markers = api.nvim_buf_get_extmarks(bufnr, ns, {s, 0}, {e, -1}, {details = true})
|
|
||||||
local res = {}
|
|
||||||
for _, mark in ipairs(markers) do
|
|
||||||
local id = mark[1]
|
|
||||||
local line = mark[2]
|
|
||||||
local startCol = mark[3]
|
|
||||||
local details = mark[4]
|
|
||||||
local endCol = details.end_col
|
|
||||||
if line < max then
|
|
||||||
local delta = details.end_row - line
|
|
||||||
if delta <= 1 and (delta == 0 or endCol == 0) then
|
|
||||||
if startCol == endCol then
|
|
||||||
api.nvim_buf_del_extmark(bufnr, ns, id)
|
|
||||||
else
|
|
||||||
if delta == 1 then
|
|
||||||
local text = api.nvim_buf_get_lines(bufnr, line, line + 1, false)[1] or ''
|
|
||||||
endCol = #text
|
|
||||||
end
|
|
||||||
table.insert(res, {details.hl_group, line, startCol, endCol, id})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
|
|
||||||
local function addHighlights(bufnr, ns, highlights, priority)
|
|
||||||
for _, items in ipairs(highlights) do
|
|
||||||
local hlGroup = items[1]
|
|
||||||
local line = items[2]
|
|
||||||
local startCol = items[3]
|
|
||||||
local endCol = items[4]
|
|
||||||
local hlMode = items[5] and 'combine' or 'replace'
|
|
||||||
-- Error: col value outside range
|
|
||||||
pcall(api.nvim_buf_set_extmark, bufnr, ns, line, startCol, {
|
|
||||||
end_col = endCol,
|
|
||||||
hl_group = hlGroup,
|
|
||||||
hl_mode = hlMode,
|
|
||||||
right_gravity = true,
|
|
||||||
priority = type(priority) == 'number' and math.min(priority, 4096) or 4096
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function addHighlightTimer(bufnr, ns, highlights, priority, maxCount)
|
|
||||||
local hls = {}
|
|
||||||
local next = {}
|
|
||||||
for i, v in ipairs(highlights) do
|
|
||||||
if i < maxCount then
|
|
||||||
table.insert(hls, v)
|
|
||||||
else
|
|
||||||
table.insert(next, v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
addHighlights(bufnr, ns, hls, priority)
|
|
||||||
if #next > 0 then
|
|
||||||
vim.defer_fn(function()
|
|
||||||
addHighlightTimer(bufnr, ns, next, priority, maxCount)
|
|
||||||
end, 30)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.set(bufnr, ns, highlights, priority)
|
|
||||||
local maxCount = vim.g.coc_highlight_maximum_count
|
|
||||||
if #highlights > maxCount then
|
|
||||||
addHighlightTimer(bufnr, ns, highlights, priority, maxCount)
|
|
||||||
else
|
|
||||||
addHighlights(bufnr, ns, highlights, priority)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
"name": "coc.nvim-release",
|
|
||||||
"version": "0.0.82",
|
|
||||||
"description": "LSP based intellisense engine for neovim & vim8.",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.12.0"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/neoclide/coc.nvim.git"
|
|
||||||
},
|
|
||||||
"author": "Qiming Zhao <chemzqm@gmail.com>",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/neoclide/coc.nvim/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/neoclide/coc.nvim#readme"
|
|
||||||
}
|
|
|
@ -1,796 +0,0 @@
|
||||||
scriptencoding utf-8
|
|
||||||
if exists('g:did_coc_loaded') || v:version < 800
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
function! s:checkVersion() abort
|
|
||||||
let l:unsupported = 0
|
|
||||||
if get(g:, 'coc_disable_startup_warning', 0) != 1
|
|
||||||
if has('nvim')
|
|
||||||
let l:unsupported = !has('nvim-0.4.0')
|
|
||||||
else
|
|
||||||
let l:unsupported = !has('patch-8.1.1719')
|
|
||||||
endif
|
|
||||||
|
|
||||||
if l:unsupported == 1
|
|
||||||
echohl Error
|
|
||||||
echom "coc.nvim requires at least Vim 8.1.1719 or Neovim 0.4.0, but you're using an older version."
|
|
||||||
echom "Please upgrade your (neo)vim."
|
|
||||||
echom "You can add this to your vimrc to avoid this message:"
|
|
||||||
echom " let g:coc_disable_startup_warning = 1"
|
|
||||||
echom "Note that some features may error out or behave incorrectly."
|
|
||||||
echom "Please do not report bugs unless you're using at least Vim 8.1.1719 or Neovim 0.4.0."
|
|
||||||
echohl None
|
|
||||||
sleep 2
|
|
||||||
else
|
|
||||||
if !has('nvim-0.5.0') && !has('patch-8.2.0750')
|
|
||||||
echohl WarningMsg
|
|
||||||
echom "coc.nvim works best on vim >= 8.2.0750 and neovim >= 0.5.0, consider upgrade your vim."
|
|
||||||
echom "You can add this to your vimrc to avoid this message:"
|
|
||||||
echom " let g:coc_disable_startup_warning = 1"
|
|
||||||
echom "Note that some features may behave incorrectly."
|
|
||||||
echohl None
|
|
||||||
sleep 2
|
|
||||||
elseif !has('nvim') && (!has('job') || !has('popupwin') || !has('textprop'))
|
|
||||||
echohl WarningMsg
|
|
||||||
echom "coc.nvim requires job, popupwin and textprop features of vim, consider recompile your vim."
|
|
||||||
echom "You can add this to your vimrc to avoid this message:"
|
|
||||||
echom " let g:coc_disable_startup_warning = 1"
|
|
||||||
echom "Note that some features may behave incorrectly."
|
|
||||||
echohl None
|
|
||||||
sleep 2
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
call s:checkVersion()
|
|
||||||
|
|
||||||
let g:did_coc_loaded = 1
|
|
||||||
let g:coc_service_initialized = 0
|
|
||||||
let s:root = expand('<sfile>:h:h')
|
|
||||||
let s:is_vim = !has('nvim')
|
|
||||||
let s:is_gvim = s:is_vim && has("gui_running")
|
|
||||||
|
|
||||||
if get(g:, 'coc_start_at_startup', 1) && !s:is_gvim
|
|
||||||
call coc#rpc#start_server()
|
|
||||||
endif
|
|
||||||
|
|
||||||
function! CocTagFunc(pattern, flags, info) abort
|
|
||||||
if a:flags !=# 'c'
|
|
||||||
" use standard tag search
|
|
||||||
return v:null
|
|
||||||
endif
|
|
||||||
return coc#rpc#request('getTagList', [])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Used by popup prompt on vim
|
|
||||||
function! CocPopupCallback(bufnr, arglist) abort
|
|
||||||
if len(a:arglist) == 2
|
|
||||||
if a:arglist[0] == 'confirm'
|
|
||||||
call coc#rpc#notify('PromptInsert', [a:arglist[1], a:bufnr])
|
|
||||||
elseif a:arglist[0] == 'exit'
|
|
||||||
execute 'silent! bd! '.a:bufnr
|
|
||||||
"call coc#rpc#notify('PromptUpdate', [a:arglist[1]])
|
|
||||||
elseif a:arglist[0] == 'change'
|
|
||||||
let text = a:arglist[1]
|
|
||||||
let current = getbufvar(a:bufnr, 'current', '')
|
|
||||||
if text !=# current
|
|
||||||
call setbufvar(a:bufnr, 'current', text)
|
|
||||||
let cursor = term_getcursor(a:bufnr)
|
|
||||||
let info = {
|
|
||||||
\ 'lnum': cursor[0],
|
|
||||||
\ 'col': cursor[1],
|
|
||||||
\ 'line': text,
|
|
||||||
\ 'changedtick': 0
|
|
||||||
\ }
|
|
||||||
call coc#rpc#notify('CocAutocmd', ['TextChangedI', a:bufnr, info])
|
|
||||||
endif
|
|
||||||
elseif a:arglist[0] == 'send'
|
|
||||||
call coc#rpc#notify('PromptKeyPress', [a:bufnr, a:arglist[1]])
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! CocAction(name, ...) abort
|
|
||||||
if !get(g:, 'coc_service_initialized', 0)
|
|
||||||
throw 'coc.nvim not ready when invoke CocAction "'.a:name.'"'
|
|
||||||
endif
|
|
||||||
return coc#rpc#request(a:name, a:000)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! CocHasProvider(name) abort
|
|
||||||
return coc#rpc#request('hasProvider', [a:name])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! CocActionAsync(name, ...) abort
|
|
||||||
return s:AsyncRequest(a:name, a:000)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! CocRequest(...) abort
|
|
||||||
return coc#rpc#request('sendRequest', a:000)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! CocNotify(...) abort
|
|
||||||
return coc#rpc#request('sendNotification', a:000)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! CocRegisterNotification(id, method, cb) abort
|
|
||||||
call coc#on_notify(a:id, a:method, a:cb)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Deprecated, use CocRegisterNotification instead
|
|
||||||
function! CocRegistNotification(id, method, cb) abort
|
|
||||||
call coc#on_notify(a:id, a:method, a:cb)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! CocLocations(id, method, ...) abort
|
|
||||||
let args = [a:id, a:method] + copy(a:000)
|
|
||||||
return coc#rpc#request('findLocations', args)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! CocLocationsAsync(id, method, ...) abort
|
|
||||||
let args = [a:id, a:method] + copy(a:000)
|
|
||||||
return s:AsyncRequest('findLocations', args)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! CocRequestAsync(...)
|
|
||||||
return s:AsyncRequest('sendRequest', a:000)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:AsyncRequest(name, args) abort
|
|
||||||
let Cb = empty(a:args)? v:null : a:args[len(a:args) - 1]
|
|
||||||
if type(Cb) == 2
|
|
||||||
if !coc#rpc#ready()
|
|
||||||
call Cb('service not started', v:null)
|
|
||||||
else
|
|
||||||
call coc#rpc#request_async(a:name, a:args[0:-2], Cb)
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
call coc#rpc#notify(a:name, a:args)
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:CommandList(...) abort
|
|
||||||
let list = coc#rpc#request('commandList', a:000)
|
|
||||||
return join(list, "\n")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:ExtensionList(...) abort
|
|
||||||
let stats = CocAction('extensionStats')
|
|
||||||
call filter(stats, 'v:val["isLocal"] == v:false')
|
|
||||||
let list = map(stats, 'v:val["id"]')
|
|
||||||
return join(list, "\n")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:SearchOptions(...) abort
|
|
||||||
let list = ['-e', '--regexp', '-F', '--fixed-strings', '-L', '--follow',
|
|
||||||
\ '-g', '--glob', '--hidden', '--no-hidden', '--no-ignore-vcs',
|
|
||||||
\ '--word-regexp', '-w', '--smart-case', '-S', '--no-config',
|
|
||||||
\ '--line-regexp', '--no-ignore', '-x']
|
|
||||||
return join(list, "\n")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:LoadedExtensions(...) abort
|
|
||||||
let list = CocAction('loadedExtensions')
|
|
||||||
return join(list, "\n")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:InstallOptions(...)abort
|
|
||||||
let list = ['-terminal', '-sync']
|
|
||||||
return join(list, "\n")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:OpenConfig()
|
|
||||||
let home = coc#util#get_config_home()
|
|
||||||
if !isdirectory(home)
|
|
||||||
echohl MoreMsg
|
|
||||||
echom 'Config directory "'.home.'" does not exist, create? (y/n)'
|
|
||||||
echohl None
|
|
||||||
let confirm = nr2char(getchar())
|
|
||||||
redraw!
|
|
||||||
if !(confirm ==? "y" || confirm ==? "\r")
|
|
||||||
return
|
|
||||||
else
|
|
||||||
call mkdir(home, 'p')
|
|
||||||
end
|
|
||||||
endif
|
|
||||||
execute 'edit '.fnameescape(home.'/coc-settings.json')
|
|
||||||
call coc#rpc#notify('checkJsonExtension', [])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_color(item, fallback) abort
|
|
||||||
let t = type(a:item)
|
|
||||||
if t == 1
|
|
||||||
return a:item
|
|
||||||
endif
|
|
||||||
if t == 4
|
|
||||||
let item = get(a:item, 'gui', {})
|
|
||||||
let color = get(item, &background, a:fallback)
|
|
||||||
return type(color) == 1 ? color : a:fallback
|
|
||||||
endif
|
|
||||||
return a:fallback
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:AddAnsiGroups() abort
|
|
||||||
let color_map = {}
|
|
||||||
let colors = ['#282828', '#cc241d', '#98971a', '#d79921', '#458588', '#b16286', '#689d6a', '#a89984', '#928374']
|
|
||||||
let names = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'grey']
|
|
||||||
for i in range(0, len(names) - 1)
|
|
||||||
let name = names[i]
|
|
||||||
if exists('g:terminal_ansi_colors')
|
|
||||||
let color_map[name] = s:get_color(get(g:terminal_ansi_colors, i, colors[i]), colors[i])
|
|
||||||
else
|
|
||||||
let color_map[name] = get(g:, 'terminal_color_'.i, colors[i])
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
try
|
|
||||||
for name in keys(color_map)
|
|
||||||
let foreground = toupper(name[0]).name[1:]
|
|
||||||
let foregroundColor = color_map[name]
|
|
||||||
for key in keys(color_map)
|
|
||||||
let background = toupper(key[0]).key[1:]
|
|
||||||
let backgroundColor = color_map[key]
|
|
||||||
exe 'hi default CocList'.foreground.background.' guifg='.foregroundColor.' guibg='.backgroundColor
|
|
||||||
endfor
|
|
||||||
exe 'hi default CocListFg'.foreground. ' guifg='.foregroundColor. ' ctermfg='.foreground
|
|
||||||
exe 'hi default CocListBg'.foreground. ' guibg='.foregroundColor. ' ctermbg='.foreground
|
|
||||||
endfor
|
|
||||||
catch /.*/
|
|
||||||
" ignore invalid color
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:CreateHighlight(group, fg, bg) abort
|
|
||||||
let cmd = coc#highlight#compose(a:fg, a:bg)
|
|
||||||
if !empty(trim(cmd))
|
|
||||||
exe 'hi default '.a:group.' '.cmd
|
|
||||||
else
|
|
||||||
exe 'hi default link '.a:group.' '.a:fg
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:OpenDiagnostics(...) abort
|
|
||||||
let height = get(a:, 1, 0)
|
|
||||||
call coc#rpc#request('fillDiagnostics', [bufnr('%')])
|
|
||||||
if height
|
|
||||||
execute ':lopen '.height
|
|
||||||
else
|
|
||||||
lopen
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:Disable() abort
|
|
||||||
if get(g:, 'coc_enabled', 0) == 0
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
autocmd! coc_nvim
|
|
||||||
call coc#rpc#request('detach', [])
|
|
||||||
echohl MoreMsg
|
|
||||||
echom '[coc.nvim] Event disabled'
|
|
||||||
echohl None
|
|
||||||
let g:coc_enabled = 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:Autocmd(...) abort
|
|
||||||
if !get(g:, 'coc_workspace_initialized', 0)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call coc#rpc#notify('CocAutocmd', a:000)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:HandleCharInsert(char, bufnr) abort
|
|
||||||
if get(g:, 'coc_feeding_keys', 0)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if get(g:, 'coc_disable_space_report', 0)
|
|
||||||
let g:coc_disable_space_report = 0
|
|
||||||
if a:char ==# ' '
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call s:Autocmd('InsertCharPre', a:char, a:bufnr)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:HandleTextChangedI(bufnr) abort
|
|
||||||
if get(g:, 'coc_feeding_keys', 0)
|
|
||||||
unlet g:coc_feeding_keys
|
|
||||||
endif
|
|
||||||
call s:Autocmd('TextChangedI', a:bufnr, coc#util#change_info())
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:HandleInsertLeave(bufnr) abort
|
|
||||||
call coc#pum#close()
|
|
||||||
call s:Autocmd('InsertLeave', a:bufnr)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:HandleWinScrolled(winid) abort
|
|
||||||
if getwinvar(a:winid, 'float', 0)
|
|
||||||
call coc#float#nvim_scrollbar(a:winid)
|
|
||||||
endif
|
|
||||||
call s:Autocmd('WinScrolled', a:winid)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:HandleWinClosed(winid) abort
|
|
||||||
call coc#float#on_close(a:winid)
|
|
||||||
call coc#notify#on_close(a:winid)
|
|
||||||
call s:Autocmd('WinClosed', a:winid)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:SyncAutocmd(...)
|
|
||||||
if !get(g:, 'coc_workspace_initialized', 0)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
call coc#rpc#request('CocAutocmd', a:000)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:VimLeavePre() abort
|
|
||||||
let g:coc_vim_leaving = 1
|
|
||||||
call s:Autocmd('VimLeavePre')
|
|
||||||
if s:is_vim && exists('$COC_NVIM_REMOTE_ADDRESS')
|
|
||||||
" Helps to avoid connection error.
|
|
||||||
call coc#rpc#close_connection()
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if get(g:, 'coc_node_env', '') ==# 'test'
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
call timer_start(1, { -> coc#client#kill('coc')})
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:VimEnter() abort
|
|
||||||
if coc#rpc#started()
|
|
||||||
if !exists('$COC_NVIM_REMOTE_ADDRESS')
|
|
||||||
call coc#rpc#notify('VimEnter', [coc#util#path_replace_patterns(), join(globpath(&runtimepath, "", 0, 1), ",")])
|
|
||||||
endif
|
|
||||||
elseif get(g:, 'coc_start_at_startup', 1)
|
|
||||||
call coc#rpc#start_server()
|
|
||||||
endif
|
|
||||||
call s:Highlight()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:Enable(initialize)
|
|
||||||
if get(g:, 'coc_enabled', 0) == 1
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
let g:coc_enabled = 1
|
|
||||||
sign define CocCurrentLine linehl=CocMenuSel
|
|
||||||
sign define CocListCurrent linehl=CocListLine
|
|
||||||
sign define CocTreeSelected linehl=CocTreeSelected
|
|
||||||
if s:is_vim
|
|
||||||
call coc#api#tabpage_ids()
|
|
||||||
endif
|
|
||||||
|
|
||||||
augroup coc_nvim
|
|
||||||
autocmd!
|
|
||||||
|
|
||||||
if !v:vim_did_enter
|
|
||||||
autocmd VimEnter * call s:VimEnter()
|
|
||||||
else
|
|
||||||
call s:Highlight()
|
|
||||||
endif
|
|
||||||
if s:is_vim
|
|
||||||
if exists('##DirChanged')
|
|
||||||
autocmd DirChanged * call s:Autocmd('DirChanged', getcwd())
|
|
||||||
endif
|
|
||||||
if exists('##TerminalOpen')
|
|
||||||
autocmd TerminalOpen * call s:Autocmd('TermOpen', +expand('<abuf>'))
|
|
||||||
endif
|
|
||||||
autocmd CursorMoved list:///* call coc#list#select(bufnr('%'), line('.'))
|
|
||||||
autocmd TabNew * call coc#api#tabpage_ids()
|
|
||||||
else
|
|
||||||
autocmd DirChanged * call s:Autocmd('DirChanged', get(v:event, 'cwd', ''))
|
|
||||||
autocmd TermOpen * call s:Autocmd('TermOpen', +expand('<abuf>'))
|
|
||||||
autocmd WinEnter * call coc#float#nvim_win_enter(win_getid())
|
|
||||||
endif
|
|
||||||
if exists('##CompleteChanged')
|
|
||||||
autocmd CompleteChanged * call timer_start(1, { -> coc#pum#close()})
|
|
||||||
endif
|
|
||||||
autocmd CursorHold * call coc#float#check_related()
|
|
||||||
if exists('##WinClosed')
|
|
||||||
autocmd WinClosed * call s:HandleWinClosed(+expand('<amatch>'))
|
|
||||||
elseif exists('##TabEnter')
|
|
||||||
autocmd TabEnter * call coc#notify#reflow()
|
|
||||||
endif
|
|
||||||
if exists('##WinScrolled')
|
|
||||||
autocmd WinScrolled * call s:HandleWinScrolled(+expand('<amatch>'))
|
|
||||||
endif
|
|
||||||
autocmd TabNew * call s:Autocmd('TabNew', coc#util#tabnr_id(tabpagenr()))
|
|
||||||
autocmd TabClosed * call s:Autocmd('TabClosed', coc#util#tabpages())
|
|
||||||
autocmd WinLeave * call s:Autocmd('WinLeave', win_getid())
|
|
||||||
autocmd WinEnter * call s:Autocmd('WinEnter', win_getid())
|
|
||||||
autocmd BufWinLeave * call s:Autocmd('BufWinLeave', +expand('<abuf>'), bufwinid(+expand('<abuf>')))
|
|
||||||
autocmd BufWinEnter * call s:Autocmd('BufWinEnter', +expand('<abuf>'), win_getid())
|
|
||||||
autocmd FileType * call s:Autocmd('FileType', expand('<amatch>'), +expand('<abuf>'))
|
|
||||||
autocmd InsertCharPre * call s:HandleCharInsert(v:char, bufnr('%'))
|
|
||||||
if exists('##TextChangedP')
|
|
||||||
autocmd TextChangedP * call s:Autocmd('TextChangedP', +expand('<abuf>'), coc#util#change_info())
|
|
||||||
endif
|
|
||||||
autocmd TextChangedI * call s:HandleTextChangedI(+expand('<abuf>'))
|
|
||||||
autocmd InsertLeave * call s:HandleInsertLeave(+expand('<abuf>'))
|
|
||||||
autocmd InsertEnter * call s:Autocmd('InsertEnter', +expand('<abuf>'))
|
|
||||||
autocmd BufHidden * call s:Autocmd('BufHidden', +expand('<abuf>'))
|
|
||||||
autocmd BufEnter * call s:Autocmd('BufEnter', +expand('<abuf>'))
|
|
||||||
autocmd TextChanged * call s:Autocmd('TextChanged', +expand('<abuf>'), getbufvar(+expand('<abuf>'), 'changedtick'))
|
|
||||||
autocmd BufWritePost * call s:Autocmd('BufWritePost', +expand('<abuf>'), getbufvar(+expand('<abuf>'), 'changedtick'))
|
|
||||||
autocmd CursorMoved * call s:Autocmd('CursorMoved', +expand('<abuf>'), [line('.'), col('.')])
|
|
||||||
autocmd CursorMovedI * call s:Autocmd('CursorMovedI', +expand('<abuf>'), [line('.'), col('.')])
|
|
||||||
autocmd CursorHold * call s:Autocmd('CursorHold', +expand('<abuf>'), [line('.'), col('.')])
|
|
||||||
autocmd CursorHoldI * call s:Autocmd('CursorHoldI', +expand('<abuf>'), [line('.'), col('.')])
|
|
||||||
autocmd BufNewFile,BufReadPost * call s:Autocmd('BufCreate', +expand('<abuf>'))
|
|
||||||
autocmd BufUnload * call s:Autocmd('BufUnload', +expand('<abuf>'))
|
|
||||||
autocmd BufWritePre * call s:SyncAutocmd('BufWritePre', +expand('<abuf>'), bufname(+expand('<abuf>')), getbufvar(+expand('<abuf>'), 'changedtick'))
|
|
||||||
autocmd FocusGained * if mode() !~# '^c' | call s:Autocmd('FocusGained') | endif
|
|
||||||
autocmd FocusLost * call s:Autocmd('FocusLost')
|
|
||||||
autocmd VimResized * call s:Autocmd('VimResized', &columns, &lines)
|
|
||||||
autocmd VimLeavePre * call s:VimLeavePre()
|
|
||||||
autocmd BufReadCmd,FileReadCmd,SourceCmd list://* call coc#list#setup(expand('<amatch>'))
|
|
||||||
autocmd BufWriteCmd __coc_refactor__* :call coc#rpc#notify('saveRefactor', [+expand('<abuf>')])
|
|
||||||
autocmd ColorScheme * call s:Highlight() | call s:Autocmd('ColorScheme')
|
|
||||||
augroup end
|
|
||||||
if a:initialize == 0
|
|
||||||
call coc#rpc#request('attach', [])
|
|
||||||
echohl MoreMsg
|
|
||||||
echom '[coc.nvim] Event enabled'
|
|
||||||
echohl None
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:Highlight() abort
|
|
||||||
hi default CocSelectedText ctermfg=Red guifg=#fb4934 guibg=NONE
|
|
||||||
hi default CocCodeLens ctermfg=Gray guifg=#999999 guibg=NONE
|
|
||||||
hi default CocUnderline term=underline cterm=underline gui=underline guisp=#ebdbb2
|
|
||||||
hi default CocBold term=bold cterm=bold gui=bold
|
|
||||||
hi default CocItalic term=italic cterm=italic gui=italic
|
|
||||||
hi default CocStrikeThrough term=strikethrough cterm=strikethrough gui=strikethrough
|
|
||||||
hi default CocMarkdownLink ctermfg=Blue guifg=#15aabf guibg=NONE
|
|
||||||
hi default CocDisabled guifg=#999999 ctermfg=gray
|
|
||||||
hi default CocSearch ctermfg=Blue guifg=#15aabf guibg=NONE
|
|
||||||
hi default CocLink term=underline cterm=underline gui=underline guisp=#15aabf
|
|
||||||
if coc#highlight#get_contrast('Normal', has('nvim') ? 'NormalFloat' : 'Pmenu') > 2.0
|
|
||||||
exe 'hi default CocFloating '.coc#highlight#create_bg_command('Normal', &background ==# 'dark' ? -30 : 30)
|
|
||||||
exe 'hi default CocMenuSel '.coc#highlight#create_bg_command('CocFloating', &background ==# 'dark' ? -20 : 20)
|
|
||||||
exe 'hi default CocFloatThumb '.coc#highlight#create_bg_command('CocFloating', &background ==# 'dark' ? -40 : 40)
|
|
||||||
hi default link CocFloatSbar CocFloating
|
|
||||||
else
|
|
||||||
exe 'hi default link CocFloating '.(has('nvim') ? 'NormalFloat' : 'Pmenu')
|
|
||||||
if coc#highlight#get_contrast('CocFloating', 'PmenuSel') > 2.0
|
|
||||||
exe 'hi default CocMenuSel '.coc#highlight#create_bg_command('CocFloating', &background ==# 'dark' ? -30 : 30)
|
|
||||||
else
|
|
||||||
exe 'hi default CocMenuSel '.coc#highlight#get_hl_command(synIDtrans(hlID('PmenuSel')), 'bg', '237', '#13354A')
|
|
||||||
endif
|
|
||||||
hi default link CocFloatThumb PmenuThumb
|
|
||||||
hi default link CocFloatSbar PmenuSbar
|
|
||||||
endif
|
|
||||||
if coc#highlight#get_contrast('Normal', 'CursorLine') < 1.3
|
|
||||||
" Avoid color too close
|
|
||||||
exe 'hi default CocListLine '.coc#highlight#create_bg_command('Normal', &background ==# 'dark' ? -20 : 20)
|
|
||||||
else
|
|
||||||
hi default link CocListLine CursorLine
|
|
||||||
endif
|
|
||||||
hi default link CocFloatActive CocSearch
|
|
||||||
hi default link CocFadeOut Conceal
|
|
||||||
hi default link CocMarkdownCode markdownCode
|
|
||||||
hi default link CocMarkdownHeader markdownH1
|
|
||||||
hi default link CocDeprecatedHighlight CocStrikeThrough
|
|
||||||
hi default link CocUnusedHighlight CocFadeOut
|
|
||||||
hi default link CocListSearch CocSearch
|
|
||||||
hi default link CocListMode ModeMsg
|
|
||||||
hi default link CocListPath Comment
|
|
||||||
hi default link CocHighlightText CursorColumn
|
|
||||||
hi default link CocHoverRange Search
|
|
||||||
hi default link CocCursorRange Search
|
|
||||||
hi default link CocLinkedEditing CocCursorRange
|
|
||||||
hi default link CocHighlightRead CocHighlightText
|
|
||||||
hi default link CocHighlightWrite CocHighlightText
|
|
||||||
" Notification
|
|
||||||
hi default CocNotificationProgress ctermfg=Blue guifg=#15aabf guibg=NONE
|
|
||||||
hi default link CocNotificationButton CocUnderline
|
|
||||||
hi default link CocNotificationError CocErrorFloat
|
|
||||||
hi default link CocNotificationWarning CocWarningFloat
|
|
||||||
hi default link CocNotificationInfo CocInfoFloat
|
|
||||||
" Snippet
|
|
||||||
hi default link CocSnippetVisual Visual
|
|
||||||
" Tree view highlights
|
|
||||||
hi default link CocTreeTitle Title
|
|
||||||
hi default link CocTreeDescription Comment
|
|
||||||
hi default link CocTreeOpenClose CocBold
|
|
||||||
hi default link CocTreeSelected CursorLine
|
|
||||||
hi default link CocSelectedRange CocHighlightText
|
|
||||||
" Symbol highlights
|
|
||||||
hi default link CocSymbolDefault MoreMsg
|
|
||||||
"Pum
|
|
||||||
hi default link CocPumSearch CocSearch
|
|
||||||
hi default link CocPumDetail Comment
|
|
||||||
hi default link CocPumMenu CocFloating
|
|
||||||
hi default link CocPumShortcut Comment
|
|
||||||
hi default link CocPumDeprecated CocStrikeThrough
|
|
||||||
hi default CocVirtualText ctermfg=12 guifg=#504945
|
|
||||||
hi default link CocPumVirtualText CocVirtualText
|
|
||||||
hi default link CocInputBoxVirtualText CocVirtualText
|
|
||||||
hi default link CocFloatDividingLine CocVirtualText
|
|
||||||
|
|
||||||
if has('nvim-0.5.0')
|
|
||||||
hi default CocCursorTransparent gui=strikethrough blend=100
|
|
||||||
endif
|
|
||||||
|
|
||||||
let sign_colors = {
|
|
||||||
\ 'Error': ['Red', '#ff0000'],
|
|
||||||
\ 'Warn': ['Brown', '#ff922b'],
|
|
||||||
\ 'Info': ['Yellow', '#fab005'],
|
|
||||||
\ 'Hint': ['Blue', '#15aabf']
|
|
||||||
\ }
|
|
||||||
for name in ['Error', 'Warning', 'Info', 'Hint']
|
|
||||||
let suffix = name ==# 'Warning' ? 'Warn' : name
|
|
||||||
if hlexists('DiagnosticUnderline'.suffix)
|
|
||||||
exe 'hi default link Coc'.name.'Highlight DiagnosticUnderline'.suffix
|
|
||||||
else
|
|
||||||
exe 'hi default link Coc'.name.'Highlight CocUnderline'
|
|
||||||
endif
|
|
||||||
if hlexists('DiagnosticSign'.suffix)
|
|
||||||
exe 'hi default link Coc'.name.'Sign DiagnosticSign'.suffix
|
|
||||||
else
|
|
||||||
exe 'hi default Coc'.name.'Sign ctermfg='.sign_colors[suffix][0].' guifg='.sign_colors[suffix][1]
|
|
||||||
endif
|
|
||||||
if hlexists('DiagnosticVirtualText'.suffix)
|
|
||||||
exe 'hi default link Coc'.name.'VirtualText DiagnosticVirtualText'.suffix
|
|
||||||
else
|
|
||||||
call s:CreateHighlight('Coc'.name.'VirtualText', 'Coc'.name.'Sign', 'Normal')
|
|
||||||
endif
|
|
||||||
if hlexists('Diagnostic'.suffix)
|
|
||||||
exe 'hi default link Coc'.name.'Float Diagnostic'.suffix
|
|
||||||
else
|
|
||||||
call s:CreateHighlight('Coc'.name.'Float', 'Coc'.name.'Sign', 'CocFloating')
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
call s:CreateHighlight('CocInlayHint', 'CocHintSign', 'SignColumn')
|
|
||||||
for name in ['Parameter', 'Type']
|
|
||||||
exe 'hi default link CocInlayHint'.name.' CocInlayHint'
|
|
||||||
endfor
|
|
||||||
|
|
||||||
call s:AddAnsiGroups()
|
|
||||||
|
|
||||||
if get(g:, 'coc_default_semantic_highlight_groups', 1)
|
|
||||||
let hlMap = {
|
|
||||||
\ 'Namespace': ['@namespace', 'Include'],
|
|
||||||
\ 'Type': ['@type', 'Type'],
|
|
||||||
\ 'Class': ['@constructor', 'Special'],
|
|
||||||
\ 'Enum': ['@type', 'Type'],
|
|
||||||
\ 'Interface': ['@type', 'Type'],
|
|
||||||
\ 'Struct': ['@structure', 'Identifier'],
|
|
||||||
\ 'TypeParameter': ['@parameter', 'Identifier'],
|
|
||||||
\ 'Parameter': ['@parameter', 'Identifier'],
|
|
||||||
\ 'Variable': ['@variable', 'Identifier'],
|
|
||||||
\ 'Property': ['@property', 'Identifier'],
|
|
||||||
\ 'EnumMember': ['@property', 'Constant'],
|
|
||||||
\ 'Event': ['@keyword', 'Keyword'],
|
|
||||||
\ 'Function': ['@function', 'Function'],
|
|
||||||
\ 'Method': ['@method', 'Function'],
|
|
||||||
\ 'Macro': ['@constant.macro', 'Define'],
|
|
||||||
\ 'Keyword': ['@keyword', 'Keyword'],
|
|
||||||
\ 'Modifier': ['@storageclass', 'StorageClass'],
|
|
||||||
\ 'Comment': ['@comment', 'Comment'],
|
|
||||||
\ 'String': ['@string', 'String'],
|
|
||||||
\ 'Number': ['@number', 'Number'],
|
|
||||||
\ 'Boolean': ['@boolean', 'Boolean'],
|
|
||||||
\ 'Regexp': ['@string.regex', 'String'],
|
|
||||||
\ 'Operator': ['@operator', 'Operator'],
|
|
||||||
\ 'Decorator': ['@symbol', 'Identifier'],
|
|
||||||
\ 'Deprecated': ['@text.strike', 'CocDeprecatedHighlight']
|
|
||||||
\ }
|
|
||||||
for [key, value] in items(hlMap)
|
|
||||||
let ts = get(value, 0, '')
|
|
||||||
let fallback = get(value, 1, '')
|
|
||||||
execute 'hi default link CocSem'.key.' '.(coc#highlight#valid(ts) ? ts : fallback)
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
let symbolMap = {
|
|
||||||
\ 'Keyword': ['@keyword', 'Keyword'],
|
|
||||||
\ 'Namespace': ['@namespace', 'Include'],
|
|
||||||
\ 'Class': ['@constructor', 'Special'],
|
|
||||||
\ 'Method': ['@method', 'Function'],
|
|
||||||
\ 'Property': ['@property', 'Identifier'],
|
|
||||||
\ 'Text': ['@text', 'CocSymbolDefault'],
|
|
||||||
\ 'Unit': ['@unit', 'CocSymbolDefault'],
|
|
||||||
\ 'Value': ['@value', 'CocSymbolDefault'],
|
|
||||||
\ 'Snippet': ['@snippet', 'CocSymbolDefault'],
|
|
||||||
\ 'Color': ['@color', 'Float'],
|
|
||||||
\ 'Reference': ['@text.reference', 'Constant'],
|
|
||||||
\ 'Folder': ['@folder', 'CocSymbolDefault'],
|
|
||||||
\ 'File': ['@file', 'Statement'],
|
|
||||||
\ 'Module': ['@module', 'Statement'],
|
|
||||||
\ 'Package': ['@package', 'Statement'],
|
|
||||||
\ 'Field': ['@field', 'Identifier'],
|
|
||||||
\ 'Constructor': ['@constructor', 'Special'],
|
|
||||||
\ 'Enum': ['@type', 'CocSymbolDefault'],
|
|
||||||
\ 'Interface': ['@type', 'CocSymbolDefault'],
|
|
||||||
\ 'Function': ['@function', 'Function'],
|
|
||||||
\ 'Variable': ['@variable.builtin', 'Special'],
|
|
||||||
\ 'Constant': ['@constant', 'Constant'],
|
|
||||||
\ 'String': ['@string', 'String'],
|
|
||||||
\ 'Number': ['@number', 'Number'],
|
|
||||||
\ 'Boolean': ['@boolean', 'Boolean'],
|
|
||||||
\ 'Array': ['@array', 'CocSymbolDefault'],
|
|
||||||
\ 'Object': ['@object', 'CocSymbolDefault'],
|
|
||||||
\ 'Key': ['@key', 'Identifier'],
|
|
||||||
\ 'Null': ['@null', 'Type'],
|
|
||||||
\ 'EnumMember': ['@property', 'Identifier'],
|
|
||||||
\ 'Struct': ['@structure', 'Keyword'],
|
|
||||||
\ 'Event': ['@constant', 'Constant'],
|
|
||||||
\ 'Operator': ['@operator', 'Operator'],
|
|
||||||
\ 'TypeParameter': ['@parameter', 'Identifier'],
|
|
||||||
\ }
|
|
||||||
for [key, value] in items(symbolMap)
|
|
||||||
let hlGroup = coc#highlight#valid(value[0]) ? value[0] : get(value, 1, 'CocSymbolDefault')
|
|
||||||
if hlexists(hlGroup)
|
|
||||||
execute 'hi default CocSymbol'.key.' '.coc#highlight#get_hl_command(synIDtrans(hlID(hlGroup)), 'fg', '223', '#ebdbb2')
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:ShowInfo()
|
|
||||||
if coc#rpc#ready()
|
|
||||||
call coc#rpc#notify('showInfo', [])
|
|
||||||
else
|
|
||||||
let lines = []
|
|
||||||
echomsg 'coc.nvim service not started, checking environment...'
|
|
||||||
let node = get(g:, 'coc_node_path', $COC_NODE_PATH == '' ? 'node' : $COC_NODE_PATH)
|
|
||||||
if !executable(node)
|
|
||||||
call add(lines, 'Error: '.node.' is not executable!')
|
|
||||||
else
|
|
||||||
let output = trim(system(node . ' --version'))
|
|
||||||
let ms = matchlist(output, 'v\(\d\+\).\(\d\+\).\(\d\+\)')
|
|
||||||
if empty(ms) || str2nr(ms[1]) < 14 || (str2nr(ms[1]) == 14 && str2nr(ms[2]) < 14)
|
|
||||||
call add(lines, 'Error: Node version '.output.' < 14.14.0, please upgrade node.js')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
" check bundle
|
|
||||||
let file = s:root.'/build/index.js'
|
|
||||||
if !filereadable(file)
|
|
||||||
call add(lines, 'Error: javascript bundle not found, please compile code of coc.nvim by esbuild.')
|
|
||||||
endif
|
|
||||||
if !empty(lines)
|
|
||||||
botright vnew
|
|
||||||
setl filetype=nofile
|
|
||||||
call setline(1, lines)
|
|
||||||
else
|
|
||||||
if get(g:, 'coc_start_at_startup',1)
|
|
||||||
echohl MoreMsg | echon 'Service stopped for some unknown reason, try :CocStart' | echohl None
|
|
||||||
else
|
|
||||||
echohl MoreMsg | echon 'Start on startup is disabled, try :CocStart' | echohl None
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:CursorRangeFromSelected(type, ...) abort
|
|
||||||
" add range by operator
|
|
||||||
call coc#rpc#request('cursorsSelect', [bufnr('%'), 'operator', a:type])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:FormatFromSelected(type)
|
|
||||||
call CocActionAsync('formatSelected', a:type)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:CodeActionFromSelected(type)
|
|
||||||
call CocActionAsync('codeAction', a:type)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:CodeActionRefactorFromSelected(type)
|
|
||||||
call CocActionAsync('codeAction', a:type, ['refactor'] ,v:true)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
command! -nargs=0 CocOutline :call coc#rpc#notify('showOutline', [])
|
|
||||||
command! -nargs=? CocDiagnostics :call s:OpenDiagnostics(<f-args>)
|
|
||||||
command! -nargs=0 CocInfo :call s:ShowInfo()
|
|
||||||
command! -nargs=0 CocOpenLog :call coc#rpc#notify('openLog', [])
|
|
||||||
command! -nargs=0 CocDisable :call s:Disable()
|
|
||||||
command! -nargs=0 CocEnable :call s:Enable(0)
|
|
||||||
command! -nargs=0 CocConfig :call s:OpenConfig()
|
|
||||||
command! -nargs=0 CocLocalConfig :call coc#rpc#notify('openLocalConfig', [])
|
|
||||||
command! -nargs=0 CocRestart :call coc#rpc#restart()
|
|
||||||
command! -nargs=0 CocStart :call coc#rpc#start_server()
|
|
||||||
command! -nargs=0 CocPrintErrors :call coc#rpc#show_errors()
|
|
||||||
command! -nargs=1 -complete=custom,s:LoadedExtensions CocWatch :call coc#rpc#notify('watchExtension', [<f-args>])
|
|
||||||
command! -nargs=+ -complete=custom,s:SearchOptions CocSearch :call coc#rpc#notify('search', [<f-args>])
|
|
||||||
command! -nargs=+ -complete=custom,s:ExtensionList CocUninstall :call CocActionAsync('uninstallExtension', <f-args>)
|
|
||||||
command! -nargs=* -complete=custom,s:CommandList -range CocCommand :call coc#rpc#notify('runCommand', [<f-args>])
|
|
||||||
command! -nargs=* -complete=custom,coc#list#options CocList :call coc#rpc#notify('openList', [<f-args>])
|
|
||||||
command! -nargs=? -complete=custom,coc#list#names CocListResume :call coc#rpc#notify('listResume', [<f-args>])
|
|
||||||
command! -nargs=? -complete=custom,coc#list#names CocListCancel :call coc#rpc#notify('listCancel', [])
|
|
||||||
command! -nargs=? -complete=custom,coc#list#names CocPrev :call coc#rpc#notify('listPrev', [<f-args>])
|
|
||||||
command! -nargs=? -complete=custom,coc#list#names CocNext :call coc#rpc#notify('listNext', [<f-args>])
|
|
||||||
command! -nargs=? -complete=custom,coc#list#names CocFirst :call coc#rpc#notify('listFirst', [<f-args>])
|
|
||||||
command! -nargs=? -complete=custom,coc#list#names CocLast :call coc#rpc#notify('listLast', [<f-args>])
|
|
||||||
command! -nargs=0 CocUpdate :call coc#util#update_extensions(1)
|
|
||||||
command! -nargs=0 -bar CocUpdateSync :call coc#util#update_extensions()
|
|
||||||
command! -nargs=* -bar -complete=custom,s:InstallOptions CocInstall :call coc#util#install_extension([<f-args>])
|
|
||||||
|
|
||||||
call s:Enable(1)
|
|
||||||
augroup coc_dynamic_autocmd
|
|
||||||
augroup END
|
|
||||||
augroup coc_dynamic_content
|
|
||||||
augroup END
|
|
||||||
augroup coc_dynamic_option
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
" Default key-mappings for completion
|
|
||||||
if empty(mapcheck('<C-n>', 'i'))
|
|
||||||
inoremap <silent><expr> <C-n> coc#pum#visible() ? coc#pum#next(1) : "\<C-n>"
|
|
||||||
endif
|
|
||||||
if empty(mapcheck('<C-p>', 'i'))
|
|
||||||
inoremap <silent><expr> <C-p> coc#pum#visible() ? coc#pum#prev(1) : "\<C-p>"
|
|
||||||
endif
|
|
||||||
if empty(mapcheck('<down>', 'i'))
|
|
||||||
inoremap <silent><expr> <down> coc#pum#visible() ? coc#pum#next(0) : "\<down>"
|
|
||||||
endif
|
|
||||||
if empty(mapcheck('<up>', 'i'))
|
|
||||||
inoremap <silent><expr> <up> coc#pum#visible() ? coc#pum#prev(0) : "\<up>"
|
|
||||||
endif
|
|
||||||
if empty(mapcheck('<C-e>', 'i'))
|
|
||||||
inoremap <silent><expr> <C-e> coc#pum#visible() ? coc#pum#cancel() : "\<C-e>"
|
|
||||||
endif
|
|
||||||
if empty(mapcheck('<C-y>', 'i'))
|
|
||||||
inoremap <silent><expr> <C-y> coc#pum#visible() ? coc#pum#confirm() : "\<C-y>"
|
|
||||||
endif
|
|
||||||
if empty(mapcheck('<PageDown>', 'i'))
|
|
||||||
inoremap <silent><expr> <PageDown> coc#pum#visible() ? coc#pum#scroll(1) : "\<PageDown>"
|
|
||||||
endif
|
|
||||||
if empty(mapcheck('<PageUp>', 'i'))
|
|
||||||
inoremap <silent><expr> <PageUp> coc#pum#visible() ? coc#pum#scroll(0) : "\<PageUp>"
|
|
||||||
endif
|
|
||||||
|
|
||||||
vnoremap <silent> <Plug>(coc-range-select) :<C-u>call CocActionAsync('rangeSelect', visualmode(), v:true)<CR>
|
|
||||||
vnoremap <silent> <Plug>(coc-range-select-backward) :<C-u>call CocActionAsync('rangeSelect', visualmode(), v:false)<CR>
|
|
||||||
nnoremap <Plug>(coc-range-select) :<C-u>call CocActionAsync('rangeSelect', '', v:true)<CR>
|
|
||||||
nnoremap <Plug>(coc-codelens-action) :<C-u>call CocActionAsync('codeLensAction')<CR>
|
|
||||||
vnoremap <silent> <Plug>(coc-format-selected) :<C-u>call CocActionAsync('formatSelected', visualmode())<CR>
|
|
||||||
vnoremap <silent> <Plug>(coc-codeaction-selected) :<C-u>call CocActionAsync('codeAction', visualmode())<CR>
|
|
||||||
vnoremap <Plug>(coc-codeaction-refactor-selected) :<C-u>call CocActionAsync('codeAction', visualmode(), ['refactor'], v:true)<CR>
|
|
||||||
nnoremap <Plug>(coc-codeaction-selected) :<C-u>set operatorfunc=<SID>CodeActionFromSelected<CR>g@
|
|
||||||
nnoremap <Plug>(coc-codeaction-refactor-selected) :<C-u>set operatorfunc=<SID>CodeActionRefactorFromSelected<CR>g@
|
|
||||||
nnoremap <Plug>(coc-codeaction) :<C-u>call CocActionAsync('codeAction', '')<CR>
|
|
||||||
nnoremap <Plug>(coc-codeaction-line) :<C-u>call CocActionAsync('codeAction', 'currline')<CR>
|
|
||||||
nnoremap <Plug>(coc-codeaction-cursor) :<C-u>call CocActionAsync('codeAction', 'cursor')<CR>
|
|
||||||
nnoremap <Plug>(coc-codeaction-refactor) :<C-u>call CocActionAsync('codeAction', 'cursor', ['refactor'], v:true)<CR>
|
|
||||||
nnoremap <Plug>(coc-codeaction-source) :<C-u>call CocActionAsync('codeAction', '', ['source'], v:true)<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-rename) :<C-u>call CocActionAsync('rename')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-format-selected) :<C-u>set operatorfunc=<SID>FormatFromSelected<CR>g@
|
|
||||||
nnoremap <silent> <Plug>(coc-format) :<C-u>call CocActionAsync('format')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-diagnostic-info) :<C-u>call CocActionAsync('diagnosticInfo')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-diagnostic-next) :<C-u>call CocActionAsync('diagnosticNext')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-diagnostic-prev) :<C-u>call CocActionAsync('diagnosticPrevious')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-diagnostic-next-error) :<C-u>call CocActionAsync('diagnosticNext', 'error')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-diagnostic-prev-error) :<C-u>call CocActionAsync('diagnosticPrevious', 'error')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-definition) :<C-u>call CocActionAsync('jumpDefinition')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-declaration) :<C-u>call CocActionAsync('jumpDeclaration')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-implementation) :<C-u>call CocActionAsync('jumpImplementation')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-type-definition) :<C-u>call CocActionAsync('jumpTypeDefinition')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-references) :<C-u>call CocActionAsync('jumpReferences')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-references-used) :<C-u>call CocActionAsync('jumpUsed')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-openlink) :<C-u>call CocActionAsync('openLink')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-fix-current) :<C-u>call CocActionAsync('doQuickfix')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-float-hide) :<C-u>call coc#float#close_all()<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-float-jump) :<c-u>call coc#float#jump()<cr>
|
|
||||||
nnoremap <silent> <Plug>(coc-command-repeat) :<C-u>call CocAction('repeatCommand')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-refactor) :<C-u>call CocActionAsync('refactor')<CR>
|
|
||||||
|
|
||||||
nnoremap <silent> <Plug>(coc-cursors-operator) :<C-u>set operatorfunc=<SID>CursorRangeFromSelected<CR>g@
|
|
||||||
vnoremap <silent> <Plug>(coc-cursors-range) :<C-u>call CocAction('cursorsSelect', bufnr('%'), 'range', visualmode())<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-cursors-word) :<C-u>call CocAction('cursorsSelect', bufnr('%'), 'word', 'n')<CR>
|
|
||||||
nnoremap <silent> <Plug>(coc-cursors-position) :<C-u>call CocAction('cursorsSelect', bufnr('%'), 'position', 'n')<CR>
|
|
||||||
|
|
||||||
vnoremap <silent> <Plug>(coc-funcobj-i) :<C-U>call CocAction('selectSymbolRange', v:true, visualmode(), ['Method', 'Function'])<CR>
|
|
||||||
vnoremap <silent> <Plug>(coc-funcobj-a) :<C-U>call CocAction('selectSymbolRange', v:false, visualmode(), ['Method', 'Function'])<CR>
|
|
||||||
onoremap <silent> <Plug>(coc-funcobj-i) :<C-U>call CocAction('selectSymbolRange', v:true, '', ['Method', 'Function'])<CR>
|
|
||||||
onoremap <silent> <Plug>(coc-funcobj-a) :<C-U>call CocAction('selectSymbolRange', v:false, '', ['Method', 'Function'])<CR>
|
|
||||||
|
|
||||||
vnoremap <silent> <Plug>(coc-classobj-i) :<C-U>call CocAction('selectSymbolRange', v:true, visualmode(), ['Interface', 'Struct', 'Class'])<CR>
|
|
||||||
vnoremap <silent> <Plug>(coc-classobj-a) :<C-U>call CocAction('selectSymbolRange', v:false, visualmode(), ['Interface', 'Struct', 'Class'])<CR>
|
|
||||||
onoremap <silent> <Plug>(coc-classobj-i) :<C-U>call CocAction('selectSymbolRange', v:true, '', ['Interface', 'Struct', 'Class'])<CR>
|
|
||||||
onoremap <silent> <Plug>(coc-classobj-a) :<C-U>call CocAction('selectSymbolRange', v:false, '', ['Interface', 'Struct', 'Class'])<CR>
|
|
|
@ -1,3 +0,0 @@
|
||||||
als
|
|
||||||
edn
|
|
||||||
esy
|
|
|
@ -1,17 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
tab_width = 8
|
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
charset = utf-8
|
|
||||||
|
|
||||||
[*.lua]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
[{Makefile,**/Makefile,runtime/doc/*.txt}]
|
|
||||||
indent_style = tab
|
|
||||||
indent_size = 8
|
|
|
@ -1,77 +0,0 @@
|
||||||
name: Bug report
|
|
||||||
description: Report a problem in nvim-lspconfig
|
|
||||||
labels: [bug]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Before reporting: search existing issues and ensure you are running the latest nightly of neovim and the latest version of nvim-lspconfig. Note that this repository implements configuration and initialization of language servers. Implementation of the language server spec itself is located in the neovim core repository.
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: "Description"
|
|
||||||
description: "A short description of the problem you are reporting."
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: "Neovim version"
|
|
||||||
description: "Output of `nvim --version`"
|
|
||||||
placeholder: |
|
|
||||||
NVIM v0.6.0-dev+209-g0603eba6e
|
|
||||||
Build type: Release
|
|
||||||
LuaJIT 2.1.0-beta3
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: "Nvim-lspconfig version"
|
|
||||||
description: "Commit hash"
|
|
||||||
placeholder: 1344a859864d4e6d23d3f3adf56d49e6386ec0d2
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: "Operating system and version"
|
|
||||||
placeholder: "macOS 11.5"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: "Affected language servers"
|
|
||||||
description: "If this issue is specific to one or more language servers, list them here. If not, write 'all'."
|
|
||||||
placeholder: "clangd"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: "Steps to reproduce"
|
|
||||||
description: "Steps to reproduce using the minimal config provided below."
|
|
||||||
placeholder: |
|
|
||||||
1. `nvim -nu minimal.lua`
|
|
||||||
2. ...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: "Actual behavior"
|
|
||||||
description: "Observed behavior."
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: "Expected behavior"
|
|
||||||
description: "A description of the behavior you expected."
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: "Minimal config"
|
|
||||||
render: Lua
|
|
||||||
description: "You can download a minimal_init.lua via `curl -fLO https://raw.githubusercontent.com/neovim/nvim-lspconfig/master/test/minimal_init.lua`. Then edit it to include your language server and add necessary configuration and paste it here."
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: "LSP log"
|
|
||||||
description: "If not using the `minimal_init.lua`, add `vim.lsp.set_log_level('debug')` to your LSP setup, upload the log file at `$HOME/.cache/nvim/lsp.log` to https://gist.github.com, and paste the link here."
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
blank_issues_enabled: false
|
|
||||||
contact_links:
|
|
||||||
- name: Question
|
|
||||||
url: https://neovim.discourse.group/c/language-server-protocol-lsp/7
|
|
||||||
about: Usage questions and support requests are answered in the Neovim Discourse
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
name: Feature request
|
|
||||||
description: Request a feature in nvim-lspconfig
|
|
||||||
labels: [enhancement]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Before requesting a new feature, search existing issues. Implementation of the language server protocol itself is located in the neovim core repository, and general feature requests may be better suited for core.
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: "Language server"
|
|
||||||
description: "Is the feature specific to a language server? If so, which one(s)?"
|
|
||||||
placeholder: "clangd"
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: "Requested feature"
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: "Other clients which have this feature"
|
|
||||||
description: "Is the feature already implemented in another LSP client for (Neo)Vim? If so, which one(s)?"
|
|
||||||
placeholder: "vim-lsp"
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
---
|
|
||||||
name: Pull Request
|
|
||||||
about: Submit a pull request
|
|
||||||
title: ''
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
If you want to make changes to the README.md, do so in scripts/README_template.md.
|
|
||||||
The CONFIG.md is auto-generated with all the options from the various LSP configuration;
|
|
||||||
do not edit it manually
|
|
||||||
-->
|
|
|
@ -1,16 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
REF_BRANCH="$1"
|
|
||||||
PR_BRANCH="$2"
|
|
||||||
|
|
||||||
# checks for added lines that contain search pattern and prints them
|
|
||||||
SEARCH_PATTERN="(dirname|fn\.cwd)"
|
|
||||||
|
|
||||||
if git diff --pickaxe-all -U0 -G "${SEARCH_PATTERN}" "${REF_BRANCH}" "${PR_BRANCH}" -- '*.lua' | grep -Ev '(configs|utils)\.lua$' | grep -E "^\+.*${SEARCH_PATTERN}" ; then
|
|
||||||
echo
|
|
||||||
echo 'String "dirname" found. There is a high risk that this might contradict the directive:'
|
|
||||||
echo '"Do not add vim.fn.cwd or util.path.dirname in root_dir".'
|
|
||||||
echo "see: https://github.com/neovim/nvim-lspconfig/blob/master/CONTRIBUTING.md#adding-a-server-to-lspconfig."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
|
@ -1,21 +0,0 @@
|
||||||
name: "Close changes to config"
|
|
||||||
on: [pull_request_target]
|
|
||||||
jobs:
|
|
||||||
close-changes:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
env:
|
|
||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
- run: |
|
|
||||||
if ! git diff origin/$GITHUB_BASE_REF...$(git branch --show-current) --exit-code -- doc/server_configurations.md doc/server_configurations.txt; then
|
|
||||||
gh pr close $PR_NUMBER
|
|
||||||
gh pr comment $PR_NUMBER --body "This pull request has been automatically closed. Changes to server_configurations.md aren't allowed - edit the lua source file instead. Consult https://github.com/neovim/nvim-lspconfig/blob/master/CONTRIBUTING.md#generating-docs."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
|
@ -1,21 +0,0 @@
|
||||||
name: codespell
|
|
||||||
on: [pull_request]
|
|
||||||
jobs:
|
|
||||||
codespell:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
|
||||||
uses: actions/setup-python@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
python-version: ${{ matrix.python-version }}
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install codespell
|
|
||||||
- name: Use codespell
|
|
||||||
run: |
|
|
||||||
codespell --quiet-level=2 --check-hidden --skip=./doc/server_configurations.md,./doc/server_configurations.txt --ignore-words=.codespellignorewords || exit
|
|
|
@ -1,12 +0,0 @@
|
||||||
on: [pull_request]
|
|
||||||
jobs:
|
|
||||||
lint-commits:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- run: npm install --save-dev @commitlint/{cli,config-conventional}
|
|
||||||
- run: |
|
|
||||||
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
|
|
||||||
- run: npx commitlint --from HEAD~1 --to HEAD --verbose
|
|
|
@ -1,32 +0,0 @@
|
||||||
name: docgen
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docgen:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: rhysd/action-setup-vim@v1
|
|
||||||
with:
|
|
||||||
neovim: true
|
|
||||||
version: nightly
|
|
||||||
- name: Run docgen
|
|
||||||
run: |
|
|
||||||
scripts/docgen.sh
|
|
||||||
- name: Commit changes
|
|
||||||
env:
|
|
||||||
COMMIT_MSG: |
|
|
||||||
docs: update server_configurations.md
|
|
||||||
skip-checks: true
|
|
||||||
run: |
|
|
||||||
git config user.name github-actions
|
|
||||||
git config user.email github-actions@github.com
|
|
||||||
git add doc/server_configurations.md doc/server_configurations.txt
|
|
||||||
# Only commit and push if we have changes
|
|
||||||
git diff --quiet && git diff --staged --quiet || (git commit -m "${COMMIT_MSG}"; git push)
|
|
|
@ -1,28 +0,0 @@
|
||||||
name: Close Non-Feature Branches
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
close-master-branch:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
env:
|
|
||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
|
|
||||||
- name: Close if master branch
|
|
||||||
if: ${{ github.head_ref == 'master' }}
|
|
||||||
run: |
|
|
||||||
gh pr close $PR_NUMBER
|
|
||||||
gh pr comment $PR_NUMBER --body "This pull request has been automatically closed. Please develop on a feature branch. Thank you."
|
|
||||||
exit 1
|
|
|
@ -1,54 +0,0 @@
|
||||||
name: lint
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout sources
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Setup luacheck
|
|
||||||
run: |
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install -y lua5.1 luarocks
|
|
||||||
sudo luarocks install luacheck
|
|
||||||
|
|
||||||
- name: Setup selene
|
|
||||||
run: |
|
|
||||||
wget "https://github.com/Kampfkarren/selene/releases/download/$VERSION/selene-$VERSION-linux.zip"
|
|
||||||
echo "$SHA256_CHECKSUM selene-$VERSION-linux.zip" > "selene-$VERSION-linux.zip.checksum"
|
|
||||||
sha256sum --check "selene-$VERSION-linux.zip.checksum"
|
|
||||||
unzip "selene-$VERSION-linux.zip"
|
|
||||||
install -Dp selene "$HOME/.local/bin/selene"
|
|
||||||
|
|
||||||
echo "::add-matcher::.github/workflows/problem_matchers/selene.json"
|
|
||||||
env:
|
|
||||||
VERSION: "0.15.0"
|
|
||||||
SHA256_CHECKSUM: "8ff9272170158fbd9c1af38206ecadc894dc456665dc9bd9f0d43a26e5e8f1af"
|
|
||||||
|
|
||||||
- name: Add $HOME/.local/bin to $PATH
|
|
||||||
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Run luacheck
|
|
||||||
run: luacheck lua/* test/*
|
|
||||||
|
|
||||||
- name: Run selene
|
|
||||||
run: selene --display-style=quiet .
|
|
||||||
|
|
||||||
style-lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout sources
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Lint with stylua
|
|
||||||
uses: JohnnyMorganz/stylua-action@1.0.0
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
# CLI arguments
|
|
||||||
args: --check .
|
|
|
@ -1,30 +0,0 @@
|
||||||
{
|
|
||||||
"problemMatcher": [
|
|
||||||
{
|
|
||||||
"owner": "selene-error",
|
|
||||||
"severity": "error",
|
|
||||||
"pattern": [
|
|
||||||
{
|
|
||||||
"regexp": "^([^:]+):(\\d+):(\\d+):\\serror(.*)$",
|
|
||||||
"file": 1,
|
|
||||||
"line": 2,
|
|
||||||
"column": 3,
|
|
||||||
"message": 4
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"owner": "selene-warning",
|
|
||||||
"severity": "warning",
|
|
||||||
"pattern": [
|
|
||||||
{
|
|
||||||
"regexp": "^([^:]+):(\\d+):(\\d+):\\swarning(.*)$",
|
|
||||||
"file": 1,
|
|
||||||
"line": 2,
|
|
||||||
"column": 3,
|
|
||||||
"message": 4
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
name: "Dirname Checker"
|
|
||||||
on: [pull_request]
|
|
||||||
jobs:
|
|
||||||
disallowed-root-checker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- run: |
|
|
||||||
if ! bash .github/ci/run_sanitizer.sh ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
|
@ -1,53 +0,0 @@
|
||||||
name: test
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
ubuntu:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout sources
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Setup build dependencies
|
|
||||||
run: |
|
|
||||||
sudo apt update &&
|
|
||||||
sudo apt install -y ninja-build \
|
|
||||||
gettext \
|
|
||||||
libtool \
|
|
||||||
libtool-bin \
|
|
||||||
autoconf \
|
|
||||||
automake \
|
|
||||||
cmake \
|
|
||||||
g++ \
|
|
||||||
pkg-config \
|
|
||||||
unzip \
|
|
||||||
gperf \
|
|
||||||
libluajit-5.1-dev \
|
|
||||||
libunibilium-dev \
|
|
||||||
libmsgpack-dev \
|
|
||||||
libtermkey-dev \
|
|
||||||
libvterm-dev \
|
|
||||||
libjemalloc-dev \
|
|
||||||
lua5.1 \
|
|
||||||
lua-lpeg \
|
|
||||||
lua-mpack \
|
|
||||||
lua-bitop
|
|
||||||
- name: Run test with building Nvim
|
|
||||||
run: |
|
|
||||||
make test
|
|
||||||
macos:
|
|
||||||
runs-on: macos-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout sources
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
- name: Setup build dependencies
|
|
||||||
run: |
|
|
||||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" &&
|
|
||||||
brew install ninja libtool automake pkg-config gettext
|
|
||||||
- name: Run test with building Nvim
|
|
||||||
run: |
|
|
||||||
make test
|
|
||||||
|
|
3
pack/acp/opt/nvim-lspconfig/.gitignore
vendored
3
pack/acp/opt/nvim-lspconfig/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
||||||
.luacheckcache
|
|
||||||
neovim
|
|
||||||
doc/tags
|
|
|
@ -1,14 +0,0 @@
|
||||||
-- vim: ft=lua tw=80
|
|
||||||
|
|
||||||
-- Rerun tests only if their modification time changed.
|
|
||||||
cache = true
|
|
||||||
|
|
||||||
ignore = {
|
|
||||||
"212", -- Unused argument, In the case of callback function, _arg_name is easier to understand than _, so this option is set to off.
|
|
||||||
"631", -- max_line_length, vscode pkg URL is too long
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Global objects defined by the C code
|
|
||||||
read_globals = {
|
|
||||||
"vim",
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
column_width = 120
|
|
||||||
line_endings = "Unix"
|
|
||||||
indent_type = "Spaces"
|
|
||||||
indent_width = 2
|
|
||||||
quote_style = "AutoPreferSingle"
|
|
||||||
no_call_parentheses = true
|
|
|
@ -1 +0,0 @@
|
||||||
Notice: CONFIG.md was moved to [doc/server_configurations.md](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md). This notice will be removed after the release of neovim 0.6.
|
|
|
@ -1,109 +0,0 @@
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- [Neovim](https://neovim.io/) 0.6 or later
|
|
||||||
- Lint task requires [luacheck](https://github.com/luarocks/luacheck#installation) and [stylua](https://github.com/JohnnyMorganz/StyLua). If using nix, you can use `nix develop` to install these to a local nix shell.
|
|
||||||
- Documentation is generated by `scripts/docgen.lua`.
|
|
||||||
- Only works on linux and macOS
|
|
||||||
|
|
||||||
## Scope of lspconfig
|
|
||||||
|
|
||||||
The point of lspconfig is to provide the minimal configuration necessary for a server to act in compliance with the language server protocol. In general, if a server requires custom client-side commands or off-spec handlers, then the server configuration should be added *without* those in lspconfig and receive a dedicated plugin such as nvim-jdtls, nvim-metals, etc.
|
|
||||||
|
|
||||||
## Pull requests (PRs)
|
|
||||||
|
|
||||||
- To avoid duplicate work, create a draft pull request.
|
|
||||||
- Avoid cosmetic changes to unrelated files in the same commit.
|
|
||||||
- Use a [feature branch](https://www.atlassian.com/git/tutorials/comparing-workflows) instead of the master branch.
|
|
||||||
- Use a **rebase workflow** for small PRs.
|
|
||||||
- After addressing review comments, it's fine to rebase and force-push.
|
|
||||||
|
|
||||||
## Adding a server to lspconfig
|
|
||||||
|
|
||||||
The general form of adding a new language server is to start with a minimal skeleton. This includes populated the `config` table with a `default_config` and `docs` table.
|
|
||||||
|
|
||||||
When choosing a server name, convert all dashes (`-`) to underscores (`_`) If the name of the server is a unique name (`pyright`, `clangd`) or a commonly used abbreviation (`zls`), prefer this as the server name. If the server instead follows the pattern x-language-server, prefer the convention `x_ls` (`jsonnet_ls`).
|
|
||||||
|
|
||||||
`default_config` should include, at minimum the following:
|
|
||||||
* `cmd`: a list which includes the executable name as the first entry, with arguments constituting subsequent list elements (`--stdio` is common).
|
|
||||||
Note that Windows has a limitation when it comes to directly invoking a server that's installed by `npm` or `gem`, so it requires additional handling.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local bin_name = 'typescript-language-server'
|
|
||||||
local cmd = { bin_name, '--stdio' }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name, '--stdio' }
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
* `filetypes`: a list for filetypes a
|
|
||||||
* `root_dir`: a function (or function handle) which returns the root of the project used to determine if lspconfig should launch a new language server, or attach a previously launched server when you open a new buffer matching the filetype of the server. Note, lspconfig does not offer a dedicated single file mode (this is not codified in the spec). Do not add `vim.fn.cwd` or `util.path.dirname` in `root_dir`. A future version of lspconfig will provide emulation of a single file mode until this is formally codified in the specification. A good fallback is `util.find_git_ancestor`, see other configurations for examples.
|
|
||||||
|
|
||||||
Additionally, the following options are often added:
|
|
||||||
|
|
||||||
* `init_options`: a table sent during initialization, corresponding to initializationOptions sent in [initializeParams](https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#initializeParams) as part of the first request sent from client to server during startup.
|
|
||||||
* `settings`: a table sent during [`workspace/didChangeConfiguration`](https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#didChangeConfigurationParams) shortly after server initialization. This is an undocumented convention for most language servers. There is often some duplication with initOptions.
|
|
||||||
|
|
||||||
A minimal example for adding a new language server is shown below for `pyright`, a python language server included in lspconfig:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
-- Only `configs` must be required, util is optional if you are using the root resolver functions, which is usually the case.
|
|
||||||
local configs = require 'lspconfig.configs'
|
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
-- Having server name defined here is the convention, this is often times also the first entry in the `cmd` table.
|
|
||||||
local server_name = 'pyright'
|
|
||||||
|
|
||||||
configs[server_name] = {
|
|
||||||
default_config = {
|
|
||||||
-- This should be executable on the command line, arguments (such as `--stdio`) are additional entries in the list.
|
|
||||||
cmd = { 'pyright-langserver' },
|
|
||||||
-- These are the filetypes that the server will either attach or start in response to opening. The user must have a filetype plugin matching the filetype, either via the built-in runtime files or installed via plugin.
|
|
||||||
filetypes = { 'python' },
|
|
||||||
-- The root directory that lspconfig uses to determine if it should start a new language server, or attach the current buffer to a previously running language server.
|
|
||||||
root_dir = util.find_git_ancestor
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
-- extremely important: the package.json that contains language server settings, not the package.json that contains javascript dependencies for the project, or the package.json that contains vscode specific settings
|
|
||||||
package_json = 'https://raw.githubusercontent.com/microsoft/pyright/master/packages/vscode-pyright/package.json',
|
|
||||||
|
|
||||||
-- The description should include at minimum the link to the github project, and ideally the steps to install the language server.
|
|
||||||
description = [[
|
|
||||||
https://github.com/microsoft/pyright
|
|
||||||
|
|
||||||
`pyright`, a static type checker and language server for python
|
|
||||||
|
|
||||||
`pyright` can be installed via `npm`
|
|
||||||
`npm install -g pyright`
|
|
||||||
]],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Commit style
|
|
||||||
|
|
||||||
lspconfig, like neovim core, follows the [conventional commit style](https://www.conventionalcommits.org/en/v1.0.0-beta.2/) please submit your commits accordingly. Generally commits will be of the form:
|
|
||||||
|
|
||||||
```
|
|
||||||
feat: add lua-language-server support
|
|
||||||
fix(lua-language-server): update root directory pattern
|
|
||||||
docs: update README.md
|
|
||||||
```
|
|
||||||
|
|
||||||
with the commit body containing additional details.
|
|
||||||
|
|
||||||
## Lint
|
|
||||||
|
|
||||||
PRs are checked with [luacheck](https://github.com/mpeterv/luacheck), [StyLua](https://github.com/JohnnyMorganz/StyLua) and [selene](https://github.com/Kampfkarren/selene). Please run the linter locally before submitting a PR:
|
|
||||||
|
|
||||||
make lint
|
|
||||||
|
|
||||||
## Generating docs
|
|
||||||
|
|
||||||
Github Actions automatically generates `server_configurations.md`. Only modify `scripts/README_template.md` or the `docs` table in the server config (the lua file). Do not modify `server_configurations.md` directly.
|
|
||||||
|
|
||||||
To preview the generated `server_configurations.md` locally, run `scripts/docgen.lua` from
|
|
||||||
`nvim` (from the project root):
|
|
||||||
|
|
||||||
nvim -R -Es +'set rtp+=$PWD' +'luafile scripts/docgen.lua'
|
|
|
@ -1,183 +0,0 @@
|
||||||
Copyright Neovim contributors. All rights reserved.
|
|
||||||
|
|
||||||
nvim-lsp is licensed under the terms of the Apache 2.0 license.
|
|
||||||
|
|
||||||
nvim-lsp's license follows:
|
|
||||||
|
|
||||||
====
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
|
@ -1,12 +0,0 @@
|
||||||
test:
|
|
||||||
sh ./scripts/run_test.sh
|
|
||||||
|
|
||||||
lint:
|
|
||||||
@printf "\nRunning luacheck\n"
|
|
||||||
luacheck lua/* test/*
|
|
||||||
@printf "\nRunning selene\n"
|
|
||||||
selene --display-style=quiet .
|
|
||||||
@printf "\nRunning stylua\n"
|
|
||||||
stylua --check .
|
|
||||||
|
|
||||||
.PHONY: test lint
|
|
|
@ -1,209 +0,0 @@
|
||||||
# lspconfig
|
|
||||||
|
|
||||||
A [collection of common configurations](doc/server_configurations.md) for Neovim's built-in [language server client](https://neovim.io/doc/user/lsp.html).
|
|
||||||
|
|
||||||
This plugin allows for declaratively configuring, launching, and initializing language servers you have installed on your system.
|
|
||||||
**Disclaimer: Language server configurations are provided on a best-effort basis and are community-maintained. See [contributions](#contributions).**
|
|
||||||
|
|
||||||
`lspconfig` has extensive help documentation, see `:help lspconfig`.
|
|
||||||
|
|
||||||
# LSP overview
|
|
||||||
|
|
||||||
Neovim supports the Language Server Protocol (LSP), which means it acts as a client to language servers and includes a Lua framework `vim.lsp` for building enhanced LSP tools. LSP facilitates features like:
|
|
||||||
|
|
||||||
- go-to-definition
|
|
||||||
- find-references
|
|
||||||
- hover
|
|
||||||
- completion
|
|
||||||
- rename
|
|
||||||
- format
|
|
||||||
- refactor
|
|
||||||
|
|
||||||
Neovim provides an interface for all of these features, and the language server client is designed to be highly extensible to allow plugins to integrate language server features which are not yet present in Neovim core such as [**auto**-completion](https://github.com/neovim/nvim-lspconfig/wiki/Autocompletion) (as opposed to manual completion with omnifunc) and [snippet integration](https://github.com/neovim/nvim-lspconfig/wiki/Snippets).
|
|
||||||
|
|
||||||
These features are not implemented in this repo, but in Neovim core. See `:help lsp` for more details.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
* Requires [Neovim v0.6.0](https://github.com/neovim/neovim/releases/tag/v0.6.0) or [Nightly](https://github.com/neovim/neovim/releases/tag/nightly). Update Neovim and 'lspconfig' before reporting an issue.
|
|
||||||
|
|
||||||
* Install 'lspconfig' like any other Vim plugin, e.g. with [vim-plug](https://github.com/junegunn/vim-plug):
|
|
||||||
|
|
||||||
```vim
|
|
||||||
Plug 'neovim/nvim-lspconfig'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Quickstart
|
|
||||||
|
|
||||||
1. Install a language server, e.g. [pyright](doc/server_configurations.md#pyright)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm i -g pyright
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Add the language server setup to your init.vim. The server name must match those found in the table of contents in [server_configurations.md](doc/server_configurations.md). This list is also accessible via `:help lspconfig-server-configurations`.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
lua << EOF
|
|
||||||
require'lspconfig'.pyright.setup{}
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Create a project, this project must contain a file matching the root directory trigger. See [Automatically launching language servers](#Automatically-launching-language-servers) for additional info.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir test_python_project
|
|
||||||
cd test_python_project
|
|
||||||
git init
|
|
||||||
touch main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Launch neovim, the language server will now be attached and providing diagnostics (see `:LspInfo`)
|
|
||||||
|
|
||||||
```
|
|
||||||
nvim main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
5. See [Keybindings and completion](#Keybindings-and-completion) for mapping useful functions and enabling omnifunc completion
|
|
||||||
|
|
||||||
## Automatically launching language servers
|
|
||||||
|
|
||||||
In order to automatically launch a language server, 'lspconfig' searches up the directory tree from your current buffer to find a file matching the `root_dir` pattern defined in each server's configuration. For [pyright](doc/server_configurations.md#pyright), this is any directory containing ".git", "setup.py", "setup.cfg", "pyproject.toml", or "requirements.txt").
|
|
||||||
|
|
||||||
Language servers require each project to have a `root` in order to provide completion and search across symbols that may not be defined in your current file, and to avoid having to index your entire filesystem on each startup.
|
|
||||||
|
|
||||||
## Enabling additional language servers
|
|
||||||
|
|
||||||
Enabling most language servers is as easy as installing the language server, ensuring it is on your PATH, and adding the following to your config:
|
|
||||||
|
|
||||||
```vim
|
|
||||||
lua << EOF
|
|
||||||
require'lspconfig'.rust_analyzer.setup{}
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
For a full list of servers, see [server_configurations.md](doc/server_configurations.md) or `:help lspconfig-server-configurations`. This document contains installation instructions and additional, optional, customization suggestions for each language server. For some servers that are not on your system path (e.g., `jdtls`, `elixirls`), you will be required to manually add `cmd` as an entry in the table passed to `setup`. Most language servers can be installed in less than a minute.
|
|
||||||
|
|
||||||
## Keybindings and completion
|
|
||||||
|
|
||||||
'lspconfig' does not map keybindings or enable completion by default. Manual, triggered completion can be provided by neovim's built-in omnifunc. For autocompletion, a general purpose [autocompletion plugin](https://github.com/neovim/nvim-lspconfig/wiki/Autocompletion) is required. The following example configuration provides suggested keymaps for the most commonly used language server functions, and manually triggered completion with omnifunc (\<c-x\>\<c-o\>).
|
|
||||||
Note: **you must pass the defined `on_attach` as an argument to every `setup {}` call** and **the keybindings in `on_attach` only take effect after the language server has started (attached to the current buffer)**.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
lua << EOF
|
|
||||||
local nvim_lsp = require('lspconfig')
|
|
||||||
|
|
||||||
-- Use an on_attach function to only map the following keys
|
|
||||||
-- after the language server attaches to the current buffer
|
|
||||||
local on_attach = function(client, bufnr)
|
|
||||||
local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
|
|
||||||
local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end
|
|
||||||
|
|
||||||
-- Enable completion triggered by <c-x><c-o>
|
|
||||||
buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
|
|
||||||
|
|
||||||
-- Mappings.
|
|
||||||
local opts = { noremap=true, silent=true }
|
|
||||||
|
|
||||||
-- See `:help vim.lsp.*` for documentation on any of the below functions
|
|
||||||
buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
|
|
||||||
buf_set_keymap('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
|
|
||||||
buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
|
|
||||||
buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>', opts)
|
|
||||||
buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>e', '<cmd>lua vim.diagnostic.open_float()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '[d', '<cmd>lua vim.diagnostic.goto_prev()<CR>', opts)
|
|
||||||
buf_set_keymap('n', ']d', '<cmd>lua vim.diagnostic.goto_next()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>q', '<cmd>lua vim.diagnostic.setloclist()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>f', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Use a loop to conveniently call 'setup' on multiple servers and
|
|
||||||
-- map buffer local keybindings when the language server attaches
|
|
||||||
local servers = { 'pyright', 'rust_analyzer', 'tsserver' }
|
|
||||||
for _, lsp in ipairs(servers) do
|
|
||||||
nvim_lsp[lsp].setup {
|
|
||||||
on_attach = on_attach,
|
|
||||||
flags = {
|
|
||||||
debounce_text_changes = 150,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
The `on_attach` hook is used to only activate the bindings after the language server attaches to the current buffer.
|
|
||||||
|
|
||||||
## Debugging
|
|
||||||
|
|
||||||
If you have an issue with 'lspconfig', the first step is to reproduce with a [minimal configuration](https://github.com/neovim/nvim-lspconfig/blob/master/test/minimal_init.lua).
|
|
||||||
|
|
||||||
The most common reasons a language server does not start or attach are:
|
|
||||||
|
|
||||||
1. The language server is not installed. 'lspconfig' does not install language servers for you. You should be able to run the `cmd` defined in each server's lua module from the command line and see that the language server starts. If the `cmd` is an executable name, ensure it is on your path.
|
|
||||||
|
|
||||||
2. Not triggering root detection. The language server will only start if it is opened in a directory, or child directory, containing a file which signals the *root* of the project. Most of the time, this is a `.git` folder, but each server defines the root config in the lua file. See [server_configurations.md](doc/server_configurations.md) or the source for the list of root directories.
|
|
||||||
|
|
||||||
3. Misconfiguration. You must pass `on_attach` and `capabilities` for **each** `setup {}` if you want these to take effect. You must also **not call `setup {}` twice for the same server**. The second call to `setup {}` will overwrite the first.
|
|
||||||
|
|
||||||
:LspInfo provides a handy overview of your active and configured language servers. Note, that it will not report any configuration changes applied in `on_new_config`.
|
|
||||||
|
|
||||||
Before reporting a bug, check your logs and the output of `:LspInfo`. Add the following to your init.vim to enable logging:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
lua << EOF
|
|
||||||
vim.lsp.set_log_level("debug")
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
Attempt to run the language server, and open the log with:
|
|
||||||
```
|
|
||||||
:lua vim.cmd('e'..vim.lsp.get_log_path())
|
|
||||||
```
|
|
||||||
Most of the time, the reason for failure is present in the logs.
|
|
||||||
|
|
||||||
## Built-in commands
|
|
||||||
|
|
||||||
* `:LspInfo` shows the status of active and configured language servers.
|
|
||||||
|
|
||||||
The following support tab-completion for all arguments:
|
|
||||||
|
|
||||||
* `:LspStart <config_name>` Start the requested server name. Will only successfully start if the command detects a root directory matching the current config. Pass `autostart = false` to your `.setup{}` call for a language server if you would like to launch clients solely with this command. Defaults to all servers matching current buffer filetype.
|
|
||||||
* `:LspStop <client_id>` Defaults to stopping all buffer clients.
|
|
||||||
* `:LspRestart <client_id>` Defaults to restarting all buffer clients.
|
|
||||||
|
|
||||||
## The wiki
|
|
||||||
|
|
||||||
Please see the [wiki](https://github.com/neovim/nvim-lspconfig/wiki) for additional topics, including:
|
|
||||||
|
|
||||||
* [Installing language servers automatically](https://github.com/neovim/nvim-lspconfig/wiki/Installing-language-servers-automatically)
|
|
||||||
* [Snippets support](https://github.com/neovim/nvim-lspconfig/wiki/Snippets)
|
|
||||||
* [Project local settings](https://github.com/neovim/nvim-lspconfig/wiki/Project-local-settings)
|
|
||||||
* [Recommended plugins for enhanced language server features](https://github.com/neovim/nvim-lspconfig/wiki/Language-specific-plugins)
|
|
||||||
|
|
||||||
## Contributions
|
|
||||||
|
|
||||||
If you are missing a language server on the list in [server_configurations.md](doc/server_configurations.md), contributing
|
|
||||||
a new configuration for it would be appreciated. You can follow these steps:
|
|
||||||
|
|
||||||
1. Read [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
||||||
|
|
||||||
2. Choose a language from [the coc.nvim wiki](https://github.com/neoclide/coc.nvim/wiki/Language-servers) or
|
|
||||||
[emacs-lsp](https://github.com/emacs-lsp/lsp-mode#supported-languages).
|
|
||||||
|
|
||||||
3. Create a new file at `lua/lspconfig/SERVER_NAME.lua`.
|
|
||||||
|
|
||||||
- Copy an [existing config](https://github.com/neovim/nvim-lspconfig/blob/master/lua/lspconfig/server_configurations/)
|
|
||||||
to get started. Most configs are simple. For an extensive example see
|
|
||||||
[texlab.lua](https://github.com/neovim/nvim-lspconfig/blob/master/lua/lspconfig/server_configurations/texlab.lua).
|
|
||||||
|
|
||||||
4. Ask questions on our [Discourse](https://neovim.discourse.group/c/7-category/7) or in the [Neovim Gitter](https://gitter.im/neovim/neovim).
|
|
||||||
|
|
||||||
You can also help out by testing [PRs with the `needs-testing`](https://github.com/neovim/nvim-lspconfig/issues?q=is%3Apr+is%3Aopen+label%3Aneeds-testing) label) that affect language servers you use regularly.
|
|
|
@ -1,648 +0,0 @@
|
||||||
*lspconfig.txt* For Nvim version 0.5.1+ Last change: 2021 Nov 7
|
|
||||||
==============================================================================
|
|
||||||
TABLE OF CONTENTS *lspconfig-toc*
|
|
||||||
|
|
||||||
1. Introduction (|lspconfig|)
|
|
||||||
2. LSP overview (|lspconfig-lsp|)
|
|
||||||
3. Quickstart (|lspconfig-quickstart|)
|
|
||||||
4. Setup {} (|lspconfig-setup|)
|
|
||||||
5. Global defaults (|lspconfig-global-defaults|)
|
|
||||||
6. Server configurations (|lspconfig-configurations|)
|
|
||||||
6a. Adding servers (|lspconfig-adding-servers|)
|
|
||||||
7. Root directories (|lspconfig-root-detection|)
|
|
||||||
7a. Advanced detection (|lspconfig-root-advanced|)
|
|
||||||
7b. Single file support (|lspconfig-single-file-support|)
|
|
||||||
8. Commands (|lspconfig-commands|)
|
|
||||||
9. Keybindings (|lspconfig-keybindings|)
|
|
||||||
10. Completion (|lspconfig-completion|)
|
|
||||||
11. Debugging (|lspconfig-debugging|)
|
|
||||||
12. Logging (|lspconfig-logging|)
|
|
||||||
13. Scope (|lspconfig-scope|)
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTRODUCTION *lspconfig*
|
|
||||||
|
|
||||||
`lspconfig` is a collection of community contributed configurations for the
|
|
||||||
built-in language server client in Neovim core. This plugin provides four
|
|
||||||
primary functionalities:
|
|
||||||
|
|
||||||
- default launch commands, initialization options, and settings for each
|
|
||||||
server
|
|
||||||
- a root directory resolver which attempts to detect the root of your project
|
|
||||||
- an autocommand mapping that either launches a new language server or
|
|
||||||
attempts to attach a language server to each opened buffer if it falls
|
|
||||||
under a tracked project
|
|
||||||
- utility commands such as LspInfo, LspStart, LspStop, and LspRestart for
|
|
||||||
managing language server instances
|
|
||||||
|
|
||||||
`lspconfig` is not required to use the built-in client, it is only one front-end
|
|
||||||
interface for when a language server specific plugin is not available.
|
|
||||||
|
|
||||||
See |lspconfig-server-configurations| by typing `K` over it for the complete
|
|
||||||
list of language servers configurations.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
LSP OVERVIEW *lspconfig-lsp*
|
|
||||||
|
|
||||||
Nvim supports the Language Server Protocol (LSP) via the built-in language
|
|
||||||
server client. LSP facilitates many features, some of which include:
|
|
||||||
|
|
||||||
- go-to-definition
|
|
||||||
- find-references
|
|
||||||
- hover
|
|
||||||
- completion
|
|
||||||
- rename
|
|
||||||
- format
|
|
||||||
- refactor
|
|
||||||
|
|
||||||
These features are implemented in Neovim core, not `lspconfig`. See `:help lsp`
|
|
||||||
for more details.
|
|
||||||
|
|
||||||
NOTE: Feature availability depends on the implementation details of the
|
|
||||||
server. A server may implement only a subset of these features. Always
|
|
||||||
consult the server documentation before filing a bug report on a missing
|
|
||||||
feature.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
QUICKSTART *lspconfig-quickstart*
|
|
||||||
|
|
||||||
- ensure the server is installed and executable from the command line
|
|
||||||
|
|
||||||
- enable the server in your Neovim configuration (Lua example):
|
|
||||||
>
|
|
||||||
require'lspconfig'.clangd.setup{}
|
|
||||||
<
|
|
||||||
- create a new project, ensure that it contains a root marker which matches the
|
|
||||||
server requirements specified in |lspconfig-server-configurations|.
|
|
||||||
|
|
||||||
- open a file within that project, such as `main.c`.
|
|
||||||
|
|
||||||
- If you need more information about a server configuration, read the corresponding
|
|
||||||
entry in |lspconfig-server-configurations|.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
THE SETUP METAMETHOD *lspconfig-setup*
|
|
||||||
|
|
||||||
`lspconfig` consists of a collection of language server configurations. Each
|
|
||||||
configuration exposes a `setup {}` metamethod which makes it easy to directly
|
|
||||||
use the default configuration or selectively override the defaults.
|
|
||||||
`setup {}` is the primary interface by which users interact with `lspconfig`.
|
|
||||||
|
|
||||||
Using the default configuration for a server is simple:
|
|
||||||
>
|
|
||||||
require'lspconfig'.clangd.setup{}
|
|
||||||
<
|
|
||||||
The available server names are listed in |lspconfig-server-configurations| and
|
|
||||||
match the server name in `config.SERVER_NAME` defined in each configuration's
|
|
||||||
source file.
|
|
||||||
|
|
||||||
The purpose of `setup{}` is to wrap the call to Nvim's built-in
|
|
||||||
`vim.lsp.start_client()` with an autocommand that automatically launch a
|
|
||||||
language server.
|
|
||||||
|
|
||||||
This autocommand calls `start_client()` or `vim.lsp.buf_attach_client()`
|
|
||||||
depending on whether the current file belongs to a project with a currently
|
|
||||||
running client. See |lspconfig-root-detection| for more details.
|
|
||||||
|
|
||||||
The `setup{}` function takes a table which contains a superset of the keys
|
|
||||||
listed in `:help vim.lsp.start_client()` with the following unique entries:
|
|
||||||
|
|
||||||
- {root_dir}
|
|
||||||
|
|
||||||
`function(filename, bufnr)`
|
|
||||||
|
|
||||||
Returns either a filepath (string) or nil. The language server will only
|
|
||||||
start if the function returns a filepath.
|
|
||||||
|
|
||||||
If a root directory (string) is returned which is unique from any
|
|
||||||
previously returned root_dir, a new server will be spawned with that
|
|
||||||
root directory. See |lspconfig-root-detection| for more details
|
|
||||||
|
|
||||||
- {name}
|
|
||||||
|
|
||||||
`string`
|
|
||||||
|
|
||||||
Defaults to the server's name (`clangd`, `pyright`, etc.).
|
|
||||||
|
|
||||||
- {filetypes}
|
|
||||||
|
|
||||||
`list[string] | nil`
|
|
||||||
|
|
||||||
Set of filetypes for which to attempt to resolve {root_dir}.
|
|
||||||
|
|
||||||
May be empty, or server may specify a default value.
|
|
||||||
|
|
||||||
- {autostart}
|
|
||||||
|
|
||||||
`bool` (default: true)
|
|
||||||
|
|
||||||
Controls if the `FileType` autocommand that launches a language server is
|
|
||||||
created. If `false`, allows for deferring language servers until manually
|
|
||||||
launched with `:LspStart` (|lspconfig-commands|).
|
|
||||||
|
|
||||||
- {single_file_support}
|
|
||||||
|
|
||||||
`bool` (default: nil)
|
|
||||||
|
|
||||||
Determines if a server is started without a matching root directory.
|
|
||||||
See |lspconfig-single-file-support|.
|
|
||||||
|
|
||||||
- {on_new_config}
|
|
||||||
|
|
||||||
`function(new_config, new_root_dir)`
|
|
||||||
|
|
||||||
Function executed after a root directory is detected. This is used to
|
|
||||||
modify the server configuration (including `cmd` itself). Most commonly,
|
|
||||||
this is used to inject additional arguments into `cmd`.
|
|
||||||
|
|
||||||
If overriding `on_new_config`, ensure that you read the
|
|
||||||
`on_new_config` defined in the source file of the default configuration
|
|
||||||
in `lspconfig`. The original `on_new_config` snippet for a given server
|
|
||||||
should likely be included in your new override. Some configurations
|
|
||||||
use `on_new_config` to dynamically set or modify `cmd`.
|
|
||||||
|
|
||||||
Note: all entries passed to `setup {}` override the entry in the default
|
|
||||||
configuration. There is no composition.
|
|
||||||
|
|
||||||
All `config` elements described in `:help vim.lsp.start_client()` can
|
|
||||||
additionally be overridden via the `setup {}` call. The most commonly
|
|
||||||
passed overrides to `setup {}` are:
|
|
||||||
|
|
||||||
- {capabilities} `table <string, string|table|bool|function>`
|
|
||||||
|
|
||||||
a table which represents the neovim client capabilities. Useful for
|
|
||||||
broadcasting to the server additional functionality (snippets, off-protocol
|
|
||||||
features) provided by plugins.
|
|
||||||
|
|
||||||
- {cmd} `list[string]`
|
|
||||||
|
|
||||||
a list where each entry corresponds to the blankspace delimited part of
|
|
||||||
the command that launches the server. The first entry is the binary used
|
|
||||||
to run the language server. Additional entries are passed as arguments.
|
|
||||||
|
|
||||||
The equivalent `cmd` for:
|
|
||||||
>
|
|
||||||
foo --bar baz
|
|
||||||
<
|
|
||||||
is:
|
|
||||||
>
|
|
||||||
{'foo', '--bar', 'baz}
|
|
||||||
<
|
|
||||||
- {handlers} `list[functions]`
|
|
||||||
|
|
||||||
a list of handlers which override the function used to process a response
|
|
||||||
from a given language server. Applied only to the server referenced by
|
|
||||||
setup. See |lsp-handler|.
|
|
||||||
|
|
||||||
- {init_options} `table <string, string|table|bool>`
|
|
||||||
|
|
||||||
a table passed during the initialization notification after launching
|
|
||||||
a language server. Equivalent to the `initializationOptions` field found
|
|
||||||
in `InitializeParams` in the LSP specification.
|
|
||||||
|
|
||||||
See upstream server documentation for available initialization
|
|
||||||
options.
|
|
||||||
|
|
||||||
- {on_attach} `function(client, bufnr)`
|
|
||||||
|
|
||||||
Callback invoked by Nvim's built-in client when attaching a buffer to a
|
|
||||||
language server. Often used to set Nvim (buffer or global) options or to
|
|
||||||
override the Nvim client properties (`resolved_capabilities`) after a
|
|
||||||
language server attaches. Most commonly used for settings buffer
|
|
||||||
local keybindings. See |lspconfig-keybindings| for a usage example.
|
|
||||||
|
|
||||||
- {settings} `table <string, string|table|bool>`
|
|
||||||
|
|
||||||
The `settings` table is sent in `on_init` via a
|
|
||||||
`workspace/didChangeConfiguration` notification from the Nvim client to
|
|
||||||
the language server. These settings allow a user to change optional runtime
|
|
||||||
settings of the language server.
|
|
||||||
|
|
||||||
The script that automatically generates `server_configurations.md` converts
|
|
||||||
the `package.json` referenced in a server configuration source file
|
|
||||||
into a list of optional settings listed in |lspconfig-server-configurations|.
|
|
||||||
|
|
||||||
As an example, to set the following settings found in the pyright
|
|
||||||
documentation:
|
|
||||||
|
|
||||||
`pyright.disableLanguageServices`: `boolean`
|
|
||||||
`pyright.disableOrganizeImports`: `boolean`
|
|
||||||
|
|
||||||
Nested keys need to be translated into a nested table and passed to
|
|
||||||
the settings field in `setup {}` as follows:
|
|
||||||
>
|
|
||||||
require('lspconfig').pyright.setup{
|
|
||||||
settings = {
|
|
||||||
pyright = {
|
|
||||||
disableLanguageServices = true,
|
|
||||||
disableOrganizeImports = true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<
|
|
||||||
|
|
||||||
Note that the autogenerated settings occasionally include VS code specific
|
|
||||||
settings. If a setting is not respected by a language server, consult
|
|
||||||
upstream documentation.
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
OVERRIDING GLOBAL DEFAULTS *lspconfig-global-defaults*
|
|
||||||
|
|
||||||
The global defaults for all servers can be overridden by extending the
|
|
||||||
`default_config` table.
|
|
||||||
|
|
||||||
>
|
|
||||||
local lspconfig = require'lspconfig'
|
|
||||||
lspconfig.util.default_config = vim.tbl_extend(
|
|
||||||
"force",
|
|
||||||
lspconfig.util.default_config,
|
|
||||||
{
|
|
||||||
autostart = false,
|
|
||||||
handlers = {
|
|
||||||
["window/logMessage"] = function(err, method, params, client_id)
|
|
||||||
if params and params.type <= vim.lsp.protocol.MessageType.Log then
|
|
||||||
vim.lsp.handlers["window/logMessage"](err, method, params, client_id)
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
["window/showMessage"] = function(err, method, params, client_id)
|
|
||||||
if params and params.type <= vim.lsp.protocol.MessageType.Warning.Error then
|
|
||||||
vim.lsp.handlers["window/showMessage"](err, method, params, client_id)
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
<
|
|
||||||
`setup {}` can additionally override these defaults in subsequent calls.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
SERVER CONFIGURATIONS *lspconfig-configurations*
|
|
||||||
|
|
||||||
See |lspconfig-server-configurations| by typing `K` over it for the complete
|
|
||||||
list of language servers configurations.
|
|
||||||
|
|
||||||
While the `setup {}` function is the primary interface to `lspconfig`, for
|
|
||||||
servers for which there is not a configuration, it is necessary to define a
|
|
||||||
configuration directly. This can be useful if there is an outstanding PR that
|
|
||||||
is in review, or when developing a language server that is unavailable
|
|
||||||
publicly. This can be done through the `configs` module.
|
|
||||||
|
|
||||||
The `configs` module is a singleton where configs are defined. The schema for
|
|
||||||
validating using `vim.validate` is:
|
|
||||||
>
|
|
||||||
configs.SERVER_NAME = {
|
|
||||||
default_config = {'t'};
|
|
||||||
on_new_config = {'f', true};
|
|
||||||
on_attach = {'f', true};
|
|
||||||
commands = {'t', true};
|
|
||||||
docs = {'t', true};
|
|
||||||
}
|
|
||||||
<
|
|
||||||
where the structure of the docs table is as follows:
|
|
||||||
>
|
|
||||||
docs = {
|
|
||||||
description = {'s', true};
|
|
||||||
default_config = {'t', true};
|
|
||||||
}
|
|
||||||
<
|
|
||||||
`commands` is a map of `name:definition` key:value pairs, where `definition`
|
|
||||||
is a list whose first value is a function implementing the command, and the
|
|
||||||
rest are either array values which will be formed into flags for the command,
|
|
||||||
or special keys like `description`. Example:
|
|
||||||
>
|
|
||||||
commands = {
|
|
||||||
TexlabBuild = {
|
|
||||||
function()
|
|
||||||
buf_build(0)
|
|
||||||
end;
|
|
||||||
"-range";
|
|
||||||
description = "Build the current buffer";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
<
|
|
||||||
The `configs.__newindex` metamethod consumes the config definition and returns
|
|
||||||
an object with a `setup()` method, to be invoked by users:
|
|
||||||
>
|
|
||||||
require'lspconfig'.SERVER_NAME.setup{}
|
|
||||||
|
|
||||||
After you set `configs.SERVER_NAME` you can add arbitrary language-specific
|
|
||||||
functions to it if necessary.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
>
|
|
||||||
configs.texlab.buf_build = buf_build
|
|
||||||
<
|
|
||||||
==============================================================================
|
|
||||||
ADDING NEW SERVERS *lspconfig-adding-servers*
|
|
||||||
|
|
||||||
The three steps for adding and enabling a new server configuration are:
|
|
||||||
|
|
||||||
- load the `lspconfig` module (note that this is a stylistic choice)
|
|
||||||
>
|
|
||||||
local lspconfig = require 'lspconfig'
|
|
||||||
<
|
|
||||||
- define the configuration
|
|
||||||
|
|
||||||
>
|
|
||||||
local configs = require 'lspconfig.configs'
|
|
||||||
|
|
||||||
-- Check if the config is already defined (useful when reloading this file)
|
|
||||||
if not configs.foo_lsp then
|
|
||||||
configs.foo_lsp = {
|
|
||||||
default_config = {
|
|
||||||
cmd = {'/home/neovim/lua-language-server/run.sh'};
|
|
||||||
filetypes = {'lua'};
|
|
||||||
root_dir = function(fname)
|
|
||||||
return lspconfig.util.find_git_ancestor(fname)
|
|
||||||
end;
|
|
||||||
settings = {};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
- call `setup()` to enable the FileType autocmd
|
|
||||||
>
|
|
||||||
lspconfig.foo_lsp.setup{}
|
|
||||||
<
|
|
||||||
==============================================================================
|
|
||||||
ROOT DETECTION *lspconfig-root-detection*
|
|
||||||
*lspconfig-root-dir*
|
|
||||||
|
|
||||||
A project's `root_dir` is used by `lspconfig` to determine whether `lspconfig`
|
|
||||||
should start a new server, or attach a previous one, to the current file.
|
|
||||||
|
|
||||||
`lspconfig` automatically launches language servers by defining a filetype
|
|
||||||
autocommand based on the `filetypes` specified in the default configuration of
|
|
||||||
each server, optionally overridable by the `filetypes` table passed to
|
|
||||||
`setup`.
|
|
||||||
|
|
||||||
This autocommand triggers a search from the current file position in the
|
|
||||||
filesystem hierarchy up to the top level directory of your filesystem. The
|
|
||||||
`root_dir` entry of each configuration is a function that returns true if the
|
|
||||||
current directory in this traversal matches a given root pattern.
|
|
||||||
|
|
||||||
The following utility functions are provided by `lspconfig`. Each function call
|
|
||||||
below returns a function that takes as its argument the current buffer path.
|
|
||||||
|
|
||||||
- `util.root_pattern`: function which takes multiple arguments, each
|
|
||||||
corresponding to a different root pattern against which the contents of the
|
|
||||||
current directory are matched using |vim.fin.glob()| while traversing up the
|
|
||||||
filesystem.
|
|
||||||
>
|
|
||||||
root_dir = util.root_pattern('pyproject.toml', 'requirements.txt')
|
|
||||||
<
|
|
||||||
- `util.find_git_ancestor`: a function that locates the first parent directory
|
|
||||||
containing a `.git` directory.
|
|
||||||
>
|
|
||||||
root_dir = util.find_git_ancestor
|
|
||||||
|
|
||||||
- `util.find_node_modules_ancestor`: a function that locates the first parent
|
|
||||||
directory containing a `node_modules` directory.
|
|
||||||
>
|
|
||||||
root_dir = util.find_node_modules_ancestor
|
|
||||||
<
|
|
||||||
|
|
||||||
- `util.find_package_json_ancestor`: a function that locates the first parent
|
|
||||||
directory containing a `package.json`.
|
|
||||||
>
|
|
||||||
root_dir = util.find_json_ancestor
|
|
||||||
<
|
|
||||||
Note: On Windows, `lspconfig` always assumes forward slash normalized paths with
|
|
||||||
capitalized drive letters.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
ADVANCED ROOT DIRECTORY DETECTION *lspconfig-root-advanced*
|
|
||||||
*lspconfig-root-composition*
|
|
||||||
|
|
||||||
The `root_dir` key in `config` and `setup` can hold any function of the form
|
|
||||||
>
|
|
||||||
function custom_root_dir(filename, bufnr)
|
|
||||||
returns nil | string
|
|
||||||
>
|
|
||||||
This allows for rich composition of root directory patterns which is necessary
|
|
||||||
for some project structures. Example (for Kotlin):
|
|
||||||
>
|
|
||||||
local root_files = {
|
|
||||||
'settings.gradle', -- Gradle (multi-project)
|
|
||||||
'settings.gradle.kts', -- Gradle (multi-project)
|
|
||||||
'build.xml', -- Ant
|
|
||||||
'pom.xml', -- Maven
|
|
||||||
}
|
|
||||||
|
|
||||||
local fallback_root_files = {
|
|
||||||
'build.gradle', -- Gradle
|
|
||||||
'build.gradle.kts', -- Gradle
|
|
||||||
}
|
|
||||||
root_dir = function(fname)
|
|
||||||
local primary = util.root_pattern(unpack(root_files))(fname)
|
|
||||||
local fallback = util.root_pattern(unpack(fallback_root_files))(fname)
|
|
||||||
return primary or fallback
|
|
||||||
end
|
|
||||||
<
|
|
||||||
Browsing the source of the default configurations is recommended.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
SINGLE FILE SUPPORT *lspconfig-single-file-support*
|
|
||||||
|
|
||||||
Language servers require each project to have a `root` in order to provide
|
|
||||||
features that require cross-file indexing.
|
|
||||||
|
|
||||||
Some servers support not passing a root directory as a proxy for single file
|
|
||||||
mode under which cross-file features may be degraded.
|
|
||||||
|
|
||||||
`lspconfig` offers limited support for an implicit single-file mode by:
|
|
||||||
|
|
||||||
- first trying to resolve the root directory pattern
|
|
||||||
- then, if `single_file_support` is enabled for a given language server
|
|
||||||
configuration, starting the server without sending `rootDirectory` or
|
|
||||||
`workspaceFolders` during initialization.
|
|
||||||
- attaching subsequent files in the parent directory to the same server
|
|
||||||
instance, depending on filetype.
|
|
||||||
|
|
||||||
Cross-file features (navigation, hover) may or may not work depending on the
|
|
||||||
language server. For a full feature-set, consider moving your files to a
|
|
||||||
directory with a project structure `lspconfig` can infer.
|
|
||||||
|
|
||||||
Note that in the event that the LSP specification is extended to support a
|
|
||||||
standard for single-file mode, lspconfig will adopt that standard.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
COMMANDS *lspconfig-commands*
|
|
||||||
|
|
||||||
- `:LspInfo` shows the status of active and configured language servers. Note
|
|
||||||
that client id refers to the Nvim RPC instance connected to a given
|
|
||||||
language server.
|
|
||||||
|
|
||||||
The following commands support tab-completion for all arguments. All commands
|
|
||||||
that require a client id can either leverage tab-completion or the info
|
|
||||||
contained in `:LspInfo`:
|
|
||||||
|
|
||||||
- `:LspStart <config_name>` launches the requested (configured) client, but only
|
|
||||||
if it successfully resolves a root directory. Note: Defaults to all
|
|
||||||
configured servers matching the current buffer filetype.
|
|
||||||
- `:LspStop <client_id>` stops the server with the given client id. Defaults to
|
|
||||||
stopping all servers active on the current buffer.
|
|
||||||
- `:LspRestart <client_id>` restarts the client with the given client id, and
|
|
||||||
will attempt to reattach to all previously attached buffers.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
EXAMPLE KEYBINDINGS *lspconfig-keybindings*
|
|
||||||
|
|
||||||
`lspconfig`, and the core client, do not map any keybindings by default. The
|
|
||||||
following is an example Lua block which demonstrates how to leverage
|
|
||||||
`on-attach` to selectively apply keybindings after a language servers has
|
|
||||||
attached to a given buffer.
|
|
||||||
>
|
|
||||||
local nvim_lsp = require('lspconfig')
|
|
||||||
|
|
||||||
-- Use an on_attach function to only map the following keys
|
|
||||||
-- after the language server attaches to the current buffer
|
|
||||||
local on_attach = function(client, bufnr)
|
|
||||||
local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
|
|
||||||
local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end
|
|
||||||
|
|
||||||
-- Enable completion triggered by <c-x><c-o>
|
|
||||||
buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
|
|
||||||
|
|
||||||
-- Mappings.
|
|
||||||
local opts = { noremap=true, silent=true }
|
|
||||||
|
|
||||||
-- See `:help vim.lsp.*` for documentation on any of the below functions
|
|
||||||
buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
|
|
||||||
buf_set_keymap('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
|
|
||||||
buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
|
|
||||||
buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>', opts)
|
|
||||||
buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>e', '<cmd>lua vim.diagnostic.open_float()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '[d', '<cmd>lua vim.diagnostic.goto_prev()<CR>', opts)
|
|
||||||
buf_set_keymap('n', ']d', '<cmd>lua vim.diagnostic.goto_next()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>q', '<cmd>lua vim.diagnostic.setloclist()<CR>', opts)
|
|
||||||
buf_set_keymap('n', '<space>f', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Use a loop to conveniently call 'setup' on multiple servers and
|
|
||||||
-- map buffer local keybindings when the language server attaches
|
|
||||||
local servers = { 'pyright', 'rust_analyzer', 'tsserver' }
|
|
||||||
for _, lsp in ipairs(servers) do
|
|
||||||
nvim_lsp[lsp].setup {
|
|
||||||
on_attach = on_attach,
|
|
||||||
flags = {
|
|
||||||
debounce_text_changes = 150,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
<
|
|
||||||
Note: these keymappings are meant for illustration and override some
|
|
||||||
infrequently used default mappings.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
COMPLETION SUPPORT *lspconfig-completion*
|
|
||||||
|
|
||||||
Manually triggered completion can be provided by Nvim's built-in omnifunc.
|
|
||||||
See `:help omnifunc` for more details.
|
|
||||||
|
|
||||||
For autocompletion, Nvim does not offer built-in functionality at this time.
|
|
||||||
Consult the `lspconfig` wiki, which provides configuration examples for using a
|
|
||||||
completion plugin with the built-in client
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
DEBUGGING *lspconfig-debugging*
|
|
||||||
|
|
||||||
While using language servers should be easy, debugging issues can be
|
|
||||||
challenging. First, it is important to identify the source of the issue, which
|
|
||||||
is typically (in rough order):
|
|
||||||
|
|
||||||
- the language server itself
|
|
||||||
- a plugin
|
|
||||||
- overrides in a user configuration
|
|
||||||
- the built-in client in Nvim core
|
|
||||||
- `lspconfig`
|
|
||||||
|
|
||||||
The first step in debugging is to test with a minimal configuration (such as
|
|
||||||
`../test/minimal_init.lua`). Historically, many users problems are due to
|
|
||||||
plugins or misconfiguration.
|
|
||||||
|
|
||||||
Should that fail, identifying which component is the culprit is challenging.
|
|
||||||
The following are the only categories of bugs that pertain to `lspconfig`.
|
|
||||||
|
|
||||||
- The root directory inferred for your project is wrong, or it should be
|
|
||||||
detected but is not due to a bug in the `lspconfig` path utilities.
|
|
||||||
- The server is launching, but you believe that the default settings,
|
|
||||||
initialization options, or command arguments are suboptimal and should be
|
|
||||||
replaced based on your understanding of the server documentation.
|
|
||||||
|
|
||||||
All bugs Nvim's built-in client should be reported to the Nvim core issue
|
|
||||||
tracker. All bugs pertaining to plugins should be reported to the respective
|
|
||||||
plugin. All missing features in a language server should be reported to the
|
|
||||||
upstream language server issue tracker.
|
|
||||||
|
|
||||||
For debugging `lspconfig` issues, the most common hurdles users face are:
|
|
||||||
|
|
||||||
- The language server is not installed or is otherwise not executable.
|
|
||||||
`lspconfig` does not install language servers for you. Ensure the `cmd`
|
|
||||||
defined in `server_configurations.md` is executable from the command
|
|
||||||
line. If the absolute path to the binary is not supplied in `cmd`, ensure
|
|
||||||
it is on your PATH.
|
|
||||||
- No root detected. `lspconfig` is built around the concept of projects. See
|
|
||||||
|lspconfig-root-detection| for more details. Most of the time,
|
|
||||||
initializing a git repo will suffice.
|
|
||||||
- Misconfiguration. Often users will override `cmd`, `on_init`, or
|
|
||||||
`handlers`. Ensure that you debug by using a stock configuration to ensure
|
|
||||||
your customizations are not introducing issues.
|
|
||||||
|
|
||||||
|LspInfo| provides an overview of your active and configured language servers
|
|
||||||
which can be useful for debugging.
|
|
||||||
|
|
||||||
Note that it will not report any configuration changes applied in
|
|
||||||
`on_new_config`.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
LOGGING *lspconfig-logging*
|
|
||||||
|
|
||||||
When debugging language servers, it is helpful to enable additional logging in
|
|
||||||
the built-in client, specifically considering the RPC logs. Example:
|
|
||||||
>
|
|
||||||
vim.lsp.set_log_level 'trace'
|
|
||||||
if vim.fn.has 'nvim-0.5.1' == 1 then
|
|
||||||
require('vim.lsp.log').set_format_func(vim.inspect)
|
|
||||||
end
|
|
||||||
<
|
|
||||||
Attempt to run the language server, and open the log with:
|
|
||||||
|
|
||||||
>
|
|
||||||
:lua vim.cmd('e'..vim.lsp.get_log_path())
|
|
||||||
<
|
|
||||||
Note that `ERROR` messages containing `stderr` only indicate that the log was
|
|
||||||
sent to `stderr`. Many servers counter-intuitively send harmless messages
|
|
||||||
via stderr.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
SCOPE *lspconfig-scope*
|
|
||||||
|
|
||||||
`lspconfig` is a community effort to create default configurations that fit
|
|
||||||
within the scope of an official plugin for Nvim. All features that are not
|
|
||||||
strictly providing default configurations for language servers will be removed
|
|
||||||
from `lspconfig` in time. The power of the Neovim LSP ecosystem is in the
|
|
||||||
composability and flexibility of integrating multiple plugins which maximizes
|
|
||||||
user choice and freedom.
|
|
||||||
|
|
||||||
`lspconfig` also opts to adhere strictly to the LSP specification, with some
|
|
||||||
small allowances when small modifications to a server configuration are
|
|
||||||
necessary to enable features critical to its usability. For more featureful
|
|
||||||
options, the `lspconfig` wiki lists community created plugins that build upon
|
|
||||||
the built-in client to provide functionality tailored to specific language
|
|
||||||
servers.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
|
|
||||||
vim:tw=78:ts=8:ft=help:norl:
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,41 +0,0 @@
|
||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"flake-utils": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1634851050,
|
|
||||||
"narHash": "sha256-N83GlSGPJJdcqhUxSCS/WwW5pksYf3VP1M13cDRTSVA=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "c91f3de5adaf1de973b797ef7485e441a65b8935",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1626644568,
|
|
||||||
"narHash": "sha256-+WxW0u6AJUn/AzIxUuNKtEDxSRcUP0v/iZ/tRXhLGEc=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "d5bd34ebf2c2c2b380b76cb86bc68522bc6af4d7",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"id": "nixpkgs",
|
|
||||||
"type": "indirect"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"nixpkgs": "nixpkgs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
description = "Quickstart configurations for the Nvim LSP client";
|
|
||||||
|
|
||||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
|
||||||
|
|
||||||
outputs = { self, nixpkgs, flake-utils }:
|
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
|
||||||
let pkgs = nixpkgs.legacyPackages.${system}; in
|
|
||||||
rec {
|
|
||||||
devShell = pkgs.mkShell {
|
|
||||||
buildInputs = [
|
|
||||||
pkgs.stylua
|
|
||||||
pkgs.luaPackages.luacheck
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
local configs = require 'lspconfig.configs'
|
|
||||||
|
|
||||||
local M = {
|
|
||||||
util = require 'lspconfig.util',
|
|
||||||
}
|
|
||||||
|
|
||||||
M._root = {}
|
|
||||||
|
|
||||||
function M.available_servers()
|
|
||||||
return vim.tbl_keys(configs)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Called from plugin/lspconfig.vim because it requires knowing that the last
|
|
||||||
-- script in scriptnames to be executed is lspconfig.
|
|
||||||
function M._root._setup()
|
|
||||||
M._root.commands = {
|
|
||||||
LspInfo = {
|
|
||||||
function()
|
|
||||||
require 'lspconfig.ui.lspinfo'()
|
|
||||||
end,
|
|
||||||
'-nargs=0',
|
|
||||||
description = '`:LspInfo` Displays attached, active, and configured language servers',
|
|
||||||
},
|
|
||||||
LspStart = {
|
|
||||||
function(server_name)
|
|
||||||
if server_name then
|
|
||||||
if configs[server_name] then
|
|
||||||
configs[server_name].launch()
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local buffer_filetype = vim.bo.filetype
|
|
||||||
for _, config in pairs(configs) do
|
|
||||||
for _, filetype_match in ipairs(config.filetypes or {}) do
|
|
||||||
if buffer_filetype == filetype_match then
|
|
||||||
config.launch()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
'-nargs=? -complete=custom,v:lua.lsp_complete_configured_servers',
|
|
||||||
description = '`:LspStart` Manually launches a language server.',
|
|
||||||
},
|
|
||||||
LspStop = {
|
|
||||||
function(cmd_args)
|
|
||||||
for _, client in ipairs(M.util.get_clients_from_cmd_args(cmd_args)) do
|
|
||||||
client.stop()
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
'-nargs=? -complete=customlist,v:lua.lsp_get_active_client_ids',
|
|
||||||
description = '`:LspStop` Manually stops the given language client(s).',
|
|
||||||
},
|
|
||||||
LspRestart = {
|
|
||||||
function(cmd_args)
|
|
||||||
for _, client in ipairs(M.util.get_clients_from_cmd_args(cmd_args)) do
|
|
||||||
client.stop()
|
|
||||||
vim.defer_fn(function()
|
|
||||||
configs[client.name].launch()
|
|
||||||
end, 500)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
'-nargs=? -complete=customlist,v:lua.lsp_get_active_client_ids',
|
|
||||||
description = '`:LspRestart` Manually restart the given language client(s).',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
M.util.create_module_commands('_root', M._root.commands)
|
|
||||||
end
|
|
||||||
|
|
||||||
local mt = {}
|
|
||||||
function mt:__index(k)
|
|
||||||
if configs[k] == nil then
|
|
||||||
local success, config = pcall(require, 'lspconfig.server_configurations.' .. k)
|
|
||||||
if success then
|
|
||||||
configs[k] = config
|
|
||||||
else
|
|
||||||
vim.notify(
|
|
||||||
string.format(
|
|
||||||
'[lspconfig] Cannot access configuration for %s. Ensure this server is listed in '
|
|
||||||
.. '`server_configurations.md` or added as a custom server.',
|
|
||||||
k
|
|
||||||
),
|
|
||||||
vim.log.levels.WARN
|
|
||||||
)
|
|
||||||
-- Return a dummy function for compatibility with user configs
|
|
||||||
return { setup = function() end }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return configs[k]
|
|
||||||
end
|
|
||||||
|
|
||||||
return setmetatable(M, mt)
|
|
|
@ -1,299 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
local api, validate, lsp = vim.api, vim.validate, vim.lsp
|
|
||||||
local tbl_extend = vim.tbl_extend
|
|
||||||
|
|
||||||
local configs = {}
|
|
||||||
|
|
||||||
function configs.__newindex(t, config_name, config_def)
|
|
||||||
validate {
|
|
||||||
name = { config_name, 's' },
|
|
||||||
default_config = { config_def.default_config, 't' },
|
|
||||||
on_new_config = { config_def.on_new_config, 'f', true },
|
|
||||||
on_attach = { config_def.on_attach, 'f', true },
|
|
||||||
commands = { config_def.commands, 't', true },
|
|
||||||
}
|
|
||||||
if config_def.commands then
|
|
||||||
for k, v in pairs(config_def.commands) do
|
|
||||||
validate {
|
|
||||||
['command.name'] = { k, 's' },
|
|
||||||
['command.fn'] = { v[1], 'f' },
|
|
||||||
}
|
|
||||||
end
|
|
||||||
else
|
|
||||||
config_def.commands = {}
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
local default_config = tbl_extend('keep', config_def.default_config, util.default_config)
|
|
||||||
|
|
||||||
-- Force this part.
|
|
||||||
default_config.name = config_name
|
|
||||||
|
|
||||||
function M.setup(config)
|
|
||||||
validate {
|
|
||||||
cmd = { config.cmd, 't', true },
|
|
||||||
root_dir = { config.root_dir, 'f', true },
|
|
||||||
filetypes = { config.filetype, 't', true },
|
|
||||||
on_new_config = { config.on_new_config, 'f', true },
|
|
||||||
on_attach = { config.on_attach, 'f', true },
|
|
||||||
commands = { config.commands, 't', true },
|
|
||||||
}
|
|
||||||
if config.commands then
|
|
||||||
for k, v in pairs(config.commands) do
|
|
||||||
validate {
|
|
||||||
['command.name'] = { k, 's' },
|
|
||||||
['command.fn'] = { v[1], 'f' },
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
config = tbl_extend('keep', config, default_config)
|
|
||||||
|
|
||||||
if util.on_setup then
|
|
||||||
pcall(util.on_setup, config)
|
|
||||||
end
|
|
||||||
|
|
||||||
if config.autostart == true then
|
|
||||||
local event
|
|
||||||
local pattern
|
|
||||||
if config.filetypes then
|
|
||||||
event = 'FileType'
|
|
||||||
pattern = table.concat(config.filetypes, ',')
|
|
||||||
else
|
|
||||||
event = 'BufReadPost'
|
|
||||||
pattern = '*'
|
|
||||||
end
|
|
||||||
api.nvim_command(
|
|
||||||
string.format(
|
|
||||||
"autocmd %s %s unsilent lua require'lspconfig'[%q].manager.try_add()",
|
|
||||||
event,
|
|
||||||
pattern,
|
|
||||||
config.name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
local get_root_dir = config.root_dir
|
|
||||||
|
|
||||||
function M.launch()
|
|
||||||
local root_dir
|
|
||||||
if get_root_dir then
|
|
||||||
local bufnr = api.nvim_get_current_buf()
|
|
||||||
local bufname = api.nvim_buf_get_name(bufnr)
|
|
||||||
if not util.bufname_valid(bufname) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
root_dir = get_root_dir(util.path.sanitize(bufname), bufnr)
|
|
||||||
end
|
|
||||||
|
|
||||||
if root_dir then
|
|
||||||
api.nvim_command(
|
|
||||||
string.format(
|
|
||||||
"autocmd BufReadPost %s/* unsilent lua require'lspconfig'[%q].manager.try_add_wrapper()",
|
|
||||||
vim.fn.fnameescape(root_dir),
|
|
||||||
config.name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
|
|
||||||
local bufname = api.nvim_buf_get_name(bufnr)
|
|
||||||
if util.bufname_valid(bufname) then
|
|
||||||
local buf_dir = util.path.sanitize(bufname)
|
|
||||||
if buf_dir:sub(1, root_dir:len()) == root_dir then
|
|
||||||
M.manager.try_add_wrapper(bufnr)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif config.single_file_support then
|
|
||||||
-- This allows on_new_config to use the parent directory of the file
|
|
||||||
-- Effectively this is the root from lspconfig's perspective, as we use
|
|
||||||
-- this to attach additional files in the same parent folder to the same server.
|
|
||||||
-- We just no longer send rootDirectory or workspaceFolders during initialization.
|
|
||||||
local bufname = api.nvim_buf_get_name(0)
|
|
||||||
if not util.bufname_valid(bufname) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local pseudo_root = util.path.dirname(util.path.sanitize(bufname))
|
|
||||||
local client_id = M.manager.add(pseudo_root, true)
|
|
||||||
vim.lsp.buf_attach_client(vim.api.nvim_get_current_buf(), client_id)
|
|
||||||
else
|
|
||||||
vim.notify(
|
|
||||||
string.format('[lspconfig] Autostart for %s failed: matching root directory not detected.', config_name)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Used by :LspInfo
|
|
||||||
M.get_root_dir = get_root_dir
|
|
||||||
M.filetypes = config.filetypes
|
|
||||||
M.handlers = config.handlers
|
|
||||||
M.cmd = config.cmd
|
|
||||||
M.autostart = config.autostart
|
|
||||||
|
|
||||||
-- In the case of a reload, close existing things.
|
|
||||||
local reload = false
|
|
||||||
if M.manager then
|
|
||||||
for _, client in ipairs(M.manager.clients()) do
|
|
||||||
client.stop(true)
|
|
||||||
end
|
|
||||||
reload = true
|
|
||||||
M.manager = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local make_config = function(_root_dir)
|
|
||||||
local new_config = vim.tbl_deep_extend('keep', vim.empty_dict(), config)
|
|
||||||
new_config = vim.tbl_deep_extend('keep', new_config, default_config)
|
|
||||||
new_config.capabilities = new_config.capabilities or lsp.protocol.make_client_capabilities()
|
|
||||||
new_config.capabilities = vim.tbl_deep_extend('keep', new_config.capabilities, {
|
|
||||||
workspace = {
|
|
||||||
configuration = true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if config_def.on_new_config then
|
|
||||||
pcall(config_def.on_new_config, new_config, _root_dir)
|
|
||||||
end
|
|
||||||
if config.on_new_config then
|
|
||||||
pcall(config.on_new_config, new_config, _root_dir)
|
|
||||||
end
|
|
||||||
|
|
||||||
new_config.on_init = util.add_hook_after(new_config.on_init, function(client, result)
|
|
||||||
-- Handle offset encoding by default
|
|
||||||
if result.offsetEncoding then
|
|
||||||
client.offset_encoding = result.offsetEncoding
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Send `settings to server via workspace/didChangeConfiguration
|
|
||||||
function client.workspace_did_change_configuration(settings)
|
|
||||||
if not settings then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if vim.tbl_isempty(settings) then
|
|
||||||
settings = { [vim.type_idx] = vim.types.dictionary }
|
|
||||||
end
|
|
||||||
return client.notify('workspace/didChangeConfiguration', {
|
|
||||||
settings = settings,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
if not vim.tbl_isempty(new_config.settings) then
|
|
||||||
client.workspace_did_change_configuration(new_config.settings)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Save the old _on_attach so that we can reference it via the BufEnter.
|
|
||||||
new_config._on_attach = new_config.on_attach
|
|
||||||
new_config.on_attach = vim.schedule_wrap(function(client, bufnr)
|
|
||||||
if bufnr == api.nvim_get_current_buf() then
|
|
||||||
M._setup_buffer(client.id, bufnr)
|
|
||||||
else
|
|
||||||
api.nvim_command(
|
|
||||||
string.format(
|
|
||||||
"autocmd BufEnter <buffer=%d> ++once lua require'lspconfig'[%q]._setup_buffer(%d,%d)",
|
|
||||||
bufnr,
|
|
||||||
config_name,
|
|
||||||
client.id,
|
|
||||||
bufnr
|
|
||||||
)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
new_config.root_dir = _root_dir
|
|
||||||
new_config.workspace_folders = {
|
|
||||||
{
|
|
||||||
uri = vim.uri_from_fname(_root_dir),
|
|
||||||
name = string.format('%s', _root_dir),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return new_config
|
|
||||||
end
|
|
||||||
|
|
||||||
local manager = util.server_per_root_dir_manager(function(_root_dir)
|
|
||||||
return make_config(_root_dir)
|
|
||||||
end)
|
|
||||||
|
|
||||||
function manager.try_add(bufnr)
|
|
||||||
bufnr = bufnr or api.nvim_get_current_buf()
|
|
||||||
|
|
||||||
if vim.api.nvim_buf_get_option(bufnr, 'buftype') == 'nofile' then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local id
|
|
||||||
local root_dir
|
|
||||||
|
|
||||||
local bufname = api.nvim_buf_get_name(bufnr)
|
|
||||||
if not util.bufname_valid(bufname) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local buf_path = util.path.sanitize(bufname)
|
|
||||||
|
|
||||||
if get_root_dir then
|
|
||||||
root_dir = get_root_dir(buf_path, bufnr)
|
|
||||||
end
|
|
||||||
|
|
||||||
if root_dir then
|
|
||||||
id = manager.add(root_dir, false)
|
|
||||||
elseif config.single_file_support then
|
|
||||||
local pseudo_root = util.path.dirname(buf_path)
|
|
||||||
id = manager.add(pseudo_root, true)
|
|
||||||
else
|
|
||||||
vim.notify(
|
|
||||||
string.format('[lspconfig] Autostart for %s failed: matching root directory not detected.', config_name)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
if id then
|
|
||||||
lsp.buf_attach_client(bufnr, id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function manager.try_add_wrapper(bufnr)
|
|
||||||
bufnr = bufnr or api.nvim_get_current_buf()
|
|
||||||
local buf_filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype')
|
|
||||||
for _, filetype in ipairs(config.filetypes) do
|
|
||||||
if buf_filetype == filetype then
|
|
||||||
manager.try_add(bufnr)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
M.manager = manager
|
|
||||||
M.make_config = make_config
|
|
||||||
if reload and not (config.autostart == false) then
|
|
||||||
for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
|
|
||||||
manager.try_add_wrapper(bufnr)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function M._setup_buffer(client_id, bufnr)
|
|
||||||
local client = lsp.get_client_by_id(client_id)
|
|
||||||
if not client then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if client.config._on_attach then
|
|
||||||
client.config._on_attach(client, bufnr)
|
|
||||||
end
|
|
||||||
if client.config.commands and not vim.tbl_isempty(client.config.commands) then
|
|
||||||
M.commands = vim.tbl_deep_extend('force', M.commands, client.config.commands)
|
|
||||||
end
|
|
||||||
if not M.commands_created and not vim.tbl_isempty(M.commands) then
|
|
||||||
-- Create the module commands
|
|
||||||
util.create_module_commands(config_name, M.commands)
|
|
||||||
M.commands_created = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
M.commands_created = false
|
|
||||||
M.commands = config_def.commands
|
|
||||||
M.name = config_name
|
|
||||||
M.document_config = config_def
|
|
||||||
|
|
||||||
rawset(t, config_name, M)
|
|
||||||
|
|
||||||
return M
|
|
||||||
end
|
|
||||||
|
|
||||||
return setmetatable({}, configs)
|
|
|
@ -1,38 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
local bin_name = 'ada_language_server'
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
bin_name = 'ada_language_server.exe'
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { bin_name },
|
|
||||||
filetypes = { 'ada' },
|
|
||||||
root_dir = util.root_pattern('Makefile', '.git', '*.gpr', '*.adc'),
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
package_json = 'https://raw.githubusercontent.com/AdaCore/ada_language_server/master/integration/vscode/ada/package.json',
|
|
||||||
description = [[
|
|
||||||
https://github.com/AdaCore/ada_language_server
|
|
||||||
|
|
||||||
Installation instructions can be found [here](https://github.com/AdaCore/ada_language_server#Install).
|
|
||||||
|
|
||||||
Can be configured by passing a "settings" object to `als.setup{}`:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
require('lspconfig').als.setup{
|
|
||||||
settings = {
|
|
||||||
ada = {
|
|
||||||
projectFile = "project.gpr";
|
|
||||||
scenarioVariables = { ... };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[util.root_pattern("Makefile", ".git", "*.gpr", "*.adc")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
-- Angular requires a node_modules directory to probe for @angular/language-service and typescript
|
|
||||||
-- in order to use your projects configured versions.
|
|
||||||
-- This defaults to the vim cwd, but will get overwritten by the resolved root of the file.
|
|
||||||
local function get_probe_dir(root_dir)
|
|
||||||
local project_root = util.find_node_modules_ancestor(root_dir)
|
|
||||||
|
|
||||||
return project_root and (project_root .. '/node_modules') or ''
|
|
||||||
end
|
|
||||||
|
|
||||||
local default_probe_dir = get_probe_dir(vim.fn.getcwd())
|
|
||||||
|
|
||||||
local bin_name = 'ngserver'
|
|
||||||
local args = {
|
|
||||||
'--stdio',
|
|
||||||
'--tsProbeLocations',
|
|
||||||
default_probe_dir,
|
|
||||||
'--ngProbeLocations',
|
|
||||||
default_probe_dir,
|
|
||||||
}
|
|
||||||
|
|
||||||
local cmd = { bin_name, unpack(args) }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name, unpack(args) }
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = cmd,
|
|
||||||
filetypes = { 'typescript', 'html', 'typescriptreact', 'typescript.tsx' },
|
|
||||||
-- Check for angular.json or .git first since that is the root of the project.
|
|
||||||
-- Don't check for tsconfig.json or package.json since there are multiple of these
|
|
||||||
-- in an angular monorepo setup.
|
|
||||||
root_dir = util.root_pattern('angular.json', '.git'),
|
|
||||||
},
|
|
||||||
on_new_config = function(new_config, new_root_dir)
|
|
||||||
local new_probe_dir = get_probe_dir(new_root_dir)
|
|
||||||
|
|
||||||
-- We need to check our probe directories because they may have changed.
|
|
||||||
new_config.cmd = {
|
|
||||||
'ngserver',
|
|
||||||
'--stdio',
|
|
||||||
'--tsProbeLocations',
|
|
||||||
new_probe_dir,
|
|
||||||
'--ngProbeLocations',
|
|
||||||
new_probe_dir,
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/angular/vscode-ng-language-service
|
|
||||||
|
|
||||||
`angular-language-server` can be installed via npm `npm install -g @angular/language-server`.
|
|
||||||
|
|
||||||
Note, that if you override the default `cmd`, you must also update `on_new_config` to set `new_config.cmd` during startup.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local project_library_path = "/path/to/project/lib"
|
|
||||||
local cmd = {"ngserver", "--stdio", "--tsProbeLocations", project_library_path , "--ngProbeLocations", project_library_path}
|
|
||||||
|
|
||||||
require'lspconfig'.angularls.setup{
|
|
||||||
cmd = cmd,
|
|
||||||
on_new_config = function(new_config,new_root_dir)
|
|
||||||
new_config.cmd = cmd
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("angular.json", ".git")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
local bin_name = 'ansible-language-server'
|
|
||||||
local cmd = { bin_name, '--stdio' }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name, '--stdio' }
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = cmd,
|
|
||||||
settings = {
|
|
||||||
ansible = {
|
|
||||||
python = {
|
|
||||||
interpreterPath = 'python',
|
|
||||||
},
|
|
||||||
ansibleLint = {
|
|
||||||
path = 'ansible-lint',
|
|
||||||
enabled = true,
|
|
||||||
},
|
|
||||||
ansible = {
|
|
||||||
path = 'ansible',
|
|
||||||
},
|
|
||||||
executionEnvironment = {
|
|
||||||
enabled = false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
filetypes = { 'yaml', 'yaml.ansible' },
|
|
||||||
root_dir = util.root_pattern('ansible.cfg', '.ansible-lint'),
|
|
||||||
single_file_support = true,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/ansible/ansible-language-server
|
|
||||||
|
|
||||||
Language server for the ansible configuration management tool.
|
|
||||||
|
|
||||||
`ansible-language-server` can be installed via `yarn`:
|
|
||||||
```sh
|
|
||||||
yarn global add ansible-language-server
|
|
||||||
```
|
|
||||||
]],
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'arduino-language-server' },
|
|
||||||
filetypes = { 'arduino' },
|
|
||||||
root_dir = util.root_pattern '*.ino',
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/arduino/arduino-language-server
|
|
||||||
|
|
||||||
Language server for Arduino
|
|
||||||
|
|
||||||
The `arduino-language-server` can be installed by running:
|
|
||||||
go get -u github.com/arduino/arduino-language-server
|
|
||||||
|
|
||||||
The `arduino-cli` tools must also be installed. Follow these instructions for your distro:
|
|
||||||
https://arduino.github.io/arduino-cli/latest/installation/
|
|
||||||
|
|
||||||
After installing the `arduino-cli` tools, follow these instructions for generating
|
|
||||||
a configuration file:
|
|
||||||
https://arduino.github.io/arduino-cli/latest/getting-started/#create-a-configuration-file
|
|
||||||
and make sure you install any relevant platforms libraries:
|
|
||||||
https://arduino.github.io/arduino-cli/latest/getting-started/#install-the-core-for-your-board
|
|
||||||
|
|
||||||
The language server also requires `clangd` be installed. It will look for `clangd` by default but
|
|
||||||
the binary path can be overridden if need be.
|
|
||||||
|
|
||||||
After all dependencies are installed you'll need to override the lspconfig command for the
|
|
||||||
language server in your setup function with the necessary configurations:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
lspconfig.arduino_language_server.setup({
|
|
||||||
cmd = {
|
|
||||||
-- Required
|
|
||||||
"arduino-language-server",
|
|
||||||
"-cli-config", "/path/to/arduino-cli.yaml",
|
|
||||||
-- Optional
|
|
||||||
"-cli", "/path/to/arduino-cli",
|
|
||||||
"-clangd", "/path/to/clangd"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
For further instruction about configuration options, run `arduino-language-server --help`.
|
|
||||||
|
|
||||||
]],
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
local bin_name = 'bash-language-server'
|
|
||||||
local cmd = { bin_name, 'start' }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name, 'start' }
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = cmd,
|
|
||||||
cmd_env = {
|
|
||||||
-- Prevent recursive scanning which will cause issues when opening a file
|
|
||||||
-- directly in the home directory (e.g. ~/foo.sh).
|
|
||||||
--
|
|
||||||
-- Default upstream pattern is "**/*@(.sh|.inc|.bash|.command)".
|
|
||||||
GLOB_PATTERN = vim.env.GLOB_PATTERN or '*@(.sh|.inc|.bash|.command)',
|
|
||||||
},
|
|
||||||
filetypes = { 'sh' },
|
|
||||||
root_dir = util.find_git_ancestor,
|
|
||||||
single_file_support = true,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/mads-hartmann/bash-language-server
|
|
||||||
|
|
||||||
Language server for bash, written using tree sitter in typescript.
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[util.find_git_ancestor]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'beancount-langserver' },
|
|
||||||
filetypes = { 'beancount' },
|
|
||||||
root_dir = util.find_git_ancestor,
|
|
||||||
single_file_support = true,
|
|
||||||
init_options = {
|
|
||||||
-- this is the path to the beancout journal file
|
|
||||||
journalFile = '',
|
|
||||||
-- this is the path to the python binary with beancount installed
|
|
||||||
pythonPath = 'python3',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/polarmutex/beancount-language-server#installation
|
|
||||||
|
|
||||||
See https://github.com/polarmutex/beancount-language-server#configuration for configuration options
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("elm.json")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
filetypes = { 'bicep' },
|
|
||||||
root_dir = util.find_git_ancestor,
|
|
||||||
init_options = {},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [=[
|
|
||||||
https://github.com/azure/bicep
|
|
||||||
Bicep language server
|
|
||||||
|
|
||||||
Bicep language server can be installed by downloading and extracting a release of bicep-langserver.zip from [Bicep GitHub releases](https://github.com/Azure/bicep/releases).
|
|
||||||
|
|
||||||
Bicep language server requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed.
|
|
||||||
|
|
||||||
Neovim does not have built-in support for the bicep filetype which is required for lspconfig to automatically launch the language server.
|
|
||||||
|
|
||||||
Filetype detection can be added via an autocmd:
|
|
||||||
```lua
|
|
||||||
vim.cmd [[ autocmd BufNewFile,BufRead *.bicep set filetype=bicep ]]
|
|
||||||
```
|
|
||||||
|
|
||||||
**By default, bicep language server does not have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of the unzipped run script or binary.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local bicep_lsp_bin = "/path/to/bicep-langserver/Bicep.LangServer.dll"
|
|
||||||
require'lspconfig'.bicep.setup{
|
|
||||||
cmd = { "dotnet", bicep_lsp_bin };
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To download the latest release and place in /usr/local/bin/bicep-langserver:
|
|
||||||
```bash
|
|
||||||
(cd $(mktemp -d) \
|
|
||||||
&& curl -fLO https://github.com/Azure/bicep/releases/latest/download/bicep-langserver.zip \
|
|
||||||
&& rm -rf /usr/local/bin/bicep-langserver \
|
|
||||||
&& unzip -d /usr/local/bin/bicep-langserver bicep-langserver.zip)
|
|
||||||
```
|
|
||||||
]=],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[util.find_git_ancestor]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
filetypes = { 'bsl', 'os' },
|
|
||||||
root_dir = util.find_git_ancestor,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/1c-syntax/bsl-language-server
|
|
||||||
|
|
||||||
Language Server Protocol implementation for 1C (BSL) - 1C:Enterprise 8 and OneScript languages.
|
|
||||||
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern(".git")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'ccls' },
|
|
||||||
filetypes = { 'c', 'cpp', 'objc', 'objcpp' },
|
|
||||||
root_dir = util.root_pattern('compile_commands.json', '.ccls', '.git'),
|
|
||||||
-- ccls does not support sending a null root directory
|
|
||||||
single_file_support = false,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/MaskRay/ccls/wiki
|
|
||||||
|
|
||||||
ccls relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) specified
|
|
||||||
as compile_commands.json or, for simpler projects, a .ccls.
|
|
||||||
For details on how to automatically generate one using CMake look [here](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html). Alternatively, you can use [Bear](https://github.com/rizsotto/Bear).
|
|
||||||
|
|
||||||
Customization options are passed to ccls at initialization time via init_options, a list of available options can be found [here](https://github.com/MaskRay/ccls/wiki/Customization#initialization-options). For example:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local lspconfig = require'lspconfig'
|
|
||||||
lspconfig.ccls.setup {
|
|
||||||
init_options = {
|
|
||||||
compilationDatabaseDirectory = "build";
|
|
||||||
index = {
|
|
||||||
threads = 0;
|
|
||||||
};
|
|
||||||
clang = {
|
|
||||||
excludeArgs = { "-frounding-math"} ;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("compile_commands.json", ".ccls", ".git")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
-- https://clangd.llvm.org/extensions.html#switch-between-sourceheader
|
|
||||||
local function switch_source_header(bufnr)
|
|
||||||
bufnr = util.validate_bufnr(bufnr)
|
|
||||||
local clangd_client = util.get_active_client_by_name(bufnr, 'clangd')
|
|
||||||
local params = { uri = vim.uri_from_bufnr(bufnr) }
|
|
||||||
if clangd_client then
|
|
||||||
clangd_client.request('textDocument/switchSourceHeader', params, function(err, result)
|
|
||||||
if err then
|
|
||||||
error(tostring(err))
|
|
||||||
end
|
|
||||||
if not result then
|
|
||||||
print 'Corresponding file cannot be determined'
|
|
||||||
return
|
|
||||||
end
|
|
||||||
vim.api.nvim_command('edit ' .. vim.uri_to_fname(result))
|
|
||||||
end, bufnr)
|
|
||||||
else
|
|
||||||
print 'method textDocument/switchSourceHeader is not supported by any servers active on the current buffer'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local root_pattern = util.root_pattern('compile_commands.json', 'compile_flags.txt', '.git')
|
|
||||||
|
|
||||||
local default_capabilities = vim.tbl_deep_extend(
|
|
||||||
'force',
|
|
||||||
util.default_config.capabilities or vim.lsp.protocol.make_client_capabilities(),
|
|
||||||
{
|
|
||||||
textDocument = {
|
|
||||||
completion = {
|
|
||||||
editsNearCursor = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
offsetEncoding = { 'utf-8', 'utf-16' },
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'clangd' },
|
|
||||||
filetypes = { 'c', 'cpp', 'objc', 'objcpp' },
|
|
||||||
root_dir = function(fname)
|
|
||||||
local filename = util.path.is_absolute(fname) and fname or util.path.join(vim.loop.cwd(), fname)
|
|
||||||
return root_pattern(filename)
|
|
||||||
end,
|
|
||||||
single_file_support = true,
|
|
||||||
capabilities = default_capabilities,
|
|
||||||
},
|
|
||||||
commands = {
|
|
||||||
ClangdSwitchSourceHeader = {
|
|
||||||
function()
|
|
||||||
switch_source_header(0)
|
|
||||||
end,
|
|
||||||
description = 'Switch between source/header',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://clangd.llvm.org/installation.html
|
|
||||||
|
|
||||||
**NOTE:** Clang >= 9 is recommended! See [this issue for more](https://github.com/neovim/nvim-lsp/issues/23).
|
|
||||||
|
|
||||||
clangd relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) specified
|
|
||||||
as compile_commands.json or, for simpler projects, a compile_flags.txt.
|
|
||||||
For details on how to automatically generate one using CMake look [here](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html). Alternatively, you can use [Bear](https://github.com/rizsotto/Bear).
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("compile_commands.json", "compile_flags.txt", ".git") or dirname]],
|
|
||||||
capabilities = [[default capabilities, with offsetEncoding utf-8]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'clojure-lsp' },
|
|
||||||
filetypes = { 'clojure', 'edn' },
|
|
||||||
root_dir = util.root_pattern('project.clj', 'deps.edn', 'build.boot', 'shadow-cljs.edn', '.git'),
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/snoe/clojure-lsp
|
|
||||||
|
|
||||||
Clojure Language Server
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("project.clj", "deps.edn", "build.boot", "shadow-cljs.edn", ".git")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'cmake-language-server' },
|
|
||||||
filetypes = { 'cmake' },
|
|
||||||
root_dir = util.root_pattern('.git', 'compile_commands.json', 'build'),
|
|
||||||
single_file_support = true,
|
|
||||||
init_options = {
|
|
||||||
buildDirectory = 'build',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/regen100/cmake-language-server
|
|
||||||
|
|
||||||
CMake LSP Implementation
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern(".git", "compile_commands.json", "build") or dirname]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'codeql', 'execute', 'language-server', '--check-errors', 'ON_CHANGE', '-q' },
|
|
||||||
filetypes = { 'ql' },
|
|
||||||
root_dir = util.root_pattern 'qlpack.yml',
|
|
||||||
log_level = vim.lsp.protocol.MessageType.Warning,
|
|
||||||
before_init = function(initialize_params)
|
|
||||||
initialize_params['workspaceFolders'] = {
|
|
||||||
{
|
|
||||||
name = 'workspace',
|
|
||||||
uri = initialize_params['rootUri'],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
end,
|
|
||||||
settings = {
|
|
||||||
search_path = vim.empty_dict(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
Reference:
|
|
||||||
https://help.semmle.com/codeql/codeql-cli.html
|
|
||||||
|
|
||||||
Binaries:
|
|
||||||
https://github.com/github/codeql-cli-binaries
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
settings = {
|
|
||||||
search_path = [[list containing all search paths, eg: '~/codeql-home/codeql-repo']],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
on_new_config = function(config)
|
|
||||||
if type(config.settings.search_path) == 'table' and not vim.tbl_isempty(config.settings.search_path) then
|
|
||||||
local search_path = '--search-path='
|
|
||||||
for _, path in ipairs(config.settings.search_path) do
|
|
||||||
search_path = search_path .. vim.fn.expand(path) .. ':'
|
|
||||||
end
|
|
||||||
config.cmd = { 'codeql', 'execute', 'language-server', '--check-errors', 'ON_CHANGE', '-q', search_path }
|
|
||||||
else
|
|
||||||
config.cmd = { 'codeql', 'execute', 'language-server', '--check-errors', 'ON_CHANGE', '-q' }
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'crystalline' },
|
|
||||||
filetypes = { 'crystal' },
|
|
||||||
root_dir = util.root_pattern 'shard.yml' or util.find_git_ancestor,
|
|
||||||
single_file_support = true,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/elbywan/crystalline
|
|
||||||
|
|
||||||
Crystal language server.
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern('shard.yml', '.git') or dirname]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'csharp-ls' },
|
|
||||||
root_dir = util.root_pattern('*.sln', '*.csproj', '.git'),
|
|
||||||
filetypes = { 'cs' },
|
|
||||||
init_options = {
|
|
||||||
AutomaticWorkspaceInit = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/razzmatazz/csharp-language-server
|
|
||||||
|
|
||||||
Language Server for C#.
|
|
||||||
|
|
||||||
csharp-ls requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed.
|
|
||||||
|
|
||||||
The preferred way to install csharp-ls is with `dotnet tool install --global csharp-ls`.
|
|
||||||
]],
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
local bin_name = 'vscode-css-language-server'
|
|
||||||
local cmd = { bin_name, '--stdio' }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name, '--stdio' }
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = cmd,
|
|
||||||
filetypes = { 'css', 'scss', 'less' },
|
|
||||||
root_dir = util.root_pattern('package.json', '.git'),
|
|
||||||
single_file_support = true,
|
|
||||||
settings = {
|
|
||||||
css = { validate = true },
|
|
||||||
scss = { validate = true },
|
|
||||||
less = { validate = true },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
|
|
||||||
https://github.com/hrsh7th/vscode-langservers-extracted
|
|
||||||
|
|
||||||
`css-languageserver` can be installed via `npm`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm i -g vscode-langservers-extracted
|
|
||||||
```
|
|
||||||
|
|
||||||
Neovim does not currently include built-in snippets. `vscode-css-language-server` only provides completions when snippet support is enabled. To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
--Enable (broadcasting) snippet capability for completion
|
|
||||||
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
|
||||||
capabilities.textDocument.completion.completionItem.snippetSupport = true
|
|
||||||
|
|
||||||
require'lspconfig'.cssls.setup {
|
|
||||||
capabilities = capabilities,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("package.json", ".git") or bufdir]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
local bin_name = 'cssmodules-language-server'
|
|
||||||
local cmd = { bin_name }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name }
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = cmd,
|
|
||||||
filetypes = { 'javascript', 'javascriptreact', 'typescript', 'typescriptreact' },
|
|
||||||
root_dir = util.find_package_json_ancestor,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/antonk52/cssmodules-language-server
|
|
||||||
|
|
||||||
Language server for autocompletion and go-to-definition functionality for CSS modules.
|
|
||||||
|
|
||||||
You can install cssmodules-language-server via npm:
|
|
||||||
```sh
|
|
||||||
npm install -g cssmodules-language-server
|
|
||||||
```
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("package.json")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
local bin_name = 'cucumber-language-server'
|
|
||||||
local cmd = { bin_name, '--stdio' }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name, '--stdio' }
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = cmd,
|
|
||||||
filetypes = { 'cucumber' },
|
|
||||||
root_dir = util.find_git_ancestor,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://cucumber.io
|
|
||||||
https://github.com/cucumber/common
|
|
||||||
https://www.npmjs.com/package/@cucumber/language-server
|
|
||||||
|
|
||||||
Language server for Cucumber.
|
|
||||||
|
|
||||||
`cucumber-language-server` can be installed via `npm`:
|
|
||||||
```sh
|
|
||||||
npm install -g @cucumber/language-server
|
|
||||||
```
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[util.find_git_ancestor]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
local bin_name = 'dart'
|
|
||||||
|
|
||||||
local find_dart_sdk_root_path = function()
|
|
||||||
if os.getenv 'FLUTTER_SDK' then
|
|
||||||
local flutter_path = os.getenv 'FLUTTER_SDK'
|
|
||||||
return util.path.join(flutter_path, 'cache', 'dart-sdk', 'bin', 'dart')
|
|
||||||
elseif vim.fn['executable'] 'flutter' == 1 then
|
|
||||||
local flutter_path = vim.fn['resolve'](vim.fn['exepath'] 'flutter')
|
|
||||||
local flutter_bin = vim.fn['fnamemodify'](flutter_path, ':h')
|
|
||||||
return util.path.join(flutter_bin, 'cache', 'dart-sdk', 'bin', 'dart')
|
|
||||||
elseif vim.fn['executable'] 'dart' == 1 then
|
|
||||||
return vim.fn['resolve'](vim.fn['exepath'] 'dart')
|
|
||||||
else
|
|
||||||
return ''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local analysis_server_snapshot_path = function()
|
|
||||||
local dart_sdk_root_path = vim.fn['fnamemodify'](find_dart_sdk_root_path(), ':h')
|
|
||||||
local snapshot = util.path.join(dart_sdk_root_path, 'snapshots', 'analysis_server.dart.snapshot')
|
|
||||||
|
|
||||||
if vim.fn['has'] 'win32' == 1 or vim.fn['has'] 'win64' == 1 then
|
|
||||||
snapshot = snapshot:gsub('/', '\\')
|
|
||||||
end
|
|
||||||
|
|
||||||
return snapshot
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { bin_name, analysis_server_snapshot_path(), '--lsp' },
|
|
||||||
filetypes = { 'dart' },
|
|
||||||
root_dir = util.root_pattern 'pubspec.yaml',
|
|
||||||
init_options = {
|
|
||||||
onlyAnalyzeProjectsWithOpenFiles = true,
|
|
||||||
suggestFromUnimportedLibraries = true,
|
|
||||||
closingLabels = true,
|
|
||||||
outline = true,
|
|
||||||
flutterOutline = true,
|
|
||||||
},
|
|
||||||
settings = {
|
|
||||||
dart = {
|
|
||||||
completeFunctionCalls = true,
|
|
||||||
showTodos = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
package_json = 'https://raw.githubusercontent.com/Dart-Code/Dart-Code/master/package.json',
|
|
||||||
description = [[
|
|
||||||
https://github.com/dart-lang/sdk/tree/master/pkg/analysis_server/tool/lsp_spec
|
|
||||||
|
|
||||||
Language server for dart.
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("pubspec.yaml")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
local lsp = vim.lsp
|
|
||||||
|
|
||||||
local function buf_cache(bufnr)
|
|
||||||
local params = {}
|
|
||||||
params['referrer'] = { uri = vim.uri_from_bufnr(bufnr) }
|
|
||||||
params['uris'] = {}
|
|
||||||
lsp.buf_request(bufnr, 'deno/cache', params, function(err)
|
|
||||||
if err then
|
|
||||||
error(tostring(err))
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function virtual_text_document_handler(uri, result)
|
|
||||||
if not result then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
for client_id, res in pairs(result) do
|
|
||||||
local lines = vim.split(res.result, '\n')
|
|
||||||
local bufnr = vim.uri_to_bufnr(uri)
|
|
||||||
|
|
||||||
local current_buf = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
|
||||||
if #current_buf ~= 0 then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, nil, lines)
|
|
||||||
vim.api.nvim_buf_set_option(bufnr, 'readonly', true)
|
|
||||||
vim.api.nvim_buf_set_option(bufnr, 'modified', false)
|
|
||||||
vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
|
|
||||||
lsp.buf_attach_client(bufnr, client_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function virtual_text_document(uri)
|
|
||||||
local params = {
|
|
||||||
textDocument = {
|
|
||||||
uri = uri,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
local result = lsp.buf_request_sync(0, 'deno/virtualTextDocument', params)
|
|
||||||
virtual_text_document_handler(uri, result)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function denols_handler(err, result, ctx)
|
|
||||||
if not result or vim.tbl_isempty(result) then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, res in pairs(result) do
|
|
||||||
local uri = res.uri or res.targetUri
|
|
||||||
if uri:match '^deno:' then
|
|
||||||
virtual_text_document(uri)
|
|
||||||
res['uri'] = uri
|
|
||||||
res['targetUri'] = uri
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
lsp.handlers[ctx.method](err, result, ctx)
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'deno', 'lsp' },
|
|
||||||
filetypes = {
|
|
||||||
'javascript',
|
|
||||||
'javascriptreact',
|
|
||||||
'javascript.jsx',
|
|
||||||
'typescript',
|
|
||||||
'typescriptreact',
|
|
||||||
'typescript.tsx',
|
|
||||||
},
|
|
||||||
root_dir = util.root_pattern('deno.json', 'deno.jsonc', 'tsconfig.json', '.git'),
|
|
||||||
init_options = {
|
|
||||||
enable = true,
|
|
||||||
lint = false,
|
|
||||||
unstable = false,
|
|
||||||
},
|
|
||||||
handlers = {
|
|
||||||
['textDocument/definition'] = denols_handler,
|
|
||||||
['textDocument/references'] = denols_handler,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
commands = {
|
|
||||||
DenolsCache = {
|
|
||||||
function()
|
|
||||||
buf_cache(0)
|
|
||||||
end,
|
|
||||||
description = 'Cache a module and all of its dependencies.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
package_json = 'https://raw.githubusercontent.com/denoland/vscode_deno/main/package.json',
|
|
||||||
description = [[
|
|
||||||
https://github.com/denoland/deno
|
|
||||||
|
|
||||||
Deno's built-in language server
|
|
||||||
|
|
||||||
To approrpiately highlight codefences returned from denols, you will need to augment vim.g.markdown_fenced languages
|
|
||||||
in your init.lua. Example:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
vim.g.markdown_fenced_languages = {
|
|
||||||
"ts=typescript"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("deno.json", "deno.jsonc", "tsconfig.json", ".git")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'dhall-lsp-server' },
|
|
||||||
filetypes = { 'dhall' },
|
|
||||||
root_dir = util.find_git_ancestor,
|
|
||||||
single_file_support = true,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/dhall-lang/dhall-haskell/tree/master/dhall-lsp-server
|
|
||||||
|
|
||||||
language server for dhall
|
|
||||||
|
|
||||||
`dhall-lsp-server` can be installed via cabal:
|
|
||||||
```sh
|
|
||||||
cabal install dhall-lsp-server
|
|
||||||
```
|
|
||||||
prebuilt binaries can be found [here](https://github.com/dhall-lang/dhall-haskell/releases).
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern(".git") or dirname]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
local bin_name = 'diagnostic-languageserver'
|
|
||||||
local cmd = { bin_name, '--stdio' }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name, '--stdio' }
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = cmd,
|
|
||||||
root_dir = util.find_git_ancestor,
|
|
||||||
single_file_support = true,
|
|
||||||
filetypes = {},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/iamcco/diagnostic-languageserver
|
|
||||||
|
|
||||||
Diagnostic language server integrate with linters.
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
filetypes = 'Empty by default, override to add filetypes',
|
|
||||||
root_dir = "Vim's starting directory",
|
|
||||||
init_options = 'Configuration from https://github.com/iamcco/diagnostic-languageserver#config--document',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
local bin_name = 'docker-langserver'
|
|
||||||
local cmd = { bin_name, '--stdio' }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name, '--stdio' }
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = cmd,
|
|
||||||
filetypes = { 'dockerfile' },
|
|
||||||
root_dir = util.root_pattern 'Dockerfile',
|
|
||||||
single_file_support = true,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/rcjsuen/dockerfile-language-server-nodejs
|
|
||||||
|
|
||||||
`docker-langserver` can be installed via `npm`:
|
|
||||||
```sh
|
|
||||||
npm install -g dockerfile-language-server-nodejs
|
|
||||||
```
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("Dockerfile")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
local bin_name = 'dot-language-server'
|
|
||||||
local cmd = { bin_name, '--stdio' }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name, '--stdio' }
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = cmd,
|
|
||||||
filetypes = { 'dot' },
|
|
||||||
root_dir = util.find_git_ancestor,
|
|
||||||
single_file_support = true,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/nikeee/dot-language-server
|
|
||||||
|
|
||||||
`dot-language-server` can be installed via `npm`:
|
|
||||||
```sh
|
|
||||||
npm install -g dot-language-server
|
|
||||||
```
|
|
||||||
]],
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = { 'efm-langserver' },
|
|
||||||
root_dir = util.find_git_ancestor,
|
|
||||||
single_file_support = true,
|
|
||||||
},
|
|
||||||
|
|
||||||
docs = {
|
|
||||||
description = [[
|
|
||||||
https://github.com/mattn/efm-langserver
|
|
||||||
|
|
||||||
General purpose Language Server that can use specified error message format generated from specified command.
|
|
||||||
|
|
||||||
Requires at minimum EFM version [v0.0.38](https://github.com/mattn/efm-langserver/releases/tag/v0.0.38) to support
|
|
||||||
launching the language server on single files. If on an older version of EFM, disable single file support:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
require('lspconfig')['efm'].setup{
|
|
||||||
settings = ..., -- You must populate this according to the EFM readme
|
|
||||||
filetypes = ..., -- Populate this according to the note below
|
|
||||||
single_file_support = false, -- This is the important line for supporting older version of EFM
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: In order for neovim's built-in language server client to send the appropriate `languageId` to EFM, **you must
|
|
||||||
specify `filetypes` in your call to `setup{}`**. Otherwise `lspconfig` will launch EFM on the `BufEnter` instead
|
|
||||||
of the `FileType` autocommand, and the `filetype` variable used to populate the `languageId` will not yet be set.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
require('lspconfig')['efm'].setup{
|
|
||||||
settings = ..., -- You must populate this according to the EFM readme
|
|
||||||
filetypes = { 'python','cpp','lua' }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[util.root_pattern(".git")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
filetypes = { 'elixir', 'eelixir' },
|
|
||||||
root_dir = function(fname)
|
|
||||||
return util.root_pattern('mix.exs', '.git')(fname) or vim.loop.os_homedir()
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
package_json = 'https://raw.githubusercontent.com/elixir-lsp/vscode-elixir-ls/master/package.json',
|
|
||||||
description = [[
|
|
||||||
https://github.com/elixir-lsp/elixir-ls
|
|
||||||
|
|
||||||
`elixir-ls` can be installed by following the instructions [here](https://github.com/elixir-lsp/elixir-ls#building-and-running).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -fLO https://github.com/elixir-lsp/elixir-ls/releases/latest/download/elixir-ls.zip
|
|
||||||
unzip elixir-ls.zip -d /path/to/elixir-ls
|
|
||||||
# Unix
|
|
||||||
chmod +x /path/to/elixir-ls/language_server.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
**By default, elixir-ls doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of your unzipped elixir-ls.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
require'lspconfig'.elixirls.setup{
|
|
||||||
-- Unix
|
|
||||||
cmd = { "/path/to/elixir-ls/language_server.sh" };
|
|
||||||
-- Windows
|
|
||||||
cmd = { "/path/to/elixir-ls/language_server.bat" };
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("mix.exs", ".git") or vim.loop.os_homedir()]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
local util = require 'lspconfig.util'
|
|
||||||
local lsp = vim.lsp
|
|
||||||
local api = vim.api
|
|
||||||
|
|
||||||
local bin_name = 'elm-language-server'
|
|
||||||
local cmd = { bin_name }
|
|
||||||
|
|
||||||
if vim.fn.has 'win32' == 1 then
|
|
||||||
cmd = { 'cmd.exe', '/C', bin_name }
|
|
||||||
end
|
|
||||||
|
|
||||||
local default_capabilities = lsp.protocol.make_client_capabilities()
|
|
||||||
default_capabilities.offsetEncoding = { 'utf-8', 'utf-16' }
|
|
||||||
local elm_root_pattern = util.root_pattern 'elm.json'
|
|
||||||
|
|
||||||
return {
|
|
||||||
default_config = {
|
|
||||||
cmd = cmd,
|
|
||||||
-- TODO(ashkan) if we comment this out, it will allow elmls to operate on elm.json. It seems like it could do that, but no other editor allows it right now.
|
|
||||||
filetypes = { 'elm' },
|
|
||||||
root_dir = function(fname)
|
|
||||||
local filetype = api.nvim_buf_get_option(0, 'filetype')
|
|
||||||
if filetype == 'elm' or (filetype == 'json' and fname:match 'elm%.json$') then
|
|
||||||
return elm_root_pattern(fname)
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
init_options = {
|
|
||||||
elmPath = 'elm',
|
|
||||||
elmFormatPath = 'elm-format',
|
|
||||||
elmTestPath = 'elm-test',
|
|
||||||
elmAnalyseTrigger = 'change',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
docs = {
|
|
||||||
package_json = 'https://raw.githubusercontent.com/elm-tooling/elm-language-client-vscode/master/package.json',
|
|
||||||
description = [[
|
|
||||||
https://github.com/elm-tooling/elm-language-server#installation
|
|
||||||
|
|
||||||
If you don't want to use Nvim to install it, then you can use:
|
|
||||||
```sh
|
|
||||||
npm install -g elm elm-test elm-format @elm-tooling/elm-language-server
|
|
||||||
```
|
|
||||||
]],
|
|
||||||
default_config = {
|
|
||||||
root_dir = [[root_pattern("elm.json")]],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue