Browse Source

vim: update coc.nvim

Maxim Likhachev 3 years ago
parent
commit
4dff3248a0
  1. 47
      etc/soft/nvim/+plugins/coc.nvim/LICENSE.md
  2. 45
      etc/soft/nvim/+plugins/coc.nvim/README.md
  3. 59
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc.vim
  4. 56
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/api.vim
  5. 13
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/client.vim
  6. 50
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/compat.vim
  7. 19
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/cursor.vim
  8. 28
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/float.vim
  9. 365
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/highlight.vim
  10. 81
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/list.vim
  11. 19
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/rpc.vim
  12. 11
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/snippet.vim
  13. 2
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/task.vim
  14. 16
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/terminal.vim
  15. 178
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/util.vim
  16. 65
      etc/soft/nvim/+plugins/coc.nvim/autoload/coc/window.vim
  17. 24
      etc/soft/nvim/+plugins/coc.nvim/autoload/health/coc.vim
  18. 87983
      etc/soft/nvim/+plugins/coc.nvim/build/index.js
  19. 277
      etc/soft/nvim/+plugins/coc.nvim/data/schema.json
  20. 1041
      etc/soft/nvim/+plugins/coc.nvim/doc/coc.txt
  21. 18
      etc/soft/nvim/+plugins/coc.nvim/esbuild.js
  22. 182
      etc/soft/nvim/+plugins/coc.nvim/history.md
  23. 6221
      etc/soft/nvim/+plugins/coc.nvim/package-lock.json
  24. 68
      etc/soft/nvim/+plugins/coc.nvim/package.json
  25. 193
      etc/soft/nvim/+plugins/coc.nvim/plugin/coc.vim
  26. 0
      etc/soft/nvim/+plugins/coc.nvim/requirements.txt
  27. 17
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/autoload/coc/source/email.vim
  28. 62
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/changedFiles.test.ts
  29. 140
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/connection.test.ts
  30. 89
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/converter.test.ts
  31. 154
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/delayer.test.ts
  32. 1054
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/features.test.ts
  33. 128
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/integration.test.ts
  34. 35
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/server/testFileWatcher.js
  35. 40
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/server/testInitializeResult.js
  36. 414
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/server/testServer.js
  37. 5
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/coc-settings.json
  38. 446
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/completion/basic.test.ts
  39. 122
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/completion/float.test.ts
  40. 66
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/completion/match.test.ts
  41. 92
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/completion/sources.test.ts
  42. 32
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/completion/util.test.ts
  43. 7
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/global/index.js
  44. 7
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/global/package.json
  45. 6
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/package.json
  46. 7
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/root.js
  47. 13
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/test/index.js
  48. 33
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/test/package.json
  49. 7
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/vim/local/index.js
  50. 7
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/vim/local/package.json
  51. 398
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/callHierarchy.test.ts
  52. 386
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/codeActions.test.ts
  53. 269
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/codelens.test.ts
  54. 254
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/colors.test.ts
  55. 82
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/commands.test.ts
  56. 71
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/fold.test.ts
  57. 253
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/format.test.ts
  58. 138
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/highlights.test.ts
  59. 178
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/hover.test.ts
  60. 93
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/index.test.ts
  61. 99
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/links.test.ts
  62. 306
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/locations.test.ts
  63. 426
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/outline.test.ts
  64. 117
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/parser.ts
  65. 347
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/refactor.test.ts
  66. 263
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/rename.test.ts
  67. 101
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/search.test.ts
  68. 143
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/selectionRange.test.ts
  69. 180
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/semanticTokens.test.ts
  70. 376
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/signature.test.ts
  71. 284
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/symbols.test.ts
  72. 22
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/helper.test.ts
  73. 248
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/helper.ts
  74. 174
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/basicList.test.ts
  75. 134
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/commandTask.test.ts
  76. 32
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/formatting.test.ts
  77. 79
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/location.test.ts
  78. 509
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/manager.test.ts
  79. 903
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/mappings.test.ts
  80. 246
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/session.test.ts
  81. 203
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/sources.test.ts
  82. 140
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/ui.test.ts
  83. 204
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/worker.test.ts
  84. 151
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/markdown/index.test.ts
  85. 119
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/markdown/renderer.test.ts
  86. 1
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/memos.json
  87. 35
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/array.test.ts
  88. 53
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/attach.test.ts
  89. 78
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/chars.test.ts
  90. 35
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/client.test.ts
  91. 728
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/completion.test.ts
  92. 247
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/configurations.test.ts
  93. 421
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/cursors.test.ts
  94. 60
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/db.test.ts
  95. 27
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/decorator.test.ts
  96. 250
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/diagnosticBuffer.test.ts
  97. 98
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/diagnosticCollection.test.ts
  98. 556
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/diagnosticManager.test.ts
  99. 60
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/dialog.test.ts
  100. 178
      etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/diff.test.ts
  101. Some files were not shown because too many files have changed in this diff Show More

47
etc/soft/nvim/+plugins/coc.nvim/LICENSE.md

@ -1,7 +1,46 @@ @@ -1,7 +1,46 @@
Copyright 2018-2018 by Qiming Zhao <chemzqm@gmail.com>
Copyright (c) <2022> <chemzqm@gmail.com>
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:
"Anti 996" License Version 1.0 (Draft)
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Permission is hereby granted to any individual or legal entity
obtaining a copy of this licensed work (including the source code,
documentation and/or related items, hereinafter collectively referred
to as the "licensed work"), free of charge, to deal with the licensed
work for any purpose, including without limitation, the rights to use,
reproduce, modify, prepare derivative works of, distribute, publish
and sublicense the licensed work, subject to the following conditions:
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. The individual or the legal entity must conspicuously display,
without modification, this License and the notice on each redistributed
or derivative copy of the Licensed Work.
2. The individual or the legal entity must strictly comply with all
applicable laws, regulations, rules and standards of the jurisdiction
relating to labor and employment where the individual is physically
located or where the individual was born or naturalized; or where the
legal entity is registered or is operating (whichever is stricter). In
case that the jurisdiction has no such laws, regulations, rules and
standards or its laws, regulations, rules and standards are
unenforceable, the individual or the legal entity are required to
comply with Core International Labor Standards.
3. The individual or the legal entity shall not induce, suggest or force
its employee(s), whether full-time or part-time, or its independent
contractor(s), in any methods, to agree in oral or written form, to
directly or indirectly restrict, weaken or relinquish his or her
rights or remedies under such laws, regulations, rules and standards
relating to labor and employment as mentioned above, no matter whether
such written or oral agreements are enforceable under the laws of the
said jurisdiction, nor shall such individual or the legal entity
limit, in any methods, the rights of its employee(s) or independent
contractor(s) from reporting or complaining to the copyright holder or
relevant authorities monitoring the compliance of the license about
its violation(s) of the said license.
THE LICENSED WORK 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 COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN ANY WAY CONNECTION WITH THE
LICENSED WORK OR THE USE OR OTHER DEALINGS IN THE LICENSED WORK.

45
etc/soft/nvim/+plugins/coc.nvim/README.md

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
</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-MIT-brightgreen.svg?style=flat-square"></a>
<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/workflow/status/neoclide/coc.nvim/coc.nvim%20CI?style=flat-square"></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>
@ -25,12 +25,30 @@ _True snippet and additional text editing support_ @@ -25,12 +25,30 @@ _True snippet and additional text editing support_
- 🌟 **Featured**: [full LSP support](https://github.com/neoclide/coc.nvim/wiki/Language-servers#supported-features)
- ❤ **Flexible**: [configured like VSCode](https://github.com/neoclide/coc.nvim/wiki/Using-the-configuration-file), [extensions work like in VSCode](https://github.com/neoclide/coc.nvim/wiki/Using-coc-extensions)
**Gold Sponsors**
<a href="https://opencollective.com/cocnvim#platinum-sponsors">
<img src="https://opencollective.com/cocnvim/tiers/gold-sponsors.svg?avatarHeight=36&width=600">
</a>
**Silver Sponsors**
<a href="https://opencollective.com/cocnvim#platinum-sponsors">
<img src="https://opencollective.com/cocnvim/tiers/silver-sponsors.svg?avatarHeight=36&width=600">
</a>
**Bronze Sponsors**
<a href="https://opencollective.com/cocnvim#platinum-sponsors">
<img src="https://opencollective.com/cocnvim/tiers/bronze-sponsors.svg?avatarHeight=36&width=600">
</a>
## Quick Start
Install [nodejs](https://nodejs.org/en/download/) >= 12.12:
```sh
curl -sL install-node.now.sh/lts | bash
```bash
curl -sL install-node.vercel.app/lts | bash
```
For [vim-plug](https://github.com/junegunn/vim-plug) users:
@ -200,6 +218,9 @@ nmap <leader>ac <Plug>(coc-codeaction) @@ -200,6 +218,9 @@ nmap <leader>ac <Plug>(coc-codeaction)
" Apply AutoFix to problem on the current line.
nmap <leader>qf <Plug>(coc-fix-current)
" 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)
@ -227,13 +248,13 @@ nmap <silent> <C-s> <Plug>(coc-range-select) @@ -227,13 +248,13 @@ 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 CocAction('format')
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 CocAction('runCommand', 'editor.action.organizeImport')
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
@ -322,6 +343,18 @@ Try these steps when you have problem with coc.nvim. @@ -322,6 +343,18 @@ Try these steps when you have problem with coc.nvim.
<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" target="_blank"><img src="https://images.opencollective.com/static/images/become_backer.svg"></a>
@ -331,4 +364,4 @@ Buy cloud service from [www.vultr.com](https://www.vultr.com/?ref=8890170-6G) @@ -331,4 +364,4 @@ Buy cloud service from [www.vultr.com](https://www.vultr.com/?ref=8890170-6G)
## License
MIT
Anti 996

59
etc/soft/nvim/+plugins/coc.nvim/autoload/coc.vim

@ -9,6 +9,7 @@ let s:is_vim = !has('nvim') @@ -9,6 +9,7 @@ let s:is_vim = !has('nvim')
let s:error_sign = get(g:, 'coc_status_error_sign', has('mac') ? '❌ ' : 'E')
let s:warning_sign = get(g:, 'coc_status_warning_sign', has('mac') ? '⚠ ' : 'W')
let s:select_api = exists('*nvim_select_popupmenu_item')
let s:complete_info_api = exists('*complete_info')
let s:callbacks = {}
function! coc#expandable() abort
@ -41,10 +42,19 @@ function! coc#on_enter() @@ -41,10 +42,19 @@ function! coc#on_enter()
endfunction
function! coc#_insert_key(method, key, ...) abort
let prefix = ''
if get(a:, 1, 1)
call coc#_cancel()
if pumvisible()
call coc#rpc#notify('CocAutocmd', ['ClosePum'])
if has('nvim-0.6.0') || has('patch-8.2.3389')
let prefix = "\<C-x>\<C-z>"
else
let g:coc_disable_space_report = 1
let prefix = "\<space>\<bs>"
endif
endif
endif
return "\<c-r>=coc#rpc#".a:method."('doKeymap', ['".a:key."'])\<CR>"
return prefix."\<c-r>=coc#rpc#".a:method."('doKeymap', ['".a:key."'])\<CR>"
endfunction
function! coc#_complete() abort
@ -79,7 +89,7 @@ function! coc#_select_confirm() abort @@ -79,7 +89,7 @@ function! coc#_select_confirm() abort
endif
let selected = complete_info()['selected']
if selected != -1
return "\<C-y>"
return "\<C-y>"
elseif pumvisible()
return "\<down>\<C-y>"
endif
@ -91,17 +101,28 @@ function! coc#_selected() @@ -91,17 +101,28 @@ function! coc#_selected()
return coc#rpc#request('hasSelected', [])
endfunction
" Deprecated
function! coc#_hide() abort
if !pumvisible() | return | endif
call feedkeys("\<C-e>", 'in')
if pumvisible()
" Make input as it is, it's not possible by `<C-e>` and `<C-p>`
call coc#rpc#notify('CocAutocmd', ['ClosePum'])
call feedkeys("\<C-x>\<C-z>", 'in')
endif
endfunction
function! coc#_cancel()
" hack for close pum
" Use of <C-e> could cause bad insert when cursor just moved.
if pumvisible()
let g:coc#_context = {'start': 0, 'preselect': -1,'candidates': []}
call feedkeys("\<Plug>CocRefresh", 'i')
call coc#rpc#notify('stopCompletion', [])
call coc#rpc#notify('CocAutocmd', ['ClosePum'])
if has('nvim-0.6.0') || has('patch-8.2.3389')
call feedkeys("\<C-x>\<C-z>", 'in')
elseif exists('*complete_info') && get(complete_info(['selected']), 'selected', -1) == -1
call feedkeys("\<C-e>", 'in')
else
let g:coc_disable_space_report = 1
call feedkeys("\<space>\<bs>", 'in')
endif
endif
endfunction
@ -194,3 +215,25 @@ function! coc#do_notify(id, method, result) @@ -194,3 +215,25 @@ function! coc#do_notify(id, method, result)
call Fn(a:result)
endif
endfunction
function! coc#complete_indent() abort
let l:curpos = getcurpos()
let l:indent_pre = indent('.')
let l:startofline = &startofline
let l:virtualedit = &virtualedit
set nostartofline
set virtualedit=all
normal! ==
let &startofline = l:startofline
let &virtualedit = l:virtualedit
let l:shift = indent('.') - l:indent_pre
let l:curpos[2] += l:shift
let l:curpos[4] += l:shift
call cursor(l:curpos[1:])
if l:shift != 0
return 1
endif
return 0
endfunction

56
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/api.vim

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
" ============================================================================
" Description: Client api used by vim8
" Author: Qiming Zhao <chemzqm@gmail.com>
" Licence: MIT licence
" Last Modified: Aug 10, 2021
" Licence: Anti 996 licence
" Last Modified: Mar 08, 2022
" ============================================================================
if has('nvim') | finish | endif
scriptencoding utf-8
@ -21,16 +21,19 @@ function! s:buf_line_count(bufnr) abort @@ -21,16 +21,19 @@ function! s:buf_line_count(bufnr) abort
if empty(info)
return 0
endif
return info[0]['linecount']
" 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 'buffer '.a:bufnr
execute 'noa buffer '.a:bufnr
let n = line('$')
execute 'buffer '.curr
execute 'noa buffer '.curr
return n
endfunction
@ -149,7 +152,7 @@ function! s:funcs.feedkeys(keys, mode, escape_csi) @@ -149,7 +152,7 @@ function! s:funcs.feedkeys(keys, mode, escape_csi)
endfunction
function! s:funcs.list_runtime_paths()
return split(&runtimepath, ',')
return globpath(&runtimepath, '', 0, 1)
endfunction
function! s:funcs.command_output(cmd)
@ -263,14 +266,22 @@ function! s:funcs.buf_get_mark(bufnr, name) @@ -263,14 +266,22 @@ function! s:funcs.buf_get_mark(bufnr, name)
return [line("'" . a:name), col("'" . a:name)]
endfunction
function! s:funcs.buf_add_highlight(bufnr, srcId, hlGroup, line, colStart, colEnd) abort
if !has('textprop') || !has('patch-8.1.1719')
function! s:funcs.buf_add_highlight(bufnr, srcId, hlGroup, line, colStart, colEnd, ...) abort
if !has('patch-8.1.1719')
return
endif
let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
let type = 'CocHighlight'.a:hlGroup
if empty(prop_type_get(type))
call prop_type_add(type, {'highlight': a:hlGroup, 'combine': 1})
let opts = get(a:, 1, 0)
let priority = get(opts, 'priority', 0)
call prop_type_add(type, {
\ 'highlight': a:hlGroup,
\ 'priority': type(priority) == 0 ? priority : 0,
\ 'combine': get(opts, 'combine', 1),
\ 'start_incl': get(opts, 'start_incl', 0),
\ 'end_incl': get(opts, 'end_incl', 0),
\ })
endif
let total = strlen(getbufline(bufnr, a:line + 1)[0])
let end = a:colEnd
@ -305,12 +316,12 @@ function! s:funcs.buf_add_highlight(bufnr, srcId, hlGroup, line, colStart, colEn @@ -305,12 +316,12 @@ function! s:funcs.buf_add_highlight(bufnr, srcId, hlGroup, line, colStart, colEn
endfunction
function! s:funcs.buf_clear_namespace(bufnr, srcId, startLine, endLine) abort
if !has('textprop') || !has('patch-8.1.1719')
if !has('patch-8.1.1719')
return
endif
let bufnr = a:bufnr == 0 ? bufnr('%') : a:bufnr
let start = a:startLine + 1
let end = a:endLine == -1 ? len(getbufline(bufnr, 1, '$')) : a:endLine + 1
let end = a:endLine == -1 ? len(getbufline(bufnr, 1, '$')) : a:endLine
if a:srcId == -1
call prop_clear(start, end, {'bufnr' : bufnr})
else
@ -352,7 +363,7 @@ function! s:funcs.buf_set_lines(bufnr, start, end, strict, ...) abort @@ -352,7 +363,7 @@ function! s:funcs.buf_set_lines(bufnr, start, end, strict, ...) abort
endif
let replacement = get(a:, 1, [])
let lineCount = s:buf_line_count(a:bufnr)
let startLnum = a:start >= 0 ? a:start + 1 : lineCount + a:start + 1
let startLnum = a:start >= 0 ? a:start + 1 : lineCount + a:start + 2
let end = a:end >= 0 ? a:end : lineCount + a:end + 1
if end == lineCount + 1
let end = lineCount
@ -376,8 +387,14 @@ function! s:funcs.buf_set_lines(bufnr, start, end, strict, ...) abort @@ -376,8 +387,14 @@ function! s:funcs.buf_set_lines(bufnr, start, end, strict, ...) abort
if delCount
let start = startLnum + len(replacement)
let saved_reg = @"
silent execute start . ','.(start + delCount - 1).'d'
let system_reg = @*
if exists('*deletebufline')
silent call deletebufline(curr, start, start + delCount - 1)
else
silent execute start . ','.(start + delCount - 1).'d'
endif
let @" = saved_reg
let @* = system_reg
endif
endif
call winrestview(storeView)
@ -396,8 +413,12 @@ function! s:funcs.buf_set_lines(bufnr, start, end, strict, ...) abort @@ -396,8 +413,12 @@ function! s:funcs.buf_set_lines(bufnr, start, end, strict, ...) abort
endif
if delCount
let start = startLnum + len(replacement)
let saved_reg = @"
let system_reg = @*
"8.1.0039
silent call deletebufline(a:bufnr, start, start + delCount - 1)
let @" = saved_reg
let @* = system_reg
endif
endif
endif
@ -423,7 +444,14 @@ function! s:funcs.buf_set_var(bufnr, name, val) @@ -423,7 +444,14 @@ function! s:funcs.buf_set_var(bufnr, name, val)
endfunction
function! s:funcs.buf_del_var(bufnr, name)
call coc#compat#buf_del_var(a:bufnr, a:name)
if 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
endfunction
function! s:funcs.buf_get_option(bufnr, name)

13
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/client.vim

@ -5,6 +5,7 @@ let s:is_win = has("win32") || has("win64") @@ -5,6 +5,7 @@ let s:is_win = has("win32") || has("win64")
let s:clients = {}
if get(g:, 'node_client_debug', 0)
echohl WarningMsg | echon '[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)
@ -81,16 +82,20 @@ function! s:start() dict @@ -81,16 +82,20 @@ function! s:start() dict
if has('nvim-0.5.0')
" could use env option
let opts['env'] = {
\ 'COC_NVIM': '1',
\ 'NODE_NO_WARNINGS': '1',
\ 'COC_CHANNEL_TIMEOUT': timeout,
\ 'TMPDIR': tmpdir
\ }
else
let original = {
\ 'NODE_NO_WARNINGS': getenv('NODE_NO_WARNINGS'),
\ 'TMPDIR': getenv('TMPDIR'),
\ }
if exists('*getenv')
let original = {
\ 'NODE_NO_WARNINGS': getenv('NODE_NO_WARNINGS'),
\ 'TMPDIR': getenv('TMPDIR'),
\ }
endif
if exists('*setenv')
call setenv('COC_NVIM', '1')
call setenv('NODE_NO_WARNINGS', '1')
call setenv('COC_CHANNEL_TIMEOUT', timeout)
call setenv('TMPDIR', tmpdir)

50
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/compat.vim

@ -19,6 +19,44 @@ function! coc#compat#buf_set_lines(bufnr, start, end, replacement) abort @@ -19,6 +19,44 @@ function! coc#compat#buf_set_lines(bufnr, start, end, replacement) abort
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)
@ -78,7 +116,7 @@ function! coc#compat#buf_del_var(bufnr, name) abort @@ -78,7 +116,7 @@ function! coc#compat#buf_del_var(bufnr, name) abort
if exists('*nvim_buf_del_var')
silent! call nvim_buf_del_var(a:bufnr, a:name)
else
if bufnr == bufnr('%')
if a:bufnr == bufnr('%')
execute 'unlet! b:'.a:name
elseif exists('*win_execute')
let winid = coc#compat#buf_win_id(a:bufnr)
@ -112,6 +150,14 @@ function! coc#compat#matchaddgroups(winid, groups) abort @@ -112,6 +150,14 @@ function! coc#compat#matchaddgroups(winid, groups) abort
endif
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)
@ -132,7 +178,7 @@ function! coc#compat#buf_del_keymap(bufnr, mode, lhs) abort @@ -132,7 +178,7 @@ function! coc#compat#buf_del_keymap(bufnr, mode, lhs) abort
if exists('*win_execute')
let winid = coc#compat#buf_win_id(a:bufnr)
if winid != -1
call win_execute(winid, 'silent! '.a:mode.'unmap <buffer> '.a:lhs)
call win_execute(winid, a:mode.'unmap <buffer> '.a:lhs, 'silent!')
endif
endif
endfunction

19
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/cursor.vim

@ -39,3 +39,22 @@ function! coc#cursor#char_offset() abort @@ -39,3 +39,22 @@ function! coc#cursor#char_offset() abort
return offset
endfunction
" Returns lastest 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#helper#get_charactor(getline(sl), sc)
if m ==# 'V'
return [sl - 1, start_idx, el, 0]
endif
let line = getline(el)
let end_idx = coc#helper#get_charactor(line, ec)
if m !=# 'char'
let end_idx = end_idx == strchars(line) ? end_idx : end_idx + 1
endif
return [sl - 1, start_idx, el - 1, end_idx]
endfunction

28
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/float.vim

@ -53,11 +53,12 @@ endfunction @@ -53,11 +53,12 @@ endfunction
" - borderhighlight: (optional) should be array for border highlights,
" highlight all borders with first value.
" - close: (optional) show close button when is 1.
" - highlights: (optional) highlight items.
" - buttons: (optional) array of button text for create buttons at bottom.
" - codes: (optional) list of CodeBlock.
" - winblend: winblend option for float window, neovim only.
" - shadow: use shadow as border style, neovim only.
" - focusable: neovim only, default to true.
" - winblend: (optional) winblend option for float window, neovim only.
" - shadow: (optional) use shadow as border style, neovim only.
" - focusable: (optional) neovim only, default to true.
function! coc#float#create_float_win(winid, bufnr, config) abort
let lines = get(a:config, 'lines', v:null)
let bufnr = coc#float#create_buf(a:bufnr, lines, 'hide')
@ -284,7 +285,7 @@ function! coc#float#nvim_close_btn(config, winid, border, hlgroup, winblend, rel @@ -284,7 +285,7 @@ function! coc#float#nvim_close_btn(config, winid, border, hlgroup, winblend, rel
\ 'focusable': v:true,
\ 'style': 'minimal',
\ }
if has('nvim-0.5.0')
if has('nvim-0.5.1')
let config['zindex'] = 300
endif
if winid
@ -318,7 +319,7 @@ function! coc#float#nvim_right_pad(config, winid, hlgroup, winblend, related) ab @@ -318,7 +319,7 @@ function! coc#float#nvim_right_pad(config, winid, hlgroup, winblend, related) ab
\ 'focusable': v:false,
\ 'style': 'minimal',
\ }
if has('nvim-0.5.0')
if has('nvim-0.5.1')
let config['zindex'] = 300
endif
if winid && nvim_win_is_valid(winid)
@ -359,7 +360,7 @@ function! coc#float#nvim_buttons(config, winid, buttons, borderbottom, pad, hlgr @@ -359,7 +360,7 @@ function! coc#float#nvim_buttons(config, winid, buttons, borderbottom, pad, hlgr
\ 'focusable': 1,
\ 'style': 'minimal',
\ }
if has('nvim-0.5.0')
if has('nvim-0.5.1')
let config['zindex'] = 300
if a:shadow
let config['border'] = 'shadow'
@ -447,7 +448,7 @@ function! coc#float#nvim_scrollbar(winid) abort @@ -447,7 +448,7 @@ function! coc#float#nvim_scrollbar(winid) abort
\ 'focusable': v:false,
\ 'style': 'minimal',
\ }
if has('nvim-0.5.0')
if has('nvim-0.5.1')
let opts['zindex'] = 300
endif
if id
@ -619,6 +620,7 @@ function! coc#float#create_prompt_win(title, default, opts) abort @@ -619,6 +620,7 @@ function! coc#float#create_prompt_win(title, default, opts) abort
exe 'inoremap <silent><expr><nowait><buffer> <cr> "\<C-r>=coc#float#prompt_insert(getline(''.''))\<cr>\<esc>"'
call feedkeys('A', 'in')
endif
call coc#util#do_autocmd('CocOpenFloatPrompt')
return [bufnr, winid]
endfunction
@ -1316,6 +1318,7 @@ function! coc#float#create_menu(lines, config) abort @@ -1316,6 +1318,7 @@ function! coc#float#create_menu(lines, config) abort
\ 'maxWidth': get(a:config, 'maxWidth', 80),
\ 'maxHeight': get(a:config, 'maxHeight', 80),
\ 'border': [1, 1, 1, 1],
\ 'highlights': get(a:config, 'highlights', []),
\ 'relative': 'cursor',
\ }
if s:is_vim
@ -1682,8 +1685,17 @@ endfunction @@ -1682,8 +1685,17 @@ endfunction
" get popup position for vim8 based on config of neovim float window
function! s:popup_position(config) abort
let relative = get(a:config, 'relative', 'editor')
let border = get(a:config, 'border', [0, 0, 0, 0])
let delta = get(border, 0, 0) + get(border, 2, 0)
if relative ==# 'cursor'
return [s:popup_cursor(a:config['row']), s:popup_cursor(a:config['col'])]
if a:config['row'] < 0
let delta = - delta
elseif a:config['row'] == 0
let delta = - get(border, 0, 0)
else
let delta = 0
endif
return [s:popup_cursor(a:config['row'] + delta), s:popup_cursor(a:config['col'])]
endif
return [a:config['row'] + 1, a:config['col'] + 1]
endfunction

365
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/highlight.vim

@ -1,9 +1,13 @@ @@ -1,9 +1,13 @@
scriptencoding utf-8
let s:is_vim = !has('nvim')
let s:clear_match_by_window = has('nvim-0.5.0') || has('patch-8.1.1084')
let s:set_extmark = exists('*nvim_buf_set_extmark')
let s:prop_offset = get(g:, 'coc_text_prop_offset', 1000)
let s:namespace_map = {}
let s:ns_id = 1
let g:coc_highlight_batch_lines = get(g:, 'coc_highlight_batch_lines', 300)
" Maxium count to highlight each time.
let g:coc_highlight_maximum_count = get(g:, 'coc_highlight_batch_count', 300)
if has('nvim-0.5.0')
try
@ -13,33 +17,64 @@ if has('nvim-0.5.0') @@ -13,33 +17,64 @@ if has('nvim-0.5.0')
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)}")
let total = coc#compat#buf_line_count(a:bufnr)
if total <= g:coc_highlight_batch_lines || get(g:, 'coc_node_env', '') ==# 'test'
call coc#highlight#update_highlights(a:bufnr, a:key, hls, 0, -1, priority)
return
endif
if bufnr('%') == a:bufnr
" Highlight visible region first
let ls = line('w0')
let le = line('w$')
let exclude = [ls, le]
let highlights = filter(copy(hls), 'v:val["lnum"]>='.(ls - 1).'&& v:val["lnum"] <='.(le - 1))
call coc#highlight#update_highlights(a:bufnr, a:key, highlights, ls - 1, le, priority)
let re = s:get_highlight_region(0, total, exclude)
if !empty(re)
call timer_start(50, { -> s:update_highlights_timer(a:bufnr, changedtick, a:key, priority, re[0], re[1], total, hls, exclude)})
endif
else
let re = s:get_highlight_region(0, total, v:null)
call s:update_highlights_timer(a:bufnr, changedtick, a:key, priority, re[0], re[1], total, hls, v:null)
endif
endfunction
" Get namespaced coc highlights from range of bufnr
" start - 0 based start line index
" end - 0 based end line index, could be -1 for last line (exclusive)
function! coc#highlight#get(bufnr, key, start, end) abort
if !has('nvim-0.5.0') && !exists('*prop_list')
throw 'Get highlights requires neovim 0.5.0 or vim support prop_list()'
endif
if !has_key(s:namespace_map, a:key) || !bufloaded(a:bufnr)
return {}
endif
let ns = coc#highlight#create_namespace(a:key)
let current = {}
if has('nvim-0.5.0')
let end = a:end == -1 ? [-1, -1] : [a:end - 1, 0]
let end = a:end == -1 ? [-1, -1] : [a:end - 1, -1]
let markers = nvim_buf_get_extmarks(a:bufnr, ns, [a:start, 0], end, {'details': v:true})
for [_, row, start_col, details] in markers
let linecount = nvim_buf_line_count(a:bufnr)
for [id, row, start_col, details] in markers
let delta = details['end_row'] - row
if delta > 1 || (delta == 1 && details['end_col'] != 0)
" Don't known neovim's api for multiple lines markers.
if row >= linecount || delta > 1 || (delta == 1 && details['end_col'] != 0)
" Remove unexpected multiple line extmark.
call nvim_buf_del_extmark(a:bufnr, ns, id)
continue
endif
let lines = getbufline(a:bufnr, row + 1)
if empty(lines)
" It's possible that markers exceeded last line.
continue
endif
let text = lines[0]
let text = get(getbufline(a:bufnr, row + 1), 0, '')
let curr = get(current, string(row), [])
call add(curr, {
\ 'hlGroup': details['hl_group'],
@ -49,10 +84,10 @@ function! coc#highlight#get(bufnr, key, start, end) abort @@ -49,10 +84,10 @@ function! coc#highlight#get(bufnr, key, start, end) abort
\ })
let current[string(row)] = curr
endfor
else
elseif exists('*prop_list')
let id = s:prop_offset + ns
" we could only get textprops line by line
let end = a:end == -1 ? getbufinfo(a:bufnr)[0]['linecount'] : a:end
let end = a:end == -1 ? coc#compat#buf_line_count(a:bufnr) : a:end
for line in range(a:start + 1, end)
let items = []
for prop in prop_list(line, {'bufnr': a:bufnr, 'id': id})
@ -74,19 +109,24 @@ endfunction @@ -74,19 +109,24 @@ endfunction
" Update highlights by check exists highlights.
function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort
let bufnr = a:bufnr
if a:bufnr == 0
let bufnr = bufnr('%')
endif
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)
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)
if type(get(a:, 4, v:null)) == 0 && getbufvar(bufnr, 'changedtick') > a:4
return
endif
let total = len(a:highlights)
" index list that exists with current highlights
let exists = []
@ -95,7 +135,7 @@ function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort @@ -95,7 +135,7 @@ function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort
if has('nvim-0.5.0') || exists('*prop_list')
let current = coc#highlight#get(bufnr, a:key, start, end)
for lnum in sort(map(keys(current), 'str2nr(v:val)'), {a, b -> a - b})
let items = current[lnum]
let items = get(current, lnum, [])
let indexes = []
let nextIndex = currIndex
if currIndex != total
@ -106,7 +146,7 @@ function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort @@ -106,7 +146,7 @@ function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort
let nextIndex = i
break
endif
if coc#helper#obj_equal(item, hi)
if s:same_highlight(item, hi)
call add(indexes, i)
let nextIndex = max([nextIndex, i + 1])
endif
@ -116,7 +156,7 @@ function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort @@ -116,7 +156,7 @@ function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort
let currIndex = nextIndex
" all highlights of current line exists, not clear.
if len(indexes) == len(items)
let exists = exists + indexes
call extend(exists, indexes)
else
if has('nvim')
call nvim_buf_clear_namespace(bufnr, ns, lnum, lnum + 1)
@ -125,10 +165,12 @@ function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort @@ -125,10 +165,12 @@ function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort
endif
endif
endfor
if has('nvim') && end == -1
if has('nvim')
let count = nvim_buf_line_count(bufnr)
" remove highlights exceed last line.
call nvim_buf_clear_namespace(bufnr, ns, count, -1)
if end == -1 || end == count
" remove highlights exceed last line.
call nvim_buf_clear_namespace(bufnr, ns, count, -1)
endif
endif
else
call coc#highlight#clear_highlight(bufnr, a:key, start, end)
@ -139,55 +181,79 @@ function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort @@ -139,55 +181,79 @@ function! coc#highlight#update_highlights(bufnr, key, highlights, ...) abort
endif
for i in indexes
let hi = a:highlights[i]
call coc#highlight#add_highlight(bufnr, ns, hi['hlGroup'], hi['lnum'], hi['colStart'], hi['colEnd'])
let opts = {}
if type(priority) == 0
let opts['priority'] = priority
endif
for key in ['combine', 'start_incl', 'end_incl']
if has_key(hi, key)
let opts[key] = hi[key]
endif
endfor
call coc#highlight#add_highlight(bufnr, ns, hi['hlGroup'], hi['lnum'], hi['colStart'], hi['colEnd'], opts)
endfor
endfunction
" 0 based line, start_col and end_col
function! coc#highlight#get_highlights(bufnr, key) abort
if !has_key(s:namespace_map, a:key) || !bufloaded(a:bufnr)
if !bufloaded(a:bufnr)
return v:null
endif
if !has_key(s:namespace_map, a:key)
return []
endif
let res = []
let ns = s:namespace_map[a:key]
if exists('*prop_list')
let lines = getbufline(a:bufnr, 1, '$')
let linecount = len(lines)
for line in range(1, linecount)
for prop in prop_list(line, {'bufnr': a:bufnr, 'id': s:prop_offset + ns})
" Could filter by end_line and types
if has('patch-8.2.3652')
for prop in prop_list(1, {'bufnr': a:bufnr, 'ids': [s:prop_offset + ns], 'end_lnum': -1})
if prop['start'] == 0 || prop['end'] == 0
" multi line tokens are not supported; simply ignore it
" multi line textprop are not supported, simply ignore it
continue
endif
let text = lines[line - 1]
call add(res, {
\ 'hlGroup': s:prop_type_hlgroup(prop['type']),
\ 'lnum': line - 1,
\ 'colStart': coc#helper#get_charactor(text, prop['col']),
\ 'colEnd': coc#helper#get_charactor(text, prop['col'] + prop['length'])
\ })
let hlGroup = s:prop_type_hlgroup(prop['type'])
let startCol = prop['col'] - 1
let endCol = startCol + prop['length']
call add(res, [hlGroup, prop['lnum'] - 1, startCol, endCol])
endfor
else
let linecount = coc#compat#buf_line_count(a:bufnr)
for line in range(1, linecount)
for prop in prop_list(line, {'bufnr': a:bufnr, 'id': s:prop_offset + ns})
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']), line - 1, startCol, endCol])
endfor
endfor
endif
elseif has('nvim-0.5.0')
let markers = nvim_buf_get_extmarks(a:bufnr, ns, 0, -1, {'details': v:true})
let lines = getbufline(a:bufnr, 1, '$')
let total = len(lines)
for [_, line, start_col, details] in markers
let total = nvim_buf_line_count(a:bufnr)
for [marker_id, line, start_col, details] in markers
if line >= total
" Could be markers exceed end of line
continue
endif
let text = lines[line]
let delta = details['end_row'] - line
if delta > 1 || (delta == 1 && details['end_col'] != 0)
" can't handle, single line only
continue
endif
call add(res, {
\ 'hlGroup': details['hl_group'],
\ 'lnum': line,
\ 'colStart': coc#helper#get_charactor(text, start_col + 1),
\ 'colEnd': delta == 1 ? strchars(text) : coc#helper#get_charactor(text, details['end_col'] + 1)
\ })
let endCol = details['end_col']
if endCol == start_col
call nvim_buf_del_extmark(a:bufnr, ns, marker_id)
continue
endif
if delta == 1
let text = get(nvim_buf_get_lines(a:bufnr, line, line + 1, 0), 0, '')
let endCol = strlen(text)
endif
call add(res, [details['hl_group'], line, start_col, endCol, marker_id])
endfor
else
throw 'Get highlights requires neovim 0.5.0 or vim support prop_list'
@ -195,12 +261,58 @@ function! coc#highlight#get_highlights(bufnr, key) abort @@ -195,12 +261,58 @@ function! coc#highlight#get_highlights(bufnr, key) abort
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)
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
endfunction
" Clear highlights by 0 based line numbers.
function! coc#highlight#clear(bufnr, key, lnums) abort
if !bufloaded(a:bufnr)
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#call('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
call nvim_buf_del_extmark(a:bufnr, ns, id)
endfor
endfunction
" highlight LSP range,
function! coc#highlight#ranges(bufnr, key, hlGroup, ranges) abort
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
@ -221,20 +333,38 @@ function! coc#highlight#ranges(bufnr, key, hlGroup, ranges) abort @@ -221,20 +333,38 @@ function! coc#highlight#ranges(bufnr, key, hlGroup, ranges) abort
endif
" TODO don't know how to count UTF16 code point, should work most cases.
let colStart = lnum == start['line'] + 1 ? strlen(strcharpart(line, 0, start['character'])) : 0
let colEnd = lnum == end['line'] + 1 ? strlen(strcharpart(line, 0, end['character'])) : -1
let colEnd = lnum == end['line'] + 1 ? strlen(strcharpart(line, 0, end['character'])) : strlen(line)
if colStart == colEnd
continue
endif
call coc#highlight#add_highlight(bufnr, srcId, a:hlGroup, lnum - 1, colStart, colEnd)
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
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 has('nvim')
call nvim_buf_add_highlight(a:bufnr, a:src_id, a:hl_group, a:line, a:col_start, a:col_end)
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#call('buf_add_highlight', [a:bufnr, a:src_id, a:hl_group, a:line, a:col_start, a:col_end])
call coc#api#call('buf_add_highlight', [a:bufnr, a:src_id, a:hl_group, a:line, a:col_start, a:col_end, opts])
endif
endfunction
@ -320,7 +450,7 @@ function! coc#highlight#highlight_lines(winid, blocks) abort @@ -320,7 +450,7 @@ function! coc#highlight#highlight_lines(winid, blocks) abort
endif
endfunction
" Copmpose hlGroups with foreground and background colors.
" 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
@ -331,10 +461,12 @@ function! coc#highlight#compose_hlgroup(fgGroup, bgGroup) abort @@ -331,10 +461,12 @@ function! coc#highlight#compose_hlgroup(fgGroup, bgGroup) abort
endif
let fgId = synIDtrans(hlID(a:fgGroup))
let bgId = synIDtrans(hlID(a:bgGroup))
let guifg = synIDattr(fgId, 'reverse', 'gui') !=# '1' ? synIDattr(fgId, 'fg', 'gui') : synIDattr(fgId, 'bg', 'gui')
let guibg = synIDattr(bgId, 'reverse', 'gui') !=# '1' ? synIDattr(bgId, 'bg', 'gui') : synIDattr(bgId, 'fg', 'gui')
let ctermfg = synIDattr(fgId, 'reverse', 'cterm') !=# '1' ? synIDattr(fgId, 'fg', 'cterm') : synIDattr(fgId, 'bg', 'cterm')
let ctermbg = synIDattr(bgId, 'reverse', 'cterm') !=# '1' ? synIDattr(bgId, 'bg', 'cterm') : synIDattr(bgId, 'fg', 'cterm')
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'
@ -362,6 +494,9 @@ function! coc#highlight#compose_hlgroup(fgGroup, bgGroup) abort @@ -362,6 +494,9 @@ function! coc#highlight#compose_hlgroup(fgGroup, bgGroup) abort
elseif underline
let cmd .= ' cterm=underline gui=underline'
endif
if cmd ==# 'silent hi ' . hlGroup
return 'Normal'
endif
execute cmd
return hlGroup
endfunction
@ -497,9 +632,21 @@ endfunction @@ -497,9 +632,21 @@ endfunction
function! s:prop_type_hlgroup(type) abort
if a:type=~# '^CocHighlight'
return a:type[12:]
return strpart(a:type, 12)
endif
return prop_type_get(a:type)['highlight']
return get(prop_type_get(a:type), 'highlight', '')
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#call('buf_clear_namespace', [bufnr, src_id, 0, -1])
endif
endfor
endfor
endfunction
function! coc#highlight#create_namespace(key) abort
@ -521,3 +668,97 @@ endfunction @@ -521,3 +668,97 @@ endfunction
function! coc#highlight#get_syntax_name(lnum, col)
return synIDattr(synIDtrans(synID(a:lnum,a:col,1)),"name")
endfunction
" TODO support check for virt_text
function! s:same_highlight(one, other) abort
if a:one['hlGroup'] !=# a:other['hlGroup']
return 0
endif
if a:one['lnum'] != a:other['lnum']
return 0
endif
if a:one['colStart'] !=# a:other['colStart']
return 0
endif
if a:one['colEnd'] !=# a:other['colEnd']
return 0
endif
return 1
endfunction
function! s:update_highlights_timer(bufnr, changedtick, key, priority, start, end, total, highlights, exclude) abort
if getbufvar(a:bufnr, 'changedtick', 0) != a:changedtick
return
endif
let highlights = filter(copy(a:highlights), 'v:val["lnum"] >='.a:start.' && v:val["lnum"] <'.a:end)
let end = a:end
if empty(highlights) && end > 0
" find maximum lnum to clear
let till = type(a:exclude) == 3 && end < get(a:exclude, 0, 0) ? get(a:exclude, 0, 0) : a:total
if till > end
let minimal = till
for hl in filter(copy(a:highlights), 'v:val["lnum"] >='.end.' && v:val["lnum"] <'.till)
let minimal = min([minimal, hl['lnum']])
endfor
let end = minimal
endif
endif
"call coc#rpc#notify('log', ['update_timer', a:bufnr, a:changedtick, a:key, a:start, end, a:total, highlights, a:exclude])
call coc#highlight#update_highlights(a:bufnr, a:key, highlights, a:start, end, a:priority)
let re = s:get_highlight_region(end, a:total, a:exclude)
if !empty(re)
call timer_start(50, { -> s:update_highlights_timer(a:bufnr, a:changedtick, a:key, a:priority, re[0], re[1], a:total, a:highlights, a:exclude)})
endif
endfunction
" Get 0 based, end exclusive region to highlight.
function! s:get_highlight_region(start, total, exclude) abort
if a:start >= a:total
return v:null
endif
if empty(a:exclude)
let end = min([a:total, a:start + g:coc_highlight_batch_lines])
return [a:start, end]
endif
if a:start < a:exclude[0] - 1
let end = min([a:exclude[0] - 1, a:start + g:coc_highlight_batch_lines])
return [a:start, end]
endif
let start = a:start
if a:start >= a:exclude[0] - 1 && a:start <= a:exclude[1] - 1
let start = a:exclude[1]
endif
if start >= a:total
return v:null
endif
let end = min([a:total, start + g:coc_highlight_batch_lines])
return [start, end]
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

81
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/list.vim

@ -3,12 +3,14 @@ let s:is_vim = !has('nvim') @@ -3,12 +3,14 @@ let s:is_vim = !has('nvim')
let s:prefix = '[List Preview]'
" filetype detect could be slow.
let s:filetype_map = {
\ 'vim': 'vim',
\ 'ts': 'typescript',
\ 'js': 'javascript',
\ 'html': 'html',
\ 'css': 'css'
\ }
\ 'c': 'c',
\ 'py': 'python',
\ 'vim': 'vim',
\ 'ts': 'typescript',
\ 'js': 'javascript',
\ 'html': 'html',
\ 'css': 'css'
\ }
function! coc#list#getchar() abort
return coc#prompt#getchar()
@ -33,7 +35,7 @@ endfunction @@ -33,7 +35,7 @@ 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']
\ '--ignore-case', '--no-quit', '--first', '--reverse']
if get(g:, 'coc_enabled', 0)
let names = coc#rpc#request('listNames', [])
call extend(list, names)
@ -66,7 +68,7 @@ function! coc#list#create(position, height, name, numberSelect) @@ -66,7 +68,7 @@ function! coc#list#create(position, height, name, numberSelect)
setl norelativenumber
setl signcolumn=yes
endif
return [bufnr('%'), win_getid()]
return [bufnr('%'), win_getid(), tabpagenr()]
endfunction
" close list windows
@ -96,7 +98,10 @@ function! coc#list#setup(source) @@ -96,7 +98,10 @@ function! coc#list#setup(source)
let source = a:source[8:]
let name = toupper(source[0]).source[1:]
execute 'syntax match Coc'.name.'Line /\v^.*$/'
nnoremap <silent><nowait><buffer> <esc> <C-w>c
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
" Check if previewwindow exists on current tab.
@ -116,7 +121,7 @@ function! coc#list#get_preview(...) abort @@ -116,7 +121,7 @@ function! coc#list#get_preview(...) abort
let info = gettabinfo(tabnr)
if !empty(info)
for win in info[0]['windows']
if getwinvar(win, 'previewwindow', 0)
if gettabwinvar(tabnr, win, 'previewwindow', 0)
return win
endif
endfor
@ -140,40 +145,10 @@ function! coc#list#scroll_preview(dir) abort @@ -140,40 +145,10 @@ function! coc#list#scroll_preview(dir) abort
endif
endfunction
function! coc#list#restore(winid, height)
if has('nvim') && nvim_win_is_valid(a:winid)
call nvim_win_set_height(a:winid, a:height)
elseif s:is_vim && exists('*win_execute')
call win_execute(a:winid, 'noa resize '.a:height, 'silent!')
redraw
endif
endfunction
function! coc#list#set_height(height) abort
if winnr('$') == 1| return | endif
execute 'resize '.a:height
endfunction
function! coc#list#hide(original, height, winid) abort
let arr = win_id2tabwin(a:winid)
" close preview window
if !empty(arr) && arr[0] != 0
silent! pclose!
let previewwin = coc#list#get_preview(arr[0])
call coc#window#close(previewwin)
endif
if !empty(getwininfo(a:original))
call win_gotoid(a:original)
endif
if a:winid
silent! call coc#window#close(a:winid)
endif
if !empty(a:height) && win_getid() == a:original
if exists('*nvim_win_set_height')
call nvim_win_set_height(a:original, a:height)
elseif win_getid() == a:original
execute 'resize '.a:height
endif
function! coc#list#close_preview(tabnr) abort
let winid = coc#list#get_preview(a:tabnr)
if winid != -1
call coc#window#close(winid)
endif
endfunction
@ -245,7 +220,7 @@ function! coc#list#preview(lines, config) abort @@ -245,7 +220,7 @@ function! coc#list#preview(lines, config) abort
execute 'noa '.mod.' sb +resize\ '.height.' '.bufnr
let winid = win_getid()
endif
noa call winrestview({"lnum": lnum ,"topline":max([1, lnum - 3])})
noa call winrestview({"lnum": lnum ,"topline":s:get_topline(a:config, lnum, winid)})
call setwinvar(winid, '&signcolumn', 'no')
call setwinvar(winid, '&number', 1)
call setwinvar(winid, '&cursorline', 0)
@ -264,7 +239,7 @@ function! coc#list#preview(lines, config) abort @@ -264,7 +239,7 @@ function! coc#list#preview(lines, config) abort
call nvim_win_set_height(winid, height)
endif
endif
call coc#compat#execute(winid, ['syntax clear', 'noa call winrestview({"lnum":'.lnum.',"topline":'.max([1, lnum - 3]).'})'])
call coc#compat#execute(winid, ['syntax clear', 'noa call winrestview({"lnum":'.lnum.',"topline":'.s:get_topline(a:config, lnum, winid).'})'])
endif
call setwinvar(winid, '&foldenable', 0)
if s:prefix.' '.name != bufname(bufnr)
@ -289,6 +264,10 @@ function! coc#list#preview(lines, config) abort @@ -289,6 +264,10 @@ function! coc#list#preview(lines, config) abort
endif
call sign_unplace('coc', {'buffer': bufnr})
call coc#compat#execute(winid, 'call clearmatches()')
if !s:is_vim
" vim send <esc> to buffer on FocusLost, <C-w> and other cases
call coc#compat#execute(winid, 'nnoremap <silent><nowait><buffer> <esc> :call CocActionAsync("listCancel")<CR>')
endif
if !empty(range)
call sign_place(1, 'coc', 'CocCurrentLine', bufnr, {'lnum': lnum})
call coc#highlight#match_ranges(winid, bufnr, [range], hlGroup, 10)
@ -312,3 +291,13 @@ function! s:load_buffer(name) abort @@ -312,3 +291,13 @@ function! s:load_buffer(name) abort
endif
return 0
endfunction
function! s:get_topline(config, lnum, winid) abort
let toplineStyle = get(a:config, 'toplineStyle', 'offset')
if toplineStyle == 'middle'
return max([1, a:lnum - winheight(a:winid)/2])
endif
let toplineOffset = get(a:config, 'toplineOffset', 3)
return max([1, a:lnum - toplineOffset])
endfunction

19
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/rpc.vim

@ -8,9 +8,9 @@ function! coc#rpc#start_server() @@ -8,9 +8,9 @@ function! coc#rpc#start_server()
if get(g:, 'coc_node_env', '') ==# 'test'
" server already started
let s:client = coc#client#create(s:name, [])
let s:client['running'] = 1
let s:client['chan_id'] = get(g:, 'coc_node_channel_id', 0)
call dictwatcheradd(g:, 'coc_node_channel_id', function('s:ChannelSet'))
let chan_id = get(g:, 'coc_node_channel_id', 0)
let s:client['running'] = chan_id != 0
let s:client['chan_id'] = chan_id
return
endif
if empty(s:client)
@ -36,12 +36,12 @@ function! coc#rpc#ready() @@ -36,12 +36,12 @@ function! coc#rpc#ready()
return 1
endfunction
function! s:ChannelSet(dict, key, val)
let chan_id = get(a:val, 'new', 0)
if empty(s:client) | return | endif
let s:client['running'] = 1
let s:client['chan_id'] = chan_id
call dictwatcherdel(g:, 'coc_node_channel_id', function('s:ChannelSet'))
function! coc#rpc#set_channel(chan_id) abort
let g:coc_node_channel_id = a:chan_id
if a:chan_id != 0
let s:client['running'] = 1
let s:client['chan_id'] = a:chan_id
endif
endfunction
function! coc#rpc#kill()
@ -77,6 +77,7 @@ function! coc#rpc#restart() @@ -77,6 +77,7 @@ function! coc#rpc#restart()
if empty(s:client)
call coc#rpc#start_server()
else
call coc#highlight#clear_all()
call coc#float#close_all()
call coc#rpc#request('detach', [])
sleep 100m

11
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/snippet.vim

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
scriptencoding utf-8
let s:is_vim = !has('nvim')
let s:map_next = 1
let s:cmd_mapping = has('nvim') || has('patch-8.2.1978')
function! coc#snippet#_select_mappings()
if !get(g:, 'coc_selectmode_mapping', 1)
@ -28,7 +29,9 @@ endfunction @@ -28,7 +29,9 @@ endfunction
function! coc#snippet#show_choices(lnum, col, len, values) abort
let m = mode()
call cursor(a:lnum, a:col + a:len)
if m !=# 'i' | startinsert | endif
if m !=# 'i'
call feedkeys("\<Esc>i")
endif
call timer_start(20, { -> coc#_do_complete(a:col - 1, a:values, 0)})
redraw
endfunction
@ -38,7 +41,6 @@ function! coc#snippet#enable() @@ -38,7 +41,6 @@ function! coc#snippet#enable()
return
endif
let b:coc_snippet_active = 1
silent! unlet g:coc_selected_text
call coc#snippet#_select_mappings()
let nextkey = get(g:, 'coc_snippet_next', '<C-j>')
let prevkey = get(g:, 'coc_snippet_prev', '<C-k>')
@ -48,9 +50,10 @@ function! coc#snippet#enable() @@ -48,9 +50,10 @@ function! coc#snippet#enable()
if s:map_next
execute 'inoremap <buffer><nowait><silent>'.nextkey." <C-R>=coc#rpc#request('snippetNext', [])<cr>"
endif
let pre = s:cmd_mapping ? '<Cmd>' : '<Esc>'
execute 'inoremap <buffer><nowait><silent>'.prevkey." <C-R>=coc#rpc#request('snippetPrev', [])<cr>"
execute 'snoremap <buffer><nowait><silent>'.prevkey." <Esc>:call coc#rpc#request('snippetPrev', [])<cr>"
execute 'snoremap <buffer><nowait><silent>'.nextkey." <Esc>:call coc#rpc#request('snippetNext', [])<cr>"
execute 'snoremap <buffer><nowait><silent>'.prevkey." ".pre.":call coc#rpc#request('snippetPrev', [])<cr>"
execute 'snoremap <buffer><nowait><silent>'.nextkey." ".pre.":call coc#rpc#request('snippetNext', [])<cr>"
endfunction
function! coc#snippet#disable()

2
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/task.vim

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
" ============================================================================
" Description: Manage long running tasks.
" Author: Qiming Zhao <chemzqm@gmail.com>
" Licence: MIT licence
" Licence: Anti 966 licence
" Version: 0.1
" Last Modified: Dec 12, 2020
" ============================================================================

16
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/terminal.vim

@ -4,12 +4,12 @@ let s:channel_map = {} @@ -4,12 +4,12 @@ let s:channel_map = {}
let s:is_win = has('win32') || has('win64')
" start terminal, return [bufnr, pid]
function! coc#terminal#start(cmd, cwd, env) abort
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 8new +setl\ buftype=nofile'
execute 'belowright '.get(g:, 'coc_terminal_height', 8).'new +setl\ buftype=nofile'
setl winfixheight
setl norelativenumber
setl nonumber
@ -33,6 +33,7 @@ function! coc#terminal#start(cmd, cwd, env) abort @@ -33,6 +33,7 @@ function! coc#terminal#start(cmd, cwd, env) abort
endif
function! s:OnExit(status) closure
call coc#rpc#notify('CocAutocmd', ['TermExit', bufnr, a:status])
if a:status == 0
execute 'silent! bd! '.bufnr
endif
@ -41,9 +42,10 @@ function! coc#terminal#start(cmd, cwd, env) abort @@ -41,9 +42,10 @@ function! coc#terminal#start(cmd, cwd, env) abort
if has('nvim')
let job_id = termopen(a:cmd, {
\ 'cwd': cwd,
\ 'pty': 1,
\ '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)
@ -89,11 +91,9 @@ function! coc#terminal#send(bufnr, text, add_new_line) abort @@ -89,11 +91,9 @@ function! coc#terminal#send(bufnr, text, add_new_line) abort
endif
endif
call chansend(chan, lines)
let winnr = bufwinnr(a:bufnr)
if winnr != -1
exe 'noa '.winnr.'wincmd w'
exe 'noa normal! G'
exe 'noa '.wincmd p
let winid = bufwinid(a:bufnr)
if winid != -1
call coc#compat#execute(winid, 'noa normal! G')
endif
else
if !a:add_new_line

178
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/util.vim

@ -3,7 +3,7 @@ let s:root = expand('<sfile>:h:h:h') @@ -3,7 +3,7 @@ let s:root = expand('<sfile>:h:h:h')
let s:is_win = has('win32') || has('win64')
let s:is_vim = !has('nvim')
let s:clear_match_by_id = has('nvim-0.5.0') || has('patch-8.1.1084')
let s:vim_api_version = 10
let s:vim_api_version = 25
let s:activate = ""
let s:quit = ""
@ -23,6 +23,12 @@ function! coc#util#api_version() abort @@ -23,6 +23,12 @@ 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'")
return map(filtered, "matchstr(v:val,'\\v^CocSem\\w+')")
endfunction
" get cursor position
function! coc#util#cursor()
return [line('.') - 1, strchars(strpart(getline('.'), 0, col('.') - 1))]
@ -159,6 +165,21 @@ function! coc#util#jump(cmd, filepath, ...) abort @@ -159,6 +165,21 @@ function! coc#util#jump(cmd, filepath, ...) abort
let extra = empty(get(a:, 1, [])) ? '' : '+'.(a:1[0] + 1)
exe 'pedit '.extra.' '.fnameescape(file)
return
elseif a:cmd == 'drop' && exists('*bufadd')
let dstbuf = bufadd(path)
let binfo = getbufinfo(dstbuf)
if len(binfo) == 1 && empty(binfo[0].windows)
exec 'buffer '.dstbuf
let &buflisted = 1
else
exec 'drop '.fnameescape(file)
endif
elseif a:cmd == 'edit'
if bufloaded(file)
exe 'b '.bufnr(file)
else
exe a:cmd.' '.fnameescape(file)
endif
else
exe a:cmd.' '.fnameescape(file)
endif
@ -211,7 +232,7 @@ function! s:Call(method, args) @@ -211,7 +232,7 @@ function! s:Call(method, args)
endtry
endfunction
function! coc#util#get_bufoptions(bufnr, maxFileSize) abort
function! coc#util#get_bufoptions(bufnr) abort
if !bufloaded(a:bufnr) | return v:null | endif
let bufname = bufname(a:bufnr)
let buftype = getbufvar(a:bufnr, '&buftype')
@ -222,23 +243,23 @@ function! coc#util#get_bufoptions(bufnr, maxFileSize) abort @@ -222,23 +243,23 @@ function! coc#util#get_bufoptions(bufnr, maxFileSize) abort
elseif !empty(bufname)
let size = getfsize(bufname)
endif
let lines = []
if getbufvar(a:bufnr, 'coc_enabled', 1) && (buftype == '' || buftype == 'acwrite') && size < a:maxFileSize
let lines = v:null
if getbufvar(a:bufnr, 'coc_enabled', 1) && (buftype == '' || buftype == 'acwrite') && size < get(g:, 'coc_max_filesize', 2097152)
let lines = getbufline(a:bufnr, 1, '$')
endif
return {
\ 'bufname': bufname,
\ 'size': size,
\ 'buftype': buftype,
\ 'lines': lines,
\ 'winid': winid,
\ 'bufname': bufname,
\ 'buftype': buftype,
\ 'previewwindow': v:false,
\ 'variables': s:variables(a:bufnr),
\ 'fullpath': empty(bufname) ? '' : fnamemodify(bufname, ':p'),
\ 'eol': getbufvar(a:bufnr, '&eol'),
\ 'variables': s:variables(a:bufnr),
\ 'filetype': getbufvar(a:bufnr, '&filetype'),
\ 'iskeyword': getbufvar(a:bufnr, '&iskeyword'),
\ 'changedtick': getbufvar(a:bufnr, 'changedtick'),
\ 'lines': lines,
\ 'fullpath': empty(bufname) ? '' : fnamemodify(bufname, ':p'),
\}
endfunction
@ -333,6 +354,9 @@ function! coc#util#get_input() @@ -333,6 +354,9 @@ function! coc#util#get_input()
endfunction
function! coc#util#get_complete_option()
if get(b:,"coc_suggest_disable",0)
return v:null
endif
let pos = getcurpos()
let line = getline(pos[1])
let input = matchstr(strpart(line, 0, pos[2] - 1), '\k*$')
@ -351,6 +375,8 @@ function! coc#util#get_complete_option() @@ -351,6 +375,8 @@ function! coc#util#get_complete_option()
\ 'synname': synname,
\ 'changedtick': b:changedtick,
\ 'blacklist': get(b:, 'coc_suggest_blacklist', []),
\ 'disabled': get(b:, 'coc_disabled_sources', []),
\ 'indentkeys': coc#util#get_indentkeys()
\}
endfunction
@ -442,6 +468,9 @@ function! coc#util#open_terminal(opts) abort @@ -442,6 +468,9 @@ function! coc#util#open_terminal(opts) abort
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)
@ -510,14 +539,14 @@ function! coc#util#vim_info() @@ -510,14 +539,14 @@ function! coc#util#vim_info()
return {
\ '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', []),
\ 'config': get(g:, 'coc_user_config', {}),
\ 'pid': coc#util#getpid(),
\ 'columns': &columns,
\ 'lines': &lines,
\ 'columns': &columns,
\ 'cmdheight': &cmdheight,
\ 'pid': coc#util#getpid(),
\ 'filetypeMap': get(g:, 'coc_filetype_map', {}),
\ 'version': coc#util#version(),
\ 'completeOpt': &completeopt,
@ -529,28 +558,30 @@ function! coc#util#vim_info() @@ -529,28 +558,30 @@ function! coc#util#vim_info()
\ 'colorscheme': get(g:, 'colors_name', ''),
\ 'workspaceFolders': get(g:, 'WorkspaceFolders', v:null),
\ 'background': &background,
\ 'runtimepath': &runtimepath,
\ 'runtimepath': join(globpath(&runtimepath, '', 0, 1), ','),
\ 'locationlist': get(g:,'coc_enable_locationlist', 1),
\ 'progpath': v:progpath,
\ 'guicursor': &guicursor,
\ 'updateHighlight': has('nvim-0.5.0') || exists('*prop_list') ? v:true : v:false,
\ 'tabCount': tabpagenr('$'),
\ 'updateHighlight': has('nvim-0.5.0') || has('patch-8.1.1719') ? v:true : v:false,
\ 'vimCommands': get(g:, 'coc_vim_commands', []),
\ 'sign': exists('*sign_place') && exists('*sign_unplace'),
\ 'textprop': has('textprop') && has('patch-8.1.1719') && !has('nvim') ? v:true : v:false,
\ 'dialog': has('nvim-0.4.0') || has('patch-8.2.0750') ? v:true : v:false,
\ 'disabledSources': get(g:, 'coc_sources_disable_map', {}),
\ 'semanticHighlights': coc#util#semantic_hlgroups()
\}
endfunction
function! coc#util#highlight_options()
function! coc#util#all_state()
return {
\ 'colorscheme': get(g:, 'colors_name', ''),
\ 'background': &background,
\ 'runtimepath': &runtimepath,
\}
\ 'bufnr': bufnr('%'),
\ 'winid': win_getid(),
\ 'bufnrs': map(getbufinfo({'bufloaded': 1}),'v:val["bufnr"]'),
\ 'winids': map(getwininfo(),'v:val["winid"]'),
\ }
endfunction
function! coc#util#set_lines(bufnr, changedtick, original, replacement, start, end) abort
function! coc#util#set_lines(bufnr, changedtick, original, replacement, start, end, changes) abort
if !bufloaded(a:bufnr)
return
endif
@ -574,7 +605,14 @@ function! coc#util#set_lines(bufnr, changedtick, original, replacement, start, e @@ -574,7 +605,14 @@ function! coc#util#set_lines(bufnr, changedtick, original, replacement, start, e
endif
endif
endif
call coc#compat#buf_set_lines(a:bufnr, a:start, a:end, a:replacement)
if exists('*nvim_buf_set_text') && !empty(a:changes) && len(a:changes) < 200
for item in a:changes
let lines = nvim_buf_get_lines(a:bufnr, 0, -1, v:false)
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
endfunction
function! coc#util#change_lines(bufnr, list) abort
@ -601,7 +639,7 @@ endfunction @@ -601,7 +639,7 @@ endfunction
" used by vim
function! coc#util#get_buf_lines(bufnr, changedtick)
if !bufloaded(a:bufnr)
if !bufloaded(a:bufnr)
return v:null
endif
let changedtick = getbufvar(a:bufnr, 'changedtick')
@ -617,6 +655,7 @@ endfunction @@ -617,6 +655,7 @@ endfunction
" used for TextChangedI with InsertCharPre
function! coc#util#get_changeinfo()
return {
\ 'bufnr': bufnr('%'),
\ 'lnum': line('.'),
\ 'line': getline('.'),
\ 'changedtick': b:changedtick,
@ -864,13 +903,92 @@ endfunction @@ -864,13 +903,92 @@ endfunction
" get tabsize & expandtab option
function! coc#util#get_format_opts(bufnr) abort
if a:bufnr && bufloaded(a:bufnr)
let tabsize = getbufvar(a:bufnr, '&shiftwidth')
if tabsize == 0
let tabsize = getbufvar(a:bufnr, '&tabstop')
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
if !coc#compat#win_is_valid(a:winid)
return v:null
endif
if has('nvim') && exists('*nvim_win_get_config')
" avoid float window
let config = nvim_win_get_config(a:winid)
if !empty(get(config, 'relative', ''))
return v:null
endif
return [tabsize, getbufvar(a:bufnr, '&expandtab')]
endif
let tabsize = &shiftwidth == 0 ? &tabstop : &shiftwidth
return [tabsize, &expandtab]
let info = getwininfo(a:winid)[0]
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,
\ 'winids': map(getwininfo(), 'v:val["winid"]'),
\ 'tabpagenr': info['tabnr'],
\ 'winnr': winnr(),
\ 'visibleRanges': s:visible_ranges(a:winid),
\ 'tabSize': tabSize,
\ 'insertSpaces': getbufvar(bufnr, '&expandtab') ? v:true : v:false
\ }
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! 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

65
etc/soft/nvim/+plugins/coc.nvim/autoload/coc/window.vim

@ -11,6 +11,29 @@ function! coc#window#tabnr(winid) abort @@ -11,6 +11,29 @@ function! coc#window#tabnr(winid) abort
endif
endfunction
function! coc#window#is_float(winid) abort
if !has('nvim')
if exists('*popup_list')
return index(popup_list(), a:winid) != -1
endif
return 0
elseif exists('*nvim_win_get_config')
let config = nvim_win_get_config(a:winid)
return !empty(config) && !empty(get(config, 'relative', ''))
endif
endfunction
function! coc#window#set_heigth(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
" Get single window by window variable, current tab only
function! coc#window#find(key, val) abort
for i in range(1, winnr('$'))
@ -22,6 +45,17 @@ function! coc#window#find(key, val) abort @@ -22,6 +45,17 @@ function! coc#window#find(key, val) abort
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
" Make sure window exists
function! coc#window#gotoid(winid) abort
noa let res = win_gotoid(a:winid)
@ -30,27 +64,48 @@ function! coc#window#gotoid(winid) abort @@ -30,27 +64,48 @@ function! coc#window#gotoid(winid) abort
endif
endfunction
" Avoid autocmd & errors
" Avoid errors
function! coc#window#close(winid) abort
if empty(a:winid) || a:winid == -1
return
endif
if exists('*nvim_win_is_valid') && exists('*nvim_win_close')
if nvim_win_is_valid(a:winid)
noa call nvim_win_close(a:winid, 1)
call nvim_win_close(a:winid, 1)
endif
elseif exists('*win_execute')
call coc#compat#execute(a:winid, 'noa close!', 'silent!')
else
let curr = win_getid()
if curr == a:winid
noa silent! close!
silent! close!
else
let res = win_gotoid(a:winid)
if res
noa silent! close!
noa call win_gotoid(curr)
silent! close!
call win_gotoid(curr)
endif
endif
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

24
etc/soft/nvim/+plugins/coc.nvim/autoload/health/coc.vim

@ -1,12 +1,23 @@ @@ -1,12 +1,23 @@
scriptencoding utf-8
let s:root = expand('<sfile>:h:h:h')
function! s:checkEnvironment() abort
let valid = 1
if !has('nvim-0.3.0')
let valid = 0
call health#report_error('Neovim version not satisfied, 0.3.0 and above required')
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.3.2')
\ + s:checkVim(!has('nvim'), 'vim', 'patch-0.8.1453')
let node = get(g:, 'coc_node_path', $COC_NODE_PATH == '' ? 'node' : $COC_NODE_PATH)
if !executable(node)
let valid = 0
@ -33,6 +44,9 @@ function! s:checkEnvironment() abort @@ -33,6 +44,9 @@ function! s:checkEnvironment() abort
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

87983
etc/soft/nvim/+plugins/coc.nvim/build/index.js

File diff suppressed because it is too large Load Diff

277
etc/soft/nvim/+plugins/coc.nvim/data/schema.json

@ -76,30 +76,61 @@ @@ -76,30 +76,61 @@
"default": false,
"description": "Disable dynamic registerCapability feature for this languageserver to avoid duplicated feature regstration."
},
"disableWorkspaceFolders": {
"type": "boolean",
"default": false,
"description": "Disable workspaceFolders feature for this languageserver."
},
"disableSnippetCompletion": {
"type": "boolean",
"default": false,
"description": "Disable completion snippet feature for this languageserver, the languageserver may not respect it."
},
"disableDiagnostics": {
"type": "boolean",
"default": false,
"description": "Disable handle diagnostics for this languageserver."
},
"disableCompletion": {
"type": "boolean",
"default": false,
"description": "Disable completion feature for this languageserver."
"disabledFeatures": {
"type": "array",
"default": [],
"description": "Disabled features for this languageserver.",
"items": {
"type": "string",
"enum": [
"completion",
"configuration",
"workspaceFolders",
"diagnostics",
"willSave",
"willSaveUntil",
"didSaveTextDocument",
"fileSystemWatcher",
"hover",
"signatureHelp",
"definition",
"references",
"documentHighlight",
"documentSymbol",
"workspaceSymbol",
"codeAction",
"codeLens",
"formatting",
"documentFormatting",
"documentRangeFormatting",
"documentOnTypeFormatting",
"rename",
"documentLink",
"executeCommand",
"pullConfiguration",
"typeDefinition",
"implementation",
"declaration",
"color",
"foldingRange",
"selectionRange",
"progress",
"callHierarchy",
"linkedEditing",
"fileEvents",
"semanticTokens"
]
}
},
"formatterPriority": {
"type": "number",
"default": 0,
"description": "Priority of this languageserver's fomatter."
"description": "Priority of this languageserver's formatter."
},
"env": {
"type": "object",
@ -192,11 +223,9 @@ @@ -192,11 +223,9 @@
"default": "127.0.0.1",
"description": "Host of server"
},
"disableWorkspaceFolders": {},
"disableSnippetCompletion": {},
"disableDynamicRegister": {},
"disableDiagnostics": {},
"disableCompletion": {},
"disabledFeatures": {},
"formatterPriority": {},
"enable": {},
"rootPatterns": {},
@ -258,10 +287,8 @@ @@ -258,10 +287,8 @@
"env": {},
"enable": {},
"disableDynamicRegister": {},
"disableWorkspaceFolders": {},
"disableSnippetCompletion": {},
"disableDiagnostics": {},
"disableCompletion": {},
"disabledFeatures": {},
"formatterPriority": {},
"rootPatterns": {},
"requireRootPattern": {},
@ -309,10 +336,8 @@ @@ -309,10 +336,8 @@
"env": {},
"enable": {},
"disableDynamicRegister": {},
"disableWorkspaceFolders": {},
"disableSnippetCompletion": {},
"disableDiagnostics": {},
"disableCompletion": {},
"disabledFeatures": {},
"formatterPriority": {},
"rootPatterns": {},
"requireRootPattern": {},
@ -355,9 +380,15 @@ @@ -355,9 +380,15 @@
"default": "npm",
"description": "Command or absolute path to npm or yarn."
},
"suggest.selection": {
"type": "string",
"default": "none",
"description": "Controls how suggestions are pre-selected when showing the suggest list.",
"enum": ["none", "recentlyUsed", "recentlyUsedByPrefix"]
},
"suggest.enablePreselect": {
"type": "boolean",
"description": "Enable preselect feature of LSP, only works on neovim",
"description": "Enable preselect feature of LSP, only works on neovim, required for suggest.selection config.",
"default": false
},
"suggest.enablePreview": {
@ -412,11 +443,6 @@ @@ -412,11 +443,6 @@
"default": 99,
"description": "Priority of language sources."
},
"suggest.numberSelect": {
"type": "boolean",
"description": "Input number to select complete item, works on neovim >= 0.4.0 only.",
"default": false
},
"suggest.disableKind": {
"type": "boolean",
"description": "Remove kind field from vim complete item.",
@ -467,16 +493,16 @@ @@ -467,16 +493,16 @@
"default": 5000,
"minimum": 500,
"maximum": 15000,
"description": "Timeout for completion, in miliseconds."
"description": "Timeout for completion, in milliseconds."
},
"suggest.minTriggerInputLength": {
"type": "integer",
"default": 1,
"description": "Mininal input length for trigger completion, default 1"
"description": "Minimal input length for trigger completion, default 1"
},
"suggest.triggerCompletionWait": {
"type": "integer",
"default": 100,
"default": 50,
"minimum": 30,
"maximum": 500,
"description": "Wait time between text change and completion start, cancel completion when text changed during wait."
@ -573,7 +599,38 @@ @@ -573,7 +599,38 @@
},
"suggest.asciiCharactersOnly": {
"type": "boolean",
"description": "Suggest ASCII characters only",
"description": "Trigger suggest with ASCII characters only",
"default": false
},
"documentHighlight.priority": {
"type": "number",
"default": -1,
"description": "Match priority used by document highlight, see ':h matchadd'"
},
"documentHighlight.timeout": {
"type": "integer",
"default": 300,
"minimum": 200,
"maximum": 5000,
"description": "Timeout for document highlight, in milliseconds."
},
"colors.filetypes": {
"type": "array",
"default": [],
"description": "Filetypes that should be enabled for colors highlight feature, use \"*\" for all filetypes.",
"items": {
"type": "string"
}
},
"colors.highlightPriority": {
"type": "number",
"description": "Priority for colors highlights, works on vim8 and neovim >= 0.6.0",
"default": 1000,
"maximum": 4096
},
"links.tooltip": {
"type": "boolean",
"description": "Show tooltip of link under cursor on CursorHold, neovim only",
"default": false
},
"diagnostic.enable": {
@ -583,9 +640,15 @@ @@ -583,9 +640,15 @@
},
"diagnostic.highlighLimit": {
"type": "number",
"description": "Limit count for highlighted diagnostics, too many diagnostic highlights could make vim stop responsing",
"description": "Limit count for highlighted diagnostics, too many diagnostic highlights could make vim stop responding",
"default": 1000
},
"diagnostic.highlightPriority": {
"type": "number",
"description": "Priority for diagnostic highlights, works on vim8 and neovim >= 0.6.0",
"default": 4096,
"maximum": 4096
},
"diagnostic.autoRefresh": {
"type": "boolean",
"description": "Enable automatically refresh diagnostics, use diagnosticRefresh action when it's disabled.",
@ -597,6 +660,24 @@ @@ -597,6 +660,24 @@
"default": "hint",
"enum": ["hint", "information", "warning", "error"]
},
"diagnostic.locationlistLevel": {
"type": ["string", "null"],
"description": "Filter diagnostics in locationlist.",
"default": null,
"enum": ["hint", "information", "warning", "error"]
},
"diagnostic.signLevel": {
"type": ["string", "null"],
"description": "Filter diagnostics displayed in signcolumn.",
"default": null,
"enum": ["hint", "information", "warning", "error"]
},
"diagnostic.messageLevel": {
"type": ["string", "null"],
"description": "Filter diagnostic message in float window/popup.",
"default": null,
"enum": ["hint", "information", "warning", "error"]
},
"diagnostic.locationlistUpdate": {
"type": "boolean",
"description": "Update locationlist on diagnostics change, only works with locationlist opened by :CocDiagnostics command and first window of associated buffer.",
@ -633,6 +714,17 @@ @@ -633,6 +714,17 @@
"description": "Use NeoVim virtual text to display diagnostics",
"default": false
},
"diagnostic.virtualTextLevel": {
"type": ["string", "null"],
"description": "Filter diagnostic message in virtual text by level",
"default": null,
"enum": ["hint", "information", "warning", "error"]
},
"diagnostic.virtualTextWinCol": {
"type": ["number", "null"],
"description": "Window column number to align virtual text",
"default": null
},
"diagnostic.virtualTextCurrentLineOnly": {
"type": "boolean",
"description": "Only show virtualText diagnostic on current cursor line",
@ -669,11 +761,6 @@ @@ -669,11 +761,6 @@
"description": "When to enable show messages of diagnostics.",
"enum": ["always", "jump", "never"]
},
"diagnostic.highlightOffset": {
"type": "number",
"description": "Offset number of buffer.addHighlight, neovim only.",
"default": 1000
},
"diagnostic.signPriority": {
"type": "number",
"description": "Priority of diagnostic signs, default to 10",
@ -735,7 +822,7 @@ @@ -735,7 +822,7 @@
"diagnostic.showUnused": {
"type": "boolean",
"default": true,
"description": "Show diagnostics with unused tag."
"description": "Show diagnostics with unused tag, affects highlight, sign, virtual text, message"
},
"diagnostic.showDeprecated": {
"type": "boolean",
@ -752,7 +839,7 @@ @@ -752,7 +839,7 @@
"default": 500,
"minimum": 200,
"maximum": 1000,
"description": "Timeout for trigger signature help, in miliseconds."
"description": "Timeout for trigger signature help, in milliseconds."
},
"signature.target": {
"type": "string",
@ -793,10 +880,16 @@ @@ -793,10 +880,16 @@
"description": "Enable codeLens feature, require neovim with set virtual text feature.",
"default": false
},
"codeLens.position": {
"type": "string",
"enum": ["top", "eol", "right_align"],
"description": "Position of codeLens, requires nvim >= 0.6.0",
"default": "top"
},
"codeLens.separator": {
"type": "string",
"description": "Separator text for codeLens in virtual text",
"default": "‣"
"default": ""
},
"codeLens.subseparator": {
"type": "string",
@ -810,7 +903,7 @@ @@ -810,7 +903,7 @@
},
"refactor.saveToFile": {
"type": "boolean",
"description": "Save to file when write refactor buffer with ':noa wa' command, set to false if you want save buffer by yourself.",
"description": "Save changed buffer to file when write refactor buffer with ':noa wa' command.",
"default": true
},
"refactor.beforeContext": {
@ -891,6 +984,11 @@ @@ -891,6 +984,11 @@
"default": null,
"description": "Highlight group for border of dialog window/popup, default to 'CocFloating'"
},
"dialog.shortcutHighlight": {
"type": "string",
"default": "MoreMsg",
"description": "Highlight group for shortcut character in menu dialog, default to 'MoreMsg'"
},
"notification.marginTop": {
"type": "number",
"default": 1,
@ -923,8 +1021,8 @@ @@ -923,8 +1021,8 @@
},
"workspace.ignoredFiletypes": {
"type": "array",
"default": ["markdown", "log", "txt", "help"],
"description": "Filetypes that should be ignored for resolve workspace folder.",
"default": [],
"description": "Filetypes that should be ignored for workspace folder resolve.",
"items": {
"type": "string"
}
@ -937,10 +1035,23 @@ @@ -937,10 +1035,23 @@
"type": "string"
}
},
"workspace.ignoredFolders": {
"type": "array",
"default": ["$HOME"],
"description": "List of folders that should not be resolved as workspace folder, environment variables and minimatch patterns can be used.",
"items": {
"type": "string"
}
},
"workspace.workspaceFolderCheckCwd": {
"type": "boolean",
"default": true,
"description": "Whether the cwd directory should be checked first when resolving workspace folder."
"description": "Whether the current working directory should be used first when checking patterns match for workspace folder."
},
"workspace.workspaceFolderFallbackCwd": {
"type": "boolean",
"default": true,
"description": "Use current working directory as workspace folder when no root patterns resolved."
},
"list.indicator": {
"type": "string",
@ -952,6 +1063,11 @@ @@ -952,6 +1063,11 @@
"default": false,
"description": "Whether to align lists in columns, default: `false`"
},
"list.menuAction": {
"type": "boolean",
"default": false,
"description": "Use menu picker instead of confirm() for choose action."
},
"list.interactiveDebounceTime": {
"type": "number",
"default": 100,
@ -965,12 +1081,12 @@ @@ -965,12 +1081,12 @@
"list.statusLineSegments": {
"type": ["array", "null"],
"default": [
"%#CocListMode#-- %{get(b:list_status, \"mode\", \"\")} --%*",
"%{get(b:list_status, \"loading\", \"\")}",
"%{get(b:list_status, \"args\", \"\")}",
"(%L/%{get(b:list_status, \"total\", \"\")})",
"%#CocListMode#-- %{coc#list#status(\"mode\")} --%*",
"%{coc#list#status(\"loading\")}",
"%{coc#list#status(\"args\")}",
"(%L/%{coc#list#status(\"total\")})",
"%=",
"%#CocListPath# %{get(b:list_status, \"cwd\", \"\")} %l/%L%*"
"%#CocListPath# %{coc#list#status(\"cwd\")} %l/%L%*"
],
"items": {
"types": "string"
@ -1017,6 +1133,17 @@ @@ -1017,6 +1133,17 @@
"default": "Search",
"description": "Highlight group used for highlight the range in preview window."
},
"list.previewToplineStyle": {
"type": "string",
"default": "offset",
"description": "Topline style for list previews",
"enum": ["offset", "middle"]
},
"list.previewToplineOffset": {
"type": "number",
"default": 3,
"description": "Topline offset for list previews"
},
"list.nextKeymap": {
"type": "string",
"default": "<C-j>",
@ -1079,6 +1206,36 @@ @@ -1079,6 +1206,36 @@
"default": "<C-p>",
"description": "Key used for jump to previous cursors position."
},
"semanticTokens.filetypes": {
"type": "array",
"description": "Filetypes that enable semanticTokens highlighting or [\"*\"] for any filetype",
"default": [],
"items": {
"type": "string"
}
},
"semanticTokens.highlightPriority": {
"type": "number",
"description": "Priority for semantic tokens highlight.",
"default": 2048,
"maximum": 4096
},
"semanticTokens.incrementTypes": {
"type": "array",
"description": "Semantic token types that should increase highlight when insert at the start and end position of token.",
"default": ["variable", "string"],
"items": {
"type": "string"
}
},
"semanticTokens.combinedModifiers": {
"type": "array",
"description": "Semantic token modifiers that should have highlight combined with syntax highlights.",
"default": ["deprecated"],
"items": {
"type": "string"
}
},
"tree.closedIcon": {
"type": "string",
"default": "+",
@ -1231,15 +1388,10 @@ @@ -1231,15 +1388,10 @@
"default": "SNIP",
"description": "Text shown in statusline to indicate snippet session is activated."
},
"coc.preferences.colorSupport": {
"coc.preferences.snippetHighlight": {
"type": "boolean",
"description": "Enable color highlight if language server support it.",
"default": true
},
"coc.preferences.semanticTokensHighlights": {
"type": "boolean",
"description": "Enable semanticTokens highlight if language server support it.",
"default": true
"description": "Use highlight group 'CocSnippetVisual' to highlight placeholders with same index of current one.",
"default": false
},
"coc.preferences.currentFunctionSymbolAutoUpdate": {
"type": "boolean",
@ -1347,6 +1499,11 @@ @@ -1347,6 +1499,11 @@
"maximum": 5000,
"description": "Will save handler timeout"
},
"coc.preferences.renameFillCurrent": {
"type": "boolean",
"default": true,
"description": "Disable to stop Refactor-Rename float/popup window from populating with old name in the New Name field."
},
"coc.source.around.enable": {
"type": "boolean",
"default": true

1041
etc/soft/nvim/+plugins/coc.nvim/doc/coc.txt

File diff suppressed because it is too large Load Diff

18
etc/soft/nvim/+plugins/coc.nvim/esbuild.js

@ -1,18 +1,20 @@ @@ -1,18 +1,20 @@
const cp = require('child_process')
const fs = require('fs')
const path = require('path')
let revision = ''
try {
let res = cp.execSync('git rev-parse HEAD', {encoding: 'utf8'})
revision = res.trim().slice(0, 10)
} catch (e) {
// ignore
let revision = 'master'
if (process.env.NODE_ENV !== 'development') {
try {
let res = cp.execSync(`git log -1 --date=iso --pretty=format:'"%h","%ad"'`, {encoding: 'utf8'})
revision = res.replaceAll('"', '').replace(',', ' ')
} catch (e) {
// ignore
}
}
let envPlugin = {
name: 'env',
setup(build) {
build.onResolve({filter: /\/appenders/}, args => {
build.onResolve({filter: /\/appenders$/}, args => {
let fullpath = path.join(args.resolveDir, args.path)
return {
path: path.relative(__dirname, fullpath).replace(/\\/g, '/'),
@ -57,7 +59,7 @@ async function start(watch) { @@ -57,7 +59,7 @@ async function start(watch) {
}
let watch = false
if (process.argv.length > 2 && process.argv[2] === '--watch') {
if (process.argv.includes('--watch')) {
console.log('watching...')
watch = {
onRebuild(error) {

182
etc/soft/nvim/+plugins/coc.nvim/history.md

@ -1,3 +1,185 @@ @@ -1,3 +1,185 @@
# 2022-03-12
- Avoid use `<sapce><bs>` for cancel completion.
# 2022-03-05
- Make `WinClosed` event fires on `CursorHold` to support vim8.
- Add events `TabNew` and `TabClose`.
- Make outline reuse TreeView buffer.
# 2022-03-02
- Add ultisnip option to `snippetManager.insertSnippet()` and
`snippetManager.resolveSnippet()`.
- Support ultisnip regex option: `/a` (ascii option).
- Support transform replacement of ultisnip, including:
- Variable placeholders, `$0`, `$1` etc.
- Escape sequence `\u` `\l` `\U` `\L` `\E` `\n` `\t`
- Conditional replacement: `(?no:text:other text)`
# 2022-02-28
- Change `workspace.ignoredFiletypes` default value to `[]`
# 2022-02-24
- Add `window.activeTextEditor`, `window.visibleTextEditors`.
- Add events `window.onDidChangeActiveTextEditor` `window.onDidChangeVisibleTextEditors`.
- Add class `RelativePattern`.
- Add `workspace.findFiles()`.
# 2022-02-23
- Add `workspace.openTextDocument()`
- Add `Workspace.getRelativePath()`.
- Add `window.terminals` `window.onDidOpenTerminal` `window.onDidCloseTerminal`
and `window.createTerminal`.
- Add `exitStatus` property to `Terminal`.
- Support `strictEnv` in `TerminalOptions` on neovim.
- Deprecated warning for `workspace.createTerminal()`,
`workspace.onDidOpenTerminal` and `workspace.onDidCloseTerminal`
# 2022-02-18
- Clear all highlights created by coc.nvim before restart.
- Support strike through for ansiparse.
- Support `highlights` for `Documentation` in float window.
# 2022-02-17
- Change workspace configuration throw error when workspace folder can't be
resolved.
- Remove configuration `diagnostic.highlightOffset`.
# 2022-02-15
- Add `events.race`.
- Change default `suggest.triggerCompletionWait` to 50.
- Support trigger completion after indent fix.
# 2022-02-14
- Add `pumvisible` property to events.
# 2022-02-10
- Add shortcut support for `window.showMenuPicker()`.
- Add configuration `dialog.shortcutHighlight` for shortcut highlight.
- Add configuration `list.menuAction` for choose action by menu picker.
# 2022-02-09
- Add error log to `nvim_error_event`.
- Add `nvim.lua()` which replace `nvim.executeLua()` to typings.d.ts.
# 2022-02-08
- Support `MenuItem` with disabled property for `window.showMenuPicker`
- Support show disabled code actions in menu picker.
# 2022-02-07
- Change `:CocLocalConfig` to open configuration file of current workspace
folder.
# 2022-02-05
- Support `version` from `textDocument/publishDiagnostics` notification's parameter.
- Support `codeDescription` of diagnostics by add href to float window.
- Support `showDocument` request from language server.
- Support `label` from DocumentSymbolOptions in outline tree.
- Support extra url use regexp under cursor with `openLink` action.
- Support `activeParameter` from signature information.
- Add `trimTrailingWhitespace`, `insertFinalNewline` and `trimFinalNewlines` to FormattingOptions.
- Add configuration `links.tooltip`, default to `false`.
# 2022-02-04
- Add `--reverse` option to list.
- Add `<esc>` key-mapping to cancel list in preview window (neovim only).
# 2022-02-02
- Remove `disableWorkspaceFolders` `disableDiagnostics` and `disableCompletion`
from language client option.
- Add configuration `documentHighlight.timeout`.
- Add `tabPersist` option to `ListAction`.
- Add `refactor` to `LocationList`
# 2022-01-30
- Add configuration `diagnostics.virtualTextLevel`.
- Remove configuration `suggest.numberSelect`
# 2022-01-26
- Use `nvim_buf_set_text` when possible to keep extmarks.
# 2022-01-25
- Not trigger completion when filtered is succeed.
- Move methods `workspace.getSelectedRange` `workspace.selectRange` to `window`
module, show deprecated warning when using old methods.
# 2022-01-23
- Support semantic tokens highlights from range provider.
# 2022-01-22
- Not set `gravity` with api `nvim_buf_set_extmark` because highlight bug, wait neovim fix.
- Support watch later created workspace folders for file events.
# 2022-01-21
- Changed semantic token highlight prefix from `CocSem_` to `CocSem`.
- Changed semantic token highlight disabled by default, use configuration
`semanticTokens.filetypes`
- Add configuration `semanticTokens.filetypes`.
- Add configuration `semanticTokens.highlightPriority`.
- Add configuration `semanticTokens.incrementTypes`.
- Add configuration `semanticTokens.combinedModifiers`.
- Add command `semanticTokens.refreshCurrent`.
- Add command `semanticTokens.inspect`.
- Add action `inspectSemanticToken`.
- Rework command `semanticTokens.checkCurrent` to show highlight information.
- Support semantic tokens highlight group composed with type and modifier.
# 2022-01-21
- Add configuration `workspace.ignoredFolders`.
- Add configuration `workspace.workspaceFolderFallbackCwd`.
# 2022-01-20
- Remove deprecated method `workspace.resolveRootFolder`.
# 2022-01-17
- Extend `buffer.updateHighlights` to support `priority`, `combine`, `start_incl` and `end_incl`.
- Add configuration `diagnostic.highlightPriority`.
- Add configuration `colors.filetypes` and `colors.highlightPriority`.
# 2022-01-16
- Add configuration `codeLens.position`.
# 2022-01-14
- Add configuration `suggest.selection`.
# 2022-01-13
- `codeLens.separator` now defaults to `""` and will be placed above lines on neovim >= 0.6.0 .
- Add configurations 'diagnostic.locationlistLevel', 'diagnostic.signLevel', 'diagnostic.messageLevel'.
# 2022-01-12
- Add document.lineAt(), export TextLine class.
- Upgrade node-client, support nvim.exec().
- Add documentHighlight.priority configuration.
# 2019-08-18 0.0.74
- feat(cursors): support multiple cursors.

6221
etc/soft/nvim/+plugins/coc.nvim/package-lock.json generated

File diff suppressed because it is too large Load Diff

68
etc/soft/nvim/+plugins/coc.nvim/package.json

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
"name": "coc.nvim-master",
"version": "0.0.80",
"description": "LSP based intellisense engine for neovim & vim8.",
"main": "./lib/index.js",
"main": "./build/index.js",
"engines": {
"node": ">=12.12.0"
},
@ -24,7 +24,6 @@ @@ -24,7 +24,6 @@
"neovim"
],
"author": "Qiming Zhao <chemzqm@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/neoclide/coc.nvim/issues"
},
@ -43,10 +42,6 @@ @@ -43,10 +42,6 @@
"coveragePathIgnorePatterns": [
"<rootDir>/src/__tests__/*"
],
"coverageReporters": [
"text",
"lcov"
],
"moduleFileExtensions": [
"ts",
"tsx",
@ -54,18 +49,27 @@ @@ -54,18 +49,27 @@
"js"
],
"transform": {
"^.+\\.tsx?$": "ts-jest"
"^.+\\.tsx?$": [
"@swc/jest"
]
},
"testRegex": "src/__tests__/.*\\.(test|spec)\\.ts$",
"coverageReporters": [
"text",
"lcov"
],
"coverageDirectory": "./coverage/"
},
"devDependencies": {
"@swc/core": "^1.2.136",
"@swc/jest": "^0.2.17",
"@types/cli-table": "^0.3.0",
"@types/debounce": "^3.0.0",
"@types/fb-watchman": "^2.0.0",
"@types/fs-extra": "^9.0.6",
"@types/jest": "^27.0.1",
"@types/marked": "^2.0.4",
"@types/glob": "^7.2.0",
"@types/jest": "^27.0.3",
"@types/marked": "^4.0.1",
"@types/minimatch": "^3.0.3",
"@types/mkdirp": "^1.0.1",
"@types/node": "12.12.12",
@ -73,49 +77,49 @@ @@ -73,49 +77,49 @@
"@types/tar": "^4.0.5",
"@types/uuid": "^8.3.0",
"@types/which": "^1.3.2",
"@typescript-eslint/eslint-plugin": "^4.11.1",
"@typescript-eslint/parser": "^4.11.1",
"@typescript-eslint/eslint-plugin": "^5.10.2",
"@typescript-eslint/parser": "^5.10.2",
"bser": "^2.1.1",
"esbuild": "^0.12.7",
"eslint": "^7.15.0",
"eslint-plugin-jest": "^24.1.3",
"eslint-plugin-jsdoc": "^30.7.13",
"jest": "27.0.6",
"ts-jest": "^27.0.5",
"typescript": "^4.3.5",
"esbuild": "^0.14.25",
"eslint": "^8.8.0",
"eslint-plugin-jest": "^26.0.0",
"eslint-plugin-jsdoc": "^37.7.0",
"jest": "27.4.5",
"typescript": "^4.5.4",
"vscode-languageserver": "7.0.0"
},
"dependencies": {
"@chemzqm/neovim": "^5.4.0",
"bytes": "^3.1.0",
"tslib": "^2.0.3",
"@chemzqm/neovim": "^5.7.5",
"ansi-styles": "^5.0.0",
"bytes": "^3.1.0",
"cli-table": "^0.3.4",
"content-disposition": "^0.5.3",
"debounce": "^1.2.0",
"decompress-response": "^6.0.0",
"fast-diff": "^1.2.0",
"fb-watchman": "^2.0.1",
"follow-redirects": "^1.14.8",
"fs-extra": "^9.0.1",
"follow-redirects": "^1.13.0",
"http-proxy-agent": "^4.0.1",
"glob": "^7.2.0",
"http-proxy-agent": "^5.0.0",
"https-proxy-agent": "^5.0.0",
"isuri": "^2.0.3",
"jsonc-parser": "^3.0.0",
"log4js": "^6.3.0",
"marked": "^2.1.3",
"log4js": "^6.4.0",
"marked": "^4.0.10",
"minimatch": "^3.0.4",
"rc": "^1.2.8",
"semver": "^7.3.2",
"strip-ansi": "^6.0.0",
"tar": "^6.1.9",
"tslib": "^2.0.3",
"unidecode": "^0.1.8",
"unzip-stream": "^0.3.1",
"content-disposition": "^0.5.3",
"decompress-response": "^6.0.0",
"uuid": "^7.0.3",
"which": "^2.0.2",
"vscode-uri": "^2.1.2",
"vscode-jsonrpc": "^6.0.0",
"vscode-languageserver-protocol": "^3.16.0",
"vscode-languageserver-textdocument": "^1.0.1",
"vscode-languageserver-types": "^3.16.0"
"vscode-languageserver-textdocument": "^1.0.3",
"vscode-languageserver-types": "^3.16.0",
"vscode-uri": "^2.1.2",
"which": "^2.0.2"
}
}

193
etc/soft/nvim/+plugins/coc.nvim/plugin/coc.vim

@ -43,7 +43,7 @@ let g:coc_service_initialized = 0 @@ -43,7 +43,7 @@ let g:coc_service_initialized = 0
let s:is_win = has('win32') || has('win64')
let s:root = expand('<sfile>:h:h')
let s:is_vim = !has('nvim')
let s:is_gvim = get(v:, 'progname', '') ==# 'gvim'
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()
@ -97,12 +97,12 @@ endfunction @@ -97,12 +97,12 @@ endfunction
function! CocLocations(id, method, ...) abort
let args = [a:id, a:method] + copy(a:000)
call coc#rpc#request('findLocations', args)
return coc#rpc#request('findLocations', args)
endfunction
function! CocLocationsAsync(id, method, ...) abort
let args = [a:id, a:method] + copy(a:000)
call coc#rpc#notify('findLocations', args)
return s:AsyncRequest('findLocations', args)
endfunction
function! CocRequestAsync(...)
@ -243,14 +243,24 @@ function! s:Disable() abort @@ -243,14 +243,24 @@ function! s:Disable() abort
endfunction
function! s:Autocmd(...) abort
if !g:coc_service_initialized
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_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:SyncAutocmd(...)
if !g:coc_service_initialized
if !get(g:, 'coc_workspace_initialized', 0)
return
endif
call coc#rpc#request('CocAutocmd', a:000)
@ -287,26 +297,26 @@ function! s:Enable(initialize) @@ -287,26 +297,26 @@ function! s:Enable(initialize)
else
autocmd DirChanged * call s:Autocmd('DirChanged', get(v:event, 'cwd', ''))
autocmd TermOpen * call s:Autocmd('TermOpen', +expand('<abuf>'))
autocmd TermClose * call s:Autocmd('TermClose', +expand('<abuf>'))
autocmd CursorMoved * call coc#float#nvim_refresh_scrollbar(win_getid())
autocmd WinEnter * call coc#float#nvim_win_enter(win_getid())
if exists('##WinClosed')
autocmd WinClosed * call coc#float#close_related(+expand('<afile>'))
autocmd WinClosed * call s:Autocmd('WinClosed', +expand('<afile>'))
endif
endif
if has('nvim-0.4.0') || has('patch-8.1.1719')
autocmd CursorHold * call coc#float#check_related()
endif
autocmd TabNew * call s:Autocmd('TabNew', tabpagenr())
autocmd TabClosed * call s:Autocmd('TabClosed', +expand('<afile>'))
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 CompleteDone * call s:Autocmd('CompleteDone', get(v:, 'completed_item', {}))
autocmd InsertCharPre * call s:Autocmd('InsertCharPre', v:char, bufnr('%'))
autocmd InsertCharPre * call s:HandleCharInsert(v:char, bufnr('%'))
if exists('##TextChangedP')
autocmd TextChangedP * call s:Autocmd('TextChangedP', +expand('<abuf>'), {'lnum': line('.'), 'col': col('.'), 'pre': strpart(getline('.'), 0, col('.') - 1), 'changedtick': b:changedtick})
autocmd TextChangedP * call s:Autocmd('TextChangedP', +expand('<abuf>'), {'lnum': line('.'), 'col': col('.'), 'line': getline('.'), 'changedtick': b:changedtick})
endif
autocmd TextChangedI * call s:Autocmd('TextChangedI', +expand('<abuf>'), {'lnum': line('.'), 'col': col('.'), 'pre': strpart(getline('.'), 0, col('.') - 1), 'changedtick': b:changedtick})
autocmd InsertLeave * call s:Autocmd('InsertLeave', +expand('<abuf>'))
@ -317,8 +327,8 @@ function! s:Enable(initialize) @@ -317,8 +327,8 @@ function! s:Enable(initialize)
autocmd BufWritePost * call s:Autocmd('BufWritePost', +expand('<abuf>'))
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>'))
autocmd CursorHoldI * call s:Autocmd('CursorHoldI', +expand('<abuf>'))
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>'))
@ -345,69 +355,72 @@ function! s:Hi() abort @@ -345,69 +355,72 @@ function! s:Hi() abort
hi default CocHintSign ctermfg=Blue guifg=#15aabf guibg=NONE
hi default CocSelectedText ctermfg=Red guifg=#fb4934 guibg=NONE
hi default CocCodeLens ctermfg=Gray guifg=#999999 guibg=NONE
hi default CocUnderline cterm=underline gui=underline
hi default CocUnderline term=underline cterm=underline gui=underline
hi default CocBold term=bold cterm=bold gui=bold
hi default CocItalic term=italic cterm=italic gui=italic
if s:is_vim || has('nvim-0.4.0')
hi default CocStrikeThrough cterm=strikethrough gui=strikethrough
hi default CocStrikeThrough term=strikethrough cterm=strikethrough gui=strikethrough
else
hi default CocStrikeThrough guifg=#989898 ctermfg=gray
endif
hi default CocMarkdownLink ctermfg=Blue guifg=#15aabf guibg=NONE
hi default link CocFadeOut Conceal
hi default link CocMarkdownCode markdownCode
hi default link CocMarkdownHeader markdownH1
hi default link CocMenuSel PmenuSel
hi default link CocErrorFloat CocErrorSign
hi default link CocWarningFloat CocWarningSign
hi default link CocInfoFloat CocInfoSign
hi default link CocHintFloat CocHintSign
hi default link CocErrorHighlight CocUnderline
hi default link CocWarningHighlight CocUnderline
hi default link CocInfoHighlight CocUnderline
hi default link CocHintHighlight CocUnderline
hi default CocDisabled guifg=#999999 ctermfg=gray
hi default link CocFadeOut Conceal
hi default link CocMarkdownCode markdownCode
hi default link CocMarkdownHeader markdownH1
hi default link CocMenuSel PmenuSel
hi default link CocErrorFloat CocErrorSign
hi default link CocWarningFloat CocWarningSign
hi default link CocInfoFloat CocInfoSign
hi default link CocHintFloat CocHintSign
hi default link CocErrorHighlight CocUnderline
hi default link CocWarningHighlight CocUnderline
hi default link CocInfoHighlight CocUnderline
hi default link CocHintHighlight CocUnderline
hi default link CocDeprecatedHighlight CocStrikeThrough
hi default link CocUnusedHighlight CocFadeOut
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 CocHighlightRead CocHighlightText
hi default link CocHighlightWrite CocHighlightText
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 CocHighlightRead CocHighlightText
hi default link CocHighlightWrite CocHighlightText
" Snippet
hi default link CocSnippetVisual Visual
" Tree view highlights
hi default link CocTreeTitle Title
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
hi default link CocTreeOpenClose CocBold
hi default link CocTreeSelected CursorLine
hi default link CocSelectedRange CocHighlightText
" Symbol highlights
hi default link CocSymbolDefault MoreMsg
hi default link CocSymbolFile Statement
hi default link CocSymbolModule Statement
hi default link CocSymbolNamespace Statement
hi default link CocSymbolPackage Statement
hi default link CocSymbolClass Statement
hi default link CocSymbolMethod Function
hi default link CocSymbolProperty Keyword
hi default link CocSymbolField CocSymbolDefault
hi default link CocSymbolConstructor Function
hi default link CocSymbolEnum CocSymbolDefault
hi default link CocSymbolInterface CocSymbolDefault
hi default link CocSymbolFunction Function
hi default link CocSymbolVariable CocSymbolDefault
hi default link CocSymbolConstant Constant
hi default link CocSymbolString String
hi default link CocSymbolNumber Number
hi default link CocSymbolBoolean Boolean
hi default link CocSymbolArray CocSymbolDefault
hi default link CocSymbolObject CocSymbolDefault
hi default link CocSymbolKey Keyword
hi default link CocSymbolNull Type
hi default link CocSymbolEnumMember CocSymbolDefault
hi default link CocSymbolStruct Keyword
hi default link CocSymbolEvent Keyword
hi default link CocSymbolOperator Operator
hi default link CocSymbolDefault MoreMsg
hi default link CocSymbolFile Statement
hi default link CocSymbolModule Statement
hi default link CocSymbolNamespace Statement
hi default link CocSymbolPackage Statement
hi default link CocSymbolClass Statement
hi default link CocSymbolMethod Function
hi default link CocSymbolProperty Keyword
hi default link CocSymbolField CocSymbolDefault
hi default link CocSymbolConstructor Function
hi default link CocSymbolEnum CocSymbolDefault
hi default link CocSymbolInterface CocSymbolDefault
hi default link CocSymbolFunction Function
hi default link CocSymbolVariable CocSymbolDefault
hi default link CocSymbolConstant Constant
hi default link CocSymbolString String
hi default link CocSymbolNumber Number
hi default link CocSymbolBoolean Boolean
hi default link CocSymbolArray CocSymbolDefault
hi default link CocSymbolObject CocSymbolDefault
hi default link CocSymbolKey Keyword
hi default link CocSymbolNull Type
hi default link CocSymbolEnumMember CocSymbolDefault
hi default link CocSymbolStruct Keyword
hi default link CocSymbolEvent Keyword
hi default link CocSymbolOperator Operator
hi default link CocSymbolTypeParameter Operator
if has('nvim')
@ -435,29 +448,39 @@ function! s:Hi() abort @@ -435,29 +448,39 @@ function! s:Hi() abort
endif
call s:AddAnsiGroups()
if get(g:, 'coc_default_semantic_highlight_groups', 0) == 1
hi default link CocSem_namespace Identifier
hi default link CocSem_type Type
hi default link CocSem_class Structure
hi default link CocSem_enum Type
hi default link CocSem_interface Type
hi default link CocSem_struct Structure
hi default link CocSem_typeParameter Type
hi default link CocSem_parameter Identifier
hi default link CocSem_variable Identifier
hi default link CocSem_property Identifier
hi default link CocSem_enumMember Constant
hi default link CocSem_event Identifier
hi default link CocSem_function Function
hi default link CocSem_method Function
hi default link CocSem_macro Macro
hi default link CocSem_keyword Keyword
hi default link CocSem_modifier StorageClass
hi default link CocSem_comment Comment
hi default link CocSem_string String
hi default link CocSem_number Number
hi default link CocSem_regexp Normal
hi default link CocSem_operator Operator
if get(g:, 'coc_default_semantic_highlight_groups', 1)
let hlMap = {
\ 'Namespace': ['TSNamespace', 'Include'],
\ 'Type': ['TSType', 'Type'],
\ 'Class': ['TSConstructor', 'Special'],
\ 'Enum': ['TSEnum', 'Type'],
\ 'Interface': ['TSInterface', 'Type'],
\ 'Struct': ['TSStruct', 'Identifier'],
\ 'TypeParameter': ['TSParameter', 'Identifier'],
\ 'Parameter': ['TSParameter', 'Identifier'],
\ 'Variable': ['TSSymbol', 'Identifier'],
\ 'Property': ['TSProperty', 'Identifier'],
\ 'EnumMember': ['TSEnumMember', 'Constant'],
\ 'Event': ['TSEvent', 'Keyword'],
\ 'Function': ['TSFunction', 'Function'],
\ 'Method': ['TSMethod', 'Function'],
\ 'Macro': ['TSConstMacro', 'Define'],
\ 'Keyword': ['TSKeyword', 'Keyword'],
\ 'Modifier': ['TSModifier', 'StorageClass'],
\ 'Comment': ['TSComment', 'Comment'],
\ 'String': ['TSString', 'String'],
\ 'Number': ['TSNumber', 'Number'],
\ 'Boolean': ['TSBoolean', 'Boolean'],
\ 'Regexp': ['TSStringRegex', 'String'],
\ 'Operator': ['TSOperator', 'Operator'],
\ 'Decorator': ['TSSymbol', 'Identifier'],
\ 'Deprecated': ['TSStrike', 'CocDeprecatedHighlight']
\ }
for [key, value] in items(hlMap)
let ts = get(value, 0, '')
let fallback = get(value, 1, '')
execute 'hi default link CocSem'.key.' '.(hlexists(ts) ? ts : fallback)
endfor
endif
endfunction

0
etc/soft/nvim/+plugins/coc.nvim/requirements.txt

17
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/autoload/coc/source/email.vim

@ -1,17 +0,0 @@ @@ -1,17 +0,0 @@
" vim source for emails
function! coc#source#email#init() abort
return {
\ 'priority': 9,
\ 'shortcut': 'Email',
\ 'triggerCharacters': ['@']
\}
endfunction
function! coc#source#email#should_complete(opt) abort
return 1
endfunction
function! coc#source#email#complete(opt, cb) abort
let items = ['foo@gmail.com', 'bar@yahoo.com']
call a:cb(items)
endfunction

62
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/changedFiles.test.ts

@ -1,62 +0,0 @@ @@ -1,62 +0,0 @@
/* eslint-disable */
import helper from '../helper'
// import * as assert from 'assert'
import fs from 'fs'
import * as lsclient from '../../language-client'
import * as path from 'path'
import { URI } from 'vscode-uri'
// import which from 'which'
beforeAll(async () => {
await helper.setup()
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
})
describe('Client integration', () => {
it('should send file change notification', (done) => {
if (global.hasOwnProperty('__TEST__')) return done()
let serverModule = path.join(__dirname, './server/testFileWatcher.js')
let serverOptions: lsclient.ServerOptions = {
module: serverModule,
transport: lsclient.TransportKind.ipc
}
let clientOptions: lsclient.LanguageClientOptions = {
documentSelector: ['css'],
synchronize: {}, initializationOptions: {},
middleware: {
}
}
let client = new lsclient.LanguageClient('css', 'Test Language Server', serverOptions, clientOptions)
let disposable = client.start()
client.onReady().then(_ => {
setTimeout(async () => {
let file = path.join(__dirname, 'test.js')
fs.writeFileSync(file, '', 'utf8')
await helper.wait(300)
let res = await client.sendRequest('custom/received')
expect(res).toEqual({
changes: [{
uri: URI.file(file).toString(),
type: 1
}]
})
fs.unlinkSync(file)
disposable.dispose()
done()
}, 200)
}, e => {
disposable.dispose()
done(e)
})
})
})

140
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/connection.test.ts

@ -1,140 +0,0 @@ @@ -1,140 +0,0 @@
import { Duplex } from 'stream'
import { ProgressType } from 'vscode-jsonrpc'
import { createProtocolConnection, DocumentSymbolParams, DocumentSymbolRequest, InitializeParams, InitializeRequest, InitializeResult, ProtocolConnection, StreamMessageReader, StreamMessageWriter } from 'vscode-languageserver-protocol/node'
import { SymbolInformation, SymbolKind } from 'vscode-languageserver-types'
import { NullLogger } from '../../language-client/client'
class TestStream extends Duplex {
public _write(chunk: string, _encoding: string, done: () => void): void {
this.emit('data', chunk)
done()
}
public _read(_size: number): void {
}
}
let serverConnection: ProtocolConnection
let clientConnection: ProtocolConnection
let progressType: ProgressType<any> = new ProgressType()
beforeEach(() => {
const up = new TestStream()
const down = new TestStream()
const logger = new NullLogger()
serverConnection = createProtocolConnection(new StreamMessageReader(up), new StreamMessageWriter(down), logger)
clientConnection = createProtocolConnection(new StreamMessageReader(down), new StreamMessageWriter(up), logger)
serverConnection.listen()
clientConnection.listen()
})
afterEach(() => {
serverConnection.dispose()
clientConnection.dispose()
})
describe('Connection Tests', () => {
it('should ensure proper param passing', async () => {
let paramsCorrect = false
serverConnection.onRequest(InitializeRequest.type, params => {
paramsCorrect = !Array.isArray(params)
let result: InitializeResult = {
capabilities: {
}
}
return result
})
const init: InitializeParams = {
rootUri: 'file:///home/dirkb',
processId: 1,
capabilities: {},
workspaceFolders: null,
}
await clientConnection.sendRequest(InitializeRequest.type, init)
expect(paramsCorrect).toBe(true)
})
it('should provid token', async () => {
serverConnection.onRequest(DocumentSymbolRequest.type, params => {
expect(params.partialResultToken).toBe('3b1db4c9-e011-489e-a9d1-0653e64707c2')
return []
})
const params: DocumentSymbolParams = {
textDocument: { uri: 'file:///abc.txt' },
partialResultToken: '3b1db4c9-e011-489e-a9d1-0653e64707c2'
}
await clientConnection.sendRequest(DocumentSymbolRequest.type, params)
})
it('should report result', async () => {
let result: SymbolInformation = {
name: 'abc',
kind: SymbolKind.Class,
location: {
uri: 'file:///abc.txt',
range: { start: { line: 0, character: 1 }, end: { line: 2, character: 3 } }
}
}
serverConnection.onRequest(DocumentSymbolRequest.type, params => {
expect(params.partialResultToken).toBe('3b1db4c9-e011-489e-a9d1-0653e64707c2')
serverConnection.sendProgress(progressType, params.partialResultToken, [result])
return []
})
const params: DocumentSymbolParams = {
textDocument: { uri: 'file:///abc.txt' },
partialResultToken: '3b1db4c9-e011-489e-a9d1-0653e64707c2'
}
let progressOK = false
clientConnection.onProgress(progressType, '3b1db4c9-e011-489e-a9d1-0653e64707c2', values => {
progressOK = (values !== undefined && values.length === 1)
})
await clientConnection.sendRequest(DocumentSymbolRequest.type, params)
expect(progressOK).toBeTruthy()
})
it('should provide workDoneToken', async () => {
serverConnection.onRequest(DocumentSymbolRequest.type, params => {
expect(params.workDoneToken).toBe('3b1db4c9-e011-489e-a9d1-0653e64707c2')
return []
})
const params: DocumentSymbolParams = {
textDocument: { uri: 'file:///abc.txt' },
workDoneToken: '3b1db4c9-e011-489e-a9d1-0653e64707c2'
}
await clientConnection.sendRequest(DocumentSymbolRequest.type, params)
})
it('should report work done progress', async () => {
serverConnection.onRequest(DocumentSymbolRequest.type, params => {
expect(params.workDoneToken).toBe('3b1db4c9-e011-489e-a9d1-0653e64707c2')
serverConnection.sendProgress(progressType, params.workDoneToken, {
kind: 'begin',
title: 'progress'
})
serverConnection.sendProgress(progressType, params.workDoneToken, {
kind: 'report',
message: 'message'
})
serverConnection.sendProgress(progressType, params.workDoneToken, {
kind: 'end',
message: 'message'
})
return []
})
const params: DocumentSymbolParams = {
textDocument: { uri: 'file:///abc.txt' },
workDoneToken: '3b1db4c9-e011-489e-a9d1-0653e64707c2'
}
let result = ''
clientConnection.onProgress(progressType, '3b1db4c9-e011-489e-a9d1-0653e64707c2', value => {
result += value.kind
})
await clientConnection.sendRequest(DocumentSymbolRequest.type, params)
expect(result).toBe('beginreportend')
})
})

89
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/converter.test.ts

@ -1,89 +0,0 @@ @@ -1,89 +0,0 @@
import { CompletionTriggerKind, Position, TextDocumentItem, TextDocumentSaveReason } from 'vscode-languageserver-protocol'
import { TextDocument } from 'vscode-languageserver-textdocument'
import { URI } from 'vscode-uri'
import * as cv from '../../language-client/utils/converter'
describe('converter', () => {
function createDocument(): TextDocument {
return TextDocument.create('file:///1', 'css', 1, '')
}
it('should asLanguageIds', () => {
let selector = ['css', { language: 'javascript' }]
expect(cv.asLanguageIds(selector)).toEqual(['css', 'javascript'])
})
it('should convertToTextDocumentItem', () => {
let doc = createDocument()
expect(cv.convertToTextDocumentItem(doc).uri).toBe(doc.uri)
expect(TextDocumentItem.is(cv.convertToTextDocumentItem(doc))).toBe(true)
})
it('should asCloseTextDocumentParams', () => {
let doc = createDocument()
expect(cv.asCloseTextDocumentParams(doc).textDocument.uri).toBe(doc.uri)
})
it('should asChangeTextDocumentParams', () => {
let doc = createDocument()
expect(cv.asChangeTextDocumentParams(doc).textDocument.uri).toBe(doc.uri)
})
it('should asWillSaveTextDocumentParams', () => {
let res = cv.asWillSaveTextDocumentParams({ document: createDocument(), reason: TextDocumentSaveReason.Manual, waitUntil: () => { } })
expect(res.textDocument).toBeDefined()
expect(res.reason).toBeDefined()
})
it('should asVersionedTextDocumentIdentifier', () => {
let res = cv.asVersionedTextDocumentIdentifier(createDocument())
expect(res.uri).toBeDefined()
expect(res.version).toBeDefined()
})
it('should asSaveTextDocumentParams', () => {
let res = cv.asSaveTextDocumentParams(createDocument(), true)
expect(res.textDocument.uri).toBeDefined()
expect(res.text).toBeDefined()
})
it('should asUri', () => {
let uri = URI.file('/tmp/a')
expect(cv.asUri(uri)).toBe(uri.toString())
})
it('should asCompletionParams', () => {
let params = cv.asCompletionParams(createDocument(), Position.create(0, 0), { triggerKind: CompletionTriggerKind.Invoked })
expect(params.textDocument).toBeDefined()
expect(params.position).toBeDefined()
expect(params.context).toBeDefined()
})
it('should asTextDocumentPositionParams', () => {
let params = cv.asTextDocumentPositionParams(createDocument(), Position.create(0, 0))
expect(params.textDocument).toBeDefined()
expect(params.position).toBeDefined()
})
it('should asTextDocumentIdentifier', () => {
let doc = cv.asTextDocumentIdentifier(createDocument())
expect(doc.uri).toBeDefined()
})
it('should asReferenceParams', () => {
let params = cv.asReferenceParams(createDocument(), Position.create(0, 0), { includeDeclaration: false })
expect(params.textDocument.uri).toBeDefined()
expect(params.position).toBeDefined()
})
it('should asDocumentSymbolParams', () => {
let doc = cv.asDocumentSymbolParams(createDocument())
expect(doc.textDocument.uri).toBeDefined()
})
it('should asCodeLensParams', () => {
let doc = cv.asCodeLensParams(createDocument())
expect(doc.textDocument.uri).toBeDefined()
})
})

154
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/delayer.test.ts

@ -1,154 +0,0 @@ @@ -1,154 +0,0 @@
/* eslint-disable */
import assert from 'assert'
import { Delayer } from '../../language-client/utils/async'
test('Delayer', () => {
let count = 0
let factory = () => {
return Promise.resolve(++count)
}
let delayer = new Delayer(0)
let promises: Thenable<any>[] = []
assert(!delayer.isTriggered())
promises.push(delayer.trigger(factory).then((result) => { assert.equal(result, 1); assert(!delayer.isTriggered()) }))
assert(delayer.isTriggered())
promises.push(delayer.trigger(factory).then((result) => { assert.equal(result, 1); assert(!delayer.isTriggered()) }))
assert(delayer.isTriggered())
promises.push(delayer.trigger(factory).then((result) => { assert.equal(result, 1); assert(!delayer.isTriggered()) }))
assert(delayer.isTriggered())
return Promise.all(promises).then(() => {
assert(!delayer.isTriggered())
}).finally(() => {
delayer.dispose()
})
})
/*
test('Delayer - simple cancel', async () => {
let count = 0
let factory = () => {
return Promise.resolve(++count)
}
let delayer = new Delayer(10)
assert(!delayer.isTriggered())
const p = delayer.trigger(factory).then(() => {
assert(false)
}, () => {
assert(true, 'yes, it was cancelled')
})
assert(delayer.isTriggered())
delayer.cancel()
assert(!delayer.isTriggered())
await p
})
test('Delayer - cancel should cancel all calls to trigger', function() {
let count = 0
let factory = () => {
return Promise.resolve(++count)
}
let delayer = new Delayer(0)
let promises: Thenable<any>[] = []
assert(!delayer.isTriggered())
promises.push(delayer.trigger(factory).then(null, () => { assert(true, 'yes, it was cancelled') }))
assert(delayer.isTriggered())
promises.push(delayer.trigger(factory).then(null, () => { assert(true, 'yes, it was cancelled') }))
assert(delayer.isTriggered())
promises.push(delayer.trigger(factory).then(null, () => { assert(true, 'yes, it was cancelled') }))
assert(delayer.isTriggered())
delayer.cancel()
return Promise.all(promises).then(() => {
assert(!delayer.isTriggered())
})
})
test('Delayer - trigger, cancel, then trigger again', function() {
let count = 0
let factory = () => {
return Promise.resolve(++count)
}
let delayer = new Delayer(0)
let promises: Thenable<any>[] = []
assert(!delayer.isTriggered())
const p = delayer.trigger(factory).then((result) => {
assert.equal(result, 1)
assert(!delayer.isTriggered())
promises.push(delayer.trigger(factory).then(null, () => { assert(true, 'yes, it was cancelled') }))
assert(delayer.isTriggered())
promises.push(delayer.trigger(factory).then(null, () => { assert(true, 'yes, it was cancelled') }))
assert(delayer.isTriggered())
delayer.cancel()
const p = Promise.all(promises).then(() => {
promises = []
assert(!delayer.isTriggered())
promises.push(delayer.trigger(factory).then(() => { assert.equal(result, 1); assert(!delayer.isTriggered()) }))
assert(delayer.isTriggered())
promises.push(delayer.trigger(factory).then(() => { assert.equal(result, 1); assert(!delayer.isTriggered()) }))
assert(delayer.isTriggered())
const p = Promise.all(promises).then(() => {
assert(!delayer.isTriggered())
})
assert(delayer.isTriggered())
return p
})
return p
})
assert(delayer.isTriggered())
return p
})
*/
test('Delayer - last task should be the one getting called', function() {
let factoryFactory = (n: number) => () => {
return Promise.resolve(n)
}
let delayer = new Delayer(0)
let promises: Thenable<any>[] = []
assert(!delayer.isTriggered())
promises.push(delayer.trigger(factoryFactory(1)).then((n) => { assert.equal(n, 3) }))
promises.push(delayer.trigger(factoryFactory(2)).then((n) => { assert.equal(n, 3) }))
promises.push(delayer.trigger(factoryFactory(3)).then((n) => { assert.equal(n, 3) }))
const p = Promise.all(promises).then(() => {
assert(!delayer.isTriggered())
})
assert(delayer.isTriggered())
return p
})

1054
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/features.test.ts

File diff suppressed because it is too large Load Diff

128
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/integration.test.ts

@ -1,128 +0,0 @@ @@ -1,128 +0,0 @@
/* eslint-disable */
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict'
import helper from '../helper'
import * as assert from 'assert'
import * as lsclient from '../../language-client'
import path from 'path'
beforeAll(async () => {
await helper.setup()
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
})
async function testLanguageServer(serverOptions: lsclient.ServerOptions): Promise<void> {
let clientOptions: lsclient.LanguageClientOptions = {
documentSelector: ['css'],
synchronize: {},
initializationOptions: {}
}
let client = new lsclient.LanguageClient('css', 'Test Language Server', serverOptions, clientOptions)
client.start()
await client.onReady()
expect(client.initializeResult).toBeDefined()
}
describe('Client integration', () => {
it('should initialize use IPC channel', (done) => {
let serverModule = path.join(__dirname, './server/testInitializeResult.js')
let serverOptions: lsclient.ServerOptions = {
run: { module: serverModule, transport: lsclient.TransportKind.ipc },
debug: { module: serverModule, transport: lsclient.TransportKind.ipc, options: { execArgv: ['--nolazy', '--inspect=6014'] } }
}
let clientOptions: lsclient.LanguageClientOptions = {
documentSelector: ['css'],
synchronize: {}, initializationOptions: {},
middleware: {
handleDiagnostics: (uri, diagnostics, next) => {
assert.equal(uri, "uri:/test.ts")
assert.ok(Array.isArray(diagnostics))
assert.equal(diagnostics.length, 0)
next(uri, diagnostics)
disposable.dispose()
done()
}
}
}
let client = new lsclient.LanguageClient('css', 'Test Language Server', serverOptions, clientOptions)
let disposable = client.start()
assert.equal(client.initializeResult, undefined)
client.onReady().then(_ => {
try {
let expected = {
capabilities: {
textDocumentSync: 1,
completionProvider: { resolveProvider: true, triggerCharacters: ['"', ':'] },
hoverProvider: true,
renameProvider: {
prepareProvider: true
}
},
customResults: {
"hello": "world"
}
}
assert.deepEqual(client.initializeResult, expected)
} catch (e) {
disposable.dispose()
done(e)
}
}, e => {
disposable.dispose()
done(e)
})
})
it('should initialize use stdio', async () => {
let serverModule = path.join(__dirname, './server/testInitializeResult.js')
let serverOptions: lsclient.ServerOptions = {
module: serverModule,
transport: lsclient.TransportKind.stdio
}
await testLanguageServer(serverOptions)
})
it('should initialize use pipe', async () => {
let serverModule = path.join(__dirname, './server/testInitializeResult.js')
let serverOptions: lsclient.ServerOptions = {
module: serverModule,
transport: lsclient.TransportKind.pipe
}
await testLanguageServer(serverOptions)
})
it('should initialize use socket', async () => {
let serverModule = path.join(__dirname, './server/testInitializeResult.js')
let serverOptions: lsclient.ServerOptions = {
module: serverModule,
transport: {
kind: lsclient.TransportKind.socket,
port: 8088
}
}
await testLanguageServer(serverOptions)
})
it('should initialize as command', async () => {
let serverModule = path.join(__dirname, './server/testInitializeResult.js')
let serverOptions: lsclient.ServerOptions = {
command: 'node',
args: [serverModule, '--stdio']
}
await testLanguageServer(serverOptions)
})
})

35
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/server/testFileWatcher.js

@ -1,35 +0,0 @@ @@ -1,35 +0,0 @@
const languageserver = require('vscode-languageserver')
let connection = languageserver.createConnection()
let documents = new languageserver.TextDocuments()
documents.listen(connection)
connection.onInitialize(() => {
let capabilities = {
textDocumentSync: documents.syncKind
}
return { capabilities }
})
connection.onInitialized(() => {
connection.sendRequest('client/registerCapability', {
registrations: [{
id: 'didChangeWatchedFiles',
method: 'workspace/didChangeWatchedFiles',
registerOptions: {
watchers: [{ globPattern: "**" }]
}
}]
})
})
let received
connection.onNotification('workspace/didChangeWatchedFiles', params => {
received = params
})
connection.onRequest('custom/received', async () => {
return received
})
connection.listen()

40
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/server/testInitializeResult.js

@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict'
Object.defineProperty(exports, "__esModule", {value: true})
const tslib_1 = require("tslib")
const assert = tslib_1.__importStar(require("assert"))
const vscode_languageserver_1 = require("vscode-languageserver")
let connection = vscode_languageserver_1.createConnection()
let documents = new vscode_languageserver_1.TextDocuments()
documents.listen(connection)
connection.onInitialize((params) => {
assert.equal(params.capabilities.workspace.applyEdit, true)
assert.equal(params.capabilities.workspace.workspaceEdit.documentChanges, true)
assert.deepEqual(params.capabilities.workspace.workspaceEdit.resourceOperations, [vscode_languageserver_1.ResourceOperationKind.Create, vscode_languageserver_1.ResourceOperationKind.Rename, vscode_languageserver_1.ResourceOperationKind.Delete])
assert.equal(params.capabilities.workspace.workspaceEdit.failureHandling, vscode_languageserver_1.FailureHandlingKind.TextOnlyTransactional)
assert.equal(params.capabilities.textDocument.completion.completionItem.deprecatedSupport, true)
assert.equal(params.capabilities.textDocument.completion.completionItem.preselectSupport, true)
assert.equal(params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport, true)
assert.equal(params.capabilities.textDocument.rename.prepareSupport, true)
let valueSet = params.capabilities.textDocument.completion.completionItemKind.valueSet
assert.equal(valueSet[0], 1)
assert.equal(valueSet[valueSet.length - 1], vscode_languageserver_1.CompletionItemKind.TypeParameter)
let capabilities = {
textDocumentSync: documents.syncKind,
completionProvider: {resolveProvider: true, triggerCharacters: ['"', ':']},
hoverProvider: true,
renameProvider: {
prepareProvider: true
}
}
return {capabilities, customResults: {"hello": "world"}}
})
connection.onInitialized(() => {
connection.sendDiagnostics({uri: "uri:/test.ts", diagnostics: []})
})
// Listen on the connection
connection.listen()

414
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/client/server/testServer.js

@ -1,414 +0,0 @@ @@ -1,414 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const assert = require('assert')
const {URI} = require('vscode-uri')
const {
createConnection, CompletionItemKind, ResourceOperationKind, FailureHandlingKind,
DiagnosticTag, CompletionItemTag, TextDocumentSyncKind, MarkupKind, SignatureInformation, ParameterInformation,
Location, Range, DocumentHighlight, DocumentHighlightKind, CodeAction, Command, TextEdit, Position, DocumentLink,
ColorInformation, Color, ColorPresentation, FoldingRange, SelectionRange, SymbolKind, ProtocolRequestType, WorkDoneProgress,
WorkDoneProgressCreateRequest} = require('vscode-languageserver')
const {
DidCreateFilesNotification,
DidRenameFilesNotification,
DidDeleteFilesNotification,
WillCreateFilesRequest, WillRenameFilesRequest, WillDeleteFilesRequest
} = require('vscode-languageserver-protocol')
let connection = createConnection()
console.log = connection.console.log.bind(connection.console)
console.error = connection.console.error.bind(connection.console)
connection.onInitialize(params => {
assert.equal((params.capabilities.workspace).applyEdit, true)
assert.equal(params.capabilities.workspace.workspaceEdit.documentChanges, true)
assert.equal(params.capabilities.workspace.workspaceEdit.failureHandling, FailureHandlingKind.TextOnlyTransactional)
assert.equal(params.capabilities.textDocument.completion.completionItem.deprecatedSupport, true)
assert.equal(params.capabilities.textDocument.completion.completionItem.preselectSupport, true)
assert.equal(params.capabilities.textDocument.completion.completionItem.tagSupport.valueSet.length, 1)
assert.equal(params.capabilities.textDocument.completion.completionItem.tagSupport.valueSet[0], CompletionItemTag.Deprecated)
assert.equal(params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport, true)
// assert.equal(params.capabilities.textDocument.definition.linkSupport, true)
// assert.equal(params.capabilities.textDocument.declaration.linkSupport, true)
// assert.equal(params.capabilities.textDocument.implementation.linkSupport, true)
// assert.equal(params.capabilities.textDocument.typeDefinition.linkSupport, true)
assert.equal(params.capabilities.textDocument.rename.prepareSupport, true)
assert.equal(params.capabilities.textDocument.publishDiagnostics.relatedInformation, true)
assert.equal(params.capabilities.textDocument.publishDiagnostics.tagSupport.valueSet.length, 2)
assert.equal(params.capabilities.textDocument.publishDiagnostics.tagSupport.valueSet[0], DiagnosticTag.Unnecessary)
assert.equal(params.capabilities.textDocument.publishDiagnostics.tagSupport.valueSet[1], DiagnosticTag.Deprecated)
assert.equal(params.capabilities.textDocument.documentLink.tooltipSupport, true)
let valueSet = params.capabilities.textDocument.completion.completionItemKind.valueSet
assert.equal(valueSet[0], 1)
assert.equal(valueSet[valueSet.length - 1], CompletionItemKind.TypeParameter)
assert.deepEqual(params.capabilities.workspace.workspaceEdit.resourceOperations, [ResourceOperationKind.Create, ResourceOperationKind.Rename, ResourceOperationKind.Delete])
assert.equal(params.capabilities.workspace.fileOperations.willCreate, true)
let capabilities = {
textDocumentSync: TextDocumentSyncKind.Full,
definitionProvider: true,
hoverProvider: true,
completionProvider: {resolveProvider: true, triggerCharacters: ['"', ':']},
signatureHelpProvider: {
triggerCharacters: [':'],
retriggerCharacters: [':']
},
referencesProvider: true,
documentHighlightProvider: true,
codeActionProvider: {
resolveProvider: true
},
documentFormattingProvider: true,
documentRangeFormattingProvider: true,
documentOnTypeFormattingProvider: {
firstTriggerCharacter: ':'
},
renameProvider: {
prepareProvider: true
},
documentLinkProvider: {
resolveProvider: true
},
colorProvider: true,
declarationProvider: true,
foldingRangeProvider: true,
implementationProvider: true,
selectionRangeProvider: true,
typeDefinitionProvider: true,
callHierarchyProvider: true,
semanticTokensProvider: {
legend: {
tokenTypes: [],
tokenModifiers: []
},
range: true,
full: {
delta: true
}
},
workspace: {
fileOperations: {
// Static reg is folders + .txt files with operation kind in the path
didCreate: {
filters: [{ scheme: 'file', pattern: { glob: '**/created-static/**{/,/*.txt}' }}]
},
didRename: {
filters: [
{ scheme: 'file', pattern: { glob: '**/renamed-static/**/', matches: 'folder' } },
{ scheme: 'file', pattern: { glob: '**/renamed-static/**/*.txt', matches: 'file' } }
]
},
didDelete: {
filters: [{ scheme: 'file', pattern: { glob: '**/deleted-static/**{/,/*.txt}' } }]
},
willCreate: {
filters: [{ scheme: 'file', pattern: { glob: '**/created-static/**{/,/*.txt}' } }]
},
willRename: {
filters: [
{ scheme: 'file', pattern: { glob: '**/renamed-static/**/', matches: 'folder' } },
{ scheme: 'file', pattern: { glob: '**/renamed-static/**/*.txt', matches: 'file' } }
]
},
willDelete: {
filters: [{ scheme: 'file', pattern: { glob: '**/deleted-static/**{/,/*.txt}' } }]
},
},
},
linkedEditingRangeProvider: true
}
return {capabilities, customResults: {hello: 'world'}}
})
connection.onInitialized(() => {
// Dynamic reg is folders + .js files with operation kind in the path
connection.client.register(DidCreateFilesNotification.type, {
filters: [{ scheme: 'file', pattern: { glob: '**/created-dynamic/**{/,/*.js}' } }]
});
connection.client.register(DidRenameFilesNotification.type, {
filters: [
{ scheme: 'file', pattern: { glob: '**/renamed-dynamic/**/', matches: 'folder' } },
{ scheme: 'file', pattern: { glob: '**/renamed-dynamic/**/*.js', matches: 'file' } }
]
});
connection.client.register(DidDeleteFilesNotification.type, {
filters: [{ scheme: 'file', pattern: { glob: '**/deleted-dynamic/**{/,/*.js}' } }]
});
connection.client.register(WillCreateFilesRequest.type, {
filters: [{ scheme: 'file', pattern: { glob: '**/created-dynamic/**{/,/*.js}' } }]
});
connection.client.register(WillRenameFilesRequest.type, {
filters: [
{ scheme: 'file', pattern: { glob: '**/renamed-dynamic/**/', matches: 'folder' } },
{ scheme: 'file', pattern: { glob: '**/renamed-dynamic/**/*.js', matches: 'file' } }
]
});
connection.client.register(WillDeleteFilesRequest.type, {
filters: [{ scheme: 'file', pattern: { glob: '**/deleted-dynamic/**{/,/*.js}' } }]
});
})
connection.onDeclaration((params) => {
assert.equal(params.position.line, 1)
assert.equal(params.position.character, 1)
return {uri: params.textDocument.uri, range: {start: {line: 1, character: 1}, end: {line: 1, character: 2}}}
})
connection.onDefinition((params) => {
assert.equal(params.position.line, 1)
assert.equal(params.position.character, 1)
return {uri: params.textDocument.uri, range: {start: {line: 0, character: 0}, end: {line: 0, character: 1}}}
})
connection.onHover((_params) => {
return {
contents: {
kind: MarkupKind.PlainText,
value: 'foo'
}
}
})
connection.onCompletion((_params) => {
return [
{label: 'item', insertText: 'text'}
]
})
connection.onCompletionResolve((item) => {
item.detail = 'detail'
return item
})
connection.onSignatureHelp((_params) => {
const result = {
signatures: [
SignatureInformation.create('label', 'doc', ParameterInformation.create('label', 'doc'))
],
activeSignature: 1,
activeParameter: 1
}
return result
})
connection.onReferences((params) => {
return [
Location.create(params.textDocument.uri, Range.create(0, 0, 0, 0)),
Location.create(params.textDocument.uri, Range.create(1, 1, 1, 1))
]
})
connection.onDocumentHighlight((_params) => {
return [
DocumentHighlight.create(Range.create(2, 2, 2, 2), DocumentHighlightKind.Read)
]
})
connection.onCodeAction((_params) => {
return [
CodeAction.create('title', Command.create('title', 'id'))
]
})
connection.onCodeActionResolve((codeAction) => {
codeAction.title = 'resolved'
return codeAction
})
connection.onDocumentFormatting((_params) => {
return [
TextEdit.insert(Position.create(0, 0), 'insert')
]
})
connection.onDocumentRangeFormatting((_params) => {
return [
TextEdit.del(Range.create(1, 1, 1, 2))
]
})
connection.onDocumentOnTypeFormatting((_params) => {
return [
TextEdit.replace(Range.create(2, 2, 2, 3), 'replace')
]
})
connection.onPrepareRename((_params) => {
return Range.create(1, 1, 1, 2)
})
connection.onRenameRequest((_params) => {
return {documentChanges: []}
})
connection.onDocumentLinks((_params) => {
return [
DocumentLink.create(Range.create(1, 1, 1, 2))
]
})
connection.onDocumentLinkResolve((link) => {
link.target = URI.file('/target.txt').toString()
return link
})
connection.onDocumentColor((_params) => {
return [
ColorInformation.create(Range.create(1, 1, 1, 2), Color.create(1, 1, 1, 1))
]
})
connection.onColorPresentation((_params) => {
return [
ColorPresentation.create('label')
]
})
connection.onFoldingRanges((_params) => {
return [
FoldingRange.create(1, 2)
]
})
connection.onImplementation((params) => {
assert.equal(params.position.line, 1)
assert.equal(params.position.character, 1)
return {uri: params.textDocument.uri, range: {start: {line: 2, character: 2}, end: {line: 3, character: 3}}}
})
connection.onSelectionRanges((_params) => {
return [
SelectionRange.create(Range.create(1, 2, 3, 4))
]
})
let lastFileOperationRequest
connection.workspace.onDidCreateFiles((params) => {lastFileOperationRequest = {type: 'create', params}})
connection.workspace.onDidRenameFiles((params) => {lastFileOperationRequest = {type: 'rename', params}})
connection.workspace.onDidDeleteFiles((params) => {lastFileOperationRequest = {type: 'delete', params}})
connection.onRequest(
new ProtocolRequestType('testing/lastFileOperationRequest'),
() => {
return lastFileOperationRequest
},
)
connection.workspace.onWillCreateFiles((params) => {
const createdFilenames = params.files.map((f) => `${f.uri}`).join('\n')
return {
documentChanges: [{
textDocument: {uri: '/dummy-edit', version: null},
edits: [
TextEdit.insert(Position.create(0, 0), `WILL CREATE:\n${createdFilenames}`),
]
}],
}
})
connection.workspace.onWillRenameFiles((params) => {
const renamedFilenames = params.files.map((f) => `${f.oldUri} -> ${f.newUri}`).join('\n')
return {
documentChanges: [{
textDocument: {uri: '/dummy-edit', version: null},
edits: [
TextEdit.insert(Position.create(0, 0), `WILL RENAME:\n${renamedFilenames}`),
]
}],
}
})
connection.workspace.onWillDeleteFiles((params) => {
const deletedFilenames = params.files.map((f) => `${f.uri}`).join('\n')
return {
documentChanges: [{
textDocument: {uri: '/dummy-edit', version: null},
edits: [
TextEdit.insert(Position.create(0, 0), `WILL DELETE:\n${deletedFilenames}`),
]
}],
}
})
connection.onTypeDefinition((params) => {
assert.equal(params.position.line, 1)
assert.equal(params.position.character, 1)
return {uri: params.textDocument.uri, range: {start: {line: 2, character: 2}, end: {line: 3, character: 3}}}
})
connection.languages.callHierarchy.onPrepare((params) => {
return [
{
kind: SymbolKind.Function,
name: 'name',
range: Range.create(1, 1, 1, 1),
selectionRange: Range.create(2, 2, 2, 2),
uri: params.textDocument.uri
}
]
})
connection.languages.callHierarchy.onIncomingCalls((params) => {
return [
{
from: params.item,
fromRanges: [Range.create(1, 1, 1, 1)]
}
]
})
connection.languages.callHierarchy.onOutgoingCalls((params) => {
return [
{
to: params.item,
fromRanges: [Range.create(1, 1, 1, 1)]
}
]
})
connection.languages.semanticTokens.onRange(() => {
return {
resultId: '1',
data: []
}
})
connection.languages.semanticTokens.on(() => {
return {
resultId: '2',
data: []
}
})
connection.languages.semanticTokens.onDelta(() => {
return {
resultId: '3',
data: []
}
})
connection.languages.onLinkedEditingRange(() => {
return {
ranges: [Range.create(1, 1, 1, 1)],
wordPattern: '\\w'
}
})
connection.onRequest(
new ProtocolRequestType('testing/sendSampleProgress'),
async (_, __) => {
const progressToken = 'TEST-PROGRESS-TOKEN'
await connection.sendRequest(WorkDoneProgressCreateRequest.type, {token: progressToken})
connection.sendProgress(WorkDoneProgress.type, progressToken, {kind: 'begin', title: 'Test Progress'})
connection.sendProgress(WorkDoneProgress.type, progressToken, {kind: 'report', percentage: 50, message: 'Halfway!'})
connection.sendProgress(WorkDoneProgress.type, progressToken, {kind: 'end', message: 'Completed!'})
},
)
// Listen on the connection
connection.listen()

5
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/coc-settings.json

@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
{
"suggest.timeout": 5000,
"suggest.triggerCompletionWait": 10,
"tslint.enable": false
}

446
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/completion/basic.test.ts

@ -1,446 +0,0 @@ @@ -1,446 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { ISource, SourceType, CompleteResult, CompleteOption } from '../../types'
import helper from '../helper'
import sources from '../../sources'
import { CancellationToken } from 'vscode-jsonrpc'
let nvim: Neovim
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
})
describe('completion', () => {
it('should not show word of word source on empty input', async () => {
await nvim.setLine('foo bar')
await helper.wait(200)
await nvim.input('of')
let res = await helper.visible('foo', 'around')
expect(res).toBe(true)
await nvim.input('<backspace>')
await helper.wait(200)
res = await helper.notVisible('foo')
expect(res).toBe(true)
})
it('should trigger on first letter insert', async () => {
await helper.edit()
await nvim.setLine('foo bar')
await helper.wait(30)
await nvim.input('of')
let res = await helper.visible('foo', 'around')
expect(res).toBe(true)
})
it('should trigger on force refresh', async () => {
await helper.edit()
await nvim.setLine('foo f')
await helper.wait(100)
await nvim.input('A')
await helper.wait(10)
await nvim.call('coc#start')
let res = await helper.visible('foo', 'around')
expect(res).toBe(true)
})
it('should filter and sort on increment search', async () => {
await helper.edit()
await nvim.setLine('forceDocumentSync format fallback')
await helper.wait(30)
await nvim.input('of')
await helper.waitPopup()
let items = await helper.getItems()
let l = items.length
await nvim.input('oa')
await helper.wait(100)
items = await helper.getItems()
expect(items.findIndex(o => o.word == 'fallback')).toBe(-1)
expect(items.length).toBeLessThan(l)
})
it('should filter on character remove by backspace', async () => {
await helper.edit()
await nvim.setLine('forceDocumentSync format fallback')
await helper.wait(30)
await nvim.input('ofa')
await helper.waitPopup()
let items = await helper.getItems()
let words = items.map(o => o.word)
expect(words).toContain('fallback')
expect(words).toContain('format')
await nvim.input('<backspace>')
await helper.wait(100)
items = await helper.getItems()
words = items.map(o => o.word)
expect(words).toEqual([])
})
it('should not trigger on insert enter', async () => {
await helper.edit()
await nvim.setLine('foo bar')
await helper.wait(30)
await nvim.input('o')
let visible = await nvim.call('pumvisible')
expect(visible).toBe(0)
})
it('should filter on fast input', async () => {
await helper.edit()
await nvim.setLine('foo bar')
await helper.wait(60)
await nvim.input('oba')
await helper.waitPopup()
let items = await helper.getItems()
let item = items.find(o => o.word == 'foo')
expect(item).toBeFalsy()
expect(items[0].word).toBe('bar')
})
it('should fix start column', async () => {
await helper.edit()
let source: ISource = {
name: 'test',
priority: 10,
enable: true,
firstMatch: false,
sourceType: SourceType.Native,
triggerCharacters: [],
doComplete: async (): Promise<CompleteResult> => {
let result: CompleteResult = {
startcol: 0,
items: [{ word: 'foo.bar' }]
}
return Promise.resolve(result)
}
}
let disposable = sources.addSource(source)
await nvim.setLine('foo.')
await nvim.input('Ab')
await helper.waitPopup()
let val = await nvim.getVar('coc#_context') as any
expect(val.start).toBe(0)
disposable.dispose()
})
it('should stop completion when type none trigger character', async () => {
await helper.edit()
let source: ISource = {
name: 'test',
priority: 10,
enable: true,
firstMatch: false,
sourceType: SourceType.Native,
triggerCharacters: [],
doComplete: async (): Promise<CompleteResult> => {
let result: CompleteResult = {
items: [{ word: 'if(' }]
}
return Promise.resolve(result)
}
}
let disposable = sources.addSource(source)
await nvim.setLine('')
await nvim.input('iif')
await helper.waitPopup()
await nvim.input('(')
await helper.wait(300)
let res = await helper.pumvisible()
expect(res).toBe(true)
disposable.dispose()
})
it('should trigger on triggerCharacters', async () => {
await helper.edit()
let source: ISource = {
name: 'trigger',
priority: 10,
enable: true,
sourceType: SourceType.Native,
triggerCharacters: ['.'],
doComplete: async (): Promise<CompleteResult> => Promise.resolve({
items: [{ word: 'foo' }]
})
}
sources.addSource(source)
await nvim.input('i')
await helper.wait(30)
await nvim.input('.')
await helper.waitPopup()
sources.removeSource(source)
let res = await helper.visible('foo', 'trigger')
expect(res).toBe(true)
})
it('should should complete items without input', async () => {
await helper.edit()
let source: ISource = {
enable: true,
name: 'trigger',
priority: 10,
sourceType: SourceType.Native,
doComplete: async (): Promise<CompleteResult> => Promise.resolve({
items: [{ word: 'foo' }, { word: 'bar' }]
})
}
let disposable = sources.addSource(source)
await nvim.command('inoremap <silent><expr> <c-space> coc#refresh()')
await nvim.input('i')
await helper.wait(30)
await nvim.input('<c-space>')
await helper.waitPopup()
let items = await helper.getItems()
expect(items.length).toBeGreaterThan(1)
disposable.dispose()
await helper.wait(300)
})
it('should show float window', async () => {
await helper.edit()
let source: ISource = {
name: 'float',
priority: 10,
enable: true,
sourceType: SourceType.Native,
doComplete: (): Promise<CompleteResult> => Promise.resolve({
items: [{ word: 'foo', info: 'bar' }]
})
}
sources.addSource(source)
await nvim.input('i')
await helper.wait(30)
await nvim.input('f')
await helper.waitPopup()
await nvim.eval('feedkeys("\\<down>","in")')
await helper.wait(800)
let hasFloat = await nvim.call('coc#float#has_float')
expect(hasFloat).toBe(1)
sources.removeSource(source)
let res = await helper.visible('foo', 'float')
expect(res).toBe(true)
})
it('should trigger on triggerPatterns', async () => {
await helper.edit()
let source: ISource = {
name: 'pattern',
priority: 10,
enable: true,
sourceType: SourceType.Native,
triggerPatterns: [/\w+\.$/],
doComplete: async (): Promise<CompleteResult> => Promise.resolve({
items: [{ word: 'foo' }]
})
}
sources.addSource(source)
await nvim.input('i')
await helper.wait(10)
await nvim.input('.')
await helper.wait(30)
let pumvisible = await nvim.call('pumvisible')
expect(pumvisible).toBe(0)
await nvim.input('a')
await helper.wait(30)
await nvim.input('.')
await helper.waitPopup()
sources.removeSource(source)
let res = await helper.visible('foo', 'pattern')
expect(res).toBe(true)
})
it('should not trigger triggerOnly source', async () => {
await helper.edit()
await nvim.setLine('foo bar')
let source: ISource = {
name: 'pattern',
triggerOnly: true,
priority: 10,
enable: true,
sourceType: SourceType.Native,
triggerPatterns: [/^From:\s*/],
doComplete: async (): Promise<CompleteResult> => Promise.resolve({
items: [{ word: 'foo' }]
})
}
let disposable = sources.addSource(source)
await nvim.input('o')
await helper.wait(10)
await nvim.input('f')
await helper.wait(10)
let res = await helper.visible('foo', 'around')
expect(res).toBe(true)
let items = await helper.items()
expect(items.length).toBe(1)
disposable.dispose()
})
it('should not trigger when cursor moved', async () => {
await helper.edit()
let source: ISource = {
name: 'trigger',
priority: 10,
enable: true,
sourceType: SourceType.Native,
triggerCharacters: ['.'],
doComplete: async (): Promise<CompleteResult> => Promise.resolve({
items: [{ word: 'foo' }]
})
}
sources.addSource(source)
await nvim.setLine('.a')
await nvim.input('A')
await nvim.eval('feedkeys("\\<bs>")')
await helper.wait(10)
await nvim.eval('feedkeys("\\<left>")')
await helper.wait(200)
let visible = await nvim.call('pumvisible')
expect(visible).toBe(0)
sources.removeSource(source)
})
it('should trigger when completion is not completed', async () => {
await helper.edit()
let token: CancellationToken
let source: ISource = {
name: 'completion',
priority: 10,
enable: true,
sourceType: SourceType.Native,
triggerCharacters: ['.'],
doComplete: async (opt, cancellationToken): Promise<CompleteResult> => {
if (opt.triggerCharacter != '.') {
token = cancellationToken
return new Promise<CompleteResult>((resolve, reject) => {
let timer = setTimeout(() => {
resolve({ items: [{ word: 'foo' }] })
}, 200)
if (cancellationToken.isCancellationRequested) {
clearTimeout(timer)
reject(new Error('Cancelled'))
}
})
}
return Promise.resolve({
items: [{ word: 'bar' }]
})
}
}
let disposable = sources.addSource(source)
await nvim.input('if')
await helper.wait(100)
await nvim.input('.')
await helper.visible('bar', 'completion')
expect(token.isCancellationRequested).toBe(true)
disposable.dispose()
})
it('should limit results for low priority source', async () => {
helper.updateConfiguration('suggest.lowPrioritySourceLimit', 2)
await nvim.setLine('filename filepath find filter findIndex')
await helper.wait(200)
await nvim.input('of')
await helper.waitPopup()
let items = await helper.getItems()
items = items.filter(o => o.menu == '[A]')
expect(items.length).toBe(2)
})
it('should limit result for high priority source', async () => {
helper.updateConfiguration('suggest.highPrioritySourceLimit', 2)
await helper.edit()
let source: ISource = {
name: 'high',
priority: 90,
enable: true,
sourceType: SourceType.Native,
triggerCharacters: ['.'],
doComplete: async (): Promise<CompleteResult> => Promise.resolve({
items: ['filename', 'filepath', 'filter', 'file'].map(key => ({ word: key }))
})
}
let disposable = sources.addSource(source)
await nvim.input('i')
await helper.wait(30)
await nvim.input('.')
await helper.waitPopup()
let items = await helper.getItems()
expect(items.length).toBeGreaterThan(1)
disposable.dispose()
})
it('should truncate label of complete items', async () => {
helper.updateConfiguration('suggest.labelMaxLength', 10)
await helper.edit()
let source: ISource = {
name: 'high',
priority: 90,
enable: true,
sourceType: SourceType.Native,
triggerCharacters: ['.'],
doComplete: async (): Promise<CompleteResult> => Promise.resolve({
items: ['a', 'b', 'c', 'd'].map(key => ({ word: key.repeat(20) }))
})
}
let disposable = sources.addSource(source)
await nvim.input('i')
await helper.wait(30)
await nvim.input('.')
await helper.waitPopup()
let items = await helper.getItems()
for (let item of items) {
expect(item.abbr.length).toBeLessThanOrEqual(10)
}
disposable.dispose()
})
it('should delete previous items if complete item is null', async () => {
await helper.edit()
let source1: ISource = {
name: 'source1',
priority: 90,
enable: true,
sourceType: SourceType.Native,
triggerCharacters: ['.'],
doComplete: async (): Promise<CompleteResult> => Promise.resolve({
items: [ {word: 'foo', dup: 1} ]
})
}
let source2: ISource = {
name: 'source2',
priority: 90,
enable: true,
sourceType: SourceType.Native,
triggerCharacters: ['.'],
doComplete: async (opt: CompleteOption): Promise<CompleteResult> => {
let result: CompleteResult = opt.input == 'foo' ? null : {
items: [{ word: 'foo', dup: 1 }], isIncomplete: true
}
return Promise.resolve(result)
}
}
let disposable1 = sources.addSource(source1)
let disposable2 = sources.addSource(source2)
await nvim.input('i')
await helper.wait(30)
await nvim.input('.f')
await helper.waitPopup()
let items = await helper.getItems()
expect(items.length).toEqual(2)
await nvim.input('oo')
await helper.waitPopup()
items = await helper.getItems()
expect(items.length).toEqual(1)
expect(items[0].word).toBe('foo')
disposable1.dispose()
disposable2.dispose()
})
})

122
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/completion/float.test.ts

@ -1,122 +0,0 @@ @@ -1,122 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import sources from '../../sources'
import { CompleteResult, ISource, SourceType } from '../../types'
import helper from '../helper'
let nvim: Neovim
let source: ISource
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
source = {
name: 'float',
priority: 10,
enable: true,
sourceType: SourceType.Native,
doComplete: (): Promise<CompleteResult> => Promise.resolve({
items: [{
word: 'foo',
info: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
}, {
word: 'foot',
info: 'foot'
}, {
word: 'football',
}]
})
}
sources.addSource(source)
})
afterAll(async () => {
sources.removeSource(source)
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
})
describe('completion float', () => {
it('should not show float window when disabled', async () => {
helper.updateConfiguration('suggest.floatEnable', false)
await helper.edit()
await nvim.input('if')
await helper.visible('foo', 'float')
helper.updateConfiguration('suggest.floatEnable', true)
let hasFloat = await nvim.call('coc#float#has_float')
expect(hasFloat).toBe(0)
})
it('should cancel float window', async () => {
await helper.edit()
await nvim.input('if')
await helper.visible('foo', 'float')
let items = await helper.getItems()
expect(items[0].word).toBe('foo')
expect(items[0].info.length > 0).toBeTruthy()
await nvim.input('<C-n>')
await helper.wait(500)
await nvim.input('<esc>')
await helper.wait(100)
let hasFloat = await nvim.call('coc#float#has_float')
expect(hasFloat).toBe(0)
})
it('should adjust float window position', async () => {
await helper.edit()
await nvim.setLine(' '.repeat(70))
await nvim.input('Af')
await helper.visible('foo', 'float')
await nvim.input('<C-n>')
await helper.wait(300)
let floatWin = await helper.getFloat()
let config = await floatWin.getConfig()
expect(config.col + config.width).toBeLessThan(180)
})
it('should redraw float window on item change', async () => {
await helper.edit()
await nvim.setLine(' '.repeat(70))
await nvim.input('Af')
await helper.visible('foo', 'float')
await nvim.input('<C-n>')
await helper.wait(50)
await nvim.input('<C-n>')
await helper.wait(300)
let floatWin = await helper.getFloat()
let buf = await floatWin.buffer
let lines = await buf.lines
expect(lines.length).toBeGreaterThan(0)
expect(lines[0]).toMatch('foot')
})
it('should hide float window when item info is empty', async () => {
await helper.edit()
await nvim.setLine(' '.repeat(70))
await nvim.input('Af')
await helper.visible('foo', 'float')
await nvim.input('<C-n>')
await helper.wait(10)
await nvim.input('<C-n>')
await helper.wait(10)
await nvim.input('<C-n>')
await helper.wait(100)
let hasFloat = await nvim.call('coc#float#has_float')
expect(hasFloat).toBe(0)
})
it('should hide float window after completion', async () => {
await helper.edit()
await nvim.setLine(' '.repeat(70))
await nvim.input('Af')
await helper.visible('foo', 'float')
await nvim.input('<C-n>')
await helper.wait(100)
await nvim.input('<C-y>')
await helper.wait(30)
let hasFloat = await nvim.call('coc#float#has_float')
expect(hasFloat).toBe(0)
})
})

66
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/completion/match.test.ts

@ -1,66 +0,0 @@ @@ -1,66 +0,0 @@
import { matchScore } from '../../completion/match'
import { getCharCodes } from '../../util/fuzzy'
function score(word: string, input: string): number {
return matchScore(word, getCharCodes(input))
}
describe('matchScore', () => {
it('should match score for last letter', () => {
expect(score('#!3', '3')).toBe(1)
})
it('should match first letter', () => {
expect(score('abc', 'a')).toBe(5)
expect(score('Abc', 'a')).toBe(2.5)
expect(score('__abc', 'a')).toBe(2.5)
expect(score('$Abc', 'a')).toBe(2)
expect(score('$Abc', 'A')).toBe(2.5)
expect(score('$Abc', '$A')).toBe(6)
expect(score('$Abc', '$a')).toBe(5.5)
expect(score('foo_bar', 'b')).toBe(2.5)
expect(score('foo_Bar', 'b')).toBe(2)
expect(score('_foo_Bar', 'b')).toBe(0.5)
expect(score('_foo_Bar', 'f')).toBe(2.5)
expect(score('bar', 'a')).toBe(1)
expect(score('fooBar', 'B')).toBe(2.5)
expect(score('fooBar', 'b')).toBe(2)
})
it('should match follow letters', () => {
expect(score('abc', 'ab')).toBe(6)
expect(score('adB', 'ab')).toBe(5.75)
expect(score('adb', 'ab')).toBe(5.1)
expect(score('adCB', 'ab')).toBe(5.05)
expect(score('a_b_c', 'ab')).toBe(6)
expect(score('FooBar', 'fb')).toBe(3.25)
expect(score('FBar', 'fb')).toBe(3)
expect(score('FooBar', 'FB')).toBe(6)
expect(score('FBar', 'FB')).toBe(6)
expect(score('a__b', 'a__b')).toBe(8)
expect(score('aBc', 'ab')).toBe(5.5)
expect(score('a_B_c', 'ab')).toBe(5.75)
expect(score('abc', 'abc')).toBe(7)
expect(score('abc', 'aC')).toBe(0)
expect(score('abc', 'ac')).toBe(5.1)
expect(score('abC', 'ac')).toBe(5.75)
expect(score('abC', 'aC')).toBe(6)
})
it('should only allow search once', () => {
expect(score('foobar', 'fbr')).toBe(0)
expect(score('foobaRow', 'fbr')).toBe(5.85)
expect(score('foobaRow', 'fbR')).toBe(6.1)
expect(score('foobar', 'fa')).toBe(5.1)
})
it('should have higher score for strict match', () => {
expect(score('language-client-protocol', 'lct')).toBe(6.1)
expect(score('language-client-types', 'lct')).toBe(7)
})
it('should find highest score', () => {
expect(score('ArrayRotateTail', 'art')).toBe(4)
})
})

92
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/completion/sources.test.ts

@ -1,92 +0,0 @@ @@ -1,92 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import helper from '../helper'
import { ISource, SourceType, CompleteResult } from '../../types'
import sources from '../../sources'
let nvim: Neovim
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
})
describe('native sources', () => {
it('should works for around source', async () => {
await helper.createDocument()
await nvim.setLine('foo ')
await helper.wait(100)
let { mode } = await nvim.mode
expect(mode).toBe('n')
await nvim.input('Af')
let res = await helper.visible('foo', 'around')
expect(res).toBe(true)
await nvim.input('<esc>')
})
it('should works for buffer source', async () => {
await nvim.command('set hidden')
await helper.createDocument()
await helper.createDocument()
await nvim.setLine('other')
await nvim.command('bp')
await helper.wait(300)
let { mode } = await nvim.mode
expect(mode).toBe('n')
await nvim.input('io')
let res = await helper.visible('other', 'buffer')
expect(res).toBe(true)
})
it('should works for file source', async () => {
await helper.edit()
await nvim.input('i/')
await helper.waitPopup()
let items = await helper.getItems()
expect(items.length).toBeGreaterThan(0)
let res = await helper.visible(items[0].word, 'file')
expect(res).toBe(true)
await nvim.input('<esc>')
await nvim.input('o./')
await helper.waitPopup()
items = await helper.getItems()
let item = items.find(o => o.word == 'vimrc')
expect(item).toBeTruthy()
})
it('should works for file source with other source use same triggerCharacter', async () => {
await helper.edit()
let source: ISource = {
name: 'test',
priority: 50,
enable: true,
firstMatch: false,
sourceType: SourceType.Native,
triggerCharacters: ['.', '/'],
doComplete: async (): Promise<CompleteResult> => {
let result: CompleteResult = {
items: [{ word: 'foo' }]
}
return Promise.resolve(result)
}
}
let disposable = sources.addSource(source)
await nvim.input('i.')
await helper.waitPopup()
let items = await helper.getItems()
expect(items.length).toBe(1)
await nvim.input('/')
await helper.waitPopup()
items = await helper.getItems()
expect(items.length).toBeGreaterThan(1)
expect(items[0].word).toBe('foo')
disposable.dispose()
})
})

32
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/completion/util.test.ts

@ -1,32 +0,0 @@ @@ -1,32 +0,0 @@
import { CompletionItemKind, TextEdit, Position } from 'vscode-languageserver-types'
import { getStartColumn, getKindString } from '../../sources/source-language'
describe('getKindString()', () => {
it('should get kind text', async () => {
let map = new Map()
map.set(CompletionItemKind.Enum, 'E')
let res = getKindString(CompletionItemKind.Enum, map, '')
expect(res).toBe('E')
})
it('should get default value', async () => {
let map = new Map()
let res = getKindString(CompletionItemKind.Enum, map, 'D')
expect(res).toBe('D')
})
})
describe('getStartColumn()', () => {
it('should get start col', async () => {
expect(getStartColumn('', [{ label: 'foo' }])).toBe(null)
expect(getStartColumn('', [
{ label: 'foo', textEdit: TextEdit.insert(Position.create(0, 0), 'a') },
{ label: 'bar' }])).toBe(null)
expect(getStartColumn('foo', [
{ label: 'foo', textEdit: TextEdit.insert(Position.create(0, 0), 'a') },
{ label: 'bar', textEdit: TextEdit.insert(Position.create(0, 1), 'b') }])).toBe(null)
expect(getStartColumn('foo', [
{ label: 'foo', textEdit: TextEdit.insert(Position.create(0, 2), 'a') },
{ label: 'bar', textEdit: TextEdit.insert(Position.create(0, 2), 'b') }])).toBe(2)
})
})

7
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/global/index.js

@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
exports.activate = async context => {
return {
getContext: () => {
return context
}
}
}

7
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/global/package.json

@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
{
"name": "global",
"version": "1.0.0",
"engines": {
"coc": "^0.0.46"
}
}

6
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/package.json

@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
{
"dependencies": {
"global": ">=1.0.0",
"test": ">=1.0.0"
}
}

7
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/root.js

@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
exports.activate = context => {
return {
root: () => {
return context.extensionPath
}
}
}

13
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/test/index.js

@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
exports.activate = async context => {
return {
asAbsolutePath: p => {
return context.asAbsolutePath(p)
},
getContext: () => {
return context
},
echo: x => {
return x
}
}
}

33
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/test/package.json

@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
{
"name": "test",
"version": "1.0.0",
"engines": {
"coc": "^0.0.46"
},
"contributes": {
"rootPatterns": [
{
"filetype": "javascript",
"patterns": [
"package.json",
"jsconfig.json"
]
}
],
"commands": [
{
"title": "Test",
"command": "test.run"
}
],
"configuration": {
"properties": {
"test.enable": {
"type": "boolean",
"default": true,
"description": "Enable test"
}
}
}
}
}

7
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/vim/local/index.js

@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
exports.activate = async context => {
return {
getContext: () => {
return context
}
}
}

7
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/extensions/vim/local/package.json

@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
{
"name": "local",
"version": "1.0.0",
"engines": {
"coc": "^0.0.46"
}
}

398
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/callHierarchy.test.ts

@ -1,398 +0,0 @@ @@ -1,398 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, CallHierarchyItem, SymbolKind, Range, SymbolTag } from 'vscode-languageserver-protocol'
import CallHierarchyHandler from '../../handler/callHierarchy'
import languages from '../../languages'
import workspace from '../../workspace'
import { disposeAll } from '../../util'
import { URI } from 'vscode-uri'
import helper, { createTmpFile } from '../helper'
let nvim: Neovim
let callHierarchy: CallHierarchyHandler
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
callHierarchy = helper.plugin.getHandler().callHierarchy
})
afterAll(async () => {
await helper.shutdown()
})
beforeEach(async () => {
await helper.createDocument()
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
function createCallItem(name: string, kind: SymbolKind, uri: string, range: Range): CallHierarchyItem {
return {
name,
kind,
uri,
range,
selectionRange: range
}
}
describe('CallHierarchy', () => {
it('should throw for when provider not exists', async () => {
let err
try {
await callHierarchy.getIncoming()
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
it('should get undefined when prepare failed', async () => {
disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], {
prepareCallHierarchy() {
return undefined
},
provideCallHierarchyIncomingCalls() {
return []
},
provideCallHierarchyOutgoingCalls() {
return []
}
}))
let res = await callHierarchy.getOutgoing()
expect(res).toBeUndefined()
})
it('should get incoming & outgoing callHierarchy items', async () => {
disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], {
prepareCallHierarchy() {
return createCallItem('foo', SymbolKind.Class, 'test:///foo', Range.create(0, 0, 0, 5))
},
provideCallHierarchyIncomingCalls() {
return [{
from: createCallItem('bar', SymbolKind.Class, 'test:///bar', Range.create(1, 0, 1, 5)),
fromRanges: [Range.create(0, 0, 0, 5)]
}]
},
provideCallHierarchyOutgoingCalls() {
return [{
to: createCallItem('bar', SymbolKind.Class, 'test:///bar', Range.create(1, 0, 1, 5)),
fromRanges: [Range.create(1, 0, 1, 5)]
}]
}
}))
let res = await callHierarchy.getIncoming()
expect(res.length).toBe(1)
expect(res[0].from.name).toBe('bar')
let outgoing = await callHierarchy.getOutgoing()
expect(outgoing.length).toBe(1)
res = await callHierarchy.getIncoming(outgoing[0].to)
expect(res.length).toBe(1)
})
it('should show message when provider not exists', async () => {
await callHierarchy.showCallHierarchyTree('incoming')
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines[0]).toMatch('callHierarchy provider not found')
await nvim.command('wincmd p')
})
it('should no results when no result returned.', async () => {
disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], {
prepareCallHierarchy() {
return []
},
provideCallHierarchyIncomingCalls() {
return []
},
provideCallHierarchyOutgoingCalls() {
return []
}
}))
await callHierarchy.showCallHierarchyTree('incoming')
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines[0]).toBe('No results')
await nvim.command('wincmd p')
})
it('should render description and support default action', async () => {
let doc = await workspace.document
let bufnr = doc.bufnr
await doc.buffer.setLines(['foo'], { start: 0, end: -1, strictIndexing: false })
let fsPath = await createTmpFile('foo\nbar\ncontent\n')
let uri = URI.file(fsPath).toString()
disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], {
prepareCallHierarchy() {
return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3))
},
provideCallHierarchyIncomingCalls() {
let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(1, 0, 1, 3))
item.detail = 'Detail'
item.tags = [SymbolTag.Deprecated]
return [{
from: item,
fromRanges: [Range.create(2, 0, 2, 5)]
}]
},
provideCallHierarchyOutgoingCalls() {
return []
}
}))
await callHierarchy.showCallHierarchyTree('incoming')
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines).toEqual([
'INCOMING CALLS',
'- c foo',
' + c bar Detail'
])
await nvim.command('exe 3')
await nvim.input('t')
await helper.wait(50)
let line = await nvim.line
expect(line).toEqual(' - c bar Detail')
await nvim.input('<cr>')
await helper.wait(50)
doc = await workspace.document
expect(doc.uri).toBe(uri)
let res = await nvim.call('coc#cursor#position')
expect(res).toEqual([1, 0])
let matches = await nvim.call('getmatches') as any[]
expect(matches.length).toBe(2)
await nvim.command(`b ${bufnr}`)
await helper.wait(50)
matches = await nvim.call('getmatches')
expect(matches.length).toBe(0)
await nvim.command(`wincmd o`)
await helper.wait(50)
})
it('should invoke open in new tab action', async () => {
let doc = await workspace.document
await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false })
let fsPath = await createTmpFile('foo\nbar\ncontent\n')
let uri = URI.file(fsPath).toString()
disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], {
prepareCallHierarchy() {
return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3))
},
provideCallHierarchyIncomingCalls() {
return []
},
provideCallHierarchyOutgoingCalls() {
let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(0, 0, 0, 1))
item.detail = 'Detail'
return [{
to: item,
fromRanges: [Range.create(1, 0, 1, 3)]
}]
}
}))
let win = await nvim.window
let tab = await nvim.call('tabpagenr')
await callHierarchy.showCallHierarchyTree('outgoing')
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines).toEqual([
'OUTGOING CALLS',
'- c foo',
' + c bar Detail'
])
await nvim.command('exe 3')
await nvim.input('<tab>')
await helper.wait(50)
await nvim.input('<cr>')
await helper.wait(200)
let newTab = await nvim.call('tabpagenr')
expect(newTab != tab).toBe(true)
doc = await workspace.document
expect(doc.uri).toBe(uri)
let res = await nvim.call('getmatches', [win.id])
expect(res.length).toBe(1)
})
it('should invoke show incoming calls action', async () => {
let doc = await workspace.document
await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false })
let fsPath = await createTmpFile('foo\nbar\ncontent\n')
let uri = URI.file(fsPath).toString()
disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], {
prepareCallHierarchy() {
return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3))
},
provideCallHierarchyIncomingCalls() {
return [{
from: createCallItem('test', SymbolKind.Class, 'test:///bar', Range.create(1, 0, 1, 5)),
fromRanges: [Range.create(0, 0, 0, 5)]
}]
},
provideCallHierarchyOutgoingCalls() {
let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(0, 0, 0, 1))
item.detail = 'Detail'
return [{
to: item,
fromRanges: [Range.create(1, 0, 1, 3)]
}]
}
}))
await callHierarchy.showCallHierarchyTree('outgoing')
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines).toEqual([
'OUTGOING CALLS',
'- c foo',
' + c bar Detail'
])
await nvim.command('exe 3')
await nvim.input('<tab>')
await helper.wait(50)
await nvim.input('2')
await helper.wait(200)
lines = await buf.lines
expect(lines).toEqual([
'INCOMING CALLS',
'- c bar Detail',
' + c test'
])
await nvim.command('bd!')
})
it('should invoke show outgoing calls action', async () => {
let doc = await workspace.document
await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false })
let fsPath = await createTmpFile('foo\nbar\ncontent\n')
let uri = URI.file(fsPath).toString()
disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], {
prepareCallHierarchy() {
return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3))
},
provideCallHierarchyIncomingCalls() {
return [{
from: createCallItem('test', SymbolKind.Class, 'test:///bar', Range.create(1, 0, 1, 5)),
fromRanges: [Range.create(0, 0, 0, 5)]
}]
},
provideCallHierarchyOutgoingCalls() {
let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(0, 0, 0, 1))
item.detail = 'Detail'
return [{
to: item,
fromRanges: [Range.create(1, 0, 1, 3)]
}]
}
}))
await callHierarchy.showCallHierarchyTree('incoming')
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines).toEqual([
'INCOMING CALLS',
'- c foo',
' + c test'
])
await nvim.command('exe 3')
await nvim.input('<tab>')
await helper.wait(50)
await nvim.input('3')
await helper.wait(200)
lines = await buf.lines
expect(lines).toEqual([
'OUTGOING CALLS',
'- c test',
' + c bar Detail'
])
await nvim.command('bd!')
})
it('should invoke dismiss action #1', async () => {
let doc = await workspace.document
await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false })
let fsPath = await createTmpFile('foo\nbar\ncontent\n')
let uri = URI.file(fsPath).toString()
disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], {
prepareCallHierarchy() {
return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3))
},
provideCallHierarchyIncomingCalls() {
return []
},
provideCallHierarchyOutgoingCalls() {
let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(0, 0, 0, 1))
item.detail = 'Detail'
return [{
to: item,
fromRanges: [Range.create(1, 0, 1, 3)]
}]
}
}))
await callHierarchy.showCallHierarchyTree('outgoing')
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines).toEqual([
'OUTGOING CALLS',
'- c foo',
' + c bar Detail'
])
await nvim.command('exe 3')
await nvim.input('<tab>')
await helper.wait(50)
await nvim.input('4')
await helper.wait(200)
lines = await buf.lines
expect(lines).toEqual([
'OUTGOING CALLS',
'- c foo'
])
await nvim.command('wincmd c')
})
it('should invoke dismiss action #2', async () => {
let doc = await workspace.document
await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false })
let fsPath = await createTmpFile('foo\nbar\ncontent\n')
let uri = URI.file(fsPath).toString()
disposables.push(languages.registerCallHierarchyProvider([{ language: '*' }], {
prepareCallHierarchy() {
return createCallItem('foo', SymbolKind.Class, doc.uri, Range.create(0, 0, 0, 3))
},
provideCallHierarchyIncomingCalls() {
return []
},
provideCallHierarchyOutgoingCalls() {
let item = createCallItem('bar', SymbolKind.Class, uri, Range.create(0, 0, 0, 1))
item.detail = 'Detail'
return [{
to: item,
fromRanges: [Range.create(1, 0, 1, 3)]
}]
}
}))
await callHierarchy.showCallHierarchyTree('outgoing')
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines).toEqual([
'OUTGOING CALLS',
'- c foo',
' + c bar Detail'
])
await nvim.command('exe 3')
await nvim.input('t')
await helper.wait(50)
await nvim.command('exe 4')
await nvim.input('<tab>')
await helper.wait(50)
await nvim.input('4')
await helper.wait(200)
lines = await buf.lines
expect(lines).toEqual([
'OUTGOING CALLS',
'- c foo',
' - c bar Detail'
])
await nvim.command('wincmd c')
})
})

386
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/codeActions.test.ts

@ -1,386 +0,0 @@ @@ -1,386 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { CancellationToken, CodeAction, Command, CodeActionContext, CodeActionKind, TextEdit, Disposable, Range, Position } from 'vscode-languageserver-protocol'
import { TextDocument } from 'vscode-languageserver-textdocument'
import commands from '../../commands'
import ActionsHandler from '../../handler/codeActions'
import languages from '../../languages'
import { ProviderResult } from '../../provider'
import { disposeAll } from '../../util'
import { rangeInRange } from '../../util/position'
import helper from '../helper'
let nvim: Neovim
let disposables: Disposable[] = []
let codeActions: ActionsHandler
let currActions: CodeAction[]
let resolvedAction: CodeAction
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
codeActions = helper.plugin.getHandler().codeActions
})
afterAll(async () => {
await helper.shutdown()
})
beforeEach(async () => {
disposables.push(languages.registerCodeActionProvider([{ language: '*' }], {
provideCodeActions: (
_document: TextDocument,
_range: Range,
_context: CodeActionContext,
_token: CancellationToken
) => currActions,
resolveCodeAction: (
_action: CodeAction,
_token: CancellationToken
): ProviderResult<CodeAction> => resolvedAction
}, undefined))
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
describe('handler codeActions', () => {
describe('organizeImport', () => {
it('should throw error when organize import action not found', async () => {
currActions = []
await helper.createDocument()
let err
try {
await codeActions.organizeImport()
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
it('should perform organize import action', async () => {
let doc = await helper.createDocument()
await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false })
let edits: TextEdit[] = []
edits.push(TextEdit.replace(Range.create(0, 0, 0, 3), 'bar'))
edits.push(TextEdit.replace(Range.create(1, 0, 1, 3), 'foo'))
let edit = { changes: { [doc.uri]: edits } }
let action = CodeAction.create('organize import', edit, CodeActionKind.SourceOrganizeImports)
currActions = [action, CodeAction.create('another action')]
await codeActions.organizeImport()
let lines = await doc.buffer.lines
expect(lines).toEqual(['bar', 'foo'])
})
it('should register editor.action.organizeImport command', async () => {
let doc = await helper.createDocument()
await doc.buffer.setLines(['foo', 'bar'], { start: 0, end: -1, strictIndexing: false })
let edits: TextEdit[] = []
edits.push(TextEdit.replace(Range.create(0, 0, 0, 3), 'bar'))
edits.push(TextEdit.replace(Range.create(1, 0, 1, 3), 'foo'))
let edit = { changes: { [doc.uri]: edits } }
let action = CodeAction.create('organize import', edit, CodeActionKind.SourceOrganizeImports)
currActions = [action, CodeAction.create('another action')]
await commands.executeCommand('editor.action.organizeImport')
let lines = await doc.buffer.lines
expect(lines).toEqual(['bar', 'foo'])
})
})
describe('codeActionRange', () => {
it('should show warning when no action available', async () => {
await helper.createDocument()
currActions = []
await codeActions.codeActionRange(1, 2, CodeActionKind.QuickFix)
let line = await helper.getCmdline()
expect(line).toMatch(/No quickfix code action/)
})
it('should apply choosen action', async () => {
let doc = await helper.createDocument()
let edits: TextEdit[] = []
edits.push(TextEdit.insert(Position.create(0, 0), 'bar'))
let edit = { changes: { [doc.uri]: edits } }
let action = CodeAction.create('code fix', edit, CodeActionKind.QuickFix)
currActions = [action]
let p = codeActions.codeActionRange(1, 2, CodeActionKind.QuickFix)
await helper.wait(50)
await nvim.input('<CR>')
await p
let buf = nvim.createBuffer(doc.bufnr)
let lines = await buf.lines
expect(lines[0]).toBe('bar')
})
})
describe('getCodeActions', () => {
it('should get empty actions', async () => {
currActions = []
let doc = await helper.createDocument()
let res = await codeActions.getCodeActions(doc)
expect(res.length).toBe(0)
})
it('should filter disabled actions', async () => {
currActions = []
let action = CodeAction.create('foo', CodeActionKind.QuickFix)
action.disabled = { reason: 'disabled' }
currActions.push(action)
action = CodeAction.create('foo', CodeActionKind.QuickFix)
action.disabled = { reason: 'disabled' }
currActions.push(action)
let doc = await helper.createDocument()
let res = await codeActions.getCodeActions(doc)
expect(res.length).toBe(0)
})
it('should get all actions', async () => {
let doc = await helper.createDocument()
await doc.buffer.setLines(['', '', ''], { start: 0, end: -1, strictIndexing: false })
let action = CodeAction.create('curr action', CodeActionKind.Empty)
currActions = [action]
let range: Range
disposables.push(languages.registerCodeActionProvider([{ language: '*' }], {
provideCodeActions: (
_document: TextDocument,
r: Range,
_context: CodeActionContext, _token: CancellationToken
) => {
range = r
return [CodeAction.create('a'), CodeAction.create('b'), CodeAction.create('c')]
},
}, undefined))
let res = await codeActions.getCodeActions(doc)
expect(range).toEqual(Range.create(0, 0, 3, 0))
expect(res.length).toBe(4)
})
it('should filter actions by range', async () => {
let doc = await helper.createDocument()
await doc.buffer.setLines(['', '', ''], { start: 0, end: -1, strictIndexing: false })
currActions = []
let range: Range
disposables.push(languages.registerCodeActionProvider([{ language: '*' }], {
provideCodeActions: (
_document: TextDocument,
r: Range,
_context: CodeActionContext, _token: CancellationToken
) => {
range = r
if (rangeInRange(r, Range.create(0, 0, 1, 0))) return [CodeAction.create('a')]
return [CodeAction.create('a'), CodeAction.create('b'), CodeAction.create('c')]
},
}, undefined))
let res = await codeActions.getCodeActions(doc, Range.create(0, 0, 0, 0))
expect(range).toEqual(Range.create(0, 0, 0, 0))
expect(res.length).toBe(1)
})
it('should filter actions by kind prefix', async () => {
let doc = await helper.createDocument()
let action = CodeAction.create('my action', CodeActionKind.SourceFixAll)
currActions = [action]
let res = await codeActions.getCodeActions(doc, undefined, [CodeActionKind.Source])
expect(res.length).toBe(1)
expect(res[0].kind).toBe(CodeActionKind.SourceFixAll)
})
})
describe('getCurrentCodeActions', () => {
let range: Range
beforeEach(() => {
disposables.push(languages.registerCodeActionProvider([{ language: '*' }], {
provideCodeActions: (
_document: TextDocument,
r: Range,
_context: CodeActionContext, _token: CancellationToken
) => {
range = r
return [CodeAction.create('a'), CodeAction.create('b'), CodeAction.create('c')]
},
}, undefined))
})
it('should get codeActions by line', async () => {
currActions = []
await helper.createDocument()
let res = await codeActions.getCurrentCodeActions('line')
expect(range).toEqual(Range.create(0, 0, 1, 0))
expect(res.length).toBe(3)
})
it('should get codeActions by cursor', async () => {
currActions = []
await helper.createDocument()
let res = await codeActions.getCurrentCodeActions('cursor')
expect(range).toEqual(Range.create(0, 0, 0, 0))
expect(res.length).toBe(3)
})
it('should get codeActions by visual mode', async () => {
currActions = []
await helper.createDocument()
await nvim.setLine('foo')
await nvim.command('normal! 0v$')
await nvim.input('<esc>')
let res = await codeActions.getCurrentCodeActions('v')
expect(range).toEqual(Range.create(0, 0, 0, 4))
expect(res.length).toBe(3)
})
})
describe('doCodeAction', () => {
it('should not throw when no action exists', async () => {
currActions = []
await helper.createDocument()
let err
try {
await codeActions.doCodeAction(undefined)
} catch (e) {
err = e
}
expect(err).toBeUndefined()
})
it('should apply single code action when only is title', async () => {
let doc = await helper.createDocument()
let edits: TextEdit[] = []
edits.push(TextEdit.insert(Position.create(0, 0), 'bar'))
let edit = { changes: { [doc.uri]: edits } }
let action = CodeAction.create('code fix', edit, CodeActionKind.QuickFix)
currActions = [action]
await codeActions.doCodeAction(undefined, 'code fix')
let lines = await doc.buffer.lines
expect(lines).toEqual(['bar'])
})
it('should apply single code action when only is codeAction array', async () => {
let doc = await helper.createDocument()
let edits: TextEdit[] = []
edits.push(TextEdit.insert(Position.create(0, 0), 'bar'))
let edit = { changes: { [doc.uri]: edits } }
let action = CodeAction.create('code fix', edit, CodeActionKind.QuickFix)
currActions = [action]
await codeActions.doCodeAction(undefined, [CodeActionKind.QuickFix])
let lines = await doc.buffer.lines
expect(lines).toEqual(['bar'])
})
it('should action dialog to choose action', async () => {
let doc = await helper.createDocument()
let edits: TextEdit[] = []
edits.push(TextEdit.insert(Position.create(0, 0), 'bar'))
let edit = { changes: { [doc.uri]: edits } }
let action = CodeAction.create('code fix', edit, CodeActionKind.QuickFix)
currActions = [action, CodeAction.create('foo')]
let promise = codeActions.doCodeAction(null)
await helper.wait(50)
let ids = await nvim.call('coc#float#get_float_win_list') as number[]
expect(ids.length).toBeGreaterThan(0)
await nvim.input('<CR>')
await promise
let lines = await doc.buffer.lines
expect(lines).toEqual(['bar'])
})
it('should choose code actions by range', async () => {
let range: Range
disposables.push(languages.registerCodeActionProvider([{ language: '*' }], {
provideCodeActions: (
_document: TextDocument,
r: Range,
_context: CodeActionContext, _token: CancellationToken
) => {
range = r
return [CodeAction.create('my title'), CodeAction.create('b'), CodeAction.create('c')]
},
}, undefined))
await helper.createDocument()
await nvim.setLine('abc')
await nvim.command('normal! 0v$')
await nvim.input('<esc>')
await codeActions.doCodeAction('v', 'my title')
expect(range).toEqual({ start: { line: 0, character: 0 }, end: { line: 0, character: 4 } })
})
})
describe('doQuickfix', () => {
it('should throw when quickfix action not exists', async () => {
let err
currActions = []
await helper.createDocument()
try {
await codeActions.doQuickfix()
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
it('should do preferred quickfix action', async () => {
let doc = await helper.createDocument()
let edits: TextEdit[] = []
edits.push(TextEdit.insert(Position.create(0, 0), 'bar'))
let edit = { changes: { [doc.uri]: edits } }
let action = CodeAction.create('code fix', edit, CodeActionKind.QuickFix)
action.isPreferred = true
currActions = [CodeAction.create('foo', CodeActionKind.QuickFix), action, CodeAction.create('bar')]
await codeActions.doQuickfix()
let lines = await doc.buffer.lines
expect(lines).toEqual(['bar'])
})
})
describe('applyCodeAction', () => {
it('should resolve codeAction', async () => {
let doc = await helper.createDocument()
let edits: TextEdit[] = []
edits.push(TextEdit.insert(Position.create(0, 0), 'bar'))
let edit = { changes: { [doc.uri]: edits } }
let action = CodeAction.create('code fix', CodeActionKind.QuickFix)
action.isPreferred = true
currActions = [action]
resolvedAction = Object.assign({ edit }, action)
let arr = await codeActions.getCurrentCodeActions('line', [CodeActionKind.QuickFix])
await codeActions.applyCodeAction(arr[0])
let lines = await doc.buffer.lines
expect(lines).toEqual(['bar'])
})
it('should throw for disabled action', async () => {
let action = CodeAction.create('my action', CodeActionKind.Empty)
action.disabled = { reason: 'disabled' }
let err
try {
await codeActions.applyCodeAction(action)
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
it('should invoke registered command after apply edit', async () => {
let called
disposables.push(commands.registerCommand('test.execute', async (s: string) => {
called = s
await nvim.command(s)
}))
let doc = await helper.createDocument()
let edits: TextEdit[] = []
edits.push(TextEdit.insert(Position.create(0, 0), 'bar'))
let edit = { changes: { [doc.uri]: edits } }
let action = CodeAction.create('code fix', CodeActionKind.QuickFix)
action.isPreferred = true
currActions = [action]
resolvedAction = Object.assign({
edit,
command: Command.create('run vim command', 'test.execute', 'normal! $')
}, action)
let arr = await codeActions.getCurrentCodeActions('line', [CodeActionKind.QuickFix])
await codeActions.applyCodeAction(arr[0])
let lines = await doc.buffer.lines
expect(lines).toEqual(['bar'])
expect(called).toBe('normal! $')
})
})
})

269
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/codelens.test.ts

@ -1,269 +0,0 @@ @@ -1,269 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, Range, Command, TextEdit, Position } from 'vscode-languageserver-protocol'
import { disposeAll } from '../../util'
import languages from '../../languages'
import commands from '../../commands'
import CodeLens from '../../handler/codelens/index'
import helper, { createTmpFile } from '../helper'
import events from '../../events'
let nvim: Neovim
let codeLens: CodeLens
let disposables: Disposable[] = []
let srcId: number
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
srcId = await nvim.createNamespace('coc-codelens')
codeLens = helper.plugin.getHandler().codeLens
helper.updateConfiguration('codeLens.enable', true)
})
afterAll(async () => {
helper.updateConfiguration('codeLens.enable', false)
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
disposeAll(disposables)
disposables = []
})
describe('codeLenes featrue', () => {
it('should do codeLenes request and resolve codeLenes', async () => {
disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], {
provideCodeLenses: () => {
return [{
range: Range.create(0, 0, 0, 1)
}, {
range: Range.create(1, 0, 1, 1)
}]
},
resolveCodeLens: codeLens => {
codeLens.command = Command.create('save', '__save')
return codeLens
}
}))
let doc = await helper.createDocument('example.js')
await nvim.call('setline', [1, ['a', 'b', 'c']])
await codeLens.checkProvider()
let buf = codeLens.buffers.getItem(doc.bufnr)
let codelens = buf.getCodelenses()
expect(codelens).toBeDefined()
expect(codelens[0].command).toBeDefined()
expect(codelens[1].command).toBeDefined()
let markers = await helper.getMarkers(doc.bufnr, srcId)
expect(markers.length).toBe(2)
})
it('should refresh codeLens on CursorHold', async () => {
disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], {
provideCodeLenses: document => {
let n = document.lineCount
let arr: any[] = []
for (let i = 0; i <= n - 2; i++) {
arr.push({
range: Range.create(i, 0, i, 1),
command: Command.create('save', '__save', i)
})
}
return arr
}
}))
let doc = await helper.createDocument('example.js')
await helper.wait(100)
let markers = await helper.getMarkers(doc.bufnr, srcId)
await nvim.call('setline', [1, ['a', 'b', 'c']])
await doc.synchronize()
await events.fire('CursorHold', [doc.bufnr])
await helper.wait(200)
markers = await helper.getMarkers(doc.bufnr, srcId)
expect(markers.length).toBe(3)
})
it('should cancel codeLenes request on document change', async () => {
let cancelled = false
disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], {
provideCodeLenses: (_, token) => {
return new Promise(resolve => {
token.onCancellationRequested(() => {
cancelled = true
clearTimeout(timer)
resolve(null)
})
let timer = setTimeout(() => {
resolve([{
range: Range.create(0, 0, 0, 1)
}, {
range: Range.create(1, 0, 1, 1)
}])
}, 2000)
})
},
resolveCodeLens: codeLens => {
codeLens.command = Command.create('save', '__save')
return codeLens
}
}))
let doc = await helper.createDocument('codelens.js')
await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'a\nb\nc')])
let p = codeLens.checkProvider()
await doc.applyEdits([TextEdit.replace(Range.create(0, 0, 0, 1), 'foo')])
await p
expect(cancelled).toBe(true)
let buf = codeLens.buffers.getItem(doc.bufnr)
let codelens = buf.getCodelenses()
expect(codelens).toBeUndefined()
})
it('should resolve on CursorMoved', async () => {
disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], {
provideCodeLenses: () => {
return [{
range: Range.create(90, 0, 90, 1)
}, {
range: Range.create(91, 0, 91, 1)
}]
},
resolveCodeLens: async codeLens => {
await helper.wait(50)
codeLens.command = Command.create('save', '__save')
return codeLens
}
}))
let doc = await helper.createDocument('example.js')
let arr = new Array(100)
arr.fill('')
await nvim.call('setline', [1, arr])
await doc.synchronize()
await codeLens.checkProvider()
await nvim.command('normal! gg')
await helper.wait(300)
await nvim.command('normal! G')
await helper.wait(300)
let buf = codeLens.buffers.getItem(doc.bufnr)
let codelens = buf.getCodelenses()
expect(codelens).toBeDefined()
expect(codelens[0].command).toBeDefined()
expect(codelens[1].command).toBeDefined()
})
it('should invoke codeLenes action', async () => {
let fn = jest.fn()
disposables.push(commands.registerCommand('__save', (...args) => {
fn(...args)
}))
disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], {
provideCodeLenses: () => {
return [{
range: Range.create(0, 0, 0, 1)
}]
},
resolveCodeLens: codeLens => {
codeLens.command = Command.create('save', '__save', 1, 2, 3)
return codeLens
}
}))
await helper.createDocument('example.js')
await nvim.call('setline', [1, ['a', 'b', 'c']])
await codeLens.checkProvider()
await helper.doAction('codeLensAction')
expect(fn).toBeCalledWith(1, 2, 3)
})
it('should use picker fo multiple codeLenses', async () => {
let fn = jest.fn()
disposables.push(commands.registerCommand('__save', (...args) => {
fn(...args)
}))
disposables.push(commands.registerCommand('__delete', (...args) => {
fn(...args)
}))
disposables.push(languages.registerCodeLensProvider([{ language: 'javascript' }], {
provideCodeLenses: () => {
return [{
range: Range.create(0, 0, 0, 1),
command: Command.create('save', '__save', 1, 2, 3)
}, {
range: Range.create(0, 1, 0, 2),
command: Command.create('save', '__delete', 4, 5, 6)
}]
}
}))
let doc = await helper.createDocument('example.js')
await nvim.call('setline', [1, ['a', 'b', 'c']])
await doc.synchronize()
await codeLens.checkProvider()
let p = helper.doAction('codeLensAction')
await helper.wait(30)
await nvim.input('<cr>')
await p
expect(fn).toBeCalledWith(1, 2, 3)
})
it('should refresh for failed codeLens request', async () => {
let called = 0
let fn = jest.fn()
disposables.push(commands.registerCommand('__save', (...args) => {
fn(...args)
}))
disposables.push(commands.registerCommand('__foo', (...args) => {
fn(...args)
}))
disposables.push(languages.registerCodeLensProvider([{ language: '*' }], {
provideCodeLenses: () => {
called++
if (called == 1) {
return null
}
return [{
range: Range.create(0, 0, 0, 1),
command: Command.create('foo', '__foo')
}]
}
}))
disposables.push(languages.registerCodeLensProvider([{ language: '*' }], {
provideCodeLenses: () => {
return [{
range: Range.create(0, 0, 0, 1),
command: Command.create('save', '__save')
}]
}
}))
let doc = await helper.createDocument('example.js')
await nvim.call('setline', [1, ['a', 'b', 'c']])
await codeLens.checkProvider()
let markers = await helper.getMarkers(doc.buffer.id, srcId)
expect(markers.length).toBeGreaterThan(0)
let codeLensBuffer = codeLens.buffers.getItem(doc.buffer.id)
await codeLensBuffer.forceFetch()
let curr = codeLensBuffer.currentCodeLens()
expect(curr.length).toBeGreaterThan(1)
expect(called).toBe(2)
})
it('should refresh on configuration change', async () => {
disposables.push(languages.registerCodeLensProvider([{ language: '*' }], {
provideCodeLenses: () => {
return [{
range: Range.create(0, 0, 0, 1),
command: Command.create('save', '__save')
}]
}
}))
let filepath = await createTmpFile('abc')
let buffer = await helper.edit(filepath)
await codeLens.checkProvider()
helper.updateConfiguration('codeLens.enable', false)
await helper.wait(10)
let markers = await helper.getMarkers(buffer.id, srcId)
expect(markers.length).toBe(0)
helper.updateConfiguration('codeLens.enable', true)
await helper.wait(300)
markers = await helper.getMarkers(buffer.id, srcId)
expect(markers.length).toBeGreaterThan(0)
})
})

254
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/colors.test.ts

@ -1,254 +0,0 @@ @@ -1,254 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { CancellationToken, Color, ColorInformation, ColorPresentation, Disposable, Position, Range } from 'vscode-languageserver-protocol'
import { TextDocument } from 'vscode-languageserver-textdocument'
import commands from '../../commands'
import { toHexString } from '../../util/color'
import Colors from '../../handler/colors/index'
import languages from '../../languages'
import { ProviderResult } from '../../provider'
import { disposeAll } from '../../util'
import helper from '../helper'
let nvim: Neovim
let state = 'normal'
let colors: Colors
let disposables: Disposable[] = []
let colorPresentations: ColorPresentation[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
colors = helper.plugin.getHandler().colors
disposables.push(languages.registerDocumentColorProvider([{ language: '*' }], {
provideColorPresentations: (
_color: Color,
_context: { document: TextDocument; range: Range },
_token: CancellationToken
): ColorPresentation[] => colorPresentations,
provideDocumentColors: (
document: TextDocument,
_token: CancellationToken
): ProviderResult<ColorInformation[]> => {
if (state == 'empty') return []
if (state == 'error') return Promise.reject(new Error('no color'))
let matches = Array.from((document.getText() as any).matchAll(/#\w{6}/g)) as any
return matches.map(o => {
let start = document.positionAt(o.index)
let end = document.positionAt(o.index + o[0].length)
return {
range: Range.create(start, end),
color: getColor(255, 255, 255)
}
})
}
}))
})
afterAll(async () => {
disposeAll(disposables)
await helper.shutdown()
})
afterEach(async () => {
colorPresentations = []
await helper.reset()
})
function getColor(r: number, g: number, b: number): Color {
return { red: r / 255, green: g / 255, blue: b / 255, alpha: 1 }
}
describe('Colors', () => {
describe('utils', () => {
it('should get hex string', () => {
let color = getColor(255, 255, 255)
let hex = toHexString(color)
expect(hex).toBe('ffffff')
})
})
describe('configuration', () => {
it('should toggle enable state on configuration change', async () => {
await helper.createDocument()
helper.updateConfiguration('coc.preferences.colorSupport', false)
expect(colors.enabled).toBe(false)
helper.updateConfiguration('coc.preferences.colorSupport', true)
expect(colors.enabled).toBe(true)
})
})
describe('commands', () => {
it('should register editor.action.pickColor command', async () => {
await helper.mockFunction('coc#util#pick_color', [0, 0, 0])
let doc = await helper.createDocument()
await nvim.setLine('#ffffff')
doc.forceSync()
await colors.doHighlight(doc.bufnr)
await commands.executeCommand('editor.action.pickColor')
let line = await nvim.getLine()
expect(line).toBe('#000000')
})
it('should register editor.action.colorPresentation command', async () => {
colorPresentations = [ColorPresentation.create('red'), ColorPresentation.create('#ff0000')]
let doc = await helper.createDocument()
await nvim.setLine('#ffffff')
doc.forceSync()
await colors.doHighlight(doc.bufnr)
let p = commands.executeCommand('editor.action.colorPresentation')
await helper.wait(100)
await nvim.input('1<enter>')
await p
let line = await nvim.getLine()
expect(line).toBe('red')
})
})
describe('doHighlight', () => {
it('should clearHighlight on empty result', async () => {
let doc = await helper.createDocument()
await nvim.setLine('#ffffff')
state = 'empty'
await colors.doHighlight(doc.bufnr)
let res = colors.hasColor(doc.bufnr)
expect(res).toBe(false)
state = 'normal'
})
it('should not highlight on error result', async () => {
let doc = await helper.createDocument()
await nvim.setLine('#ffffff')
state = 'error'
await colors.doHighlight(doc.bufnr)
let res = colors.hasColor(doc.bufnr)
expect(res).toBe(false)
state = 'normal'
})
it('should highlight after document changed', async () => {
let doc = await helper.createDocument()
doc.forceSync()
await colors.doHighlight(doc.bufnr)
expect(colors.hasColor(doc.bufnr)).toBe(false)
expect(colors.hasColorAtPosition(doc.bufnr, Position.create(0, 1))).toBe(false)
await nvim.setLine('#ffffff #ff0000')
doc.forceSync()
await helper.wait(300)
expect(colors.hasColorAtPosition(doc.bufnr, Position.create(0, 1))).toBe(true)
expect(colors.hasColor(doc.bufnr)).toBe(true)
})
it('should clearHighlight on clearHighlight', async () => {
let doc = await helper.createDocument()
await nvim.setLine('#ffffff #ff0000')
doc.forceSync()
await colors.doHighlight(doc.bufnr)
expect(colors.hasColor(doc.bufnr)).toBe(true)
colors.clearHighlight(doc.bufnr)
expect(colors.hasColor(doc.bufnr)).toBe(false)
})
it('should highlight colors', async () => {
let doc = await helper.createDocument()
await nvim.setLine('#ffffff')
await colors.doHighlight(doc.bufnr)
let exists = await nvim.call('hlexists', 'BGffffff')
expect(exists).toBe(1)
})
})
describe('hasColor()', () => {
it('should return false when bufnr not exists', async () => {
let res = colors.hasColor(99)
colors.clearHighlight(99)
expect(res).toBe(false)
})
})
describe('getColorInformation()', () => {
it('should return null when highlighter not exists', async () => {
let res = await colors.getColorInformation(99)
expect(res).toBe(null)
})
it('should return null when color not found', async () => {
let doc = await helper.createDocument()
await nvim.setLine('#ffffff foo ')
doc.forceSync()
await colors.doHighlight(doc.bufnr)
await nvim.call('cursor', [1, 12])
let res = await colors.getColorInformation(doc.bufnr)
expect(res).toBe(null)
})
})
describe('hasColorAtPosition()', () => {
it('should return false when bufnr not exists', async () => {
let res = colors.hasColorAtPosition(99, Position.create(0, 0))
expect(res).toBe(false)
})
})
describe('pickPresentation()', () => {
it('should show warning when color not exists', async () => {
await helper.createDocument()
await colors.pickPresentation()
let msg = await helper.getCmdline()
expect(msg).toMatch('Color not found')
})
it('should not throw when presentations not exists', async () => {
colorPresentations = []
let doc = await helper.createDocument()
await nvim.setLine('#ffffff')
doc.forceSync()
await colors.doHighlight(99)
await colors.doHighlight(doc.bufnr)
await helper.doAction('colorPresentation')
})
it('should pick presentations', async () => {
colorPresentations = [ColorPresentation.create('red'), ColorPresentation.create('#ff0000')]
let doc = await helper.createDocument()
await nvim.setLine('#ffffff')
doc.forceSync()
await colors.doHighlight(doc.bufnr)
let p = helper.doAction('colorPresentation')
await helper.wait(100)
await nvim.input('1<enter>')
await p
let line = await nvim.getLine()
expect(line).toBe('red')
})
})
describe('pickColor()', () => {
it('should show warning when color not exists', async () => {
await helper.createDocument()
await colors.pickColor()
let msg = await helper.getCmdline()
expect(msg).toMatch('not found')
})
it('should pickColor', async () => {
await helper.mockFunction('coc#util#pick_color', [0, 0, 0])
let doc = await helper.createDocument()
await nvim.setLine('#ffffff')
doc.forceSync()
await colors.doHighlight(doc.bufnr)
await helper.doAction('pickColor')
let line = await nvim.getLine()
expect(line).toBe('#000000')
})
it('should not throw when pick color return 0', async () => {
await helper.mockFunction('coc#util#pick_color', 0)
let doc = await helper.createDocument()
await nvim.setLine('#ffffff')
doc.forceSync()
await colors.doHighlight(doc.bufnr)
await helper.doAction('pickColor')
let line = await nvim.getLine()
expect(line).toBe('#ffffff')
})
})
})

82
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/commands.test.ts

@ -1,82 +0,0 @@ @@ -1,82 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable } from 'vscode-languageserver-protocol'
import CommandsHandler from '../../handler/commands'
import commandManager from '../../commands'
import { disposeAll } from '../../util'
import helper from '../helper'
let nvim: Neovim
let commands: CommandsHandler
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
commands = (helper.plugin as any).handler.commands
})
afterAll(async () => {
await helper.shutdown()
})
beforeEach(async () => {
await helper.createDocument()
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
describe('Commands', () => {
describe('addVimCommand', () => {
it('should register global vim commands', async () => {
await commandManager.executeCommand('vim.config')
await helper.wait(50)
let bufname = await nvim.call('bufname', ['%'])
expect(bufname).toMatch('coc-settings.json')
let list = commands.getCommandList()
expect(list.includes('vim.config')).toBe(true)
})
it('should add vim command with title', async () => {
commands.addVimCommand({ id: 'list', cmd: 'CocList', title: 'list of coc.nvim' })
let res = commandManager.titles.get('vim.list')
expect(res).toBe('list of coc.nvim')
commandManager.unregister('vim.list')
})
})
describe('getCommands', () => {
it('should get command items', async () => {
let res = commands.getCommands()
let idx = res.findIndex(o => o.id == 'workspace.showOutput')
expect(idx != -1).toBe(true)
})
})
describe('repeat', () => {
it('should repeat command', async () => {
// let buf = await nvim.buffer
await nvim.call('setline', [1, ['a', 'b', 'c']])
await nvim.call('cursor', [1, 1])
commands.addVimCommand({ id: 'remove', cmd: 'normal! dd' })
await commands.runCommand('vim.remove')
await helper.wait(50)
let res = await nvim.call('getline', [1, '$'])
expect(res).toEqual(['b', 'c'])
await commands.repeat()
await helper.wait(50)
res = await nvim.call('getline', [1, '$'])
expect(res).toEqual(['c'])
})
})
describe('runCommand', () => {
it('should open command list without id', async () => {
await commands.runCommand()
await helper.wait(100)
let bufname = await nvim.call('bufname', ['%'])
expect(bufname).toBe('list:///commands')
})
})
})

71
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/fold.test.ts

@ -1,71 +0,0 @@ @@ -1,71 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, FoldingRange } from 'vscode-languageserver-protocol'
import FoldHandler from '../../handler/fold'
import languages from '../../languages'
import { disposeAll } from '../../util'
import helper from '../helper'
let nvim: Neovim
let folds: FoldHandler
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
folds = (helper.plugin as any).handler.fold
})
afterAll(async () => {
await helper.shutdown()
})
beforeEach(async () => {
await helper.createDocument()
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
describe('Folds', () => {
it('should return false when no fold ranges found', async () => {
disposables.push(languages.registerFoldingRangeProvider([{ language: '*' }], {
provideFoldingRanges(_doc) {
return []
}
}))
let res = await folds.fold()
expect(res).toBe(false)
})
it('should fold all fold ranges', async () => {
disposables.push(languages.registerFoldingRangeProvider([{ language: '*' }], {
provideFoldingRanges(_doc) {
return [FoldingRange.create(1, 3), FoldingRange.create(4, 6, 0, 0, 'comment')]
}
}))
await nvim.call('setline', [1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']])
let res = await folds.fold()
expect(res).toBe(true)
let closed = await nvim.call('foldclosed', [2])
expect(closed).toBe(2)
closed = await nvim.call('foldclosed', [5])
expect(closed).toBe(5)
})
it('should fold comment ranges', async () => {
disposables.push(languages.registerFoldingRangeProvider([{ language: '*' }], {
provideFoldingRanges(_doc) {
return [FoldingRange.create(1, 3), FoldingRange.create(4, 6, 0, 0, 'comment')]
}
}))
await nvim.call('setline', [1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']])
let res = await folds.fold('comment')
expect(res).toBe(true)
let closed = await nvim.call('foldclosed', [2])
expect(closed).toBe(-1)
closed = await nvim.call('foldclosed', [5])
expect(closed).toBe(5)
})
})

253
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/format.test.ts

@ -1,253 +0,0 @@ @@ -1,253 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, Position, Range, TextEdit } from 'vscode-languageserver-protocol'
import languages from '../../languages'
import { disposeAll } from '../../util'
import window from '../../window'
import workspace from '../../workspace'
import Format from '../../handler/format'
import helper, { createTmpFile } from '../helper'
let nvim: Neovim
let disposables: Disposable[] = []
let format: Format
beforeAll(async () => {
let { configurations } = workspace
configurations.updateUserConfig({ 'coc.preferences.formatOnType': true })
await helper.setup()
nvim = helper.nvim
format = helper.plugin.getHandler().format
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
helper.updateConfiguration('coc.preferences.formatOnSaveFiletypes', [])
await helper.reset()
disposeAll(disposables)
disposables = []
})
describe('format handler', () => {
describe('documentFormat', () => {
it('should throw when provider not found', async () => {
let doc = await helper.createDocument()
let err
try {
await format.documentFormat(doc)
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
it('should return false when get empty edits ', async () => {
disposables.push(languages.registerDocumentFormatProvider(['*'], {
provideDocumentFormattingEdits: () => {
return []
}
}))
let doc = await helper.createDocument()
let res = await format.documentFormat(doc)
expect(res).toBe(false)
})
})
describe('formatOnSave', () => {
it('should not throw when provider not found', async () => {
helper.updateConfiguration('coc.preferences.formatOnSaveFiletypes', ['javascript'])
let filepath = await createTmpFile('')
await helper.edit(filepath)
await nvim.command('setf javascript')
await nvim.setLine('foo')
await nvim.command('silent w')
await helper.wait(100)
})
it('should invoke format on save', async () => {
helper.updateConfiguration('coc.preferences.formatOnSaveFiletypes', ['text'])
disposables.push(languages.registerDocumentFormatProvider(['text'], {
provideDocumentFormattingEdits: document => {
let lines = document.getText().replace(/\n$/, '').split(/\n/)
let edits: TextEdit[] = []
for (let i = 0; i < lines.length; i++) {
let text = lines[i]
if (!text.startsWith(' ')) {
edits.push(TextEdit.insert(Position.create(i, 0), ' '))
}
}
return edits
}
}))
let filepath = await createTmpFile('a\nb\nc\n')
let buf = await helper.edit(filepath)
await nvim.command('setf text')
await nvim.command('w')
let lines = await buf.lines
expect(lines).toEqual([' a', ' b', ' c'])
})
it('should cancel when timeout', async () => {
helper.updateConfiguration('coc.preferences.formatOnSaveFiletypes', ['*'])
disposables.push(languages.registerDocumentFormatProvider(['*'], {
provideDocumentFormattingEdits: () => {
return new Promise(resolve => {
setTimeout(() => {
resolve(undefined)
}, 2000)
})
}
}))
let filepath = await createTmpFile('a\nb\nc\n')
await helper.edit(filepath)
let n = Date.now()
await nvim.command('w')
expect(Date.now() - n).toBeLessThan(1000)
})
})
describe('rangeFormat', () => {
it('should invoke range format', async () => {
disposables.push(languages.registerDocumentRangeFormatProvider(['text'], {
provideDocumentRangeFormattingEdits: (_document, range) => {
let lines: number[] = []
for (let i = range.start.line; i <= range.end.line; i++) {
lines.push(i)
}
return lines.map(i => {
return TextEdit.insert(Position.create(i, 0), ' ')
})
}
}))
let doc = await helper.createDocument()
await nvim.call('setline', [1, ['a', 'b', 'c']])
await nvim.command('setf text')
await nvim.command('normal! ggvG')
await nvim.input('<esc>')
await helper.doAction('formatSelected', 'v')
let buf = nvim.createBuffer(doc.bufnr)
let lines = await buf.lines
expect(lines).toEqual([' a', ' b', ' c'])
})
it('should format range by formatexpr option', async () => {
let range: Range
disposables.push(languages.registerDocumentRangeFormatProvider(['text'], {
provideDocumentRangeFormattingEdits: (_document, r) => {
range = r
return []
}
}))
await helper.createDocument()
await nvim.call('setline', [1, ['a', 'b', 'c']])
await nvim.command('setf text')
await nvim.command(`setl formatexpr=CocAction('formatSelected')`)
await nvim.command('normal! ggvGgq')
expect(range).toEqual({
start: { line: 0, character: 0 }, end: { line: 3, character: 0 }
})
})
})
describe('formatOnType', () => {
it('should invoke format', async () => {
disposables.push(languages.registerDocumentFormatProvider(['text'], {
provideDocumentFormattingEdits: () => {
return [TextEdit.insert(Position.create(0, 0), ' ')]
}
}))
await helper.createDocument()
await nvim.setLine('foo')
await nvim.command('setf text')
await helper.doAction('format')
let line = await nvim.line
expect(line).toEqual(' foo')
})
it('should does format on type', async () => {
disposables.push(languages.registerOnTypeFormattingEditProvider(['text'], {
provideOnTypeFormattingEdits: () => {
return [TextEdit.insert(Position.create(0, 0), ' ')]
}
}, ['|']))
await helper.edit()
await nvim.command('setf text')
await nvim.input('i|')
await helper.wait(200)
let line = await nvim.line
expect(line).toBe(' |')
let cursor = await window.getCursorPosition()
expect(cursor).toEqual({ line: 0, character: 3 })
})
it('should format on new line inserted', async () => {
disposables.push(languages.registerOnTypeFormattingEditProvider(['text'], {
provideOnTypeFormattingEdits: (doc, position) => {
let text = doc.getText()
if (text.startsWith(' ')) return []
return [TextEdit.insert(Position.create(position.line, 0), ' ')]
}
}, ['\n']))
let buf = await helper.edit()
await nvim.command('setf text')
await nvim.setLine('foo')
await nvim.input('o')
await helper.wait(100)
let lines = await buf.lines
expect(lines).toEqual([' foo', ''])
})
it('should adjust cursor after format on type', async () => {
disposables.push(languages.registerOnTypeFormattingEditProvider(['text'], {
provideOnTypeFormattingEdits: () => {
return [
TextEdit.insert(Position.create(0, 0), ' '),
TextEdit.insert(Position.create(0, 2), 'end')
]
}
}, ['|']))
await helper.edit()
await nvim.command('setf text')
await nvim.setLine('"')
await nvim.input('i|')
await helper.wait(100)
let line = await nvim.line
expect(line).toBe(' |"end')
let cursor = await window.getCursorPosition()
expect(cursor).toEqual({ line: 0, character: 3 })
})
})
describe('bracketEnterImprove', () => {
afterEach(() => {
nvim.command('iunmap <CR>', true)
})
it('should format vim file on enter', async () => {
let buf = await helper.edit('foo.vim')
await nvim.command(`inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm() : "\\<C-g>u\\<CR>\\<c-r>=coc#on_enter()\\<CR>"`)
await nvim.setLine('let foo={}')
await nvim.command(`normal! gg$`)
await nvim.input('i')
await nvim.eval(`feedkeys("\\<CR>", 'im')`)
await helper.wait(100)
let lines = await buf.lines
expect(lines).toEqual(['let foo={', ' \\ ', ' \\ }'])
})
it('should add new line between bracket', async () => {
let buf = await helper.edit()
await nvim.command(`inoremap <silent><expr> <cr> pumvisible() ? coc#_select_confirm() : "\\<C-g>u\\<CR>\\<c-r>=coc#on_enter()\\<CR>"`)
await nvim.setLine(' {}')
await nvim.command(`normal! gg$`)
await nvim.input('i')
await nvim.eval(`feedkeys("\\<CR>", 'im')`)
await helper.wait(100)
let lines = await buf.lines
expect(lines).toEqual([' {', ' ', ' }'])
})
})
})

138
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/highlights.test.ts

@ -1,138 +0,0 @@ @@ -1,138 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, DocumentHighlightKind, Position, Range } from 'vscode-languageserver-protocol'
import Highlights from '../../handler/highlights'
import languages from '../../languages'
import workspace from '../../workspace'
import { disposeAll } from '../../util'
import helper from '../helper'
let nvim: Neovim
let disposables: Disposable[] = []
let highlights: Highlights
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
highlights = helper.plugin.getHandler().documentHighlighter
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
disposeAll(disposables)
disposables = []
})
function registProvider(): void {
disposables.push(languages.registerDocumentHighlightProvider([{ language: '*' }], {
provideDocumentHighlights: async document => {
let word = await nvim.eval('expand("<cword>")')
// let word = document.get
let matches = Array.from((document.getText() as any).matchAll(/\w+/g)) as any[]
let filtered = matches.filter(o => o[0] == word)
return filtered.map((o, i) => {
let start = document.positionAt(o.index)
let end = document.positionAt(o.index + o[0].length)
return {
range: Range.create(start, end),
kind: i % 2 == 0 ? DocumentHighlightKind.Read : DocumentHighlightKind.Write
}
})
}
}))
}
describe('document highlights', () => {
it('should return null when highlights provide not exists', async () => {
let doc = await helper.createDocument()
let res = await highlights.getHighlights(doc, Position.create(0, 0))
expect(res).toBeNull()
})
it('should cancel request on CursorMoved', async () => {
let fn = jest.fn()
languages.registerDocumentHighlightProvider([{ language: '*' }], {
provideDocumentHighlights: (_document, _position, token) => {
return new Promise(resolve => {
token.onCancellationRequested(() => {
clearTimeout(timer)
fn()
resolve([])
})
let timer = setTimeout(() => {
resolve([{ range: Range.create(0, 0, 0, 3) }])
}, 3000)
})
}
})
await helper.edit()
await nvim.setLine('foo')
let p = highlights.highlight()
await helper.wait(50)
await nvim.call('cursor', [1, 2])
await p
expect(fn).toBeCalled()
})
it('should add highlights to symbols', async () => {
registProvider()
await helper.createDocument()
await nvim.setLine('foo bar foo')
await helper.doAction('highlight')
let winid = await nvim.call('win_getid') as number
expect(highlights.hasHighlights(winid)).toBe(true)
})
it('should return highlight ranges', async () => {
registProvider()
await helper.createDocument()
await nvim.setLine('foo bar foo')
let res = await helper.doAction('symbolRanges')
expect(res.length).toBe(2)
})
it('should return null when cursor not in word range', async () => {
disposables.push(languages.registerDocumentHighlightProvider([{ language: '*' }], {
provideDocumentHighlights: () => {
return [{ range: Range.create(0, 0, 0, 3) }]
}
}))
let doc = await helper.createDocument()
await nvim.setLine(' oo')
await nvim.call('cursor', [1, 2])
let res = await highlights.getHighlights(doc, Position.create(0, 0))
expect(res).toBeNull()
})
it('should not throw when document is command line', async () => {
await nvim.call('feedkeys', ['q:', 'in'])
let doc = await workspace.document
expect(doc.isCommandLine).toBe(true)
let err
try {
await highlights.highlight()
} catch (e) {
err = e
}
await nvim.input('<C-c>')
expect(err).toBeUndefined()
})
it('should not throw when provider not found', async () => {
disposeAll(disposables)
await helper.createDocument()
await nvim.setLine(' oo')
await nvim.call('cursor', [1, 2])
let err
try {
await highlights.highlight()
} catch (e) {
err = e
}
expect(err).toBeUndefined()
})
})

178
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/hover.test.ts

@ -1,178 +0,0 @@ @@ -1,178 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, MarkedString, Hover, Range, TextEdit, Position } from 'vscode-languageserver-protocol'
import HoverHandler from '../../handler/hover'
import { URI } from 'vscode-uri'
import languages from '../../languages'
import { disposeAll } from '../../util'
import helper, { createTmpFile } from '../helper'
let nvim: Neovim
let hover: HoverHandler
let disposables: Disposable[] = []
let hoverResult: Hover
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
hover = helper.plugin.getHandler().hover
})
afterAll(async () => {
await helper.shutdown()
})
beforeEach(async () => {
await helper.createDocument()
disposables.push(languages.registerHoverProvider([{ language: '*' }], {
provideHover: (_doc, _pos, _token) => {
return hoverResult
}
}))
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
async function getDocumentText(): Promise<string> {
let lines = await nvim.call('getbufline', ['coc://document', 1, '$']) as string[]
return lines.join('\n')
}
describe('Hover', () => {
describe('onHover', () => {
it('should return false when hover not found', async () => {
hoverResult = null
let res = await hover.onHover('preview')
expect(res).toBe(false)
})
it('should show MarkupContent hover', async () => {
hoverResult = { contents: { kind: 'plaintext', value: 'my hover' } }
await hover.onHover('preview')
let res = await getDocumentText()
expect(res).toMatch('my hover')
})
it('should show MarkedString hover', async () => {
hoverResult = { contents: 'string hover' }
disposables.push(languages.registerHoverProvider([{ language: '*' }], {
provideHover: (_doc, _pos, _token) => {
return { contents: { language: 'typescript', value: 'language hover' } }
}
}))
await hover.onHover('preview')
let res = await getDocumentText()
expect(res).toMatch('string hover')
expect(res).toMatch('language hover')
})
it('should show MarkedString hover array', async () => {
hoverResult = { contents: ['foo', { language: 'typescript', value: 'bar' }] }
await hover.onHover('preview')
let res = await getDocumentText()
expect(res).toMatch('foo')
expect(res).toMatch('bar')
})
it('should highlight hover range', async () => {
await nvim.setLine('var')
await nvim.command('normal! 0')
hoverResult = { contents: ['foo'], range: Range.create(0, 0, 0, 3) }
await hover.onHover('preview')
let res = await nvim.call('getmatches') as any[]
expect(res.length).toBe(1)
expect(res[0].group).toBe('CocHoverRange')
await helper.wait(600)
res = await nvim.call('getmatches')
expect(res.length).toBe(0)
})
})
describe('previewHover', () => {
it('should echo hover message', async () => {
hoverResult = { contents: ['foo'] }
let res = await hover.onHover('echo')
expect(res).toBe(true)
let msg = await helper.getCmdline()
expect(msg).toMatch('foo')
})
it('should show hover in float window', async () => {
hoverResult = { contents: { kind: 'markdown', value: '```typescript\nconst foo:number\n```' } }
await hover.onHover('float')
let win = await helper.getFloat()
expect(win).toBeDefined()
let lines = await nvim.eval(`getbufline(winbufnr(${win.id}),1,'$')`)
expect(lines).toEqual(['const foo:number'])
})
})
describe('getHover', () => {
it('should get hover from MarkedString array', async () => {
hoverResult = { contents: ['foo', { language: 'typescript', value: 'bar' }] }
disposables.push(languages.registerHoverProvider([{ language: '*' }], {
provideHover: (_doc, _pos, _token) => {
return { contents: { language: 'typescript', value: 'MarkupContent hover' } }
}
}))
disposables.push(languages.registerHoverProvider([{ language: '*' }], {
provideHover: (_doc, _pos, _token) => {
return { contents: MarkedString.fromPlainText('MarkedString hover') }
}
}))
let res = await hover.getHover()
expect(res.includes('foo')).toBe(true)
expect(res.includes('bar')).toBe(true)
expect(res.includes('MarkupContent hover')).toBe(true)
expect(res.includes('MarkedString hover')).toBe(true)
})
it('should filter empty hover message', async () => {
hoverResult = { contents: [''] }
let res = await hover.getHover()
expect(res.length).toBe(0)
})
})
describe('definitionHover', () => {
it('should load definition from buffer', async () => {
hoverResult = { contents: 'string hover' }
let doc = await helper.createDocument()
await nvim.call('cursor', [1, 1])
await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'foo\nbar')])
disposables.push(languages.registerDefinitionProvider([{ language: '*' }], {
provideDefinition() {
return [{
targetUri: doc.uri,
targetRange: Range.create(0, 0, 1, 3),
targetSelectionRange: Range.create(0, 0, 0, 3),
}]
}
}))
await hover.definitionHover('preview')
let res = await getDocumentText()
expect(res).toBe('string hover\n\nfoo\nbar')
})
it('should load definition link from file', async () => {
let fsPath = await createTmpFile('foo\nbar\n')
hoverResult = { contents: 'string hover' }
let doc = await helper.createDocument()
await nvim.call('cursor', [1, 1])
await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'foo\nbar')])
disposables.push(languages.registerDefinitionProvider([{ language: '*' }], {
provideDefinition() {
return [{
targetUri: URI.file(fsPath).toString(),
targetRange: Range.create(0, 0, 1, 3),
targetSelectionRange: Range.create(0, 0, 0, 3),
}]
}
}))
await hover.definitionHover('preview')
let res = await getDocumentText()
expect(res).toBe('string hover\n\nfoo\nbar')
})
})
})

93
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/index.test.ts

@ -1,93 +0,0 @@ @@ -1,93 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable } from 'vscode-languageserver-protocol'
import Handler from '../../handler/index'
import { disposeAll } from '../../util'
import helper from '../helper'
let nvim: Neovim
let handler: Handler
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
handler = (helper.plugin as any).handler
})
afterAll(async () => {
await helper.shutdown()
})
beforeEach(async () => {
await helper.createDocument()
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
describe('Handler', () => {
describe('hasProvider', () => {
it('should check provider for document', async () => {
let res = await handler.hasProvider('definition')
expect(res).toBe(false)
})
})
describe('checkProvier', () => {
it('should throw error when provider not found', async () => {
let doc = await helper.createDocument()
let err
try {
handler.checkProvier('definition', doc.textDocument)
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
})
describe('withRequestToken', () => {
it('should cancel previous request when called again', async () => {
let cancelled = false
let p = handler.withRequestToken('test', token => {
return new Promise(s => {
token.onCancellationRequested(() => {
cancelled = true
clearTimeout(timer)
s(undefined)
})
let timer = setTimeout(() => {
s(undefined)
}, 3000)
})
}, false)
setTimeout(async () => {
await handler.withRequestToken('test', () => {
return Promise.resolve(undefined)
}, false)
}, 50)
await p
expect(cancelled).toBe(true)
})
it('should cancel request on insert start', async () => {
let cancelled = false
let p = handler.withRequestToken('test', token => {
return new Promise(s => {
token.onCancellationRequested(() => {
cancelled = true
clearTimeout(timer)
s(undefined)
})
let timer = setTimeout(() => {
s(undefined)
}, 3000)
})
}, false)
await nvim.input('i')
await p
expect(cancelled).toBe(true)
})
})
})

99
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/links.test.ts

@ -1,99 +0,0 @@ @@ -1,99 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, DocumentLink, Range } from 'vscode-languageserver-protocol'
import LinksHandler from '../../handler/links'
import languages from '../../languages'
import { disposeAll } from '../../util'
import helper from '../helper'
let nvim: Neovim
let links: LinksHandler
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
links = (helper.plugin as any).handler.links
})
afterAll(async () => {
await helper.shutdown()
})
beforeEach(async () => {
await helper.createDocument()
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
describe('Links', () => {
it('should get document links', async () => {
disposables.push(languages.registerDocumentLinkProvider([{ language: '*' }], {
provideDocumentLinks: (_doc, _token) => {
return [
DocumentLink.create(Range.create(0, 0, 0, 5), 'test:///foo'),
DocumentLink.create(Range.create(1, 0, 1, 5), 'test:///bar')
]
}
}))
let res = await links.getLinks()
expect(res.length).toBe(2)
})
it('should throw error when link target not resolved', async () => {
disposables.push(languages.registerDocumentLinkProvider([{ language: '*' }], {
provideDocumentLinks(_doc, _token) {
return [
DocumentLink.create(Range.create(0, 0, 0, 5))
]
},
resolveDocumentLink(link) {
return link
}
}))
let res = await links.getLinks()
let err
try {
await links.openLink(res[0])
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
it('should open link at current position', async () => {
await nvim.setLine('foo')
await nvim.command('normal! 0')
disposables.push(languages.registerDocumentLinkProvider([{ language: '*' }], {
provideDocumentLinks(_doc, _token) {
return [
DocumentLink.create(Range.create(0, 0, 0, 5)),
]
},
resolveDocumentLink(link) {
link.target = 'test:///foo'
return link
}
}))
await links.openCurrentLink()
let bufname = await nvim.call('bufname', '%')
expect(bufname).toBe('test:///foo')
await nvim.call('setline', [1, ['a', 'b', 'c']])
await nvim.call('cursor', [3, 1])
let res = await links.openCurrentLink()
expect(res).toBe(false)
})
it('should return false when current links not found', async () => {
await nvim.setLine('foo')
await nvim.command('normal! 0')
disposables.push(languages.registerDocumentLinkProvider([{ language: '*' }], {
provideDocumentLinks(_doc, _token) {
return []
}
}))
let res = await links.openCurrentLink()
expect(res).toBe(false)
})
})

306
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/locations.test.ts

@ -1,306 +0,0 @@ @@ -1,306 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, LocationLink, Location, Range } from 'vscode-languageserver-protocol'
import LocationHandler from '../../handler/locations'
import languages from '../../languages'
import services from '../../services'
import workspace from '../../workspace'
import { disposeAll } from '../../util'
import helper from '../helper'
import { URI } from 'vscode-uri'
let nvim: Neovim
let locations: LocationHandler
let disposables: Disposable[] = []
let currLocations: Location[]
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
Object.assign(workspace.env, {
locationlist: false
})
locations = helper.plugin.getHandler().locations
})
afterAll(async () => {
await helper.shutdown()
})
beforeEach(async () => {
await helper.createDocument()
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
function createLocation(name: string, sl: number, sc: number, el: number, ec: number): Location {
return Location.create(`test://${name}`, Range.create(sl, sc, el, ec))
}
describe('locations', () => {
describe('reference', () => {
beforeEach(() => {
disposables.push(languages.registerReferencesProvider([{ language: '*' }], {
provideReferences: () => {
return currLocations
}
}))
})
it('should get references', async () => {
currLocations = [createLocation('foo', 0, 0, 0, 0), createLocation('bar', 0, 0, 0, 0)]
let res = await locations.references()
expect(res.length).toBe(2)
})
it('should jump to references', async () => {
currLocations = [createLocation('foo', 0, 0, 0, 0)]
let res = await locations.gotoReferences('edit', true)
expect(res).toBe(true)
let name = await nvim.call('bufname', ['%'])
expect(name).toBe('test://foo')
})
it('should return false when references not found', async () => {
currLocations = []
let res = await locations.gotoReferences('edit', true)
expect(res).toBe(false)
})
})
describe('definition', () => {
beforeEach(() => {
disposables.push(languages.registerDefinitionProvider([{ language: '*' }], {
provideDefinition: () => {
return currLocations
}
}))
})
it('should get definitions', async () => {
currLocations = [createLocation('foo', 0, 0, 0, 0), createLocation('bar', 0, 0, 0, 0)]
let res = await locations.definitions()
expect(res.length).toBe(2)
})
it('should jump to definitions', async () => {
currLocations = [createLocation('foo', 0, 0, 0, 0)]
let res = await locations.gotoDefinition('edit')
expect(res).toBe(true)
let name = await nvim.call('bufname', ['%'])
expect(name).toBe('test://foo')
})
it('should return false when definitions not found', async () => {
currLocations = []
let res = await locations.gotoDefinition('edit')
expect(res).toBe(false)
})
})
describe('declaration', () => {
beforeEach(() => {
disposables.push(languages.registerDeclarationProvider([{ language: '*' }], {
provideDeclaration: () => {
return currLocations
}
}))
})
it('should get declarations', async () => {
currLocations = [createLocation('foo', 0, 0, 0, 0), createLocation('bar', 0, 0, 0, 0)]
let res = await locations.declarations() as Location[]
expect(res.length).toBe(2)
})
it('should jump to declaration', async () => {
currLocations = [createLocation('foo', 0, 0, 0, 0)]
let res = await locations.gotoDeclaration('edit')
expect(res).toBe(true)
let name = await nvim.call('bufname', ['%'])
expect(name).toBe('test://foo')
})
it('should return false when declaration not found', async () => {
currLocations = []
let res = await locations.gotoDeclaration('edit')
expect(res).toBe(false)
})
})
describe('typeDefinition', () => {
beforeEach(() => {
disposables.push(languages.registerTypeDefinitionProvider([{ language: '*' }], {
provideTypeDefinition: () => {
return currLocations
}
}))
})
it('should get type definition', async () => {
currLocations = [createLocation('foo', 0, 0, 0, 0), createLocation('bar', 0, 0, 0, 0)]
let res = await locations.typeDefinitions() as Location[]
expect(res.length).toBe(2)
})
it('should jump to type definition', async () => {
currLocations = [createLocation('foo', 0, 0, 0, 0)]
let res = await locations.gotoTypeDefinition('edit')
expect(res).toBe(true)
let name = await nvim.call('bufname', ['%'])
expect(name).toBe('test://foo')
})
it('should return false when type definition not found', async () => {
currLocations = []
let res = await locations.gotoTypeDefinition('edit')
expect(res).toBe(false)
})
})
describe('implementation', () => {
beforeEach(() => {
disposables.push(languages.registerImplementationProvider([{ language: '*' }], {
provideImplementation: () => {
return currLocations
}
}))
})
it('should get implementations', async () => {
currLocations = [createLocation('foo', 0, 0, 0, 0), createLocation('bar', 0, 0, 0, 0)]
let res = await locations.implementations() as Location[]
expect(res.length).toBe(2)
})
it('should jump to implementation', async () => {
currLocations = [createLocation('foo', 0, 0, 0, 0)]
let res = await locations.gotoImplementation('edit')
expect(res).toBe(true)
let name = await nvim.call('bufname', ['%'])
expect(name).toBe('test://foo')
})
it('should return false when implementation not found', async () => {
currLocations = []
let res = await locations.gotoImplementation('edit')
expect(res).toBe(false)
})
})
describe('getTagList', () => {
it('should return null when cword not exists', async () => {
let res = await locations.getTagList()
expect(res).toBe(null)
})
it('should return null when provider not exists', async () => {
await nvim.setLine('foo')
await nvim.command('normal! ^')
let res = await locations.getTagList()
expect(res).toBe(null)
})
it('should return null when result is empty', async () => {
disposables.push(languages.registerDefinitionProvider([{ language: '*' }], {
provideDefinition: () => {
return []
}
}))
await nvim.setLine('foo')
await nvim.command('normal! ^')
let res = await locations.getTagList()
expect(res).toBe(null)
})
it('should return tag definitions', async () => {
disposables.push(languages.registerDefinitionProvider([{ language: '*' }], {
provideDefinition: () => {
return [createLocation('bar', 2, 0, 2, 5), Location.create(URI.file('/foo').toString(), Range.create(1, 0, 1, 5))]
}
}))
await nvim.setLine('foo')
await nvim.command('normal! ^')
let res = await locations.getTagList()
expect(res).toEqual([
{
name: 'foo',
cmd: 'keepjumps 3 | normal 1|',
filename: 'test://bar'
},
{ name: 'foo', cmd: 'keepjumps 2 | normal 1|', filename: '/foo' }
])
})
})
describe('findLocations', () => {
// hook result
let fn
let result: any
beforeAll(() => {
fn = services.sendRequest
services.sendRequest = () => {
return Promise.resolve(result)
}
})
afterAll(() => {
services.sendRequest = fn
})
it('should handle locations from language client', async () => {
result = [createLocation('bar', 2, 0, 2, 5)]
await locations.findLocations('foo', 'mylocation', {}, false)
let res = await nvim.getVar('coc_jump_locations')
expect(res).toEqual([{
uri: 'test://bar',
lnum: 3,
col: 1,
filename: 'test://bar',
text: '',
range: Range.create(2, 0, 2, 5)
}])
})
it('should handle nested locations', async () => {
let location: any = {
location: createLocation('file', 0, 0, 0, 0),
children: [{
location: createLocation('foo', 3, 0, 3, 5),
children: []
}, {
location: createLocation('bar', 4, 0, 4, 5),
children: []
}]
}
result = location
await locations.findLocations('foo', 'mylocation', {}, false)
let res = await nvim.getVar('coc_jump_locations') as any[]
expect(res.length).toBe(3)
})
})
describe('handleLocations', () => {
it('should not throw when location is undefined', async () => {
await locations.handleLocations(null)
})
it('should not throw when locations is empty array', async () => {
await locations.handleLocations([])
})
it('should handle single location', async () => {
await locations.handleLocations(createLocation('single', 0, 0, 0, 0))
let bufname = await nvim.call('bufname', ['%'])
expect(bufname).toBe('test://single')
})
it('should handle location link', async () => {
let link = LocationLink.create('test://link', Range.create(0, 0, 0, 3), Range.create(1, 0, 1, 3))
await locations.handleLocations([link])
let bufname = await nvim.call('bufname', ['%'])
expect(bufname).toBe('test://link')
})
})
})

426
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/outline.test.ts

@ -1,426 +0,0 @@ @@ -1,426 +0,0 @@
import { Buffer, Neovim } from '@chemzqm/neovim'
import { CancellationToken, CodeAction, CodeActionContext, CodeActionKind, Disposable, Range, SymbolTag, TextEdit } from 'vscode-languageserver-protocol'
import events from '../../events'
import Symbols from '../../handler/symbols/index'
import languages from '../../languages'
import { ProviderResult } from '../../provider'
import { disposeAll } from '../../util'
import workspace from '../../workspace'
import helper from '../helper'
import Parser from './parser'
let nvim: Neovim
let symbols: Symbols
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
symbols = helper.plugin.getHandler().symbols
})
beforeEach(() => {
disposables.push(languages.registerDocumentSymbolProvider([{ language: 'javascript' }], {
provideDocumentSymbols: document => {
let parser = new Parser(document.getText())
let res = parser.parse()
if (res.length) {
res[0].tags = [SymbolTag.Deprecated]
}
return Promise.resolve(res)
}
}))
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
disposeAll(disposables)
disposables = []
})
async function getOutlineBuffer(): Promise<Buffer | undefined> {
let winid = await nvim.call('coc#window#find', ['cocViewId', 'OUTLINE'])
if (winid == -1) return undefined
let bufnr = await nvim.call('winbufnr', [winid])
if (bufnr == -1) return undefined
return nvim.createBuffer(bufnr)
}
describe('symbols outline', () => {
let defaultCode = `class myClass {
fun1() { }
fun2() {}
}`
async function createBuffer(code = defaultCode): Promise<Buffer> {
await helper.edit()
let buf = await nvim.buffer
await nvim.command('setf javascript')
await buf.setLines(code.split('\n'), { start: 0, end: -1, strictIndexing: false })
let doc = await workspace.document
doc.forceSync()
return buf
}
describe('configuration', () => {
afterEach(() => {
let { configurations } = workspace
configurations.updateUserConfig({
'outline.splitCommand': 'botright 30vs',
'outline.followCursor': true,
'outline.keepWindow': false,
'outline.sortBy': 'category',
'outline.expandLevel': 1,
'outline.checkBufferSwitch': true
})
})
it('should follow cursor', async () => {
await createBuffer()
let curr = await nvim.call('bufnr', ['%'])
await symbols.showOutline(0)
let bufnr = await nvim.call('bufnr', ['%'])
await nvim.command('wincmd p')
await nvim.command('exe 3')
await events.fire('CursorHold', [curr])
await helper.wait(50)
let buf = nvim.createBuffer(bufnr)
let lines = await buf.getLines()
expect(lines).toEqual([
'OUTLINE', '- c myClass 1', ' m fun1 2', ' m fun2 3'
])
let signs = await buf.getSigns({ group: 'CocTree' })
expect(signs.length).toBe(1)
expect(signs[0]).toEqual({
lnum: 2,
id: 3001,
name: 'CocTreeSelected',
priority: 10,
group: 'CocTree'
})
})
it('should not follow cursor', async () => {
workspace.configurations.updateUserConfig({
'outline.followCursor': false,
})
await createBuffer()
let curr = await nvim.call('bufnr', ['%'])
await symbols.showOutline(0)
let bufnr = await nvim.call('bufnr', ['%'])
await nvim.command('wincmd p')
await nvim.command('exe 3')
await events.fire('CursorHold', [curr])
await helper.wait(50)
let buf = nvim.createBuffer(bufnr)
let signs = await buf.getSigns({ group: 'CocTree' })
expect(signs.length).toBe(0)
})
it('should keep current window', async () => {
workspace.configurations.updateUserConfig({
'outline.keepWindow': true,
})
await createBuffer()
let curr = await nvim.call('bufnr', ['%'])
await symbols.showOutline()
let bufnr = await nvim.call('bufnr', ['%'])
expect(curr).toBe(bufnr)
})
it('should check on buffer switch', async () => {
workspace.configurations.updateUserConfig({
'outline.checkBufferSwitch': true,
})
await createBuffer()
await symbols.showOutline(1)
await helper.edit('unnamed')
await helper.wait(300)
let buf = await getOutlineBuffer()
let lines = await buf.lines
expect(lines).toEqual(['Document symbol provider not found'])
})
it('should not check on buffer switch', async () => {
workspace.configurations.updateUserConfig({
'outline.checkBufferSwitch': false
})
await helper.wait(30)
await createBuffer()
await symbols.showOutline(1)
await helper.edit('unnamed')
await helper.wait(100)
let buf = await getOutlineBuffer()
let lines = await buf.lines
expect(lines).toEqual([
'OUTLINE', '- c myClass 1', ' m fun1 2', ' m fun2 3'
])
})
it('should not check on buffer reload', async () => {
workspace.configurations.updateUserConfig({
'outline.checkBufferSwitch': false
})
await symbols.showOutline(1)
await helper.wait(50)
await createBuffer()
await helper.wait(50)
let buf = await getOutlineBuffer()
expect(buf).toBeUndefined()
})
it('should sort by position', async () => {
let code = `class myClass {
fun2() { }
fun1() {}
}`
workspace.configurations.updateUserConfig({
'outline.sortBy': 'position',
})
await createBuffer(code)
await symbols.showOutline(1)
let buf = await getOutlineBuffer()
let lines = await buf.lines
expect(lines).toEqual([
'OUTLINE', '- c myClass 1', ' m fun2 2', ' m fun1 3'
])
})
it('should sort by name', async () => {
let code = `class myClass {
fun2() {}
fun1() {}
}`
workspace.configurations.updateUserConfig({
'outline.sortBy': 'name',
})
await createBuffer(code)
await symbols.showOutline(1)
let buf = await getOutlineBuffer()
let lines = await buf.lines
expect(lines).toEqual([
'OUTLINE', '- c myClass 1', ' m fun1 3', ' m fun2 2'
])
})
})
describe('events', () => {
it('should dispose on buffer unload', async () => {
await createBuffer()
let curr = await nvim.call('bufnr', ['%'])
await symbols.showOutline(0)
await nvim.command('tabe')
await nvim.command(`bd! ${curr}`)
await helper.wait(30)
let buf = await getOutlineBuffer()
expect(buf).toBeUndefined()
})
it('should check current window on BufEnter', async () => {
await createBuffer()
await symbols.showOutline(0)
let winid = await nvim.call('win_getid', [])
await nvim.command('enew')
await helper.wait(200)
let win = await nvim.window
expect(win.id).toBe(winid)
})
it('should recreated when original window exists', async () => {
await symbols.showOutline(1)
await helper.wait(50)
await createBuffer()
await helper.wait(50)
let buf = await getOutlineBuffer()
expect(buf).toBeDefined()
})
it('should keep old outline when new buffer not attached', async () => {
await createBuffer()
await symbols.showOutline(1)
await nvim.command(`vnew +setl\\ buftype=nofile`)
await helper.wait(50)
let buf = await getOutlineBuffer()
expect(buf).toBeDefined()
let lines = await buf.lines
expect(lines).toEqual([
'OUTLINE', '- c myClass 1', ' m fun1 2', ' m fun2 3'
])
})
it('should not reload when switch to original buffer', async () => {
await createBuffer()
await symbols.showOutline(0)
let buf = await getOutlineBuffer()
let name = await buf.name
await nvim.command('wincmd p')
await helper.wait(50)
buf = await getOutlineBuffer()
let curr = await buf.name
expect(curr).toBe(name)
})
it('should dispose provider on outline hide', async () => {
await createBuffer()
let bufnr = await nvim.call('bufnr', ['%'])
await symbols.showOutline(0)
await nvim.command('q')
await helper.wait(30)
let exists = symbols.hasOutline(bufnr)
expect(exists).toBe(false)
})
})
describe('show()', () => {
it('should throw when document not attached', async () => {
await nvim.command(`edit +setl\\ buftype=nofile t`)
await helper.wait(50)
let err
try {
await symbols.showOutline(1)
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
it('should not throw when provider not exists', async () => {
await symbols.showOutline(1)
let buf = await getOutlineBuffer()
expect(buf).toBeDefined()
})
it('should not throw when symbols is empty', async () => {
await createBuffer('')
await symbols.showOutline(1)
let buf = await getOutlineBuffer()
expect(buf).toBeDefined()
})
it('should jump to selected symbol', async () => {
await createBuffer()
let bufnr = await nvim.call('bufnr', ['%'])
await symbols.showOutline(0)
await helper.wait(50)
await nvim.command('exe 3')
await nvim.input('<cr>')
await helper.wait(50)
let curr = await nvim.call('bufnr', ['%'])
expect(curr).toBe(bufnr)
let cursor = await nvim.call('coc#cursor#position')
expect(cursor).toEqual([1, 2])
})
it('should update symbols', async () => {
await createBuffer()
let doc = await workspace.document
let bufnr = await nvim.call('bufnr', ['%'])
await symbols.showOutline(1)
await helper.wait(10)
let buf = nvim.createBuffer(bufnr)
let code = 'class foo{}'
await buf.setLines(code.split('\n'), {
start: 0,
end: -1,
strictIndexing: false
})
await doc.synchronize()
await helper.wait(200)
buf = await getOutlineBuffer()
let lines = await buf.lines
expect(lines).toEqual([
'No results',
'',
'OUTLINE'
])
})
})
describe('actions', () => {
it('should invoke visual select', async () => {
await createBuffer()
let bufnr = await nvim.call('bufnr', ['%'])
await symbols.showOutline(0)
await helper.wait(50)
await nvim.command('exe 3')
await nvim.input('<tab>')
await helper.wait(50)
await nvim.input('<cr>')
await helper.wait(50)
let m = await nvim.mode
expect(m.mode).toBe('v')
let buf = await nvim.buffer
expect(buf.id).toBe(bufnr)
})
it('should invoke selected code action', async () => {
const codeAction = CodeAction.create('my action', CodeActionKind.Refactor)
let uri: string
disposables.push(languages.registerCodeActionProvider([{ language: '*' }], {
provideCodeActions: (
_document,
_range: Range,
_context: CodeActionContext,
_token: CancellationToken
) => [codeAction],
resolveCodeAction: (action): ProviderResult<CodeAction> => {
action.edit = {
changes: {
[uri]: [TextEdit.del(Range.create(0, 0, 0, 5))]
}
}
return action
}
}, undefined))
await createBuffer()
let bufnr = await nvim.call('bufnr', ['%'])
let doc = workspace.getDocument(bufnr)
uri = doc.uri
await symbols.showOutline(0)
await helper.wait(50)
await nvim.command('exe 3')
await nvim.input('<tab>')
await helper.wait(50)
await nvim.input('<cr>')
await helper.wait(200)
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines[0]).toBe(' myClass {')
})
})
describe('hide()', () => {
it('should hide outline', async () => {
await createBuffer('')
await symbols.showOutline(0)
await symbols.hideOutline()
let buf = await getOutlineBuffer()
expect(buf).toBeUndefined()
})
it('should not throw when outline not exists', async () => {
await symbols.hideOutline()
let buf = await getOutlineBuffer()
expect(buf).toBeUndefined()
})
})
describe('dispose', () => {
it('should dispose provider and views', async () => {
await createBuffer('')
let bufnr = await nvim.call('bufnr', ['%'])
await symbols.showOutline(1)
symbols.dispose()
await helper.wait(50)
expect(symbols.hasOutline(bufnr)).toBe(false)
let buf = await getOutlineBuffer()
expect(buf).toBeUndefined()
})
})
})

117
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/parser.ts

@ -1,117 +0,0 @@ @@ -1,117 +0,0 @@
import { TextDocument } from 'vscode-languageserver-textdocument'
import { DocumentSymbol, SymbolKind, Range } from 'vscode-languageserver-protocol'
/**
* A syntax parser that parse `class` and `method` only.
*/
export default class Parser {
private _curr = 0
private _symbols: DocumentSymbol[] = []
private currSymbol: DocumentSymbol | undefined
private len: number
private textDocument: TextDocument
constructor(private _content: string) {
this.len = _content.length
this.textDocument = TextDocument.create('test:///a', 'txt', 1, _content)
}
public parse(): DocumentSymbol[] {
while (this._curr <= this.len - 1) {
this.parseToken()
}
return this._symbols
}
/**
* Parse a symbol, reset currSymbol & _curr
*/
private parseToken(): void {
this.skipSpaces()
if (this.currSymbol) {
let endOffset = this.textDocument.offsetAt(this.currSymbol.range.end)
if (this._curr > endOffset) {
this.currSymbol = undefined
}
}
let remain = this.getLineRemian()
let ms = remain.match(/^(class)\s(\w+)\s\{\s*/)
if (ms) {
// find class
let start = this._curr + 6
let end = start + ms[2].length
let selectionRange = Range.create(this.textDocument.positionAt(start), this.textDocument.positionAt(end))
let endPosition = this.findMatchedIndex(this._curr + ms[0].length)
let range = Range.create(this.textDocument.positionAt(this._curr), this.textDocument.positionAt(endPosition))
let symbolInfo: DocumentSymbol = {
range,
selectionRange,
kind: SymbolKind.Class,
name: ms[2],
children: []
}
if (this.currSymbol && this.currSymbol.children) {
this.currSymbol.children.push(symbolInfo)
} else {
this._symbols.push(symbolInfo)
}
this.currSymbol = symbolInfo
} else if (this.currSymbol && this.currSymbol.kind == SymbolKind.Class) {
let ms = remain.match(/(\w+)\(.*\)\s*\{/)
if (ms) {
// find method
let start = this._curr
let end = start + ms[1].length
let selectionRange = Range.create(this.textDocument.positionAt(start), this.textDocument.positionAt(end))
let endPosition = this.findMatchedIndex(this._curr + ms[0].length)
let range = Range.create(this.textDocument.positionAt(this._curr), this.textDocument.positionAt(endPosition))
let symbolInfo: DocumentSymbol = {
range,
selectionRange,
kind: SymbolKind.Method,
name: ms[1]
}
if (this.currSymbol && this.currSymbol.children) {
this.currSymbol.children.push(symbolInfo)
} else {
this._symbols.push(symbolInfo)
}
}
}
this._curr = this._curr + remain.length + 1
}
private findMatchedIndex(start: number): number {
let level = 0
for (let i = start; i < this.len; i++) {
let ch = this._content[i]
if (ch == '{') {
level = level + 1
}
if (ch == '}') {
if (level == 0) return i
level = level - 1
}
}
throw new Error(`Can't find matched }`)
}
private getLineRemian(): string {
let chars = ''
for (let i = this._curr; i < this.len; i++) {
let ch = this._content[i]
if (ch == '\n') break
chars = chars + ch
}
return chars
}
private skipSpaces(): void {
for (let i = this._curr; i < this.len; i++) {
let ch = this._content[i]
if (!ch || /\S/.test(ch)) {
this._curr = i
break
}
}
}
}

347
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/refactor.test.ts

@ -1,347 +0,0 @@ @@ -1,347 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import fs from 'fs'
import { URI } from 'vscode-uri'
import Refactor, { FileItem } from '../../handler/refactor/index'
import helper, { createTmpFile } from '../helper'
import languages from '../../languages'
import { WorkspaceEdit, Range } from 'vscode-languageserver-types'
import { Disposable } from '@chemzqm/neovim/lib/api/Buffer'
let nvim: Neovim
let refactor: Refactor
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
refactor = helper.plugin.getHandler().refactor
})
beforeEach(async () => {
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
refactor.reset()
await helper.reset()
})
describe('refactor', () => {
describe('create', () => {
it('should create from workspaceEdit', async () => {
let changes = {
[URI.file(__filename).toString()]: [{
range: Range.create(0, 0, 0, 6),
newText: ''
}, {
range: Range.create(1, 0, 1, 6),
newText: ''
}]
}
let edit: WorkspaceEdit = { changes }
let buf = await refactor.fromWorkspaceEdit(edit)
let shown = await buf.valid
expect(shown).toBe(true)
let items = buf.fileItems
expect(items.length).toBe(1)
})
it('should create from locations', async () => {
let uri = URI.file(__filename).toString()
let locations = [{
uri,
range: Range.create(0, 0, 0, 6),
}, {
uri,
range: Range.create(1, 0, 1, 6),
}]
let buf = await refactor.fromLocations(locations)
let shown = await buf.valid
expect(shown).toBe(true)
let items = buf.fileItems
expect(items.length).toBe(1)
})
})
describe('onChange', () => {
it('should ignore when change after range', async () => {
let doc = await helper.createDocument()
await doc.buffer.append(['foo', 'bar'])
await refactor.fromLocations([{ uri: doc.uri, range: Range.create(0, 0, 0, 3) }])
let lines = await nvim.call('getline', [1, '$'])
await doc.buffer.append(['def'])
doc.forceSync()
await helper.wait(100)
let newLines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(newLines)
})
it('should adjust when change before range', async () => {
let doc = await helper.createDocument()
await doc.buffer.append(['', '', '', '', 'foo', 'bar'])
await helper.wait(50)
doc.forceSync()
let buf = await refactor.fromLocations([{ uri: doc.uri, range: Range.create(4, 0, 4, 3) }])
await doc.buffer.setLines(['def'], { start: 0, end: 0, strictIndexing: false })
doc.forceSync()
await helper.wait(100)
let fileRange = buf.getFileRange(4)
expect(fileRange.start).toBe(2)
expect(fileRange.end).toBe(8)
})
it('should removed when lines empty', async () => {
let doc = await helper.createDocument()
await doc.buffer.append(['', '', '', '', 'foo', 'bar'])
await helper.wait(50)
doc.forceSync()
let buf = await refactor.fromLocations([{ uri: doc.uri, range: Range.create(4, 0, 4, 3) }])
await doc.buffer.setLines([], { start: 0, end: -1, strictIndexing: false })
doc.forceSync()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines.length).toBe(3)
let items = buf.fileItems
expect(items.length).toBe(0)
})
it('should change when liens changed', async () => {
let doc = await helper.createDocument()
await doc.buffer.append(['', '', '', '', 'foo', 'bar'])
await helper.wait(50)
doc.forceSync()
await refactor.fromLocations([{ uri: doc.uri, range: Range.create(4, 0, 4, 3) }])
await doc.buffer.setLines(['def'], { start: 5, end: 6, strictIndexing: false })
doc.forceSync()
await helper.wait(30)
let lines = await nvim.call('getline', [1, '$'])
expect(lines[lines.length - 2]).toBe('def')
})
})
describe('refactor#getFileChanges', () => {
it('should get changes #1', async () => {
await helper.createDocument()
let lines = `
Save current buffer to make changes
\u3000
\u3000
\u3000/a.ts
})
} `
let buf = await refactor.fromLines(lines.split('\n'))
let changes = await buf.getFileChanges()
expect(changes).toEqual([{ lnum: 5, filepath: '/a.ts', lines: [' })', ' } '] }])
})
it('should get changes #2', async () => {
let lines = `
\u3000/a.ts
})
} `
let buf = await refactor.fromLines(lines.split('\n'))
let changes = await buf.getFileChanges()
expect(changes).toEqual([{ lnum: 2, filepath: '/a.ts', lines: [' })', ' } '] }])
})
it('should get changes #3', async () => {
let lines = `
\u3000/a.ts
})
}
\u3000`
let buf = await refactor.fromLines(lines.split('\n'))
let changes = await buf.getFileChanges()
expect(changes).toEqual([{ lnum: 2, filepath: '/a.ts', lines: [' })', ' }'] }])
})
it('should get changes #4', async () => {
let lines = `
\u3000/a.ts
foo
\u3000/b.ts
bar
\u3000`
let buf = await refactor.fromLines(lines.split('\n'))
let changes = await buf.getFileChanges()
expect(changes).toEqual([
{ filepath: '/a.ts', lnum: 2, lines: ['foo'] },
{ filepath: '/b.ts', lnum: 4, lines: ['bar'] }
])
})
})
describe('Refactor#createRefactorBuffer', () => {
it('should create refactor buffer', async () => {
await helper.createDocument()
let winid = await nvim.call('win_getid')
let buf = await refactor.createRefactorBuffer()
let curr = await nvim.call('win_getid')
expect(curr).toBeGreaterThan(winid)
let valid = await buf.valid
expect(valid).toBe(true)
})
it('should jump to position by <CR>', async () => {
await helper.createDocument()
let buf = await refactor.createRefactorBuffer()
let fileItem: FileItem = {
filepath: __filename,
ranges: [{ start: 10, end: 11 }, { start: 15, end: 20 }]
}
await buf.addFileItems([fileItem])
await nvim.call('cursor', [5, 1])
await buf.splitOpen()
let line = await nvim.eval('line(".")')
let bufname = await nvim.eval('bufname("%")')
expect(bufname).toMatch('refactor.test.ts')
expect(line).toBe(11)
})
})
describe('Refactor#saveRefactor', () => {
it('should adjust line ranges after change', async () => {
let filename = await createTmpFile('foo\n\nbar\n')
let fileItem: FileItem = {
filepath: filename,
ranges: [{ start: 0, end: 1 }, { start: 2, end: 3 }]
}
let buf = await refactor.createRefactorBuffer()
await buf.addFileItems([fileItem])
nvim.pauseNotification()
nvim.call('setline', [5, ['xyz']], true)
nvim.command('undojoin', true)
nvim.call('append', [5, ['de']], true)
nvim.command('undojoin', true)
nvim.call('append', [8, ['bar']], true)
await nvim.resumeNotification()
await helper.wait(100)
let res = await refactor.save(buf.buffer.id)
expect(res).toBe(true)
let content = fs.readFileSync(filename, 'utf8')
expect(content).toBe('xyz\nde\n\nbar\nbar\n')
})
it('should not save when no change made', async () => {
let buf = await refactor.createRefactorBuffer()
let fileItem: FileItem = {
filepath: __filename,
ranges: [{ start: 10, end: 11 }, { start: 15, end: 20 }]
}
await buf.addFileItems([fileItem])
let res = await buf.save()
expect(res).toBe(false)
})
it('should sync buffer change to file', async () => {
let doc = await helper.createDocument()
await doc.buffer.replace(['foo', 'bar', 'line'], 0)
await helper.wait(30)
let filename = URI.parse(doc.uri).fsPath
let fileItem: FileItem = {
filepath: filename,
ranges: [{ start: 0, end: 2 }]
}
let buf = await refactor.createRefactorBuffer()
await buf.addFileItems([fileItem])
await nvim.call('setline', [5, 'changed'])
let res = await buf.save()
expect(res).toBe(true)
expect(fs.existsSync(filename)).toBe(true)
let content = fs.readFileSync(filename, 'utf8')
let lines = content.split('\n')
expect(lines).toEqual(['changed', 'bar', 'line', ''])
fs.unlinkSync(filename)
})
})
describe('doRefactor', () => {
let disposable: Disposable
afterEach(() => {
if (disposable) disposable.dispose()
disposable = null
})
it('should throw when rename provider not found', async () => {
await helper.createDocument()
let err
try {
await refactor.doRefactor()
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
it('should show message when prepare failed', async () => {
await helper.createDocument()
disposable = languages.registerRenameProvider(['*'], {
prepareRename: () => {
return undefined
},
provideRenameEdits: () => {
return null
}
})
await refactor.doRefactor()
let res = await helper.getCmdline()
expect(res).toMatch(/unable to rename/)
})
it('should show message when returned edits is null', async () => {
await helper.createDocument()
disposable = languages.registerRenameProvider(['*'], {
provideRenameEdits: () => {
return null
}
})
await refactor.doRefactor()
let res = await helper.getCmdline()
expect(res).toMatch(/returns null/)
})
it('should open refactor window when edits is valid', async () => {
let filepath = __filename
disposable = languages.registerRenameProvider(['*'], {
provideRenameEdits: () => {
let changes = {
[URI.file(filepath).toString()]: [{
range: Range.create(0, 0, 0, 6),
newText: ''
}, {
range: Range.create(1, 0, 1, 6),
newText: ''
}]
}
let edit: WorkspaceEdit = { changes }
return edit
}
})
await helper.createDocument(filepath)
let winid = await nvim.call('win_getid')
await refactor.doRefactor()
let currWin = await nvim.call('win_getid')
expect(currWin - winid).toBeGreaterThan(0)
let bufnr = await nvim.call('bufnr', ['%'])
let b = refactor.getBuffer(bufnr)
expect(b).toBeDefined()
})
})
describe('search', () => {
it('should open refactor buffer from search result', async () => {
let escaped = await nvim.call('fnameescape', [__dirname])
await nvim.command(`cd ${escaped}`)
await helper.createDocument()
await refactor.search(['registerRenameProvider'])
let buf = await nvim.buffer
let name = await buf.name
expect(name).toMatch(/__coc_refactor__/)
let lines = await buf.lines
expect(lines[0]).toMatch(/Save current buffer/)
})
})
})

263
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/rename.test.ts

@ -1,263 +0,0 @@ @@ -1,263 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, Position, Range, TextEdit } from 'vscode-languageserver-protocol'
import { TextDocument } from 'vscode-languageserver-textdocument'
import Rename from '../../handler/rename'
import languages from '../../languages'
import { disposeAll } from '../../util'
import helper from '../helper'
let nvim: Neovim
let disposables: Disposable[] = []
let rename: Rename
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
rename = helper.plugin.getHandler().rename
})
function getWordRangeAtPosition(doc: TextDocument, position: Position): Range | null {
let lines = doc.getText().split(/\r?\n/)
let line = lines[position.line]
if (line.length == 0 || position.character >= line.length) return null
if (!/\w/.test(line[position.character])) return null
let start = position.character
let end = position.character + 1
if (!/\w/.test(line[start])) {
return Range.create(position, { line: position.line, character: position.character + 1 })
}
while (start >= 0) {
let ch = line[start - 1]
if (!ch || !/\w/.test(ch)) break
start = start - 1
}
while (end <= line.length) {
let ch = line[end]
if (!ch || !/\w/.test(ch)) break
end = end + 1
}
return Range.create(position.line, start, position.line, end)
}
function getSymbolRanges(textDocument: TextDocument, word: string): Range[] {
let res: Range[] = []
let str = ''
let content = textDocument.getText()
for (let i = 0, l = content.length; i < l; i++) {
let ch = content[i]
if ('-' == ch && str.length == 0) {
continue
}
let isKeyword = /\w/.test(ch)
if (isKeyword) {
str = str + ch
}
if (str.length > 0 && !isKeyword && str == word) {
res.push(Range.create(textDocument.positionAt(i - str.length), textDocument.positionAt(i)))
}
if (!isKeyword) {
str = ''
}
}
return res
}
beforeEach(() => {
disposables.push(languages.registerRenameProvider([{ language: 'javascript' }], {
provideRenameEdits: (doc, position: Position, newName: string) => {
let range = getWordRangeAtPosition(doc, position)
if (range) {
let word = doc.getText(range)
if (word) {
let ranges = getSymbolRanges(doc, word)
return {
changes: {
[doc.uri]: ranges.map(o => TextEdit.replace(o, newName))
}
}
}
}
return undefined
},
prepareRename: (doc, position) => {
let range = getWordRangeAtPosition(doc, position)
return range ? { range, placeholder: doc.getText(range) } : null
}
}))
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
disposeAll(disposables)
disposables = []
})
describe('rename handler', () => {
describe('getWordEdit', () => {
it('should not throw when provider not found', async () => {
await helper.edit()
let res = await rename.getWordEdit()
expect(res).toBe(null)
})
it('should return null when prepare failed', async () => {
let doc = await helper.createDocument('t.js')
await nvim.setLine('你')
await doc.synchronize()
let res = await rename.getWordEdit()
expect(res).toBe(null)
})
it('should return workspace edit', async () => {
let doc = await helper.createDocument('t.js')
await nvim.setLine('foo foo')
await doc.synchronize()
let res = await rename.getWordEdit()
expect(res).toBeDefined()
expect(res.changes[doc.uri].length).toBe(2)
})
it('should extract words from buffer', async () => {
let doc = await helper.createDocument('t')
await nvim.setLine('你 你 你')
await doc.synchronize()
let res = await rename.getWordEdit()
expect(res).toBeDefined()
expect(res.changes[doc.uri].length).toBe(3)
})
})
describe('rename', () => {
it('should throw when provider not found', async () => {
await helper.edit()
let err
try {
await rename.rename('foo')
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
it('should return false for invalid position', async () => {
await helper.createDocument('t.js')
let res = await rename.rename('foo')
expect(res).toBe(false)
})
it('should use newName from placeholder', async () => {
await helper.createDocument('t.js')
await nvim.setLine('foo foo foo')
let p = rename.rename()
await helper.wait(50)
await nvim.input('<C-u>')
await helper.wait(10)
await nvim.input('bar')
await nvim.input('<cr>')
let res = await p
expect(res).toBe(true)
})
it('should return false for empty name', async () => {
await helper.createDocument('t.js')
await nvim.setLine('foo foo foo')
let p = rename.rename()
await helper.wait(50)
await nvim.input('<C-u>')
await helper.wait(20)
await nvim.input('<cr>')
let res = await p
expect(res).toBe(false)
})
it('should use newName from range', async () => {
disposables.push(languages.registerRenameProvider([{ language: '*' }], {
provideRenameEdits: (doc, position: Position, newName: string) => {
let range = getWordRangeAtPosition(doc, position)
if (range) {
let word = doc.getText(range)
if (word) {
let ranges = getSymbolRanges(doc, word)
return {
changes: {
[doc.uri]: ranges.map(o => TextEdit.replace(o, newName))
}
}
}
}
return undefined
},
prepareRename: (doc, position) => {
let range = getWordRangeAtPosition(doc, position)
return range ? range : null
}
}))
await helper.createDocument()
await nvim.setLine('foo foo foo')
let p = rename.rename()
await helper.wait(50)
await nvim.input('<C-u>')
await helper.wait(10)
await nvim.input('bar')
await nvim.input('<cr>')
let res = await p
expect(res).toBe(true)
let line = await nvim.getLine()
expect(line).toBe('bar bar bar')
})
it('should use newName from cword', async () => {
disposables.push(languages.registerRenameProvider([{ language: '*' }], {
provideRenameEdits: (doc, position: Position, newName: string) => {
let range = getWordRangeAtPosition(doc, position)
if (range) {
let word = doc.getText(range)
if (word) {
let ranges = getSymbolRanges(doc, word)
return {
changes: {
[doc.uri]: ranges.map(o => TextEdit.replace(o, newName))
}
}
}
}
return undefined
}
}))
await helper.createDocument()
await nvim.setLine('foo foo foo')
let p = rename.rename()
await helper.wait(50)
await nvim.input('<C-u>')
await helper.wait(10)
await nvim.input('bar')
await nvim.input('<cr>')
let res = await p
expect(res).toBe(true)
let line = await nvim.getLine()
expect(line).toBe('bar bar bar')
})
it('should return false when result is empty', async () => {
disposables.push(languages.registerRenameProvider([{ language: '*' }], {
provideRenameEdits: () => {
return null
}
}))
await helper.createDocument()
await nvim.setLine('foo foo foo')
let p = rename.rename()
await helper.wait(50)
await nvim.input('<C-u>')
await helper.wait(10)
await nvim.input('bar')
await nvim.input('<cr>')
let res = await p
expect(res).toBe(false)
})
})
})

101
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/search.test.ts

@ -1,101 +0,0 @@ @@ -1,101 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import Refactor from '../../handler/refactor'
import Search, { getPathFromArgs } from '../../handler/search'
import helper from '../helper'
import path from 'path'
let nvim: Neovim
let refactor: Refactor
// use fake rg command
let cmd = path.resolve(__dirname, '../rg')
let cwd = process.cwd()
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
refactor = helper.plugin.getHandler().refactor
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
refactor.reset()
await helper.reset()
})
describe('getPathFromArgs', () => {
it('should get undefined path', async () => {
let res = getPathFromArgs(['a'])
expect(res).toBeUndefined()
res = getPathFromArgs(['a', 'b', '-c'])
expect(res).toBeUndefined()
res = getPathFromArgs(['a', '-b', 'c'])
expect(res).toBeUndefined()
})
})
describe('search', () => {
it('should open refactor window', async () => {
let search = new Search(nvim, cmd)
let buf = await refactor.createRefactorBuffer()
await search.run([], cwd, buf)
await helper.wait(50)
let fileItems = buf.fileItems
expect(fileItems.length).toBe(2)
expect(fileItems[0].ranges.length).toBe(2)
})
it('should abort task', async () => {
let search = new Search(nvim, cmd)
let buf = await refactor.createRefactorBuffer()
let p = search.run(['--sleep', '1000'], cwd, buf)
search.abort()
await p
let fileItems = buf.fileItems
expect(fileItems.length).toBe(0)
})
it('should work with CocAction search', async () => {
await helper.doAction('search', ['CocAction'])
let bufnr = await nvim.call('bufnr', ['%'])
let buf = refactor.getBuffer(bufnr)
expect(buf).toBeDefined()
})
it('should fail on invalid command', async () => {
let search = new Search(nvim, 'rrg')
let buf = await refactor.createRefactorBuffer()
let err
try {
await search.run([], cwd, buf)
} catch (e) {
err = e
}
expect(err).toBeDefined()
let msg = await helper.getCmdline()
expect(msg).toMatch(/Error on command "rrg"/)
})
it('should show empty result when no result found', async () => {
await helper.doAction('search', ['should found ' + ' no result'])
let bufnr = await nvim.call('bufnr', ['%'])
let buf = refactor.getBuffer(bufnr)
expect(buf).toBeDefined()
let buffer = await nvim.buffer
let lines = await buffer.lines
expect(lines[1]).toMatch(/No match found/)
})
it('should use corrent search folder for rg', async () => {
let search = new Search(nvim, 'rg')
await helper.createDocument()
let buf = await refactor.createRefactorBuffer()
await search.run(['-w', 'createRefactorBuffer', 'src/__tests__'], cwd, buf)
let buffer = await nvim.buffer
let lines = await buffer.lines
expect(lines[1].startsWith('Files: ')).toBe(true)
})
})

143
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/selectionRange.test.ts

@ -1,143 +0,0 @@ @@ -1,143 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, Position, Range, TextEdit } from 'vscode-languageserver-protocol'
import SelectionRange from '../../handler/selectionRange'
import languages from '../../languages'
import workspace from '../../workspace'
import { disposeAll } from '../../util'
import helper from '../helper'
let nvim: Neovim
let disposables: Disposable[] = []
let selection: SelectionRange
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
selection = helper.plugin.getHandler().selectionRange
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
disposeAll(disposables)
disposables = []
})
describe('selectionRange', () => {
describe('getSelectionRanges()', () => {
it('should throw error when selectionRange provider not exists', async () => {
let doc = await helper.createDocument()
await doc.synchronize()
let err
try {
await selection.getSelectionRanges()
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
it('should return ranges', async () => {
await helper.createDocument()
disposables.push(languages.registerSelectionRangeProvider([{ language: '*' }], {
provideSelectionRanges: _doc => {
return [{
range: Range.create(0, 0, 0, 1)
}]
}
}))
let res = await selection.getSelectionRanges()
expect(res).toBeDefined()
expect(Array.isArray(res)).toBe(true)
})
})
describe('selectRange()', () => {
async function getSelectedRange(): Promise<Range> {
let m = await nvim.mode
expect(m.mode).toBe('v')
let bufnr = await nvim.call('bufnr', ['%'])
await nvim.input('<esc>')
let doc = workspace.getDocument(bufnr)
let res = await workspace.getSelectedRange('v', doc)
return res
}
it('should select ranges forward', async () => {
let doc = await helper.createDocument()
let called = 0
await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'foo\nbar\ntest\n')])
await nvim.call('cursor', [1, 1])
disposables.push(languages.registerSelectionRangeProvider([{ language: '*' }], {
provideSelectionRanges: _doc => {
called += 1
let arr = [{
range: Range.create(0, 0, 0, 1)
}, {
range: Range.create(0, 0, 0, 3)
}, {
range: Range.create(0, 0, 1, 3)
}]
return arr
}
}))
await doc.synchronize()
await selection.selectRange('', false)
await selection.selectRange('', true)
expect(called).toBe(1)
let res = await getSelectedRange()
expect(res).toEqual(Range.create(0, 0, 0, 1))
await selection.selectRange('v', true)
expect(called).toBe(2)
res = await getSelectedRange()
expect(res).toEqual(Range.create(0, 0, 0, 3))
await selection.selectRange('v', true)
expect(called).toBe(3)
res = await getSelectedRange()
expect(res).toEqual(Range.create(0, 0, 1, 3))
await selection.selectRange('v', true)
expect(called).toBe(4)
let m = await nvim.mode
expect(m.mode).toBe('n')
})
it('should select ranges backward', async () => {
let doc = await helper.createDocument()
await doc.applyEdits([TextEdit.insert(Position.create(0, 0), 'foo\nbar\ntest\n')])
await nvim.call('cursor', [1, 1])
disposables.push(languages.registerSelectionRangeProvider([{ language: '*' }], {
provideSelectionRanges: _doc => {
let arr = [{
range: Range.create(0, 0, 0, 1)
}, {
range: Range.create(0, 0, 0, 3)
}, {
range: Range.create(0, 0, 1, 3)
}]
return arr
}
}))
await doc.synchronize()
await selection.selectRange('', true)
let mode = await nvim.call('mode')
expect(mode).toBe('v')
await nvim.input('<esc>')
await workspace.selectRange(Range.create(0, 0, 1, 3))
await nvim.input('<esc>')
await selection.selectRange('v', false)
let r = await getSelectedRange()
expect(r).toEqual(Range.create(0, 0, 0, 3))
await nvim.input('<esc>')
await selection.selectRange('v', false)
r = await getSelectedRange()
expect(r).toEqual(Range.create(0, 0, 0, 1))
await nvim.input('<esc>')
await selection.selectRange('v', false)
mode = await nvim.call('mode')
expect(mode).toBe('n')
})
})
})

180
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/semanticTokens.test.ts

@ -1,180 +0,0 @@ @@ -1,180 +0,0 @@
import { Buffer, Neovim } from '@chemzqm/neovim'
import { Disposable, SemanticTokensLegend } from 'vscode-languageserver-protocol'
import languages from '../../languages'
import SemanticTokensHighlights from '../../handler/semanticTokensHighlights/index'
import { disposeAll } from '../../util'
import workspace from '../../workspace'
import helper from '../helper'
let nvim: Neovim
let disposables: Disposable[] = []
let highlighter: SemanticTokensHighlights
let legend: SemanticTokensLegend = {
tokenTypes: [
"comment",
"keyword",
"string",
"number",
"regexp",
"operator",
"namespace",
"type",
"struct",
"class",
"interface",
"enum",
"enumMember",
"typeParameter",
"function",
"method",
"property",
"macro",
"variable",
"parameter",
"angle",
"arithmetic",
"attribute",
"bitwise",
"boolean",
"brace",
"bracket",
"builtinType",
"character",
"colon",
"comma",
"comparison",
"constParameter",
"dot",
"escapeSequence",
"formatSpecifier",
"generic",
"label",
"lifetime",
"logical",
"operator",
"parenthesis",
"punctuation",
"selfKeyword",
"semicolon",
"typeAlias",
"union",
"unresolvedReference"
],
tokenModifiers: [
"documentation",
"declaration",
"definition",
"static",
"abstract",
"deprecated",
"readonly",
"constant",
"controlFlow",
"injected",
"mutable",
"consuming",
"async",
"library",
"public",
"unsafe",
"attribute",
"trait",
"callable",
"intraDocLink"
]
}
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
highlighter = helper.plugin.getHandler().semanticHighlighter
})
afterAll(async () => {
await helper.shutdown()
})
beforeEach(async () => {
async function createBuffer(code: string): Promise<Buffer> {
let buf = await nvim.buffer
await nvim.command('setf rust')
await buf.setLines(code.split('\n'), { start: 0, end: -1, strictIndexing: false })
let doc = await workspace.document
doc.forceSync()
return buf
}
disposables.push(languages.registerDocumentSemanticTokensProvider([{ language: 'rust' }], {
provideDocumentSemanticTokens: () => {
return {
resultId: '1',
data: [
0, 0, 2, 1, 0,
0, 3, 4, 14, 2,
0, 4, 1, 41, 0,
0, 1, 1, 41, 0,
0, 2, 1, 25, 0,
1, 4, 8, 17, 0,
0, 8, 1, 41, 0,
0, 1, 3, 2, 0,
0, 3, 1, 41, 0,
0, 1, 1, 44, 0,
1, 0, 1, 25, 0,
]
}
}
}, legend))
await createBuffer(`fn main() {
println!("H");
}`)
})
afterEach(async () => {
workspace.configurations.updateUserConfig({
'coc.preferences.semanticTokensHighlights': true
})
await helper.reset()
disposeAll(disposables)
disposables = []
})
describe('semanticTokens', () => {
describe('triggerSemanticTokens', () => {
it('should be disabled', async () => {
await helper.createDocument()
workspace.configurations.updateUserConfig({
'coc.preferences.semanticTokensHighlights': false
})
const curr = await highlighter.getCurrentItem()
let err
try {
curr.checkState()
} catch (e) {
err = e
}
expect(err).toBeDefined()
expect(err.message).toMatch('disabled by configuration')
})
it('should get legend by API', async () => {
const doc = await workspace.document
const l = languages.getLegend(doc.textDocument)
expect(l).toEqual(legend)
})
it('should get semanticTokens by API', async () => {
// const doc = await workspace.document
// const highlights = await highlighter.getHighlights(doc.bufnr)
// expect(highlights.length).toBe(11)
// expect(highlights[0].hlGroup).toBe('CocSem_keyword')
})
it('should doHighlight', async () => {
const doc = await workspace.document
await nvim.call('CocAction', 'semanticHighlight')
const highlights = await nvim.call("coc#highlight#get_highlights", [doc.bufnr, 'semanticTokens'])
expect(highlights.length).toBe(11)
expect(highlights[0].hlGroup).toBe('CocSem_keyword')
})
})
})

376
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/signature.test.ts

@ -1,376 +0,0 @@ @@ -1,376 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable, Position, ParameterInformation, SignatureInformation } from 'vscode-languageserver-protocol'
import languages from '../../languages'
import { disposeAll } from '../../util'
import Signature from '../../handler/signature'
import workspace from '../../workspace'
import helper from '../helper'
let nvim: Neovim
let signature: Signature
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
signature = helper.plugin.getHandler().signature
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
disposeAll(disposables)
disposables = []
})
describe('signatureHelp', () => {
describe('triggerSignatureHelp', () => {
it('should show signature by api', async () => {
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
return {
signatures: [SignatureInformation.create('foo()', 'my signature')],
activeParameter: null,
activeSignature: null
}
}
}, []))
await helper.createDocument()
await nvim.input('foo')
await signature.triggerSignatureHelp()
let win = await helper.getFloat()
expect(win).toBeDefined()
let lines = await helper.getWinLines(win.id)
expect(lines[2]).toMatch('my signature')
})
it('should trigger by space', async () => {
let called = false
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
called = true
return {
signatures: [SignatureInformation.create('foo()', 'my signature')],
activeParameter: null,
activeSignature: null
}
}
}, [' ']))
await helper.createDocument()
await nvim.input('i')
await helper.wait(30)
await nvim.input(' ')
await helper.wait(50)
expect(called).toBe(true)
})
it('should show signature help with param label as string', async () => {
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
return {
signatures: [
SignatureInformation.create('foo()', 'my signature'),
SignatureInformation.create('foo(a, b)', 'my signature', ParameterInformation.create('a', 'description')),
],
activeParameter: 0,
activeSignature: 1
}
}
}, []))
await helper.createDocument()
await nvim.input('foo')
await signature.triggerSignatureHelp()
let win = await helper.getFloat()
expect(win).toBeDefined()
let lines = await helper.getWinLines(win.id)
expect(lines.join('\n')).toMatch(/description/)
})
it('should consider coc_last_placeholder on select mode', async () => {
let pos: Position
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, position) => {
pos = position
return {
signatures: [
SignatureInformation.create('foo(a, b)', 'my signature', ParameterInformation.create('a', 'description')),
],
activeParameter: 1,
activeSignature: null
}
}
}, []))
let doc = await helper.createDocument()
let line = await nvim.call('line', ['.'])
await nvim.setLine(' fn(abc, def)')
await nvim.command('normal! 0fave')
await nvim.input('<C-g>')
let placeholder = {
bufnr: doc.bufnr,
start: Position.create(line - 1, 5),
end: Position.create(line - 1, 8)
}
await nvim.setVar('coc_last_placeholder', placeholder)
let m = await nvim.mode
expect(m.mode).toBe('s')
await signature.triggerSignatureHelp()
let win = await helper.getFloat()
expect(win).toBeDefined()
expect(pos).toEqual(Position.create(0, 5))
})
})
describe('events', () => {
it('should trigger signature help', async () => {
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
return {
signatures: [SignatureInformation.create('foo(x, y)', 'my signature')],
activeParameter: 0,
activeSignature: 0
}
}
}, ['(', ',']))
await helper.createDocument()
await nvim.input('foo')
await nvim.input('(')
await helper.wait(100)
let win = await helper.getFloat()
expect(win).toBeDefined()
let lines = await helper.getWinLines(win.id)
expect(lines[2]).toMatch('my signature')
})
it('should cancel trigger on InsertLeave', async () => {
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: async (_doc, _position, token) => {
await helper.wait(1000)
if (token.isCancellationRequested) return undefined
return {
signatures: [SignatureInformation.create('foo()', 'my signature')],
activeParameter: null,
activeSignature: null
}
}
}, ['(', ',']))
await helper.createDocument()
await nvim.input('foo')
let p = signature.triggerSignatureHelp()
await helper.wait(10)
await nvim.command('stopinsert')
await nvim.call('feedkeys', [String.fromCharCode(27), 'in'])
let res = await p
expect(res).toBe(false)
})
it('should not close signature on type', async () => {
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
return {
signatures: [SignatureInformation.create('foo()', 'my signature')],
activeParameter: null,
activeSignature: null
}
}
}, ['(', ',']))
await helper.createDocument()
await nvim.input('foo(')
await helper.wait(100)
await nvim.input('bar')
await helper.wait(100)
let win = await helper.getFloat()
expect(win).toBeDefined()
let lines = await helper.getWinLines(win.id)
expect(lines[2]).toMatch('my signature')
})
it('should close signature float when empty signatures returned', async () => {
let empty = false
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
if (empty) return undefined
return {
signatures: [SignatureInformation.create('foo()', 'my signature')],
activeParameter: null,
activeSignature: null
}
}
}, ['(', ',']))
await helper.createDocument()
await nvim.input('foo(')
await helper.wait(100)
let win = await helper.getFloat()
expect(win).toBeDefined()
empty = true
await signature.triggerSignatureHelp()
await helper.wait(50)
let res = await nvim.call('coc#float#valid', [win.id])
expect(res).toBe(0)
})
})
describe('float window', () => {
it('should align signature window to top', async () => {
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
return {
signatures: [SignatureInformation.create('foo()', 'my signature')],
activeParameter: null,
activeSignature: null
}
}
}, ['(', ',']))
await helper.createDocument()
let buf = await nvim.buffer
await buf.setLines(['', '', '', '', ''], { start: 0, end: -1, strictIndexing: true })
await nvim.call('cursor', [5, 1])
await nvim.input('foo(')
await helper.wait(100)
let win = await helper.getFloat()
expect(win).toBeDefined()
let lines = await helper.getWinLines(win.id)
expect(lines[2]).toMatch('my signature')
let res = await nvim.call('coc#float#cursor_relative', [win.id]) as any
expect(res.row).toBeLessThan(0)
})
it('should show parameter docs', async () => {
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
return {
signatures: [SignatureInformation.create('foo(a, b)', 'my signature',
ParameterInformation.create('a', 'foo'),
ParameterInformation.create([7, 8], 'bar'))],
activeParameter: 1,
activeSignature: null
}
}
}, ['(', ',']))
await helper.createDocument()
let buf = await nvim.buffer
await buf.setLines(['', '', '', '', ''], { start: 0, end: -1, strictIndexing: true })
await nvim.call('cursor', [5, 1])
await nvim.input('foo(a,')
await helper.wait(100)
let win = await helper.getFloat()
expect(win).toBeDefined()
let lines = await helper.getWinLines(win.id)
expect(lines.join('\n')).toMatch('bar')
})
})
describe('configurations', () => {
let { configurations } = workspace
afterEach(() => {
configurations.updateUserConfig({
'signature.target': 'float',
'signature.hideOnTextChange': false,
'signature.enable': true,
'signature.triggerSignatureWait': 500
})
})
it('should cancel signature on timeout', async () => {
configurations.updateUserConfig({ 'signature.triggerSignatureWait': 50 })
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position, token) => {
return new Promise(resolve => {
token.onCancellationRequested(() => {
clearTimeout(timer)
resolve(undefined)
})
let timer = setTimeout(() => {
resolve({
signatures: [SignatureInformation.create('foo()', 'my signature')],
activeParameter: null,
activeSignature: null
})
}, 200)
})
}
}, ['(', ',']))
await helper.createDocument()
await signature.triggerSignatureHelp()
let win = await helper.getFloat()
expect(win).toBeUndefined()
configurations.updateUserConfig({ 'signature.triggerSignatureWait': 100 })
})
it('should hide signature window on text change', async () => {
configurations.updateUserConfig({ 'signature.hideOnTextChange': true })
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
return {
signatures: [SignatureInformation.create('foo()', 'my signature')],
activeParameter: null,
activeSignature: null
}
}
}, ['(', ',']))
await helper.createDocument()
await nvim.input('ifoo(')
let winid = await helper.waitFloat()
await nvim.input('x')
await helper.wait(100)
let res = await nvim.call('coc#float#valid', [winid])
expect(res).toBe(0)
configurations.updateUserConfig({ 'signature.hideOnTextChange': false })
})
it('should disable signature help trigger', async () => {
configurations.updateUserConfig({ 'signature.enable': false })
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
return {
signatures: [SignatureInformation.create('foo()', 'my signature')],
activeParameter: null,
activeSignature: null
}
}
}, ['(', ',']))
await helper.createDocument()
await nvim.input('foo')
await nvim.input('(')
await helper.wait(100)
let win = await helper.getFloat()
expect(win).toBeUndefined()
})
it('should echo simple signature help', async () => {
let idx = 0
let activeSignature = null
configurations.updateUserConfig({ 'signature.target': 'echo' })
disposables.push(languages.registerSignatureHelpProvider([{ scheme: 'file' }], {
provideSignatureHelp: (_doc, _position) => {
return {
signatures: [SignatureInformation.create('foo(a, b)', 'my signature',
ParameterInformation.create('a', 'foo'),
ParameterInformation.create([7, 8], 'bar')),
SignatureInformation.create('a'.repeat(workspace.env.columns + 10))
],
activeParameter: idx,
activeSignature
}
}
}, []))
await helper.createDocument()
await nvim.input('foo(')
await signature.triggerSignatureHelp()
let line = await helper.getCmdline()
expect(line).toMatch('(a, b)')
await nvim.input('a,')
idx = 1
await signature.triggerSignatureHelp()
line = await helper.getCmdline()
expect(line).toMatch('foo(a, b)')
activeSignature = 1
await signature.triggerSignatureHelp()
line = await helper.getCmdline()
expect(line).toMatch('aaaaaa')
})
})
})

284
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/handler/symbols.test.ts

@ -1,284 +0,0 @@ @@ -1,284 +0,0 @@
import { Buffer, Neovim } from '@chemzqm/neovim'
import { Disposable, SymbolInformation, SymbolKind, Range } from 'vscode-languageserver-protocol'
import Symbols from '../../handler/symbols/index'
import languages from '../../languages'
import workspace from '../../workspace'
import events from '../../events'
import { disposeAll } from '../../util'
import helper from '../helper'
import Parser from './parser'
let nvim: Neovim
let symbols: Symbols
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
symbols = helper.plugin.getHandler().symbols
})
beforeEach(() => {
disposables.push(languages.registerDocumentSymbolProvider([{ language: 'javascript' }], {
provideDocumentSymbols: document => {
let parser = new Parser(document.getText())
let res = parser.parse()
return Promise.resolve(res)
}
}))
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
disposeAll(disposables)
disposables = []
})
describe('Parser', () => {
it('should parse content', async () => {
let code = `class myClass {
fun1() { }
}`
let parser = new Parser(code)
let res = parser.parse()
expect(res.length).toBeGreaterThan(0)
})
})
describe('symbols handler', () => {
async function createBuffer(code: string): Promise<Buffer> {
let buf = await nvim.buffer
await nvim.command('setf javascript')
await buf.setLines(code.split('\n'), { start: 0, end: -1, strictIndexing: false })
let doc = await workspace.document
doc.forceSync()
return buf
}
describe('configuration', () => {
afterEach(() => {
helper.updateConfiguration('coc.preferences.currentFunctionSymbolAutoUpdate', false)
helper.updateConfiguration('coc.preferences.currentFunctionSymbolAutoUpdate', false)
})
it('should get configuration', async () => {
let functionUpdate = symbols.functionUpdate
expect(functionUpdate).toBe(false)
helper.updateConfiguration('coc.preferences.currentFunctionSymbolAutoUpdate', true)
functionUpdate = symbols.functionUpdate
expect(functionUpdate).toBe(true)
})
it('should update symbols automatically', async () => {
helper.updateConfiguration('coc.preferences.currentFunctionSymbolAutoUpdate', true)
let code = `class myClass {
fun1() {
}
}`
let buf = await createBuffer(code)
await nvim.call('cursor', [2, 8])
await events.fire('CursorHold', [buf.id])
let val = await buf.getVar('coc_current_function')
expect(val).toBe('fun1')
await nvim.call('cursor', [1, 8])
await events.fire('CursorHold', [buf.id])
val = await buf.getVar('coc_current_function')
expect(val).toBe('myClass')
})
})
describe('documentSymbols', () => {
it('should get symbols of current buffer', async () => {
let code = `class myClass {
fun1() { }
}`
await createBuffer(code)
let res = await helper.plugin.cocAction('documentSymbols')
expect(res.length).toBe(2)
})
it('should get current function symbols', async () => {
let code = `class myClass {
fun1() {
}
fun2() {
}
}
`
await createBuffer(code)
await nvim.call('cursor', [3, 0])
let res = await helper.doAction('getCurrentFunctionSymbol')
expect(res).toBe('fun1')
await nvim.command('normal! G')
res = await helper.doAction('getCurrentFunctionSymbol')
expect(res).toBe('')
})
it('should reset coc_current_function when symbols not exists', async () => {
let code = `class myClass {
fun1() {
}
}`
await createBuffer(code)
await nvim.call('cursor', [3, 0])
let res = await helper.doAction('getCurrentFunctionSymbol')
expect(res).toBe('fun1')
await nvim.command('normal! ggdG')
res = await symbols.getCurrentFunctionSymbol()
expect(res).toBe('')
})
it('should support SymbolInformation', async () => {
disposables.push(languages.registerDocumentSymbolProvider(['*'], {
provideDocumentSymbols: () => {
return [
SymbolInformation.create('root', SymbolKind.Function, Range.create(0, 0, 0, 10)),
SymbolInformation.create('child', SymbolKind.Function, Range.create(0, 0, 0, 10), '', 'root')
]
}
}))
let doc = await helper.createDocument()
let res = await symbols.getDocumentSymbols(doc.bufnr)
expect(res.length).toBe(2)
expect(res[0].text).toBe('root')
expect(res[1].text).toBe('child')
})
})
describe('selectSymbolRange', () => {
it('should show warning when no symbols exists', async () => {
disposables.push(languages.registerDocumentSymbolProvider(['*'], {
provideDocumentSymbols: () => {
return []
}
}))
await helper.createDocument()
await nvim.call('cursor', [3, 0])
await symbols.selectSymbolRange(false, '', ['Function'])
let msg = await helper.getCmdline()
expect(msg).toMatch(/No symbols found/)
})
it('should select symbol range at cursor position', async () => {
let code = `class myClass {
fun1() {
}
}`
let buf = await createBuffer(code)
await nvim.call('cursor', [3, 0])
await helper.doAction('selectSymbolRange', false, '', ['Function', 'Method'])
let mode = await nvim.mode
expect(mode.mode).toBe('v')
let doc = workspace.getDocument(buf.id)
await nvim.input('<esc>')
let res = await workspace.getSelectedRange('v', doc)
expect(res).toEqual({ start: { line: 1, character: 6 }, end: { line: 2, character: 6 } })
})
it('should select inner range', async () => {
let code = `class myClass {
fun1() {
let foo;
}
}`
let buf = await createBuffer(code)
await nvim.call('cursor', [3, 3])
await symbols.selectSymbolRange(true, '', ['Method'])
let mode = await nvim.mode
expect(mode.mode).toBe('v')
let doc = workspace.getDocument(buf.id)
await nvim.input('<esc>')
let res = await workspace.getSelectedRange('v', doc)
expect(res).toEqual({
start: { line: 2, character: 8 }, end: { line: 2, character: 16 }
})
})
it('should reset visualmode when selection not found', async () => {
let code = `class myClass {}`
await createBuffer(code)
await nvim.call('cursor', [1, 1])
await nvim.command('normal! gg0v$')
let mode = await nvim.mode
expect(mode.mode).toBe('v')
await nvim.input('<esc>')
await symbols.selectSymbolRange(true, 'v', ['Method'])
mode = await nvim.mode
expect(mode.mode).toBe('v')
})
it('should select symbol range from select range', async () => {
let code = `class myClass {
fun1() {
}
}`
let buf = await createBuffer(code)
await nvim.call('cursor', [2, 8])
await nvim.command('normal! viw')
await nvim.input('<esc>')
await helper.doAction('selectSymbolRange', false, 'v', ['Class'])
let mode = await nvim.mode
expect(mode.mode).toBe('v')
let doc = workspace.getDocument(buf.id)
await nvim.input('<esc>')
let res = await workspace.getSelectedRange('v', doc)
expect(res).toEqual({ start: { line: 0, character: 0 }, end: { line: 3, character: 4 } })
})
})
describe('cancel', () => {
it('should cancel symbols request on insert', async () => {
let cancelled = false
disposables.push(languages.registerDocumentSymbolProvider([{ language: 'text' }], {
provideDocumentSymbols: (_doc, token) => {
return new Promise(s => {
token.onCancellationRequested(() => {
if (timer) clearTimeout(timer)
cancelled = true
s(undefined)
})
let timer = setTimeout(() => {
s(undefined)
}, 3000)
})
}
}))
let doc = await helper.createDocument('t.txt')
let p = symbols.getDocumentSymbols(doc.bufnr)
setTimeout(async () => {
await nvim.input('i')
}, 500)
await p
expect(cancelled).toBe(true)
})
})
describe('workspaceSymbols', () => {
it('should get workspace symbols', async () => {
disposables.push(languages.registerWorkspaceSymbolProvider({
provideWorkspaceSymbols: (_query, _token) => {
return [SymbolInformation.create('far', SymbolKind.Class, Range.create(0, 0, 0, 0))]
},
resolveWorkspaceSymbol: sym => {
let res = Object.assign({}, sym)
res.location.uri = 'test:///foo'
return res
}
}))
disposables.push(languages.registerWorkspaceSymbolProvider({
provideWorkspaceSymbols: (_query, _token) => {
return [SymbolInformation.create('bar', SymbolKind.Function, Range.create(0, 0, 0, 0))]
}
}))
let res = await symbols.getWorkspaceSymbols('a')
expect(res.length).toBe(2)
let resolved = await symbols.resolveWorkspaceSymbol(res[0])
expect(resolved?.location?.uri).toBe('test:///foo')
})
})
})

22
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/helper.test.ts

@ -1,22 +0,0 @@ @@ -1,22 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import Plugin from '../plugin'
import helper from './helper'
let nvim: Neovim
let plugin: Plugin
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
plugin = helper.plugin
})
describe('Helper', () => {
it('should setup', () => {
expect(nvim).toBeTruthy()
expect(plugin.isReady).toBeTruthy()
})
})
afterAll(async () => {
await helper.shutdown()
})

248
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/helper.ts

@ -1,248 +0,0 @@ @@ -1,248 +0,0 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { Buffer, Neovim, Window } from '@chemzqm/neovim'
import * as cp from 'child_process'
import { EventEmitter } from 'events'
import fs from 'fs'
import os from 'os'
import path from 'path'
import util from 'util'
import attach from '../attach'
import Document from '../model/document'
import Plugin from '../plugin'
import workspace from '../workspace'
import { v4 as uuid } from 'uuid'
import { VimCompleteItem } from '../types'
export interface CursorPosition {
bufnum: number
lnum: number
col: number
}
process.on('uncaughtException', err => {
let msg = 'Uncaught exception: ' + err.stack
console.error(msg)
})
export class Helper extends EventEmitter {
public nvim: Neovim
public proc: cp.ChildProcess
public plugin: Plugin
constructor() {
super()
this.setMaxListeners(99)
}
public setup(): Promise<void> {
const vimrc = path.resolve(__dirname, 'vimrc')
let proc = this.proc = cp.spawn('nvim', ['-u', vimrc, '-i', 'NONE', '--embed'], {
cwd: __dirname
})
let plugin = this.plugin = attach({ proc })
this.nvim = plugin.nvim
this.nvim.uiAttach(160, 80, {}).catch(_e => {
// noop
})
proc.on('exit', () => {
this.proc = null
})
this.nvim.on('notification', (method, args) => {
if (method == 'redraw') {
for (let arg of args) {
let event = arg[0]
this.emit(event, arg.slice(1))
}
}
})
return new Promise(resolve => {
plugin.once('ready', resolve)
})
}
public async shutdown(): Promise<void> {
this.plugin.dispose()
await this.nvim.quit()
if (this.proc) {
this.proc.kill('SIGKILL')
}
await this.wait(60)
}
public async waitPopup(): Promise<void> {
for (let i = 0; i < 40; i++) {
await this.wait(50)
let visible = await this.nvim.call('pumvisible')
if (visible) return
}
throw new Error('timeout after 2s')
}
public async waitFloat(): Promise<number> {
for (let i = 0; i < 40; i++) {
await this.wait(50)
let winid = await this.nvim.call('coc#float#get_float_win')
if (winid) return winid
}
throw new Error('timeout after 2s')
}
public async selectCompleteItem(idx: number): Promise<void> {
await this.nvim.call('nvim_select_popupmenu_item', [idx, true, true, {}])
}
public async doAction(method: string, ...args: any[]): Promise<any> {
return await this.plugin.cocAction(method, ...args)
}
public async reset(): Promise<void> {
let mode = await this.nvim.mode
if (mode.mode != 'n' || mode.blocking) {
await this.nvim.command('stopinsert')
await this.nvim.call('feedkeys', [String.fromCharCode(27), 'in'])
}
await this.nvim.command('silent! %bwipeout!')
await this.wait(80)
}
public async pumvisible(): Promise<boolean> {
let res = await this.nvim.call('pumvisible', []) as number
return res == 1
}
public wait(ms = 30): Promise<void> {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, ms)
})
}
public async visible(word: string, source?: string): Promise<boolean> {
await this.waitPopup()
let context = await this.nvim.getVar('coc#_context') as any
let items = context.candidates
if (!items) return false
let item = items.find(o => o.word == word)
if (!item || !item.user_data) return false
try {
let o = JSON.parse(item.user_data)
if (source && o.source !== source) {
return false
}
} catch (e) {
return false
}
return true
}
public async notVisible(word: string): Promise<boolean> {
let items = await this.getItems()
return items.findIndex(o => o.word == word) == -1
}
public async getItems(): Promise<VimCompleteItem[]> {
let visible = await this.pumvisible()
if (!visible) return []
let context = await this.nvim.getVar('coc#_context') as any
let items = context.candidates
return items || []
}
public async edit(file?: string): Promise<Buffer> {
if (!file || !path.isAbsolute(file)) {
file = path.join(__dirname, file ? file : `${uuid()}`)
}
let escaped = await this.nvim.call('fnameescape', file) as string
await this.nvim.command(`edit ${escaped}`)
await this.wait(60)
let bufnr = await this.nvim.call('bufnr', ['%']) as number
return this.nvim.createBuffer(bufnr)
}
public async createDocument(name?: string): Promise<Document> {
let buf = await this.edit(name)
let doc = workspace.getDocument(buf.id)
if (!doc) return await workspace.document
return doc
}
public async getMarkers(bufnr: number, ns: number): Promise<[number, number, number][]> {
return await this.nvim.call('nvim_buf_get_extmarks', [bufnr, ns, 0, -1, {}]) as [number, number, number][]
}
public async getCmdline(): Promise<string> {
let str = ''
for (let i = 1, l = 70; i < l; i++) {
let ch = await this.nvim.call('screenchar', [79, i])
if (ch == -1) break
str += String.fromCharCode(ch)
}
return str.trim()
}
public updateConfiguration(key: string, value: any): () => void {
let { configurations } = workspace as any
let curr = workspace.getConfiguration(key)
configurations.updateUserConfig({ [key]: value })
return () => {
configurations.updateUserConfig({ [key]: curr })
}
}
public async mockFunction(name: string, result: string | number | any): Promise<void> {
let content = `
function! ${name}(...)
return ${typeof result == 'number' ? result : JSON.stringify(result)}
endfunction
`
let file = await createTmpFile(content)
await this.nvim.command(`source ${file}`)
}
public async items(): Promise<VimCompleteItem[]> {
let context = await this.nvim.getVar('coc#_context')
return context['candidates'] || []
}
public async screenLine(line: number): Promise<string> {
let res = ''
for (let i = 1; i <= 80; i++) {
let ch = await this.nvim.call('screenchar', [line, i])
res = res + String.fromCharCode(ch)
}
return res
}
public async getWinLines(winid: number): Promise<string[]> {
return await this.nvim.eval(`getbufline(winbufnr(${winid}), 1, '$')`) as string[]
}
public async getFloat(): Promise<Window> {
let wins = await this.nvim.windows
let floatWin: Window
for (let win of wins) {
let f = await win.getVar('float')
if (f) floatWin = win
}
return floatWin
}
public async getFloats(): Promise<Window[]> {
let ids = await this.nvim.call('coc#float#get_float_win_list', [])
if (!ids) return []
return ids.map(id => this.nvim.createWindow(id))
}
}
export async function createTmpFile(content: string): Promise<string> {
let tmpFolder = path.join(os.tmpdir(), `coc-${process.pid}`)
if (!fs.existsSync(tmpFolder)) {
fs.mkdirSync(tmpFolder)
}
let filename = path.join(tmpFolder, uuid())
await util.promisify(fs.writeFile)(filename, content, 'utf8')
return filename
}
export default new Helper()

174
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/basicList.test.ts

@ -1,174 +0,0 @@ @@ -1,174 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { URI } from 'vscode-uri'
import { Disposable, Range, Location } from 'vscode-languageserver-protocol'
import BasicList, { getFiletype, PreviewOptions } from '../../list/basic'
import manager from '../../list/manager'
import { ListItem } from '../../types'
import { disposeAll } from '../../util'
import helper from '../helper'
let nvim: Neovim
let disposables: Disposable[] = []
let previewOptions: PreviewOptions
let list: SimpleList
class SimpleList extends BasicList {
public name = 'simple'
public defaultAction: 'preview'
constructor(nvim: Neovim) {
super(nvim)
this.addAction('preview', async (_item, context) => {
await this.preview(previewOptions, context)
})
}
public loadItems(): Promise<ListItem[]> {
return Promise.resolve(['a', 'b', 'c'].map((s, idx) => {
return { label: s, location: Location.create('test:///a', Range.create(idx, 0, idx + 1, 0)) } as ListItem
}))
}
}
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
beforeEach(() => {
list = new SimpleList(nvim)
disposables.push(manager.registerList(list))
})
afterEach(async () => {
disposeAll(disposables)
manager.reset()
await helper.reset()
})
describe('getFiletype()', () => {
it('should get filetype', async () => {
expect(getFiletype('javascriptreact')).toBe('javascript')
expect(getFiletype('typescriptreact')).toBe('typescript')
expect(getFiletype('foo.bar')).toBe('foo')
expect(getFiletype('foo')).toBe('foo')
})
})
describe('BasicList', () => {
async function doPreview(opts: PreviewOptions): Promise<number> {
previewOptions = opts
await manager.start(['--normal', 'simple'])
await manager.session.ui.ready
await manager.doAction('preview')
let res = await nvim.call('coc#list#has_preview') as number
expect(res).toBeGreaterThan(0)
let winid = await nvim.call('win_getid', [res])
return winid
}
describe('preview()', () => {
it('should preview lines', async () => {
await doPreview({ filetype: '', lines: ['foo', 'bar'] })
})
it('should preview with bufname', async () => {
await doPreview({
bufname: 't.js',
filetype: 'typescript',
lines: ['foo', 'bar']
})
})
it('should preview with range highlight', async () => {
let winid = await doPreview({
bufname: 't.js',
filetype: 'typescript',
lines: ['foo', 'bar'],
range: Range.create(0, 0, 0, 3)
})
let res = await nvim.call('getmatches', [winid])
expect(res.length).toBeGreaterThan(0)
})
})
describe('createAction()', () => {
it('should overwrite action', async () => {
let idx: number
list.createAction({
name: 'foo',
execute: () => { idx = 0 }
})
list.createAction({
name: 'foo',
execute: () => { idx = 1 }
})
await manager.start(['--normal', 'simple'])
await manager.session.ui.ready
await manager.doAction('foo')
expect(idx).toBe(1)
})
})
describe('jumpTo()', () => {
it('should jump to uri', async () => {
let uri = URI.file(__filename).toString()
await list.jumpTo(uri, 'edit')
let bufname = await nvim.call('bufname', ['%'])
expect(bufname).toMatch('basicList.test.ts')
})
it('should jump to location', async () => {
let uri = URI.file(__filename).toString()
let loc = Location.create(uri, Range.create(0, 0, 1, 0))
await list.jumpTo(loc, 'edit')
let bufname = await nvim.call('bufname', ['%'])
expect(bufname).toMatch('basicList.test.ts')
})
it('should jump to location with empty range', async () => {
let uri = URI.file(__filename).toString()
let loc = Location.create(uri, Range.create(0, 0, 0, 0))
await list.jumpTo(loc, 'edit')
let bufname = await nvim.call('bufname', ['%'])
expect(bufname).toMatch('basicList.test.ts')
})
})
describe('convertLocation()', () => {
it('should convert uri', async () => {
let uri = URI.file(__filename).toString()
let res = await list.convertLocation(uri)
expect(res.uri).toBe(uri)
})
it('should convert location with line', async () => {
let uri = URI.file(__filename).toString()
let res = await list.convertLocation({ uri, line: 'convertLocation()', text: 'convertLocation' })
expect(res.uri).toBe(uri)
res = await list.convertLocation({ uri, line: 'convertLocation()' })
expect(res.uri).toBe(uri)
})
it('should convert location with custom schema', async () => {
let uri = 'test:///foo'
let res = await list.convertLocation({ uri, line: 'convertLocation()'})
expect(res.uri).toBe(uri)
})
})
describe('quickfix action', () => {
it('should invoke quickfix action', async () => {
list.addLocationActions()
await manager.start(['--normal', 'simple', '-arg'])
await manager.session.ui.ready
await manager.session.ui.selectAll()
await manager.doAction('quickfix')
let res = await nvim.call('getqflist')
expect(res.length).toBeGreaterThan(1)
})
})
})

134
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/commandTask.test.ts

@ -1,134 +0,0 @@ @@ -1,134 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import path from 'path'
import { ListContext, ListTask } from '../../types'
import manager from '../../list/manager'
import helper, { createTmpFile } from '../helper'
import BasicList from '../../list/basic'
import { Disposable } from 'vscode-languageserver-protocol'
import { disposeAll } from '../../util'
class DataList extends BasicList {
public name = 'data'
public async loadItems(_context: ListContext): Promise<ListTask> {
let fsPath = await createTmpFile(`console.log('foo');console.log('');console.log('bar');`)
return this.createCommandTask({
cmd: 'node',
args: [fsPath],
cwd: path.dirname(fsPath),
onLine: line => {
if (!line) return undefined
return {
label: line
}
}
})
}
}
class SleepList extends BasicList {
public name = 'sleep'
public loadItems(_context: ListContext): Promise<ListTask> {
return Promise.resolve(this.createCommandTask({
cmd: 'sleep',
args: ['10'],
cwd: __dirname,
onLine: line => {
return {
label: line
}
}
}))
}
}
class StderrList extends BasicList {
public name = 'stderr'
public async loadItems(_context: ListContext): Promise<ListTask> {
let fsPath = await createTmpFile(`console.error('stderr');console.log('stdout')`)
return Promise.resolve(this.createCommandTask({
cmd: 'node',
args: [fsPath],
cwd: path.dirname(fsPath),
onLine: line => {
return {
label: line
}
}
}))
}
}
class ErrorTask extends BasicList {
public name = 'error'
public async loadItems(_context: ListContext): Promise<ListTask> {
return Promise.resolve(this.createCommandTask({
cmd: 'NOT_EXISTS',
args: [],
cwd: __dirname,
onLine: line => {
return {
label: line
}
}
}))
}
}
let nvim: Neovim
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
disposeAll(disposables)
manager.reset()
await helper.reset()
})
describe('Command task', () => {
it('should not show stderr', async () => {
disposables.push(manager.registerList(new StderrList(nvim)))
await manager.start(['stderr'])
await manager.session.ui.ready
let lines = await nvim.call('getline', [1, '$']) as string[]
expect(lines).toEqual(['stdout'])
})
it('should not show error', async () => {
disposables.push(manager.registerList(new ErrorTask(nvim)))
await manager.start(['error'])
await helper.wait(100)
let res = await helper.getCmdline()
expect(res).toMatch('NOT_EXISTS ENOENT')
})
it('should create command task', async () => {
let list = new DataList(nvim)
disposables.push(manager.registerList(list))
await manager.start(['data'])
await helper.wait(500)
let lines = await nvim.call('getline', [1, '$']) as string[]
expect(lines).toEqual(['foo', 'bar'])
})
it('should stop command task', async () => {
let list = new SleepList(nvim)
disposables.push(manager.registerList(list))
await manager.start(['sleep'])
manager.session.stop()
})
it('should show error for bad key', async () => {
let list = new DataList(nvim)
list.config.fixKey('<X-a>')
await helper.wait(500)
let msg = await helper.getCmdline()
expect(msg).toMatch('not supported')
})
})

32
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/formatting.test.ts

@ -1,32 +0,0 @@ @@ -1,32 +0,0 @@
import { formatPath, UnformattedListItem, formatListItems } from '../../list/formatting'
describe('formatPath()', () => {
it('should format path', async () => {
expect(formatPath('hidden', 'path')).toBe('')
expect(formatPath('full', __filename)).toMatch('formatting.test.ts')
expect(formatPath('short', __filename)).toMatch('formatting.test.ts')
expect(formatPath('filename', __filename)).toMatch('formatting.test.ts')
})
})
describe('formatListItems', () => {
it('should format list items', async () => {
expect(formatListItems(false, [])).toEqual([])
let items: UnformattedListItem[] = [{
label: ['a', 'b', 'c']
}]
expect(formatListItems(false, items)).toEqual([{
label: 'a\tb\tc'
}])
items = [{
label: ['a', 'b', 'c']
}, {
label: ['foo', 'bar', 'go']
}]
expect(formatListItems(true, items)).toEqual([{
label: 'a \tb \tc '
}, {
label: 'foo\tbar\tgo'
}])
})
})

79
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/location.test.ts

@ -1,79 +0,0 @@ @@ -1,79 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import manager from '../../list/manager'
import { Range } from 'vscode-languageserver-protocol'
import events from '../../events'
import helper from '../helper'
let nvim: Neovim
const locations: any[] = [{
filename: __filename,
range: Range.create(0, 0, 0, 6),
text: 'foo'
}, {
filename: __filename,
range: Range.create(2, 0, 2, 6),
text: 'Bar'
}, {
filename: __filename,
range: Range.create(3, 0, 4, 6),
text: 'multiple'
}]
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
await nvim.setVar('coc_jump_locations', locations)
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
manager.reset()
await helper.reset()
await helper.wait(100)
})
describe('list commands', () => {
it('should highlight ranges', async () => {
await manager.start(['--normal', '--auto-preview', 'location'])
await manager.session.ui.ready
await helper.wait(200)
manager.prompt.cancel()
await nvim.command('wincmd k')
let name = await nvim.eval('bufname("%")')
expect(name).toMatch('location.test.ts')
let res = await nvim.call('getmatches')
expect(res.length).toBe(1)
})
it('should change highlight on cursor move', async () => {
await manager.start(['--normal', '--auto-preview', 'location'])
await manager.session.ui.ready
await helper.wait(200)
await nvim.command('exe 2')
let bufnr = await nvim.eval('bufnr("%")')
await events.fire('CursorMoved', [bufnr, [2, 1]])
await helper.wait(300)
await nvim.command('wincmd k')
let res = await nvim.call('getmatches')
expect(res.length).toBe(1)
expect(res[0]['pos1']).toEqual([3, 1, 6])
})
it('should highlight multiple line range', async () => {
await manager.start(['--normal', '--auto-preview', 'location'])
await manager.session.ui.ready
await helper.wait(200)
await nvim.command('exe 3')
let bufnr = await nvim.eval('bufnr("%")')
await events.fire('CursorMoved', [bufnr, [2, 1]])
await helper.wait(300)
await nvim.command('wincmd k')
let res = await nvim.call('getmatches')
expect(res.length).toBe(1)
expect(res[0]['pos1']).toBeDefined()
expect(res[0]['pos2']).toBeDefined()
})
})

509
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/manager.test.ts

@ -1,509 +0,0 @@ @@ -1,509 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import path from 'path'
import manager from '../../list/manager'
import events from '../../events'
import { QuickfixItem, IList, ListItem } from '../../types'
import helper from '../helper'
let nvim: Neovim
const locations: ReadonlyArray<QuickfixItem> = [{
filename: __filename,
col: 2,
lnum: 1,
text: 'foo'
}, {
filename: __filename,
col: 1,
lnum: 2,
text: 'Bar'
}, {
filename: __filename,
col: 1,
lnum: 3,
text: 'option'
}]
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
await nvim.setVar('coc_jump_locations', locations)
})
afterEach(async () => {
manager.reset()
await helper.reset()
})
afterAll(async () => {
await helper.shutdown()
})
describe('list', () => {
describe('events', () => {
it('should cancel and enable prompt', async () => {
let winid = await nvim.call('win_getid')
await manager.start(['location'])
await manager.session.ui.ready
await nvim.call('win_gotoid', [winid])
await helper.wait(50)
let res = await nvim.call('coc#prompt#activated')
expect(res).toBe(0)
await nvim.command('wincmd p')
await helper.wait(50)
res = await nvim.call('coc#prompt#activated')
expect(res).toBe(1)
})
})
describe('list commands', () => {
it('should be activated', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await helper.wait(50)
expect(manager.isActivated).toBe(true)
let line = await nvim.getLine()
expect(line).toMatch(/manager.test.ts/)
})
it('should get list names', () => {
let names = manager.names
expect(names.length > 0).toBe(true)
})
it('should resume list', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await helper.wait(30)
await nvim.eval('feedkeys("j", "in")')
await helper.wait(30)
let line = await nvim.call('line', '.')
expect(line).toBe(2)
await manager.cancel()
await helper.wait(30)
await manager.resume()
await helper.wait(30)
line = await nvim.call('line', '.')
expect(line).toBe(2)
})
it('should not quit list with --no-quit', async () => {
await manager.start(['--normal', '--no-quit', 'location'])
await manager.session.ui.ready
let winnr = await nvim.eval('win_getid()') as number
await manager.doAction()
await helper.wait(100)
let wins = await nvim.windows
let ids = wins.map(o => o.id)
expect(ids).toContain(winnr)
})
it('should do default action for first item', async () => {
await manager.start(['--normal', '--first', 'location'])
await helper.wait(300)
let name = await nvim.eval('bufname("%")') as string
let filename = path.basename(__filename)
expect(name.includes(filename)).toBe(true)
let pos = await nvim.eval('getcurpos()')
expect(pos[1]).toBe(1)
expect(pos[2]).toBe(2)
})
it('should goto next & previous', async () => {
await manager.start(['location'])
await manager.session?.ui.ready
await helper.wait(60)
await manager.doAction()
await manager.cancel()
let bufname = await nvim.eval('expand("%:p")')
expect(bufname).toMatch('manager.test.ts')
await manager.next()
let line = await nvim.call('line', '.')
expect(line).toBe(2)
await helper.wait(60)
await manager.previous()
line = await nvim.call('line', '.')
expect(line).toBe(1)
})
it('should parse arguments', async () => {
await manager.start(['--input=test', '--normal', '--no-sort', '--ignore-case', '--top', '--number-select', '--auto-preview', '--strict', 'location'])
await helper.wait(30)
let opts = manager.session?.listOptions
expect(opts).toEqual({
numberSelect: true,
autoPreview: true,
first: false,
input: 'test',
interactive: false,
matcher: 'strict',
ignorecase: true,
position: 'top',
mode: 'normal',
noQuit: false,
sort: false
})
})
})
describe('list options', () => {
it('should respect input option', async () => {
await manager.start(['--input=foo', 'location'])
await manager.session.ui.ready
await helper.wait(30)
let line = await helper.getCmdline()
expect(line).toMatch('foo')
expect(manager.isActivated).toBe(true)
})
it('should respect regex filter', async () => {
await manager.start(['--input=f.o', '--regex', 'location'])
await helper.wait(200)
let item = await manager.session?.ui.item
expect(item.label).toMatch('foo')
})
it('should respect normal option', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
let line = await helper.getCmdline()
expect(line).toBe('')
})
it('should respect nosort option', async () => {
await manager.start(['--ignore-case', '--no-sort', 'location'])
await manager.session.ui.ready
expect(manager.isActivated).toBe(true)
await nvim.input('oo')
await helper.wait(100)
let line = await nvim.call('getline', ['.'])
expect(line).toMatch('foo')
})
it('should respect ignorecase option', async () => {
await manager.start(['--ignore-case', '--strict', 'location'])
await manager.session.ui.ready
expect(manager.isActivated).toBe(true)
await nvim.input('bar')
await helper.wait(100)
let n = manager.session?.ui.length
expect(n).toBe(1)
let line = await nvim.line
expect(line).toMatch('Bar')
})
it('should respect top option', async () => {
await manager.start(['--top', 'location'])
await manager.session.ui.ready
let nr = await nvim.call('winnr')
expect(nr).toBe(1)
})
it('should respect number select option', async () => {
await manager.start(['--number-select', 'location'])
await manager.session.ui.ready
await helper.wait(100)
await nvim.eval('feedkeys("2", "in")')
await helper.wait(100)
let lnum = locations[1].lnum
let curr = await nvim.call('line', '.')
expect(lnum).toBe(curr)
})
it('should respect auto preview option', async () => {
await manager.start(['--auto-preview', 'location'])
await helper.wait(300)
let previewWinnr = await nvim.call('coc#list#has_preview')
expect(previewWinnr).toBe(2)
let bufnr = await nvim.call('winbufnr', previewWinnr)
let buf = nvim.createBuffer(bufnr)
let name = await buf.name
expect(name).toMatch('manager.test.ts')
await nvim.eval('feedkeys("j", "in")')
await helper.wait(100)
let winnr = await nvim.call('coc#list#has_preview')
expect(winnr).toBe(previewWinnr)
})
it('should respect tab option', async () => {
await manager.start(['--tab', '--auto-preview', 'location'])
await manager.session.ui.ready
await helper.wait(200)
await nvim.command('wincmd l')
let previewwindow = await nvim.eval('w:previewwindow')
expect(previewwindow).toBe(1)
})
})
describe('list configuration', () => {
it('should change indicator', async () => {
helper.updateConfiguration('list.indicator', '>>')
await manager.start(['location'])
await helper.wait(200)
let line = await helper.getCmdline()
expect(line).toMatch('>>')
})
it('should split right for preview window', async () => {
helper.updateConfiguration('list.previewSplitRight', true)
let win = await nvim.window
await manager.start(['location'])
await helper.wait(100)
await manager.doAction('preview')
await helper.wait(100)
manager.prompt.cancel()
await helper.wait(10)
await nvim.call('win_gotoid', [win.id])
await nvim.command('wincmd l')
let curr = await nvim.window
let isPreview = await curr.getVar('previewwindow')
expect(isPreview).toBe(1)
helper.updateConfiguration('list.previewSplitRight', false)
})
it('should toggle selection mode', async () => {
await manager.start(['--normal', 'location'])
await manager.session?.ui.ready
await nvim.input('V')
await helper.wait(30)
await nvim.input('1')
await helper.wait(30)
await nvim.input('j')
await helper.wait(100)
await manager.session?.ui.toggleSelection()
let items = await manager.session?.ui.getItems()
expect(items.length).toBe(2)
})
it('should change next/previous keymap', async () => {
helper.updateConfiguration('list.nextKeymap', '<tab>')
helper.updateConfiguration('list.previousKeymap', '<s-tab>')
await manager.start(['location'])
await manager.session.ui.ready
await helper.wait(100)
await nvim.eval('feedkeys("\\<tab>", "in")')
await helper.wait(100)
let line = await nvim.line
expect(line).toMatch('Bar')
await nvim.eval('feedkeys("\\<s-tab>", "in")')
await helper.wait(100)
line = await nvim.line
expect(line).toMatch('foo')
})
it('should respect mouse events', async () => {
async function setMouseEvent(line: number): Promise<void> {
let winid = manager.session?.ui.winid
await nvim.command(`let v:mouse_winid = ${winid}`)
await nvim.command(`let v:mouse_lnum = ${line}`)
await nvim.command(`let v:mouse_col = 1`)
}
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await helper.wait(100)
await setMouseEvent(1)
await manager.onNormalInput('<LeftMouse>')
await setMouseEvent(2)
await manager.onNormalInput('<LeftDrag>')
await setMouseEvent(3)
await manager.onNormalInput('<LeftRelease>')
await helper.wait(100)
let items = await manager.session?.ui.getItems()
expect(items.length).toBe(3)
})
it('should toggle preview', async () => {
await manager.start(['--normal', '--auto-preview', 'location'])
await manager.session.ui.ready
await helper.wait(100)
await manager.togglePreview()
await helper.wait(100)
await manager.togglePreview()
await helper.wait(100)
let has = await nvim.call('coc#list#has_preview')
expect(has).toBeGreaterThan(0)
})
it('should show help of current list', async () => {
await manager.start(['--normal', '--auto-preview', 'location'])
await helper.wait(200)
await manager.session?.showHelp()
let bufname = await nvim.call('bufname', '%')
expect(bufname).toBe('[LIST HELP]')
})
it('should resolve list item', async () => {
let list: IList = {
name: 'test',
actions: [{
name: 'open', execute: _item => {
// noop
}
}],
defaultAction: 'open',
loadItems: () => Promise.resolve([{ label: 'foo' }, { label: 'bar' }]),
resolveItem: item => {
item.label = item.label.slice(0, 1)
return Promise.resolve(item)
}
}
let disposable = manager.registerList(list)
await manager.start(['--normal', 'test'])
await manager.session.ui.ready
await helper.wait(50)
let line = await nvim.line
expect(line).toBe('f')
disposable.dispose()
})
})
describe('descriptions', () => {
it('should get descriptions', async () => {
let res = manager.descriptions
expect(res).toBeDefined()
expect(res.location).toBeDefined()
})
})
describe('loadItems()', () => {
it('should load items for list', async () => {
let res = await manager.loadItems('location')
expect(res.length).toBeGreaterThan(0)
; (manager as any).lastSession = undefined
manager.toggleMode()
manager.stop()
})
})
describe('onInsertInput()', () => {
it('should handle insert input', async () => {
await manager.onInsertInput('k')
await manager.onInsertInput('<LeftMouse>')
await manager.start(['--number-select', 'location'])
await manager.session.ui.ready
await manager.onInsertInput('1')
await helper.wait(300)
let bufname = await nvim.call('expand', ['%:p'])
expect(bufname).toMatch('manager.test.ts')
})
it('should ignore invalid input', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await manager.onInsertInput('<X-y>')
await manager.onInsertInput(String.fromCharCode(65533))
await manager.onInsertInput(String.fromCharCode(30))
expect(manager.isActivated).toBe(true)
})
it('should ignore <plug> insert', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<plug>x", "in")')
await helper.wait(50)
expect(manager.isActivated).toBe(true)
})
})
describe('parseArgs()', () => {
it('should show error for bad option', async () => {
manager.parseArgs(['$x', 'location'])
let msg = await helper.getCmdline()
expect(msg).toMatch('Invalid list option')
})
it('should show error for option not exists', async () => {
manager.parseArgs(['-xyz', 'location'])
let msg = await helper.getCmdline()
expect(msg).toMatch('Invalid option')
})
it('should show error for interactive with list not support interactive', async () => {
manager.parseArgs(['--interactive', 'location'])
let msg = await helper.getCmdline()
expect(msg).toMatch('not supported')
})
})
describe('resume()', () => {
it('should resume by name', async () => {
await events.fire('FocusGained', [])
await manager.start(['location'])
await manager.session.ui.ready
await helper.wait(50)
await manager.session.hide()
await helper.wait(100)
await manager.resume('location')
expect(manager.isActivated).toBe(true)
})
})
describe('start()', () => {
it('should show error when loadItems throws', async () => {
let list: IList = {
name: 'test',
actions: [{
name: 'open',
execute: (_item: ListItem) => {
}
}],
defaultAction: 'open',
loadItems: () => {
throw new Error('test error')
}
}
manager.registerList(list)
await manager.start(['test'])
await helper.wait(50)
let msg = await helper.getCmdline()
expect(msg).toMatch('test error')
})
})
describe('first(), last()', () => {
it('should get session by name', async () => {
let last: string
let list: IList = {
name: 'test',
actions: [{
name: 'open',
execute: (item: ListItem) => {
last = item.label
}
}],
defaultAction: 'open',
loadItems: () => Promise.resolve([{ label: 'foo' }, { label: 'bar' }])
}
manager.registerList(list)
await manager.start(['test'])
await manager.session.ui.ready
await manager.first('a')
await manager.last('a')
await manager.first('test')
expect(last).toBe('foo')
await manager.last('test')
expect(last).toBe('bar')
})
})
describe('registerList()', () => {
it('should recreat list', async () => {
let list: IList = {
name: 'test',
actions: [{
name: 'open', execute: _item => {
// noop
}
}],
defaultAction: 'open',
loadItems: () => Promise.resolve([{ label: 'foo' }, { label: 'bar' }])
}
manager.registerList(list)
helper.updateConfiguration('list.source.test.defaultAction', 'open')
let disposable = manager.registerList(list)
disposable.dispose()
await helper.wait(30)
let msg = await helper.getCmdline()
expect(msg).toMatch('recreated')
})
})
})

903
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/mappings.test.ts

@ -1,903 +0,0 @@ @@ -1,903 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { CancellationToken } from 'vscode-jsonrpc'
import BasicList from '../../list/basic'
import manager from '../../list/manager'
import window from '../../window'
import { ListContext, IList, ListItem, QuickfixItem } from '../../types'
import helper from '../helper'
class TestList extends BasicList {
public name = 'test'
public timeout = 3000
public text = 'test'
public detail = 'detail'
public loadItems(_context: ListContext, token: CancellationToken): Promise<ListItem[]> {
return new Promise(resolve => {
let timer = setTimeout(() => {
resolve([{ label: this.text }])
}, this.timeout)
token.onCancellationRequested(() => {
if (timer) {
clearTimeout(timer)
resolve([])
}
})
})
}
}
let nvim: Neovim
const locations: ReadonlyArray<QuickfixItem> = [{
filename: __filename,
col: 2,
lnum: 1,
text: 'foo'
}, {
filename: __filename,
col: 1,
lnum: 2,
text: 'Bar'
}, {
filename: __filename,
col: 1,
lnum: 3,
text: 'option'
}]
const lineList: IList = {
name: 'lines',
actions: [{
name: 'open',
execute: async item => {
await window.moveTo({
line: (item as ListItem).data.line,
character: 0
})
// noop
}
}],
defaultAction: 'open',
async loadItems(_context, _token): Promise<ListItem[]> {
let lines = []
for (let i = 0; i < 100; i++) {
lines.push(i.toString())
}
return lines.map((line, idx) => ({
label: line,
data: { line: idx }
}))
}
}
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
await nvim.setVar('coc_jump_locations', locations)
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
manager.reset()
await helper.reset()
})
describe('list normal mappings', () => {
it('should tabopen by t', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("t", "in")')
await helper.wait(100)
let nr = await nvim.call('tabpagenr')
expect(nr).toBe(2)
})
it('should open by <cr>', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<cr>", "in")')
await helper.wait(100)
let bufname = await nvim.call('expand', ['%:p'])
expect(bufname).toMatch('mappings.test.ts')
})
it('should stop by <C-c>', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-c>", "in")')
await helper.wait(50)
let loading = manager.session?.worker.isLoading
expect(loading).toBe(false)
})
it('should jump back by <C-o>', async () => {
let doc = await helper.createDocument()
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-o>", "in")')
await helper.wait(50)
let bufnr = await nvim.call('bufnr', ['%'])
expect(bufnr).toBe(doc.bufnr)
})
it('should scroll preview window by <C-e>, <C-y>', async () => {
await helper.createDocument()
await manager.start(['--auto-preview', '--normal', 'location'])
await manager.session.ui.ready
await helper.wait(100)
let winnr = await nvim.call('coc#list#has_preview') as number
expect(winnr).toBeGreaterThan(0)
let winid = await nvim.call('win_getid', [winnr])
await nvim.eval('feedkeys("\\<C-e>", "in")')
await helper.wait(50)
let res = await nvim.call('getwininfo', [winid])
expect(res[0].topline).toBeGreaterThan(1)
await nvim.eval('feedkeys("\\<C-y>", "in")')
await helper.wait(50)
res = await nvim.call('getwininfo', [winid])
expect(res[0].topline).toBeLessThan(7)
})
it('should insert command by :', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys(":", "in")')
await helper.wait(50)
await nvim.eval('feedkeys("let g:x = 1\\<cr>", "in")')
await helper.wait(50)
let res = await nvim.getVar('x')
expect(res).toBe(1)
})
it('should select action by <tab>', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<tab>", "in")')
await helper.wait(100)
await nvim.input('t')
await helper.wait(300)
let nr = await nvim.call('tabpagenr')
expect(nr).toBe(2)
})
it('should preview by p', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await helper.wait(50)
await nvim.eval('feedkeys("p", "in")')
await helper.wait(200)
let winnr = await nvim.call('coc#list#has_preview')
expect(winnr).toBe(2)
})
it('should stop task by <C-c>', async () => {
let disposable = manager.registerList(new TestList(nvim))
let p = manager.start(['--normal', 'test'])
await helper.wait(200)
await nvim.input('<C-c>')
await helper.wait(200)
await p
let len = manager.session?.ui.length
expect(len).toBe(0)
disposable.dispose()
})
it('should cancel list by <esc>', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<esc>", "in")')
await helper.wait(200)
expect(manager.isActivated).toBe(false)
})
it('should reload list by <C-l>', async () => {
let list = new TestList(nvim)
list.timeout = 0
let disposable = manager.registerList(list)
await manager.start(['--normal', 'test'])
await manager.session.ui.ready
list.text = 'new'
await nvim.input('<C-l>')
await helper.wait(30)
let line = await nvim.line
expect(line).toMatch('new')
disposable.dispose()
})
it('should select all items by <C-a>', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.input('<C-a>')
await helper.wait(30)
let selected = manager.session?.ui.selectedItems
expect(selected.length).toBe(locations.length)
})
it('should toggle selection <space>', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<space>", "in")')
await helper.wait(100)
let selected = manager.session?.ui.selectedItems
expect(selected.length).toBe(1)
await nvim.eval('feedkeys("k", "in")')
await helper.wait(100)
await nvim.eval('feedkeys("\\<space>", "in")')
await helper.wait(100)
selected = manager.session?.ui.selectedItems
expect(selected.length).toBe(0)
})
it('should change to insert mode by i, o, a', async () => {
let keys = ['i', 'I', 'o', 'O', 'a', 'A']
for (let key of keys) {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await helper.wait(50)
await nvim.eval(`feedkeys("${key}", "in")`)
await helper.wait(100)
let mode = manager.prompt.mode
expect(mode).toBe('insert')
}
})
it('should show help by ?', async () => {
await manager.start(['--normal', 'location'])
await helper.wait(30)
await nvim.eval('feedkeys("?", "in")')
await helper.wait(30)
await nvim.input('<CR>')
await helper.wait(100)
let bufname = await nvim.call('bufname', '%')
expect(bufname).toBe('[LIST HELP]')
})
it('should drop by d', async () => {
await manager.start(['--normal', 'location'])
await helper.wait(30)
await nvim.eval('feedkeys("d", "in")')
await helper.wait(100)
let nr = await nvim.call('tabpagenr')
expect(nr).toBe(1)
})
it('should split by s', async () => {
await manager.start(['--normal', 'location'])
await helper.wait(30)
await nvim.eval('feedkeys("s", "in")')
await helper.wait(100)
let nr = await nvim.call('winnr')
expect(nr).toBe(1)
})
})
describe('list insert mappings', () => {
it('should open by <cr>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<cr>", "in")')
await helper.wait(100)
let bufname = await nvim.call('expand', ['%:p'])
expect(bufname).toMatch('mappings.test.ts')
})
it('should paste input by <C-v>', async () => {
await nvim.call('setreg', ['*', 'foo'])
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-v>", "in")')
await helper.wait(100)
let input = manager.prompt.input
expect(input).toBe('foo')
})
it('should insert register content by <C-r>', async () => {
await nvim.call('setreg', ['*', 'foo'])
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-r>", "in")')
await helper.wait(30)
await nvim.eval('feedkeys("*", "in")')
await helper.wait(100)
let input = manager.prompt.input
expect(input).toBe('foo')
await nvim.eval('feedkeys("\\<C-r>", "in")')
await helper.wait(30)
await nvim.eval('feedkeys("<", "in")')
await helper.wait(100)
input = manager.prompt.input
expect(input).toBe('foo')
manager.prompt.reset()
})
it('should cancel by <esc>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<esc>", "in")')
await helper.wait(100)
expect(manager.isActivated).toBe(false)
})
it('should select action by <tab>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await helper.wait(100)
nvim.call('eval', 'feedkeys("\\<tab>", "in")', true)
await helper.wait(100)
await nvim.input('t')
await helper.wait(500)
let pages = await nvim.tabpages
expect(pages.length).toBe(2)
})
it('should select action for visual selected items', async () => {
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await helper.wait(100)
await nvim.input('V')
await helper.wait(30)
await nvim.input('2')
await helper.wait(30)
await nvim.input('j')
await helper.wait(30)
await manager.doAction('tabe')
let nr = await nvim.call('tabpagenr')
expect(nr).toBeGreaterThan(3)
})
it('should stop loading by <C-c>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-c>", "in")')
await helper.wait(100)
expect(manager.isActivated).toBe(true)
})
it('should reload by <C-l>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-l>", "in")')
await helper.wait(100)
expect(manager.isActivated).toBe(true)
})
it('should change to normal mode by <C-o>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-o>", "in")')
await helper.wait(100)
expect(manager.isActivated).toBe(true)
let line = await helper.getCmdline()
expect(line).toBe('')
})
it('should select line by <down> and <up>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<down>", "in")')
await helper.wait(50)
await nvim.eval('feedkeys("\\<up>", "in")')
await helper.wait(50)
expect(manager.isActivated).toBe(true)
let line = await nvim.line
expect(line).toMatch('foo')
})
it('should move cursor by <left> and <right>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("f", "in")')
await helper.wait(10)
await nvim.eval('feedkeys("\\<left>", "in")')
await helper.wait(10)
await nvim.eval('feedkeys("\\<left>", "in")')
await helper.wait(10)
await nvim.eval('feedkeys("a", "in")')
await helper.wait(10)
await nvim.eval('feedkeys("\\<right>", "in")')
await helper.wait(10)
await nvim.eval('feedkeys("\\<right>", "in")')
await helper.wait(10)
await nvim.eval('feedkeys("c", "in")')
await helper.wait(10)
let input = manager.prompt.input
expect(input).toBe('afc')
})
it('should move cursor by <end> and <home>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<home>", "in")')
await helper.wait(30)
await nvim.eval('feedkeys("\\<end>a", "in")')
await helper.wait(30)
let input = manager.prompt.input
expect(input).toBe('a')
})
it('should move cursor by <PageUp> <PageDown> <C-d>', async () => {
let disposable = manager.registerList(lineList)
await manager.start(['lines'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<PageDown>", "in")')
await helper.wait(100)
let line = await nvim.eval('line(".")')
expect(line).toBeGreaterThan(1)
await nvim.eval('feedkeys("\\<PageUp>", "in")')
await helper.wait(100)
await nvim.eval('feedkeys("\\<C-d>", "in")')
await helper.wait(100)
disposable.dispose()
})
it('should scroll window by <C-f> and <C-b>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await helper.wait(30)
await nvim.eval('feedkeys("\\<C-f>", "in")')
await helper.wait(100)
await nvim.eval('feedkeys("\\<C-b>", "in")')
await helper.wait(100)
})
it('should change input by <Backspace>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("f", "in")')
await helper.wait(30)
await nvim.eval('feedkeys("\\<Backspace>", "in")')
await helper.wait(30)
let input = manager.prompt.input
expect(input).toBe('')
})
it('should change input by <C-x>', async () => {
let revert = helper.updateConfiguration('list.insertMappings', {
'<C-b>': 'prompt:removetail',
})
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("foo", "in")')
await helper.wait(30)
await nvim.eval('feedkeys("\\<C-a>", "in")')
await helper.wait(30)
await nvim.eval('feedkeys("\\<C-b>", "in")')
await helper.wait(30)
let input = manager.prompt.input
revert()
expect(input).toBe('')
})
it('should change input by <C-h>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("f", "in")')
await helper.wait(30)
await nvim.eval('feedkeys("\\<C-h>", "in")')
await helper.wait(30)
let input = manager.prompt.input
expect(input).toBe('')
})
it('should change input by <C-w>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-w>", "in")')
await helper.wait(30)
await nvim.eval('feedkeys("f", "in")')
await helper.wait(30)
await nvim.eval('feedkeys("a", "in")')
await helper.wait(30)
await nvim.eval('feedkeys("\\<C-w>", "in")')
await helper.wait(30)
let input = manager.prompt.input
expect(input).toBe('')
})
it('should change input by <C-u>', async () => {
await manager.start(['--input=a', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-u>", "in")')
await helper.wait(30)
let input = manager.prompt.input
expect(input).toBe('')
})
it('should change input by <C-n> and <C-p>', async () => {
async function session(input: string): Promise<void> {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("${input}", "in")`)
await helper.wait(100)
await manager.cancel()
}
await session('foo')
await session('bar')
await manager.start(['location'])
await manager.session.ui.ready
await helper.wait(50)
await nvim.eval('feedkeys("\\<C-n>", "in")')
await helper.wait(100)
let input = manager.prompt.input
expect(input.length).toBeGreaterThan(0)
await nvim.eval('feedkeys("\\<C-p>", "in")')
await helper.wait(100)
input = manager.prompt.input
expect(input.length).toBeGreaterThan(0)
})
it('should change matcher by <C-s>', async () => {
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-s>", "in")')
await helper.wait(10)
let matcher = manager.session?.listOptions.matcher
expect(matcher).toBe('strict')
await nvim.eval('feedkeys("\\<C-s>", "in")')
await helper.wait(10)
matcher = manager.session?.listOptions.matcher
expect(matcher).toBe('regex')
await nvim.eval('feedkeys("f", "in")')
await helper.wait(30)
let len = manager.session?.ui.length
expect(len).toBeGreaterThan(0)
})
})
describe('evalExpression', () => {
it('should throw for bad expression', async () => {
let revert = helper.updateConfiguration('list.normalMappings', {
t: 'expr',
})
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("t", "in")')
await helper.wait(30)
revert()
let msg = await helper.getCmdline()
expect(msg).toMatch('Invalid list mapping expression')
})
it('should show help', async () => {
helper.updateConfiguration('list.normalMappings', {
t: 'do:help',
})
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("t", "in")')
await helper.wait(50)
let bufname = await nvim.call('bufname', ['%'])
expect(bufname).toMatch('[LIST HELP]')
})
it('should exit list', async () => {
helper.updateConfiguration('list.normalMappings', {
t: 'do:exit',
})
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("t", "in")')
await helper.wait(50)
expect(manager.isActivated).toBe(false)
})
it('should cancel prompt', async () => {
helper.updateConfiguration('list.normalMappings', {
t: 'do:cancel',
})
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("t", "in")')
await helper.wait(50)
let res = await nvim.call('coc#prompt#activated')
expect(res).toBe(0)
})
it('should jump back', async () => {
let doc = await helper.createDocument()
helper.updateConfiguration('list.normalMappings', {
t: 'do:jumpback',
})
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("t", "in")')
await helper.wait(50)
let bufnr = await nvim.call('bufnr', ['%'])
expect(bufnr).toBe(doc.bufnr)
})
it('should invoke normal command', async () => {
let revert = helper.updateConfiguration('list.normalMappings', {
x: 'normal!:G'
})
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("x", "in")`)
await helper.wait(50)
revert()
let lnum = await nvim.call('line', ['.'])
expect(lnum).toBeGreaterThan(1)
})
it('should toggle, scroll preview', async () => {
let revert = helper.updateConfiguration('list.normalMappings', {
'<space>': 'do:toggle',
a: 'do:toggle',
b: 'do:previewtoggle',
c: 'do:previewup',
d: 'do:previewdown',
e: 'prompt:insertregister',
f: 'do:stop',
g: 'do:togglemode',
})
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys(" ", "in")`)
await helper.wait(50)
for (let key of ['a', 'b', 'c', 'd', 'e', 'f', 'g']) {
await nvim.eval(`feedkeys("${key}", "in")`)
await helper.wait(50)
}
revert()
expect(manager.isActivated).toBe(true)
})
it('should show error when action not exists', async () => {
helper.updateConfiguration('list.normalMappings', {
t: 'do:invalid',
})
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("t", "in")')
await helper.wait(50)
let cmd = await helper.getCmdline()
expect(cmd).toMatch('not supported')
})
it('should show error when prompt action not exists', async () => {
helper.updateConfiguration('list.normalMappings', {
t: 'prompt:invalid',
})
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("t", "in")')
await helper.wait(50)
let cmd = await helper.getCmdline()
expect(cmd).toMatch('not supported')
})
it('should show error for invalid expression ', async () => {
helper.updateConfiguration('list.normalMappings', {
t: 'x:y',
})
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("t", "in")')
await helper.wait(50)
let cmd = await helper.getCmdline()
expect(cmd).toMatch('Invalid expression')
})
})
describe('User mappings', () => {
it('should show warning for invalid key', async () => {
let revert = helper.updateConfiguration('list.insertMappings', {
xy: 'action:tabe',
})
await helper.wait(30)
let msg = await helper.getCmdline()
revert()
await nvim.command('echo ""')
expect(msg).toMatch('Invalid list mappings key')
revert = helper.updateConfiguration('list.insertMappings', {
'<M-x>': 'action:tabe',
})
await helper.wait(30)
msg = await helper.getCmdline()
revert()
expect(msg).toMatch('Invalid list mappings key')
})
it('should execute action keymap', async () => {
await helper.wait(200)
let revert = helper.updateConfiguration('list.insertMappings', {
'<C-d>': 'action:tabe',
})
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("\\<C-d>", "in")`)
await helper.wait(200)
let nr = await nvim.call('tabpagenr')
expect(nr).toBe(2)
revert()
})
it('should execute expr keymap', async () => {
await helper.mockFunction('TabOpen', 'tabe')
helper.updateConfiguration('list.insertMappings', {
'<C-t>': 'expr:TabOpen',
})
helper.updateConfiguration('list.normalMappings', {
t: 'expr:TabOpen',
})
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("\\<C-t>", "in")`)
await helper.wait(100)
let nr = await nvim.call('tabpagenr')
expect(nr).toBe(2)
await manager.start(['--normal', 'location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("t", "in")`)
await helper.wait(100)
nr = await nvim.call('tabpagenr')
expect(nr).toBe(3)
})
it('should execute do mappings', async () => {
helper.updateConfiguration('list.previousKeymap', '<c-j>')
helper.updateConfiguration('list.nextKeymap', '<c-k>')
helper.updateConfiguration('list.insertMappings', {
'<C-r>': 'do:refresh',
'<C-a>': 'do:selectall',
'<C-s>': 'do:switch',
'<C-l>': 'do:cancel',
'<C-t>': 'do:toggle',
'<C-n>': 'do:next',
'<C-p>': 'do:previous',
'<C-x>': 'do:defaultaction',
'<C-h>': 'do:help',
'<C-d>': 'do:exit',
'<C-b>': 'do:toggleMode'
})
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-r>", "in")')
await helper.wait(30)
expect(manager.isActivated).toBe(true)
await nvim.eval('feedkeys("\\<C-a>", "in")')
await helper.wait(30)
expect(manager.session?.ui.selectedItems.length).toBe(locations.length)
await nvim.eval('feedkeys("\\<C-s>", "in")')
await helper.wait(30)
expect(manager.session?.listOptions.matcher).toBe('strict')
await nvim.eval('feedkeys("\\<C-n>", "in")')
await helper.wait(30)
let item = await manager.session?.ui.item
expect(item.label).toMatch(locations[1].text)
await nvim.eval('feedkeys("\\<C-p>", "in")')
await helper.wait(30)
item = await manager.session?.ui.item
expect(item.label).toMatch(locations[0].text)
await nvim.eval('feedkeys("\\<C-x>", "in")')
await helper.wait(30)
expect(manager.isActivated).toBe(false)
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-l>", "in")')
await helper.wait(50)
let res = await nvim.call('coc#prompt#activated')
expect(res).toBe(0)
await manager.session.hide()
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("?", "in")')
await helper.wait(30)
await nvim.input('<CR>')
await manager.cancel()
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-d>", "in")')
await helper.wait(100)
expect(manager.isActivated).toBe(false)
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval('feedkeys("\\<C-b>", "in")')
await helper.wait(100)
expect(manager.isActivated).toBe(true)
await nvim.call('coc#prompt#stop_prompt', ['list'])
}, 20000)
it('should execute prompt mappings', async () => {
helper.updateConfiguration('list.insertMappings', {
'<C-p>': 'prompt:previous',
'<C-n>': 'prompt:next',
'<C-a>': 'prompt:start',
'<C-e>': 'prompt:end',
'<Left>': 'prompt:left',
'<Right>': 'prompt:right',
'<backspace>': 'prompt:deleteforward',
'<C-x>': 'prompt:deletebackward',
'<C-k>': 'prompt:removetail',
'<C-u>': 'prompt:removeahead',
})
await manager.start(['location'])
await manager.session.ui.ready
for (let key of ['<C-p>', '<C-n>', '<C-a>', '<C-e>', '<Left>', '<Right>', '<backspace>', '<C-x>', '<C-k>', '<C-u>']) {
await nvim.input(key)
await helper.wait(30)
}
expect(manager.isActivated).toBe(true)
})
it('should execute feedkeys keymap', async () => {
helper.updateConfiguration('list.insertMappings', {
'<C-f>': 'feedkeys:\\<C-f>',
})
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("\\<C-f>", "in")`)
await helper.wait(30)
let line = await nvim.call('line', '.')
expect(line).toBe(locations.length)
})
it('should execute normal keymap', async () => {
helper.updateConfiguration('list.insertMappings', {
'<C-g>': 'normal:G',
})
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("\\<C-g>", "in")`)
await helper.wait(30)
let line = await nvim.call('line', '.')
expect(line).toBe(locations.length)
})
it('should execute command keymap', async () => {
helper.updateConfiguration('list.insertMappings', {
'<C-w>': 'command:wincmd p',
})
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("\\<C-w>", "in")`)
await helper.wait(30)
expect(manager.isActivated).toBe(true)
let winnr = await nvim.call('winnr')
expect(winnr).toBe(1)
})
it('should execute call keymap', async () => {
await helper.mockFunction('Test', 1)
helper.updateConfiguration('list.insertMappings', {
'<C-t>': 'call:Test',
})
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("\\<C-t>", "in")`)
await helper.wait(30)
expect(manager.isActivated).toBe(true)
})
it('should insert clipboard register to prompt', async () => {
helper.updateConfiguration('list.insertMappings', {
'<C-r>': 'prompt:paste',
})
await nvim.command('let @* = "foobar"')
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("\\<C-r>", "in")`)
await helper.wait(100)
let { input } = manager.prompt
expect(input).toMatch('foobar')
await nvim.command('let @* = ""')
await nvim.eval(`feedkeys("\\<C-r>", "in")`)
await helper.wait(100)
expect(manager.prompt.input).toMatch('foobar')
})
it('should insert text from default register to prompt', async () => {
helper.updateConfiguration('list.insertMappings', {
'<C-v>': 'eval:@@',
})
await nvim.command('let @@ = "bar"')
await manager.start(['location'])
await manager.session.ui.ready
await nvim.eval(`feedkeys("\\<C-v>", "in")`)
await helper.wait(200)
let { input } = manager.prompt
expect(input).toMatch('bar')
})
})

246
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/session.test.ts

@ -1,246 +0,0 @@ @@ -1,246 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable } from 'vscode-languageserver-protocol'
import BasicList from '../../list/basic'
import manager from '../../list/manager'
import ListSession from '../../list/session'
import { ListItem } from '../../types'
import { disposeAll } from '../../util'
import helper from '../helper'
let labels: string[] = []
let lastItem: string
let lastItems: ListItem[]
class SimpleList extends BasicList {
public name = 'simple'
public detail = 'detail'
public options = [{
name: 'foo',
description: 'foo'
}]
constructor(nvim: Neovim) {
super(nvim)
this.addAction('open', item => {
lastItem = item.label
})
this.addMultipleAction('multiple', items => {
lastItems = items
})
this.addAction('parallel', async () => {
await helper.wait(100)
}, { parallel: true })
this.addAction('reload', item => {
lastItem = item.label
}, { persist: true, reload: true })
}
public loadItems(): Promise<ListItem[]> {
return Promise.resolve(labels.map(s => {
return { label: s } as ListItem
}))
}
}
let nvim: Neovim
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
disposeAll(disposables)
manager.reset()
await helper.reset()
})
describe('list session', () => {
describe('doDefaultAction()', () => {
it('should throw error when default action not exists', async () => {
labels = ['a', 'b', 'c']
let list = new SimpleList(nvim)
list.defaultAction = 'foo'
disposables.push(manager.registerList(list))
await manager.start(['--normal', 'simple'])
let ui = manager.session.ui
await ui.ready
let err
try {
await manager.session.first()
} catch (e) {
err = e
}
expect(err).toBeDefined()
err = null
try {
await manager.session.last()
} catch (e) {
err = e
}
expect(err).toBeDefined()
})
})
describe('doItemAction()', () => {
it('should invoke multiple action', async () => {
labels = ['a', 'b', 'c']
let list = new SimpleList(nvim)
disposables.push(manager.registerList(list))
await manager.start(['--normal', 'simple'])
let ui = manager.session.ui
await ui.ready
await ui.selectAll()
await manager.doAction('multiple')
expect(lastItems.length).toBe(3)
lastItems = undefined
})
it('should invoke parallel action', async () => {
labels = ['a', 'b', 'c']
let list = new SimpleList(nvim)
disposables.push(manager.registerList(list))
await manager.start(['--normal', 'simple'])
let ui = manager.session.ui
await ui.ready
await ui.selectAll()
let d = Date.now()
await manager.doAction('parallel')
expect(Date.now() - d).toBeLessThan(300)
})
it('should invoke reload action', async () => {
labels = ['a', 'b', 'c']
let list = new SimpleList(nvim)
disposables.push(manager.registerList(list))
await manager.start(['--normal', 'simple'])
let ui = manager.session.ui
await ui.ready
labels = ['d', 'e']
await manager.doAction('reload')
await helper.wait(50)
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines).toEqual(['d', 'e'])
})
})
describe('resume()', () => {
it('should do preview on resume', async () => {
labels = ['a', 'b', 'c']
let lastItem
let list = new SimpleList(nvim)
list.actions.push({
name: 'preview',
execute: item => {
lastItem = item
}
})
disposables.push(manager.registerList(list))
await manager.start(['--normal', '--auto-preview', 'simple'])
let ui = manager.session.ui
await ui.ready
await ui.selectLines(1, 2)
await helper.wait(50)
await nvim.call('coc#window#close', [ui.winid])
await helper.wait(100)
await manager.session.resume()
await helper.wait(100)
expect(lastItem).toBeDefined()
})
})
describe('jumpBack()', () => {
it('should jump back', async () => {
let win = await nvim.window
labels = ['a', 'b', 'c']
let list = new SimpleList(nvim)
disposables.push(manager.registerList(list))
await manager.start(['--normal', 'simple'])
let ui = manager.session.ui
await ui.ready
manager.session.jumpBack()
await helper.wait(50)
let winid = await nvim.call('win_getid')
expect(winid).toBe(win.id)
})
})
describe('doNumberSelect()', () => {
async function create(len: number): Promise<ListSession> {
labels = []
for (let i = 0; i < len; i++) {
let code = 'a'.charCodeAt(0) + i
labels.push(String.fromCharCode(code))
}
let list = new SimpleList(nvim)
disposables.push(manager.registerList(list))
await manager.start(['--normal', '--number-select', 'simple'])
let ui = manager.session.ui
await ui.ready
return manager.session
}
it('should return false for invalid number', async () => {
let session = await create(5)
let res = await session.doNumberSelect('a')
expect(res).toBe(false)
res = await session.doNumberSelect('8')
expect(res).toBe(false)
})
it('should consider 0 as 10', async () => {
let session = await create(15)
let res = await session.doNumberSelect('0')
expect(res).toBe(true)
expect(lastItem).toBe('j')
})
})
})
describe('showHelp()', () => {
it('should show description and options in help', async () => {
labels = ['a', 'b', 'c']
let list = new SimpleList(nvim)
disposables.push(manager.registerList(list))
await manager.start(['--normal', 'simple'])
let ui = manager.session.ui
await ui.ready
await manager.session.showHelp()
let lines = await nvim.call('getline', [1, '$'])
expect(lines.indexOf('DESCRIPTION')).toBeGreaterThan(0)
expect(lines.indexOf('ARGUMENTS')).toBeGreaterThan(0)
})
})
describe('chooseAction()', () => {
it('should filter actions not have shortcuts', async () => {
labels = ['a', 'b', 'c']
let list = new SimpleList(nvim)
list.actions.push({
name: 'a',
execute: () => {
}
})
list.actions.push({
name: 'b',
execute: () => {
}
})
list.actions.push({
name: 'ab',
execute: () => {
}
})
disposables.push(manager.registerList(list))
await manager.start(['--normal', 'simple'])
let ui = manager.session.ui
await ui.ready
let p = manager.session.chooseAction()
await helper.wait(100)
await nvim.input('a')
await p
})
})

203
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/sources.test.ts

@ -1,203 +0,0 @@ @@ -1,203 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { ListContext, ListItem, ListArgument } from '../../types'
import manager from '../../list/manager'
import languages from '../../languages'
import helper from '../helper'
import workspace from '../../workspace'
import { CancellationToken } from 'vscode-jsonrpc'
import { Location, Range } from 'vscode-languageserver-types'
import BasicList from '../../list/basic'
let listItems: ListItem[] = []
class OptionList extends BasicList {
public name = 'option'
public options: ListArgument[] = [{
name: '-w, -word',
description: 'word'
}, {
name: '-i, -input INPUT',
hasValue: true,
description: 'input'
}]
constructor(nvim) {
super(nvim)
this.addLocationActions()
}
public loadItems(_context: ListContext, _token: CancellationToken): Promise<ListItem[]> {
return Promise.resolve(listItems)
}
}
jest.setTimeout(3000)
let nvim: Neovim
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
manager.dispose()
await helper.shutdown()
})
afterEach(async () => {
manager.reset()
await helper.reset()
await helper.wait(100)
})
describe('BasicList', () => {
describe('parse arguments', () => {
it('should parse args #1', () => {
let list = new OptionList(nvim)
let res = list.parseArguments(['-w'])
expect(res).toEqual({ word: true })
})
it('should parse args #2', () => {
let list = new OptionList(nvim)
let res = list.parseArguments(['-word'])
expect(res).toEqual({ word: true })
})
it('should parse args #3', () => {
let list = new OptionList(nvim)
let res = list.parseArguments(['-input', 'foo'])
expect(res).toEqual({ input: 'foo' })
})
})
describe('preview()', () => {
it('should preview sketch buffer', async () => {
await nvim.command('new')
await nvim.setLine('foo')
let buffer = await nvim.buffer
await helper.wait(30)
let doc = workspace.getDocument(buffer.id)
expect(doc.uri).toMatch('untitled')
let list = new OptionList(nvim)
listItems.push({
label: 'foo',
location: Location.create(doc.uri, Range.create(0, 0, 0, 0))
})
let disposable = manager.registerList(list)
await manager.start(['option'])
await helper.wait(100)
await manager.doAction('preview')
await helper.wait(100)
await nvim.command('wincmd p')
let win = await nvim.window
let isPreview = await win.getVar('previewwindow')
expect(isPreview).toBe(1)
let line = await nvim.line
expect(line).toBe('foo')
disposable.dispose()
})
})
})
describe('list sources', () => {
describe('commands', () => {
it('should load commands source', async () => {
await manager.start(['commands'])
await helper.wait(100)
expect(manager.isActivated).toBe(true)
})
it('should do run action', async () => {
await manager.start(['commands'])
await helper.wait(100)
await manager.doAction()
})
})
describe('diagnostics', () => {
it('should load diagnostics source', async () => {
await manager.start(['diagnostics'])
await manager.session?.ui.ready
await helper.wait(100)
expect(manager.isActivated).toBe(true)
})
})
describe('extensions', () => {
it('should load extensions source', async () => {
await manager.start(['extensions'])
await manager.session?.ui.ready
await helper.wait(100)
expect(manager.isActivated).toBe(true)
})
})
describe('folders', () => {
it('should load folders source', async () => {
await manager.start(['folders'])
await manager.session?.ui.ready
await helper.wait(100)
expect(manager.isActivated).toBe(true)
})
})
describe('lists', () => {
it('should load lists source', async () => {
await manager.start(['lists'])
await manager.session?.ui.ready
await helper.wait(100)
expect(manager.isActivated).toBe(true)
})
})
describe('outline', () => {
it('should load outline source', async () => {
await manager.start(['outline'])
await manager.session?.ui.ready
await helper.wait(100)
expect(manager.isActivated).toBe(true)
})
})
describe('services', () => {
it('should load services source', async () => {
await manager.start(['services'])
await manager.session?.ui.ready
await helper.wait(100)
expect(manager.isActivated).toBe(true)
})
})
describe('sources', () => {
it('should load sources source', async () => {
await manager.start(['sources'])
await manager.session?.ui.ready
await helper.wait(100)
expect(manager.isActivated).toBe(true)
})
})
describe('symbols', () => {
it('should load symbols source', async () => {
let disposable = languages.registerWorkspaceSymbolProvider({
provideWorkspaceSymbols: () => []
})
await manager.start(['symbols'])
await manager.session?.ui.ready
await helper.wait(100)
expect(manager.isActivated).toBe(true)
disposable.dispose()
})
})
describe('links', () => {
it('should load links source', async () => {
let disposable = languages.registerDocumentLinkProvider([{ scheme: 'file' }, { scheme: 'untitled' }], {
provideDocumentLinks: () => []
})
await manager.start(['links'])
await manager.session?.ui.ready
await helper.wait(100)
expect(manager.isActivated).toBe(true)
disposable.dispose()
})
})
})

140
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/ui.test.ts

@ -1,140 +0,0 @@ @@ -1,140 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable } from 'vscode-languageserver-protocol'
import BasicList from '../../list/basic'
import events from '../../events'
import manager from '../../list/manager'
import { ListItem } from '../../types'
import { disposeAll } from '../../util'
import helper from '../helper'
let labels: string[] = []
let lastItem: string
class SimpleList extends BasicList {
public name = 'simple'
constructor(nvim: Neovim) {
super(nvim)
this.addAction('open', item => {
lastItem = item.label
})
}
public loadItems(): Promise<ListItem[]> {
return Promise.resolve(labels.map(s => {
return { label: s, ansiHighlights: [{ span: [0, 1], hlGroup: 'Search' }] } as ListItem
}))
}
}
let nvim: Neovim
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
disposeAll(disposables)
manager.reset()
await helper.reset()
})
describe('list ui', () => {
describe('selectLines()', () => {
it('should select lines', async () => {
labels = ['foo', 'bar']
disposables.push(manager.registerList(new SimpleList(nvim)))
await manager.start(['simple'])
let ui = manager.session.ui
await ui.ready
await ui.selectLines(3, 1)
let buf = await nvim.buffer
let res = await buf.getSigns({ group: 'coc-list' })
expect(res.length).toBe(2)
})
})
describe('resume()', () => {
it('should resume with selected lines', async () => {
labels = ['foo', 'bar']
disposables.push(manager.registerList(new SimpleList(nvim)))
await manager.start(['simple'])
let ui = manager.session.ui
await ui.ready
await ui.selectLines(1, 2)
await nvim.call('coc#window#close', [ui.winid])
await helper.wait(100)
await manager.session.resume()
await helper.wait(100)
let buf = await nvim.buffer
let res = await buf.getSigns({ group: 'coc-list' })
expect(res.length).toBe(2)
})
})
describe('events', () => {
async function mockMouse(winid: number, lnum: number): Promise<void> {
await nvim.command(`let v:mouse_winid = ${winid}`)
await nvim.command(`let v:mouse_lnum = ${lnum}`)
await nvim.command('let v:mouse_col = 1')
}
it('should fire action on double click', async () => {
labels = ['foo', 'bar']
disposables.push(manager.registerList(new SimpleList(nvim)))
await manager.start(['simple'])
let ui = manager.session.ui
await ui.ready
await mockMouse(ui.winid, 1)
await manager.session.onMouseEvent('<2-LeftMouse>')
await helper.wait(100)
expect(lastItem).toBe('foo')
})
it('should select clicked line', async () => {
labels = ['foo', 'bar']
disposables.push(manager.registerList(new SimpleList(nvim)))
await manager.start(['simple'])
let ui = manager.session.ui
await ui.ready
await mockMouse(ui.winid, 2)
await ui.onMouse('mouseDown')
await helper.wait(50)
await mockMouse(ui.winid, 2)
await ui.onMouse('mouseUp')
await helper.wait(50)
let item = await ui.item
expect(item.label).toBe('bar')
})
it('should jump to original window on click', async () => {
labels = ['foo', 'bar']
let win = await nvim.window
disposables.push(manager.registerList(new SimpleList(nvim)))
await manager.start(['simple'])
let ui = manager.session.ui
await ui.ready
await mockMouse(win.id, 1)
await ui.onMouse('mouseUp')
await helper.wait(50)
let curr = await nvim.window
expect(curr.id).toBe(win.id)
})
it('should highlights items on CursorMoved', async () => {
labels = (new Array(400)).fill('a')
disposables.push(manager.registerList(new SimpleList(nvim)))
await manager.start(['simple', '--normal'])
let ui = manager.session.ui
await ui.ready
await nvim.call('cursor', [350, 1])
await events.fire('CursorMoved', [ui.bufnr, [350, 1]])
await helper.wait(300)
let res = await nvim.call('getmatches')
expect(res.length).toBeGreaterThan(300)
})
})
})

204
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/list/worker.test.ts

@ -1,204 +0,0 @@ @@ -1,204 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import manager from '../../list/manager'
import { parseInput } from '../../list/worker'
import helper from '../helper'
import { ListContext, ListTask, ListItem } from '../../types'
import { CancellationToken, Disposable } from 'vscode-languageserver-protocol'
import { EventEmitter } from 'events'
import colors from 'colors/safe'
import BasicList from '../../list/basic'
import { disposeAll } from '../../util'
let items: ListItem[] = []
class DataList extends BasicList {
public name = 'data'
public loadItems(): Promise<ListItem[]> {
return Promise.resolve(items)
}
}
class IntervalTaskList extends BasicList {
public name = 'task'
public timeout = 3000
public loadItems(_context: ListContext, token: CancellationToken): Promise<ListTask> {
let emitter: any = new EventEmitter()
let i = 0
let interval = setInterval(() => {
emitter.emit('data', { label: i.toFixed() })
i++
}, 50)
emitter.dispose = () => {
clearInterval(interval)
emitter.emit('end')
}
token.onCancellationRequested(() => {
emitter.dispose()
})
return emitter
}
}
class DelayTask extends BasicList {
public name = 'delay'
public interactive = true
public loadItems(_context: ListContext, token: CancellationToken): Promise<ListTask> {
let emitter: any = new EventEmitter()
let disposed = false
setTimeout(() => {
if (disposed) return
emitter.emit('data', { label: 'ahead' })
}, 100)
setTimeout(() => {
if (disposed) return
emitter.emit('data', { label: 'abort' })
}, 200)
emitter.dispose = () => {
disposed = true
emitter.emit('end')
}
token.onCancellationRequested(() => {
emitter.dispose()
})
return emitter
}
}
class InteractiveList extends BasicList {
public name = 'test'
public interactive = true
public loadItems(context: ListContext, _token: CancellationToken): Promise<ListItem[]> {
return Promise.resolve([{
label: colors.magenta(context.input || '')
}])
}
}
class ErrorList extends BasicList {
public name = 'error'
public interactive = true
public loadItems(_context: ListContext, _token: CancellationToken): Promise<ListItem[]> {
return Promise.reject(new Error('test error'))
}
}
class ErrorTaskList extends BasicList {
public name = 'task'
public loadItems(_context: ListContext, _token: CancellationToken): Promise<ListTask> {
let emitter: any = new EventEmitter()
let timeout = setTimeout(() => {
emitter.emit('error', new Error('task error'))
}, 100)
emitter.dispose = () => {
clearTimeout(timeout)
}
return emitter
}
}
let nvim: Neovim
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
disposeAll(disposables)
manager.reset()
await helper.reset()
})
describe('parseInput', () => {
it('should parse input with space', async () => {
let res = parseInput('a b')
expect(res).toEqual(['a', 'b'])
})
it('should parse input with escaped space', async () => {
let res = parseInput('a\\ b')
expect(res).toEqual(['a b'])
})
})
describe('list worker', () => {
it('should work with long running task', async () => {
disposables.push(manager.registerList(new IntervalTaskList(nvim)))
await manager.start(['task'])
await helper.wait(300)
let len = manager.session?.length
expect(len > 2).toBe(true)
await manager.cancel()
})
it('should sort by sortText', async () => {
items = [{
label: 'abc',
sortText: 'b'
}, {
label: 'ade',
sortText: 'a'
}]
disposables.push(manager.registerList(new DataList(nvim)))
await manager.start(['data'])
await helper.wait(100)
await nvim.input('a')
await helper.wait(100)
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines).toEqual(['ade', 'abc'])
await manager.cancel()
})
it('should cancel task by use CancellationToken', async () => {
disposables.push(manager.registerList(new IntervalTaskList(nvim)))
await manager.start(['task'])
expect(manager.session?.worker.isLoading).toBe(true)
await helper.wait(100)
manager.session?.stop()
expect(manager.session?.worker.isLoading).toBe(false)
})
it('should render slow interactive list', async () => {
disposables.push(manager.registerList(new DelayTask(nvim)))
await manager.start(['delay'])
await nvim.input('a')
await helper.wait(600)
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines).toEqual(['ahead', 'abort'])
})
it('should work with interactive list', async () => {
disposables.push(manager.registerList(new InteractiveList(nvim)))
await manager.start(['-I', 'test'])
await manager.session?.ui.ready
expect(manager.isActivated).toBe(true)
await nvim.eval('feedkeys("f", "in")')
await helper.wait(100)
await nvim.eval('feedkeys("a", "in")')
await helper.wait(100)
await nvim.eval('feedkeys("x", "in")')
await helper.wait(300)
let item = await manager.session?.ui.item
expect(item.label).toBe('fax')
})
it('should not activate on load error', async () => {
disposables.push(manager.registerList(new ErrorList(nvim)))
await manager.start(['test'])
expect(manager.isActivated).toBe(false)
})
it('should deactivate on task error', async () => {
disposables.push(manager.registerList(new ErrorTaskList(nvim)))
await manager.start(['task'])
await helper.wait(500)
expect(manager.isActivated).toBe(false)
})
})

151
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/markdown/index.test.ts

@ -1,151 +0,0 @@ @@ -1,151 +0,0 @@
import { getHighlightItems, parseMarkdown, parseDocuments } from '../../markdown/index'
describe('getHighlightItems', () => {
it('should get highlights in single line', async () => {
let res = getHighlightItems('this line has highlights', 0, [10, 15])
expect(res).toEqual([{
colStart: 10,
colEnd: 15,
lnum: 0,
hlGroup: 'CocUnderline'
}])
})
it('should get highlights when active end extended', async () => {
let res = getHighlightItems('this line', 0, [5, 30])
expect(res).toEqual([{
colStart: 5,
colEnd: 9,
lnum: 0,
hlGroup: 'CocUnderline'
}])
})
it('should get highlights across line', async () => {
let res = getHighlightItems('this line\nhas highlights', 0, [5, 15])
expect(res).toEqual([{
colStart: 5, colEnd: 9, lnum: 0, hlGroup: 'CocUnderline'
}, {
colStart: 0, colEnd: 5, lnum: 1, hlGroup: 'CocUnderline'
}])
})
})
describe('parseMarkdown', () => {
it('should parse code blocks', async () => {
let content = `
\`\`\`js
var global = globalThis
\`\`\`
\`\`\`ts
let str:string
\`\`\`
`
let res = parseMarkdown(content, {})
expect(res.lines).toEqual([
'var global = globalThis',
'',
'let str:string'
])
expect(res.codes).toEqual([
{ filetype: 'javascript', startLine: 0, endLine: 1 },
{ filetype: 'typescript', startLine: 2, endLine: 3 }
])
})
it('should parse html code block', async () => {
let content = `
example:
\`\`\`html
<div>code</div>
\`\`\`
`
let res = parseMarkdown(content, {})
expect(res.lines).toEqual(['example:', '', '<div>code</div>'])
expect(res.codes).toEqual([{ filetype: 'html', startLine: 2, endLine: 3 }])
})
it('should compose empty lines', async () => {
let content = 'foo\n\n\nbar\n\n\n'
let res = parseMarkdown(content, {})
expect(res.lines).toEqual(['foo', '', 'bar'])
})
it('should parse ansi highlights', async () => {
let content = '__foo__\n[link](link)'
let res = parseMarkdown(content, {})
expect(res.lines).toEqual(['foo', 'link'])
expect(res.highlights).toEqual([
{ hlGroup: 'CocBold', lnum: 0, colStart: 0, colEnd: 3 },
{ hlGroup: 'CocUnderline', lnum: 1, colStart: 0, colEnd: 4 }
])
})
it('should exclude images by option', async () => {
let content = 'head\n![img](img)\ncontent ![img](img) ![img](img)'
let res = parseMarkdown(content, { excludeImages: true })
expect(res.lines).toEqual(['head', '', 'content'])
})
})
describe('parseDocuments', () => {
it('should parse documents with diagnostic filetypes', async () => {
let docs = [{
filetype: 'Error',
content: 'Error text'
}, {
filetype: 'Warning',
content: 'Warning text'
}]
let res = parseDocuments(docs)
expect(res.lines).toEqual([
'Error text',
'─',
'Warning text'
])
expect(res.codes).toEqual([
{ hlGroup: 'CocErrorFloat', startLine: 0, endLine: 1 },
{ hlGroup: 'CocWarningFloat', startLine: 2, endLine: 3 }
])
})
it('should parse markdown document with filetype document', async () => {
let docs = [{
filetype: 'typescript',
content: 'const workspace'
}, {
filetype: 'markdown',
content: '**header**'
}]
let res = parseDocuments(docs)
expect(res.lines).toEqual([
'const workspace',
'─',
'header'
])
expect(res.highlights).toEqual([{
hlGroup: 'CocBold',
lnum: 2,
colStart: 0,
colEnd: 6
}])
expect(res.codes).toEqual([
{ filetype: 'typescript', startLine: 0, endLine: 1 }
])
})
it('should parse documents with active highlights', async () => {
let docs = [{
filetype: 'javascript',
content: 'func(foo, bar)',
active: [5, 8]
}, {
filetype: 'javascript',
content: 'func()',
active: [15, 20]
}]
let res = parseDocuments(docs as any)
expect(res.highlights).toEqual([{ colStart: 5, colEnd: 8, lnum: 0, hlGroup: 'CocUnderline' }
])
})
})

119
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/markdown/renderer.test.ts

@ -1,119 +0,0 @@ @@ -1,119 +0,0 @@
import marked from 'marked'
import Renderer from '../../markdown/renderer'
import * as styles from '../../markdown/styles'
import { parseAnsiHighlights, AnsiResult } from '../../util/ansiparse'
marked.setOptions({
renderer: new Renderer()
})
function parse(text: string): AnsiResult {
let m = marked(text)
let res = parseAnsiHighlights(m.split(/\n/)[0], true)
return res
}
describe('styles', () => {
it('should add styles', async () => {
let keys = ['gray', 'magenta', 'bold', 'underline', 'italic', 'strikethrough', 'yellow', 'green', 'blue']
for (let key of keys) {
let res = styles[key]('text')
expect(res).toContain('text')
}
})
})
describe('Renderer of marked', () => {
it('should create bold highlights', async () => {
let res = parse('**note**.')
expect(res.highlights[0]).toEqual({
span: [0, 4],
hlGroup: 'CocBold'
})
})
it('should create italic highlights', async () => {
let res = parse('_note_.')
expect(res.highlights[0]).toEqual({
span: [0, 4],
hlGroup: 'CocItalic'
})
})
it('should create underline highlights for link', async () => {
let res = parse('[baidu](https://baidu.com)')
expect(res.highlights[0]).toEqual({
span: [0, 5],
hlGroup: 'CocMarkdownLink'
})
res = parse('https://baidu.com')
expect(res.highlights[0]).toEqual({
span: [0, 17],
hlGroup: 'CocUnderline'
})
})
it('should parse link', async () => {
// let res = parse('https://doc.rust-lang.org/nightly/core/iter/traits/iterator/Iterator.t.html#map.v')
// console.log(JSON.stringify(res, null, 2))
let link = 'https://doc.rust-lang.org/nightly/core/iter/traits/iterator/Iterator.t.html#map.v'
let parsed = marked(link)
let res = parseAnsiHighlights(parsed.split(/\n/)[0], true)
expect(res.line).toEqual(link)
expect(res.highlights.length).toBeGreaterThan(0)
expect(res.highlights[0].hlGroup).toBe('CocUnderline')
})
it('should create highlight for code span', async () => {
let res = parse('`let foo = "bar"`')
expect(res.highlights[0]).toEqual({
span: [0, 15],
hlGroup: 'CocMarkdownCode'
})
})
it('should create header highlights', async () => {
let res = parse('# header')
expect(res.highlights[0]).toEqual({
span: [0, 8],
hlGroup: 'CocMarkdownHeader'
})
res = parse('## header')
expect(res.highlights[0]).toEqual({
span: [0, 9],
hlGroup: 'CocMarkdownHeader'
})
res = parse('### header')
expect(res.highlights[0]).toEqual({
span: [0, 10],
hlGroup: 'CocMarkdownHeader'
})
})
it('should indent blockquote', async () => {
let res = parse('> header')
expect(res.line).toBe(' header')
})
it('should preserve code block', async () => {
let text = '``` js\nconsole.log("foo")\n```'
let m = marked(text)
expect(m.split('\n')).toEqual([
'``` js',
'console.log("foo")',
'```',
''
])
})
it('should renderer table', async () => {
let text = `
| Syntax | Description |
| ----------- | ----------- |
| Header | Title |
| Paragraph | Text |
`
let res = marked(text)
expect(res).toContain('Syntax')
})
})

1
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/memos.json

@ -1 +0,0 @@ @@ -1 +0,0 @@
{}

35
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/array.test.ts

@ -1,35 +0,0 @@ @@ -1,35 +0,0 @@
import * as assert from 'assert'
import * as arrays from '../../util/array'
describe('Arrays', () => {
test('distinct', () => {
function compare(a: string): string {
return a
}
assert.deepStrictEqual(arrays.distinct(['32', '4', '5'], compare), ['32', '4', '5'])
assert.deepStrictEqual(arrays.distinct(['32', '4', '5', '4'], compare), ['32', '4', '5'])
assert.deepStrictEqual(arrays.distinct(['32', 'constructor', '5', '1'], compare), ['32', 'constructor', '5', '1'])
assert.deepStrictEqual(arrays.distinct(['32', 'constructor', 'proto', 'proto', 'constructor'], compare), ['32', 'constructor', 'proto'])
assert.deepStrictEqual(arrays.distinct(['32', '4', '5', '32', '4', '5', '32', '4', '5', '5'], compare), ['32', '4', '5'])
})
test('tail', () => {
assert.strictEqual(arrays.tail([1, 2, 3]), 3)
})
test('lastIndex', () => {
let res = arrays.lastIndex([1, 2, 3], x => x < 3)
assert.strictEqual(res, 1)
})
test('flatMap', () => {
let objs: { [key: string]: number[] }[] = [{ x: [1, 2] }, { y: [3, 4] }, { z: [5, 6] }]
function values(item: { [key: string]: number[] }): number[] {
return Object.keys(item).reduce((p, c) => p.concat(item[c]), [])
}
let res = arrays.flatMap(objs, values)
assert.deepStrictEqual(res, [1, 2, 3, 4, 5, 6])
})
})

53
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/attach.test.ts

@ -1,53 +0,0 @@ @@ -1,53 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import events from '../../events'
import helper from '../helper'
function wait(ms: number): Promise<void> {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, ms)
})
}
let nvim: Neovim
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
})
describe('attach', () => {
it('should listen CocInstalled', async () => {
nvim.emit('notification', 'VimEnter')
await helper.wait(100)
})
it('should not throw on event handler error', async () => {
events.on('CursorHold', async () => {
throw new Error('error')
})
let fn = jest.fn()
nvim.emit('request', 'CocAutocmd', ['CursorHold'], {
send: fn
})
await wait(100)
expect(fn).toBeCalled()
})
it('should not throw when plugin method not found', async () => {
let fn = jest.fn()
nvim.emit('request', 'NotExists', [], {
send: fn
})
await wait(100)
expect(fn).toBeCalled()
})
})

78
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/chars.test.ts

@ -1,78 +0,0 @@ @@ -1,78 +0,0 @@
import { Chars } from '../../model/chars'
describe('chars keyword option', () => {
it('should match @', () => {
let chars = new Chars('@')
expect(chars.isKeywordChar('a')).toBe(true)
expect(chars.isKeywordChar('z')).toBe(true)
expect(chars.isKeywordChar('A')).toBe(true)
expect(chars.isKeywordChar('Z')).toBe(true)
})
it('should match letter range', () => {
let chars = new Chars('a-z')
expect(chars.isKeywordChar('a')).toBe(true)
expect(chars.isKeywordChar('A')).toBe(false)
})
it('should match code range', () => {
let chars = new Chars('48-57')
expect(chars.isKeywordChar('a')).toBe(false)
expect(chars.isKeywordChar('0')).toBe(true)
expect(chars.isKeywordChar('9')).toBe(true)
})
it('should match @-@', () => {
let chars = new Chars('@-@')
expect(chars.isKeywordChar('@')).toBe(true)
})
it('should match single code', () => {
let chars = new Chars('58')
expect(chars.isKeywordChar(':')).toBe(true)
})
it('should match single character', () => {
let chars = new Chars('_')
expect(chars.isKeywordChar('_')).toBe(true)
})
})
describe('chars addKeyword', () => {
it('should add keyword', () => {
let chars = new Chars('_')
chars.addKeyword(':')
expect(chars.isKeywordChar(':')).toBe(true)
})
})
describe('chars change keyword', () => {
it('should change keyword', () => {
let chars = new Chars('_')
chars.setKeywordOption(':')
expect(chars.isKeywordChar(':')).toBe(true)
expect(chars.isKeywordChar('_')).toBe(false)
})
})
describe('chars match keywords', () => {
it('should match keywords', () => {
let chars = new Chars('@')
let res = chars.matchKeywords('foo bar')
expect(res).toEqual(['foo', 'bar'])
})
it('should consider unicode character as word', () => {
let chars = new Chars('@')
let res = chars.matchKeywords('blackкофе')
expect(res).toEqual(['blackкофе'])
})
})
describe('chars isKeyword', () => {
it('should check isKeyword', () => {
let chars = new Chars('@')
expect(chars.isKeyword('foo')).toBe(true)
expect(chars.isKeyword('f@')).toBe(false)
})
})

35
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/client.test.ts

@ -1,35 +0,0 @@ @@ -1,35 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import helper from '../helper'
let nvim: Neovim
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
})
describe('node client pauseNotification', () => {
it('should work with notify & request', async () => {
nvim.pauseNotification()
nvim.call('setline', [1, 'foo'], true)
nvim.call('append', [1, ['bar']], true)
await nvim.resumeNotification(false, true)
await helper.wait(500)
let buffer = await nvim.buffer
let lines = await buffer.lines
expect(lines).toEqual(['foo', 'bar'])
nvim.pauseNotification()
nvim.call('eval', ['&buftype'], true)
nvim.call('bufnr', ['%'], true)
let res = await nvim.resumeNotification()
expect(res).toEqual([['', buffer.id], null])
})
})

728
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/completion.test.ts

@ -1,728 +0,0 @@ @@ -1,728 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Disposable } from 'vscode-jsonrpc'
import { CompletionItem, InsertTextFormat, Position, Range, TextEdit, CompletionList } from 'vscode-languageserver-types'
import completion from '../../completion'
import languages from '../../languages'
import { CompletionItemProvider } from '../../provider'
import snippetManager from '../../snippets/manager'
import sources from '../../sources'
import { CompleteOption, CompleteResult, ISource, SourceType } from '../../types'
import { disposeAll } from '../../util'
import workspace from '../../workspace'
import helper from '../helper'
let nvim: Neovim
let disposables: Disposable[] = []
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
beforeEach(async () => {
disposables = []
await helper.createDocument()
await nvim.call('feedkeys', [String.fromCharCode(27), 'in'])
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
describe('completion events', () => {
it('should load preferences', () => {
let minTriggerInputLength = completion.config.minTriggerInputLength
expect(minTriggerInputLength).toBe(1)
})
it('should reload preferences onChange', () => {
let { configurations } = workspace
configurations.updateUserConfig({ 'suggest.maxCompleteItemCount': 30 })
let snippetIndicator = completion.config.maxItemCount
expect(snippetIndicator).toBe(30)
})
})
describe('completion start', () => {
it('should deactivate on doComplete error', async () => {
let fn = (completion as any)._doComplete
; (completion as any)._doComplete = async () => {
throw new Error('fake')
}
let option: CompleteOption = await nvim.call('coc#util#get_complete_option')
await completion.startCompletion(option)
; (completion as any)._doComplete = fn
expect(completion.isActivated).toBe(false)
})
it('should start completion', async () => {
await nvim.setLine('foo football')
await nvim.input('a')
await nvim.call('cursor', [1, 2])
let option: CompleteOption = await nvim.call('coc#util#get_complete_option')
await completion.startCompletion(option)
expect(completion.isActivated).toBe(true)
})
it('should show slow source', async () => {
let source: ISource = {
priority: 0,
enable: true,
name: 'slow',
sourceType: SourceType.Service,
triggerCharacters: ['.'],
doComplete: (_opt: CompleteOption): Promise<CompleteResult> => new Promise(resolve => {
setTimeout(() => {
resolve({ items: [{ word: 'foo' }, { word: 'bar' }] })
}, 600)
})
}
disposables.push(sources.addSource(source))
await helper.edit()
await nvim.input('i.')
await helper.waitPopup()
expect(completion.isActivated).toBe(true)
let items = await helper.items()
expect(items.length).toBe(2)
})
})
describe('completion resumeCompletion', () => {
it('should stop if no filtered items', async () => {
await nvim.setLine('foo ')
await helper.wait(50)
await nvim.input('Af')
await helper.waitPopup()
expect(completion.isActivated).toBe(true)
await nvim.input('d')
await helper.wait(60)
expect(completion.isActivated).toBe(false)
})
it('should deactivate without filtered items', async () => {
await nvim.setLine('foo fbi ')
await nvim.input('Af')
await helper.waitPopup()
await nvim.input('c')
await helper.wait(100)
let items = await helper.items()
expect(items.length).toBe(0)
expect(completion.isActivated).toBe(false)
})
it('should deactivate when insert space', async () => {
let source: ISource = {
priority: 0,
enable: true,
name: 'empty',
sourceType: SourceType.Service,
triggerCharacters: ['.'],
doComplete: (_opt: CompleteOption): Promise<CompleteResult> => new Promise(resolve => {
resolve({ items: [{ word: 'foo bar' }] })
})
}
sources.addSource(source)
await helper.edit()
await nvim.input('i.')
await helper.waitPopup()
expect(completion.isActivated).toBe(true)
sources.removeSource(source)
let items = await helper.items()
expect(items[0].word).toBe('foo bar')
await nvim.input(' ')
await helper.wait(60)
expect(completion.isActivated).toBe(false)
})
it('should use resume input to filter', async () => {
let source: ISource = {
priority: 0,
enable: true,
name: 'source',
sourceType: SourceType.Service,
triggerCharacters: ['.'],
doComplete: (): Promise<CompleteResult> => new Promise(resolve => {
setTimeout(() => {
resolve({ items: [{ word: 'foo' }, { word: 'bar' }] })
}, 60)
})
}
sources.addSource(source)
await helper.edit()
await nvim.input('i.')
await helper.wait(20)
await nvim.input('f')
await helper.waitPopup()
expect(completion.isActivated).toBe(true)
let items = await helper.items()
expect(items.length).toBe(1)
expect(items[0].word).toBe('foo')
sources.removeSource(source)
})
it('should filter slow source', async () => {
let source: ISource = {
priority: 0,
enable: true,
name: 'slow',
sourceType: SourceType.Service,
triggerCharacters: ['.'],
doComplete: (): Promise<CompleteResult> => new Promise(resolve => {
setTimeout(() => {
resolve({ items: [{ word: 'foo' }, { word: 'bar' }] })
}, 600)
})
}
disposables.push(sources.addSource(source))
await helper.edit()
await nvim.input('i.')
await helper.wait(60)
await nvim.input('f')
await helper.waitPopup()
await nvim.input('o')
await helper.wait(100)
expect(completion.isActivated).toBe(true)
let items = await helper.items()
expect(items.length).toBe(1)
expect(items[0].word).toBe('foo')
})
it('should complete inComplete source', async () => {
let source: ISource = {
priority: 0,
enable: true,
name: 'inComplete',
sourceType: SourceType.Service,
triggerCharacters: ['.'],
doComplete: async (opt: CompleteOption): Promise<CompleteResult> => {
await helper.wait(30)
if (opt.input.length <= 1) {
return { isIncomplete: true, items: [{ word: 'foo' }, { word: opt.input }] }
}
return { isIncomplete: false, items: [{ word: 'foo' }, { word: opt.input }] }
}
}
disposables.push(sources.addSource(source))
await helper.edit()
await nvim.input('i.')
await helper.waitPopup()
expect(completion.isActivated).toBe(true)
await nvim.input('a')
await helper.wait(30)
await nvim.input('b')
await helper.wait(100)
})
it('should not complete inComplete source when isIncomplete is false', async () => {
await helper.createDocument()
let lastOption: CompleteOption
let source: ISource = {
priority: 0,
enable: true,
name: 'inComplete',
sourceType: SourceType.Service,
triggerCharacters: ['.'],
doComplete: async (opt: CompleteOption): Promise<CompleteResult> => {
lastOption = opt
await helper.wait(30)
if (opt.input.length <= 1) {
return { isIncomplete: true, items: [{ word: 'foobar' }] }
}
return { isIncomplete: false, items: [{ word: 'foobar' }] }
}
}
disposables.push(sources.addSource(source))
await helper.edit()
await nvim.input('i.')
await helper.waitPopup()
expect(completion.isActivated).toBe(true)
await nvim.input('fo')
await helper.wait(100)
await nvim.input('b')
await helper.wait(200)
expect(completion.isActivated).toBe(true)
})
})
describe('completion InsertEnter', () => {
it('should trigger completion if triggerAfterInsertEnter is true', async () => {
await helper.createDocument()
await nvim.setLine('foo fo')
let config = workspace.getConfiguration('suggest')
config.update('triggerAfterInsertEnter', true)
await helper.wait(100)
let triggerAfterInsertEnter = completion.config.triggerAfterInsertEnter
expect(triggerAfterInsertEnter).toBe(true)
await nvim.input('A')
await helper.waitPopup()
expect(completion.isActivated).toBe(true)
config.update('triggerAfterInsertEnter', undefined)
})
it('should not trigger when input length too small', async () => {
let config = workspace.getConfiguration('suggest')
config.update('triggerAfterInsertEnter', true)
await helper.wait(100)
let triggerAfterInsertEnter = completion.config.triggerAfterInsertEnter
expect(triggerAfterInsertEnter).toBe(true)
await nvim.setLine('foo ')
await nvim.input('A')
await helper.wait(100)
expect(completion.isActivated).toBe(false)
config.update('triggerAfterInsertEnter', undefined)
})
})
describe('completion TextChangedP', () => {
it('should stop when input length below option input length', async () => {
await helper.edit()
await nvim.setLine('foo fbi ')
await nvim.input('Af')
await helper.waitPopup()
await nvim.input('<backspace>')
await helper.wait(100)
expect(completion.isActivated).toBe(false)
})
it('should fix cursor position with plain text on additionalTextEdits', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'foo',
filterText: 'foo',
additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'a\nbar')]
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('if')
await helper.waitPopup()
await helper.selectCompleteItem(0)
await helper.wait(200)
let line = await nvim.line
expect(line).toBe('barfoo')
let [, lnum, col] = await nvim.call('getcurpos')
expect(lnum).toBe(2)
expect(col).toBe(7)
})
it('should filter in complete request', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (doc, pos, token, context): Promise<CompletionList> => {
let option = (context as any).option
if (context.triggerCharacter == '.') {
return {
isIncomplete: true,
items: [
{
label: 'foo'
}, {
label: 'bar'
}
]
}
}
if (option.input == 'f') {
await helper.wait(100)
if (token.isCancellationRequested) return
return {
isIncomplete: true,
items: [
{
label: 'foo'
}
]
}
}
if (option.input == 'fo') {
await helper.wait(100)
if (token.isCancellationRequested) return
return {
isIncomplete: false,
items: [
{
label: 'foo'
}
]
}
}
}
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider, ['.']))
await nvim.input('i.')
await helper.waitPopup()
await nvim.input('f')
await helper.wait(60)
await nvim.input('o')
await helper.wait(300)
let res = await helper.getItems()
expect(res.length).toBe(1)
})
it('should provide word when textEdit after startcol', async () => {
// some LS would send textEdit after first character,
// need fix the word from newText
let provider: CompletionItemProvider = {
provideCompletionItems: async (_, position): Promise<CompletionItem[]> => {
if (position.line != 0) return null
return [{
label: 'bar',
filterText: 'ar',
textEdit: {
range: Range.create(0, 1, 0, 1),
newText: 'ar'
}
}]
}
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('ib')
await helper.waitPopup()
let context = await nvim.getVar('coc#_context') as any
expect(context.start).toBe(1)
expect(context.candidates[0].word).toBe('ar')
})
it('should adjust completion position by textEdit start position', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (_document, _position, _token, context): Promise<CompletionItem[]> => {
if (!context.triggerCharacter) return
return [{
label: 'foo',
textEdit: {
range: Range.create(0, 0, 0, 1),
newText: '?foo'
}
}]
}
}
disposables.push(languages.registerCompletionItemProvider('fix', 'f', null, provider, ['?']))
await nvim.input('i?')
await helper.waitPopup()
await nvim.eval('feedkeys("\\<C-n>", "in")')
await helper.wait(200)
let line = await nvim.line
expect(line).toBe('?foo')
})
it('should fix cursor position with snippet on additionalTextEdits', async () => {
await helper.createDocument()
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'if',
insertTextFormat: InsertTextFormat.Snippet,
textEdit: { range: Range.create(0, 0, 0, 2), newText: 'if($1)' },
additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'bar ')],
preselect: true
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('ii')
await helper.waitPopup()
let res = await helper.getItems()
let idx = res.findIndex(o => o.menu == '[edit]')
await helper.selectCompleteItem(idx)
await helper.wait(800)
let line = await nvim.line
expect(line).toBe('bar if()')
let [, lnum, col] = await nvim.call('getcurpos')
expect(lnum).toBe(1)
expect(col).toBe(8)
})
it('should fix cursor position with plain text snippet on additionalTextEdits', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'if',
insertTextFormat: InsertTextFormat.Snippet,
textEdit: { range: Range.create(0, 0, 0, 2), newText: 'do$0' },
additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'bar ')],
preselect: true
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('iif')
await helper.waitPopup()
await helper.selectCompleteItem(0)
await helper.wait(200)
let line = await nvim.line
let [, lnum, col] = await nvim.call('getcurpos')
expect(line).toBe('bar do')
expect(lnum).toBe(1)
expect(col).toBe(7)
})
it('should fix cursor position with nested snippet on additionalTextEdits', async () => {
await helper.createDocument()
let res = await snippetManager.insertSnippet('func($1)$0')
expect(res).toBe(true)
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'if',
insertTextFormat: InsertTextFormat.Snippet,
insertText: 'do$0',
additionalTextEdits: [TextEdit.insert(Position.create(0, 0), 'bar ')],
preselect: true
}]
}
disposables.push(languages.registerCompletionItemProvider('edits', 'edit', null, provider))
await nvim.input('if')
await helper.waitPopup()
await helper.selectCompleteItem(0)
await helper.wait(200)
let line = await nvim.line
let [, lnum, col] = await nvim.call('getcurpos')
expect(line).toBe('bar func(do)')
expect(lnum).toBe(1)
expect(col).toBe(12)
})
it('should fix input for snippet item', async () => {
let provider: CompletionItemProvider = {
provideCompletionItems: async (): Promise<CompletionItem[]> => [{
label: 'foo',
filterText: 'foo',
insertText: '${1:foo}($2)',
insertTextFormat: InsertTextFormat.Snippet,
}]
}
disposables.push(languages.registerCompletionItemProvider('snippets-test', 'st', null, provider))
await nvim.input('if')
await helper.waitPopup()
await nvim.input('<C-n>')
await helper.wait(100)
let line = await nvim.line
expect(line).toBe('foo')
})
it('should filter on none keyword input', async () => {
let source: ISource = {
priority: 99,
enable: true,
name: 'temp',
sourceType: SourceType.Service,
doComplete: (_opt: CompleteOption): Promise<CompleteResult> => Promise.resolve({ items: [{ word: 'foo#abc' }] }),
}
disposables.push(sources.addSource(source))
await nvim.input('if')
await helper.waitPopup()
await nvim.input('#')
await helper.wait(100)
let items = await helper.getItems()
expect(items[0].word).toBe('foo#abc')
})
it('should use source-provided score', async () => {
let source: ISource = {
priority: 0,
enable: true,
name: 'source',
sourceType: SourceType.Service,
doComplete: (_opt: CompleteOption): Promise<CompleteResult> => Promise.resolve({
items: [
{ word: 'candidate_a', sourceScore: 0.1 },
{ word: 'candidate_b', sourceScore: 10 },
{ word: 'candidate_c' },
]
}),
}
disposables.push(sources.addSource(source))
await nvim.input('ocand')
await helper.waitPopup()
let items = await helper.getItems()
expect(items[0].word).toBe('candidate_b')
expect(items[1].word).toBe('candidate_c')
expect(items[2].word).toBe('candidate_a')
})
it('should do resolve for complete item', async () => {
let source: ISource = {
priority: 0,
enable: true,
name: 'resolve',
sourceType: SourceType.Service,
triggerCharacters: ['.'],
doComplete: (_opt: CompleteOption): Promise<CompleteResult> => Promise.resolve({ items: [{ word: 'foo' }] }),
onCompleteResolve: item => {
item.info = 'detail'
}
}
sources.addSource(source)
await nvim.input('i.')
await helper.waitPopup()
await helper.wait(100)
await nvim.input('<C-n>')
await helper.wait(100)
// let items = completion.completeItems
// expect(items[0].info).toBe('detail')
sources.removeSource(source)
})
})
describe('completion done', () => {
it('should fix word on CompleteDone', async () => {
await nvim.setLine('fball football')
await nvim.input('i')
await nvim.call('cursor', [1, 2])
let option: CompleteOption = await nvim.call('coc#util#get_complete_option')
await completion.startCompletion(option)
let items = await helper.items()
expect(items.length).toBe(1)
await nvim.input('<C-n>')
await helper.wait(30)
await nvim.call('coc#_select')
await helper.wait(100)
let line = await nvim.line
expect(line).toBe('football football')
})
})
describe('completion option', () => {
it('should hide kind and menu when configured', async () => {
helper.updateConfiguration('suggest.disableKind', true)
helper.updateConfiguration('suggest.disableMenu', true)
await nvim.setLine('fball football')
await nvim.input('of')
await helper.waitPopup()
let items = await helper.getItems()
expect(items[0].kind).toBeUndefined()
expect(items[0].menu).toBeUndefined()
helper.updateConfiguration('suggest.disableKind', false)
helper.updateConfiguration('suggest.disableMenu', false)
})
})
describe('completion trigger', () => {
it('should trigger completion on type trigger character', async () => {
let source: ISource = {
priority: 1,
enable: true,
name: 'trigger',
sourceType: SourceType.Service,
triggerCharacters: ['.'],
doComplete: (opt: CompleteOption): Promise<CompleteResult> => {
if (opt.triggerCharacter == '.') {
return Promise.resolve({ items: [{ word: 'bar' }] })
}
return Promise.resolve({ items: [{ word: 'foo#bar' }] })
}
}
sources.addSource(source)
await nvim.input('i')
await helper.wait(30)
await nvim.input('.')
await helper.waitPopup()
let items = await helper.items()
expect(items.length).toBeGreaterThan(0)
sources.removeSource(source)
})
it('should not trigger if autoTrigger is none', async () => {
let config = workspace.getConfiguration('suggest')
config.update('autoTrigger', 'none')
let autoTrigger = completion.config.autoTrigger
expect(autoTrigger).toBe('none')
await nvim.setLine('foo fo')
await nvim.input('A')
await helper.wait(100)
expect(completion.isActivated).toBe(false)
config.update('autoTrigger', 'always')
})
it('should trigger complete on trigger patterns match', async () => {
let source: ISource = {
priority: 99,
enable: true,
name: 'temp',
triggerPatterns: [/EM/],
sourceType: SourceType.Service,
doComplete: (opt: CompleteOption): Promise<CompleteResult> => {
if (!opt.input.startsWith('EM')) return null
return Promise.resolve({
items: [
{ word: 'foo', filterText: 'EMfoo' },
{ word: 'bar', filterText: 'EMbar' }
]
})
},
}
disposables.push(sources.addSource(source))
await nvim.input('i')
await nvim.input('EM')
await helper.waitPopup()
let items = await helper.getItems()
expect(items.length).toBe(2)
})
it('should trigger complete when pumvisible and triggerPatterns match', async () => {
await nvim.setLine('EnumMember')
let source: ISource = {
priority: 99,
enable: true,
name: 'temp',
triggerPatterns: [/EM/],
sourceType: SourceType.Service,
doComplete: (opt: CompleteOption): Promise<CompleteResult> => {
if (!opt.input.startsWith('EM')) return null
return Promise.resolve({
items: [
{ word: 'a', filterText: 'EMa' },
{ word: 'b', filterText: 'EMb' }
]
})
},
}
disposables.push(sources.addSource(source))
await nvim.input('o')
await helper.wait(10)
await nvim.input('E')
await helper.wait(30)
await nvim.input('M')
await helper.waitPopup()
let items = await helper.getItems()
expect(items.length).toBeGreaterThan(2)
})
})
describe('completion TextChangedI', () => {
it('should respect commitCharacter on TextChangedI', async () => {
let source: ISource = {
priority: 0,
enable: true,
name: 'slow',
sourceType: SourceType.Service,
triggerCharacters: ['.'],
doComplete: (opt: CompleteOption): Promise<CompleteResult> => {
if (opt.triggerCharacter == '.') {
return Promise.resolve({ items: [{ word: 'bar' }] })
}
return Promise.resolve({ items: [{ word: 'foo' }] })
},
shouldCommit: (_item, character) => character == '.'
}
sources.addSource(source)
await nvim.input('if')
await helper.pumvisible()
await helper.wait(100)
await nvim.input('.')
await helper.wait(100)
sources.removeSource(source)
})
it('should cancel completion with same pretext', async () => {
await nvim.setLine('foo')
await nvim.input('of')
await helper.pumvisible()
await helper.wait(30)
await nvim.call('coc#_cancel', [])
let line = await nvim.line
let visible = await nvim.call('pumvisible')
expect(line).toBe('f')
expect(visible).toBe(0)
})
})

247
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/configurations.test.ts

@ -1,247 +0,0 @@ @@ -1,247 +0,0 @@
import fs from 'fs'
import os from 'os'
import { ParseError } from 'jsonc-parser'
import path from 'path'
import Configurations from '../../configuration'
import { convertErrors, getChangedKeys, getConfigurationValue, getKeys, parseConfiguration } from '../../configuration/util'
import { IConfigurationModel } from '../../types'
import { URI } from 'vscode-uri'
import { v1 as uuidv1 } from 'uuid'
import { CONFIG_FILE_NAME } from '../../util'
const config = fs.readFileSync(path.join(__dirname, './settings.json'), 'utf8')
const workspaceConfigFile = path.resolve(__dirname, `../sample/.vim/${CONFIG_FILE_NAME}`)
function getConfigurationModel(): IConfigurationModel {
let [, contents] = parseConfiguration(config)
return { contents }
}
function createConfigurations(): Configurations {
let userConfigFile = path.join(__dirname, './settings.json')
return new Configurations(userConfigFile)
}
describe('Configurations', () => {
it('should convert errors', () => {
let errors: ParseError[] = []
for (let i = 0; i < 17; i++) {
errors.push({
error: i,
offset: 0,
length: 10
})
}
let res = convertErrors('file:///1', 'abc', errors)
expect(res.length).toBe(17)
})
it('should get all keys', () => {
let res = getKeys({
foo: {
bar: 1,
from: {
to: 2
}
},
bar: [1, 2]
})
expect(res).toEqual(['foo', 'foo.bar', 'foo.from', 'foo.from.to', 'bar'])
})
it('should get configuration value', () => {
let root = {
foo: {
bar: 1,
from: {
to: 2
}
},
bar: [1, 2]
}
let res = getConfigurationValue(root, 'foo.from.to', 1)
expect(res).toBe(2)
res = getConfigurationValue(root, 'foo.from', 1)
expect(res).toEqual({ to: 2 })
})
it('should add folder as workspace configuration', () => {
let configurations = createConfigurations()
configurations.onDidChange(e => {
let affects = e.affectsConfiguration('coc')
expect(affects).toBe(true)
})
configurations.addFolderFile(workspaceConfigFile)
let o = configurations.configuration.workspace.contents
expect(o.coc.preferences.rootPath).toBe('./src')
configurations.dispose()
})
it('should get changed keys #1', () => {
let res = getChangedKeys({ y: 2 }, { x: 1 })
expect(res).toEqual(['x', 'y'])
})
it('should get changed keys #2', () => {
let res = getChangedKeys({ x: 1, c: { d: 4 } }, { x: 1, b: { x: 5 } })
expect(res).toEqual(['b', 'b.x', 'c', 'c.d'])
})
it('should load default configurations', () => {
let conf = new Configurations()
expect(conf.defaults.contents.coc).toBeDefined()
let c = conf.getConfiguration('languageserver')
expect(c).toEqual({})
conf.dispose()
})
it('should parse configurations', () => {
let { contents } = getConfigurationModel()
expect(contents.foo.bar).toBe(1)
expect(contents.bar.foo).toBe(2)
expect(contents.schema).toEqual({ 'https://example.com': '*.yaml' })
})
it('should update user config #1', () => {
let conf = new Configurations()
let fn = jest.fn()
conf.onDidChange(e => {
expect(e.affectsConfiguration('x')).toBe(true)
fn()
})
conf.updateUserConfig({ x: 1 })
let config = conf.configuration.user
expect(config.contents).toEqual({ x: 1 })
expect(fn).toBeCalled()
})
it('should update user config #2', () => {
let conf = new Configurations()
conf.updateUserConfig({ x: 1 })
conf.updateUserConfig({ x: undefined })
let config = conf.configuration.user
expect(config.contents).toEqual({})
})
it('should update workspace config', () => {
let conf = new Configurations()
conf.updateUserConfig({ foo: { bar: 1 } })
let curr = conf.getConfiguration('foo')
curr.update('bar', 2, false)
curr = conf.getConfiguration('foo')
let n = curr.get<number>('bar')
expect(n).toBe(2)
})
it('should handle errors', () => {
let tmpFile = path.join(os.tmpdir(), uuidv1())
fs.writeFileSync(tmpFile, '{"x":', 'utf8')
let conf = new Configurations(tmpFile)
let errors = conf.errorItems
expect(errors.length > 1).toBe(true)
conf.dispose()
})
it('should change to new folder configuration', () => {
let conf = new Configurations()
conf.addFolderFile(workspaceConfigFile)
let configFile = path.join(__dirname, './settings.json')
conf.addFolderFile(configFile)
let file = path.resolve(__dirname, '../sample/tmp.js')
let fn = jest.fn()
conf.onDidChange(fn)
conf.setFolderConfiguration(URI.file(file).toString())
let { contents } = conf.workspace
expect(contents.foo).toBeUndefined()
expect(fn).toBeCalled()
conf.dispose()
})
it('should get nested property', () => {
let config = createConfigurations()
let conf = config.getConfiguration('servers.c')
let res = conf.get<string>('trace.server', '')
expect(res).toBe('verbose')
config.dispose()
})
it('should get user and workspace configuration', () => {
let userConfigFile = path.join(__dirname, './settings.json')
let configurations = new Configurations(userConfigFile)
let data = configurations.configuration.toData()
expect(data.user).toBeDefined()
expect(data.workspace).toBeDefined()
expect(data.defaults).toBeDefined()
let value = configurations.configuration.getValue()
expect(value.foo).toBeDefined()
expect(value.foo.bar).toBe(1)
configurations.dispose()
})
it('should override with new value', () => {
let configurations = createConfigurations()
configurations.configuration.defaults.setValue('foo', 1)
let { contents } = configurations.defaults
expect(contents.foo).toBe(1)
configurations.dispose()
})
it('should extends defaults', () => {
let configurations = createConfigurations()
configurations.extendsDefaults({ 'a.b': 1 })
configurations.extendsDefaults({ 'a.b': 2 })
let o = configurations.defaults.contents
expect(o.a.b).toBe(2)
configurations.dispose()
})
it('should update configuration', async () => {
let configurations = createConfigurations()
configurations.addFolderFile(workspaceConfigFile)
let fn = jest.fn()
configurations.onDidChange(e => {
expect(e.affectsConfiguration('foo')).toBe(true)
expect(e.affectsConfiguration('foo.bar')).toBe(true)
expect(e.affectsConfiguration('foo.bar', 'file://tmp/foo.js')).toBe(false)
fn()
})
let config = configurations.getConfiguration('foo')
let o = config.get<number>('bar')
expect(o).toBe(1)
config.update('bar', 6)
config = configurations.getConfiguration('foo')
expect(config.get<number>('bar')).toBe(6)
expect(fn).toBeCalledTimes(1)
configurations.dispose()
})
it('should remove configuration', async () => {
let configurations = createConfigurations()
configurations.addFolderFile(workspaceConfigFile)
let fn = jest.fn()
configurations.onDidChange(e => {
expect(e.affectsConfiguration('foo')).toBe(true)
expect(e.affectsConfiguration('foo.bar')).toBe(true)
fn()
})
let config = configurations.getConfiguration('foo')
let o = config.get<number>('bar')
expect(o).toBe(1)
config.update('bar', null, true)
config = configurations.getConfiguration('foo')
expect(config.get<any>('bar')).toBeUndefined()
expect(fn).toBeCalledTimes(1)
configurations.dispose()
})
})
describe('parse configuration', () => {
it('should only split top level dot keys', () => {
let o = { 'x.y': 'foo' }
let [, contents] = parseConfiguration(JSON.stringify(o))
expect(contents).toEqual({ x: { y: 'foo' } })
let schema = { 'my.schema': { 'foo.bar': 1 } }
let [, obj] = parseConfiguration(JSON.stringify(schema))
expect(obj).toEqual({ my: { schema: { 'foo.bar': 1 } } })
})
})

421
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/cursors.test.ts

@ -1,421 +0,0 @@ @@ -1,421 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import { Range } from 'vscode-languageserver-types'
import Cursors from '../../cursors'
import Document from '../../model/document'
import helper from '../helper'
let nvim: Neovim
let cursors: Cursors
let ns: number
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
ns = await nvim.createNamespace('coc-cursors')
cursors = new Cursors(nvim)
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
nvim.pauseNotification()
cursors.reset()
await nvim.resumeNotification()
await helper.reset()
})
async function rangeCount(): Promise<number> {
let buf = await nvim.buffer
let markers = await helper.getMarkers(buf.id, ns)
return markers.length
}
describe('cursors#select', () => {
it('should select by position', async () => {
let doc = await helper.createDocument()
await nvim.call('setline', [1, ['a', 'b']])
await nvim.call('cursor', [1, 1])
await helper.wait(100)
doc.forceSync()
await helper.wait(100)
await cursors.select(doc.bufnr, 'position', 'n')
await helper.wait(30)
let n = await rangeCount()
expect(n).toBe(1)
await nvim.setOption('virtualedit', 'onemore')
await nvim.call('cursor', [2, 2])
await cursors.select(doc.bufnr, 'position', 'n')
n = await rangeCount()
expect(n).toBe(2)
await cursors.select(doc.bufnr, 'position', 'n')
n = await rangeCount()
expect(n).toBe(1)
})
it('should select by word', async () => {
let doc = await helper.createDocument()
await nvim.call('setline', [1, ['foo', 'bar']])
await nvim.call('cursor', [1, 1])
await helper.wait(30)
doc.forceSync()
await cursors.select(doc.bufnr, 'word', 'n')
let n = await rangeCount()
expect(n).toBe(1)
await nvim.call('cursor', [2, 2])
await cursors.select(doc.bufnr, 'word', 'n')
n = await rangeCount()
expect(n).toBe(2)
await cursors.select(doc.bufnr, 'word', 'n')
n = await rangeCount()
expect(n).toBe(1)
})
it('should select last character', async () => {
let doc = await helper.createDocument()
await nvim.setOption('virtualedit', 'onemore')
await nvim.call('setline', [1, ['}', '{']])
await nvim.call('cursor', [1, 2])
await helper.wait(30)
doc.forceSync()
await cursors.select(doc.bufnr, 'word', 'n')
let n = await rangeCount()
expect(n).toBe(1)
await nvim.call('cursor', [2, 1])
await helper.wait(30)
doc.forceSync()
await cursors.select(doc.bufnr, 'word', 'n')
n = await rangeCount()
expect(n).toBe(2)
})
it('should select by visual range', async () => {
let doc = await helper.createDocument()
await nvim.call('setline', [1, ['"foo"', '"bar"']])
await nvim.call('cursor', [1, 1])
await nvim.command('normal! vE')
await helper.wait(30)
doc.forceSync()
await cursors.select(doc.bufnr, 'range', 'v')
let n = await rangeCount()
expect(n).toBe(1)
await nvim.call('cursor', [2, 1])
await nvim.command('normal! vE')
await cursors.select(doc.bufnr, 'range', 'v')
n = await rangeCount()
expect(n).toBe(2)
await cursors.select(doc.bufnr, 'range', 'v')
n = await rangeCount()
expect(n).toBe(1)
})
it('should select by operator', async () => {
await nvim.command('nmap x <Plug>(coc-cursors-operator)')
await helper.createDocument()
await nvim.call('setline', [1, ['"short"', '"long"']])
await nvim.call('cursor', [1, 2])
await nvim.input('xa"')
await helper.wait(30)
await nvim.call('cursor', [2, 2])
await nvim.input('xa"')
await helper.wait(30)
await nvim.command('nunmap x')
})
})
describe('cursors#addRanges', () => {
it('should add ranges', async () => {
let doc = await helper.createDocument()
await nvim.call('setline', [1, ['foo foo foo', 'bar bar']])
await helper.wait(30)
doc.forceSync()
let ranges = [
Range.create(0, 0, 0, 3),
Range.create(0, 4, 0, 7),
Range.create(0, 8, 0, 11),
Range.create(1, 0, 1, 3),
Range.create(1, 4, 1, 7)
]
await cursors.addRanges(ranges)
let n = await rangeCount()
expect(n).toBe(5)
})
})
describe('cursors#onchange', () => {
async function setup(): Promise<Document> {
let doc = await helper.createDocument()
await nvim.call('setline', [1, ['foo foo foo', 'bar bar']])
await helper.wait(30)
doc.forceSync()
let ranges = [
Range.create(0, 0, 0, 3),
Range.create(0, 4, 0, 7),
Range.create(0, 8, 0, 11),
Range.create(1, 0, 1, 3),
Range.create(1, 4, 1, 7)
]
await cursors.addRanges(ranges)
await nvim.call('cursor', [1, 1])
return doc
}
it('should ignore change after last range', async () => {
let doc = await setup()
await doc.buffer.append(['append'])
doc.forceSync()
await helper.wait(50)
let n = await rangeCount()
expect(n).toBe(5)
})
it('should adjust ranges on change before first line', async () => {
let doc = await setup()
await doc.buffer.setLines(['prepend'], { start: 0, end: 0, strictIndexing: false })
doc.forceSync()
await helper.wait(200)
let n = await rangeCount()
expect(n).toBe(5)
await nvim.call('cursor', [2, 1])
await nvim.input('ia')
await helper.wait(100)
doc.forceSync()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['prepend', 'afoo afoo afoo', 'abar abar'])
})
it('should work when change made to unrelated line', async () => {
let doc = await setup()
await doc.buffer.setLines(['prepend'], { start: 0, end: 0, strictIndexing: false })
doc.forceSync()
await helper.wait(200)
let n = await rangeCount()
expect(n).toBe(5)
await nvim.call('cursor', [1, 1])
await nvim.input('ia')
await helper.wait(200)
doc.forceSync()
await helper.wait(100)
await nvim.call('cursor', [2, 1])
await nvim.input('a')
await helper.wait(100)
await doc.synchronize()
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['aprepend', 'afoo afoo afoo', 'abar abar'])
})
it('should add text before', async () => {
let doc = await setup()
await nvim.input('iabc')
await helper.wait(30)
await doc.synchronize()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['abcfoo abcfoo abcfoo', 'abcbar abcbar'])
})
it('should add text after', async () => {
let doc = await setup()
await nvim.call('cursor', [1, 4])
await nvim.input('iabc')
await helper.wait(30)
await doc.synchronize()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['fooabc fooabc fooabc', 'barabc barabc'])
})
it('should add text around', async () => {
let doc = await setup()
await nvim.setLine('"foo" foo foo')
await helper.wait(30)
doc.forceSync()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['"foo" "foo" "foo"', '"bar" "bar"'])
})
it('should remove text before', async () => {
let doc = await setup()
await nvim.command('normal! x')
doc.forceSync()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['oo oo oo', 'ar ar'])
})
it('should remove text middle', async () => {
let doc = await setup()
await nvim.call('cursor', [2, 2])
await nvim.command('normal! x')
doc.forceSync()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['fo fo fo', 'br br'])
})
it('should remove text after', async () => {
let doc = await setup()
await nvim.call('cursor', [1, 3])
await nvim.command('normal! x')
doc.forceSync()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['fo fo fo', 'ba ba'])
})
it('should remove text around', async () => {
let doc = await helper.createDocument()
await nvim.call('setline', [1, ['"foo" "bar"']])
await helper.wait(30)
doc.forceSync()
let ranges = [
Range.create(0, 0, 0, 5),
Range.create(0, 6, 0, 11)
]
await cursors.addRanges(ranges)
await nvim.call('cursor', [1, 2])
await nvim.setLine('foo "bar"')
doc.forceSync()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['foo bar'])
})
it('should replace text before', async () => {
let doc = await setup()
await nvim.call('cursor', [1, 1])
await nvim.command('normal! ra')
doc.forceSync()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['aoo aoo aoo', 'aar aar'])
})
it('should replace text after', async () => {
let doc = await setup()
await nvim.call('cursor', [1, 3])
await nvim.command('normal! ra')
doc.forceSync()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['foa foa foa', 'baa baa'])
})
it('should replace text middle', async () => {
let doc = await setup()
await nvim.call('cursor', [1, 2])
await nvim.input('sab')
await helper.wait(30)
doc.forceSync()
await helper.wait(100)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['fabo fabo fabo', 'babr babr'])
})
it('should adjust undo & redo on add & remove', async () => {
let doc = await setup()
await nvim.call('cursor', [1, 4])
await nvim.input('iabc')
await helper.wait(30)
doc.forceSync()
let n = await rangeCount()
expect(n).toBe(5)
await helper.wait(30)
await nvim.command('undo')
await helper.wait(30)
doc.forceSync()
n = await rangeCount()
expect(n).toBe(5)
await helper.wait(30)
await nvim.command('redo')
await helper.wait(30)
doc.forceSync()
expect(await rangeCount()).toBe(5)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['fooabc fooabc fooabc', 'barabc barabc'])
})
it('should adjust undo & redo on change around', async () => {
let doc = await setup()
await nvim.setLine('"foo" foo foo')
await helper.wait(30)
doc.forceSync()
expect(await rangeCount()).toBe(5)
await helper.wait(30)
await nvim.command('undo')
await helper.wait(30)
doc.forceSync()
expect(await rangeCount()).toBe(5)
await helper.wait(30)
await nvim.command('redo')
await helper.wait(30)
doc.forceSync()
expect(await rangeCount()).toBe(5)
let lines = await nvim.call('getline', [1, '$'])
expect(lines).toEqual(['"foo" "foo" "foo"', '"bar" "bar"'])
})
})
describe('cursors#keymaps', () => {
async function setup(): Promise<void> {
let doc = await helper.createDocument()
await nvim.call('setline', [1, ['a', 'b', 'c']])
await helper.wait(30)
doc.forceSync()
await nvim.call('cursor', [1, 1])
await cursors.select(doc.bufnr, 'position', 'n')
await helper.wait(30)
await nvim.call('cursor', [2, 1])
await cursors.select(doc.bufnr, 'position', 'n')
await helper.wait(30)
await nvim.call('cursor', [3, 1])
await cursors.select(doc.bufnr, 'position', 'n')
}
async function hasKeymap(key): Promise<boolean> {
let buf = await nvim.buffer
let keymaps = await buf.getKeymap('n') as any
return keymaps.find(o => o.lhs == key) != null
}
it('should setup cancel keymap', async () => {
await setup()
let count = await rangeCount()
expect(count).toBe(3)
await nvim.input('<esc>')
await helper.wait(100)
count = await rangeCount()
expect(count).toBe(0)
let has = await hasKeymap('<Esc>')
expect(has).toBe(false)
})
it('should setup next key', async () => {
await setup()
await nvim.input('<C-n>')
await helper.wait(50)
let cursor = await nvim.call('coc#cursor#position')
expect(cursor).toEqual([0, 0])
await nvim.input('<C-n>')
await helper.wait(50)
cursor = await nvim.call('coc#cursor#position')
expect(cursor).toEqual([1, 0])
})
it('should setup previous key', async () => {
await setup()
await nvim.input('<C-p>')
await helper.wait(50)
let cursor = await nvim.call('coc#cursor#position')
expect(cursor).toEqual([1, 0])
await nvim.input('<C-p>')
await helper.wait(50)
cursor = await nvim.call('coc#cursor#position')
expect(cursor).toEqual([0, 0])
})
})

60
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/db.test.ts

@ -1,60 +0,0 @@ @@ -1,60 +0,0 @@
import DB from '../../model/db'
import path from 'path'
let db: DB
beforeAll(async () => {
db = new DB(path.join(__dirname, 'db.json'))
})
afterAll(async () => {
db.destroy()
})
afterEach(async () => {
db.clear()
})
describe('DB', () => {
test('db.exists()', async () => {
let exists = db.exists('a.b')
expect(exists).toBe(false)
db.push('a.b', { foo: 1 })
exists = db.exists('a.b.foo')
expect(exists).toBe(true)
})
test('db.fetch()', async () => {
let res = await db.fetch('x')
expect(res).toBeUndefined()
db.push('x', 1)
res = await db.fetch('x')
expect(res).toBe(1)
db.push('x', { foo: 1 })
res = await db.fetch('x')
expect(res).toEqual({ foo: 1 })
})
test('db.delete()', async () => {
db.push('foo.bar', 1)
db.delete('foo.bar')
let exists = db.exists('foo.bar')
expect(exists).toBe(false)
})
test('db.push()', async () => {
db.push('foo.x', 1)
db.push('foo.y', '2')
db.push('foo.z', true)
db.push('foo.n', null)
db.push('foo.o', { x: 1 })
let res = db.fetch('foo')
expect(res).toEqual({
x: 1,
y: '2',
z: true,
n: null,
o: { x: 1 }
})
})
})

27
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/decorator.test.ts

@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
import * as decorator from '../../util/decorator'
class CallTest {
public count = 0
@decorator.memorize
public async memorized(): Promise<number> { return ++this.count }
}
describe('memorize', () => {
test('overlapping', async () => {
const c = new CallTest()
const first = c.memorized()
const second = c.memorized()
expect(await first).toBe(1)
expect(await second).toBe(2)
})
test('nonoverlapping', async () => {
const c = new CallTest()
const first = c.memorized()
expect(await first).toBe(1)
const second = c.memorized()
expect(await second).toBe(1)
})
})

250
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/diagnosticBuffer.test.ts

@ -1,250 +0,0 @@ @@ -1,250 +0,0 @@
import helper from '../helper'
import { Neovim } from '@chemzqm/neovim'
import { DiagnosticBuffer } from '../../diagnostic/buffer'
import { Range, DiagnosticSeverity, Diagnostic, DiagnosticTag, Position } from 'vscode-languageserver-types'
import workspace from '../../workspace'
let nvim: Neovim
const config: any = {
autoRefresh: true,
checkCurrentLine: false,
locationlistUpdate: true,
enableSign: true,
enableHighlightLineNumber: true,
enableMessage: 'always',
messageTarget: 'echo',
messageDelay: 250,
refreshOnInsertMode: false,
virtualTextSrcId: 99,
virtualText: false,
virtualTextCurrentLineOnly: true,
virtualTextPrefix: " ",
virtualTextLines: 3,
virtualTextLineSeparator: " \\ ",
displayByAle: false,
level: DiagnosticSeverity.Hint,
signPriority: 11,
errorSign: '>>',
warningSign: '>>',
infoSign: '>>',
hintSign: '>>',
filetypeMap: {
default: ''
},
}
async function createDiagnosticBuffer(): Promise<DiagnosticBuffer> {
let doc = await helper.createDocument()
return new DiagnosticBuffer(nvim, doc.bufnr, doc.uri, config, () => {
// noop
})
}
function createDiagnostic(msg: string, range?: Range, severity?: DiagnosticSeverity, tags?: DiagnosticTag[]): Diagnostic & { collection: string } {
range = range ? range : Range.create(0, 0, 0, 1)
return Object.assign(Diagnostic.create(range, msg, severity || DiagnosticSeverity.Error, 999, 'test'), { collection: 'test', tags })
}
let ns: number
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
ns = await nvim.createNamespace('coc-diagnostic')
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
})
describe('diagnostic buffer', () => {
describe('refresh()', () => {
it('should add signs', async () => {
let diagnostics = [createDiagnostic('foo'), createDiagnostic('bar')]
let buf = await createDiagnosticBuffer()
buf.addSigns('a', diagnostics)
await helper.wait(30)
let res = await nvim.call('sign_getplaced', [buf.bufnr, { group: 'CocDiagnostica' }])
let signs = res[0].signs
expect(signs).toBeDefined()
expect(signs[0].name).toBe('CocError')
})
it('should set diagnostic info', async () => {
let r = Range.create(0, 1, 0, 2)
let diagnostics = [
createDiagnostic('foo', r, DiagnosticSeverity.Error),
createDiagnostic('bar', r, DiagnosticSeverity.Warning),
createDiagnostic('foo', r, DiagnosticSeverity.Hint),
createDiagnostic('bar', r, DiagnosticSeverity.Information)
]
let buf = await createDiagnosticBuffer()
await buf.refresh({ '': diagnostics })
let buffer = await nvim.buffer
let res = await buffer.getVar('coc_diagnostic_info')
expect(res).toEqual({
lnums: [1, 1, 1, 1],
information: 1,
hint: 1,
warning: 1,
error: 1
})
})
it('should add highlight', async () => {
let buf = await createDiagnosticBuffer()
let doc = workspace.getDocument(buf.bufnr)
await nvim.setLine('abc')
await doc.patchChange(true)
nvim.pauseNotification()
buf.updateHighlights('', [
createDiagnostic('foo', Range.create(0, 0, 0, 1), DiagnosticSeverity.Error),
createDiagnostic('bar', Range.create(0, 0, 0, 1), DiagnosticSeverity.Warning)
])
await nvim.resumeNotification()
let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any
expect(res).toEqual([
[
1,
0,
0,
{
hl_group: 'CocWarningHighlight',
priority: 4096,
end_col: 1,
end_row: 0
}
],
[
2,
0,
0,
{
hl_group: 'CocErrorHighlight',
priority: 4096,
end_col: 1,
end_row: 0
}
]
])
nvim.pauseNotification()
buf.updateHighlights('', [])
await nvim.resumeNotification()
res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any[]
expect(res.length).toBe(0)
})
it('should add deprecated highlight', async () => {
let diagnostic = createDiagnostic('foo', Range.create(0, 0, 0, 1), DiagnosticSeverity.Information, [DiagnosticTag.Deprecated])
let buf = await createDiagnosticBuffer()
let doc = workspace.getDocument(buf.bufnr)
await nvim.setLine('foo')
await doc.patchChange(true)
nvim.pauseNotification()
buf.updateHighlights('', [diagnostic])
await nvim.resumeNotification()
let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, {}]) as [number, number, number][]
expect(res.length).toBe(1)
})
})
describe('showVirtualText()', () => {
beforeEach(async () => {
config.virtualText = true
config.virtualTextSrcId = await nvim.createNamespace('diagnostics-virtualText')
})
afterEach(() => {
config.virtualText = false
config.virtualTextCurrentLineOnly = true
})
it('should show virtual text on current line', async () => {
let diagnostic = createDiagnostic('foo')
let buf = await createDiagnosticBuffer()
let diagnostics = [diagnostic]
await buf.refresh({ '': diagnostics })
let ns = config.virtualTextSrcId
let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any
expect(res.length).toBe(1)
let texts = res[0][3].virt_text
expect(texts[0]).toEqual([' foo', 'CocErrorVirtualText'])
})
it('should virtual text on all lines', async () => {
config.virtualTextCurrentLineOnly = false
let buf = await createDiagnosticBuffer()
let diagnostics = [
createDiagnostic('foo', Range.create(0, 0, 0, 1)),
createDiagnostic('bar', Range.create(1, 0, 1, 1)),
]
await buf.refresh({ '': diagnostics })
let ns = config.virtualTextSrcId
let res = await nvim.call('nvim_buf_get_extmarks', [buf.bufnr, ns, 0, -1, { details: true }]) as any
expect(res.length).toBe(2)
})
})
describe('updateLocationList()', () => {
beforeEach(async () => {
config.locationlistUpdate = true
})
afterEach(() => {
config.locationlistUpdate = false
})
it('should update location list', async () => {
let buf = await createDiagnosticBuffer()
await nvim.call('setloclist', [0, [], 'r', { title: 'Diagnostics of coc', items: [] }])
await buf.refresh({
a: [createDiagnostic('foo')]
})
let res = await nvim.eval(`getloclist(bufwinid(${buf.bufnr}))`) as any[]
expect(res.length).toBe(1)
expect(res[0].text).toBe('[test 999] foo [E]')
})
})
describe('clear()', () => {
let config = workspace.getConfiguration('diagnostic')
beforeEach(() => {
config.update('virtualText', true)
})
afterEach(() => {
config.update('virtualText', false)
})
it('should clear all diagnostics', async () => {
let diagnostic = createDiagnostic('foo')
let buf = await createDiagnosticBuffer()
let diagnostics = [diagnostic]
await buf.refresh({ '': diagnostics })
buf.clear()
await helper.wait(50)
let buffer = await nvim.buffer
let res = await buffer.getVar("coc_diagnostic_info")
expect(res == null).toBe(true)
})
})
describe('getDiagnostics()', () => {
it('should get sorted diagnostics', async () => {
let buf = await createDiagnosticBuffer()
let diagnostics = [
createDiagnostic('three', Range.create(0, 1, 0, 2), DiagnosticSeverity.Error),
createDiagnostic('one', Range.create(0, 0, 0, 2), DiagnosticSeverity.Warning),
createDiagnostic('two', Range.create(0, 0, 0, 2), DiagnosticSeverity.Error),
]
diagnostics[0].tags = [DiagnosticTag.Unnecessary]
await buf.refresh({
x: diagnostics,
y: [createDiagnostic('four', Range.create(0, 0, 0, 2), DiagnosticSeverity.Error)]
})
let res = buf.getDiagnosticsAt(Position.create(0, 1), false)
let arr = res.map(o => o.message)
expect(arr).toEqual(['four', 'two', 'three', 'one'])
})
})
})

98
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/diagnosticCollection.test.ts

@ -1,98 +0,0 @@ @@ -1,98 +0,0 @@
import DiagnosticCollection from '../../diagnostic/collection'
import { Diagnostic, Range } from 'vscode-languageserver-types'
function createDiagnostic(msg: string, range?: Range): Diagnostic {
range = range ? range : Range.create(0, 0, 0, 1)
return Diagnostic.create(range, msg)
}
describe('diagnostic collection', () => {
it('should create collection', () => {
let collection = new DiagnosticCollection('test')
expect(collection.name).toBe('test')
})
it('should set diagnostic with uri', () => {
let collection = new DiagnosticCollection('test')
let diagnostic = createDiagnostic('error')
let uri = 'file:///1'
collection.set(uri, [diagnostic])
expect(collection.get(uri).length).toBe(1)
collection.set(uri, [])
expect(collection.get(uri).length).toBe(0)
})
it('should clear diagnostics with null as diagnostics', () => {
let collection = new DiagnosticCollection('test')
let diagnostic = createDiagnostic('error')
let uri = 'file:///1'
collection.set(uri, [diagnostic])
expect(collection.get(uri).length).toBe(1)
collection.set(uri, null)
expect(collection.get(uri).length).toBe(0)
})
it('should clear diagnostics with undefined as diagnostics in entries', () => {
let collection = new DiagnosticCollection('test')
let diagnostic = createDiagnostic('error')
let entries: [string, Diagnostic[] | null][] = [
['file:1', [diagnostic]],
['file:1', undefined]
]
let uri = 'file:///1'
collection.set(entries)
expect(collection.get(uri).length).toBe(0)
})
it('should set diagnostics with entries', () => {
let collection = new DiagnosticCollection('test')
let diagnostic = createDiagnostic('error')
let uri = 'file:///1'
let other = 'file:///2'
let entries: [string, Diagnostic[]][] = [
[uri, [diagnostic]],
[other, [diagnostic]],
[uri, [createDiagnostic('other')]]
]
collection.set(entries)
expect(collection.get(uri).length).toBe(2)
expect(collection.get(other).length).toBe(1)
})
it('should delete diagnostics for uri', () => {
let collection = new DiagnosticCollection('test')
let diagnostic = createDiagnostic('error')
let uri = 'file:///1'
collection.set(uri, [diagnostic])
collection.delete(uri)
expect(collection.get(uri).length).toBe(0)
})
it('should clear all diagnostics', () => {
let collection = new DiagnosticCollection('test')
let diagnostic = createDiagnostic('error')
let uri = 'file:///1'
collection.set(uri, [diagnostic])
collection.clear()
expect(collection.get(uri).length).toBe(0)
})
it('should call for every uri with diagnostics', () => {
let collection = new DiagnosticCollection('test')
let diagnostic = createDiagnostic('error')
let uri = 'file:///1'
let other = 'file:///2'
let entries: [string, Diagnostic[]][] = [
[uri, [diagnostic]],
[other, [diagnostic]],
[uri, [createDiagnostic('other')]]
]
collection.set(entries)
let arr: string[] = []
collection.forEach(uri => {
arr.push(uri)
})
expect(arr).toEqual([uri, other])
})
})

556
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/diagnosticManager.test.ts

@ -1,556 +0,0 @@ @@ -1,556 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import path from 'path'
import { severityLevel, getNameFromSeverity } from '../../diagnostic/util'
import { Range, DiagnosticSeverity, Diagnostic, Location, DiagnosticTag } from 'vscode-languageserver-types'
import { URI } from 'vscode-uri'
import Document from '../../model/document'
import workspace from '../../workspace'
import window from '../../window'
import manager from '../../diagnostic/manager'
import helper, { createTmpFile } from '../helper'
let nvim: Neovim
function createDiagnostic(msg: string, range?: Range, severity?: DiagnosticSeverity): Diagnostic {
range = range ? range : Range.create(0, 0, 0, 1)
return Diagnostic.create(range, msg, severity || DiagnosticSeverity.Error)
}
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
manager.reset()
await helper.reset()
})
async function createDocument(name?: string): Promise<Document> {
let doc = await helper.createDocument(name)
let collection = manager.create('test')
let diagnostics: Diagnostic[] = []
await doc.buffer.setLines(['foo bar foo bar', 'foo bar', 'foo', 'bar'], {
start: 0,
end: -1,
strictIndexing: false
})
diagnostics.push(createDiagnostic('error', Range.create(0, 2, 0, 4), DiagnosticSeverity.Error))
diagnostics.push(createDiagnostic('warning', Range.create(0, 5, 0, 6), DiagnosticSeverity.Warning))
diagnostics.push(createDiagnostic('information', Range.create(1, 0, 1, 1), DiagnosticSeverity.Information))
diagnostics.push(createDiagnostic('hint', Range.create(1, 2, 1, 3), DiagnosticSeverity.Hint))
diagnostics.push(createDiagnostic('error', Range.create(2, 0, 2, 2), DiagnosticSeverity.Error))
collection.set(doc.uri, diagnostics)
doc.forceSync()
return doc
}
describe('diagnostic manager', () => {
describe('refresh()', () => {
it('should refresh on buffer create', async () => {
let uri = URI.file(path.join(path.dirname(__dirname), 'doc')).toString()
let fn = jest.fn()
let disposable = manager.onDidRefresh(() => {
fn()
})
let collection = manager.create('tmp')
let diagnostic = createDiagnostic('My Error')
collection.set(uri, [diagnostic])
let doc = await helper.createDocument('doc')
let val = await doc.buffer.getVar('coc_diagnostic_info') as any
expect(fn).toBeCalled()
expect(val).toBeDefined()
expect(val.error).toBe(1)
collection.dispose()
disposable.dispose()
})
it('should delay refresh on InsertLeave', async () => {
let doc = await helper.createDocument()
await nvim.input('i')
let collection = manager.create('test')
let diagnostics: Diagnostic[] = []
await doc.buffer.setLines(['foo bar foo bar', 'foo bar', 'foo', 'bar'], {
start: 0,
end: -1,
strictIndexing: false
})
diagnostics.push(createDiagnostic('error', Range.create(0, 2, 0, 4), DiagnosticSeverity.Error))
collection.set(doc.uri, diagnostics)
await helper.wait(10)
await nvim.input('<esc>')
await helper.wait(100)
let val = await doc.buffer.getVar('coc_diagnostic_info') as any
expect(val).toBe(null)
await helper.wait(600)
val = await doc.buffer.getVar('coc_diagnostic_info') as any
expect(val).toBeDefined()
})
})
describe('toggleDiagnostic()', () => {
it('should toggle diagnostics', async () => {
let doc = await createDocument()
await helper.wait(50)
manager.toggleDiagnostic()
await helper.wait(50)
let val = await doc.buffer.getVar('coc_diagnostic_info') as any
expect(val).toBe(null)
manager.toggleDiagnostic()
await helper.wait(50)
val = await doc.buffer.getVar('coc_diagnostic_info') as any
expect(val).toBeDefined()
expect(val.error).toBe(2)
})
})
describe('getDiagnosticList()', () => {
it('should get all diagnostics', async () => {
await createDocument()
let list = manager.getDiagnosticList()
expect(list).toBeDefined()
expect(list.length).toBeGreaterThanOrEqual(5)
expect(list[0].severity).toBe('Error')
expect(list[1].severity).toBe('Error')
expect(list[2].severity).toBe('Warning')
expect(list[3].severity).toBe('Information')
expect(list[4].severity).toBe('Hint')
})
it('should filter diagnostics by configuration', async () => {
let config = workspace.getConfiguration('diagnostic')
config.update('level', 'warning')
config.update('showUnused', false)
config.update('showDeprecated', false)
let doc = await createDocument()
let diagnostics = manager.getDiagnostics(doc.uri)['test']
diagnostics[0].tags = [DiagnosticTag.Unnecessary]
diagnostics[2].tags = [DiagnosticTag.Deprecated]
let collection = manager.getCollectionByName('test')
collection.set(doc.uri, diagnostics)
let list = manager.getDiagnosticList()
expect(list.length).toBe(1)
expect(list[0].severity).toBe('Warning')
let res = manager.getDiagnostics(doc.uri)['test']
expect(res.length).toBe(1)
helper.updateConfiguration('diagnostic.level', 'hint')
helper.updateConfiguration('diagnostic.showUnused', true)
helper.updateConfiguration('diagnostic.showDeprecated', true)
let ranges = manager.getSortedRanges(doc.uri)
expect(ranges.length).toBe(3)
})
})
describe('preview()', () => {
it('should not throw with empty diagnostics', async () => {
await helper.createDocument()
await manager.preview()
let tabpage = await nvim.tabpage
let wins = await tabpage.windows
expect(wins.length).toBe(1)
})
it('should open preview window', async () => {
await createDocument()
await nvim.call('cursor', [1, 3])
await manager.preview()
let res = await nvim.call('coc#window#find', ['&previewwindow', 1])
expect(res).toBeDefined()
await nvim.call('win_gotoid', [res])
let buf = await nvim.buffer
let lines = await buf.lines
expect(lines[0]).toEqual('[test] [E]')
})
})
describe('setLocationlist()', () => {
it('should set location list', async () => {
let doc = await createDocument()
await manager.setLocationlist(doc.bufnr)
await nvim.command('lopen')
let buftype = await nvim.eval('&buftype') as string
expect(buftype).toBe('quickfix')
})
})
describe('setConfigurationErrors()', () => {
it('should set configuration errors', async () => {
let doc = await helper.createDocument()
let errors = [{
location: Location.create(doc.uri, Range.create(0, 0, 1, 0)),
message: 'foo',
}, {
location: Location.create(doc.uri, Range.create(1, 0, 2, 0)),
message: 'bar',
}]
manager.setConfigurationErrors(errors)
await helper.wait(50)
let res = manager.getDiagnostics(doc.uri, 'config')['config']
expect(res.length).toBe(2)
manager.setConfigurationErrors()
await helper.wait(50)
res = manager.getDiagnostics(doc.uri, 'config')['config']
expect(res.length).toBe(0)
})
})
describe('create()', () => {
it('should create diagnostic collection', async () => {
let doc = await helper.createDocument()
let collection = manager.create('test')
collection.set(doc.uri, [createDiagnostic('foo')])
await helper.wait(50)
let info = await doc.buffer.getVar('coc_diagnostic_info')
expect(info).toBeDefined()
await nvim.command('bd!')
await helper.wait(50)
})
})
describe('getSortedRanges()', () => {
it('should get sorted ranges of document', async () => {
let doc = await helper.createDocument()
await nvim.call('setline', [1, ['a', 'b', 'c']])
let collection = manager.create('test')
let diagnostics: Diagnostic[] = []
diagnostics.push(createDiagnostic('x', Range.create(0, 0, 0, 1)))
diagnostics.push(createDiagnostic('y', Range.create(0, 1, 0, 2)))
diagnostics.push(createDiagnostic('z', Range.create(1, 0, 1, 2)))
collection.set(doc.uri, diagnostics)
let ranges = manager.getSortedRanges(doc.uri)
expect(ranges[0]).toEqual(Range.create(0, 0, 0, 1))
expect(ranges[1]).toEqual(Range.create(0, 1, 0, 2))
expect(ranges[2]).toEqual(Range.create(1, 0, 1, 2))
ranges = manager.getSortedRanges(doc.uri, 'error')
expect(ranges.length).toBe(3)
expect(manager.getSortedRanges(doc.uri, 'warning').length).toBe(0)
})
})
describe('getDiagnosticsInRange', () => {
it('should get diagnostics in range', async () => {
let doc = await helper.createDocument()
let collection = manager.create('test')
let diagnostics: Diagnostic[] = []
await doc.buffer.setLines(['foo bar foo bar', 'foo bar'], {
start: 0,
end: -1,
strictIndexing: false
})
await helper.wait(300)
diagnostics.push(createDiagnostic('a', Range.create(0, 0, 0, 1)))
diagnostics.push(createDiagnostic('b', Range.create(0, 2, 0, 3)))
diagnostics.push(createDiagnostic('c', Range.create(1, 0, 1, 2)))
collection.set(doc.uri, diagnostics)
let res = manager.getDiagnosticsInRange(doc.textDocument, Range.create(0, 0, 0, 3))
expect(res.length).toBe(2)
})
})
describe('getCurrentDiagnostics', () => {
it('should get diagnostics under corsor', async () => {
let config = workspace.getConfiguration('diagnostic')
await createDocument()
let diagnostics = await manager.getCurrentDiagnostics()
expect(diagnostics.length).toBe(0)
await nvim.call('cursor', [1, 4])
diagnostics = await manager.getCurrentDiagnostics()
expect(diagnostics.length).toBe(1)
config.update('checkCurrentLine', true)
await nvim.call('cursor', [1, 2])
diagnostics = await manager.getCurrentDiagnostics()
expect(diagnostics.length).toBe(2)
config.update('checkCurrentLine', false)
})
it('should get empty diagnostic at end of line', async () => {
let doc = await helper.createDocument()
await nvim.setLine('foo')
doc.forceSync()
await nvim.command('normal! $')
let diagnostic = Diagnostic.create(Range.create(0, 3, 1, 0), 'error', DiagnosticSeverity.Error)
let collection = manager.create('empty')
collection.set(doc.uri, [diagnostic])
await manager.refreshBuffer(doc.bufnr, true)
let diagnostics = await manager.getCurrentDiagnostics()
expect(diagnostics.length).toBeGreaterThanOrEqual(1)
expect(diagnostics[0].message).toBe('error')
collection.dispose()
})
it('should get diagnostic next to end of line', async () => {
let doc = await helper.createDocument()
await nvim.setLine('foo')
doc.forceSync()
await nvim.command('normal! $')
let diagnostic = Diagnostic.create(Range.create(0, 3, 0, 4), 'error', DiagnosticSeverity.Error)
let collection = manager.create('empty')
collection.set(doc.uri, [diagnostic])
await manager.refreshBuffer(doc.bufnr, true)
let diagnostics = await manager.getCurrentDiagnostics()
expect(diagnostics.length).toBeGreaterThanOrEqual(1)
expect(diagnostics[0].message).toBe('error')
collection.dispose()
})
it('should get diagnostic with empty range at end of line', async () => {
let doc = await helper.createDocument()
await nvim.setLine('foo')
doc.forceSync()
await nvim.command('normal! $')
let diagnostic = Diagnostic.create(Range.create(0, 3, 1, 0), 'error', DiagnosticSeverity.Error)
let collection = manager.create('empty')
collection.set(doc.uri, [diagnostic])
await manager.refreshBuffer(doc.bufnr, true)
let diagnostics = await manager.getCurrentDiagnostics()
expect(diagnostics.length).toBeGreaterThanOrEqual(1)
expect(diagnostics[0].message).toBe('error')
collection.dispose()
})
it('should get diagnostic pass end of the buffer lines', async () => {
let doc = await helper.createDocument()
await nvim.setLine('foo')
doc.forceSync()
await nvim.command('normal! ^')
let diagnostic = Diagnostic.create(Range.create(1, 0, 1, 0), 'error', DiagnosticSeverity.Error)
let collection = manager.create('empty')
collection.set(doc.uri, [diagnostic])
await manager.refreshBuffer(doc.bufnr, true)
let diagnostics = await manager.getCurrentDiagnostics()
expect(diagnostics.length).toBeGreaterThanOrEqual(1)
expect(diagnostics[0].message).toBe('error')
collection.dispose()
})
})
describe('jumpRelated', () => {
it('should jump to related position', async () => {
let doc = await helper.createDocument()
let range = Range.create(0, 0, 0, 10)
let location = Location.create(URI.file(__filename).toString(), range)
let diagnostic = Diagnostic.create(range, 'msg', DiagnosticSeverity.Error, 1000, 'test',
[{ location, message: 'test' }])
let collection = manager.create('positions')
collection.set(doc.uri, [diagnostic])
await manager.refreshBuffer(doc.uri, true)
await nvim.call('cursor', [1, 1])
await manager.jumpRelated()
await helper.wait(100)
let bufname = await nvim.call('bufname', '%')
expect(bufname).toMatch('diagnosticManager')
})
it('should open location list', async () => {
let doc = await helper.createDocument()
let range = Range.create(0, 0, 0, 10)
let diagnostic = Diagnostic.create(range, 'msg', DiagnosticSeverity.Error, 1000, 'test',
[{
location: Location.create(URI.file(__filename).toString(), Range.create(1, 0, 1, 10)),
message: 'foo'
}, {
location: Location.create(URI.file(__filename).toString(), Range.create(2, 0, 2, 10)),
message: 'bar'
}])
let collection = manager.create('positions')
collection.set(doc.uri, [diagnostic])
await manager.refreshBuffer(doc.uri, true)
await nvim.call('cursor', [1, 1])
await manager.jumpRelated()
await helper.wait(100)
let bufname = await nvim.call('bufname', '%')
expect(bufname).toBe('list:///location')
})
})
describe('jumpPrevious & jumpNext', () => {
it('should jump to previous', async () => {
let doc = await createDocument()
await nvim.command('normal! G$')
let ranges = manager.getSortedRanges(doc.uri)
ranges.reverse()
for (let i = 0; i < ranges.length; i++) {
await manager.jumpPrevious()
let pos = await window.getCursorPosition()
expect(pos).toEqual(ranges[i].start)
}
await manager.jumpPrevious()
})
it('should jump to next', async () => {
let doc = await createDocument()
await nvim.call('cursor', [0, 0])
let ranges = manager.getSortedRanges(doc.uri)
for (let i = 0; i < ranges.length; i++) {
await manager.jumpNext()
let pos = await window.getCursorPosition()
expect(pos).toEqual(ranges[i].start)
}
await manager.jumpNext()
})
})
describe('diagnostic configuration', () => {
it('should use filetype map from config', async () => {
let config = workspace.getConfiguration('diagnostic')
config.update('filetypeMap', { default: 'bufferType' })
let doc = await createDocument('foo.js')
let collection = manager.getCollectionByName('test')
let diagnostics = [createDiagnostic('99', Range.create(0, 0, 0, 2), DiagnosticSeverity.Error)]
collection.set(doc.uri, diagnostics)
await nvim.call('cursor', [1, 1])
await nvim.command('doautocmd CursorHold')
let winid = await helper.waitFloat()
await nvim.call('win_gotoid', [winid])
await nvim.command('normal! $')
let res = await nvim.eval('synIDattr(synID(line("."),col("."),1),"name")')
expect(res).toMatch(/javascript/i)
config.update('filetypeMap', {})
})
it('should show floating window on cursor hold', async () => {
let config = workspace.getConfiguration('diagnostic')
config.update('messageTarget', 'float')
await createDocument()
await nvim.call('cursor', [1, 3])
await nvim.command('doautocmd CursorHold')
let winid = await helper.waitFloat()
let bufnr = await nvim.call('nvim_win_get_buf', winid) as number
let buf = nvim.createBuffer(bufnr)
let lines = await buf.lines
expect(lines.join('\n')).toMatch('error')
})
it('should echo messages on cursor hold', async () => {
let config = workspace.getConfiguration('diagnostic')
config.update('messageTarget', 'echo')
await createDocument()
await nvim.call('cursor', [1, 3])
await helper.wait(600)
let line = await helper.getCmdline()
expect(line).toMatch('error')
config.update('messageTarget', 'float')
})
it('should show diagnostics of current line', async () => {
let config = workspace.getConfiguration('diagnostic')
config.update('checkCurrentLine', true)
await createDocument()
await nvim.call('cursor', [1, 1])
let winid = await helper.waitFloat()
let bufnr = await nvim.call('nvim_win_get_buf', winid) as number
let buf = nvim.createBuffer(bufnr)
let lines = await buf.lines
expect(lines.length).toBe(3)
config.update('checkCurrentLine', false)
})
it('should filter diagnostics by level', async () => {
helper.updateConfiguration('diagnostic.level', 'warning')
let doc = await createDocument()
let diagnosticsMap = manager.getDiagnostics(doc.uri)
for (let diagnostics of Object.values(diagnosticsMap)) {
for (let diagnostic of diagnostics) {
expect(diagnostic.severity != DiagnosticSeverity.Hint).toBe(true)
expect(diagnostic.severity != DiagnosticSeverity.Information).toBe(true)
}
}
helper.updateConfiguration('diagnostic.level', 'hint')
})
it('should send ale diagnostic items', async () => {
let config = workspace.getConfiguration('diagnostic')
config.update('displayByAle', true)
let content = `
function! MockAleResults(bufnr, collection, items)
let g:collection = a:collection
let g:items = a:items
endfunction
`
let file = await createTmpFile(content)
await nvim.command(`source ${file}`)
await createDocument()
await helper.wait(50)
let items = await nvim.getVar('items') as any[]
expect(Array.isArray(items)).toBe(true)
expect(items.length).toBeGreaterThan(0)
await nvim.command('bd!')
await helper.wait(50)
items = await nvim.getVar('items') as any[]
expect(items).toEqual([])
config.update('displayByAle', false)
})
})
describe('severityLevel & getNameFromSeverity', () => {
it('should get severity level', () => {
expect(severityLevel('hint')).toBe(DiagnosticSeverity.Hint)
expect(severityLevel('error')).toBe(DiagnosticSeverity.Error)
expect(severityLevel('warning')).toBe(DiagnosticSeverity.Warning)
expect(severityLevel('information')).toBe(DiagnosticSeverity.Information)
expect(severityLevel('')).toBe(DiagnosticSeverity.Hint)
})
it('should get severity name', () => {
expect(getNameFromSeverity(null as any)).toBe('CocError')
})
})
describe('toggleDiagnosticBuffer', () => {
it('should toggle diagnostics for buffer', async () => {
let doc = await createDocument()
// required to wait refresh finish
await helper.wait(50)
await manager.toggleDiagnosticBuffer(doc.bufnr)
await helper.wait(50)
let buf = nvim.createBuffer(doc.bufnr)
let res = await buf.getVar('coc_diagnostic_info') as any
expect(res == null).toBe(true)
await manager.toggleDiagnosticBuffer(doc.bufnr)
await helper.wait(50)
res = await buf.getVar('coc_diagnostic_info') as any
expect(res.error).toBe(2)
})
})
describe('refresh', () => {
let config = workspace.getConfiguration('diagnostic')
beforeEach(() => {
config.update('autoRefresh', false)
})
afterEach(() => {
config.update('autoRefresh', true)
})
it('should refresh by bufnr', async () => {
let doc = await createDocument()
let buf = nvim.createBuffer(doc.bufnr)
let res = await buf.getVar('coc_diagnostic_info') as any
// should not refresh
expect(res == null).toBe(true)
manager.refresh(doc.bufnr)
await helper.wait(100)
res = await buf.getVar('coc_diagnostic_info') as any
expect(res?.error).toBe(2)
})
it('should refresh all buffers', async () => {
let one = await helper.createDocument('one')
let two = await helper.createDocument('two')
let collection = manager.create('tmp')
collection.set([[one.uri, [createDiagnostic('Error one')]], [two.uri, [createDiagnostic('Error two')]]])
manager.refresh()
await helper.wait(50)
for (let bufnr of [one.bufnr, two.bufnr]) {
let buf = nvim.createBuffer(bufnr)
let res = await buf.getVar('coc_diagnostic_info') as any
expect(res?.error).toBe(1)
}
collection.dispose()
})
})
})

60
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/dialog.test.ts

@ -1,60 +0,0 @@ @@ -1,60 +0,0 @@
import { Neovim } from '@chemzqm/neovim'
import Dialog, { DialogButton } from '../../model/dialog'
import helper from '../helper'
let nvim: Neovim
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
await helper.reset()
})
describe('Dialog module', () => {
it('should show dialog', async () => {
let dialog = new Dialog(nvim, { content: '你好' })
await dialog.show({})
let winid = await dialog.winid
let win = nvim.createWindow(winid)
let width = await win.width
expect(width).toBe(4)
await nvim.call('coc#float#close', [winid])
})
it('should invoke callback with index -1', async () => {
let callback = jest.fn()
let dialog = new Dialog(nvim, { content: '你好', callback })
await dialog.show({})
let winid = await dialog.winid
await nvim.call('coc#float#close', [winid])
await helper.wait(50)
expect(callback).toHaveBeenCalledWith(-1)
})
it('should invoke callback on click', async () => {
let callback = jest.fn()
let buttons: DialogButton[] = [{
index: 0,
text: 'yes'
}, {
index: 1,
text: 'no'
}]
let dialog = new Dialog(nvim, { content: '你好', buttons, callback })
await dialog.show({})
let winid = await dialog.winid
let btnwin = await nvim.call('coc#float#get_related', [winid, 'buttons'])
await nvim.call('win_gotoid', [btnwin])
await nvim.call('cursor', [2, 1])
await nvim.call('coc#float#nvim_float_click', [])
await helper.wait(50)
expect(callback).toHaveBeenCalledWith(0)
})
})

178
etc/soft/nvim/+plugins/coc.nvim/src/__tests__/modules/diff.test.ts

@ -1,178 +0,0 @@ @@ -1,178 +0,0 @@
import { TextEdit } from 'vscode-languageserver-types'
import { TextDocument } from 'vscode-languageserver-textdocument'
import { diffLines, getChange, patchLine, ChangedLines } from '../../util/diff'
describe('diff lines', () => {
function diff(oldStr: string, newStr: string): ChangedLines {
let oldLines = oldStr.split('\n')
return diffLines(oldLines, newStr.split('\n'), oldLines.length - 2)
}
it('should diff changed lines', () => {
let res = diff('a\n', 'b\n')
expect(res).toEqual({ start: 0, end: 1, replacement: ['b'] })
})
it('should diff added lines', () => {
let res = diff('a\n', 'a\nb\n')
expect(res).toEqual({
start: 1,
end: 1,
replacement: ['b']
})
})
it('should diff remove lines', () => {
let res = diff('a\n\n', 'a\n')
expect(res).toEqual({
start: 1,
end: 2,
replacement: []
})
})
it('should diff remove multiple lines', () => {
let res = diff('a\n\n\n', 'a\n')
expect(res).toEqual({
start: 1,
end: 3,
replacement: []
})
})
it('should diff removed line', () => {
let res = diff('a\n\n\nb', 'a\n\nb')
expect(res).toEqual({
start: 2,
end: 3,
replacement: []
})
})
it('should reduce changed lines', async () => {
let res = diffLines(['a', 'b', 'c'], ['a', 'b', 'c', 'd'], 0)
expect(res).toEqual({
start: 3,
end: 3,
replacement: ['d']
})
})
})
describe('patch line', () => {
it('should patch line', () => {
let res = patchLine('foo', 'bar foo bar')
expect(res.length).toBe(7)
expect(res).toBe(' foo')
})
})
describe('should get text edits', () => {
function applyEdits(oldStr: string, newStr: string): void {
let doc = TextDocument.create('untitled://1', 'markdown', 0, oldStr)
let change = getChange(doc.getText(), newStr)
let start = doc.positionAt(change.start)
let end = doc.positionAt(change.end)
let edit: TextEdit = {
range: { start, end },
newText: change.newText
}
let res = TextDocument.applyEdits(doc, [edit])
expect(res).toBe(newStr)
}
it('should get diff for comments ', async () => {
let oldStr = '/*\n *\n * \n'
let newStr = '/*\n *\n *\n * \n'
let doc = TextDocument.create('untitled://1', 'markdown', 0, oldStr)
let change = getChange(doc.getText(), newStr, 1)
let start = doc.positionAt(change.start)
let end = doc.positionAt(change.end)
let edit: TextEdit = {
range: { start, end },
newText: change.newText
}
let res = TextDocument.applyEdits(doc, [edit])
expect(res).toBe(newStr)
})
it('should return null for same content', () => {
let change = getChange('', '')
expect(change).toBeNull()
change = getChange('abc', 'abc')
expect(change).toBeNull()
})
it('should get diff for added', () => {
applyEdits('1\n2', '1\n2\n3\n4')
})
it('should get diff for added #0', () => {
applyEdits('\n\n', '\n\n\n')
})
it('should get diff for added #1', () => {
applyEdits('1\n2\n3', '5\n1\n2\n3')
})
it('should get diff for added #2', () => {
applyEdits('1\n2\n3', '1\n2\n4\n3')
})
it('should get diff for added #3', () => {
applyEdits('1\n2\n3', '4\n1\n2\n3\n5')
})
it('should get diff for added #4', () => {
applyEdits(' ', ' ')
})
it('should get diff for replace', () => {
applyEdits('1\n2\n3\n4\n5', '1\n5\n3\n6\n7')
})
it('should get diff for replace #1', () => {
applyEdits('1\n2\n3\n4\n5', '1\n5\n3\n6\n7')
})
it('should get diff for remove #0', () => {
applyEdits('1\n2\n3\n4', '1\n4')
})
it('should get diff for remove #1', () => {
applyEdits('1\n2\n3\n4', '1')
})
it('should get diff for remove #2', () => {
applyEdits(' ', ' ')
})
it('should prefer cursor position for change', async () => {
let res = getChange(' int n', ' n', 0)
expect(res).toEqual({ start: 1, end: 5, newText: '' })
res = getChange(' int n', ' n')
expect(res).toEqual({ start: 0, end: 4, newText: '' })
})
it('should prefer next line for change', async () => {
let res = getChange('a\nb', 'a\nc\nb')
expect(res).toEqual({ start: 2, end: 2, newText: 'c\n' })
applyEdits('a\nb', 'a\nc\nb')
})
it('should prefer previous line for change', async () => {
let res = getChange('\n\na', '\na')
expect(res).toEqual({ start: 0, end: 1, newText: '' })
})
it('should consider cursor', () => {
let res = getChange('\n\n\n', '\n\n\n\n', 1)
expect(res).toEqual({ start: 2, end: 2, newText: '\n' })
})
it('should get minimal diff', () => {
let res = getChange('foo\nbar', 'fab\nbar', 2)
expect(res).toEqual({ start: 1, end: 3, newText: 'ab' })
})
})

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save