I broke up with neovim....vim is my best friend now
This commit is contained in:
21
dot_vim/plugged/vim-lsp/LICENSE
Normal file
21
dot_vim/plugged/vim-lsp/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Prabir Shrestha
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
47
dot_vim/plugged/vim-lsp/LICENSE-THIRD-PARTY
Normal file
47
dot_vim/plugged/vim-lsp/LICENSE-THIRD-PARTY
Normal file
@@ -0,0 +1,47 @@
|
||||
The vim-lsp source code bundle part of third party's code following which carry
|
||||
their own copyright notices and license terms:
|
||||
|
||||
* vim-lsc - https://github.com/natebosch/vim-lsc
|
||||
* autoload/lsc/diff.vim
|
||||
* autoload/lsc/cursor.vim
|
||||
====================================================================
|
||||
|
||||
Copyright 2017 vim-lsc authors
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
* vim-yggdrasil - https://github.com/m-pilia/vim-yggdrasil
|
||||
* autoload/utils/tree.vim
|
||||
====================================================================
|
||||
|
||||
Copyright 2019 Martino Pilia <martino.pilia@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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
247
dot_vim/plugged/vim-lsp/README.md
Normal file
247
dot_vim/plugged/vim-lsp/README.md
Normal file
@@ -0,0 +1,247 @@
|
||||
# vim-lsp [](https://gitter.im/vimlsp/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
Async [Language Server Protocol](https://github.com/Microsoft/language-server-protocol) plugin for vim8 and neovim.
|
||||
|
||||
# Installing
|
||||
|
||||
Install [vim-plug](https://github.com/junegunn/vim-plug) and then:
|
||||
|
||||
```viml
|
||||
Plug 'prabirshrestha/vim-lsp'
|
||||
```
|
||||
|
||||
__Performance__
|
||||
|
||||
Certain bottlenecks in Vim script have been implemented in lua. If you would like to take advantage of these performance gains
|
||||
use vim compiled with lua or neovim v0.4.0+
|
||||
|
||||
## Registering servers
|
||||
|
||||
```viml
|
||||
if executable('pylsp')
|
||||
" pip install python-lsp-server
|
||||
au User lsp_setup call lsp#register_server({
|
||||
\ 'name': 'pylsp',
|
||||
\ 'cmd': {server_info->['pylsp']},
|
||||
\ 'allowlist': ['python'],
|
||||
\ })
|
||||
endif
|
||||
|
||||
function! s:on_lsp_buffer_enabled() abort
|
||||
setlocal omnifunc=lsp#complete
|
||||
setlocal signcolumn=yes
|
||||
if exists('+tagfunc') | setlocal tagfunc=lsp#tagfunc | endif
|
||||
nmap <buffer> gd <plug>(lsp-definition)
|
||||
nmap <buffer> gs <plug>(lsp-document-symbol-search)
|
||||
nmap <buffer> gS <plug>(lsp-workspace-symbol-search)
|
||||
nmap <buffer> gr <plug>(lsp-references)
|
||||
nmap <buffer> gi <plug>(lsp-implementation)
|
||||
nmap <buffer> gt <plug>(lsp-type-definition)
|
||||
nmap <buffer> <leader>rn <plug>(lsp-rename)
|
||||
nmap <buffer> [g <plug>(lsp-previous-diagnostic)
|
||||
nmap <buffer> ]g <plug>(lsp-next-diagnostic)
|
||||
nmap <buffer> K <plug>(lsp-hover)
|
||||
nnoremap <buffer> <expr><c-f> lsp#scroll(+4)
|
||||
nnoremap <buffer> <expr><c-d> lsp#scroll(-4)
|
||||
|
||||
let g:lsp_format_sync_timeout = 1000
|
||||
autocmd! BufWritePre *.rs,*.go call execute('LspDocumentFormatSync')
|
||||
|
||||
" refer to doc to add more commands
|
||||
endfunction
|
||||
|
||||
augroup lsp_install
|
||||
au!
|
||||
" call s:on_lsp_buffer_enabled only for languages that has the server registered.
|
||||
autocmd User lsp_buffer_enabled call s:on_lsp_buffer_enabled()
|
||||
augroup END
|
||||
```
|
||||
|
||||
Refer to [vim-lsp-settings](https://github.com/mattn/vim-lsp-settings) on how to easily setup language servers using vim-lsp automatically.
|
||||
|
||||
```viml
|
||||
Plug 'prabirshrestha/vim-lsp'
|
||||
Plug 'mattn/vim-lsp-settings'
|
||||
```
|
||||
|
||||
## auto-complete
|
||||
|
||||
Refer to docs on configuring omnifunc or [asyncomplete.vim](https://github.com/prabirshrestha/asyncomplete.vim).
|
||||
|
||||
## Snippets
|
||||
vim-lsp does not support snippets by default. If you want snippet integration, you will first have to install a third-party snippet plugin and a plugin that integrates it in vim-lsp.
|
||||
At the moment, you have following options:
|
||||
1. [vim-vsnip](https://github.com/hrsh7th/vim-vsnip) together with [vim-vsnip-integ](https://github.com/hrsh7th/vim-vsnip-integ)
|
||||
2. [UltiSnips](https://github.com/SirVer/ultisnips) together with [vim-lsp-ultisnips](https://github.com/thomasfaingnaert/vim-lsp-ultisnips)
|
||||
3. [neosnippet.vim](https://github.com/Shougo/neosnippet.vim) together with [vim-lsp-neosnippet](https://github.com/thomasfaingnaert/vim-lsp-neosnippet)
|
||||
|
||||
For more information, refer to the readme and documentation of the respective plugins.
|
||||
|
||||
## Folding
|
||||
|
||||
You can let the language server automatically handle folding for you. To enable this, you have to set `'foldmethod'`, `'foldexpr'` and (optionally) `'foldtext'`:
|
||||
|
||||
```vim
|
||||
set foldmethod=expr
|
||||
\ foldexpr=lsp#ui#vim#folding#foldexpr()
|
||||
\ foldtext=lsp#ui#vim#folding#foldtext()
|
||||
```
|
||||
|
||||
If you would like to disable folding globally, you can add this to your configuration:
|
||||
|
||||
```vim
|
||||
let g:lsp_fold_enabled = 0
|
||||
```
|
||||
|
||||
Also see `:h vim-lsp-folding`.
|
||||
|
||||
## Semantic highlighting
|
||||
vim-lsp supports the unofficial extension to the LSP protocol for semantic highlighting (https://github.com/microsoft/vscode-languageserver-node/pull/367).
|
||||
This feature requires Neovim highlights, or Vim with the `textprop` feature enabled.
|
||||
You will also need to link language server semantic scopes to Vim highlight groups.
|
||||
Refer to `:h vim-lsp-semantic` for more info.
|
||||
|
||||
## Supported commands
|
||||
|
||||
**Note:**
|
||||
* Some servers may only support partial commands.
|
||||
* While it is possible to register multiple servers for the same filetype, some commands will pick only the first server that supports it. For example, it doesn't make sense for rename and format commands to be sent to multiple servers.
|
||||
|
||||
| Command | Description|
|
||||
|--|--|
|
||||
|`:LspAddTreeCallHierarchyIncoming`| Find incoming call hierarchy for the symbol under cursor, but add the result to the current list |
|
||||
|`:LspCallHierarchyIncoming`| Find incoming call hierarchy for the symbol under cursor |
|
||||
|`:LspCallHierarchyOutgoing`| Find outgoing call hierarchy for the symbol under cursor |
|
||||
|`:LspCodeAction`| Gets a list of possible commands that can be applied to a file so it can be fixed (quick fix) |
|
||||
|`:LspCodeLens`| Gets a list of possible commands that can be executed on the current document |
|
||||
|`:LspDeclaration`| Go to the declaration of the word under the cursor, and open in the current window |
|
||||
|`:LspDefinition`| Go to the definition of the word under the cursor, and open in the current window |
|
||||
|`:LspDocumentDiagnostics`| Get current document diagnostics information |
|
||||
|`:LspDocumentFormat`| Format entire document |
|
||||
|`:LspDocumentRangeFormat`| Format document selection |
|
||||
|`:LspDocumentSymbol`| Show document symbols |
|
||||
|`:LspHover`| Show hover information |
|
||||
|`:LspImplementation` | Show implementation of interface in the current window |
|
||||
|`:LspNextDiagnostic`| jump to next diagnostic (all of error, warning, information, hint) |
|
||||
|`:LspNextError`| jump to next error |
|
||||
|`:LspNextReference`| jump to next reference to the symbol under cursor |
|
||||
|`:LspNextWarning`| jump to next warning |
|
||||
|`:LspPeekDeclaration`| Go to the declaration of the word under the cursor, but open in preview window |
|
||||
|`:LspPeekDefinition`| Go to the definition of the word under the cursor, but open in preview window |
|
||||
|`:LspPeekImplementation`| Go to the implementation of an interface, but open in preview window |
|
||||
|`:LspPeekTypeDefinition`| Go to the type definition of the word under the cursor, but open in preview window |
|
||||
|`:LspPreviousDiagnostic`| jump to previous diagnostic (all of error, warning, information, hint) |
|
||||
|`:LspPreviousError`| jump to previous error |
|
||||
|`:LspPreviousReference`| jump to previous reference to the symbol under cursor |
|
||||
|`:LspPreviousWarning`| jump to previous warning |
|
||||
|`:LspReferences`| Find references |
|
||||
|`:LspRename`| Rename symbol |
|
||||
|`:LspStatus` | Show the status of the language server |
|
||||
|`:LspTypeDefinition`| Go to the type definition of the word under the cursor, and open in the current window |
|
||||
|`:LspTypeHierarchy`| View type hierarchy of the symbol under the cursor |
|
||||
|`:LspWorkspaceSymbol`| Search/Show workspace symbol |
|
||||
|
||||
### Diagnostics
|
||||
|
||||
Document diagnostics (e.g. warnings, errors) are enabled by default, but if you
|
||||
preferred to turn them off and use other plugins instead (like
|
||||
[Neomake](https://github.com/neomake/neomake) or
|
||||
[ALE](https://github.com/w0rp/ale), set `g:lsp_diagnostics_enabled` to
|
||||
`0`:
|
||||
|
||||
```viml
|
||||
let g:lsp_diagnostics_enabled = 0 " disable diagnostics support
|
||||
```
|
||||
|
||||
### Highlight references
|
||||
|
||||
Highlight references to the symbol under the cursor (enabled by default).
|
||||
You can disable it by adding
|
||||
|
||||
```viml
|
||||
let g:lsp_document_highlight_enabled = 0
|
||||
```
|
||||
|
||||
to your configuration.
|
||||
|
||||
To change the style of the highlighting, you can set or link the `lspReference`
|
||||
highlight group, e.g.:
|
||||
|
||||
```viml
|
||||
highlight lspReference ctermfg=red guifg=red ctermbg=green guibg=green
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
In order to enable file logging set `g:lsp_log_file`.
|
||||
|
||||
```vim
|
||||
let g:lsp_log_verbose = 1
|
||||
let g:lsp_log_file = expand('~/vim-lsp.log')
|
||||
|
||||
" for asyncomplete.vim log
|
||||
let g:asyncomplete_log_file = expand('~/asyncomplete.log')
|
||||
```
|
||||
|
||||
You can get detailed status on your servers using `:CheckHealth` -- built into neovim or in a plugin on vim:
|
||||
|
||||
```vim
|
||||
if !has('nvim') | Plug 'rhysd/vim-healthcheck' | endif
|
||||
CheckHealth
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
[vim-themis](https://github.com/thinca/vim-themis) is used for testing. To run
|
||||
integration tests [gopls](https://github.com/golang/tools/tree/master/gopls)
|
||||
executable must be in path.
|
||||
|
||||
## Maintainers
|
||||
|
||||
- [Prabir Shrestha](https://github.com/prabirshrestha) (author, maintainer)
|
||||
- [mattn](https://github.com/mattn) (maintainer)
|
||||
- [hrsh7th](https://github.com/hrsh7th) (maintainer)
|
||||
- [Thomas Faingnaert](https://github.com/thomasfaingnaert) (maintainer)
|
||||
- [rhysd](https://github.com/rhysd) (maintainer)
|
||||
|
||||
## Backers
|
||||
|
||||
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/vim-lsp#backer)]
|
||||
|
||||
<a href="https://opencollective.com/vim-lsp/backer/0/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/1/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/2/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/3/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/4/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/5/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/6/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/7/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/8/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/9/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/9/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/10/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/10/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/11/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/11/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/12/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/12/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/13/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/13/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/backer/14/website" target="_blank"><img src="https://opencollective.com/vim-lsp/backer/14/avatar.svg"></a>
|
||||
|
||||
|
||||
## Sponsors
|
||||
|
||||
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor](https://opencollective.com/vim-lsp#sponsor)]
|
||||
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/0/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/1/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/2/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/3/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/4/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/5/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/6/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/7/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/8/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/9/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/9/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/10/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/10/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/11/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/11/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/12/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/12/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/13/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/13/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vim-lsp/sponsor/14/website" target="_blank"><img src="https://opencollective.com/vim-lsp/sponsor/14/avatar.svg"></a>
|
||||
|
||||
65
dot_vim/plugged/vim-lsp/autoload/health/lsp.vim
Normal file
65
dot_vim/plugged/vim-lsp/autoload/health/lsp.vim
Normal file
@@ -0,0 +1,65 @@
|
||||
function! s:BuildConfigBlock(section, info) abort
|
||||
let l:block = get(a:info, a:section, '')
|
||||
if !empty(l:block)
|
||||
return printf("### %s\n%s\n", a:section, l:block)
|
||||
endif
|
||||
return ''
|
||||
endf
|
||||
|
||||
|
||||
function! health#lsp#check() abort
|
||||
call health#report_start('server status')
|
||||
let l:server_status = lsp#collect_server_status()
|
||||
|
||||
let l:has_printed = v:false
|
||||
for l:k in sort(keys(l:server_status))
|
||||
let l:report = l:server_status[l:k]
|
||||
|
||||
let l:status_msg = printf('%s: %s', l:k, l:report.status)
|
||||
if l:report.status == 'running'
|
||||
call health#report_ok(l:status_msg)
|
||||
elseif l:report.status == 'failed'
|
||||
call health#report_error(l:status_msg, 'See :help g:lsp_log_verbose to debug server failure.')
|
||||
else
|
||||
call health#report_warn(l:status_msg)
|
||||
endif
|
||||
let l:has_printed = v:true
|
||||
endfor
|
||||
|
||||
if !l:has_printed
|
||||
call health#report_warn('no servers connected')
|
||||
endif
|
||||
|
||||
for l:k in sort(keys(l:server_status))
|
||||
call health#report_start(printf('server configuration: %s', l:k))
|
||||
let l:report = l:server_status[l:k]
|
||||
|
||||
let l:msg = "\t\n"
|
||||
let l:msg .= s:BuildConfigBlock('allowlist', l:report.info)
|
||||
let l:msg .= s:BuildConfigBlock('blocklist', l:report.info)
|
||||
let l:cfg = get(l:report.info, 'workspace_config', '')
|
||||
if !empty(l:cfg)
|
||||
if get(g:, 'loaded_scriptease', 0)
|
||||
let l:cfg = scriptease#dump(l:cfg, {'width': &columns-1})
|
||||
else
|
||||
let l:cfg = json_encode(l:cfg)
|
||||
" Add some whitespace to make it readable.
|
||||
let l:cfg = substitute(l:cfg, '[,{(\[]', "&\n\t", 'g')
|
||||
let l:cfg = substitute(l:cfg, '":', '& ', 'g')
|
||||
let l:cfg = substitute(l:cfg, '\v[})\]]+', "\n&", 'g')
|
||||
let l:cfg = substitute(l:cfg, '\n\s*\n', "\n", 'g')
|
||||
endif
|
||||
let l:msg .= printf("### workspace_config\n```json\n%s\n```", l:cfg)
|
||||
endif
|
||||
call health#report_info(l:msg)
|
||||
endfor
|
||||
|
||||
call health#report_start('Performance')
|
||||
if lsp#utils#has_lua() && g:lsp_use_lua
|
||||
call health#report_ok('Using lua for faster performance.')
|
||||
else
|
||||
call health#report_warn('Missing requirements to enable lua for faster performance.')
|
||||
endif
|
||||
|
||||
endf
|
||||
|
||||
1332
dot_vim/plugged/vim-lsp/autoload/lsp.vim
Normal file
1332
dot_vim/plugged/vim-lsp/autoload/lsp.vim
Normal file
File diff suppressed because it is too large
Load Diff
1700
dot_vim/plugged/vim-lsp/autoload/lsp/callbag.vim
Normal file
1700
dot_vim/plugged/vim-lsp/autoload/lsp/callbag.vim
Normal file
File diff suppressed because it is too large
Load Diff
198
dot_vim/plugged/vim-lsp/autoload/lsp/capabilities.vim
Normal file
198
dot_vim/plugged/vim-lsp/autoload/lsp/capabilities.vim
Normal file
@@ -0,0 +1,198 @@
|
||||
function! s:has_provider(server_name, ...) abort
|
||||
let l:value = lsp#get_server_capabilities(a:server_name)
|
||||
for l:provider in a:000
|
||||
if empty(l:value) || type(l:value) != type({}) || !has_key(l:value, l:provider)
|
||||
return 0
|
||||
endif
|
||||
let l:value = l:value[l:provider]
|
||||
endfor
|
||||
return (type(l:value) == type(v:true) && l:value == v:true) || type(l:value) == type({})
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_declaration_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'declarationProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_definition_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'definitionProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_references_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'referencesProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_hover_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'hoverProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_rename_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'renameProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_rename_prepare_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'renameProvider', 'prepareProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_workspace_folders_change_notifications(server_name) abort
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server_name)
|
||||
if type(l:capabilities) == type({}) && !empty(l:capabilities)
|
||||
let l:workspace = get(l:capabilities, 'workspace', {})
|
||||
if type(l:workspace) == type({}) && !empty(l:workspace)
|
||||
let l:workspace_folders = get(l:workspace, 'workspaceFolders', {})
|
||||
if type(l:workspace_folders) == type({}) && !empty(l:workspace_folders)
|
||||
if get(l:workspace_folders, 'supported', v:false) && get(l:workspace_folders, 'changeNotifications', '') ==# 'workspace/didChangeWorkspaceFolders'
|
||||
return v:true
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
return v:false
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_document_formatting_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'documentFormattingProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_document_range_formatting_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'documentRangeFormattingProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_document_symbol_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'documentSymbolProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_workspace_symbol_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'workspaceSymbolProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_implementation_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'implementationProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_code_action_provider(server_name) abort
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server_name)
|
||||
if !empty(l:capabilities) && has_key(l:capabilities, 'codeActionProvider')
|
||||
if type(l:capabilities['codeActionProvider']) == type({})
|
||||
if has_key(l:capabilities['codeActionProvider'], 'codeActionKinds') && type(l:capabilities['codeActionProvider']['codeActionKinds']) == type([])
|
||||
return len(l:capabilities['codeActionProvider']['codeActionKinds']) != 0
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
return s:has_provider(a:server_name, 'codeActionProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_code_lens_provider(server_name) abort
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server_name)
|
||||
if !empty(l:capabilities) && has_key(l:capabilities, 'codeLensProvider')
|
||||
return 1
|
||||
endif
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_type_definition_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'typeDefinitionProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_type_hierarchy_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'typeHierarchyProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_document_highlight_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'documentHighlightProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_folding_range_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'foldingRangeProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_call_hierarchy_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'callHierarchyProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_semantic_tokens(server_name) abort
|
||||
return s:has_provider(a:server_name, 'semanticTokensProvider')
|
||||
endfunction
|
||||
|
||||
" [supports_did_save (boolean), { 'includeText': boolean }]
|
||||
function! lsp#capabilities#get_text_document_save_registration_options(server_name) abort
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server_name)
|
||||
if !empty(l:capabilities) && has_key(l:capabilities, 'textDocumentSync')
|
||||
if type(l:capabilities['textDocumentSync']) == type({})
|
||||
let l:save_options = get(l:capabilities['textDocumentSync'], 'save', 0)
|
||||
if type(l:save_options) == type({})
|
||||
return [1, {'includeText': get(l:save_options, 'includeText', 0)}]
|
||||
else
|
||||
return [l:save_options ? 1 : 0, {'includeText': 0 }]
|
||||
endif
|
||||
else
|
||||
return [1, { 'includeText': 0 }]
|
||||
endif
|
||||
endif
|
||||
return [0, { 'includeText': 0 }]
|
||||
endfunction
|
||||
|
||||
" supports_did_change (boolean)
|
||||
function! lsp#capabilities#get_text_document_change_sync_kind(server_name) abort
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server_name)
|
||||
if !empty(l:capabilities) && has_key(l:capabilities, 'textDocumentSync')
|
||||
if type(l:capabilities['textDocumentSync']) == type({})
|
||||
if has_key(l:capabilities['textDocumentSync'], 'change') && type(l:capabilities['textDocumentSync']['change']) == type(1)
|
||||
let l:val = l:capabilities['textDocumentSync']['change']
|
||||
return l:val >= 0 && l:val <= 2 ? l:val : 1
|
||||
else
|
||||
return 1
|
||||
endif
|
||||
elseif type(l:capabilities['textDocumentSync']) == type(1)
|
||||
return l:capabilities['textDocumentSync']
|
||||
else
|
||||
return 1
|
||||
endif
|
||||
endif
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_signature_help_provider(server_name) abort
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server_name)
|
||||
if !empty(l:capabilities) && has_key(l:capabilities, 'signatureHelpProvider')
|
||||
return 1
|
||||
endif
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#get_signature_help_trigger_characters(server_name) abort
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server_name)
|
||||
if !empty(l:capabilities) && has_key(l:capabilities, 'signatureHelpProvider')
|
||||
let l:trigger_chars = []
|
||||
if type(l:capabilities['signatureHelpProvider']) == type({})
|
||||
if has_key(l:capabilities['signatureHelpProvider'], 'triggerCharacters')
|
||||
let l:trigger_chars = l:capabilities['signatureHelpProvider']['triggerCharacters']
|
||||
endif
|
||||
" If retriggerChars exist, just treat them like triggerChars.
|
||||
if has_key(l:capabilities['signatureHelpProvider'], 'retriggerCharacters')
|
||||
let l:trigger_chars += l:capabilities['signatureHelpProvider']['retriggerCharacters']
|
||||
endif
|
||||
return l:trigger_chars
|
||||
endif
|
||||
endif
|
||||
return []
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#get_code_action_kinds(server_name) abort
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server_name)
|
||||
if !empty(l:capabilities) && has_key(l:capabilities, 'codeActionProvider')
|
||||
if type(l:capabilities['codeActionProvider']) == type({})
|
||||
if has_key(l:capabilities['codeActionProvider'], 'codeActionKinds') && type(l:capabilities['codeActionProvider']['codeActionKinds']) == type([])
|
||||
return l:capabilities['codeActionProvider']['codeActionKinds']
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
return []
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_completion_resolve_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'completionProvider', 'resolveProvider')
|
||||
endfunction
|
||||
|
||||
function! lsp#capabilities#has_inlay_hint_provider(server_name) abort
|
||||
return s:has_provider(a:server_name, 'inlayHintProvider')
|
||||
endfunction
|
||||
465
dot_vim/plugged/vim-lsp/autoload/lsp/client.vim
Normal file
465
dot_vim/plugged/vim-lsp/autoload/lsp/client.vim
Normal file
@@ -0,0 +1,465 @@
|
||||
let s:save_cpo = &cpoptions
|
||||
set cpoptions&vim
|
||||
|
||||
let s:clients = {} " { client_id: ctx }
|
||||
|
||||
" Vars used by native lsp
|
||||
let s:jobidseq = 0
|
||||
|
||||
function! s:create_context(client_id, opts) abort
|
||||
if a:client_id <= 0
|
||||
return {}
|
||||
endif
|
||||
|
||||
let l:ctx = {
|
||||
\ 'opts': a:opts,
|
||||
\ 'buffer': '',
|
||||
\ 'content-length': -1,
|
||||
\ 'requests': {},
|
||||
\ 'request_sequence': 0,
|
||||
\ 'on_notifications': {},
|
||||
\ }
|
||||
|
||||
let s:clients[a:client_id] = l:ctx
|
||||
|
||||
return l:ctx
|
||||
endfunction
|
||||
|
||||
function! s:dispose_context(client_id) abort
|
||||
if a:client_id > 0
|
||||
if has_key(s:clients, a:client_id)
|
||||
unlet s:clients[a:client_id]
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_stdout(id, data, event) abort
|
||||
let l:ctx = get(s:clients, a:id, {})
|
||||
|
||||
if empty(l:ctx)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:ctx['buffer'] .= a:data
|
||||
|
||||
while 1
|
||||
if l:ctx['content-length'] < 0
|
||||
" wait for all headers to arrive
|
||||
let l:header_end_index = stridx(l:ctx['buffer'], "\r\n\r\n")
|
||||
if l:header_end_index < 0
|
||||
" no headers found
|
||||
return
|
||||
endif
|
||||
let l:headers = l:ctx['buffer'][:l:header_end_index - 1]
|
||||
let l:ctx['content-length'] = s:get_content_length(l:headers)
|
||||
if l:ctx['content-length'] < 0
|
||||
" invalid content-length
|
||||
call lsp#log('on_stdout', a:id, 'invalid content-length')
|
||||
call s:lsp_stop(a:id)
|
||||
return
|
||||
endif
|
||||
let l:ctx['buffer'] = l:ctx['buffer'][l:header_end_index + 4:] " 4 = len(\r\n\r\n)
|
||||
endif
|
||||
|
||||
if len(l:ctx['buffer']) < l:ctx['content-length']
|
||||
" incomplete message, wait for next buffer to arrive
|
||||
return
|
||||
endif
|
||||
|
||||
" we have full message
|
||||
let l:response_str = l:ctx['buffer'][:l:ctx['content-length'] - 1]
|
||||
let l:ctx['content-length'] = -1
|
||||
|
||||
try
|
||||
let l:response = json_decode(l:response_str)
|
||||
catch
|
||||
call lsp#log('s:on_stdout json_decode failed', v:exception)
|
||||
endtry
|
||||
|
||||
let l:ctx['buffer'] = l:ctx['buffer'][len(l:response_str):]
|
||||
|
||||
if exists('l:response')
|
||||
" call appropriate callbacks
|
||||
let l:on_notification_data = { 'response': l:response }
|
||||
if has_key(l:response, 'method') && has_key(l:response, 'id')
|
||||
" it is a request from a server
|
||||
let l:request = l:response
|
||||
if has_key(l:ctx['opts'], 'on_request')
|
||||
call l:ctx['opts']['on_request'](a:id, l:request)
|
||||
endif
|
||||
elseif has_key(l:response, 'id')
|
||||
" it is a request->response
|
||||
if !(type(l:response['id']) == type(0) || type(l:response['id']) == type(''))
|
||||
" response['id'] can be number | string | null based on the spec
|
||||
call lsp#log('invalid response id. ignoring message', l:response)
|
||||
continue
|
||||
endif
|
||||
if has_key(l:ctx['requests'], l:response['id'])
|
||||
let l:on_notification_data['request'] = l:ctx['requests'][l:response['id']]
|
||||
endif
|
||||
if has_key(l:ctx['opts'], 'on_notification')
|
||||
" call client's on_notification first
|
||||
try
|
||||
call l:ctx['opts']['on_notification'](a:id, l:on_notification_data, 'on_notification')
|
||||
catch
|
||||
call lsp#log('s:on_stdout client option on_notification() error', v:exception, v:throwpoint)
|
||||
endtry
|
||||
endif
|
||||
if has_key(l:ctx['on_notifications'], l:response['id'])
|
||||
" call lsp#client#send({ 'on_notification }) second
|
||||
try
|
||||
call l:ctx['on_notifications'][l:response['id']](a:id, l:on_notification_data, 'on_notification')
|
||||
catch
|
||||
call lsp#log('s:on_stdout client request on_notification() error', v:exception, v:throwpoint)
|
||||
endtry
|
||||
unlet l:ctx['on_notifications'][l:response['id']]
|
||||
endif
|
||||
if has_key(l:ctx['requests'], l:response['id'])
|
||||
unlet l:ctx['requests'][l:response['id']]
|
||||
else
|
||||
call lsp#log('cannot find the request corresponding to response: ', l:response)
|
||||
endif
|
||||
else
|
||||
" it is a notification
|
||||
if has_key(l:ctx['opts'], 'on_notification')
|
||||
try
|
||||
call l:ctx['opts']['on_notification'](a:id, l:on_notification_data, 'on_notification')
|
||||
catch
|
||||
call lsp#log('s:on_stdout on_notification() error', v:exception, v:throwpoint)
|
||||
endtry
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if empty(l:response_str)
|
||||
" buffer is empty, wait for next message to arrive
|
||||
return
|
||||
endif
|
||||
endwhile
|
||||
endfunction
|
||||
|
||||
function! s:get_content_length(headers) abort
|
||||
for l:header in split(a:headers, "\r\n")
|
||||
let l:kvp = split(l:header, ':')
|
||||
if len(l:kvp) == 2
|
||||
if l:kvp[0] =~? '^Content-Length'
|
||||
return str2nr(l:kvp[1], 10)
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
return -1
|
||||
endfunction
|
||||
|
||||
function! s:on_stderr(id, data, event) abort
|
||||
let l:ctx = get(s:clients, a:id, {})
|
||||
if empty(l:ctx)
|
||||
return
|
||||
endif
|
||||
if has_key(l:ctx['opts'], 'on_stderr')
|
||||
try
|
||||
call l:ctx['opts']['on_stderr'](a:id, a:data, a:event)
|
||||
catch
|
||||
call lsp#log('s:on_stderr exception', v:exception, v:throwpoint)
|
||||
echom v:exception
|
||||
endtry
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_exit(id, status, event) abort
|
||||
let l:ctx = get(s:clients, a:id, {})
|
||||
if empty(l:ctx)
|
||||
return
|
||||
endif
|
||||
if has_key(l:ctx['opts'], 'on_exit')
|
||||
try
|
||||
call l:ctx['opts']['on_exit'](a:id, a:status, a:event)
|
||||
catch
|
||||
call lsp#log('s:on_exit exception', v:exception, v:throwpoint)
|
||||
echom v:exception
|
||||
endtry
|
||||
endif
|
||||
call s:dispose_context(a:id)
|
||||
endfunction
|
||||
|
||||
function! s:lsp_start(opts) abort
|
||||
let l:opts = {
|
||||
\ 'on_stdout': function('s:on_stdout'),
|
||||
\ 'on_stderr': function('s:on_stderr'),
|
||||
\ 'on_exit': function('s:on_exit'),
|
||||
\ 'normalize': 'string'
|
||||
\ }
|
||||
if has_key(a:opts, 'env')
|
||||
let l:opts.env = a:opts.env
|
||||
endif
|
||||
|
||||
if has_key(a:opts, 'cmd')
|
||||
let l:client_id = lsp#utils#job#start(a:opts.cmd, l:opts)
|
||||
elseif has_key(a:opts, 'tcp')
|
||||
let l:client_id = lsp#utils#job#connect(a:opts.tcp, l:opts)
|
||||
else
|
||||
return -1
|
||||
endif
|
||||
|
||||
let l:ctx = s:create_context(l:client_id, a:opts)
|
||||
let l:ctx['id'] = l:client_id
|
||||
|
||||
return l:client_id
|
||||
endfunction
|
||||
|
||||
function! s:lsp_stop(id) abort
|
||||
call lsp#utils#job#stop(a:id)
|
||||
endfunction
|
||||
|
||||
let s:send_type_request = 1
|
||||
let s:send_type_notification = 2
|
||||
let s:send_type_response = 3
|
||||
function! s:lsp_send(id, opts, type) abort " opts = { id?, method?, result?, params?, on_notification }
|
||||
let l:ctx = get(s:clients, a:id, {})
|
||||
if empty(l:ctx) | return -1 | endif
|
||||
|
||||
let l:request = { 'jsonrpc': '2.0' }
|
||||
|
||||
if (a:type == s:send_type_request)
|
||||
let l:ctx['request_sequence'] = l:ctx['request_sequence'] + 1
|
||||
let l:request['id'] = l:ctx['request_sequence']
|
||||
let l:ctx['requests'][l:request['id']] = l:request
|
||||
if has_key(a:opts, 'on_notification')
|
||||
let l:ctx['on_notifications'][l:request['id']] = a:opts['on_notification']
|
||||
endif
|
||||
endif
|
||||
|
||||
if has_key(a:opts, 'id')
|
||||
let l:request['id'] = a:opts['id']
|
||||
endif
|
||||
if has_key(a:opts, 'method')
|
||||
let l:request['method'] = a:opts['method']
|
||||
endif
|
||||
if has_key(a:opts, 'params')
|
||||
let l:request['params'] = a:opts['params']
|
||||
endif
|
||||
if has_key(a:opts, 'result')
|
||||
let l:request['result'] = a:opts['result']
|
||||
endif
|
||||
if has_key(a:opts, 'error')
|
||||
let l:request['error'] = a:opts['error']
|
||||
endif
|
||||
|
||||
let l:json = json_encode(l:request)
|
||||
let l:payload = 'Content-Length: ' . len(l:json) . "\r\n\r\n" . l:json
|
||||
|
||||
call lsp#utils#job#send(a:id, l:payload)
|
||||
|
||||
if (a:type == s:send_type_request)
|
||||
let l:id = l:request['id']
|
||||
if get(a:opts, 'sync', 0) !=# 0
|
||||
let l:timeout = get(a:opts, 'sync_timeout', -1)
|
||||
if lsp#utils#_wait(l:timeout, {-> !has_key(l:ctx['requests'], l:request['id'])}, 1) == -1
|
||||
throw 'lsp#client: timeout'
|
||||
endif
|
||||
endif
|
||||
return l:id
|
||||
else
|
||||
return 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:lsp_get_last_request_id(id) abort
|
||||
return s:clients[a:id]['request_sequence']
|
||||
endfunction
|
||||
|
||||
function! s:lsp_is_error(obj_or_response) abort
|
||||
let l:vt = type(a:obj_or_response)
|
||||
if l:vt == type('')
|
||||
return len(a:obj_or_response) > 0
|
||||
elseif l:vt == type({})
|
||||
return has_key(a:obj_or_response, 'error')
|
||||
endif
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:is_server_instantiated_notification(notification) abort
|
||||
return !has_key(a:notification, 'request')
|
||||
endfunction
|
||||
|
||||
function! s:native_out_cb(cbctx, channel, response) abort
|
||||
if !has_key(a:cbctx, 'ctx') | return | endif
|
||||
let l:ctx = a:cbctx['ctx']
|
||||
if has_key(a:response, 'method') && has_key(a:response, 'id')
|
||||
" it is a request from a server
|
||||
let l:request = a:response
|
||||
if has_key(l:ctx['opts'], 'on_request')
|
||||
call l:ctx['opts']['on_request'](l:ctx['id'], l:request)
|
||||
endif
|
||||
elseif !has_key(a:response, 'id') && has_key(l:ctx['opts'], 'on_notification')
|
||||
" it is a notification
|
||||
let l:on_notification_data = { 'response': a:response }
|
||||
try
|
||||
call l:ctx['opts']['on_notification'](l:ctx['id'], l:on_notification_data, 'on_notification')
|
||||
catch
|
||||
call lsp#log('s:native_notification_callback on_notification() error', v:exception, v:throwpoint)
|
||||
endtry
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:native_err_cb(cbctx, channel, response) abort
|
||||
if !has_key(a:cbctx, 'ctx') | return | endif
|
||||
let l:ctx = a:cbctx['ctx']
|
||||
if has_key(l:ctx['opts'], 'on_stderr')
|
||||
try
|
||||
call l:ctx['opts']['on_stderr'](l:ctx['id'], a:response, 'stderr')
|
||||
catch
|
||||
call lsp#log('s:on_stderr exception', v:exception, v:throwpoint)
|
||||
echom v:exception
|
||||
endtry
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" public apis {{{
|
||||
|
||||
function! lsp#client#start(opts) abort
|
||||
if g:lsp_use_native_client && lsp#utils#has_native_lsp_client()
|
||||
if has_key(a:opts, 'cmd')
|
||||
let l:cbctx = {}
|
||||
let l:jobopt = { 'in_mode': 'lsp', 'out_mode': 'lsp', 'noblock': 1,
|
||||
\ 'out_cb': function('s:native_out_cb', [l:cbctx]),
|
||||
\ 'err_cb': function('s:native_err_cb', [l:cbctx]),
|
||||
\ }
|
||||
if has_key(a:opts, 'cwd') | let l:jobopt['cwd'] = a:opts['cwd'] | endif
|
||||
if has_key(a:opts, 'env') | let l:jobopt['env'] = a:opts['env'] | endif
|
||||
let s:jobidseq += 1
|
||||
let l:jobid = s:jobidseq " jobid == clientid
|
||||
call lsp#log_verbose('using native lsp client')
|
||||
let l:job = job_start(a:opts['cmd'], l:jobopt)
|
||||
if job_status(l:job) !=? 'run' | return -1 | endif
|
||||
let l:ctx = s:create_context(l:jobid, a:opts)
|
||||
let l:ctx['id'] = l:jobid
|
||||
let l:ctx['job'] = l:job
|
||||
let l:ctx['channel'] = job_getchannel(l:job)
|
||||
let l:cbctx['ctx'] = l:ctx
|
||||
return l:jobid
|
||||
elseif has_key(a:opts, 'tcp')
|
||||
" add support for tcp
|
||||
call lsp#log('tcp not supported when using native lsp client')
|
||||
return -1
|
||||
endif
|
||||
endif
|
||||
return s:lsp_start(a:opts)
|
||||
endfunction
|
||||
|
||||
function! lsp#client#stop(client_id) abort
|
||||
if g:lsp_use_native_client && lsp#utils#has_native_lsp_client()
|
||||
let l:ctx = get(s:clients, a:client_id, {})
|
||||
if empty(l:ctx) | return | endif
|
||||
call job_stop(l:ctx['job'])
|
||||
else
|
||||
return s:lsp_stop(a:client_id)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#client#send_request(client_id, opts) abort
|
||||
if g:lsp_use_native_client && lsp#utils#has_native_lsp_client()
|
||||
let l:ctx = get(s:clients, a:client_id, {})
|
||||
if empty(l:ctx) | return -1 | endif
|
||||
let l:request = {}
|
||||
" id shouldn't be passed to request as vim will overwrite it. refer to :h language-server-protocol
|
||||
if has_key(a:opts, 'method') | let l:request['method'] = a:opts['method'] | endif
|
||||
if has_key(a:opts, 'params') | let l:request['params'] = a:opts['params'] | endif
|
||||
|
||||
call ch_sendexpr(l:ctx['channel'], l:request, { 'callback': function('s:on_response_native', [l:ctx, l:request]) })
|
||||
let l:ctx['requests'][l:request['id']] = l:request
|
||||
if has_key(a:opts, 'on_notification')
|
||||
let l:ctx['on_notifications'][l:request['id']] = a:opts['on_notification']
|
||||
endif
|
||||
let l:ctx['request_sequence'] = l:request['id']
|
||||
return l:request['id']
|
||||
else
|
||||
return s:lsp_send(a:client_id, a:opts, s:send_type_request)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_response_native(ctx, request, channel, response) abort
|
||||
" request -> response
|
||||
let l:on_notification_data = { 'response': a:response, 'request': a:request }
|
||||
if has_key(a:ctx['opts'], 'on_notification')
|
||||
" call client's on_notification first
|
||||
try
|
||||
call a:ctx['opts']['on_notification'](a:ctx['id'], l:on_notification_data, 'on_notification')
|
||||
catch
|
||||
call lsp#log('s:on_response_native client option on_notification() error', v:exception, v:throwpoint)
|
||||
endtry
|
||||
endif
|
||||
if has_key(a:ctx['on_notifications'], a:request['id'])
|
||||
" call lsp#client#send({ 'on_notification' }) second
|
||||
try
|
||||
call a:ctx['on_notifications'][a:request['id']](a:ctx['id'], l:on_notification_data, 'on_notification')
|
||||
catch
|
||||
call lsp#log('s:on_response_native client request on_notification() error', v:exception, v:throwpoint, a:request, a:response)
|
||||
endtry
|
||||
unlet a:ctx['on_notifications'][a:response['id']]
|
||||
if has_key(a:ctx['requests'], a:response['id'])
|
||||
unlet a:ctx['requests'][a:response['id']]
|
||||
else
|
||||
call lsp#log('cannot find the request corresponding to response: ', a:response)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#client#send_notification(client_id, opts) abort
|
||||
if g:lsp_use_native_client && lsp#utils#has_native_lsp_client()
|
||||
let l:ctx = get(s:clients, a:client_id, {})
|
||||
if empty(l:ctx) | return -1 | endif
|
||||
let l:request = {}
|
||||
if has_key(a:opts, 'method') | let l:request['method'] = a:opts['method'] | endif
|
||||
if has_key(a:opts, 'params') | let l:request['params'] = a:opts['params'] | endif
|
||||
call ch_sendexpr(l:ctx['channel'], l:request)
|
||||
return 0
|
||||
else
|
||||
return s:lsp_send(a:client_id, a:opts, s:send_type_notification)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#client#send_response(client_id, opts) abort
|
||||
if g:lsp_use_native_client && lsp#utils#has_native_lsp_client()
|
||||
let l:ctx = get(s:clients, a:client_id, {})
|
||||
if empty(l:ctx) | return -1 | endif
|
||||
let l:request = {}
|
||||
if has_key(a:opts, 'id') | let l:request['id'] = a:opts['id'] | endif
|
||||
if has_key(a:opts, 'result') | let l:request['result'] = a:opts['result'] | endif
|
||||
if has_key(a:opts, 'error') | let l:request['error'] = a:opts['error'] | endif
|
||||
call ch_sendexpr(l:ctx['channel'], l:request)
|
||||
return 0
|
||||
else
|
||||
return s:lsp_send(a:client_id, a:opts, s:send_type_response)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#client#get_last_request_id(client_id) abort
|
||||
return s:lsp_get_last_request_id(a:client_id)
|
||||
endfunction
|
||||
|
||||
function! lsp#client#is_error(obj_or_response) abort
|
||||
return s:lsp_is_error(a:obj_or_response)
|
||||
endfunction
|
||||
|
||||
function! lsp#client#error_message(obj_or_response) abort
|
||||
try
|
||||
return a:obj_or_response['error']['data']['message']
|
||||
catch
|
||||
endtry
|
||||
try
|
||||
return a:obj_or_response['error']['message']
|
||||
catch
|
||||
endtry
|
||||
return string(a:obj_or_response)
|
||||
endfunction
|
||||
|
||||
function! lsp#client#is_server_instantiated_notification(notification) abort
|
||||
return s:is_server_instantiated_notification(a:notification)
|
||||
endfunction
|
||||
|
||||
" }}}
|
||||
|
||||
let &cpoptions = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
" vim sw=4 ts=4 et
|
||||
@@ -0,0 +1,207 @@
|
||||
" https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
|
||||
let s:enabled = 0
|
||||
|
||||
let s:Markdown = vital#lsp#import('VS.Vim.Syntax.Markdown')
|
||||
let s:MarkupContent = vital#lsp#import('VS.LSP.MarkupContent')
|
||||
let s:FloatingWindow = vital#lsp#import('VS.Vim.Window.FloatingWindow')
|
||||
let s:Window = vital#lsp#import('VS.Vim.Window')
|
||||
let s:Buffer = vital#lsp#import('VS.Vim.Buffer')
|
||||
|
||||
function! lsp#internal#completion#documentation#_enable() abort
|
||||
" don't even bother registering if the feature is disabled
|
||||
if !g:lsp_completion_documentation_enabled | return | endif
|
||||
|
||||
if !s:FloatingWindow.is_available() | return | endif
|
||||
if !exists('##CompleteChanged') | return | endif
|
||||
|
||||
if s:enabled | return | endif
|
||||
let s:enabled = 1
|
||||
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#merge(
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent('CompleteChanged'),
|
||||
\ lsp#callbag#filter({_->g:lsp_completion_documentation_enabled}),
|
||||
\ lsp#callbag#map({->copy(v:event)}),
|
||||
\ lsp#callbag#debounceTime(g:lsp_completion_documentation_delay),
|
||||
\ lsp#callbag#switchMap({event->
|
||||
\ lsp#callbag#pipe(
|
||||
\ s:resolve_completion(event),
|
||||
\ lsp#callbag#tap({managed_user_data->s:show_floating_window(event, managed_user_data)}),
|
||||
\ lsp#callbag#takeUntil(lsp#callbag#fromEvent('CompleteDone'))
|
||||
\ )
|
||||
\ })
|
||||
\ ),
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent('CompleteDone'),
|
||||
\ lsp#callbag#tap({_->s:close_floating_window(v:false)}),
|
||||
\ )
|
||||
\ ),
|
||||
\ lsp#callbag#subscribe(),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! s:resolve_completion(event) abort
|
||||
let l:managed_user_data = lsp#omni#get_managed_user_data_from_completed_item(a:event['completed_item'])
|
||||
if empty(l:managed_user_data)
|
||||
return lsp#callbag#of({})
|
||||
endif
|
||||
|
||||
let l:completion_item = l:managed_user_data['completion_item']
|
||||
|
||||
if has_key(l:completion_item, 'documentation')
|
||||
return lsp#callbag#of(l:managed_user_data)
|
||||
elseif lsp#capabilities#has_completion_resolve_provider(l:managed_user_data['server_name'])
|
||||
return lsp#callbag#pipe(
|
||||
\ lsp#request(l:managed_user_data['server_name'], {
|
||||
\ 'method': 'completionItem/resolve',
|
||||
\ 'params': l:completion_item,
|
||||
\ }),
|
||||
\ lsp#callbag#map({x->{
|
||||
\ 'server_name': l:managed_user_data['server_name'],
|
||||
\ 'completion_item': x['response']['result'],
|
||||
\ 'complete_position': l:managed_user_data['complete_position'],
|
||||
\ }})
|
||||
\ )
|
||||
else
|
||||
return lsp#callbag#of(l:managed_user_data)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:show_floating_window(event, managed_user_data) abort
|
||||
if empty(a:managed_user_data) || !pumvisible()
|
||||
call s:close_floating_window(v:true)
|
||||
return
|
||||
endif
|
||||
let l:completion_item = a:managed_user_data['completion_item']
|
||||
|
||||
let l:contents = []
|
||||
|
||||
" Add detail field if provided.
|
||||
if type(get(l:completion_item, 'detail', v:null)) == type('')
|
||||
if !empty(l:completion_item.detail)
|
||||
let l:detail = s:MarkupContent.normalize({
|
||||
\ 'language': &filetype,
|
||||
\ 'value': l:completion_item['detail'],
|
||||
\ }, {
|
||||
\ 'compact': !g:lsp_preview_fixup_conceal
|
||||
\ })
|
||||
let l:contents += [l:detail]
|
||||
endif
|
||||
endif
|
||||
|
||||
" Add documentation filed if provided.
|
||||
let l:documentation = s:MarkupContent.normalize(get(l:completion_item, 'documentation', ''), {
|
||||
\ 'compact': !g:lsp_preview_fixup_conceal
|
||||
\ })
|
||||
if !empty(l:documentation)
|
||||
let l:contents += [l:documentation]
|
||||
endif
|
||||
|
||||
" Ignore if contents is empty.
|
||||
if empty(l:contents)
|
||||
return s:close_floating_window(v:true)
|
||||
endif
|
||||
|
||||
" Update contents.
|
||||
let l:doc_win = s:get_doc_win()
|
||||
call deletebufline(l:doc_win.get_bufnr(), 1, '$')
|
||||
call setbufline(l:doc_win.get_bufnr(), 1, lsp#utils#_split_by_eol(join(l:contents, "\n\n")))
|
||||
|
||||
" Calculate layout.
|
||||
if g:lsp_float_max_width >= 1
|
||||
let l:maxwidth = g:lsp_float_max_width
|
||||
elseif g:lsp_float_max_width == 0
|
||||
let l:maxwidth = &columns
|
||||
else
|
||||
let l:maxwidth = float2nr(&columns * 0.4)
|
||||
endif
|
||||
let l:size = l:doc_win.get_size({
|
||||
\ 'maxwidth': l:maxwidth,
|
||||
\ 'maxheight': float2nr(&lines * 0.4),
|
||||
\ })
|
||||
let l:margin_right = &columns - 1 - (float2nr(a:event.col) + float2nr(a:event.width) + 1 + (a:event.scrollbar ? 1 : 0))
|
||||
let l:margin_left = float2nr(a:event.col) - 3
|
||||
if l:size.width < l:margin_right
|
||||
" do nothing
|
||||
elseif l:margin_left <= l:margin_right
|
||||
let l:size.width = l:margin_right
|
||||
else
|
||||
let l:size.width = l:margin_left
|
||||
endif
|
||||
let l:pos = s:compute_position(a:event, l:size)
|
||||
if empty(l:pos)
|
||||
call s:close_floating_window(v:true)
|
||||
return
|
||||
endif
|
||||
|
||||
" Show popupmenu and apply markdown syntax.
|
||||
call l:doc_win.open({
|
||||
\ 'row': l:pos[0] + 1,
|
||||
\ 'col': l:pos[1] + 1,
|
||||
\ 'width': l:size.width,
|
||||
\ 'height': l:size.height,
|
||||
\ 'border': v:true,
|
||||
\ 'topline': 1,
|
||||
\ })
|
||||
call s:Window.do(l:doc_win.get_winid(), { -> s:Markdown.apply() })
|
||||
endfunction
|
||||
|
||||
function! s:close_floating_window(force) abort
|
||||
" Ignore `CompleteDone` if it occurred by `complete()` because in this case, the popup menu will re-appear immediately.
|
||||
let l:ctx = {}
|
||||
function! l:ctx.callback(force) abort
|
||||
if !pumvisible() || a:force
|
||||
call s:get_doc_win().close()
|
||||
endif
|
||||
endfunction
|
||||
call timer_start(1, { -> l:ctx.callback(a:force) })
|
||||
endfunction
|
||||
|
||||
function! s:compute_position(event, size) abort
|
||||
let l:col_if_right = a:event.col + a:event.width + 1 + (a:event.scrollbar ? 1 : 0)
|
||||
let l:col_if_left = a:event.col - a:size.width - 2
|
||||
|
||||
if a:size.width >= (&columns - l:col_if_right)
|
||||
let l:col = l:col_if_left
|
||||
else
|
||||
let l:col = l:col_if_right
|
||||
endif
|
||||
|
||||
if l:col <= 0
|
||||
return []
|
||||
endif
|
||||
if &columns <= l:col + a:size.width
|
||||
return []
|
||||
endif
|
||||
|
||||
return [a:event.row, l:col]
|
||||
endfunction
|
||||
|
||||
function! s:get_doc_win() abort
|
||||
if exists('s:doc_win')
|
||||
return s:doc_win
|
||||
endif
|
||||
|
||||
let s:doc_win = s:FloatingWindow.new({
|
||||
\ 'on_opened': { -> execute('doautocmd <nomodeline> User lsp_float_opened') },
|
||||
\ 'on_closed': { -> execute('doautocmd <nomodeline> User lsp_float_closed') }
|
||||
\ })
|
||||
call s:doc_win.set_var('&wrap', 1)
|
||||
call s:doc_win.set_var('&conceallevel', 2)
|
||||
noautocmd silent let l:bufnr = s:Buffer.create()
|
||||
call s:doc_win.set_bufnr(l:bufnr)
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&buftype', 'nofile')
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&bufhidden', 'hide')
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&buflisted', 0)
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&swapfile', 0)
|
||||
return s:doc_win
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#completion#documentation#_disable() abort
|
||||
if !s:enabled | return | endif
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
@@ -0,0 +1,20 @@
|
||||
function! lsp#internal#diagnostics#_enable() abort
|
||||
" don't even bother registering if the feature is disabled
|
||||
if !g:lsp_diagnostics_enabled | return | endif
|
||||
|
||||
call lsp#internal#diagnostics#state#_enable() " Needs to be the first one to register
|
||||
call lsp#internal#diagnostics#echo#_enable()
|
||||
call lsp#internal#diagnostics#highlights#_enable()
|
||||
call lsp#internal#diagnostics#float#_enable()
|
||||
call lsp#internal#diagnostics#signs#_enable()
|
||||
call lsp#internal#diagnostics#virtual_text#_enable()
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#_disable() abort
|
||||
call lsp#internal#diagnostics#echo#_disable()
|
||||
call lsp#internal#diagnostics#float#_disable()
|
||||
call lsp#internal#diagnostics#highlights#_disable()
|
||||
call lsp#internal#diagnostics#virtual_text#_disable()
|
||||
call lsp#internal#diagnostics#signs#_disable()
|
||||
call lsp#internal#diagnostics#state#_disable() " Needs to be the last one to unregister
|
||||
endfunction
|
||||
@@ -0,0 +1,40 @@
|
||||
" options = {
|
||||
" buffers: '1' " optional string, defaults to current buffer, '*' for all buffers
|
||||
" }
|
||||
function! lsp#internal#diagnostics#document_diagnostics_command#do(options) abort
|
||||
if !g:lsp_diagnostics_enabled
|
||||
call lsp#utils#error(':LspDocumentDiagnostics g:lsp_diagnostics_enabled must be enabled')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:buffers = get(a:options, 'buffers', '')
|
||||
|
||||
let l:filtered_diagnostics = {}
|
||||
|
||||
if l:buffers ==# '*'
|
||||
let l:filtered_diagnostics = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_uri_and_server()
|
||||
else
|
||||
let l:uri = lsp#utils#get_buffer_uri()
|
||||
if !empty(l:uri)
|
||||
let l:filtered_diagnostics[l:uri] = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri)
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:result = []
|
||||
for [l:uri, l:value] in items(l:filtered_diagnostics)
|
||||
if lsp#internal#diagnostics#state#_is_enabled_for_buffer(bufnr(lsp#utils#uri_to_path(l:uri)))
|
||||
for l:diagnostics in values(l:value)
|
||||
let l:result += lsp#ui#vim#utils#diagnostics_to_loc_list({ 'response': l:diagnostics })
|
||||
endfor
|
||||
endif
|
||||
endfor
|
||||
|
||||
if empty(l:result)
|
||||
call lsp#utils#error('No diagnostics results')
|
||||
return
|
||||
else
|
||||
call setloclist(0, l:result)
|
||||
echo 'Retrieved diagnostics results'
|
||||
botright lopen
|
||||
endif
|
||||
endfunction
|
||||
@@ -0,0 +1,41 @@
|
||||
" internal state for whether it is enabled or not to avoid multiple subscriptions
|
||||
let s:enabled = 0
|
||||
|
||||
function! lsp#internal#diagnostics#echo#_enable() abort
|
||||
" don't even bother registering if the feature is disabled
|
||||
if !g:lsp_diagnostics_echo_cursor | return | endif
|
||||
|
||||
if s:enabled | return | endif
|
||||
let s:enabled = 1
|
||||
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent(['CursorMoved']),
|
||||
\ lsp#callbag#filter({_->g:lsp_diagnostics_echo_cursor}),
|
||||
\ lsp#callbag#debounceTime(g:lsp_diagnostics_echo_delay),
|
||||
\ lsp#callbag#map({_->{'bufnr': bufnr('%'), 'curpos': getcurpos()[0:2], 'changedtick': b:changedtick }}),
|
||||
\ lsp#callbag#distinctUntilChanged({a,b -> a['bufnr'] == b['bufnr'] && a['curpos'] == b['curpos'] && a['changedtick'] == b['changedtick']}),
|
||||
\ lsp#callbag#filter({_->mode() is# 'n'}),
|
||||
\ lsp#callbag#filter({_->getbufvar(bufnr('%'), '&buftype') !=# 'terminal' }),
|
||||
\ lsp#callbag#map({_->lsp#internal#diagnostics#under_cursor#get_diagnostic()}),
|
||||
\ lsp#callbag#subscribe({x->s:echo(x)}),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#echo#_disable() abort
|
||||
if !s:enabled | return | endif
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
let s:enabled = 0
|
||||
endfunction
|
||||
|
||||
function! s:echo(diagnostic) abort
|
||||
if !empty(a:diagnostic) && has_key(a:diagnostic, 'message')
|
||||
call lsp#utils#echo_with_truncation('LSP: '. substitute(a:diagnostic['message'], '\n\+', ' ', 'g'))
|
||||
let s:displaying_message = 1
|
||||
elseif get(s:, 'displaying_message', 0)
|
||||
call lsp#utils#echo_with_truncation('')
|
||||
let s:displaying_message = 0
|
||||
endif
|
||||
endfunction
|
||||
@@ -0,0 +1,26 @@
|
||||
" Return first error line or v:null if there are no errors
|
||||
" available.
|
||||
" options = {
|
||||
" 'bufnr': '', " optional
|
||||
" }
|
||||
function! lsp#internal#diagnostics#first_line#get_first_error_line(options) abort
|
||||
let l:bufnr = get(a:options, 'bufnr', bufnr('%'))
|
||||
|
||||
if !lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr)
|
||||
return v:null
|
||||
endif
|
||||
|
||||
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
|
||||
let l:diagnostics_by_server = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri)
|
||||
|
||||
let l:first_error_line = v:null
|
||||
for l:diagnostics_response in values(l:diagnostics_by_server)
|
||||
for l:item in lsp#utils#iteratable(l:diagnostics_response['params']['diagnostics'])
|
||||
let l:severity = get(l:item, 'severity', 1)
|
||||
if l:severity ==# 1 && (l:first_error_line ==# v:null || l:first_error_line ># l:item['range']['start']['line'])
|
||||
let l:first_error_line = l:item['range']['start']['line']
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
return l:first_error_line ==# v:null ? v:null : l:first_error_line + 1
|
||||
endfunction
|
||||
@@ -0,0 +1,123 @@
|
||||
" internal state for whether it is enabled or not to avoid multiple subscriptions
|
||||
let s:enabled = 0
|
||||
|
||||
let s:Markdown = vital#lsp#import('VS.Vim.Syntax.Markdown')
|
||||
let s:MarkupContent = vital#lsp#import('VS.LSP.MarkupContent')
|
||||
let s:FloatingWindow = vital#lsp#import('VS.Vim.Window.FloatingWindow')
|
||||
let s:Window = vital#lsp#import('VS.Vim.Window')
|
||||
let s:Buffer = vital#lsp#import('VS.Vim.Buffer')
|
||||
|
||||
function! lsp#internal#diagnostics#float#_enable() abort
|
||||
" don't even bother registering if the feature is disabled
|
||||
if !lsp#ui#vim#output#float_supported() | return | endif
|
||||
if !g:lsp_diagnostics_float_cursor | return | endif
|
||||
|
||||
if s:enabled | return | endif
|
||||
let s:enabled = 1
|
||||
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#merge(
|
||||
\ lsp#callbag#fromEvent(['CursorMoved', 'CursorHold']),
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent(['InsertEnter']),
|
||||
\ lsp#callbag#filter({_->!g:lsp_diagnostics_float_insert_mode_enabled}),
|
||||
\ lsp#callbag#tap({_->s:hide_float()}),
|
||||
\ )
|
||||
\ ),
|
||||
\ lsp#callbag#filter({_->g:lsp_diagnostics_float_cursor}),
|
||||
\ lsp#callbag#tap({_->s:hide_float()}),
|
||||
\ lsp#callbag#debounceTime(g:lsp_diagnostics_float_delay),
|
||||
\ lsp#callbag#map({_->{'bufnr': bufnr('%'), 'curpos': getcurpos()[0:2], 'changedtick': b:changedtick }}),
|
||||
\ lsp#callbag#distinctUntilChanged({a,b -> a['bufnr'] == b['bufnr'] && a['curpos'] == b['curpos'] && a['changedtick'] == b['changedtick']}),
|
||||
\ lsp#callbag#filter({_->mode() is# 'n'}),
|
||||
\ lsp#callbag#filter({_->getbufvar(bufnr('%'), '&buftype') !=# 'terminal' }),
|
||||
\ lsp#callbag#map({_->lsp#internal#diagnostics#under_cursor#get_diagnostic()}),
|
||||
\ lsp#callbag#subscribe({x->s:show_float(x)}),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#float#_disable() abort
|
||||
if !s:enabled | return | endif
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
let s:enabled = 0
|
||||
endfunction
|
||||
|
||||
function! s:show_float(diagnostic) abort
|
||||
let l:doc_win = s:get_doc_win()
|
||||
if !empty(a:diagnostic) && has_key(a:diagnostic, 'message')
|
||||
" Update contents.
|
||||
call deletebufline(l:doc_win.get_bufnr(), 1, '$')
|
||||
call setbufline(l:doc_win.get_bufnr(), 1, lsp#utils#_split_by_eol(a:diagnostic['message']))
|
||||
|
||||
" Compute size.
|
||||
if g:lsp_float_max_width >= 1
|
||||
let l:maxwidth = g:lsp_float_max_width
|
||||
elseif g:lsp_float_max_width == 0
|
||||
let l:maxwidth = &columns
|
||||
else
|
||||
let l:maxwidth = float2nr(&columns * 0.4)
|
||||
endif
|
||||
let l:size = l:doc_win.get_size({
|
||||
\ 'maxwidth': l:maxwidth,
|
||||
\ 'maxheight': float2nr(&lines * 0.4),
|
||||
\ })
|
||||
|
||||
" Compute position.
|
||||
let l:pos = s:compute_position(l:size)
|
||||
|
||||
" Open window.
|
||||
call l:doc_win.open({
|
||||
\ 'row': l:pos[0],
|
||||
\ 'col': l:pos[1],
|
||||
\ 'width': l:size.width,
|
||||
\ 'height': l:size.height,
|
||||
\ 'border': v:true,
|
||||
\ 'topline': 1,
|
||||
\ })
|
||||
else
|
||||
call s:hide_float()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:hide_float() abort
|
||||
let l:doc_win = s:get_doc_win()
|
||||
call l:doc_win.close()
|
||||
endfunction
|
||||
|
||||
function! s:get_doc_win() abort
|
||||
if exists('s:doc_win')
|
||||
return s:doc_win
|
||||
endif
|
||||
|
||||
let s:doc_win = s:FloatingWindow.new({
|
||||
\ 'on_opened': { -> execute('doautocmd <nomodeline> User lsp_float_opened') },
|
||||
\ 'on_closed': { -> execute('doautocmd <nomodeline> User lsp_float_closed') }
|
||||
\ })
|
||||
call s:doc_win.set_var('&wrap', 1)
|
||||
call s:doc_win.set_var('&conceallevel', 2)
|
||||
noautocmd silent let l:bufnr = s:Buffer.create()
|
||||
call s:doc_win.set_bufnr(l:bufnr)
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&buftype', 'nofile')
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&bufhidden', 'hide')
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&buflisted', 0)
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&swapfile', 0)
|
||||
return s:doc_win
|
||||
endfunction
|
||||
|
||||
function! s:compute_position(size) abort
|
||||
let l:pos = screenpos(0, line('.'), col('.'))
|
||||
if l:pos.row == 0 && l:pos.col == 0
|
||||
let l:pos = {'curscol': screencol(), 'row': screenrow()}
|
||||
endif
|
||||
let l:pos = [l:pos.row + 1, l:pos.curscol + 1]
|
||||
if l:pos[0] + a:size.height > &lines
|
||||
let l:pos[0] = l:pos[0] - a:size.height - 3
|
||||
endif
|
||||
if l:pos[1] + a:size.width > &columns
|
||||
let l:pos[1] = l:pos[1] - a:size.width - 3
|
||||
endif
|
||||
return l:pos
|
||||
endfunction
|
||||
@@ -0,0 +1,207 @@
|
||||
" internal state for whether it is enabled or not to avoid multiple subscriptions
|
||||
let s:enabled = 0
|
||||
let s:namespace_id = '' " will be set when enabled
|
||||
|
||||
let s:severity_sign_names_mapping = {
|
||||
\ 1: 'LspError',
|
||||
\ 2: 'LspWarning',
|
||||
\ 3: 'LspInformation',
|
||||
\ 4: 'LspHint',
|
||||
\ }
|
||||
|
||||
if !hlexists('LspErrorHighlight')
|
||||
highlight link LspErrorHighlight Error
|
||||
endif
|
||||
|
||||
if !hlexists('LspWarningHighlight')
|
||||
highlight link LspWarningHighlight Todo
|
||||
endif
|
||||
|
||||
if !hlexists('LspInformationHighlight')
|
||||
highlight link LspInformationHighlight Normal
|
||||
endif
|
||||
|
||||
if !hlexists('LspHintHighlight')
|
||||
highlight link LspHintHighlight Normal
|
||||
endif
|
||||
|
||||
function! lsp#internal#diagnostics#highlights#_enable() abort
|
||||
" don't even bother registering if the feature is disabled
|
||||
if !lsp#utils#_has_highlights() | return | endif
|
||||
if !g:lsp_diagnostics_highlights_enabled | return | endif
|
||||
|
||||
if s:enabled | return | endif
|
||||
let s:enabled = 1
|
||||
|
||||
if empty(s:namespace_id)
|
||||
if has('nvim')
|
||||
let s:namespace_id = nvim_create_namespace('vim_lsp_diagnostics_highlights')
|
||||
else
|
||||
let s:namespace_id = 'vim_lsp_diagnostics_highlights'
|
||||
for l:severity in keys(s:severity_sign_names_mapping)
|
||||
let l:hl_group = s:severity_sign_names_mapping[l:severity] . 'Highlight'
|
||||
call prop_type_add(s:get_prop_type_name(l:severity),
|
||||
\ {'highlight': l:hl_group, 'combine': v:true, 'priority': lsp#internal#textprop#priority('diagnostics_highlight') })
|
||||
endfor
|
||||
endif
|
||||
endif
|
||||
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#merge(
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
|
||||
\ && has_key(x['response'], 'method') && x['response']['method'] ==# '$/vimlsp/lsp_diagnostics_updated'
|
||||
\ && !lsp#client#is_error(x['response'])}),
|
||||
\ lsp#callbag#map({x->x['response']['params']}),
|
||||
\ ),
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent(['InsertEnter', 'InsertLeave']),
|
||||
\ lsp#callbag#filter({_->!g:lsp_diagnostics_highlights_insert_mode_enabled}),
|
||||
\ lsp#callbag#map({_->{ 'uri': lsp#utils#get_buffer_uri() }}),
|
||||
\ ),
|
||||
\ ),
|
||||
\ lsp#callbag#filter({_->g:lsp_diagnostics_highlights_enabled}),
|
||||
\ lsp#callbag#debounceTime(g:lsp_diagnostics_highlights_delay),
|
||||
\ lsp#callbag#tap({x->s:clear_highlights(x)}),
|
||||
\ lsp#callbag#tap({x->s:set_highlights(x)}),
|
||||
\ lsp#callbag#subscribe(),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#highlights#_disable() abort
|
||||
if !s:enabled | return | endif
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
call s:clear_all_highlights()
|
||||
let s:enabled = 0
|
||||
endfunction
|
||||
|
||||
function! s:get_prop_type_name(severity) abort
|
||||
return s:namespace_id . '_' . get(s:severity_sign_names_mapping, a:severity, 'LspError')
|
||||
endfunction
|
||||
|
||||
function! s:clear_all_highlights() abort
|
||||
for l:bufnr in range(1, bufnr('$'))
|
||||
if bufexists(l:bufnr) && bufloaded(l:bufnr)
|
||||
if has('nvim')
|
||||
call nvim_buf_clear_namespace(l:bufnr, s:namespace_id, 0, -1)
|
||||
else
|
||||
for l:severity in keys(s:severity_sign_names_mapping)
|
||||
try
|
||||
" TODO: need to check for valid range before calling prop_add
|
||||
" See https://github.com/prabirshrestha/vim-lsp/pull/721
|
||||
silent! call prop_remove({
|
||||
\ 'type': s:get_prop_type_name(l:severity),
|
||||
\ 'bufnr': l:bufnr,
|
||||
\ 'all': v:true })
|
||||
catch
|
||||
call lsp#log('diagnostics', 'clear_all_highlights', 'prop_remove', v:exception, v:throwpoint)
|
||||
endtry
|
||||
endfor
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:clear_highlights(params) abort
|
||||
" TODO: optimize by looking at params
|
||||
call s:clear_all_highlights()
|
||||
endfunction
|
||||
|
||||
function! s:set_highlights(params) abort
|
||||
" TODO: optimize by looking at params
|
||||
if !g:lsp_diagnostics_highlights_insert_mode_enabled
|
||||
if mode()[0] ==# 'i' | return | endif
|
||||
endif
|
||||
|
||||
for l:bufnr in range(1, bufnr('$'))
|
||||
if lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr) && bufexists(l:bufnr) && bufloaded(l:bufnr)
|
||||
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
|
||||
for [l:server, l:diagnostics_response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
|
||||
call s:place_highlights(l:server, l:diagnostics_response, l:bufnr)
|
||||
endfor
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:place_highlights(server, diagnostics_response, bufnr) abort
|
||||
" TODO: make diagnostics highlights same across vim and neovim
|
||||
for l:item in lsp#utils#iteratable(a:diagnostics_response['params']['diagnostics'])
|
||||
let [l:start_line, l:start_col] = lsp#utils#position#lsp_to_vim(a:bufnr, l:item['range']['start'])
|
||||
let [l:end_line, l:end_col] = lsp#utils#position#lsp_to_vim(a:bufnr, l:item['range']['end'])
|
||||
let l:severity = get(l:item, 'severity', 3)
|
||||
let l:hl_group = get(s:severity_sign_names_mapping, l:severity, 'LspError') . 'Highlight'
|
||||
if has('nvim')
|
||||
for l:line in range(l:start_line, l:end_line)
|
||||
if l:line == l:start_line
|
||||
let l:highlight_start_col = l:start_col
|
||||
else
|
||||
let l:highlight_start_col = 1
|
||||
endif
|
||||
|
||||
if l:line == l:end_line
|
||||
let l:highlight_end_col = l:end_col
|
||||
else
|
||||
" neovim treats -1 as end of line, special handle it later
|
||||
" when calling nvim_buf_add_higlight
|
||||
let l:highlight_end_col = -1
|
||||
endif
|
||||
|
||||
if l:start_line == l:end_line && l:highlight_start_col == l:highlight_end_col
|
||||
" higlighting same start col and end col on same line
|
||||
" doesn't work so use -1 for start col
|
||||
let l:highlight_start_col -= 1
|
||||
if l:highlight_start_col <= 0
|
||||
let l:highlight_start_col = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
call nvim_buf_add_highlight(a:bufnr, s:namespace_id, l:hl_group,
|
||||
\ l:line - 1, l:highlight_start_col - 1, l:highlight_end_col == -1 ? -1 : l:highlight_end_col)
|
||||
endfor
|
||||
else
|
||||
if l:start_line == l:end_line
|
||||
try
|
||||
" TODO: need to check for valid range before calling prop_add
|
||||
" See https://github.com/prabirshrestha/vim-lsp/pull/721
|
||||
silent! call prop_add(l:start_line, l:start_col, {
|
||||
\ 'end_col': l:end_col,
|
||||
\ 'bufnr': a:bufnr,
|
||||
\ 'type': s:get_prop_type_name(l:severity),
|
||||
\ })
|
||||
catch
|
||||
call lsp#log('diagnostics', 'place_highlights', 'prop_add', v:exception, v:throwpoint)
|
||||
endtry
|
||||
else
|
||||
for l:line in range(l:start_line, l:end_line)
|
||||
if l:line == l:start_line
|
||||
let l:highlight_start_col = l:start_col
|
||||
else
|
||||
let l:highlight_start_col = 1
|
||||
endif
|
||||
|
||||
if l:line == l:end_line
|
||||
let l:highlight_end_col = l:end_col
|
||||
else
|
||||
let l:highlight_end_col = strlen(getbufline(a:bufnr, l:line, l:line)[0]) + 1
|
||||
endif
|
||||
|
||||
try
|
||||
" TODO: need to check for valid range before calling prop_add
|
||||
" See https://github.com/prabirshrestha/vim-lsp/pull/721
|
||||
silent! call prop_add(l:line, l:highlight_start_col, {
|
||||
\ 'end_col': l:highlight_end_col,
|
||||
\ 'bufnr': a:bufnr,
|
||||
\ 'type': s:get_prop_type_name(l:severity),
|
||||
\ })
|
||||
catch
|
||||
call lsp#log('diagnostics', 'place_highlights', 'prop_add', v:exception, v:throwpoint)
|
||||
endtry
|
||||
endfor
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
@@ -0,0 +1,199 @@
|
||||
function! s:severity_of(diagnostic) abort
|
||||
return get(a:diagnostic, 'severity', 1)
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#movement#_next_error(...) abort
|
||||
let l:diagnostics = filter(s:get_all_buffer_diagnostics(),
|
||||
\ {_, diagnostic -> s:severity_of(diagnostic) ==# 1 })
|
||||
let l:options = lsp#utils#parse_command_options(a:000)
|
||||
call s:next_diagnostic(l:diagnostics, l:options)
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#movement#_next_warning(...) abort
|
||||
let l:diagnostics = filter(s:get_all_buffer_diagnostics(),
|
||||
\ {_, diagnostic -> s:severity_of(diagnostic) ==# 2 })
|
||||
let l:options = lsp#utils#parse_command_options(a:000)
|
||||
call s:next_diagnostic(l:diagnostics, l:options)
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#movement#_next_diagnostics(...) abort
|
||||
let l:options = lsp#utils#parse_command_options(a:000)
|
||||
call s:next_diagnostic(s:get_all_buffer_diagnostics(), l:options)
|
||||
endfunction
|
||||
|
||||
function! s:next_diagnostic(diagnostics, options) abort
|
||||
if !len(a:diagnostics)
|
||||
return
|
||||
endif
|
||||
call sort(a:diagnostics, 's:compare_diagnostics')
|
||||
|
||||
let l:wrap = 1
|
||||
if has_key(a:options, 'wrap')
|
||||
let l:wrap = a:options['wrap']
|
||||
endif
|
||||
|
||||
let l:view = winsaveview()
|
||||
let l:next_line = 0
|
||||
let l:next_col = 0
|
||||
for l:diagnostic in a:diagnostics
|
||||
let [l:line, l:col] = lsp#utils#position#lsp_to_vim('%', l:diagnostic['range']['start'])
|
||||
if l:line > l:view['lnum']
|
||||
\ || (l:line == l:view['lnum'] && l:col > l:view['col'] + 1)
|
||||
let l:next_line = l:line
|
||||
let l:next_col = l:col - 1
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
if l:next_line == 0
|
||||
if !l:wrap
|
||||
return
|
||||
endif
|
||||
" Wrap to start
|
||||
let [l:next_line, l:next_col] = lsp#utils#position#lsp_to_vim('%', a:diagnostics[0]['range']['start'])
|
||||
let l:next_col -= 1
|
||||
endif
|
||||
|
||||
let l:view['lnum'] = l:next_line
|
||||
let l:view['col'] = l:next_col
|
||||
let l:view['topline'] = 1
|
||||
let l:height = winheight(0)
|
||||
let l:totalnum = line('$')
|
||||
if l:totalnum > l:height
|
||||
let l:half = l:height / 2
|
||||
if l:totalnum - l:half < l:view['lnum']
|
||||
let l:view['topline'] = l:totalnum - l:height + 1
|
||||
else
|
||||
let l:view['topline'] = l:view['lnum'] - l:half
|
||||
endif
|
||||
endif
|
||||
call winrestview(l:view)
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#movement#_previous_error(...) abort
|
||||
let l:diagnostics = filter(s:get_all_buffer_diagnostics(),
|
||||
\ {_, diagnostic -> s:severity_of(diagnostic) ==# 1 })
|
||||
let l:options = lsp#utils#parse_command_options(a:000)
|
||||
call s:previous_diagnostic(l:diagnostics, l:options)
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#movement#_previous_warning(...) abort
|
||||
let l:options = lsp#utils#parse_command_options(a:000)
|
||||
let l:diagnostics = filter(s:get_all_buffer_diagnostics(),
|
||||
\ {_, diagnostic -> s:severity_of(diagnostic) ==# 2 })
|
||||
call s:previous_diagnostic(l:diagnostics, l:options)
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#movement#_previous_diagnostics(...) abort
|
||||
let l:options = lsp#utils#parse_command_options(a:000)
|
||||
call s:previous_diagnostic(s:get_all_buffer_diagnostics(), l:options)
|
||||
endfunction
|
||||
|
||||
function! s:previous_diagnostic(diagnostics, options) abort
|
||||
if !len(a:diagnostics)
|
||||
return
|
||||
endif
|
||||
call sort(a:diagnostics, 's:compare_diagnostics')
|
||||
|
||||
let l:wrap = 1
|
||||
if has_key(a:options, 'wrap')
|
||||
let l:wrap = a:options['wrap']
|
||||
endif
|
||||
|
||||
let l:view = winsaveview()
|
||||
let l:next_line = 0
|
||||
let l:next_col = 0
|
||||
let l:index = len(a:diagnostics) - 1
|
||||
while l:index >= 0
|
||||
let [l:line, l:col] = lsp#utils#position#lsp_to_vim('%', a:diagnostics[l:index]['range']['start'])
|
||||
if l:line < l:view['lnum']
|
||||
\ || (l:line == l:view['lnum'] && l:col < l:view['col'])
|
||||
let l:next_line = l:line
|
||||
let l:next_col = l:col - 1
|
||||
break
|
||||
endif
|
||||
let l:index = l:index - 1
|
||||
endwhile
|
||||
|
||||
if l:next_line == 0
|
||||
if !l:wrap
|
||||
return
|
||||
endif
|
||||
" Wrap to end
|
||||
let [l:next_line, l:next_col] = lsp#utils#position#lsp_to_vim('%', a:diagnostics[-1]['range']['start'])
|
||||
let l:next_col -= 1
|
||||
endif
|
||||
|
||||
let l:view['lnum'] = l:next_line
|
||||
let l:view['col'] = l:next_col
|
||||
let l:view['topline'] = 1
|
||||
let l:height = winheight(0)
|
||||
let l:totalnum = line('$')
|
||||
if l:totalnum > l:height
|
||||
let l:half = l:height / 2
|
||||
if l:totalnum - l:half < l:view['lnum']
|
||||
let l:view['topline'] = l:totalnum - l:height + 1
|
||||
else
|
||||
let l:view['topline'] = l:view['lnum'] - l:half
|
||||
endif
|
||||
endif
|
||||
call winrestview(l:view)
|
||||
endfunction
|
||||
|
||||
function! s:get_diagnostics(uri) abort
|
||||
if has_key(s:diagnostics, a:uri)
|
||||
return [1, s:diagnostics[a:uri]]
|
||||
else
|
||||
if s:is_win
|
||||
" vim in windows always uses upper case for drive letter, so use lowercase in case lang server uses lowercase
|
||||
" https://github.com/theia-ide/typescript-language-server/issues/23
|
||||
let l:uri = substitute(a:uri, '^' . a:uri[:8], tolower(a:uri[:8]), '')
|
||||
if has_key(s:diagnostics, l:uri)
|
||||
return [1, s:diagnostics[l:uri]]
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
return [0, {}]
|
||||
endfunction
|
||||
|
||||
" Get diagnostics for the current buffer URI from all servers
|
||||
function! s:get_all_buffer_diagnostics(...) abort
|
||||
let l:server = get(a:000, 0, '')
|
||||
|
||||
let l:bufnr = bufnr('%')
|
||||
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
|
||||
|
||||
if !lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr)
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:diagnostics_by_server = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri)
|
||||
let l:diagnostics = []
|
||||
if empty(l:server)
|
||||
for l:item in values(l:diagnostics_by_server)
|
||||
let l:diagnostics += lsp#utils#iteratable(l:item['params']['diagnostics'])
|
||||
endfor
|
||||
else
|
||||
if has_key(l:diagnostics_by_server, l:server)
|
||||
let l:diagnostics = lsp#utils#iteratable(l:diagnostics_by_server[l:server]['params']['diagnostics'])
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:diagnostics
|
||||
endfunction
|
||||
|
||||
function! s:compare_diagnostics(d1, d2) abort
|
||||
let l:range1 = a:d1['range']
|
||||
let l:line1 = l:range1['start']['line'] + 1
|
||||
let l:col1 = l:range1['start']['character'] + 1
|
||||
let l:range2 = a:d2['range']
|
||||
let l:line2 = l:range2['start']['line'] + 1
|
||||
let l:col2 = l:range2['start']['character'] + 1
|
||||
|
||||
if l:line1 == l:line2
|
||||
return l:col1 == l:col2 ? 0 : l:col1 > l:col2 ? 1 : -1
|
||||
else
|
||||
return l:line1 > l:line2 ? 1 : -1
|
||||
endif
|
||||
endfunction
|
||||
" vim sw=4 ts=4 et
|
||||
@@ -0,0 +1,151 @@
|
||||
" internal state for whether it is enabled or not to avoid multiple subscriptions
|
||||
let s:enabled = 0
|
||||
let s:sign_group = 'vim_lsp'
|
||||
|
||||
let s:severity_sign_names_mapping = {
|
||||
\ 1: 'LspError',
|
||||
\ 2: 'LspWarning',
|
||||
\ 3: 'LspInformation',
|
||||
\ 4: 'LspHint',
|
||||
\ }
|
||||
|
||||
if !hlexists('LspErrorText')
|
||||
highlight link LspErrorText Error
|
||||
endif
|
||||
|
||||
if !hlexists('LspWarningText')
|
||||
highlight link LspWarningText Todo
|
||||
endif
|
||||
|
||||
if !hlexists('LspInformationText')
|
||||
highlight link LspInformationText Normal
|
||||
endif
|
||||
|
||||
if !hlexists('LspHintText')
|
||||
highlight link LspHintText Normal
|
||||
endif
|
||||
|
||||
function! lsp#internal#diagnostics#signs#_enable() abort
|
||||
" don't even bother registering if the feature is disabled
|
||||
if !lsp#utils#_has_signs() | return | endif
|
||||
if !g:lsp_diagnostics_signs_enabled | return | endif
|
||||
|
||||
if s:enabled | return | endif
|
||||
let s:enabled = 1
|
||||
|
||||
call s:define_sign('LspError', 'E>', g:lsp_diagnostics_signs_error)
|
||||
call s:define_sign('LspWarning', 'W>', g:lsp_diagnostics_signs_warning)
|
||||
call s:define_sign('LspInformation', 'I>', g:lsp_diagnostics_signs_information)
|
||||
call s:define_sign('LspHint', 'H>', g:lsp_diagnostics_signs_hint)
|
||||
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#merge(
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
|
||||
\ && has_key(x['response'], 'method') && x['response']['method'] ==# '$/vimlsp/lsp_diagnostics_updated'
|
||||
\ && !lsp#client#is_error(x['response'])}),
|
||||
\ lsp#callbag#map({x->x['response']['params']}),
|
||||
\ ),
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent(['InsertEnter', 'InsertLeave']),
|
||||
\ lsp#callbag#filter({_->!g:lsp_diagnostics_signs_insert_mode_enabled}),
|
||||
\ lsp#callbag#map({_->{ 'uri': lsp#utils#get_buffer_uri() }}),
|
||||
\ ),
|
||||
\ ),
|
||||
\ lsp#callbag#filter({_->g:lsp_diagnostics_signs_enabled}),
|
||||
\ lsp#callbag#debounceTime(g:lsp_diagnostics_signs_delay),
|
||||
\ lsp#callbag#tap({x->s:clear_signs(x)}),
|
||||
\ lsp#callbag#tap({x->s:set_signs(x)}),
|
||||
\ lsp#callbag#subscribe(),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#signs#_disable() abort
|
||||
if !s:enabled | return | endif
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
call s:clear_all_signs()
|
||||
call s:undefine_signs()
|
||||
let s:enabled = 0
|
||||
endfunction
|
||||
|
||||
" Set default sign text to handle case when user provides empty dict
|
||||
function! s:define_sign(sign_name, sign_default_text, sign_options) abort
|
||||
let l:options = {
|
||||
\ 'text': get(a:sign_options, 'text', a:sign_default_text),
|
||||
\ 'texthl': a:sign_name . 'Text',
|
||||
\ 'linehl': a:sign_name . 'Line',
|
||||
\ }
|
||||
let l:sign_icon = get(a:sign_options, 'icon', '')
|
||||
if !empty(l:sign_icon)
|
||||
let l:options['icon'] = l:sign_icon
|
||||
endif
|
||||
call sign_define(a:sign_name, l:options)
|
||||
endfunction
|
||||
|
||||
function! s:undefine_signs() abort
|
||||
call sign_undefine('LspError')
|
||||
call sign_undefine('LspWarning')
|
||||
call sign_undefine('LspInformation')
|
||||
call sign_undefine('LspHint')
|
||||
endfunction
|
||||
|
||||
function! s:clear_all_signs() abort
|
||||
call sign_unplace(s:sign_group)
|
||||
endfunction
|
||||
|
||||
" params => {
|
||||
" server: '' " optional
|
||||
" uri: '' " optional
|
||||
" }
|
||||
function! s:clear_signs(params) abort
|
||||
" TODO: optimize by looking at params
|
||||
call s:clear_all_signs()
|
||||
endfunction
|
||||
|
||||
" params => {
|
||||
" server: '' " optional
|
||||
" uri: '' " optional
|
||||
" }
|
||||
function! s:set_signs(params) abort
|
||||
" TODO: optimize by looking at params
|
||||
if !g:lsp_diagnostics_signs_insert_mode_enabled
|
||||
if mode()[0] ==# 'i' | return | endif
|
||||
endif
|
||||
|
||||
for l:bufnr in range(1, bufnr('$'))
|
||||
if lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr) && bufexists(l:bufnr) && bufloaded(l:bufnr)
|
||||
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
|
||||
for [l:server, l:diagnostics_response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
|
||||
call s:place_signs(l:server, l:diagnostics_response, l:bufnr)
|
||||
endfor
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:place_signs(server, diagnostics_response, bufnr) abort
|
||||
for l:item in lsp#utils#iteratable(a:diagnostics_response['params']['diagnostics'])
|
||||
let l:line = lsp#utils#position#lsp_line_to_vim(a:bufnr, l:item['range']['start'])
|
||||
|
||||
" Some language servers report an unexpected EOF one line past the end
|
||||
" key 'linecount' may be missing.
|
||||
if has_key(getbufinfo(a:bufnr)[0], 'linecount')
|
||||
if l:line == getbufinfo(a:bufnr)[0].linecount + 1
|
||||
let l:line = l:line - 1
|
||||
endif
|
||||
endif
|
||||
|
||||
if has_key(l:item, 'severity') && !empty(l:item['severity'])
|
||||
let l:sign_name = get(s:severity_sign_names_mapping, l:item['severity'], 'LspError')
|
||||
let l:sign_priority = get(g:lsp_diagnostics_signs_priority_map, l:sign_name, g:lsp_diagnostics_signs_priority)
|
||||
let l:sign_priority = get(g:lsp_diagnostics_signs_priority_map,
|
||||
\ a:server . '_' . l:sign_name, l:sign_priority)
|
||||
" pass 0 and let vim generate sign id
|
||||
let l:sign_id = sign_place(0, s:sign_group, l:sign_name, a:bufnr,
|
||||
\{ 'lnum': l:line, 'priority': l:sign_priority })
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
@@ -0,0 +1,173 @@
|
||||
" https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
|
||||
"
|
||||
" Refer to https://github.com/microsoft/language-server-protocol/pull/1019 on normalization of urls.
|
||||
" {
|
||||
" 'normalized_uri': {
|
||||
" 'server_name': {
|
||||
" 'method': 'textDocument/publishDiagnostics',
|
||||
" 'params': {
|
||||
" 'uri': 'uri', " this uri is not normalized and is exactly what server returns
|
||||
" 'dignostics': [ " array can never be null but can be empty
|
||||
" https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
|
||||
" { range, message, severity?, code?, codeDesciption?, source?, tags?, relatedInformation?, data? }
|
||||
" ]
|
||||
" }
|
||||
" }
|
||||
" }
|
||||
" Note: Do not remove when buffer unloads or doesn't exist since some server
|
||||
" may send diagnsotics information regardless of textDocument/didOpen.
|
||||
" buffer state is removed when server exits.
|
||||
" TODO: reset buffer state when server initializes. ignoring for now for perf.
|
||||
let s:diagnostics_state = {}
|
||||
|
||||
" internal state for whether it is enabled or not to avoid multiple subscriptions
|
||||
let s:enabled = 0
|
||||
|
||||
let s:diagnostic_kinds = {
|
||||
\ 1: 'error',
|
||||
\ 2: 'warning',
|
||||
\ 3: 'information',
|
||||
\ 4: 'hint',
|
||||
\ }
|
||||
|
||||
function! lsp#internal#diagnostics#state#_enable() abort
|
||||
" don't even bother registering if the feature is disabled
|
||||
if !g:lsp_diagnostics_enabled | return | endif
|
||||
|
||||
if s:enabled | return | endif
|
||||
let s:enabled = 1
|
||||
|
||||
call lsp#internal#diagnostics#state#_reset()
|
||||
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#merge(
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
|
||||
\ && get(x['response'], 'method', '') ==# 'textDocument/publishDiagnostics'}),
|
||||
\ lsp#callbag#tap({x->s:on_text_documentation_publish_diagnostics(x['server'], x['response'])}),
|
||||
\ ),
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
|
||||
\ && get(x['response'], 'method', '') ==# '$/vimlsp/lsp_server_exit' }),
|
||||
\ lsp#callbag#tap({x->s:on_exit(x['response'])}),
|
||||
\ ),
|
||||
\ ),
|
||||
\ lsp#callbag#subscribe(),
|
||||
\ )
|
||||
|
||||
call s:notify_diagnostics_update()
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#state#_disable() abort
|
||||
if !s:enabled | return | endif
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
call lsp#internal#diagnostics#state#_reset()
|
||||
call s:notify_diagnostics_update()
|
||||
let s:enabled = 0
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#state#_reset() abort
|
||||
let s:diagnostics_state = {}
|
||||
let s:diagnostics_disabled_buffers = {}
|
||||
endfunction
|
||||
|
||||
" callers should always treat the return value as immutable
|
||||
" @return {
|
||||
" 'servername': response
|
||||
" }
|
||||
function! lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(uri) abort
|
||||
return get(s:diagnostics_state, lsp#utils#normalize_uri(a:uri), {})
|
||||
endfunction
|
||||
|
||||
" callers should always treat the return value as immutable.
|
||||
" callers should treat uri as normalized via lsp#utils#normalize_uri
|
||||
" @return {
|
||||
" 'normalized_uri': {
|
||||
" 'servername': response
|
||||
" }
|
||||
" }
|
||||
function! lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_uri_and_server() abort
|
||||
return s:diagnostics_state
|
||||
endfunction
|
||||
|
||||
function! s:on_text_documentation_publish_diagnostics(server, response) abort
|
||||
if lsp#client#is_error(a:response) | return | endif
|
||||
let l:normalized_uri = lsp#utils#normalize_uri(a:response['params']['uri'])
|
||||
if !has_key(s:diagnostics_state, l:normalized_uri)
|
||||
let s:diagnostics_state[l:normalized_uri] = {}
|
||||
endif
|
||||
let s:diagnostics_state[l:normalized_uri][a:server] = a:response
|
||||
call s:notify_diagnostics_update(a:server, l:normalized_uri)
|
||||
endfunction
|
||||
|
||||
function! s:on_exit(response) abort
|
||||
let l:server = a:response['params']['server']
|
||||
let l:notify = 0
|
||||
for [l:key, l:value] in items(s:diagnostics_state)
|
||||
if has_key(l:value, l:server)
|
||||
let l:notify = 1
|
||||
call remove(l:value, l:server)
|
||||
endif
|
||||
endfor
|
||||
if l:notify | call s:notify_diagnostics_update(l:server) | endif
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#state#_force_notify_buffer(buffer) abort
|
||||
" TODO: optimize buffer only
|
||||
call s:notify_diagnostics_update()
|
||||
endfunction
|
||||
|
||||
" call s:notify_diagnostics_update()
|
||||
" call s:notify_diagnostics_update('server')
|
||||
" call s:notify_diagnostics_update('server', 'uri')
|
||||
function! s:notify_diagnostics_update(...) abort
|
||||
let l:data = { 'server': '$vimlsp', 'response': { 'method': '$/vimlsp/lsp_diagnostics_updated', 'params': {} } }
|
||||
" if a:0 > 0 | let l:data['response']['params']['server'] = a:1 | endif
|
||||
" if a:0 > 1 | let l:data['response']['params']['uri'] = a:2 | endif
|
||||
call lsp#stream(1, l:data)
|
||||
doautocmd <nomodeline> User lsp_diagnostics_updated
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#state#_enable_for_buffer(bufnr) abort
|
||||
if getbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1) == 0
|
||||
call setbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1)
|
||||
call s:notify_diagnostics_update()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#state#_disable_for_buffer(bufnr) abort
|
||||
if getbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1) != 0
|
||||
call setbufvar(a:bufnr, 'lsp_diagnostics_enabled', 0)
|
||||
call s:notify_diagnostics_update()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#state#_is_enabled_for_buffer(bufnr) abort
|
||||
return getbufvar(a:bufnr, 'lsp_diagnostics_enabled', 1) == 1
|
||||
endfunction
|
||||
|
||||
" Return dict with diagnostic counts for the specified buffer
|
||||
" { 'error': 1, 'warning': 0, 'information': 0, 'hint': 0 }
|
||||
function! lsp#internal#diagnostics#state#_get_diagnostics_count_for_buffer(bufnr) abort
|
||||
let l:counts = {
|
||||
\ 'error': 0,
|
||||
\ 'warning': 0,
|
||||
\ 'information': 0,
|
||||
\ 'hint': 0,
|
||||
\ }
|
||||
if lsp#internal#diagnostics#state#_is_enabled_for_buffer(a:bufnr)
|
||||
let l:uri = lsp#utils#get_buffer_uri(a:bufnr)
|
||||
for [l:_, l:response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
|
||||
for l:diagnostic in lsp#utils#iteratable(l:response['params']['diagnostics'])
|
||||
let l:key = get(s:diagnostic_kinds, get(l:diagnostic, 'severity', 1) , 'error')
|
||||
let l:counts[l:key] += 1
|
||||
endfor
|
||||
endfor
|
||||
end
|
||||
return l:counts
|
||||
endfunction
|
||||
@@ -0,0 +1,48 @@
|
||||
" Returns a diagnostic object, or empty dictionary if no diagnostics are
|
||||
" available.
|
||||
" options = {
|
||||
" 'server': '', " optional
|
||||
" }
|
||||
function! lsp#internal#diagnostics#under_cursor#get_diagnostic(...) abort
|
||||
let l:options = get(a:000, 0, {})
|
||||
let l:server = get(l:options, 'server', '')
|
||||
let l:bufnr = bufnr('%')
|
||||
|
||||
if !lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr)
|
||||
return {}
|
||||
endif
|
||||
|
||||
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
|
||||
|
||||
let l:diagnostics_by_server = lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri)
|
||||
let l:diagnostics = []
|
||||
if empty(l:server)
|
||||
for l:item in values(l:diagnostics_by_server)
|
||||
let l:diagnostics += lsp#utils#iteratable(l:item['params']['diagnostics'])
|
||||
endfor
|
||||
else
|
||||
if has_key(l:diagnostics_by_server, l:server)
|
||||
let l:diagnostics = lsp#utils#iteratable(l:diagnostics_by_server[l:server]['params']['diagnostics'])
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:line = line('.')
|
||||
let l:col = col('.')
|
||||
|
||||
let l:closest_diagnostic = {}
|
||||
let l:closest_distance = -1
|
||||
|
||||
for l:diagnostic in l:diagnostics
|
||||
let [l:start_line, l:start_col] = lsp#utils#position#lsp_to_vim('%', l:diagnostic['range']['start'])
|
||||
|
||||
if l:line == l:start_line
|
||||
let l:distance = abs(l:start_col - l:col)
|
||||
if l:closest_distance < 0 || l:distance < l:closest_distance
|
||||
let l:closest_diagnostic = l:diagnostic
|
||||
let l:closest_distance = l:distance
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:closest_diagnostic
|
||||
endfunction
|
||||
@@ -0,0 +1,191 @@
|
||||
" internal state for whether it is enabled or not to avoid multiple subscriptions
|
||||
let s:enabled = 0
|
||||
let s:namespace_id = '' " will be set when enabled
|
||||
let s:severity_sign_names_mapping = {
|
||||
\ 1: 'LspError',
|
||||
\ 2: 'LspWarning',
|
||||
\ 3: 'LspInformation',
|
||||
\ 4: 'LspHint',
|
||||
\ }
|
||||
|
||||
if !hlexists('LspErrorVirtualText')
|
||||
if !hlexists('LspErrorText')
|
||||
highlight link LspErrorVirtualText Error
|
||||
else
|
||||
highlight link LspErrorVirtualText LspErrorText
|
||||
endif
|
||||
endif
|
||||
|
||||
if !hlexists('LspWarningVirtualText')
|
||||
if !hlexists('LspWarningText')
|
||||
highlight link LspWarningVirtualText Todo
|
||||
else
|
||||
highlight link LspWarningVirtualText LspWarningText
|
||||
endif
|
||||
endif
|
||||
|
||||
if !hlexists('LspInformationVirtualText')
|
||||
if !hlexists('LspInformationText')
|
||||
highlight link LspInformationVirtualText Normal
|
||||
else
|
||||
highlight link LspInformationVirtualText LspInformationText
|
||||
endif
|
||||
endif
|
||||
|
||||
if !hlexists('LspHintVirtualText')
|
||||
if !hlexists('LspHintText')
|
||||
highlight link LspHintVirtualText Normal
|
||||
else
|
||||
highlight link LspHintVirtualText LspHintText
|
||||
endif
|
||||
endif
|
||||
|
||||
function! lsp#internal#diagnostics#virtual_text#_enable() abort
|
||||
" don't even bother registering if the feature is disabled
|
||||
if !lsp#utils#_has_nvim_virtual_text() && !lsp#utils#_has_vim_virtual_text() | return | endif
|
||||
if !g:lsp_diagnostics_virtual_text_enabled | return | endif
|
||||
|
||||
if s:enabled | return | endif
|
||||
let s:enabled = 1
|
||||
|
||||
if has('nvim')
|
||||
if empty(s:namespace_id)
|
||||
let s:namespace_id = nvim_create_namespace('vim_lsp_diagnostic_virtual_text')
|
||||
endif
|
||||
else
|
||||
if index(prop_type_list(), 'vim_lsp_LspError_virtual_text') ==# -1
|
||||
call prop_type_add('vim_lsp_LspError_virtual_text', { 'highlight': 'LspErrorVirtualText' })
|
||||
call prop_type_add('vim_lsp_LspWarning_virtual_text', { 'highlight': 'LspWarningVirtualText' })
|
||||
call prop_type_add('vim_lsp_LspInformation_virtual_text', { 'highlight': 'LspInformationVirtualText' })
|
||||
call prop_type_add('vim_lsp_LspHint_virtual_text', { 'highlight': 'LspHintVirtualText' })
|
||||
endif
|
||||
endif
|
||||
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#merge(
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
|
||||
\ && has_key(x['response'], 'method') && x['response']['method'] ==# '$/vimlsp/lsp_diagnostics_updated'
|
||||
\ && !lsp#client#is_error(x['response'])}),
|
||||
\ lsp#callbag#map({x->x['response']['params']}),
|
||||
\ ),
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent(['InsertEnter', 'InsertLeave']),
|
||||
\ lsp#callbag#filter({_->!g:lsp_diagnostics_virtual_text_insert_mode_enabled}),
|
||||
\ lsp#callbag#map({_->{ 'uri': lsp#utils#get_buffer_uri() }}),
|
||||
\ ),
|
||||
\ ),
|
||||
\ lsp#callbag#filter({_->g:lsp_diagnostics_virtual_text_enabled}),
|
||||
\ lsp#callbag#debounceTime(g:lsp_diagnostics_virtual_text_delay),
|
||||
\ lsp#callbag#tap({x->s:clear_virtual_text(x)}),
|
||||
\ lsp#callbag#tap({x->s:set_virtual_text(x)}),
|
||||
\ lsp#callbag#subscribe(),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#diagnostics#virtual_text#_disable() abort
|
||||
if !s:enabled | return | endif
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
call s:clear_all_virtual_text()
|
||||
let s:enabled = 0
|
||||
endfunction
|
||||
|
||||
function! s:clear_all_virtual_text() abort
|
||||
if has('nvim')
|
||||
for l:bufnr in nvim_list_bufs()
|
||||
if bufexists(l:bufnr) && bufloaded(l:bufnr)
|
||||
call nvim_buf_clear_namespace(l:bufnr, s:namespace_id, 0, -1)
|
||||
endif
|
||||
endfor
|
||||
else
|
||||
let l:types = ['vim_lsp_LspError_virtual_text', 'vim_lsp_LspWarning_virtual_text', 'vim_lsp_LspInformation_virtual_text', 'vim_lsp_LspHint_virtual_text']
|
||||
for l:bufnr in map(copy(getbufinfo()), 'v:val.bufnr')
|
||||
if lsp#utils#_has_prop_remove_types()
|
||||
call prop_remove({'types': l:types, 'bufnr': l:bufnr, 'all': v:true})
|
||||
else
|
||||
for l:type in l:types
|
||||
call prop_remove({'type': l:type, 'bufnr': l:bufnr, 'all': v:true})
|
||||
endfor
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" params => {
|
||||
" server: '' " optional
|
||||
" uri: '' " optional
|
||||
" }
|
||||
function! s:clear_virtual_text(params) abort
|
||||
" TODO: optimize by looking at params
|
||||
call s:clear_all_virtual_text()
|
||||
endfunction
|
||||
|
||||
" params => {
|
||||
" server: '' " optional
|
||||
" uri: '' " optional
|
||||
" }
|
||||
function! s:set_virtual_text(params) abort
|
||||
" TODO: optimize by looking at params
|
||||
if !g:lsp_diagnostics_virtual_text_insert_mode_enabled
|
||||
if mode()[0] ==# 'i' | return | endif
|
||||
endif
|
||||
|
||||
if has('nvim')
|
||||
for l:bufnr in nvim_list_bufs()
|
||||
if lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr) && bufexists(l:bufnr) && bufloaded(l:bufnr)
|
||||
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
|
||||
for [l:server, l:diagnostics_response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
|
||||
call s:place_virtual_text(l:server, l:diagnostics_response, l:bufnr)
|
||||
endfor
|
||||
endif
|
||||
endfor
|
||||
else
|
||||
for l:bufnr in map(copy(getbufinfo()), 'v:val.bufnr')
|
||||
if lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr) && bufexists(l:bufnr) && bufloaded(l:bufnr)
|
||||
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
|
||||
for [l:server, l:diagnostics_response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
|
||||
call s:place_virtual_text(l:server, l:diagnostics_response, l:bufnr)
|
||||
endfor
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:place_virtual_text(server, diagnostics_response, bufnr) abort
|
||||
for l:item in lsp#utils#iteratable(a:diagnostics_response['params']['diagnostics'])
|
||||
let l:line = lsp#utils#position#lsp_line_to_vim(a:bufnr, l:item['range']['start'])
|
||||
let l:name = get(s:severity_sign_names_mapping, get(l:item, 'severity', 3), 'LspError')
|
||||
let l:text = g:lsp_diagnostics_virtual_text_prefix . l:item['message']
|
||||
|
||||
" Some language servers report an unexpected EOF one line past the end
|
||||
if l:line == getbufinfo(a:bufnr)[0].linecount + 1
|
||||
let l:line = l:line - 1
|
||||
endif
|
||||
|
||||
if has('nvim')
|
||||
let l:hl_name = l:name . 'VirtualText'
|
||||
" need to do -1 for virtual text
|
||||
call nvim_buf_set_virtual_text(a:bufnr, s:namespace_id, l:line - 1,
|
||||
\ [[l:text, l:hl_name]], {})
|
||||
else
|
||||
" it's an error to add virtual text on lines that don't exist
|
||||
" anymore due to async processing, just skip such diagnostics
|
||||
if l:line <= getbufinfo(a:bufnr)[0].linecount
|
||||
let l:type = 'vim_lsp_' . l:name . '_virtual_text'
|
||||
call prop_remove({'all': v:true, 'type': l:type, 'bufnr': a:bufnr}, l:line)
|
||||
call prop_add(
|
||||
\ l:line, 0,
|
||||
\ {
|
||||
\ 'type': l:type, 'text': l:text, 'bufnr': a:bufnr,
|
||||
\ 'text_align': g:lsp_diagnostics_virtual_text_align,
|
||||
\ 'text_padding_left': g:lsp_diagnostics_virtual_text_padding_left,
|
||||
\ 'text_wrap': g:lsp_diagnostics_virtual_text_wrap,
|
||||
\ })
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
@@ -0,0 +1,131 @@
|
||||
" https://microsoft.github.io/language-server-protocol/specification#textDocument_codeAction
|
||||
|
||||
" internal state for whether it is enabled or not to avoid multiple subscriptions
|
||||
let s:enabled = 0
|
||||
|
||||
let s:sign_group = 'vim_lsp_document_code_action_signs'
|
||||
|
||||
if !hlexists('LspCodeActionText')
|
||||
highlight link LspCodeActionText Normal
|
||||
endif
|
||||
|
||||
function! lsp#internal#document_code_action#signs#_enable() abort
|
||||
if !lsp#utils#_has_signs() | return | endif
|
||||
" don't even bother registering if the feature is disabled
|
||||
if !g:lsp_document_code_action_signs_enabled | return | endif
|
||||
|
||||
if s:enabled | return | endif
|
||||
let s:enabled = 1
|
||||
|
||||
call s:define_sign('LspCodeAction', 'A>', g:lsp_document_code_action_signs_hint)
|
||||
|
||||
" Note:
|
||||
" - update CodeAction signs when CusorMoved or CursorHold
|
||||
" - clear signs when InsertEnter or BufLeave
|
||||
" - debounce code action requests
|
||||
" - automatically switch to latest code action request via switchMap()
|
||||
" - cancel code action request via takeUntil() when BufLeave
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#merge(
|
||||
\ lsp#callbag#fromEvent(['CursorMoved', 'CursorHold']),
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent(['InsertEnter', 'BufLeave']),
|
||||
\ lsp#callbag#tap({_ -> s:clear_signs() }),
|
||||
\ )
|
||||
\ ),
|
||||
\ lsp#callbag#filter({_ -> g:lsp_document_code_action_signs_enabled }),
|
||||
\ lsp#callbag#debounceTime(g:lsp_document_code_action_signs_delay),
|
||||
\ lsp#callbag#map({_->{'bufnr': bufnr('%'), 'curpos': getcurpos()[0:2], 'changedtick': b:changedtick }}),
|
||||
\ lsp#callbag#distinctUntilChanged({a,b -> a['bufnr'] == b['bufnr'] && a['curpos'] == b['curpos'] && a['changedtick'] == b['changedtick']}),
|
||||
\ lsp#callbag#filter({_->mode() is# 'n' && getbufvar(bufnr('%'), '&buftype') !=# 'terminal' }),
|
||||
\ lsp#callbag#switchMap({_->
|
||||
\ lsp#callbag#pipe(
|
||||
\ s:send_request(),
|
||||
\ lsp#callbag#materialize(),
|
||||
\ lsp#callbag#filter({x->lsp#callbag#isNextNotification(x)}),
|
||||
\ lsp#callbag#map({x->x['value']}),
|
||||
\ lsp#callbag#takeUntil(
|
||||
\ lsp#callbag#fromEvent('BufLeave')
|
||||
\ )
|
||||
\ )
|
||||
\ }),
|
||||
\ lsp#callbag#subscribe({x->s:set_signs(x)}),
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#document_code_action#signs#_disable() abort
|
||||
if !s:enabled | return | endif
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:send_request() abort
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_code_action_provider(v:val)')
|
||||
|
||||
if empty(l:servers)
|
||||
return lsp#callbag#empty()
|
||||
endif
|
||||
|
||||
let l:range = lsp#utils#range#_get_current_line_range()
|
||||
return lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromList(l:servers),
|
||||
\ lsp#callbag#flatMap({server->
|
||||
\ lsp#request(server, {
|
||||
\ 'method': 'textDocument/codeAction',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'range': l:range,
|
||||
\ 'context': {
|
||||
\ 'diagnostics': [],
|
||||
\ 'only': ['', 'quickfix', 'refactor', 'refactor.extract', 'refactor.inline', 'refactor.rewrite'],
|
||||
\ }
|
||||
\ }
|
||||
\ })
|
||||
\ }),
|
||||
\ lsp#callbag#filter({x-> !lsp#client#is_error(x['response']) && !empty(x['response']['result'])}),
|
||||
\ lsp#callbag#take(1),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! s:clear_signs() abort
|
||||
call sign_unplace(s:sign_group)
|
||||
endfunction
|
||||
|
||||
function! s:set_signs(data) abort
|
||||
call s:clear_signs()
|
||||
|
||||
if lsp#client#is_error(a:data['response']) | return | endif
|
||||
|
||||
if empty(a:data['response']['result'])
|
||||
return
|
||||
endif
|
||||
|
||||
let l:bufnr = bufnr(lsp#utils#uri_to_path(a:data['request']['params']['textDocument']['uri']))
|
||||
call s:place_signs(a:data, l:bufnr)
|
||||
endfunction
|
||||
|
||||
" Set default sign text to handle case when user provides empty dict
|
||||
function! s:define_sign(sign_name, sign_default_text, sign_options) abort
|
||||
let l:options = {
|
||||
\ 'text': get(a:sign_options, 'text', a:sign_default_text),
|
||||
\ 'texthl': a:sign_name . 'Text',
|
||||
\ 'linehl': a:sign_name . 'Line',
|
||||
\ }
|
||||
let l:sign_icon = get(a:sign_options, 'icon', '')
|
||||
if !empty(l:sign_icon)
|
||||
let l:options['icon'] = l:sign_icon
|
||||
endif
|
||||
call sign_define(a:sign_name, l:options)
|
||||
endfunction
|
||||
|
||||
function! s:place_signs(data, bufnr) abort
|
||||
if !bufexists(a:bufnr) || !bufloaded(a:bufnr)
|
||||
return
|
||||
endif
|
||||
let l:sign_priority = g:lsp_document_code_action_signs_priority
|
||||
let l:line = lsp#utils#position#lsp_line_to_vim(a:bufnr, a:data['request']['params']['range']['start'])
|
||||
let l:sign_id = sign_place(0, s:sign_group, 'LspCodeAction', a:bufnr,
|
||||
\ { 'lnum': l:line, 'priority': l:sign_priority })
|
||||
endfunction
|
||||
@@ -0,0 +1,86 @@
|
||||
" options - {
|
||||
" bufnr: bufnr('%') " required
|
||||
" server - 'server_name' " optional
|
||||
" sync: 0 " optional, defaults to 0 (async)
|
||||
" }
|
||||
function! lsp#internal#document_formatting#format(options) abort
|
||||
let l:mode = mode()
|
||||
if l:mode =~# '[vV]' || l:mode ==# "\<C-V>"
|
||||
return lsp#internal#document_range_formatting#format(a:options)
|
||||
endif
|
||||
|
||||
if has_key(a:options, 'server')
|
||||
let l:servers = [a:options['server']]
|
||||
else
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_document_formatting_provider(v:val)')
|
||||
endif
|
||||
|
||||
if len(l:servers) == 0
|
||||
let l:filetype = getbufvar(a:options['bufnr'], '&filetype')
|
||||
call lsp#utils#error('textDocument/formatting not supported for ' . l:filetype)
|
||||
return
|
||||
endif
|
||||
|
||||
" TODO: ask user to select server for formatting if there are multiple servers
|
||||
let l:server = l:servers[0]
|
||||
|
||||
redraw | echo 'Formatting Document ...'
|
||||
|
||||
call lsp#_new_command()
|
||||
|
||||
let l:request = {
|
||||
\ 'method': 'textDocument/formatting',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(a:options['bufnr']),
|
||||
\ 'options': {
|
||||
\ 'tabSize': lsp#utils#buffer#get_indent_size(a:options['bufnr']),
|
||||
\ 'insertSpaces': getbufvar(a:options['bufnr'], '&expandtab') ? v:true : v:false,
|
||||
\ }
|
||||
\ },
|
||||
\ 'bufnr': a:options['bufnr'],
|
||||
\ }
|
||||
|
||||
if get(a:options, 'sync', 0) == 1
|
||||
try
|
||||
let l:x = lsp#callbag#pipe(
|
||||
\ lsp#request(l:server, l:request),
|
||||
\ lsp#callbag#takeUntil(lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'command')}),
|
||||
\ )),
|
||||
\ lsp#callbag#toList(),
|
||||
\ ).wait({ 'sleep': get(a:options, 'sleep', 1), 'timeout': get(a:options, 'timeout', g:lsp_format_sync_timeout) })
|
||||
call s:format_next(l:x[0])
|
||||
call s:format_complete()
|
||||
catch
|
||||
call s:format_error(v:exception . ' ' . v:throwpoint)
|
||||
endtry
|
||||
else
|
||||
return lsp#callbag#pipe(
|
||||
\ lsp#request(l:server, l:request),
|
||||
\ lsp#callbag#takeUntil(lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'command')}),
|
||||
\ )),
|
||||
\ lsp#callbag#subscribe({
|
||||
\ 'next':{x->s:format_next(x)},
|
||||
\ 'error': {x->s:format_error(e)},
|
||||
\ 'complete': {->s:format_complete()},
|
||||
\ }),
|
||||
\ )
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:format_next(x) abort
|
||||
if lsp#client#is_error(a:x['response']) | return | endif
|
||||
call lsp#utils#text_edit#apply_text_edits(a:x['request']['params']['textDocument']['uri'], get(a:x['response'], 'result', ''))
|
||||
endfunction
|
||||
|
||||
function! s:format_error(e) abort
|
||||
call lsp#log('Formatting Document Failed', a:e)
|
||||
call lsp#utils#error('Formatting Document Failed.' . (type(a:e) == type('') ? a:e : ''))
|
||||
endfunction
|
||||
|
||||
function! s:format_complete() abort
|
||||
redraw | echo 'Formatting Document complete'
|
||||
endfunction
|
||||
@@ -0,0 +1,238 @@
|
||||
let s:use_vim_textprops = lsp#utils#_has_textprops() && !has('nvim')
|
||||
let s:prop_id = 11
|
||||
|
||||
function! lsp#internal#document_highlight#_enable() abort
|
||||
" don't event bother registering if the feature is disabled
|
||||
if !g:lsp_document_highlight_enabled | return | endif
|
||||
|
||||
" Highlight group for references
|
||||
if !hlexists('lspReference')
|
||||
highlight link lspReference CursorColumn
|
||||
endif
|
||||
|
||||
" Note:
|
||||
" - update highlight references when CusorMoved or CursorHold
|
||||
" - clear highlights when InsertEnter or BufLeave
|
||||
" - debounce highlight requests
|
||||
" - automatically switch to latest highlight request via switchMap()
|
||||
" - cancel highlight request via takeUntil() when BufLeave
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#merge(
|
||||
\ lsp#callbag#fromEvent(['CursorMoved', 'CursorHold']),
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent(['InsertEnter', 'BufLeave']),
|
||||
\ lsp#callbag#tap({_ -> s:clear_highlights() }),
|
||||
\ )
|
||||
\ ),
|
||||
\ lsp#callbag#filter({_ -> g:lsp_document_highlight_enabled }),
|
||||
\ lsp#callbag#debounceTime(g:lsp_document_highlight_delay),
|
||||
\ lsp#callbag#map({_->{'bufnr': bufnr('%'), 'curpos': getcurpos()[0:2], 'changedtick': b:changedtick }}),
|
||||
\ lsp#callbag#distinctUntilChanged({a,b -> a['bufnr'] == b['bufnr'] && a['curpos'] == b['curpos'] && a['changedtick'] == b['changedtick']}),
|
||||
\ lsp#callbag#filter({_->mode() is# 'n' && getbufvar(bufnr('%'), '&buftype') !=# 'terminal' }),
|
||||
\ lsp#callbag#switchMap({_->
|
||||
\ lsp#callbag#pipe(
|
||||
\ s:send_highlight_request(),
|
||||
\ lsp#callbag#materialize(),
|
||||
\ lsp#callbag#filter({x->lsp#callbag#isNextNotification(x)}),
|
||||
\ lsp#callbag#map({x->x['value']}),
|
||||
\ lsp#callbag#takeUntil(
|
||||
\ lsp#callbag#fromEvent('BufLeave')
|
||||
\ )
|
||||
\ )
|
||||
\ }),
|
||||
\ lsp#callbag#filter({_->mode() is# 'n'}),
|
||||
\ lsp#callbag#subscribe({x->s:set_highlights(x)}),
|
||||
\)
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#document_highlight#_disable() abort
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:send_highlight_request() abort
|
||||
let l:capability = 'lsp#capabilities#has_document_highlight_provider(v:val)'
|
||||
let l:servers = filter(lsp#get_allowed_servers(), l:capability)
|
||||
|
||||
if empty(l:servers)
|
||||
return lsp#callbag#empty()
|
||||
endif
|
||||
|
||||
return lsp#request(l:servers[0], {
|
||||
\ 'method': 'textDocument/documentHighlight',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'position': lsp#get_position(),
|
||||
\ },
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
function! s:set_highlights(data) abort
|
||||
let l:bufnr = bufnr('%')
|
||||
|
||||
call s:clear_highlights()
|
||||
|
||||
if mode() !=# 'n' | return | endif
|
||||
|
||||
if lsp#client#is_error(a:data['response']) | return | endif
|
||||
|
||||
" Get references from the response
|
||||
let l:reference_list = a:data['response']['result']
|
||||
if empty(l:reference_list)
|
||||
return
|
||||
endif
|
||||
|
||||
" Convert references to vim positions
|
||||
let l:position_list = []
|
||||
for l:reference in l:reference_list
|
||||
call extend(l:position_list, lsp#utils#range#lsp_to_vim(l:bufnr, l:reference['range']))
|
||||
endfor
|
||||
|
||||
call sort(l:position_list, function('s:compare_positions'))
|
||||
|
||||
" Ignore response if the cursor is not over a reference anymore
|
||||
if s:in_reference(l:position_list) == -1 | return | endif
|
||||
|
||||
" Store references
|
||||
if s:use_vim_textprops
|
||||
let b:lsp_reference_positions = l:position_list
|
||||
let b:lsp_reference_matches = []
|
||||
else
|
||||
let w:lsp_reference_positions = l:position_list
|
||||
let w:lsp_reference_matches = []
|
||||
endif
|
||||
|
||||
" Apply highlights to the buffer
|
||||
call s:init_reference_highlight(l:bufnr)
|
||||
if s:use_vim_textprops
|
||||
for l:position in l:position_list
|
||||
try
|
||||
" TODO: need to check for valid range before calling prop_add
|
||||
" See https://github.com/prabirshrestha/vim-lsp/pull/721
|
||||
silent! call prop_add(l:position[0], l:position[1], {
|
||||
\ 'id': s:prop_id,
|
||||
\ 'bufnr': l:bufnr,
|
||||
\ 'length': l:position[2],
|
||||
\ 'type': 'vim-lsp-reference-highlight'})
|
||||
call add(b:lsp_reference_matches, l:position[0])
|
||||
catch
|
||||
call lsp#log('document_highlight', 'set_highlights', v:exception, v:throwpoint)
|
||||
endtry
|
||||
endfor
|
||||
else
|
||||
for l:position in l:position_list
|
||||
let l:match = matchaddpos('lspReference', [l:position], -5)
|
||||
call add(w:lsp_reference_matches, l:match)
|
||||
endfor
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:clear_highlights() abort
|
||||
if s:use_vim_textprops
|
||||
if exists('b:lsp_reference_matches')
|
||||
let l:bufnr = bufnr('%')
|
||||
for l:line in b:lsp_reference_matches
|
||||
silent! call prop_remove(
|
||||
\ {'id': s:prop_id,
|
||||
\ 'bufnr': l:bufnr,
|
||||
\ 'all': v:true}, l:line)
|
||||
endfor
|
||||
unlet b:lsp_reference_matches
|
||||
unlet b:lsp_reference_positions
|
||||
endif
|
||||
else
|
||||
if exists('w:lsp_reference_matches')
|
||||
for l:match in w:lsp_reference_matches
|
||||
silent! call matchdelete(l:match)
|
||||
endfor
|
||||
unlet w:lsp_reference_matches
|
||||
unlet w:lsp_reference_positions
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Compare two positions
|
||||
function! s:compare_positions(p1, p2) abort
|
||||
let l:line_1 = a:p1[0]
|
||||
let l:line_2 = a:p2[0]
|
||||
if l:line_1 != l:line_2
|
||||
return l:line_1 > l:line_2 ? 1 : -1
|
||||
endif
|
||||
let l:col_1 = a:p1[1]
|
||||
let l:col_2 = a:p2[1]
|
||||
return l:col_1 - l:col_2
|
||||
endfunction
|
||||
|
||||
" If the cursor is over a reference, return its index in
|
||||
" the array. Otherwise, return -1.
|
||||
function! s:in_reference(reference_list) abort
|
||||
let l:line = line('.')
|
||||
let l:column = col('.')
|
||||
let l:index = 0
|
||||
for l:position in a:reference_list
|
||||
if l:line == l:position[0] &&
|
||||
\ l:column >= l:position[1] &&
|
||||
\ l:column < l:position[1] + l:position[2]
|
||||
return l:index
|
||||
endif
|
||||
let l:index += 1
|
||||
endfor
|
||||
return -1
|
||||
endfunction
|
||||
|
||||
function! s:init_reference_highlight(buf) abort
|
||||
if s:use_vim_textprops
|
||||
let l:props = {
|
||||
\ 'bufnr': a:buf,
|
||||
\ 'highlight': 'lspReference',
|
||||
\ 'combine': v:true,
|
||||
\ 'priority': lsp#internal#textprop#priority('document_highlight')
|
||||
\ }
|
||||
if prop_type_get('vim-lsp-reference-highlight', { 'bufnr': a:buf }) == {}
|
||||
call prop_type_add('vim-lsp-reference-highlight', l:props)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Cyclically move between references by `offset` occurrences.
|
||||
function! lsp#internal#document_highlight#jump(offset) abort
|
||||
if s:use_vim_textprops && !exists('b:lsp_reference_positions') ||
|
||||
\ !s:use_vim_textprops && !exists('w:lsp_reference_positions')
|
||||
echohl WarningMsg
|
||||
echom 'References not available'
|
||||
echohl None
|
||||
return
|
||||
endif
|
||||
|
||||
" Get index of reference under cursor
|
||||
let l:index = s:use_vim_textprops ? s:in_reference(b:lsp_reference_positions) : s:in_reference(w:lsp_reference_positions)
|
||||
if l:index < 0
|
||||
return
|
||||
endif
|
||||
|
||||
let l:n = s:use_vim_textprops ? len(b:lsp_reference_positions) : len(w:lsp_reference_positions)
|
||||
let l:index += a:offset
|
||||
|
||||
" Show a message when reaching TOP/BOTTOM of the file
|
||||
if l:index < 0
|
||||
echohl WarningMsg
|
||||
echom 'search hit TOP, continuing at BOTTOM'
|
||||
echohl None
|
||||
elseif l:index >= (s:use_vim_textprops ? len(b:lsp_reference_positions) : len(w:lsp_reference_positions))
|
||||
echohl WarningMsg
|
||||
echom 'search hit BOTTOM, continuing at TOP'
|
||||
echohl None
|
||||
endif
|
||||
|
||||
" Wrap index
|
||||
if l:index < 0 || l:index >= (s:use_vim_textprops ? len(b:lsp_reference_positions) : len(w:lsp_reference_positions))
|
||||
let l:index = (l:index % l:n + l:n) % l:n
|
||||
endif
|
||||
|
||||
" Jump
|
||||
let l:target = (s:use_vim_textprops ? b:lsp_reference_positions : w:lsp_reference_positions)[l:index][0:1]
|
||||
normal! m`
|
||||
call cursor(l:target[0], l:target[1])
|
||||
endfunction
|
||||
@@ -0,0 +1,278 @@
|
||||
" https://microsoft.github.io/language-server-protocol/specification#textDocument_hover
|
||||
|
||||
let s:Markdown = vital#lsp#import('VS.Vim.Syntax.Markdown')
|
||||
let s:MarkupContent = vital#lsp#import('VS.LSP.MarkupContent')
|
||||
let s:FloatingWindow = vital#lsp#import('VS.Vim.Window.FloatingWindow')
|
||||
let s:Window = vital#lsp#import('VS.Vim.Window')
|
||||
let s:Buffer = vital#lsp#import('VS.Vim.Buffer')
|
||||
|
||||
" options - {
|
||||
" server - 'server_name' " optional
|
||||
" ui - 'float' | 'preview'
|
||||
" }
|
||||
function! lsp#internal#document_hover#under_cursor#do(options) abort
|
||||
let l:bufnr = bufnr('%')
|
||||
let l:ui = get(a:options, 'ui', g:lsp_hover_ui)
|
||||
if empty(l:ui)
|
||||
let l:ui = s:FloatingWindow.is_available() ? 'float' : 'preview'
|
||||
endif
|
||||
|
||||
if l:ui ==# 'float'
|
||||
let l:doc_win = s:get_doc_win()
|
||||
if l:doc_win.is_visible()
|
||||
if bufnr('%') ==# l:doc_win.get_bufnr()
|
||||
call s:close_floating_window()
|
||||
else
|
||||
call l:doc_win.enter()
|
||||
inoremap <buffer><silent> <Plug>(lsp-float-close) <ESC>:<C-u>call <SID>close_floating_window()<CR>
|
||||
nnoremap <buffer><silent> <Plug>(lsp-float-close) :<C-u>call <SID>close_floating_window()<CR>
|
||||
execute('doautocmd <nomodeline> User lsp_float_focused')
|
||||
if !hasmapto('<Plug>(lsp-float-close)')
|
||||
imap <silent> <buffer> <C-c> <Plug>(lsp-float-close)
|
||||
nmap <silent> <buffer> <C-c> <Plug>(lsp-float-close)
|
||||
endif
|
||||
endif
|
||||
return
|
||||
endif
|
||||
endif
|
||||
|
||||
if has_key(a:options, 'server')
|
||||
let l:servers = [a:options['server']]
|
||||
else
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_hover_provider(v:val)')
|
||||
endif
|
||||
|
||||
if len(l:servers) == 0
|
||||
let l:filetype = getbufvar(l:bufnr, '&filetype')
|
||||
call lsp#utils#error('textDocument/hover not supported for ' . l:filetype)
|
||||
return
|
||||
endif
|
||||
|
||||
redraw | echo 'Retrieving hover ...'
|
||||
|
||||
call lsp#_new_command()
|
||||
|
||||
" TODO: ask user to select server for formatting if there are multiple servers
|
||||
let l:request = {
|
||||
\ 'method': 'textDocument/hover',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'position': lsp#get_position(),
|
||||
\ },
|
||||
\ }
|
||||
call lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromList(l:servers),
|
||||
\ lsp#callbag#flatMap({server->
|
||||
\ lsp#request(server, l:request)
|
||||
\ }),
|
||||
\ lsp#callbag#tap({x->s:show_hover(l:ui, x['server_name'], x['request'], x['response'])}),
|
||||
\ lsp#callbag#takeUntil(lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'command')}),
|
||||
\ )),
|
||||
\ lsp#callbag#subscribe(),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#document_hover#under_cursor#getpreviewwinid() abort
|
||||
if exists('s:doc_win')
|
||||
return s:doc_win.get_winid()
|
||||
endif
|
||||
return v:null
|
||||
endfunction
|
||||
|
||||
function! s:show_hover(ui, server_name, request, response) abort
|
||||
if !has_key(a:response, 'result') || empty(a:response['result']) ||
|
||||
\ empty(a:response['result']['contents'])
|
||||
call lsp#utils#error('No hover information found in server - ' . a:server_name)
|
||||
return
|
||||
endif
|
||||
|
||||
echo ''
|
||||
|
||||
if s:FloatingWindow.is_available() && a:ui ==? 'float'
|
||||
call s:show_floating_window(a:server_name, a:request, a:response)
|
||||
else
|
||||
call s:show_preview_window(a:server_name, a:request, a:response)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:show_preview_window(server_name, request, response) abort
|
||||
let l:contents = s:get_contents(a:response['result']['contents'])
|
||||
|
||||
" Ignore if contents is empty.
|
||||
if empty(l:contents)
|
||||
call lsp#utils#error('Empty contents for LspHover')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:lines = lsp#utils#_split_by_eol(join(l:contents, "\n\n"))
|
||||
let l:view = winsaveview()
|
||||
let l:alternate=@#
|
||||
silent! pclose
|
||||
sp LspHoverPreview
|
||||
execute 'resize '.min([len(l:lines), &previewheight])
|
||||
set previewwindow
|
||||
setlocal conceallevel=2
|
||||
setlocal bufhidden=hide
|
||||
setlocal nobuflisted
|
||||
setlocal buftype=nofile
|
||||
setlocal noswapfile
|
||||
%d _
|
||||
call setline(1, l:lines)
|
||||
call s:Window.do(win_getid(), {->s:Markdown.apply()})
|
||||
execute "normal \<c-w>p"
|
||||
call winrestview(l:view)
|
||||
let @#=l:alternate
|
||||
endfunction
|
||||
|
||||
function! s:show_floating_window(server_name, request, response) abort
|
||||
call s:close_floating_window()
|
||||
|
||||
let l:contents = s:get_contents(a:response['result']['contents'])
|
||||
|
||||
" Ignore if contents is empty.
|
||||
if empty(l:contents)
|
||||
return s:close_floating_window()
|
||||
endif
|
||||
|
||||
" Update contents.
|
||||
let l:doc_win = s:get_doc_win()
|
||||
silent! call deletebufline(l:doc_win.get_bufnr(), 1, '$')
|
||||
call setbufline(l:doc_win.get_bufnr(), 1, lsp#utils#_split_by_eol(join(l:contents, "\n\n")))
|
||||
|
||||
" Calculate layout.
|
||||
if g:lsp_float_max_width >= 1
|
||||
let l:maxwidth = g:lsp_float_max_width
|
||||
elseif g:lsp_float_max_width == 0
|
||||
let l:maxwidth = &columns
|
||||
else
|
||||
let l:maxwidth = float2nr(&columns * 0.4)
|
||||
endif
|
||||
let l:size = l:doc_win.get_size({
|
||||
\ 'maxwidth': l:maxwidth,
|
||||
\ 'maxheight': float2nr(&lines * 0.4),
|
||||
\ })
|
||||
let l:pos = s:compute_position(l:size)
|
||||
if empty(l:pos)
|
||||
call s:close_floating_window()
|
||||
return
|
||||
endif
|
||||
|
||||
execute printf('augroup vim_lsp_hover_close_on_move_%d', bufnr('%'))
|
||||
autocmd!
|
||||
execute printf('autocmd InsertEnter,BufLeave,CursorMoved <buffer> call s:close_floating_window_on_move(%s)', getcurpos())
|
||||
augroup END
|
||||
|
||||
" Show popupmenu and apply markdown syntax.
|
||||
call l:doc_win.open({
|
||||
\ 'row': l:pos[0],
|
||||
\ 'col': l:pos[1],
|
||||
\ 'width': l:size.width,
|
||||
\ 'height': l:size.height,
|
||||
\ 'border': v:true,
|
||||
\ })
|
||||
call s:Window.do(l:doc_win.get_winid(), { -> s:Markdown.apply() })
|
||||
|
||||
" Format contents to fit window
|
||||
call setbufvar(l:doc_win.get_bufnr(), '&textwidth', l:size.width)
|
||||
call s:Window.do(l:doc_win.get_winid(), { -> s:format_window() })
|
||||
endfunction
|
||||
|
||||
function! s:format_window() abort
|
||||
global/^/normal! gqgq
|
||||
endfunction
|
||||
|
||||
function! s:get_contents(contents) abort
|
||||
if type(a:contents) == type('')
|
||||
return [a:contents]
|
||||
elseif type(a:contents) == type([])
|
||||
let l:result = []
|
||||
for l:content in a:contents
|
||||
let l:result += s:get_contents(l:content)
|
||||
endfor
|
||||
return l:result
|
||||
elseif type(a:contents) == type({})
|
||||
if has_key(a:contents, 'value')
|
||||
if has_key(a:contents, 'kind')
|
||||
if a:contents['kind'] ==? 'markdown'
|
||||
let l:detail = s:MarkupContent.normalize(a:contents['value'], {
|
||||
\ 'compact': !g:lsp_preview_fixup_conceal
|
||||
\ })
|
||||
return [l:detail]
|
||||
else
|
||||
return [a:contents['value']]
|
||||
endif
|
||||
elseif has_key(a:contents, 'language')
|
||||
let l:detail = s:MarkupContent.normalize(a:contents, {
|
||||
\ 'compact': !g:lsp_preview_fixup_conceal
|
||||
\ })
|
||||
return [l:detail]
|
||||
else
|
||||
return ''
|
||||
endif
|
||||
else
|
||||
return ''
|
||||
endif
|
||||
else
|
||||
return ''
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:close_floating_window() abort
|
||||
call s:get_doc_win().close()
|
||||
endfunction
|
||||
|
||||
function! s:close_floating_window_on_move(curpos) abort
|
||||
if a:curpos != getcurpos() | call s:close_floating_window() | endif
|
||||
endf
|
||||
|
||||
function! s:on_opened() abort
|
||||
inoremap <buffer><silent> <Plug>(lsp-float-close) <ESC>:<C-u>call <SID>close_floating_window()<CR>
|
||||
nnoremap <buffer><silent> <Plug>(lsp-float-close) :<C-u>call <SID>close_floating_window()<CR>
|
||||
execute('doautocmd <nomodeline> User lsp_float_opened')
|
||||
if !hasmapto('<Plug>(lsp-float-close)')
|
||||
imap <silent> <buffer> <C-c> <Plug>(lsp-float-close)
|
||||
nmap <silent> <buffer> <C-c> <Plug>(lsp-float-close)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_closed() abort
|
||||
execute('doautocmd <nomodeline> User lsp_float_closed')
|
||||
endfunction
|
||||
|
||||
function! s:get_doc_win() abort
|
||||
if exists('s:doc_win')
|
||||
return s:doc_win
|
||||
endif
|
||||
|
||||
let s:doc_win = s:FloatingWindow.new({
|
||||
\ 'on_opened': function('s:on_opened'),
|
||||
\ 'on_closed': function('s:on_closed')
|
||||
\ })
|
||||
call s:doc_win.set_var('&wrap', 1)
|
||||
call s:doc_win.set_var('&conceallevel', 2)
|
||||
call s:doc_win.set_bufnr(s:Buffer.create())
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&buftype', 'nofile')
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&bufhidden', 'hide')
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&buflisted', 0)
|
||||
call setbufvar(s:doc_win.get_bufnr(), '&swapfile', 0)
|
||||
return s:doc_win
|
||||
endfunction
|
||||
|
||||
function! s:compute_position(size) abort
|
||||
let l:pos = screenpos(0, line('.'), col('.'))
|
||||
if l:pos.row == 0 && l:pos.col == 0
|
||||
" workaround for float position
|
||||
let l:pos = {'curscol': wincol(), 'row': winline()}
|
||||
endif
|
||||
let l:pos = [l:pos.row + 1, l:pos.curscol + 1]
|
||||
if l:pos[0] + a:size.height > &lines
|
||||
let l:pos[0] = l:pos[0] - a:size.height - 3
|
||||
endif
|
||||
if l:pos[1] + a:size.width > &columns
|
||||
let l:pos[1] = l:pos[1] - a:size.width - 3
|
||||
endif
|
||||
return l:pos
|
||||
endfunction
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
" options - {
|
||||
" bufnr: bufnr('%') " required
|
||||
" type: '' " optional: defaults to visualmode(). overridden by opfunc
|
||||
" server - 'server_name' " optional
|
||||
" sync: 0 " optional, defaults to 0 (async)
|
||||
" }
|
||||
function! lsp#internal#document_range_formatting#format(options) abort
|
||||
if has_key(a:options, 'server')
|
||||
let l:servers = [a:options['server']]
|
||||
else
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_document_range_formatting_provider(v:val)')
|
||||
endif
|
||||
|
||||
if len(l:servers) == 0
|
||||
let l:filetype = getbufvar(a:options['bufnr'], '&filetype')
|
||||
call lsp#utils#error('textDocument/rangeFormatting not supported for ' . l:filetype)
|
||||
return
|
||||
endif
|
||||
|
||||
" TODO: ask user to select server for formatting if there are multiple servers
|
||||
let l:server = l:servers[0]
|
||||
|
||||
redraw | echo 'Formatting Document Range ...'
|
||||
|
||||
call lsp#_new_command()
|
||||
|
||||
let [l:start_lnum, l:start_col, l:end_lnum, l:end_col] = s:get_selection_pos(get(a:options, 'type', visualmode()))
|
||||
let l:start_char = lsp#utils#to_char('%', l:start_lnum, l:start_col)
|
||||
let l:end_char = lsp#utils#to_char('%', l:end_lnum, l:end_col)
|
||||
|
||||
let l:request = {
|
||||
\ 'method': 'textDocument/rangeFormatting',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(a:options['bufnr']),
|
||||
\ 'range': {
|
||||
\ 'start': { 'line': l:start_lnum - 1, 'character': l:start_char },
|
||||
\ 'end': { 'line': l:end_lnum - 1, 'character': l:end_char },
|
||||
\ },
|
||||
\ 'options': {
|
||||
\ 'tabSize': lsp#utils#buffer#get_indent_size(a:options['bufnr']),
|
||||
\ 'insertSpaces': getbufvar(a:options['bufnr'], '&expandtab') ? v:true : v:false,
|
||||
\ }
|
||||
\ },
|
||||
\ 'bufnr': a:options['bufnr'],
|
||||
\ }
|
||||
|
||||
if get(a:options, 'sync', 0) == 1
|
||||
try
|
||||
let l:x = lsp#callbag#pipe(
|
||||
\ lsp#request(l:server, l:request),
|
||||
\ lsp#callbag#takeUntil(lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'command')}),
|
||||
\ )),
|
||||
\ lsp#callbag#toList(),
|
||||
\ ).wait({ 'sleep': get(a:options, 'sleep', 1), 'timeout': get(a:options, 'timeout', g:lsp_format_sync_timeout) })
|
||||
call s:format_next(l:x[0])
|
||||
call s:format_complete()
|
||||
catch
|
||||
call s:format_error(v:exception . ' ' . v:throwpoint)
|
||||
endtry
|
||||
else
|
||||
return lsp#callbag#pipe(
|
||||
\ lsp#request(l:server, l:request),
|
||||
\ lsp#callbag#takeUntil(lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'command')}),
|
||||
\ )),
|
||||
\ lsp#callbag#subscribe({
|
||||
\ 'next':{x->s:format_next(x)},
|
||||
\ 'error': {x->s:format_error(e)},
|
||||
\ 'complete': {->s:format_complete()},
|
||||
\ }),
|
||||
\ )
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:format_next(x) abort
|
||||
if lsp#client#is_error(a:x['response']) | return | endif
|
||||
call lsp#utils#text_edit#apply_text_edits(a:x['request']['params']['textDocument']['uri'], a:x['response']['result'])
|
||||
endfunction
|
||||
|
||||
function! s:format_error(e) abort
|
||||
call lsp#log('Formatting Document Range Failed', a:e)
|
||||
call lsp#utils#error('Formatting Document Range Failed.' . (type(a:e) == type('') ? a:e : ''))
|
||||
endfunction
|
||||
|
||||
function! s:format_complete() abort
|
||||
redraw | echo 'Formatting Document Range complete'
|
||||
endfunction
|
||||
|
||||
function! s:get_selection_pos(type) abort
|
||||
" TODO: support bufnr
|
||||
if a:type ==? 'v'
|
||||
let l:start_pos = getpos("'<")[1:2]
|
||||
let l:end_pos = getpos("'>")[1:2]
|
||||
" fix end_pos column (see :h getpos() and :h 'selection')
|
||||
let l:end_line = getline(l:end_pos[0])
|
||||
let l:offset = (&selection ==# 'inclusive' ? 1 : 2)
|
||||
let l:end_pos[1] = len(l:end_line[:l:end_pos[1]-l:offset])
|
||||
" edge case: single character selected with selection=exclusive
|
||||
if l:start_pos[0] == l:end_pos[0] && l:start_pos[1] > l:end_pos[1]
|
||||
let l:end_pos[1] = l:start_pos[1]
|
||||
endif
|
||||
elseif a:type ==? 'line'
|
||||
let l:start_pos = [line("'["), 1]
|
||||
let l:end_lnum = line("']")
|
||||
let l:end_pos = [line("']"), len(getline(l:end_lnum))]
|
||||
elseif a:type ==? 'char'
|
||||
let l:start_pos = getpos("'[")[1:2]
|
||||
let l:end_pos = getpos("']")[1:2]
|
||||
else
|
||||
let l:start_pos = [0, 0]
|
||||
let l:end_pos = [0, 0]
|
||||
endif
|
||||
|
||||
return l:start_pos + l:end_pos
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#document_range_formatting#opfunc(type) abort
|
||||
call lsp#internal#document_range_formatting#format({
|
||||
\ 'type': a:type,
|
||||
\ 'bufnr': bufnr('%'),
|
||||
\ })
|
||||
endfunction
|
||||
@@ -0,0 +1,76 @@
|
||||
" https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol
|
||||
" options - {
|
||||
" bufnr: bufnr('%') " optional
|
||||
" server - 'server_name' " optional
|
||||
" }
|
||||
function! lsp#internal#document_symbol#search#do(options) abort
|
||||
let l:bufnr = get(a:options, 'bufnr', bufnr('%'))
|
||||
if has_key(a:options, 'server')
|
||||
let l:servers = [a:options['server']]
|
||||
else
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_document_symbol_provider(v:val)')
|
||||
endif
|
||||
|
||||
if len(l:servers) == 0
|
||||
let l:filetype = getbufvar(l:bufnr, '&filetype')
|
||||
call lsp#utils#error('textDocument/documentSymbol not supported for ' . l:filetype)
|
||||
return
|
||||
endif
|
||||
|
||||
redraw | echo 'Retrieving document symbols ...'
|
||||
|
||||
call lsp#internal#ui#quickpick#open({
|
||||
\ 'items': [],
|
||||
\ 'busy': 1,
|
||||
\ 'input': '',
|
||||
\ 'key': 'text',
|
||||
\ 'on_accept': function('s:on_accept'),
|
||||
\ 'on_close': function('s:on_close'),
|
||||
\ })
|
||||
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromList(l:servers),
|
||||
\ lsp#callbag#flatMap({server->
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#request(server, {
|
||||
\ 'method': 'textDocument/documentSymbol',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(l:bufnr),
|
||||
\ },
|
||||
\ }),
|
||||
\ lsp#callbag#map({x->{'server': server, 'request': x['request'], 'response': x['response']}}),
|
||||
\ )
|
||||
\ }),
|
||||
\ lsp#callbag#scan({acc, curr->add(acc, curr)}, []),
|
||||
\ lsp#callbag#tap({x->s:update_ui_items(x)}),
|
||||
\ lsp#callbag#subscribe({
|
||||
\ 'complete':{->lsp#internal#ui#quickpick#busy(0)},
|
||||
\ 'error':{e->s:on_error(e)},
|
||||
\ }),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! s:update_ui_items(x) abort
|
||||
let l:items = []
|
||||
for l:i in a:x
|
||||
let l:items += lsp#ui#vim#utils#symbols_to_loc_list(l:i['server'], l:i)
|
||||
endfor
|
||||
call lsp#internal#ui#quickpick#items(l:items)
|
||||
endfunction
|
||||
|
||||
function! s:on_accept(data, ...) abort
|
||||
call lsp#internal#ui#quickpick#close()
|
||||
call lsp#utils#location#_open_vim_list_item(a:data['items'][0], '')
|
||||
endfunction
|
||||
|
||||
function! s:on_close(...) abort
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_error(e) abort
|
||||
call lsp#internal#ui#quickpick#close()
|
||||
call lsp#log('LspDocumentSymbolSearch error', a:e)
|
||||
endfunction
|
||||
127
dot_vim/plugged/vim-lsp/autoload/lsp/internal/inlay_hints.vim
Normal file
127
dot_vim/plugged/vim-lsp/autoload/lsp/internal/inlay_hints.vim
Normal file
@@ -0,0 +1,127 @@
|
||||
let s:use_vim_textprops = lsp#utils#_has_vim_virtual_text() && !has('nvim')
|
||||
|
||||
function! s:set_inlay_hints(data) abort
|
||||
let l:bufnr = bufnr('%')
|
||||
|
||||
call s:clear_inlay_hints()
|
||||
|
||||
if mode() !=# 'n' | return | endif
|
||||
|
||||
if lsp#client#is_error(a:data['response']) | return | endif
|
||||
|
||||
" Get hints from the response
|
||||
let l:hints = a:data['response']['result']
|
||||
if empty(l:hints)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:not_curline = s:has_inlay_hints_mode('!curline')
|
||||
for l:hint in l:hints
|
||||
if l:not_curline && l:hint.position.line+1 ==# line('.')
|
||||
continue
|
||||
endif
|
||||
let l:label = ''
|
||||
if type(l:hint.label) ==# v:t_list
|
||||
let l:label = join(map(copy(l:hint.label), {_,v -> v.value}), '')
|
||||
else
|
||||
let l:label = l:hint.label
|
||||
endif
|
||||
let l:text = (get(l:hint, 'paddingLeft', v:false) ? ' ' : '') . l:label . (get(l:hint, 'paddingRight', v:false) ? ' ' : '')
|
||||
if !has_key(l:hint, 'kind') || l:hint.kind ==# 1
|
||||
call prop_add(l:hint.position.line+1, l:hint.position.character+1, {'type': 'vim_lsp_inlay_hint_type', 'text': l:text, 'bufnr': l:bufnr})
|
||||
elseif l:hint.kind ==# 2
|
||||
call prop_add(l:hint.position.line+1, l:hint.position.character+1, {'type': 'vim_lsp_inlay_hint_parameter', 'text': l:text, 'bufnr': l:bufnr})
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:init_inlay_hints() abort
|
||||
if index(prop_type_list(), 'vim_lsp_inlay_hint_type') ==# -1
|
||||
call prop_type_add('vim_lsp_inlay_hint_type', { 'highlight': 'lspInlayHintsType' })
|
||||
call prop_type_add('vim_lsp_inlay_hint_parameter', { 'highlight': 'lspInlayHintsParameter' })
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#inlay_hints#_disable() abort
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:clear_inlay_hints() abort
|
||||
let l:bufnr = bufnr('%')
|
||||
call prop_remove({'type': 'vim_lsp_inlay_hint_type', 'bufnr': l:bufnr, 'all': v:true})
|
||||
call prop_remove({'type': 'vim_lsp_inlay_hint_parameter', 'bufnr': l:bufnr, 'all': v:true})
|
||||
endfunction
|
||||
|
||||
function! s:has_inlay_hints_mode(value) abort
|
||||
let l:m = get(g:, 'lsp_inlay_hints_mode', {})
|
||||
if type(l:m) != v:t_dict | return v:false | endif
|
||||
if mode() ==# 'i'
|
||||
let l:a = get(l:m, 'insert', [])
|
||||
elseif mode() ==# 'n'
|
||||
let l:a = get(l:m, 'normal', [])
|
||||
else
|
||||
return v:false
|
||||
endif
|
||||
if type(l:a) != v:t_list | return v:false | endif
|
||||
return index(l:a, a:value) != -1 ? v:true : v:false
|
||||
endfunction
|
||||
|
||||
function! s:send_inlay_hints_request() abort
|
||||
let l:capability = 'lsp#capabilities#has_inlay_hint_provider(v:val)'
|
||||
let l:servers = filter(lsp#get_allowed_servers(), l:capability)
|
||||
|
||||
if empty(l:servers)
|
||||
return lsp#callbag#empty()
|
||||
endif
|
||||
|
||||
if s:has_inlay_hints_mode('curline')
|
||||
let l:range = lsp#utils#range#get_range_curline()
|
||||
else
|
||||
let l:range = lsp#utils#range#get_range()
|
||||
endif
|
||||
return lsp#request(l:servers[0], {
|
||||
\ 'method': 'textDocument/inlayHint',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'range': l:range,
|
||||
\ },
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#inlay_hints#_enable() abort
|
||||
if !s:use_vim_textprops | return | endif
|
||||
if !g:lsp_inlay_hints_enabled | return | endif
|
||||
|
||||
if !hlexists('lspInlayHintsType')
|
||||
highlight link lspInlayHintsType Label
|
||||
endif
|
||||
if !hlexists('lspInlayHintsParameter')
|
||||
highlight link lspInlayHintsParameter Todo
|
||||
endif
|
||||
|
||||
call s:init_inlay_hints()
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#merge(
|
||||
\ lsp#callbag#fromEvent(['CursorMoved', 'CursorHold']),
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent(['InsertEnter', 'BufLeave']),
|
||||
\ lsp#callbag#tap({_ -> s:clear_inlay_hints() }),
|
||||
\ )
|
||||
\ ),
|
||||
\ lsp#callbag#filter({_ -> g:lsp_inlay_hints_enabled }),
|
||||
\ lsp#callbag#debounceTime(g:lsp_inlay_hints_delay),
|
||||
\ lsp#callbag#filter({_->getbufvar(bufnr('%'), '&buftype') !~# '^(help\|terminal\|prompt\|popup)$'}),
|
||||
\ lsp#callbag#switchMap({_->
|
||||
\ lsp#callbag#pipe(
|
||||
\ s:send_inlay_hints_request(),
|
||||
\ lsp#callbag#materialize(),
|
||||
\ lsp#callbag#filter({x->lsp#callbag#isNextNotification(x)}),
|
||||
\ lsp#callbag#map({x->x['value']})
|
||||
\ )
|
||||
\ }),
|
||||
\ lsp#callbag#subscribe({x->s:set_inlay_hints(x)}),
|
||||
\)
|
||||
endfunction
|
||||
411
dot_vim/plugged/vim-lsp/autoload/lsp/internal/semantic.vim
Normal file
411
dot_vim/plugged/vim-lsp/autoload/lsp/internal/semantic.vim
Normal file
@@ -0,0 +1,411 @@
|
||||
let s:use_vim_textprops = lsp#utils#_has_textprops() && !has('nvim')
|
||||
let s:use_nvim_highlight = lsp#utils#_has_nvim_buf_highlight()
|
||||
let s:textprop_cache = 'vim-lsp-semantic-cache'
|
||||
|
||||
if s:use_nvim_highlight
|
||||
let s:namespace_id = nvim_create_namespace('vim-lsp-semantic')
|
||||
endif
|
||||
|
||||
" Global functions {{{1
|
||||
function! lsp#internal#semantic#is_enabled() abort
|
||||
return g:lsp_semantic_enabled && (s:use_vim_textprops || s:use_nvim_highlight) ? v:true : v:false
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#semantic#_enable() abort
|
||||
if !lsp#internal#semantic#is_enabled() | return | endif
|
||||
|
||||
augroup lsp#internal#semantic
|
||||
autocmd!
|
||||
au User lsp_buffer_enabled call s:on_lsp_buffer_enabled()
|
||||
augroup END
|
||||
|
||||
let l:events = [['User', 'lsp_buffer_enabled'], 'TextChanged', 'TextChangedI']
|
||||
if exists('##TextChangedP')
|
||||
call add(l:events, 'TextChangedP')
|
||||
endif
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromEvent(l:events),
|
||||
\ lsp#callbag#filter({_->lsp#internal#semantic#is_enabled()}),
|
||||
\ lsp#callbag#debounceTime(g:lsp_semantic_delay),
|
||||
\ lsp#callbag#filter({_->index(['help', 'terminal', 'prompt', 'popup'], getbufvar(bufnr('%'), '&buftype')) ==# -1}),
|
||||
\ lsp#callbag#filter({_->!lsp#utils#is_large_window(win_getid())}),
|
||||
\ lsp#callbag#switchMap({_->
|
||||
\ lsp#callbag#pipe(
|
||||
\ s:semantic_request(),
|
||||
\ lsp#callbag#materialize(),
|
||||
\ lsp#callbag#filter({x->lsp#callbag#isNextNotification(x)}),
|
||||
\ lsp#callbag#map({x->x['value']})
|
||||
\ )
|
||||
\ }),
|
||||
\ lsp#callbag#subscribe({x->s:handle_semantic_request(x)})
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#semantic#_disable() abort
|
||||
augroup lsp#internal#semantic
|
||||
autocmd!
|
||||
augroup END
|
||||
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#semantic#get_legend(server) abort
|
||||
if !lsp#capabilities#has_semantic_tokens(a:server)
|
||||
return {'tokenTypes': [], 'tokenModifiers': []}
|
||||
endif
|
||||
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server)
|
||||
return l:capabilities['semanticTokensProvider']['legend']
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#semantic#get_token_types() abort
|
||||
let l:capability = 'lsp#capabilities#has_semantic_tokens(v:val)'
|
||||
let l:servers = filter(lsp#get_allowed_servers(), l:capability)
|
||||
|
||||
if empty(l:servers)
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:legend = lsp#internal#semantic#get_legend(l:servers[0])
|
||||
let l:token_types = l:legend['tokenTypes']
|
||||
call map(l:token_types, {_, type -> toupper(type[0]) . type[1:]})
|
||||
return l:token_types
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#semantic#get_token_modifiers() abort
|
||||
let l:capability = 'lsp#capabilities#has_semantic_tokens(v:val)'
|
||||
let l:servers = filter(lsp#get_allowed_servers(), l:capability)
|
||||
|
||||
if empty(l:servers)
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:legend = lsp#internal#semantic#get_legend(l:servers[0])
|
||||
let l:token_modifiers = l:legend['tokenModifiers']
|
||||
call map(l:token_modifiers, {_, modifier -> toupper(modifier[0]) . modifier[1:]})
|
||||
return l:token_modifiers
|
||||
endfunction
|
||||
|
||||
function! s:on_lsp_buffer_enabled() abort
|
||||
augroup lsp#internal#semantic
|
||||
if !exists('#BufUnload#<buffer>')
|
||||
execute 'au BufUnload <buffer> call setbufvar(' . bufnr() . ', ''lsp_semantic_previous_result_id'', '''')'
|
||||
endif
|
||||
augroup END
|
||||
endfunction
|
||||
|
||||
function! s:supports_full_semantic_request(server) abort
|
||||
if !lsp#capabilities#has_semantic_tokens(a:server)
|
||||
return v:false
|
||||
endif
|
||||
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server)['semanticTokensProvider']
|
||||
if !has_key(l:capabilities, 'full')
|
||||
return v:false
|
||||
endif
|
||||
|
||||
if type(l:capabilities['full']) ==# v:t_dict
|
||||
return v:true
|
||||
endif
|
||||
|
||||
return l:capabilities['full']
|
||||
endfunction
|
||||
|
||||
function! s:supports_delta_semantic_request(server) abort
|
||||
if !lsp#capabilities#has_semantic_tokens(a:server)
|
||||
return v:false
|
||||
endif
|
||||
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server)['semanticTokensProvider']
|
||||
if !has_key(l:capabilities, 'full')
|
||||
return v:false
|
||||
endif
|
||||
|
||||
if type(l:capabilities['full']) !=# v:t_dict
|
||||
return v:false
|
||||
endif
|
||||
|
||||
if !has_key(l:capabilities['full'], 'delta')
|
||||
return v:false
|
||||
endif
|
||||
|
||||
return l:capabilities['full']['delta']
|
||||
endfunction
|
||||
|
||||
function! s:get_server() abort
|
||||
let l:capability = 's:supports_delta_semantic_request(v:val)'
|
||||
let l:servers = filter(lsp#get_allowed_servers(), l:capability)
|
||||
if empty(l:servers)
|
||||
let l:capability = 's:supports_full_semantic_request(v:val)'
|
||||
let l:servers = filter(lsp#get_allowed_servers(), l:capability)
|
||||
endif
|
||||
if empty(l:servers)
|
||||
return ''
|
||||
endif
|
||||
return l:servers[0]
|
||||
endfunction
|
||||
|
||||
function! s:semantic_request() abort
|
||||
let l:server = s:get_server()
|
||||
if l:server ==# ''
|
||||
return lsp#callbag#empty()
|
||||
endif
|
||||
|
||||
if (s:supports_delta_semantic_request(l:server)
|
||||
\ && getbufvar(bufnr(), 'lsp_semantic_previous_result_id') !=# '')
|
||||
return s:delta_semantic_request(l:server)
|
||||
else
|
||||
return s:full_semantic_request(l:server)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:full_semantic_request(server) abort
|
||||
return lsp#request(a:server, {
|
||||
\ 'method': 'textDocument/semanticTokens/full',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier()
|
||||
\ }})
|
||||
endfunction
|
||||
|
||||
function! s:delta_semantic_request(server) abort
|
||||
return lsp#request(a:server, {
|
||||
\ 'method': 'textDocument/semanticTokens/full/delta',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'previousResultId': getbufvar(bufname(), 'lsp_semantic_previous_result_id', 0)
|
||||
\ }})
|
||||
endfunction
|
||||
|
||||
" Highlight helper functions {{{1
|
||||
function! s:handle_semantic_request(data) abort
|
||||
if lsp#client#is_error(a:data['response'])
|
||||
call lsp#log('Skipping semantic highlight: response is invalid')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:server = a:data['server_name']
|
||||
let l:uri = a:data['request']['params']['textDocument']['uri']
|
||||
let l:path = lsp#utils#uri_to_path(l:uri)
|
||||
let l:bufnr = bufnr(l:path)
|
||||
|
||||
" Skip if the buffer doesn't exist. This might happen when a buffer is
|
||||
" opened and quickly deleted.
|
||||
if !bufloaded(l:bufnr) | return | endif
|
||||
|
||||
if has_key(a:data['response']['result'], 'data')
|
||||
call s:handle_semantic_tokens_response(l:server, l:bufnr, a:data['response']['result'])
|
||||
elseif has_key(a:data['response']['result'], 'edits')
|
||||
call s:handle_semantic_tokens_delta_response(l:server, l:bufnr, a:data['response']['result'])
|
||||
else
|
||||
" Don't update previous result ID if we could not update local copy
|
||||
call lsp#log('SemanticHighlight: unsupported semanticTokens method')
|
||||
return
|
||||
endif
|
||||
|
||||
if has_key(a:data['response']['result'], 'resultId')
|
||||
call setbufvar(l:bufnr, 'lsp_semantic_previous_result_id', a:data['response']['result']['resultId'])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:handle_semantic_tokens_response(server, buf, result) abort
|
||||
let l:highlights = {}
|
||||
let l:legend = lsp#internal#semantic#get_legend(a:server)
|
||||
for l:token in s:decode_tokens(a:result['data'])
|
||||
let [l:key, l:value] = s:add_highlight(a:server, l:legend, a:buf, l:token)
|
||||
let l:highlights[l:key] = get(l:highlights, l:key, []) + l:value
|
||||
endfor
|
||||
call s:apply_highlights(a:server, a:buf, l:highlights)
|
||||
|
||||
call setbufvar(a:buf, 'lsp_semantic_local_data', a:result['data'])
|
||||
endfunction
|
||||
|
||||
function! s:startpos_compare(edit1, edit2) abort
|
||||
return a:edit1[0] == a:edit2[0] ? 0 : a:edit1[0] > a:edit2[0] ? -1 : 1
|
||||
endfunction
|
||||
|
||||
function! s:handle_semantic_tokens_delta_response(server, buf, result) abort
|
||||
" The locations given in the edit are all referenced to the state before
|
||||
" any are applied and sorting is not required from the server,
|
||||
" therefore the edits must be sorted before applying.
|
||||
let l:edits = a:result['edits']
|
||||
call sort(l:edits, function('s:startpos_compare'))
|
||||
|
||||
let l:localdata = getbufvar(a:buf, 'lsp_semantic_local_data')
|
||||
for l:edit in l:edits
|
||||
let l:insertdata = get(l:edit, 'data', [])
|
||||
let l:localdata = l:localdata[:l:edit['start'] - 1]
|
||||
\ + l:insertdata
|
||||
\ + l:localdata[l:edit['start'] + l:edit['deleteCount']:]
|
||||
endfor
|
||||
call setbufvar(a:buf, 'lsp_semantic_local_data', l:localdata)
|
||||
|
||||
let l:highlights = {}
|
||||
let l:legend = lsp#internal#semantic#get_legend(a:server)
|
||||
for l:token in s:decode_tokens(l:localdata)
|
||||
let [l:key, l:value] = s:add_highlight(a:server, l:legend, a:buf, l:token)
|
||||
let l:highlights[l:key] = get(l:highlights, l:key, []) + l:value
|
||||
endfor
|
||||
call s:apply_highlights(a:server, a:buf, l:highlights)
|
||||
endfunction
|
||||
|
||||
function! s:decode_tokens(data) abort
|
||||
let l:tokens = []
|
||||
|
||||
let l:i = 0
|
||||
let l:line = 0
|
||||
let l:char = 0
|
||||
while l:i < len(a:data)
|
||||
let l:line = l:line + a:data[l:i]
|
||||
if a:data[l:i] > 0
|
||||
let l:char = 0
|
||||
endif
|
||||
let l:char = l:char + a:data[l:i + 1]
|
||||
|
||||
call add(l:tokens, {
|
||||
\ 'pos': {'line': l:line, 'character': l:char},
|
||||
\ 'length': a:data[l:i + 2],
|
||||
\ 'token_idx': a:data[l:i + 3],
|
||||
\ 'token_modifiers': a:data[l:i + 4]
|
||||
\ })
|
||||
|
||||
let l:i = l:i + 5
|
||||
endwhile
|
||||
|
||||
return l:tokens
|
||||
endfunction
|
||||
|
||||
function! s:clear_highlights(server, buf) abort
|
||||
if s:use_vim_textprops
|
||||
let l:BeginsWith = {str, prefix -> str[0:len(prefix) - 1] ==# prefix}
|
||||
let l:IsSemanticTextprop = {_, textprop -> l:BeginsWith(textprop, s:textprop_type_prefix)}
|
||||
let l:textprop_types = prop_type_list()
|
||||
call filter(l:textprop_types, l:IsSemanticTextprop)
|
||||
for l:textprop_type in l:textprop_types
|
||||
silent! call prop_remove({'type': l:textprop_type, 'bufnr': a:buf, 'all': v:true})
|
||||
endfor
|
||||
elseif s:use_nvim_highlight
|
||||
call nvim_buf_clear_namespace(a:buf, s:namespace_id, 0, line('$'))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:add_highlight(server, legend, buf, token) abort
|
||||
let l:startpos = lsp#utils#position#lsp_to_vim(a:buf, a:token['pos'])
|
||||
let l:endpos = a:token['pos']
|
||||
let l:endpos['character'] = l:endpos['character'] + a:token['length']
|
||||
let l:endpos = lsp#utils#position#lsp_to_vim(a:buf, l:endpos)
|
||||
|
||||
if s:use_vim_textprops
|
||||
let l:textprop_name = s:get_textprop_type(a:server, a:legend, a:token['token_idx'], a:token['token_modifiers'])
|
||||
return [l:textprop_name, [[l:startpos[0], l:startpos[1], l:endpos[0], l:endpos[1]]]]
|
||||
elseif s:use_nvim_highlight
|
||||
let l:char = a:token['pos']['character']
|
||||
let l:hl_name = s:get_hl_group(a:server, a:legend, a:token['token_idx'], a:token['token_modifiers'])
|
||||
return [l:hl_name, [[l:startpos[0] - 1, l:startpos[1] - 1, l:endpos[1] - 1]]]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:apply_highlights(server, buf, highlights) abort
|
||||
call s:clear_highlights(a:server, a:buf)
|
||||
|
||||
if s:use_vim_textprops
|
||||
for [l:type, l:prop_list] in items(a:highlights)
|
||||
call prop_add_list({'type': l:type, 'bufnr': a:buf}, l:prop_list)
|
||||
endfor
|
||||
elseif s:use_nvim_highlight
|
||||
call lsp#log(a:highlights)
|
||||
for [l:hl_name, l:instances] in items(a:highlights)
|
||||
for l:instance in l:instances
|
||||
let [l:line, l:startcol, l:endcol] = l:instance
|
||||
try
|
||||
call nvim_buf_add_highlight(a:buf, s:namespace_id, l:hl_name, l:line, l:startcol, l:endcol)
|
||||
catch
|
||||
call lsp#log('SemanticHighlight: error while adding ' . l:hl_name . ' highlight on line ' . l:line)
|
||||
endtry
|
||||
endfor
|
||||
endfor
|
||||
end
|
||||
endfunction
|
||||
|
||||
let s:hl_group_prefix = 'LspSemantic'
|
||||
|
||||
let s:default_highlight_groups = {
|
||||
\ s:hl_group_prefix . 'Type': 'Type',
|
||||
\ s:hl_group_prefix . 'Class': 'Type',
|
||||
\ s:hl_group_prefix . 'Enum': 'Type',
|
||||
\ s:hl_group_prefix . 'Interface': 'TypeDef',
|
||||
\ s:hl_group_prefix . 'Struct': 'Type',
|
||||
\ s:hl_group_prefix . 'TypeParameter': 'Type',
|
||||
\ s:hl_group_prefix . 'Parameter': 'Identifier',
|
||||
\ s:hl_group_prefix . 'Variable': 'Identifier',
|
||||
\ s:hl_group_prefix . 'Property': 'Identifier',
|
||||
\ s:hl_group_prefix . 'EnumMember': 'Constant',
|
||||
\ s:hl_group_prefix . 'Event': 'Identifier',
|
||||
\ s:hl_group_prefix . 'Function': 'Function',
|
||||
\ s:hl_group_prefix . 'Method': 'Function',
|
||||
\ s:hl_group_prefix . 'Macro': 'Macro',
|
||||
\ s:hl_group_prefix . 'Keyword': 'Keyword',
|
||||
\ s:hl_group_prefix . 'Modifier': 'Type',
|
||||
\ s:hl_group_prefix . 'Comment': 'Comment',
|
||||
\ s:hl_group_prefix . 'String': 'String',
|
||||
\ s:hl_group_prefix . 'Number': 'Number',
|
||||
\ s:hl_group_prefix . 'Regexp': 'String',
|
||||
\ s:hl_group_prefix . 'Operator': 'Operator',
|
||||
\ s:hl_group_prefix . 'Decorator': 'Macro'
|
||||
\ }
|
||||
|
||||
function! s:get_hl_group(server, legend, token_idx, token_modifiers) abort
|
||||
" get highlight group name
|
||||
let l:Capitalise = {str -> toupper(str[0]) . str[1:]}
|
||||
let l:token_name = l:Capitalise(a:legend['tokenTypes'][a:token_idx])
|
||||
let l:token_modifiers = []
|
||||
for l:modifier_idx in range(len(a:legend['tokenModifiers']))
|
||||
" float2nr(pow(2, a)) is 1 << a
|
||||
if and(a:token_modifiers, float2nr(pow(2, l:modifier_idx)))
|
||||
let l:modifier_name = a:legend['tokenModifiers'][l:modifier_idx]
|
||||
call add(l:token_modifiers, l:Capitalise(l:modifier_name))
|
||||
endif
|
||||
endfor
|
||||
call sort(l:token_modifiers)
|
||||
let l:hl_group = s:hl_group_prefix
|
||||
\ . reduce(l:token_modifiers, {acc, val -> acc . val}, '')
|
||||
\ . l:token_name
|
||||
|
||||
" create the highlight group if it does not already exist
|
||||
if !hlexists(l:hl_group)
|
||||
if has_key(s:default_highlight_groups, l:hl_group)
|
||||
exec 'highlight link' l:hl_group s:default_highlight_groups[l:hl_group]
|
||||
else
|
||||
if a:token_modifiers != 0
|
||||
let l:base_hl_group = s:get_hl_group(a:server, a:legend, a:token_idx, 0)
|
||||
exec 'highlight link' l:hl_group l:base_hl_group
|
||||
else
|
||||
exec 'highlight link' l:hl_group 'Normal'
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:hl_group
|
||||
endfunction
|
||||
|
||||
let s:textprop_type_prefix = 'vim-lsp-semantic-'
|
||||
|
||||
function! s:get_textprop_type(server, legend, token_idx, token_modifiers) abort
|
||||
" get textprop type name
|
||||
let l:textprop_type = s:textprop_type_prefix . a:server . '-' . a:token_idx . '-' . a:token_modifiers
|
||||
|
||||
" create the textprop type if it does not already exist
|
||||
if prop_type_get(l:textprop_type) ==# {}
|
||||
let l:hl_group = s:get_hl_group(a:server, a:legend, a:token_idx, a:token_modifiers)
|
||||
silent! call prop_type_add(l:textprop_type, {
|
||||
\ 'highlight': l:hl_group,
|
||||
\ 'combine': v:true,
|
||||
\ 'priority': lsp#internal#textprop#priority('semantic')})
|
||||
endif
|
||||
|
||||
return l:textprop_type
|
||||
endfunction
|
||||
|
||||
" vim: fdm=marker
|
||||
@@ -0,0 +1,74 @@
|
||||
let s:ErrorType = 1
|
||||
let s:WarningType = 2
|
||||
let s:InfoType = 3
|
||||
let s:LogType = 4
|
||||
|
||||
function! lsp#internal#show_message#_enable() abort
|
||||
if g:lsp_show_message_log_level ==# 'none' | return | endif
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->
|
||||
\ g:lsp_show_message_log_level !=# 'none' &&
|
||||
\ has_key(x, 'response') && has_key(x['response'], 'method')
|
||||
\ && x['response']['method'] ==# 'window/showMessage'
|
||||
\ }),
|
||||
\ lsp#callbag#tap({x->s:handle_show_message(x['server'], x['response']['params'])}),
|
||||
\ lsp#callbag#subscribe({ 'error': function('s:on_error') }),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#show_message#_disable() abort
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_error(e) abort
|
||||
call lsp#log('lsp#internal#show_message error', a:e)
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:handle_show_message(server, params) abort
|
||||
let l:level = s:name_to_level(g:lsp_show_message_log_level)
|
||||
let l:type = a:params['type']
|
||||
if l:level < l:type
|
||||
return
|
||||
endif
|
||||
|
||||
let l:message = a:params['message']
|
||||
try
|
||||
if l:type == s:ErrorType
|
||||
echohl ErrorMsg
|
||||
elseif l:type == s:WarningType
|
||||
echohl WarningMsg
|
||||
endif
|
||||
echom printf('%s: %s: %s', a:server, s:type_to_name(l:type), l:message)
|
||||
finally
|
||||
echohl None
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:name_to_level(name) abort
|
||||
if a:name ==# 'none'
|
||||
return 0
|
||||
elseif a:name ==# 'error'
|
||||
return s:ErrorType
|
||||
elseif a:name ==# 'warn' || a:name ==# 'warning'
|
||||
return s:WarningType
|
||||
elseif a:name ==# 'info'
|
||||
return s:InfoType
|
||||
elseif a:name ==# 'log'
|
||||
return s:LogType
|
||||
else
|
||||
return 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:type_to_name(type) abort
|
||||
return get(['unknown', 'error', 'warning', 'info', 'log'], a:type, 'unknown')
|
||||
endfunction
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
function! lsp#internal#show_message_request#_enable() abort
|
||||
if !g:lsp_show_message_request_enabled | return | endif
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->
|
||||
\ g:lsp_show_message_request_enabled &&
|
||||
\ has_key(x, 'request') && !has_key(x, 'response') &&
|
||||
\ has_key(x['request'], 'method') && x['request']['method'] ==# 'window/showMessageRequest'
|
||||
\ }),
|
||||
\ lsp#callbag#map({x->s:show_message_request(x['server'], x['request'])}),
|
||||
\ lsp#callbag#map({x->s:send_message_response(x['server'], x['request'], x['action'])}),
|
||||
\ lsp#callbag#flatten(),
|
||||
\ lsp#callbag#materialize(),
|
||||
\ lsp#callbag#subscribe({ 'error': function('s:on_error') }),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#show_message_request#_disable() abort
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_error(e) abort
|
||||
call lsp#log('lsp#internal#show_message_request error', a:e)
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:show_message_request(server_name, request) abort
|
||||
let l:params = a:request['params']
|
||||
|
||||
let l:selected_action = v:null
|
||||
|
||||
if has_key(l:params, 'actions') && !empty(l:params['actions'])
|
||||
let l:options = map(copy(l:params['actions']), {i, action ->
|
||||
\ printf('%d - [%s] %s', i + 1, a:server_name, action['title'])
|
||||
\ })
|
||||
let l:index = inputlist([l:params['message']] + l:options)
|
||||
if l:index > 0 && l:index <= len(l:index)
|
||||
let l:selected_action = l:params['actions'][l:index - 1]
|
||||
endif
|
||||
else
|
||||
echom l:params['message']
|
||||
endif
|
||||
|
||||
return { 'server': a:server_name, 'request': a:request, 'action': l:selected_action }
|
||||
endfunction
|
||||
|
||||
function! s:send_message_response(server_name, request, action) abort
|
||||
return lsp#request(a:server_name, {
|
||||
\ 'id': a:request['id'],
|
||||
\ 'result': a:action
|
||||
\})
|
||||
endfunction
|
||||
13
dot_vim/plugged/vim-lsp/autoload/lsp/internal/textprop.vim
Normal file
13
dot_vim/plugged/vim-lsp/autoload/lsp/internal/textprop.vim
Normal file
@@ -0,0 +1,13 @@
|
||||
" TODO: currently, quickpick is generated via vim-quickpick, 'quickpick' is
|
||||
" not used.
|
||||
let s:priorities = {
|
||||
\ 'quickpick': 1,
|
||||
\ 'folding': 2,
|
||||
\ 'semantic': 3,
|
||||
\ 'diagnostics_highlight': 4,
|
||||
\ 'document_highlight': 5,
|
||||
\}
|
||||
|
||||
function! lsp#internal#textprop#priority(name) abort
|
||||
return get(s:priorities, a:name, 0)
|
||||
endfunction
|
||||
@@ -0,0 +1,91 @@
|
||||
function! lsp#internal#type_hierarchy#show() abort
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_type_hierarchy_provider(v:val)')
|
||||
let l:command_id = lsp#_new_command()
|
||||
|
||||
if len(l:servers) == 0
|
||||
return lsp#utils#error('Retrieving type hierarchy not supported for ' . &filetype)
|
||||
endif
|
||||
|
||||
let l:ctx = { 'counter': len(l:servers), 'list':[], 'last_command_id': l:command_id }
|
||||
" direction 0 children, 1 parent, 2 both
|
||||
for l:server in l:servers
|
||||
call lsp#send_request(l:server, {
|
||||
\ 'method': 'textDocument/typeHierarchy',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'position': lsp#get_position(),
|
||||
\ 'direction': 2,
|
||||
\ 'resolve': 1,
|
||||
\ },
|
||||
\ 'on_notification': function('s:handle_type_hierarchy', [l:ctx, l:server, 'type hierarchy']),
|
||||
\ })
|
||||
endfor
|
||||
|
||||
echo 'Retrieving type hierarchy ...'
|
||||
endfunction
|
||||
|
||||
function! s:handle_type_hierarchy(ctx, server, type, data) abort "ctx = {counter, list, last_command_id}
|
||||
if a:ctx['last_command_id'] != lsp#_last_command()
|
||||
return
|
||||
endif
|
||||
|
||||
if lsp#client#is_error(a:data['response'])
|
||||
call lsp#utils#error('Failed to '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
return
|
||||
endif
|
||||
|
||||
if empty(a:data['response']['result'])
|
||||
echo 'No type hierarchy found'
|
||||
return
|
||||
endif
|
||||
|
||||
" Create new buffer in a split
|
||||
let l:position = 'topleft'
|
||||
let l:orientation = 'new'
|
||||
exec l:position . ' ' . 10 . l:orientation
|
||||
|
||||
let l:provider = {
|
||||
\ 'root': a:data['response']['result'],
|
||||
\ 'root_state': 'expanded',
|
||||
\ 'bufnr': bufnr('%'),
|
||||
\ 'getChildren': function('s:get_children_for_tree_hierarchy'),
|
||||
\ 'getParent': function('s:get_parent_for_tree_hierarchy'),
|
||||
\ 'getTreeItem': function('s:get_treeitem_for_tree_hierarchy'),
|
||||
\ }
|
||||
|
||||
call lsp#utils#tree#new(l:provider)
|
||||
|
||||
echo 'Retrieved type hierarchy'
|
||||
endfunction
|
||||
|
||||
function! s:hierarchyitem_to_treeitem(hierarchyitem) abort
|
||||
return {
|
||||
\ 'id': a:hierarchyitem,
|
||||
\ 'label': a:hierarchyitem['name'],
|
||||
\ 'command': function('s:hierarchy_treeitem_command', [a:hierarchyitem]),
|
||||
\ 'collapsibleState': has_key(a:hierarchyitem, 'parents') && !empty(a:hierarchyitem['parents']) ? 'expanded' : 'none',
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
function! s:hierarchy_treeitem_command(hierarchyitem) abort
|
||||
bwipeout
|
||||
call lsp#utils#tagstack#_update()
|
||||
call lsp#utils#location#_open_lsp_location(a:hierarchyitem)
|
||||
endfunction
|
||||
|
||||
function! s:get_children_for_tree_hierarchy(Callback, ...) dict abort
|
||||
if a:0 == 0
|
||||
call a:Callback('success', [l:self['root']])
|
||||
return
|
||||
else
|
||||
call a:Callback('success', a:1['parents'])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:get_parent_for_tree_hierarchy(...) dict abort
|
||||
" TODO
|
||||
endfunction
|
||||
|
||||
function! s:get_treeitem_for_tree_hierarchy(Callback, object) dict abort
|
||||
call a:Callback('success', s:hierarchyitem_to_treeitem(a:object))
|
||||
endfunction
|
||||
@@ -0,0 +1,39 @@
|
||||
let s:Markdown = vital#lsp#import('VS.Vim.Syntax.Markdown')
|
||||
let s:Window = vital#lsp#import('VS.Vim.Window')
|
||||
|
||||
function! lsp#internal#ui#popupmenu#open(opt) abort
|
||||
let l:Callback = remove(a:opt, 'callback')
|
||||
let l:items = remove(a:opt, 'items')
|
||||
|
||||
let l:items_with_shortcuts= map(l:items, {
|
||||
\ idx, item -> ((idx < 9) ? '['.(idx+1).'] ' : '').item
|
||||
\ })
|
||||
|
||||
function! Filter(id, key) abort closure
|
||||
if a:key >= 1 && a:key <= len(l:items)
|
||||
call popup_close(a:id, a:key)
|
||||
elseif a:key ==# "\<C-j>"
|
||||
call win_execute(a:id, 'normal! j')
|
||||
elseif a:key ==# "\<C-k>"
|
||||
call win_execute(a:id, 'normal! k')
|
||||
else
|
||||
return popup_filter_menu(a:id, a:key)
|
||||
endif
|
||||
|
||||
return v:true
|
||||
endfunction
|
||||
|
||||
let l:popup_opt = extend({
|
||||
\ 'callback': funcref('s:callback', [l:Callback]),
|
||||
\ 'filter': funcref('Filter'),
|
||||
\ }, a:opt)
|
||||
|
||||
let l:winid = popup_menu(l:items_with_shortcuts, l:popup_opt)
|
||||
call s:Window.do(l:winid, { -> s:Markdown.apply() })
|
||||
execute('doautocmd <nomodeline> User lsp_float_opened')
|
||||
endfunction
|
||||
|
||||
function! s:callback(callback, id, selected) abort
|
||||
call a:callback(a:id, a:selected)
|
||||
execute('doautocmd <nomodeline> User lsp_float_closed')
|
||||
endfunction
|
||||
461
dot_vim/plugged/vim-lsp/autoload/lsp/internal/ui/quickpick.vim
Normal file
461
dot_vim/plugged/vim-lsp/autoload/lsp/internal/ui/quickpick.vim
Normal file
@@ -0,0 +1,461 @@
|
||||
" https://github.com/prabirshrestha/quickpick.vim#968f00787c1a118228aee869351e754bec555298
|
||||
" :QuickpickEmbed path=autoload/lsp/internal/ui/quickpick.vim namespace=lsp#internal#ui#quickpick prefix=lsp-quickpick
|
||||
|
||||
let s:has_timer = exists('*timer_start') && exists('*timer_stop')
|
||||
let s:has_matchfuzzy = exists('*matchfuzzy')
|
||||
let s:has_matchfuzzypos = exists('*matchfuzzypos')
|
||||
let s:has_proptype = exists('*prop_type_add') && exists('*prop_type_delete')
|
||||
|
||||
"
|
||||
" is_floating
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:is_floating(winid) abort
|
||||
if !s:win_exists(a:winid)
|
||||
return 0
|
||||
endif
|
||||
let l:config = nvim_win_get_config(a:winid)
|
||||
return empty(l:config) || !empty(get(l:config, 'relative', ''))
|
||||
endfunction
|
||||
else
|
||||
function! s:is_floating(winid) abort
|
||||
return s:win_exists(a:winid) && win_id2win(a:winid) == 0
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! s:win_exists(winid) abort
|
||||
return winheight(a:winid) != -1
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#ui#quickpick#open(opt) abort
|
||||
call lsp#internal#ui#quickpick#close() " hide existing picker if exists
|
||||
|
||||
" when key is empty, item is a string else it is a dict
|
||||
" fitems is filtered items and is the item that is filtered
|
||||
let s:state = extend({
|
||||
\ 'items': [],
|
||||
\ 'highlights': [],
|
||||
\ 'fitems': [],
|
||||
\ 'key': '',
|
||||
\ 'busy': 0,
|
||||
\ 'busyframes': ['-', '\', '|', '/'],
|
||||
\ 'filetype': 'lsp-quickpick',
|
||||
\ 'promptfiletype': 'lsp-quickpick-filter',
|
||||
\ 'input': '',
|
||||
\ 'maxheight': 10,
|
||||
\ 'debounce': 250,
|
||||
\ 'filter': 1,
|
||||
\ }, a:opt)
|
||||
|
||||
let s:inputecharpre = 0
|
||||
let s:state['busyframe'] = 0
|
||||
|
||||
let s:state['bufnr'] = bufnr('%')
|
||||
let s:state['winid'] = win_getid()
|
||||
let s:state['wininfo'] = getwininfo()
|
||||
|
||||
" create result buffer
|
||||
exe printf('keepalt botright 3new %s', s:state['filetype'])
|
||||
let s:state['resultsbufnr'] = bufnr('%')
|
||||
let s:state['resultswinid'] = win_getid()
|
||||
if s:has_proptype
|
||||
call prop_type_add('highlight', { 'highlight': 'Directory', 'bufnr': s:state['resultsbufnr'] })
|
||||
endif
|
||||
|
||||
" create prompt buffer
|
||||
exe printf('keepalt botright 1new %s', s:state['promptfiletype'])
|
||||
let s:state['promptbufnr'] = bufnr('%')
|
||||
let s:state['promptwinid'] = win_getid()
|
||||
|
||||
call win_gotoid(s:state['resultswinid'])
|
||||
call s:set_buffer_options()
|
||||
setlocal cursorline
|
||||
call s:update_items()
|
||||
exec printf('setlocal filetype=' . s:state['filetype'])
|
||||
call s:notify('open', { 'bufnr': s:state['bufnr'], 'winid': s:state['winid'] , 'resultsbufnr': s:state['resultsbufnr'], 'resultswinid': s:state['resultswinid'] })
|
||||
|
||||
call win_gotoid(s:state['promptwinid'])
|
||||
call s:set_buffer_options()
|
||||
call setline(1, s:state['input'])
|
||||
|
||||
" map keys
|
||||
inoremap <buffer><silent> <Plug>(lsp-quickpick-accept) <ESC>:<C-u>call <SID>on_accept()<CR>
|
||||
nnoremap <buffer><silent> <Plug>(lsp-quickpick-accept) :<C-u>call <SID>on_accept()<CR>
|
||||
|
||||
inoremap <buffer><silent> <Plug>(lsp-quickpick-close) <ESC>:<C-u>call lsp#internal#ui#quickpick#close()<CR>
|
||||
nnoremap <buffer><silent> <Plug>(lsp-quickpick-close) :<C-u>call lsp#internal#ui#quickpick#close()<CR>
|
||||
|
||||
inoremap <buffer><silent> <Plug>(lsp-quickpick-cancel) <ESC>:<C-u>call <SID>on_cancel()<CR>
|
||||
nnoremap <buffer><silent> <Plug>(lsp-quickpick-cancel) :<C-u>call <SID>on_cancel()<CR>
|
||||
|
||||
inoremap <buffer><silent> <Plug>(lsp-quickpick-move-next) <C-o>:<C-u>call <SID>on_move_next()<CR>
|
||||
nnoremap <buffer><silent> <Plug>(lsp-quickpick-move-next) :<C-u>call <SID>on_move_next()<CR>
|
||||
|
||||
inoremap <buffer><silent> <Plug>(lsp-quickpick-move-previous) <C-o>:<C-u>call <SID>on_move_previous()<CR>
|
||||
nnoremap <buffer><silent> <Plug>(lsp-quickpick-move-previous) :<C-u>call <SID>on_move_previous()<CR>
|
||||
|
||||
exec printf('setlocal filetype=' . s:state['promptfiletype'])
|
||||
|
||||
if !hasmapto('<Plug>(lsp-quickpick-accept)')
|
||||
imap <buffer><cr> <Plug>(lsp-quickpick-accept)
|
||||
nmap <buffer><cr> <Plug>(lsp-quickpick-accept)
|
||||
endif
|
||||
|
||||
if !hasmapto('<Plug>(lsp-quickpick-cancel)')
|
||||
imap <silent> <buffer> <C-c> <Plug>(lsp-quickpick-cancel)
|
||||
map <silent> <buffer> <C-c> <Plug>(lsp-quickpick-cancel)
|
||||
imap <silent> <buffer> <Esc> <Plug>(lsp-quickpick-cancel)
|
||||
map <silent> <buffer> <Esc> <Plug>(lsp-quickpick-cancel)
|
||||
endif
|
||||
|
||||
if !hasmapto('<Plug>(lsp-quickpick-move-next)')
|
||||
imap <silent> <buffer> <C-n> <Plug>(lsp-quickpick-move-next)
|
||||
nmap <silent> <buffer> <C-n> <Plug>(lsp-quickpick-move-next)
|
||||
imap <silent> <buffer> <C-j> <Plug>(lsp-quickpick-move-next)
|
||||
nmap <silent> <buffer> <C-j> <Plug>(lsp-quickpick-move-next)
|
||||
endif
|
||||
|
||||
if !hasmapto('<Plug>(lsp-quickpick-move-previous)')
|
||||
imap <silent> <buffer> <C-p> <Plug>(lsp-quickpick-move-previous)
|
||||
nmap <silent> <buffer> <C-p> <Plug>(lsp-quickpick-move-previous)
|
||||
imap <silent> <buffer> <C-k> <Plug>(lsp-quickpick-move-previous)
|
||||
nmap <silent> <buffer> <C-k> <Plug>(lsp-quickpick-move-previous)
|
||||
endif
|
||||
|
||||
call cursor(line('$'), 0)
|
||||
call feedkeys('i', 'n')
|
||||
|
||||
augroup lsp#internal#ui#quickpick
|
||||
autocmd!
|
||||
autocmd InsertCharPre <buffer> call s:on_insertcharpre()
|
||||
autocmd TextChangedI <buffer> call s:on_inputchanged()
|
||||
autocmd InsertEnter <buffer> call s:on_insertenter()
|
||||
autocmd InsertLeave <buffer> call s:on_insertleave()
|
||||
|
||||
if exists('##TextChangedP')
|
||||
autocmd TextChangedP <buffer> call s:on_inputchanged()
|
||||
endif
|
||||
augroup END
|
||||
|
||||
call s:notify_items()
|
||||
call s:notify_selection()
|
||||
call lsp#internal#ui#quickpick#busy(s:state['busy'])
|
||||
endfunction
|
||||
|
||||
function! s:set_buffer_options() abort
|
||||
" set buffer options
|
||||
abc <buffer>
|
||||
setlocal bufhidden=unload " unload buf when no longer displayed
|
||||
setlocal buftype=nofile " buffer is not related to any file<Paste>
|
||||
setlocal noswapfile " don't create swap file
|
||||
setlocal nowrap " don't soft-wrap
|
||||
setlocal nonumber " don't show line numbers
|
||||
setlocal nolist " don't use list mode (visible tabs etc)
|
||||
setlocal foldcolumn=0 " don't show a fold column at side
|
||||
setlocal foldlevel=99 " don't fold anything
|
||||
setlocal nospell " spell checking off
|
||||
setlocal nobuflisted " don't show up in the buffer list
|
||||
setlocal textwidth=0 " don't hardwarp (break long lines)
|
||||
setlocal nocursorline " highlight the line cursor is off
|
||||
setlocal nocursorcolumn " disable cursor column
|
||||
setlocal noundofile " don't enable undo
|
||||
setlocal winfixheight
|
||||
if exists('+colorcolumn') | setlocal colorcolumn=0 | endif
|
||||
if exists('+relativenumber') | setlocal norelativenumber | endif
|
||||
setlocal signcolumn=yes " for prompt
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#ui#quickpick#close() abort
|
||||
if !exists('s:state')
|
||||
return
|
||||
endif
|
||||
|
||||
call lsp#internal#ui#quickpick#busy(0)
|
||||
|
||||
call win_gotoid(s:state['winid'])
|
||||
call s:notify('close', { 'bufnr': s:state['bufnr'], 'winid': s:state['winid'], 'resultsbufnr': s:state['resultsbufnr'], 'resultswinid': s:state['winid'] })
|
||||
|
||||
augroup lsp#internal#ui#quickpick
|
||||
autocmd!
|
||||
augroup END
|
||||
|
||||
exe 'silent! bunload! ' . s:state['promptbufnr']
|
||||
exe 'silent! bunload! ' . s:state['resultsbufnr']
|
||||
call s:restore_windows()
|
||||
|
||||
let s:inputecharpre = 0
|
||||
|
||||
unlet s:state
|
||||
endfunction
|
||||
|
||||
function! s:restore_windows() abort
|
||||
let [l:tabnr, l:_] = win_id2tabwin(s:state['winid'])
|
||||
if l:tabnr == 0
|
||||
return
|
||||
endif
|
||||
|
||||
let l:Resizable = {_, info ->
|
||||
\ info.tabnr == l:tabnr &&
|
||||
\ s:win_exists(info.winid) &&
|
||||
\ !s:is_floating(info.winid)
|
||||
\ }
|
||||
let l:wins_to_resize = sort(filter(s:state['wininfo'], l:Resizable), {l, r -> l.winnr - r.winnr})
|
||||
let l:open_winids_to_resize = map(filter(getwininfo(), l:Resizable), {_, info -> info.winid})
|
||||
|
||||
let l:resize_cmd = ''
|
||||
for l:info in l:wins_to_resize
|
||||
if index(l:open_winids_to_resize, l:info.winid) == -1
|
||||
return
|
||||
endif
|
||||
|
||||
let l:resize_cmd .= printf('%dresize %d | vert %dresize %d |', l:info.winnr, l:info.height, l:info.winnr, l:info.width)
|
||||
endfor
|
||||
|
||||
" winrestcmd repeats :resize commands twice after patch-8.2.2631.
|
||||
" To simulate this behavior, execute the :resize commands twice.
|
||||
" see https://github.com/vim/vim/issues/7988
|
||||
exe 'silent! ' . l:resize_cmd . l:resize_cmd
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#ui#quickpick#items(items) abort
|
||||
let s:state['items'] = a:items
|
||||
call s:update_items()
|
||||
call s:notify_items()
|
||||
call s:notify_selection()
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#ui#quickpick#busy(busy) abort
|
||||
let s:state['busy'] = a:busy
|
||||
if a:busy
|
||||
if !has_key(s:state, 'busytimer')
|
||||
let s:state['busyframe'] = 0
|
||||
let s:state['busytimer'] = timer_start(60, function('s:busy_tick'), { 'repeat': -1 })
|
||||
endif
|
||||
else
|
||||
if has_key(s:state, 'busytimer')
|
||||
call timer_stop(s:state['busytimer'])
|
||||
call remove(s:state, 'busytimer')
|
||||
redraw
|
||||
echohl None
|
||||
echo ''
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#ui#quickpick#results_winid() abort
|
||||
if exists('s:state')
|
||||
return s:state['resultswinid']
|
||||
else
|
||||
return 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:busy_tick(...) abort
|
||||
let s:state['busyframe'] = s:state['busyframe'] + 1
|
||||
if s:state['busyframe'] >= len(s:state['busyframes'])
|
||||
let s:state['busyframe'] = 0
|
||||
endif
|
||||
redraw
|
||||
echohl Question | echon s:state['busyframes'][s:state['busyframe']]
|
||||
echohl None
|
||||
endfunction
|
||||
|
||||
function! s:update_items() abort
|
||||
call s:win_execute(s:state['resultswinid'], 'silent! %delete _')
|
||||
|
||||
let s:state['highlights'] = []
|
||||
|
||||
if s:state['filter'] " if filter is enabled
|
||||
if empty(s:trim(s:state['input']))
|
||||
let s:state['fitems'] = s:state['items']
|
||||
else
|
||||
if empty(s:state['key']) " item is string
|
||||
if s:has_matchfuzzypos
|
||||
let l:matchfuzzyresult = matchfuzzypos(s:state['items'], s:state['input'])
|
||||
let l:fitems = l:matchfuzzyresult[0]
|
||||
let l:highlights = l:matchfuzzyresult[1]
|
||||
let s:state['fitems'] = l:fitems
|
||||
let s:state['highlights'] = l:highlights
|
||||
elseif s:has_matchfuzzy
|
||||
let s:state['fitems'] = matchfuzzy(s:state['items'], s:state['input'])
|
||||
else
|
||||
let s:state['fitems'] = filter(copy(s:state['items']), 'stridx(toupper(v:val), toupper(s:state["input"])) >= 0')
|
||||
endif
|
||||
else " item is dict
|
||||
if s:has_matchfuzzypos
|
||||
" vim requires matchfuzzypos to have highlights.
|
||||
" matchfuzzy only patch doesn't support dict search
|
||||
let l:matchfuzzyresult = matchfuzzypos(s:state['items'], s:state['input'], { 'key': s:state['key'] })
|
||||
let l:fitems = l:matchfuzzyresult[0]
|
||||
let l:highlights = l:matchfuzzyresult[1]
|
||||
let s:state['fitems'] = l:fitems
|
||||
let s:state['highlights'] = l:highlights
|
||||
else
|
||||
let s:state['fitems'] = filter(copy(s:state['items']), 'stridx(toupper(v:val[s:state["key"]]), toupper(s:state["input"])) >= 0')
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
else " if filter is disabled
|
||||
let s:state['fitems'] = s:state['items']
|
||||
endif
|
||||
|
||||
|
||||
if empty(s:state['key']) " item is string
|
||||
let l:lines = s:state['fitems']
|
||||
else " item is dict
|
||||
let l:lines = map(copy(s:state['fitems']), 'v:val[s:state["key"]]')
|
||||
endif
|
||||
|
||||
call setbufline(s:state['resultsbufnr'], 1, l:lines)
|
||||
|
||||
if s:has_proptype && !empty(s:state['highlights'])
|
||||
let l:i = 0
|
||||
for l:line in s:state['highlights']
|
||||
for l:pos in l:line
|
||||
let l:cs = split(getbufline(s:state['resultsbufnr'], l:i + 1)[0], '\zs')
|
||||
let l:mpos = strlen(join(l:cs[: l:pos - 1], ''))
|
||||
let l:len = strlen(l:cs[l:pos])
|
||||
call prop_add(l:i + 1, l:mpos + 1, { 'length': l:len, 'type': 'highlight', 'bufnr': s:state['resultsbufnr'] })
|
||||
endfor
|
||||
let l:i += 1
|
||||
endfor
|
||||
endif
|
||||
|
||||
call s:win_execute(s:state['resultswinid'], printf('resize %d', min([len(s:state['fitems']), s:state['maxheight']])))
|
||||
call s:win_execute(s:state['promptwinid'], 'resize 1')
|
||||
endfunction
|
||||
|
||||
function! s:on_accept() abort
|
||||
if win_gotoid(s:state['resultswinid'])
|
||||
let l:index = line('.') - 1 " line is 1 index, list is 0 index
|
||||
let l:fitems = s:state['fitems']
|
||||
if l:index < 0 || len(l:fitems) <= l:index
|
||||
let l:items = []
|
||||
else
|
||||
let l:items = [l:fitems[l:index]]
|
||||
endif
|
||||
call win_gotoid(s:state['winid'])
|
||||
call s:notify('accept', { 'items': l:items })
|
||||
end
|
||||
endfunction
|
||||
|
||||
function! s:on_cancel() abort
|
||||
call win_gotoid(s:state['winid'])
|
||||
call s:notify('cancel', {})
|
||||
call lsp#internal#ui#quickpick#close()
|
||||
endfunction
|
||||
|
||||
function! s:on_move_next() abort
|
||||
let l:col = col('.')
|
||||
call s:win_execute(s:state['resultswinid'], 'normal! j')
|
||||
call s:notify_selection()
|
||||
endfunction
|
||||
|
||||
function! s:on_move_previous() abort
|
||||
let l:col = col('.')
|
||||
call s:win_execute(s:state['resultswinid'], 'normal! k')
|
||||
call s:notify_selection()
|
||||
endfunction
|
||||
|
||||
function! s:notify_items() abort
|
||||
" items could be huge, so don't send the items as part of data
|
||||
call s:notify('items', { 'bufnr': s:state['bufnr'], 'winid': s:state['winid'], 'resultsbufnr': s:state['resultsbufnr'], 'resultswinid': s:state['resultswinid'] })
|
||||
endfunction
|
||||
|
||||
function! s:notify_selection() abort
|
||||
let l:original_winid = win_getid()
|
||||
call win_gotoid(s:state['resultswinid'])
|
||||
let l:index = line('.') - 1 " line is 1 based, list is 0 based
|
||||
if l:index < 0 || ((l:index + 1) > len(s:state['fitems']))
|
||||
let l:items = []
|
||||
else
|
||||
let l:items = [s:state['fitems'][l:index]]
|
||||
endif
|
||||
let l:data = {
|
||||
\ 'bufnr': s:state['bufnr'],
|
||||
\ 'winid': s:state['winid'],
|
||||
\ 'resultsbufnr': s:state['resultsbufnr'],
|
||||
\ 'resultswinid': s:state['resultswinid'],
|
||||
\ 'items': l:items,
|
||||
\ }
|
||||
noautocmd call win_gotoid(s:state['winid'])
|
||||
call s:notify('selection', l:data)
|
||||
noautocmd call win_gotoid(l:original_winid)
|
||||
endfunction
|
||||
|
||||
function! s:on_inputchanged() abort
|
||||
if s:inputecharpre
|
||||
if s:has_timer && s:state['debounce'] > 0
|
||||
call s:debounce_onchange()
|
||||
else
|
||||
call s:notify_onchange()
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_insertcharpre() abort
|
||||
let s:inputecharpre = 1
|
||||
endfunction
|
||||
|
||||
function! s:on_insertenter() abort
|
||||
let s:inputecharpre = 0
|
||||
endfunction
|
||||
|
||||
function! s:on_insertleave() abort
|
||||
if s:has_timer && has_key(s:state, 'debounce_onchange_timer')
|
||||
call timer_stop(s:state['debounce_onchange_timer'])
|
||||
call remove(s:state, 'debounce_onchange_timer')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:debounce_onchange() abort
|
||||
if has_key(s:state, 'debounce_onchange_timer')
|
||||
call timer_stop(s:state['debounce_onchange_timer'])
|
||||
call remove(s:state, 'debounce_onchange_timer')
|
||||
endif
|
||||
let s:state['debounce_onchange_timer'] = timer_start(s:state['debounce'], function('s:notify_onchange'))
|
||||
endfunction
|
||||
|
||||
function! s:notify_onchange(...) abort
|
||||
let s:state['input'] = getbufline(s:state['promptbufnr'], 1)[0]
|
||||
call s:notify('change', { 'input': s:state['input'] })
|
||||
if s:state['filter']
|
||||
call s:update_items()
|
||||
call s:notify_selection()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:notify(name, data) abort
|
||||
if has_key(s:state, 'on_event') | call s:state['on_event'](a:data, a:name) | endif
|
||||
if has_key(s:state, 'on_' . a:name) | call s:state['on_' . a:name](a:data, a:name) | endif
|
||||
endfunction
|
||||
|
||||
if exists('*win_execute')
|
||||
function! s:win_execute(win_id, cmd) abort
|
||||
call win_execute(a:win_id, a:cmd)
|
||||
endfunction
|
||||
else
|
||||
function! s:win_execute(winid, cmd) abort
|
||||
let l:original_winid = win_getid()
|
||||
if l:original_winid == a:winid
|
||||
exec a:cmd
|
||||
else
|
||||
if win_gotoid(a:winid)
|
||||
exec a:cmd
|
||||
call win_gotoid(l:original_winid)
|
||||
end
|
||||
endif
|
||||
endfunction
|
||||
endif
|
||||
|
||||
if exists('*trim')
|
||||
function! s:trim(str) abort
|
||||
return trim(a:str)
|
||||
endfunction
|
||||
else
|
||||
function! s:trim(str) abort
|
||||
return substitute(a:str, '^\s*\|\s*$', '', 'g')
|
||||
endfunction
|
||||
endif
|
||||
|
||||
" vim: set sw=2 ts=2 sts=2 et tw=78 foldmarker={{{,}}} foldmethod=marker spell:
|
||||
@@ -0,0 +1,70 @@
|
||||
" https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress
|
||||
|
||||
let s:progress_ui = []
|
||||
let s:enabled = 0
|
||||
|
||||
function! lsp#internal#work_done_progress#_enable() abort
|
||||
if !g:lsp_work_done_progress_enabled | return | endif
|
||||
|
||||
if s:enabled | return | endif
|
||||
let s:enabled = 1
|
||||
let s:progress_ui = []
|
||||
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'response') && has_key(x['response'], 'method')
|
||||
\ && x['response']['method'] ==# '$/progress' && has_key(x['response'], 'params')
|
||||
\ && has_key(x['response']['params'], 'value') && type(x['response']['params']['value']) == type({})}),
|
||||
\ lsp#callbag#subscribe({'next': {x->s:handle_work_done_progress(x['server'], x['response'])}})
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! s:handle_work_done_progress(server, response) abort
|
||||
let l:value = a:response['params']['value']
|
||||
let l:token = a:response['params']['token']
|
||||
let l:new = {
|
||||
\ 'server': a:server,
|
||||
\ 'token': l:token,
|
||||
\ 'title': '',
|
||||
\ 'message': '',
|
||||
\ }
|
||||
|
||||
if l:value['kind'] ==# 'end'
|
||||
let l:new['message'] = ''
|
||||
let l:new['percentage'] = 100
|
||||
call filter(s:progress_ui, {_, x->x['token'] !=# l:token || x['server'] !=# a:server})
|
||||
elseif l:value['kind'] ==# 'begin'
|
||||
let l:new['title'] = l:value['title']
|
||||
call filter(s:progress_ui, {_, x->x['token'] !=# l:token || x['server'] !=# a:server})
|
||||
call insert(s:progress_ui, l:new)
|
||||
elseif l:value['kind'] ==# 'report'
|
||||
let l:new['message'] = get(l:value, 'message', '')
|
||||
if has_key(l:value, 'percentage')
|
||||
" l:value['percentage'] is uinteger in specification.
|
||||
" But some implementation return float. (e.g. clangd11)
|
||||
" So we round it.
|
||||
let l:new['percentage'] = float2nr(l:value['percentage'] + 0.5)
|
||||
endif
|
||||
let l:idx = match(s:progress_ui, l:token)
|
||||
let l:new['title'] = s:progress_ui[l:idx]['title']
|
||||
call filter(s:progress_ui, {_, x->x['token'] !=# l:token || x['server'] !=# a:server})
|
||||
call insert(s:progress_ui, l:new)
|
||||
endif
|
||||
doautocmd <nomodeline> User lsp_progress_updated
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#work_done_progress#_disable() abort
|
||||
if !s:enabled | return | endif
|
||||
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
|
||||
let s:enabled = 0
|
||||
let s:progress_ui = []
|
||||
endfunction
|
||||
|
||||
function! lsp#internal#work_done_progress#get_progress() abort
|
||||
return s:progress_ui
|
||||
endfunction
|
||||
@@ -0,0 +1,94 @@
|
||||
" https://microsoft.github.io/language-server-protocol/specification#workspace_symbol
|
||||
" options - {
|
||||
" bufnr: bufnr('%') " optional
|
||||
" server - 'server_name' " optional
|
||||
" query: '' " optional
|
||||
" }
|
||||
function! lsp#internal#workspace_symbol#search#do(options) abort
|
||||
if has_key(a:options, 'server')
|
||||
let l:servers = [a:options['server']]
|
||||
else
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_document_symbol_provider(v:val)')
|
||||
endif
|
||||
|
||||
if len(l:servers) == 0
|
||||
echom 'textDocument/workspaceSymbol not supported'
|
||||
call lsp#utils#error('textDocument/workspaceSymbol not supported')
|
||||
return
|
||||
endif
|
||||
|
||||
redraw | echo 'Retrieving workspace symbols ...'
|
||||
|
||||
let l:TextChangeSubject = lsp#callbag#makeSubject()
|
||||
|
||||
" use callbag debounce instead of quickpick debounce
|
||||
call lsp#internal#ui#quickpick#open({
|
||||
\ 'items': [],
|
||||
\ 'input': get(a:options, 'query', ''),
|
||||
\ 'key': 'text',
|
||||
\ 'debounce': 0,
|
||||
\ 'on_change': function('s:on_change', [l:TextChangeSubject]),
|
||||
\ 'on_accept': function('s:on_accept'),
|
||||
\ 'on_close': function('s:on_close'),
|
||||
\ })
|
||||
|
||||
let s:Dispose = lsp#callbag#pipe(
|
||||
\ l:TextChangeSubject,
|
||||
\ lsp#callbag#debounceTime(250),
|
||||
\ lsp#callbag#distinctUntilChanged(),
|
||||
\ lsp#callbag#switchMap({query->
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromList(l:servers),
|
||||
\ lsp#callbag#tap({_->lsp#internal#ui#quickpick#busy(1)}),
|
||||
\ lsp#callbag#flatMap({server->
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#request(server, {
|
||||
\ 'method': 'workspace/symbol',
|
||||
\ 'params': {
|
||||
\ 'query': query
|
||||
\ }
|
||||
\ }),
|
||||
\ lsp#callbag#map({x->{'server': server, 'request': x['request'], 'response': x['response']}}),
|
||||
\ )
|
||||
\ }),
|
||||
\ lsp#callbag#scan({acc, curr->add(acc, curr)}, []),
|
||||
\ lsp#callbag#tap({x->s:update_ui_items(x)}),
|
||||
\ lsp#callbag#tap({'complete': {->lsp#internal#ui#quickpick#busy(0)}}),
|
||||
\ )
|
||||
\ }),
|
||||
\ lsp#callbag#subscribe({
|
||||
\ 'error': {e->s:on_error(e)},
|
||||
\ }),
|
||||
\ )
|
||||
" Notify empty query. Some servers may not return results when query is empty
|
||||
call l:TextChangeSubject(1, '')
|
||||
endfunction
|
||||
|
||||
function! s:on_change(TextChangeSubject, data, ...) abort
|
||||
call a:TextChangeSubject(1, a:data['input'])
|
||||
endfunction
|
||||
|
||||
function! s:update_ui_items(x) abort
|
||||
let l:items = []
|
||||
for l:i in a:x
|
||||
let l:items += lsp#ui#vim#utils#symbols_to_loc_list(l:i['server'], l:i)
|
||||
endfor
|
||||
call lsp#internal#ui#quickpick#items(l:items)
|
||||
endfunction
|
||||
|
||||
function! s:on_accept(data, name) abort
|
||||
call lsp#internal#ui#quickpick#close()
|
||||
call lsp#utils#location#_open_vim_list_item(a:data['items'][0], '')
|
||||
endfunction
|
||||
|
||||
function! s:on_close(...) abort
|
||||
if exists('s:Dispose')
|
||||
call s:Dispose()
|
||||
unlet s:Dispose
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_error(e) abort
|
||||
call lsp#internal#ui#quickpick#close()
|
||||
call lsp#log('LspWorkspaceSymbolSearch error', a:e)
|
||||
endfunction
|
||||
453
dot_vim/plugged/vim-lsp/autoload/lsp/omni.vim
Normal file
453
dot_vim/plugged/vim-lsp/autoload/lsp/omni.vim
Normal file
@@ -0,0 +1,453 @@
|
||||
" vint: -ProhibitUnusedVariable
|
||||
|
||||
" constants {{{
|
||||
let s:t_dict = type({})
|
||||
|
||||
let s:default_completion_item_kinds = {
|
||||
\ '1': 'text',
|
||||
\ '2': 'method',
|
||||
\ '3': 'function',
|
||||
\ '4': 'constructor',
|
||||
\ '5': 'field',
|
||||
\ '6': 'variable',
|
||||
\ '7': 'class',
|
||||
\ '8': 'interface',
|
||||
\ '9': 'module',
|
||||
\ '10': 'property',
|
||||
\ '11': 'unit',
|
||||
\ '12': 'value',
|
||||
\ '13': 'enum',
|
||||
\ '14': 'keyword',
|
||||
\ '15': 'snippet',
|
||||
\ '16': 'color',
|
||||
\ '17': 'file',
|
||||
\ '18': 'reference',
|
||||
\ '19': 'folder',
|
||||
\ '20': 'enum member',
|
||||
\ '21': 'constant',
|
||||
\ '22': 'struct',
|
||||
\ '23': 'event',
|
||||
\ '24': 'operator',
|
||||
\ '25': 'type parameter',
|
||||
\ }
|
||||
|
||||
let s:completion_item_kinds = {}
|
||||
|
||||
let s:completion_status_success = 'success'
|
||||
let s:completion_status_failed = 'failed'
|
||||
let s:completion_status_pending = 'pending'
|
||||
|
||||
let s:is_user_data_support = has('patch-8.0.1493')
|
||||
let s:managed_user_data_key_base = 0
|
||||
let s:managed_user_data_map = {}
|
||||
|
||||
" }}}
|
||||
|
||||
" completion state
|
||||
let s:completion = {'counter': 0, 'status': '', 'matches': []}
|
||||
|
||||
function! lsp#omni#complete(findstart, base) abort
|
||||
let l:info = s:find_complete_servers()
|
||||
if empty(l:info['server_names'])
|
||||
return a:findstart ? -1 : []
|
||||
endif
|
||||
|
||||
if a:findstart
|
||||
return col('.')
|
||||
else
|
||||
if !g:lsp_async_completion
|
||||
let s:completion['status'] = s:completion_status_pending
|
||||
endif
|
||||
|
||||
let l:left = strpart(getline('.'), 0, col('.')-1)
|
||||
|
||||
" Initialize the default startcol. It will be updated if the completion items has textEdit.
|
||||
let s:completion['startcol'] = s:get_startcol(l:left, l:info['server_names'])
|
||||
|
||||
" The `l:info` variable will be filled with completion results after request was finished.
|
||||
call s:send_completion_request(l:info)
|
||||
|
||||
if g:lsp_async_completion
|
||||
" If g:lsp_async_completion == v:true, the `s:display_completions` " will be called by `s:send_completion_request`.
|
||||
redraw
|
||||
return exists('v:none') ? v:none : []
|
||||
else
|
||||
" Wait for finished the textDocument/completion request and then call `s:display_completions` explicitly.
|
||||
call lsp#utils#_wait(-1, {-> s:completion['status'] isnot# s:completion_status_pending || complete_check()}, 10)
|
||||
call timer_start(0, { timer -> s:display_completions(timer, l:info) })
|
||||
|
||||
return exists('v:none') ? v:none : []
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:get_filter_label(item) abort
|
||||
return lsp#utils#_trim(a:item['word'])
|
||||
endfunction
|
||||
|
||||
function! s:prefix_filter(item, last_typed_word) abort
|
||||
let l:label = s:get_filter_label(a:item)
|
||||
|
||||
if g:lsp_ignorecase
|
||||
return stridx(tolower(l:label), tolower(a:last_typed_word)) == 0
|
||||
else
|
||||
return stridx(l:label, a:last_typed_word) == 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:contains_filter(item, last_typed_word) abort
|
||||
let l:label = s:get_filter_label(a:item)
|
||||
|
||||
if g:lsp_ignorecase
|
||||
return stridx(tolower(l:label), tolower(a:last_typed_word)) >= 0
|
||||
else
|
||||
return stridx(l:label, a:last_typed_word) >= 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:pair = {
|
||||
\ '"': '"',
|
||||
\ '''': '''',
|
||||
\ '{': '}',
|
||||
\ '(': ')',
|
||||
\ '[': ']',
|
||||
\}
|
||||
|
||||
function! s:display_completions(timer, info) abort
|
||||
" TODO: Allow multiple servers
|
||||
let l:server_name = a:info['server_names'][0]
|
||||
let l:server_info = lsp#get_server_info(l:server_name)
|
||||
|
||||
let l:current_line = strpart(getline('.'), 0, col('.') - 1)
|
||||
let l:last_typed_word = strpart(l:current_line, s:completion['startcol'] - 1)
|
||||
|
||||
let l:filter = has_key(l:server_info, 'config') && has_key(l:server_info['config'], 'filter') ? l:server_info['config']['filter'] : { 'name': 'prefix' }
|
||||
if l:filter['name'] ==? 'prefix'
|
||||
let s:completion['matches'] = filter(s:completion['matches'], {_, item -> s:prefix_filter(item, l:last_typed_word)})
|
||||
if has_key(s:pair, l:last_typed_word[0])
|
||||
let [l:lhs, l:rhs] = [l:last_typed_word[0], s:pair[l:last_typed_word[0]]]
|
||||
for l:item in s:completion['matches']
|
||||
let l:str = l:item['word']
|
||||
if len(l:str) > 1 && l:str[0] ==# l:lhs && l:str[-1:] ==# l:rhs
|
||||
let l:item['word'] = l:str[:-2]
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
elseif l:filter['name'] ==? 'contains'
|
||||
let s:completion['matches'] = filter(s:completion['matches'], {_, item -> s:contains_filter(item, l:last_typed_word)})
|
||||
endif
|
||||
|
||||
let s:completion['status'] = ''
|
||||
|
||||
if mode() is# 'i'
|
||||
call complete(s:completion['startcol'], s:completion['matches'])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:handle_omnicompletion(server_name, complete_counter, info, data) abort
|
||||
if s:completion['counter'] != a:complete_counter
|
||||
" ignore old completion results
|
||||
return
|
||||
endif
|
||||
|
||||
if lsp#client#is_error(a:data) || !has_key(a:data, 'response') || !has_key(a:data['response'], 'result')
|
||||
let s:completion['status'] = s:completion_status_failed
|
||||
return
|
||||
endif
|
||||
|
||||
let l:result = s:get_completion_result(a:server_name, a:data)
|
||||
let s:completion['matches'] = l:result['items']
|
||||
let s:completion['startcol'] = min([l:result['startcol'], s:completion['startcol']])
|
||||
let s:completion['status'] = s:completion_status_success
|
||||
|
||||
if g:lsp_async_completion
|
||||
call s:display_completions(0, a:info)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#omni#get_kind_text(completion_item, ...) abort
|
||||
let l:server = get(a:, 1, '')
|
||||
if empty(l:server) " server name
|
||||
let l:completion_item_kinds = s:default_completion_item_kinds
|
||||
else
|
||||
if !has_key(s:completion_item_kinds, l:server)
|
||||
let l:server_info = lsp#get_server_info(l:server)
|
||||
if has_key (l:server_info, 'config') && has_key(l:server_info['config'], 'completion_item_kinds')
|
||||
let s:completion_item_kinds[l:server] = extend(copy(s:default_completion_item_kinds), l:server_info['config']['completion_item_kinds'])
|
||||
else
|
||||
let s:completion_item_kinds[l:server] = s:default_completion_item_kinds
|
||||
endif
|
||||
endif
|
||||
let l:completion_item_kinds = s:completion_item_kinds[l:server]
|
||||
endif
|
||||
|
||||
return has_key(a:completion_item, 'kind') && has_key(l:completion_item_kinds, a:completion_item['kind'])
|
||||
\ ? l:completion_item_kinds[a:completion_item['kind']] : ''
|
||||
endfunction
|
||||
|
||||
function! s:get_kind_text_mappings(server) abort
|
||||
let l:server_name = a:server['name']
|
||||
if has_key(s:completion_item_kinds, l:server_name)
|
||||
return s:completion_item_kinds[l:server_name]
|
||||
else
|
||||
if has_key(a:server, 'config') && has_key(a:server['config'], 'completion_item_kinds')
|
||||
let s:completion_item_kinds[l:server_name] = extend(copy(s:default_completion_item_kinds), a:server['config']['completion_item_kinds'])
|
||||
else
|
||||
let s:completion_item_kinds[l:server_name] = s:default_completion_item_kinds
|
||||
endif
|
||||
return s:completion_item_kinds[l:server_name]
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" auxiliary functions {{{
|
||||
|
||||
function! s:find_complete_servers() abort
|
||||
let l:server_names = []
|
||||
for l:server_name in lsp#get_allowed_servers()
|
||||
let l:init_capabilities = lsp#get_server_capabilities(l:server_name)
|
||||
if has_key(l:init_capabilities, 'completionProvider')
|
||||
" TODO: support triggerCharacters
|
||||
call add(l:server_names, l:server_name)
|
||||
endif
|
||||
endfor
|
||||
|
||||
return { 'server_names': l:server_names }
|
||||
endfunction
|
||||
|
||||
function! s:send_completion_request(info) abort
|
||||
let s:completion['counter'] = s:completion['counter'] + 1
|
||||
let l:server_name = a:info['server_names'][0]
|
||||
" TODO: support multiple servers
|
||||
call lsp#send_request(l:server_name, {
|
||||
\ 'method': 'textDocument/completion',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'position': lsp#get_position(),
|
||||
\ 'context': { 'triggerKind': 1 },
|
||||
\ },
|
||||
\ 'on_notification': function('s:handle_omnicompletion', [l:server_name, s:completion['counter'], a:info]),
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
function! s:get_completion_result(server_name, data) abort
|
||||
let l:result = a:data['response']['result']
|
||||
|
||||
let l:options = {
|
||||
\ 'server': lsp#get_server_info(a:server_name),
|
||||
\ 'position': lsp#get_position(),
|
||||
\ 'response': a:data['response'],
|
||||
\ }
|
||||
|
||||
return lsp#omni#get_vim_completion_items(l:options)
|
||||
endfunction
|
||||
|
||||
function! s:sort_by_sorttext(i1, i2) abort
|
||||
let l:text1 = get(a:i1, 'sortText')
|
||||
let l:text2 = get(a:i2, 'sortText')
|
||||
|
||||
" sortText is possibly empty string
|
||||
let l:text1 = !empty(l:text1) ? l:text1 : a:i1['label']
|
||||
let l:text2 = !empty(l:text2) ? l:text2 : a:i2['label']
|
||||
|
||||
if g:lsp_ignorecase
|
||||
return l:text1 ==? l:text2 ? 0 : l:text1 >? l:text2 ? 1 : -1
|
||||
else
|
||||
return l:text1 ==# l:text2 ? 0 : l:text1 ># l:text2 ? 1 : -1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Create vim's completed items from LSP response.
|
||||
"
|
||||
" options = {
|
||||
" server: {}, " needs to be server_info and not server_name
|
||||
" position: lsp#get_position(),
|
||||
" response: {}, " needs to be the entire lsp response. errors need to be
|
||||
" handled before calling the fuction
|
||||
" }
|
||||
"
|
||||
" * The returned` startcol` may be the same as the cursor position, in which case you need to decide which one to use.
|
||||
"
|
||||
" @return { 'items': v:completed_item[], 'incomplete': v:t_bool, 'startcol': number }
|
||||
"
|
||||
function! lsp#omni#get_vim_completion_items(options) abort
|
||||
let l:server = a:options['server']
|
||||
let l:server_name = l:server['name']
|
||||
let l:kind_text_mappings = s:get_kind_text_mappings(l:server)
|
||||
let l:complete_position = a:options['position']
|
||||
let l:current_line = getline('.')
|
||||
let l:default_startcol = s:get_startcol(strcharpart(l:current_line, 0, l:complete_position['character']), [l:server_name])
|
||||
let l:default_start_character = strchars(strpart(l:current_line, 0, l:default_startcol - 1))
|
||||
let l:refresh_pattern = s:get_refresh_pattern([l:server_name])
|
||||
|
||||
let l:result = a:options['response']['result']
|
||||
if type(l:result) == type([])
|
||||
let l:items = l:result
|
||||
let l:incomplete = 0
|
||||
elseif type(l:result) == type({})
|
||||
let l:items = l:result['items']
|
||||
let l:incomplete = l:result['isIncomplete']
|
||||
else
|
||||
let l:items = []
|
||||
let l:incomplete = 0
|
||||
endif
|
||||
|
||||
let l:sort = has_key(l:server, 'config') && has_key(l:server['config'], 'sort') ? l:server['config']['sort'] : v:null
|
||||
|
||||
if len(l:items) > 0 && type(l:sort) == s:t_dict && len(l:items) <= l:sort['max']
|
||||
" If first item contains sortText, maybe we can use sortText
|
||||
call sort(l:items, function('s:sort_by_sorttext'))
|
||||
endif
|
||||
|
||||
let l:start_character = l:complete_position['character']
|
||||
|
||||
let l:start_characters = [] " The mapping of item specific start_character.
|
||||
let l:vim_complete_items = []
|
||||
for l:completion_item in l:items
|
||||
let l:expandable = get(l:completion_item, 'insertTextFormat', 1) == 2
|
||||
let l:vim_complete_item = {
|
||||
\ 'kind': get(l:kind_text_mappings, get(l:completion_item, 'kind', '') , ''),
|
||||
\ 'dup': 1,
|
||||
\ 'empty': 1,
|
||||
\ 'icase': 1,
|
||||
\ }
|
||||
let l:range = lsp#utils#text_edit#get_range(get(l:completion_item, 'textEdit', {}))
|
||||
if has_key(l:completion_item, 'textEdit') && type(l:completion_item['textEdit']) == s:t_dict && !empty(l:range) && has_key(l:completion_item['textEdit'], 'newText')
|
||||
let l:text_edit_new_text = l:completion_item['textEdit']['newText']
|
||||
if has_key(l:completion_item, 'filterText') && !empty(l:completion_item['filterText']) && matchstr(l:text_edit_new_text, '^' . l:refresh_pattern) ==# ''
|
||||
" Use filterText as word.
|
||||
let l:vim_complete_item['word'] = l:completion_item['filterText']
|
||||
else
|
||||
" Use textEdit.newText as word.
|
||||
let l:vim_complete_item['word'] = l:text_edit_new_text
|
||||
endif
|
||||
|
||||
" Fix overlapped text if needed.
|
||||
let l:item_start_character = l:range['start']['character']
|
||||
if l:item_start_character < l:default_start_character
|
||||
" Add already typed word. The typescript-language-server returns `[Symbol]` item for the line of `Hoo.|`. So we should add `.` (`.[Symbol]`) .
|
||||
let l:overlap_text = strcharpart(l:current_line, l:item_start_character, l:default_start_character - l:item_start_character)
|
||||
if stridx(l:vim_complete_item['word'], l:overlap_text) != 0
|
||||
let l:vim_complete_item['word'] = l:overlap_text . l:vim_complete_item['word']
|
||||
endif
|
||||
endif
|
||||
let l:start_character = min([l:item_start_character, l:start_character])
|
||||
let l:start_characters += [l:item_start_character]
|
||||
elseif has_key(l:completion_item, 'insertText') && !empty(l:completion_item['insertText'])
|
||||
let l:vim_complete_item['word'] = l:completion_item['insertText']
|
||||
let l:start_characters += [l:default_start_character]
|
||||
else
|
||||
let l:vim_complete_item['word'] = l:completion_item['label']
|
||||
let l:start_characters += [l:default_start_character]
|
||||
endif
|
||||
|
||||
if l:expandable
|
||||
let l:vim_complete_item['word'] = lsp#utils#make_valid_word(substitute(l:vim_complete_item['word'], '\$[0-9]\+\|\${\%(\\.\|[^}]\)\+}', '', 'g'))
|
||||
let l:vim_complete_item['abbr'] = l:completion_item['label'] . '~'
|
||||
else
|
||||
let l:vim_complete_item['abbr'] = l:completion_item['label']
|
||||
endif
|
||||
|
||||
if s:is_user_data_support
|
||||
let l:vim_complete_item['user_data'] = s:create_user_data(l:completion_item, l:server_name, l:complete_position, l:start_characters[len(l:start_characters) - 1])
|
||||
endif
|
||||
|
||||
let l:vim_complete_items += [l:vim_complete_item]
|
||||
endfor
|
||||
|
||||
" Add the additional text for startcol correction.
|
||||
if l:start_character != l:default_start_character
|
||||
for l:i in range(len(l:start_characters))
|
||||
let l:item_start_character = l:start_characters[l:i]
|
||||
if l:start_character < l:item_start_character
|
||||
let l:item = l:vim_complete_items[l:i]
|
||||
let l:item['word'] = strcharpart(l:current_line, l:start_character, l:item_start_character - l:start_character) . l:item['word']
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
let l:startcol = lsp#utils#position#lsp_character_to_vim('%', { 'line': l:complete_position['line'], 'character': l:start_character })
|
||||
|
||||
return { 'items': l:vim_complete_items, 'incomplete': l:incomplete, 'startcol': l:startcol }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" Clear internal user_data map.
|
||||
"
|
||||
" This function should call at `CompleteDone` only if not empty `v:completed_item`.
|
||||
"
|
||||
function! lsp#omni#_clear_managed_user_data_map() abort
|
||||
let s:managed_user_data_key_base = 0
|
||||
let s:managed_user_data_map = {}
|
||||
endfunction
|
||||
|
||||
"
|
||||
" create item's user_data.
|
||||
"
|
||||
function! s:create_user_data(completion_item, server_name, complete_position, start_character) abort
|
||||
let l:user_data_key = s:create_user_data_key(s:managed_user_data_key_base)
|
||||
let s:managed_user_data_map[l:user_data_key] = {
|
||||
\ 'complete_position': a:complete_position,
|
||||
\ 'server_name': a:server_name,
|
||||
\ 'completion_item': a:completion_item,
|
||||
\ 'start_character': a:start_character,
|
||||
\ }
|
||||
let s:managed_user_data_key_base += 1
|
||||
return l:user_data_key
|
||||
endfunction
|
||||
|
||||
function! lsp#omni#get_managed_user_data_from_completed_item(completed_item) abort
|
||||
" the item has no user_data.
|
||||
if !has_key(a:completed_item, 'user_data')
|
||||
return {}
|
||||
endif
|
||||
|
||||
let l:user_data_string = get(a:completed_item, 'user_data', '')
|
||||
if type(l:user_data_string) != type('')
|
||||
return {}
|
||||
endif
|
||||
|
||||
" Check managed user_data.
|
||||
if has_key(s:managed_user_data_map, l:user_data_string)
|
||||
return s:managed_user_data_map[l:user_data_string]
|
||||
endif
|
||||
|
||||
" Check json.
|
||||
if stridx(l:user_data_string, '"vim-lsp/key"') != -1
|
||||
try
|
||||
let l:user_data = json_decode(l:user_data_string)
|
||||
if has_key(l:user_data, 'vim-lsp/key')
|
||||
let l:user_data_key = s:create_user_data_key(l:user_data['vim-lsp/key'])
|
||||
if has_key(s:managed_user_data_map, l:user_data_key)
|
||||
return s:managed_user_data_map[l:user_data_key]
|
||||
endif
|
||||
endif
|
||||
catch /.*/
|
||||
endtry
|
||||
endif
|
||||
return {}
|
||||
endfunction
|
||||
|
||||
function! lsp#omni#get_completion_item_kinds() abort
|
||||
return map(keys(s:default_completion_item_kinds), {idx, key -> str2nr(key)})
|
||||
endfunction
|
||||
|
||||
function! s:create_user_data_key(base) abort
|
||||
return '{"vim-lsp/key":"' . a:base . '"}'
|
||||
endfunction
|
||||
|
||||
function! s:get_startcol(left, server_names) abort
|
||||
" Initialize the default startcol. It will be updated if the completion items has textEdit.
|
||||
let l:startcol = 1 + matchstrpos(a:left, s:get_refresh_pattern(a:server_names))[1]
|
||||
return l:startcol == 0 ? strlen(a:left) + 1 : l:startcol
|
||||
endfunction
|
||||
|
||||
function! s:get_refresh_pattern(server_names) abort
|
||||
for l:server_name in a:server_names
|
||||
let l:server_info = lsp#get_server_info(l:server_name)
|
||||
if has_key(l:server_info, 'config') && has_key(l:server_info['config'], 'refresh_pattern')
|
||||
return l:server_info['config']['refresh_pattern']
|
||||
endif
|
||||
endfor
|
||||
return '\(\k\+$\)'
|
||||
endfunction
|
||||
|
||||
" }}}
|
||||
157
dot_vim/plugged/vim-lsp/autoload/lsp/tag.vim
Normal file
157
dot_vim/plugged/vim-lsp/autoload/lsp/tag.vim
Normal file
@@ -0,0 +1,157 @@
|
||||
let s:tag_kind_priority = ['definition', 'declaration', 'implementation', 'type definition']
|
||||
|
||||
function! s:not_supported(what) abort
|
||||
call lsp#log(a:what . ' not supported for ' . &filetype)
|
||||
endfunction
|
||||
|
||||
function! s:location_to_tag(loc) abort
|
||||
if has_key(a:loc, 'targetUri')
|
||||
let l:uri = a:loc['targetUri']
|
||||
let l:range = a:loc['targetRange']
|
||||
else
|
||||
let l:uri = a:loc['uri']
|
||||
let l:range = a:loc['range']
|
||||
endif
|
||||
|
||||
if !lsp#utils#is_file_uri(l:uri)
|
||||
return v:null
|
||||
endif
|
||||
|
||||
let l:path = lsp#utils#uri_to_path(l:uri)
|
||||
let [l:line, l:col] = lsp#utils#position#lsp_to_vim(l:path, l:range['start'])
|
||||
return {
|
||||
\ 'filename': l:path,
|
||||
\ 'cmd': printf('/\%%%dl\%%%dc/', l:line, l:col)
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
function! s:handle_locations(ctx, server, type, data) abort
|
||||
try
|
||||
if lsp#client#is_error(a:data['response']) || !has_key(a:data['response'], 'result')
|
||||
call lsp#utils#error('Failed to retrieve ' . a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
return
|
||||
endif
|
||||
|
||||
let l:list = a:ctx['list']
|
||||
let l:result = a:data['response']['result']
|
||||
if type(l:result) != type([])
|
||||
let l:result = [l:result]
|
||||
endif
|
||||
for l:loc in l:result
|
||||
let l:tag = s:location_to_tag(l:loc)
|
||||
if !empty(l:tag)
|
||||
call add(l:list, extend(l:tag, { 'name': a:ctx['pattern'], 'kind': a:type }))
|
||||
endif
|
||||
endfor
|
||||
finally
|
||||
let a:ctx['counter'] -= 1
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:handle_symbols(ctx, server, data) abort
|
||||
try
|
||||
if lsp#client#is_error(a:data['response']) || !has_key(a:data['response'], 'result')
|
||||
call lsp#utils#error('Failed to retrieve workspace symbols for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
return
|
||||
endif
|
||||
|
||||
let l:list = a:ctx['list']
|
||||
for l:symbol in a:data['response']['result']
|
||||
let l:tag = s:location_to_tag(l:symbol['location'])
|
||||
if empty(l:tag)
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:tag['name'] = l:symbol['name']
|
||||
if has_key(l:symbol, 'kind')
|
||||
let l:tag['kind'] = lsp#ui#vim#utils#_get_symbol_text_from_kind(a:server, l:symbol['kind'])
|
||||
endif
|
||||
call add(l:list, l:tag)
|
||||
endfor
|
||||
finally
|
||||
let a:ctx['counter'] -= 1
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:tag_view_sub(ctx, method, params) abort
|
||||
let l:operation = substitute(a:method, '\u', ' \l\0', 'g')
|
||||
|
||||
let l:capabilities_func = printf('lsp#capabilities#has_%s_provider(v:val)', substitute(l:operation, ' ', '_', 'g'))
|
||||
let l:servers = filter(lsp#get_allowed_servers(), l:capabilities_func)
|
||||
if empty(l:servers)
|
||||
call s:not_supported('retrieving ' . l:operation)
|
||||
return v:false
|
||||
endif
|
||||
|
||||
let a:ctx['counter'] += len(l:servers)
|
||||
for l:server in l:servers
|
||||
call lsp#send_request(l:server, {
|
||||
\ 'method': 'textDocument/'.a:method,
|
||||
\ 'params': a:params,
|
||||
\ 'on_notification': function('s:handle_locations', [a:ctx, l:server, l:operation])
|
||||
\})
|
||||
endfor
|
||||
return v:true
|
||||
endfunction
|
||||
|
||||
function! s:tag_view(ctx) abort
|
||||
let l:params = {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'position': lsp#get_position(),
|
||||
\ }
|
||||
return !empty(filter(copy(g:lsp_tagfunc_source_methods),
|
||||
\ {_, m -> s:tag_view_sub(a:ctx, m, l:params)}))
|
||||
endfunction
|
||||
|
||||
function! s:tag_search(ctx) abort
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_workspace_symbol_provider(v:val)')
|
||||
if empty(l:servers)
|
||||
call s:not_supported('retrieving workspace symbols')
|
||||
return v:false
|
||||
endif
|
||||
|
||||
let a:ctx['counter'] = len(l:servers)
|
||||
for l:server in l:servers
|
||||
call lsp#send_request(l:server, {
|
||||
\ 'method': 'workspace/symbol',
|
||||
\ 'params': { 'query': a:ctx['pattern'] },
|
||||
\ 'on_notification': function('s:handle_symbols', [a:ctx, l:server])
|
||||
\ })
|
||||
endfor
|
||||
return v:true
|
||||
endfunction
|
||||
|
||||
function! s:compare_tags(path, a, b) abort
|
||||
" TODO: custom tag sorting, maybe?
|
||||
if a:a['filename'] !=# a:b['filename']
|
||||
if a:a['filename'] ==# a:path
|
||||
return -1
|
||||
elseif a:b['filename'] ==# a:path
|
||||
return 1
|
||||
endif
|
||||
endif
|
||||
let l:rank_a = index(s:tag_kind_priority, get(a:a, 'kind', ''))
|
||||
let l:rank_b = index(s:tag_kind_priority, get(a:b, 'kind', ''))
|
||||
if l:rank_a != l:rank_b
|
||||
return l:rank_a < l:rank_b ? -1 : 1
|
||||
endif
|
||||
if a:a['filename'] !=# a:b['filename']
|
||||
return a:a['filename'] <# a:b['filename'] ? -1 : 1
|
||||
endif
|
||||
return str2nr(a:a['cmd']) - str2nr(a:b['cmd'])
|
||||
endfunction
|
||||
|
||||
function! lsp#tag#tagfunc(pattern, flags, info) abort
|
||||
if stridx(a:flags, 'i') >= 0
|
||||
return v:null
|
||||
endif
|
||||
|
||||
let l:ctx = { 'pattern': a:pattern, 'counter': 0, 'list': [] }
|
||||
if !(stridx(a:flags, 'c') >= 0 ? s:tag_view(l:ctx) : s:tag_search(l:ctx))
|
||||
" No supported methods so use builtin tag source
|
||||
return v:null
|
||||
endif
|
||||
call lsp#utils#_wait(-1, {-> l:ctx['counter'] == 0}, 50)
|
||||
call sort(l:ctx['list'], function('s:compare_tags', [a:info['buf_ffname']]))
|
||||
return l:ctx['list']
|
||||
endfunction
|
||||
497
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim.vim
Normal file
497
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim.vim
Normal file
@@ -0,0 +1,497 @@
|
||||
function! s:not_supported(what) abort
|
||||
return lsp#utils#error(printf("%s not supported for filetype '%s'", a:what, &filetype))
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#implementation(in_preview, ...) abort
|
||||
let l:ctx = { 'in_preview': a:in_preview }
|
||||
if a:0
|
||||
let l:ctx['mods'] = a:1
|
||||
endif
|
||||
call s:list_location('implementation', l:ctx)
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#type_definition(in_preview, ...) abort
|
||||
let l:ctx = { 'in_preview': a:in_preview }
|
||||
if a:0
|
||||
let l:ctx['mods'] = a:1
|
||||
endif
|
||||
call s:list_location('typeDefinition', l:ctx)
|
||||
endfunction
|
||||
|
||||
|
||||
function! lsp#ui#vim#declaration(in_preview, ...) abort
|
||||
let l:ctx = { 'in_preview': a:in_preview }
|
||||
if a:0
|
||||
let l:ctx['mods'] = a:1
|
||||
endif
|
||||
call s:list_location('declaration', l:ctx)
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#definition(in_preview, ...) abort
|
||||
let l:ctx = { 'in_preview': a:in_preview }
|
||||
if a:0
|
||||
let l:ctx['mods'] = a:1
|
||||
endif
|
||||
call s:list_location('definition', l:ctx)
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#references() abort
|
||||
let l:ctx = { 'jump_if_one': 0 }
|
||||
let l:request_params = { 'context': { 'includeDeclaration': v:false } }
|
||||
call s:list_location('references', l:ctx, l:request_params)
|
||||
endfunction
|
||||
|
||||
function! s:list_location(method, ctx, ...) abort
|
||||
" typeDefinition => type definition
|
||||
let l:operation = substitute(a:method, '\u', ' \l\0', 'g')
|
||||
|
||||
let l:capabilities_func = printf('lsp#capabilities#has_%s_provider(v:val)', substitute(l:operation, ' ', '_', 'g'))
|
||||
let l:servers = filter(lsp#get_allowed_servers(), l:capabilities_func)
|
||||
let l:command_id = lsp#_new_command()
|
||||
|
||||
|
||||
let l:ctx = extend({ 'counter': len(l:servers), 'list':[], 'last_command_id': l:command_id, 'jump_if_one': 1, 'mods': '', 'in_preview': 0 }, a:ctx)
|
||||
if len(l:servers) == 0
|
||||
call s:not_supported('Retrieving ' . l:operation)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:params = {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'position': lsp#get_position(),
|
||||
\ }
|
||||
if a:0
|
||||
call extend(l:params, a:1)
|
||||
endif
|
||||
for l:server in l:servers
|
||||
call lsp#send_request(l:server, {
|
||||
\ 'method': 'textDocument/' . a:method,
|
||||
\ 'params': l:params,
|
||||
\ 'on_notification': function('s:handle_location', [l:ctx, l:server, l:operation]),
|
||||
\ })
|
||||
endfor
|
||||
|
||||
echo printf('Retrieving %s ...', l:operation)
|
||||
endfunction
|
||||
|
||||
function! s:rename(server, new_name, pos) abort
|
||||
if empty(a:new_name)
|
||||
echo '... Renaming aborted ...'
|
||||
return
|
||||
endif
|
||||
|
||||
" needs to flush existing open buffers
|
||||
call lsp#send_request(a:server, {
|
||||
\ 'method': 'textDocument/rename',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'position': a:pos,
|
||||
\ 'newName': a:new_name,
|
||||
\ },
|
||||
\ 'on_notification': function('s:handle_workspace_edit', [a:server, lsp#_last_command(), 'rename']),
|
||||
\ })
|
||||
|
||||
echo ' ... Renaming ...'
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#rename() abort
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_rename_prepare_provider(v:val)')
|
||||
let l:prepare_support = 1
|
||||
if len(l:servers) == 0
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_rename_provider(v:val)')
|
||||
let l:prepare_support = 0
|
||||
endif
|
||||
|
||||
let l:command_id = lsp#_new_command()
|
||||
|
||||
if len(l:servers) == 0
|
||||
call s:not_supported('Renaming')
|
||||
return
|
||||
endif
|
||||
|
||||
" TODO: ask the user which server it should use to rename if there are multiple
|
||||
let l:server = l:servers[0]
|
||||
|
||||
if l:prepare_support
|
||||
call lsp#send_request(l:server, {
|
||||
\ 'method': 'textDocument/prepareRename',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'position': lsp#get_position(),
|
||||
\ },
|
||||
\ 'on_notification': function('s:handle_rename_prepare', [l:server, l:command_id, 'rename_prepare', expand('<cword>'), lsp#get_position()]),
|
||||
\ })
|
||||
return
|
||||
endif
|
||||
|
||||
call s:rename(l:server, input('new name: ', expand('<cword>')), lsp#get_position())
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#stop_server(...) abort
|
||||
let l:name = get(a:000, 0, '')
|
||||
for l:server in lsp#get_allowed_servers()
|
||||
if !empty(l:name) && l:server != l:name
|
||||
continue
|
||||
endif
|
||||
echo 'Stopping' l:server 'server ...'
|
||||
call lsp#stop_server(l:server)
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#workspace_symbol(query) abort
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_workspace_symbol_provider(v:val)')
|
||||
let l:command_id = lsp#_new_command()
|
||||
|
||||
if len(l:servers) == 0
|
||||
call s:not_supported('Retrieving workspace symbols')
|
||||
return
|
||||
endif
|
||||
|
||||
if !empty(a:query)
|
||||
let l:query = a:query
|
||||
else
|
||||
let l:query = inputdialog('query>', '', "\<ESC>")
|
||||
if l:query ==# "\<ESC>"
|
||||
return
|
||||
endif
|
||||
endif
|
||||
|
||||
for l:server in l:servers
|
||||
call lsp#send_request(l:server, {
|
||||
\ 'method': 'workspace/symbol',
|
||||
\ 'params': {
|
||||
\ 'query': l:query,
|
||||
\ },
|
||||
\ 'on_notification': function('s:handle_symbol', [l:server, l:command_id, 'workspaceSymbol']),
|
||||
\ })
|
||||
endfor
|
||||
|
||||
redraw
|
||||
echo 'Retrieving workspace symbols ...'
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#document_symbol() abort
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_document_symbol_provider(v:val)')
|
||||
let l:command_id = lsp#_new_command()
|
||||
|
||||
if len(l:servers) == 0
|
||||
call s:not_supported('Retrieving symbols')
|
||||
return
|
||||
endif
|
||||
|
||||
for l:server in l:servers
|
||||
call lsp#send_request(l:server, {
|
||||
\ 'method': 'textDocument/documentSymbol',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ },
|
||||
\ 'on_notification': function('s:handle_symbol', [l:server, l:command_id, 'documentSymbol']),
|
||||
\ })
|
||||
endfor
|
||||
|
||||
echo 'Retrieving document symbols ...'
|
||||
endfunction
|
||||
|
||||
function! s:handle_symbol(server, last_command_id, type, data) abort
|
||||
if a:last_command_id != lsp#_last_command()
|
||||
return
|
||||
endif
|
||||
|
||||
if lsp#client#is_error(a:data['response'])
|
||||
call lsp#utils#error('Failed to retrieve '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
return
|
||||
endif
|
||||
|
||||
let l:list = lsp#ui#vim#utils#symbols_to_loc_list(a:server, a:data)
|
||||
|
||||
if has('patch-8.2.2147')
|
||||
call setqflist(l:list)
|
||||
call setqflist([], 'a', {'title': a:type})
|
||||
else
|
||||
call setqflist([])
|
||||
call setqflist(l:list)
|
||||
endif
|
||||
|
||||
if empty(l:list)
|
||||
call lsp#utils#error('No ' . a:type .' found')
|
||||
else
|
||||
echo 'Retrieved ' . a:type
|
||||
botright copen
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:handle_location(ctx, server, type, data) abort "ctx = {counter, list, last_command_id, jump_if_one, mods, in_preview}
|
||||
if a:ctx['last_command_id'] != lsp#_last_command()
|
||||
return
|
||||
endif
|
||||
|
||||
let a:ctx['counter'] = a:ctx['counter'] - 1
|
||||
|
||||
if lsp#client#is_error(a:data['response']) || !has_key(a:data['response'], 'result')
|
||||
call lsp#utils#error('Failed to retrieve '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
else
|
||||
let a:ctx['list'] = a:ctx['list'] + lsp#utils#location#_lsp_to_vim_list(a:data['response']['result'])
|
||||
endif
|
||||
|
||||
if a:ctx['counter'] == 0
|
||||
if empty(a:ctx['list'])
|
||||
call lsp#utils#error('No ' . a:type .' found')
|
||||
else
|
||||
call lsp#utils#tagstack#_update()
|
||||
|
||||
let l:loc = a:ctx['list'][0]
|
||||
|
||||
if len(a:ctx['list']) == 1 && a:ctx['jump_if_one'] && !a:ctx['in_preview']
|
||||
call lsp#utils#location#_open_vim_list_item(l:loc, a:ctx['mods'])
|
||||
echo 'Retrieved ' . a:type
|
||||
redraw
|
||||
elseif !a:ctx['in_preview']
|
||||
call setqflist([])
|
||||
call setqflist(a:ctx['list'])
|
||||
echo 'Retrieved ' . a:type
|
||||
botright copen
|
||||
else
|
||||
let l:lines = readfile(l:loc['filename'])
|
||||
if has_key(l:loc,'viewstart') " showing a locationLink
|
||||
let l:view = l:lines[l:loc['viewstart'] : l:loc['viewend']]
|
||||
call lsp#ui#vim#output#preview(a:server, l:view, {
|
||||
\ 'statusline': ' LSP Peek ' . a:type,
|
||||
\ 'filetype': &filetype
|
||||
\ })
|
||||
else " showing a location
|
||||
call lsp#ui#vim#output#preview(a:server, l:lines, {
|
||||
\ 'statusline': ' LSP Peek ' . a:type,
|
||||
\ 'cursor': { 'line': l:loc['lnum'], 'col': l:loc['col'], 'align': g:lsp_peek_alignment },
|
||||
\ 'filetype': &filetype
|
||||
\ })
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:handle_rename_prepare(server, last_command_id, type, cword, position, data) abort
|
||||
if a:last_command_id != lsp#_last_command()
|
||||
return
|
||||
endif
|
||||
|
||||
if lsp#client#is_error(a:data['response'])
|
||||
call lsp#utils#error('Failed to retrieve '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
return
|
||||
endif
|
||||
let l:result = a:data['response']['result']
|
||||
|
||||
" Check response: null.
|
||||
if empty(l:result)
|
||||
echo 'The ' . a:server . ' returns for ' . a:type . ' (The rename request may be invalid at the given position).'
|
||||
return
|
||||
endif
|
||||
|
||||
" Check response: { defaultBehavior: boolean }.
|
||||
if has_key(l:result, 'defaultBehavior')
|
||||
call timer_start(1, {x->s:rename(a:server, input('new name: ', a:cword), a:position)})
|
||||
return
|
||||
endif
|
||||
|
||||
" Check response: { placeholder: string }
|
||||
if has_key(l:result, 'placeholder') && !empty(l:result['placeholder'])
|
||||
call timer_start(1, {x->s:rename(a:server, input('new name: ', a:cword), a:position)})
|
||||
return
|
||||
endif
|
||||
|
||||
" Check response: { range: Range } | Range
|
||||
let l:range = get(l:result, 'range', l:result)
|
||||
let l:lines = getline(1, '$')
|
||||
let [l:start_line, l:start_col] = lsp#utils#position#lsp_to_vim('%', l:range['start'])
|
||||
let [l:end_line, l:end_col] = lsp#utils#position#lsp_to_vim('%', l:range['end'])
|
||||
if l:start_line ==# l:end_line
|
||||
let l:name = l:lines[l:start_line - 1][l:start_col - 1 : l:end_col - 2]
|
||||
else
|
||||
let l:name = l:lines[l:start_line - 1][l:start_col - 1 :]
|
||||
for l:i in range(l:start_line, l:end_line - 2)
|
||||
let l:name .= "\n" . l:lines[l:i]
|
||||
endfor
|
||||
if l:end_col - 2 < 0
|
||||
let l:name .= "\n"
|
||||
else
|
||||
let l:name .= l:lines[l:end_line - 1][: l:end_col - 2]
|
||||
endif
|
||||
endif
|
||||
|
||||
call timer_start(1, {x->s:rename(a:server, input('new name: ', l:name), l:range['start'])})
|
||||
endfunction
|
||||
|
||||
function! s:handle_workspace_edit(server, last_command_id, type, data) abort
|
||||
if a:last_command_id != lsp#_last_command()
|
||||
return
|
||||
endif
|
||||
|
||||
if lsp#client#is_error(a:data['response'])
|
||||
call lsp#utils#error('Failed to retrieve '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
return
|
||||
endif
|
||||
|
||||
call lsp#utils#workspace_edit#apply_workspace_edit(a:data['response']['result'])
|
||||
|
||||
echo 'Renamed'
|
||||
endfunction
|
||||
|
||||
function! s:handle_text_edit(server, last_command_id, type, data) abort
|
||||
if a:last_command_id != lsp#_last_command()
|
||||
return
|
||||
endif
|
||||
|
||||
if lsp#client#is_error(a:data['response'])
|
||||
call lsp#utils#error('Failed to '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
return
|
||||
endif
|
||||
|
||||
call lsp#utils#text_edit#apply_text_edits(a:data['request']['params']['textDocument']['uri'], a:data['response']['result'])
|
||||
|
||||
redraw | echo 'Document formatted'
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#code_action(opts) abort
|
||||
call lsp#ui#vim#code_action#do(extend({
|
||||
\ 'sync': v:false,
|
||||
\ 'selection': v:false,
|
||||
\ 'query': '',
|
||||
\ }, a:opts))
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#code_lens() abort
|
||||
call lsp#ui#vim#code_lens#do({
|
||||
\ 'sync': v:false,
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#add_tree_call_hierarchy_incoming() abort
|
||||
let l:ctx = { 'add_tree': v:true }
|
||||
call lsp#ui#vim#call_hierarchy_incoming(l:ctx)
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#call_hierarchy_incoming(ctx) abort
|
||||
let l:ctx = extend({ 'method': 'incomingCalls', 'key': 'from' }, a:ctx)
|
||||
call s:prepare_call_hierarchy(l:ctx)
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#call_hierarchy_outgoing() abort
|
||||
let l:ctx = { 'method': 'outgoingCalls', 'key': 'to' }
|
||||
call s:prepare_call_hierarchy(l:ctx)
|
||||
endfunction
|
||||
|
||||
function! s:prepare_call_hierarchy(ctx) abort
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_call_hierarchy_provider(v:val)')
|
||||
let l:command_id = lsp#_new_command()
|
||||
|
||||
let l:ctx = extend({ 'counter': len(l:servers), 'list':[], 'last_command_id': l:command_id }, a:ctx)
|
||||
if len(l:servers) == 0
|
||||
call s:not_supported('Retrieving call hierarchy')
|
||||
return
|
||||
endif
|
||||
|
||||
for l:server in l:servers
|
||||
call lsp#send_request(l:server, {
|
||||
\ 'method': 'textDocument/prepareCallHierarchy',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'position': lsp#get_position(),
|
||||
\ },
|
||||
\ 'on_notification': function('s:handle_prepare_call_hierarchy', [l:ctx, l:server, 'prepare_call_hierarchy']),
|
||||
\ })
|
||||
endfor
|
||||
|
||||
echo 'Preparing call hierarchy ...'
|
||||
endfunction
|
||||
|
||||
function! s:handle_prepare_call_hierarchy(ctx, server, type, data) abort
|
||||
if a:ctx['last_command_id'] != lsp#_last_command()
|
||||
return
|
||||
endif
|
||||
|
||||
if lsp#client#is_error(a:data['response']) || !has_key(a:data['response'], 'result')
|
||||
call lsp#utils#error('Failed to '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
return
|
||||
endif
|
||||
if empty(a:data['response']['result'])
|
||||
call lsp#utils#warning('Failed to '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
return
|
||||
endif
|
||||
|
||||
for l:item in a:data['response']['result']
|
||||
call s:call_hierarchy(a:ctx, a:server, l:item)
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:call_hierarchy(ctx, server, item) abort
|
||||
call lsp#send_request(a:server, {
|
||||
\ 'method': 'callHierarchy/' . a:ctx['method'],
|
||||
\ 'params': {
|
||||
\ 'item': a:item,
|
||||
\ },
|
||||
\ 'on_notification': function('s:handle_call_hierarchy', [a:ctx, a:server, 'call_hierarchy']),
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
function! s:handle_call_hierarchy(ctx, server, type, data) abort
|
||||
if a:ctx['last_command_id'] != lsp#_last_command()
|
||||
return
|
||||
endif
|
||||
|
||||
let a:ctx['counter'] = a:ctx['counter'] - 1
|
||||
|
||||
if lsp#client#is_error(a:data['response']) || !has_key(a:data['response'], 'result')
|
||||
call lsp#utils#error('Failed to retrieve '. a:type . ' for ' . a:server . ': ' . lsp#client#error_message(a:data['response']))
|
||||
elseif a:data['response']['result'] isnot v:null
|
||||
for l:item in a:data['response']['result']
|
||||
let l:loc = s:hierarchy_item_to_vim(l:item[a:ctx['key']], a:server)
|
||||
if l:loc isnot v:null
|
||||
let a:ctx['list'] += [l:loc]
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
if a:ctx['counter'] == 0
|
||||
if empty(a:ctx['list'])
|
||||
call lsp#utils#error('No ' . a:type .' found')
|
||||
else
|
||||
call lsp#utils#tagstack#_update()
|
||||
if get(a:ctx, 'add_tree', v:false)
|
||||
let l:qf = getqflist({'idx' : 0, 'items': []})
|
||||
let l:pos = l:qf.idx
|
||||
let l:parent = l:qf.items
|
||||
let l:level = count(l:parent[l:pos-1].text, g:lsp_tree_incoming_prefix)
|
||||
let a:ctx['list'] = extend(l:parent, map(a:ctx['list'], 'extend(v:val, {"text": repeat("' . g:lsp_tree_incoming_prefix . '", l:level+1) . v:val.text})'), l:pos)
|
||||
endif
|
||||
call setqflist([])
|
||||
call setqflist(a:ctx['list'])
|
||||
echo 'Retrieved ' . a:type
|
||||
botright copen
|
||||
if get(a:ctx, 'add_tree', v:false)
|
||||
" move the cursor to the newly added item
|
||||
execute l:pos + 1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:hierarchy_item_to_vim(item, server) abort
|
||||
let l:uri = a:item['uri']
|
||||
if !lsp#utils#is_file_uri(l:uri)
|
||||
return v:null
|
||||
endif
|
||||
|
||||
let l:path = lsp#utils#uri_to_path(l:uri)
|
||||
let [l:line, l:col] = lsp#utils#position#lsp_to_vim(l:path, a:item['range']['start'])
|
||||
let l:text = '[' . lsp#ui#vim#utils#_get_symbol_text_from_kind(a:server, a:item['kind']) . '] ' . a:item['name']
|
||||
if has_key(a:item, 'detail')
|
||||
let l:text .= ": " . a:item['detail']
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'filename': l:path,
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ }
|
||||
endfunction
|
||||
207
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/code_action.vim
Normal file
207
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/code_action.vim
Normal file
@@ -0,0 +1,207 @@
|
||||
" vint: -ProhibitUnusedVariable
|
||||
|
||||
function! lsp#ui#vim#code_action#complete(input, command, len) abort
|
||||
let l:server_names = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_code_action_provider(v:val)')
|
||||
let l:kinds = []
|
||||
for l:server_name in l:server_names
|
||||
let l:kinds += lsp#capabilities#get_code_action_kinds(l:server_name)
|
||||
endfor
|
||||
return filter(copy(l:kinds), { _, kind -> kind =~ '^' . a:input })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" @param option = {
|
||||
" selection: v:true | v:false = Provide by CommandLine like `:'<,'>LspCodeAction`
|
||||
" sync: v:true | v:false = Specify enable synchronous request. Example use case is `BufWritePre`
|
||||
" query: string = Specify code action kind query. If query provided and then filtered code action is only one, invoke code action immediately.
|
||||
" ui: 'float' | 'preview'
|
||||
" }
|
||||
"
|
||||
function! lsp#ui#vim#code_action#do(option) abort
|
||||
let l:selection = get(a:option, 'selection', v:false)
|
||||
let l:sync = get(a:option, 'sync', v:false)
|
||||
let l:query = get(a:option, 'query', '')
|
||||
let l:ui = get(a:option, 'ui', g:lsp_code_action_ui)
|
||||
if empty(l:ui)
|
||||
let l:ui = lsp#utils#_has_popup_menu() ? 'float' : 'preview'
|
||||
endif
|
||||
|
||||
let l:server_names = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_code_action_provider(v:val)')
|
||||
if len(l:server_names) == 0
|
||||
return lsp#utils#error('Code action not supported for ' . &filetype)
|
||||
endif
|
||||
|
||||
if l:selection
|
||||
let l:range = lsp#utils#range#_get_recent_visual_range()
|
||||
else
|
||||
let l:range = lsp#utils#range#_get_current_line_range()
|
||||
endif
|
||||
|
||||
let l:ctx = {
|
||||
\ 'count': len(l:server_names),
|
||||
\ 'results': [],
|
||||
\}
|
||||
let l:bufnr = bufnr('%')
|
||||
let l:command_id = lsp#_new_command()
|
||||
for l:server_name in l:server_names
|
||||
let l:diagnostic = lsp#internal#diagnostics#under_cursor#get_diagnostic({'server': l:server_name})
|
||||
call lsp#send_request(l:server_name, {
|
||||
\ 'method': 'textDocument/codeAction',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'range': empty(l:diagnostic) || l:selection ? l:range : l:diagnostic['range'],
|
||||
\ 'context': {
|
||||
\ 'diagnostics' : empty(l:diagnostic) ? [] : [l:diagnostic],
|
||||
\ 'only': ['', 'quickfix', 'refactor', 'refactor.extract', 'refactor.inline', 'refactor.rewrite', 'source', 'source.organizeImports'],
|
||||
\ },
|
||||
\ },
|
||||
\ 'sync': l:sync,
|
||||
\ 'on_notification': function('s:handle_code_action', [l:ui, l:ctx, l:server_name, l:command_id, l:sync, l:query, l:bufnr]),
|
||||
\ })
|
||||
endfor
|
||||
echo 'Retrieving code actions ...'
|
||||
endfunction
|
||||
|
||||
function! s:handle_code_action(ui, ctx, server_name, command_id, sync, query, bufnr, data) abort
|
||||
" Ignore old request.
|
||||
if a:command_id != lsp#_last_command()
|
||||
return
|
||||
endif
|
||||
|
||||
call add(a:ctx['results'], {
|
||||
\ 'server_name': a:server_name,
|
||||
\ 'data': a:data,
|
||||
\})
|
||||
let a:ctx['count'] -= 1
|
||||
if a:ctx['count'] ># 0
|
||||
return
|
||||
endif
|
||||
|
||||
let l:total_code_actions = []
|
||||
for l:result in a:ctx['results']
|
||||
let l:server_name = l:result['server_name']
|
||||
let l:data = l:result['data']
|
||||
" Check response error.
|
||||
if lsp#client#is_error(l:data['response'])
|
||||
call lsp#utils#error('Failed to CodeAction for ' . l:server_name . ': ' . lsp#client#error_message(l:data['response']))
|
||||
continue
|
||||
endif
|
||||
|
||||
" Check code actions.
|
||||
let l:code_actions = l:data['response']['result']
|
||||
|
||||
" Filter code actions.
|
||||
if !empty(a:query)
|
||||
let l:code_actions = filter(l:code_actions, { _, action -> get(action, 'kind', '') =~# '^' . a:query })
|
||||
endif
|
||||
if empty(l:code_actions)
|
||||
continue
|
||||
endif
|
||||
|
||||
for l:code_action in l:code_actions
|
||||
let l:item = {
|
||||
\ 'server_name': l:server_name,
|
||||
\ 'code_action': l:code_action,
|
||||
\ }
|
||||
if get(l:code_action, 'isPreferred', v:false)
|
||||
let l:total_code_actions = [l:item] + l:total_code_actions
|
||||
else
|
||||
call add(l:total_code_actions, l:item)
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
|
||||
if len(l:total_code_actions) == 0
|
||||
echo 'No code actions found'
|
||||
return
|
||||
endif
|
||||
call lsp#log('s:handle_code_action', l:total_code_actions)
|
||||
|
||||
if len(l:total_code_actions) == 1 && !empty(a:query)
|
||||
let l:action = l:total_code_actions[0]
|
||||
if s:handle_disabled_action(l:action) | return | endif
|
||||
" Clear 'Retrieving code actions ...' message
|
||||
echo ''
|
||||
call s:handle_one_code_action(l:action['server_name'], a:sync, a:bufnr, l:action['code_action'])
|
||||
return
|
||||
endif
|
||||
|
||||
" Prompt to choose code actions when empty query provided.
|
||||
let l:items = []
|
||||
for l:action in l:total_code_actions
|
||||
let l:title = printf('[%s] %s', l:action['server_name'], l:action['code_action']['title'])
|
||||
if has_key(l:action['code_action'], 'kind') && l:action['code_action']['kind'] !=# ''
|
||||
let l:title .= ' (' . l:action['code_action']['kind'] . ')'
|
||||
endif
|
||||
call add(l:items, { 'title': l:title, 'item': l:action })
|
||||
endfor
|
||||
|
||||
if lsp#utils#_has_popup_menu() && a:ui ==? 'float'
|
||||
call lsp#internal#ui#popupmenu#open({
|
||||
\ 'title': 'Code actions',
|
||||
\ 'items': mapnew(l:items, { idx, item -> item.title}),
|
||||
\ 'pos': 'topleft',
|
||||
\ 'line': 'cursor+1',
|
||||
\ 'col': 'cursor',
|
||||
\ 'callback': funcref('s:popup_accept_code_action', [a:sync, a:bufnr, l:items]),
|
||||
\ })
|
||||
else
|
||||
call lsp#internal#ui#quickpick#open({
|
||||
\ 'items': l:items,
|
||||
\ 'key': 'title',
|
||||
\ 'on_accept': funcref('s:quickpick_accept_code_action', [a:sync, a:bufnr]),
|
||||
\ })
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:popup_accept_code_action(sync, bufnr, items, id, selected, ...) abort
|
||||
if a:selected <= 0 | return | endif
|
||||
let l:item = a:items[a:selected - 1]['item']
|
||||
if s:handle_disabled_action(l:item) | return | endif
|
||||
call s:handle_one_code_action(l:item['server_name'], a:sync, a:bufnr, l:item['code_action'])
|
||||
execute('doautocmd <nomodeline> User lsp_float_closed')
|
||||
endfunction
|
||||
|
||||
function! s:quickpick_accept_code_action(sync, bufnr, data, ...) abort
|
||||
call lsp#internal#ui#quickpick#close()
|
||||
if empty(a:data['items']) | return | endif
|
||||
let l:selected = a:data['items'][0]['item']
|
||||
if s:handle_disabled_action(l:selected) | return | endif
|
||||
call s:handle_one_code_action(l:selected['server_name'], a:sync, a:bufnr, l:selected['code_action'])
|
||||
endfunction
|
||||
|
||||
function! s:handle_disabled_action(code_action) abort
|
||||
if has_key(a:code_action, 'disabled')
|
||||
echo 'This action is disabled: ' . a:code_action['disabled']['reason']
|
||||
return v:true
|
||||
endif
|
||||
return v:false
|
||||
endfunction
|
||||
|
||||
function! s:handle_one_code_action(server_name, sync, bufnr, command_or_code_action) abort
|
||||
" has WorkspaceEdit.
|
||||
if has_key(a:command_or_code_action, 'edit')
|
||||
call lsp#utils#workspace_edit#apply_workspace_edit(a:command_or_code_action['edit'])
|
||||
endif
|
||||
|
||||
" Command.
|
||||
if has_key(a:command_or_code_action, 'command') && type(a:command_or_code_action['command']) == type('')
|
||||
call lsp#ui#vim#execute_command#_execute({
|
||||
\ 'server_name': a:server_name,
|
||||
\ 'command_name': get(a:command_or_code_action, 'command', ''),
|
||||
\ 'command_args': get(a:command_or_code_action, 'arguments', v:null),
|
||||
\ 'sync': a:sync,
|
||||
\ 'bufnr': a:bufnr,
|
||||
\ })
|
||||
|
||||
" has Command.
|
||||
elseif has_key(a:command_or_code_action, 'command') && type(a:command_or_code_action['command']) == type({})
|
||||
call lsp#ui#vim#execute_command#_execute({
|
||||
\ 'server_name': a:server_name,
|
||||
\ 'command_name': get(a:command_or_code_action['command'], 'command', ''),
|
||||
\ 'command_args': get(a:command_or_code_action['command'], 'arguments', v:null),
|
||||
\ 'sync': a:sync,
|
||||
\ 'bufnr': a:bufnr,
|
||||
\ })
|
||||
endif
|
||||
endfunction
|
||||
137
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/code_lens.vim
Normal file
137
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/code_lens.vim
Normal file
@@ -0,0 +1,137 @@
|
||||
" https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens
|
||||
|
||||
" @param option = {
|
||||
" }
|
||||
"
|
||||
function! lsp#ui#vim#code_lens#do(option) abort
|
||||
let l:sync = get(a:option, 'sync', v:false)
|
||||
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_code_lens_provider(v:val)')
|
||||
if len(l:servers) == 0
|
||||
return lsp#utils#error('Code lens not supported for ' . &filetype)
|
||||
endif
|
||||
|
||||
redraw | echo 'Retrieving codelens ...'
|
||||
|
||||
let l:bufnr = bufnr('%')
|
||||
|
||||
call lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromList(l:servers),
|
||||
\ lsp#callbag#flatMap({server->
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#request(server, {
|
||||
\ 'method': 'textDocument/codeLens',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(l:bufnr),
|
||||
\ },
|
||||
\ }),
|
||||
\ lsp#callbag#map({x->x['response']['result']}),
|
||||
\ lsp#callbag#filter({codelenses->!empty(codelenses)}),
|
||||
\ lsp#callbag#flatMap({codelenses->
|
||||
\ lsp#callbag#pipe(
|
||||
\ lsp#callbag#fromList(codelenses),
|
||||
\ lsp#callbag#flatMap({codelens->
|
||||
\ has_key(codelens, 'command') ? lsp#callbag#of(codelens) : s:resolve_codelens(server, codelens)}),
|
||||
\ )
|
||||
\ }),
|
||||
\ lsp#callbag#map({codelens->{ 'server': server, 'codelens': codelens }}),
|
||||
\ )
|
||||
\ }),
|
||||
\ lsp#callbag#reduce({acc,curr->add(acc, curr)}, []),
|
||||
\ lsp#callbag#flatMap({x->s:chooseCodeLens(x, l:bufnr)}),
|
||||
\ lsp#callbag#tap({x-> lsp#ui#vim#execute_command#_execute({
|
||||
\ 'server_name': x['server'],
|
||||
\ 'command_name': get(x['codelens']['command'], 'command', ''),
|
||||
\ 'command_args': get(x['codelens']['command'], 'arguments', v:null),
|
||||
\ 'bufnr': l:bufnr,
|
||||
\ })}),
|
||||
\ lsp#callbag#takeUntil(lsp#callbag#pipe(
|
||||
\ lsp#stream(),
|
||||
\ lsp#callbag#filter({x->has_key(x, 'command')}),
|
||||
\ )),
|
||||
\ lsp#callbag#subscribe({
|
||||
\ 'error': {e->lsp#utils#error('Error running codelens ' . json_encode(e))},
|
||||
\ }),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! s:resolve_codelens(server, codelens) abort
|
||||
" TODO: return callbag#lsp#empty() if codelens resolve not supported by server
|
||||
return lsp#callbag#pipe(
|
||||
\ lsp#request(a:server, {
|
||||
\ 'method': 'codeLens/resolve',
|
||||
\ 'params': a:codelens
|
||||
\ }),
|
||||
\ lsp#callbag#map({x->x['response']['result']}),
|
||||
\ )
|
||||
endfunction
|
||||
|
||||
function! s:chooseCodeLens(items, bufnr) abort
|
||||
redraw | echo 'Select codelens:'
|
||||
if empty(a:items)
|
||||
return lsp#callbag#throwError('No codelens found')
|
||||
endif
|
||||
return lsp#callbag#create(function('s:quickpick_open', [a:items, a:bufnr]))
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#code_lens#_get_subtitle(item) abort
|
||||
" Since element of arguments property of Command interface is defined as any in LSP spec, it is
|
||||
" up to the language server implementation.
|
||||
" Currently this only impacts rust-analyzer. See #1118 for more details.
|
||||
|
||||
if !has_key(a:item['codelens']['command'], 'arguments')
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:arguments = a:item['codelens']['command']['arguments']
|
||||
for l:argument in l:arguments
|
||||
if type(l:argument) != type({}) || !has_key(l:argument, 'label')
|
||||
return ''
|
||||
endif
|
||||
endfor
|
||||
|
||||
return ': ' . join(map(copy(l:arguments), 'v:val["label"]'), ' > ')
|
||||
endfunction
|
||||
|
||||
function! s:quickpick_open(items, bufnr, next, error, complete) abort
|
||||
if empty(a:items)
|
||||
return lsp#callbag#empty()
|
||||
endif
|
||||
|
||||
let l:items = []
|
||||
for l:item in a:items
|
||||
let l:title = printf("[%s] %s%s\t| L%s:%s",
|
||||
\ l:item['server'],
|
||||
\ l:item['codelens']['command']['title'],
|
||||
\ lsp#ui#vim#code_lens#_get_subtitle(l:item),
|
||||
\ lsp#utils#position#lsp_line_to_vim(a:bufnr, l:item['codelens']['range']['start']),
|
||||
\ getbufline(a:bufnr, lsp#utils#position#lsp_line_to_vim(a:bufnr, l:item['codelens']['range']['start']))[0])
|
||||
call add(l:items, { 'title': l:title, 'item': l:item })
|
||||
endfor
|
||||
|
||||
call lsp#internal#ui#quickpick#open({
|
||||
\ 'items': l:items,
|
||||
\ 'key': 'title',
|
||||
\ 'on_accept': function('s:quickpick_accept', [a:next, a:error, a:complete]),
|
||||
\ 'on_cancel': function('s:quickpick_cancel', [a:next, a:error, a:complete]),
|
||||
\ })
|
||||
|
||||
return function('s:quickpick_dispose')
|
||||
endfunction
|
||||
|
||||
function! s:quickpick_dispose() abort
|
||||
call lsp#internal#ui#quickpick#close()
|
||||
endfunction
|
||||
|
||||
function! s:quickpick_accept(next, error, complete, data, ...) abort
|
||||
call lsp#internal#ui#quickpick#close()
|
||||
let l:items = a:data['items']
|
||||
if len(l:items) > 0
|
||||
call a:next(l:items[0]['item'])
|
||||
endif
|
||||
call a:complete()
|
||||
endfunction
|
||||
|
||||
function! s:quickpick_cancel(next, error, complete, ...) abort
|
||||
call a:complete()
|
||||
endfunction
|
||||
303
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/completion.vim
Normal file
303
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/completion.vim
Normal file
@@ -0,0 +1,303 @@
|
||||
" vint: -ProhibitUnusedVariable
|
||||
"
|
||||
let s:context = {}
|
||||
|
||||
function! lsp#ui#vim#completion#_setup() abort
|
||||
augroup lsp_ui_vim_completion
|
||||
autocmd!
|
||||
autocmd CompleteDone * call s:on_complete_done()
|
||||
augroup END
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#completion#_disable() abort
|
||||
augroup lsp_ui_vim_completion
|
||||
autocmd!
|
||||
augroup END
|
||||
endfunction
|
||||
|
||||
"
|
||||
" After CompleteDone, v:complete_item's word has been inserted into the line.
|
||||
" Yet not inserted commit characters.
|
||||
"
|
||||
" below example uses | as cursor position.
|
||||
"
|
||||
" 1. `call getbuf|`<C-x><C-o>
|
||||
" 2. select `getbufline` item.
|
||||
" 3. Insert commit characters. e.g. `(`
|
||||
" 4. fire CompleteDone, then the line is `call getbufline|`
|
||||
" 5. call feedkeys to call `s:on_complete_done_after`
|
||||
" 6. then the line is `call getbufline(|` in `s:on_complete_done_after`
|
||||
"
|
||||
function! s:on_complete_done() abort
|
||||
" Sometimes, vim occurs `CompleteDone` unexpectedly.
|
||||
" We try to detect it by checking empty completed_item.
|
||||
if empty(v:completed_item) || get(v:completed_item, 'word', '') ==# '' && get(v:completed_item, 'abbr', '') ==# ''
|
||||
doautocmd <nomodeline> User lsp_complete_done
|
||||
return
|
||||
endif
|
||||
|
||||
" Try to get managed user_data.
|
||||
let l:managed_user_data = lsp#omni#get_managed_user_data_from_completed_item(v:completed_item)
|
||||
|
||||
" Clear managed user_data.
|
||||
call lsp#omni#_clear_managed_user_data_map()
|
||||
|
||||
" If managed user_data does not exists, skip it.
|
||||
if empty(l:managed_user_data)
|
||||
doautocmd <nomodeline> User lsp_complete_done
|
||||
return
|
||||
endif
|
||||
|
||||
let s:context['done_line'] = getline('.')
|
||||
let s:context['done_line_nr'] = line('.')
|
||||
let s:context['completed_item'] = copy(v:completed_item)
|
||||
let s:context['done_position'] = lsp#utils#position#vim_to_lsp('%', getpos('.')[1 : 2])
|
||||
let s:context['complete_position'] = l:managed_user_data['complete_position']
|
||||
let s:context['server_name'] = l:managed_user_data['server_name']
|
||||
let s:context['completion_item'] = l:managed_user_data['completion_item']
|
||||
let s:context['start_character'] = l:managed_user_data['start_character']
|
||||
call feedkeys(printf("\<C-r>=<SNR>%d_on_complete_done_after()\<CR>", s:SID()), 'n')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" Apply textEdit or insertText(snippet) and additionalTextEdits.
|
||||
"
|
||||
function! s:on_complete_done_after() abort
|
||||
" Clear message line. feedkeys above leave garbage on message line.
|
||||
echo ''
|
||||
|
||||
" Ignore process if the mode() is not insert-mode after feedkeys.
|
||||
if mode(1)[0] !=# 'i'
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:done_line = s:context['done_line']
|
||||
let l:done_line_nr = s:context['done_line_nr']
|
||||
let l:completed_item = s:context['completed_item']
|
||||
let l:done_position = s:context['done_position']
|
||||
let l:complete_position = s:context['complete_position']
|
||||
let l:server_name = s:context['server_name']
|
||||
let l:completion_item = s:context['completion_item']
|
||||
let l:start_character = s:context['start_character']
|
||||
|
||||
" check the commit characters are <BS> or <C-w>.
|
||||
if line('.') ==# l:done_line_nr && strlen(getline('.')) < strlen(l:done_line)
|
||||
doautocmd <nomodeline> User lsp_complete_done
|
||||
return ''
|
||||
endif
|
||||
|
||||
" Do nothing if text_edit is disabled.
|
||||
if !g:lsp_text_edit_enabled
|
||||
doautocmd <nomodeline> User lsp_complete_done
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:completion_item = s:resolve_completion_item(l:completion_item, l:server_name)
|
||||
|
||||
" clear completed string if need.
|
||||
let l:is_expandable = s:is_expandable(l:done_line, l:done_position, l:complete_position, l:completion_item, l:completed_item)
|
||||
if l:is_expandable
|
||||
call s:clear_auto_inserted_text(l:done_line, l:done_position, l:complete_position)
|
||||
endif
|
||||
|
||||
" apply additionalTextEdits.
|
||||
if has_key(l:completion_item, 'additionalTextEdits') && !empty(l:completion_item['additionalTextEdits'])
|
||||
call lsp#utils#text_edit#apply_text_edits(lsp#utils#get_buffer_uri(bufnr('%')), l:completion_item['additionalTextEdits'])
|
||||
endif
|
||||
|
||||
" snippet or textEdit.
|
||||
if l:is_expandable
|
||||
" At this timing, the cursor may have been moved by additionalTextEdit, so we use overflow information instead of textEdit itself.
|
||||
if type(get(l:completion_item, 'textEdit', v:null)) == type({})
|
||||
let l:range = lsp#utils#text_edit#get_range(l:completion_item['textEdit'])
|
||||
let l:overflow_before = max([0, l:start_character - l:range['start']['character']])
|
||||
let l:overflow_after = max([0, l:range['end']['character'] - l:complete_position['character']])
|
||||
let l:text = l:completion_item['textEdit']['newText']
|
||||
else
|
||||
let l:overflow_before = 0
|
||||
let l:overflow_after = 0
|
||||
let l:text = s:get_completion_text(l:completion_item)
|
||||
endif
|
||||
|
||||
" apply snipept or text_edit
|
||||
let l:position = lsp#utils#position#vim_to_lsp('%', getpos('.')[1 : 2])
|
||||
let l:range = {
|
||||
\ 'start': {
|
||||
\ 'line': l:position['line'],
|
||||
\ 'character': l:position['character'] - (l:complete_position['character'] - l:start_character) - l:overflow_before,
|
||||
\ },
|
||||
\ 'end': {
|
||||
\ 'line': l:position['line'],
|
||||
\ 'character': l:position['character'] + l:overflow_after,
|
||||
\ }
|
||||
\ }
|
||||
|
||||
if get(l:completion_item, 'insertTextFormat', 1) == 2
|
||||
" insert Snippet.
|
||||
call lsp#utils#text_edit#apply_text_edits('%', [{ 'range': l:range, 'newText': '' }])
|
||||
call cursor(lsp#utils#position#lsp_to_vim('%', l:range['start']))
|
||||
if exists('g:lsp_snippet_expand') && len(g:lsp_snippet_expand) > 0
|
||||
call g:lsp_snippet_expand[0]({ 'snippet': l:text })
|
||||
else
|
||||
call s:simple_expand_text(l:text)
|
||||
endif
|
||||
else
|
||||
" apply TextEdit.
|
||||
call lsp#utils#text_edit#apply_text_edits('%', [{ 'range': l:range, 'newText': l:text }])
|
||||
|
||||
" The VSCode always apply completion word as snippet.
|
||||
" It means we should place cursor to end of new inserted text as snippet does.
|
||||
let l:lines = lsp#utils#_split_by_eol(l:text)
|
||||
let l:start = l:range.start
|
||||
let l:start.line += len(l:lines) - 1
|
||||
let l:start.character += strchars(l:lines[-1])
|
||||
call cursor(lsp#utils#position#lsp_to_vim('%', l:start))
|
||||
endif
|
||||
endif
|
||||
|
||||
doautocmd <nomodeline> User lsp_complete_done
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
"
|
||||
" is_expandable
|
||||
"
|
||||
function! s:is_expandable(done_line, done_position, complete_position, completion_item, completed_item) abort
|
||||
if get(a:completion_item, 'textEdit', v:null) isnot# v:null
|
||||
let l:range = lsp#utils#text_edit#get_range(a:completion_item['textEdit'])
|
||||
if l:range['start']['line'] != l:range['end']['line']
|
||||
return v:true
|
||||
endif
|
||||
|
||||
" compute if textEdit will change text.
|
||||
let l:completed_before = strcharpart(a:done_line, 0, a:complete_position['character'])
|
||||
let l:completed_after = strcharpart(a:done_line, a:done_position['character'], strchars(a:done_line) - a:done_position['character'])
|
||||
let l:completed_line = l:completed_before . l:completed_after
|
||||
let l:text_edit_before = strcharpart(l:completed_line, 0, l:range['start']['character'])
|
||||
let l:text_edit_after = strcharpart(l:completed_line, l:range['end']['character'], strchars(l:completed_line) - l:range['end']['character'])
|
||||
return a:done_line !=# l:text_edit_before . s:trim_unmeaning_tabstop(a:completion_item['textEdit']['newText']) . l:text_edit_after
|
||||
endif
|
||||
return s:get_completion_text(a:completion_item) !=# s:trim_unmeaning_tabstop(a:completed_item['word'])
|
||||
endfunction
|
||||
|
||||
"
|
||||
" trim_unmeaning_tabstop
|
||||
"
|
||||
function! s:trim_unmeaning_tabstop(text) abort
|
||||
return substitute(a:text, '\%(\$0\|\${0}\)$', '', 'g')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" Try `completionItem/resolve` if it possible.
|
||||
"
|
||||
function! s:resolve_completion_item(completion_item, server_name) abort
|
||||
" server_name is not provided.
|
||||
if empty(a:server_name)
|
||||
return a:completion_item
|
||||
endif
|
||||
|
||||
" check server capabilities.
|
||||
let l:capabilities = lsp#get_server_capabilities(a:server_name)
|
||||
if !has_key(l:capabilities, 'completionProvider')
|
||||
\ || type(l:capabilities['completionProvider']) != v:t_dict
|
||||
\ || !has_key(l:capabilities['completionProvider'], 'resolveProvider')
|
||||
\ || !l:capabilities['completionProvider']['resolveProvider']
|
||||
return a:completion_item
|
||||
endif
|
||||
|
||||
let l:ctx = {}
|
||||
let l:ctx['response'] = {}
|
||||
function! l:ctx['callback'](data) abort
|
||||
let l:self['response'] = a:data['response']
|
||||
endfunction
|
||||
|
||||
try
|
||||
call lsp#send_request(a:server_name, {
|
||||
\ 'method': 'completionItem/resolve',
|
||||
\ 'params': a:completion_item,
|
||||
\ 'sync': 1,
|
||||
\ 'sync_timeout': g:lsp_completion_resolve_timeout,
|
||||
\ 'on_notification': function(l:ctx['callback'], [], l:ctx)
|
||||
\ })
|
||||
catch /.*/
|
||||
call lsp#log('s:resolve_completion_item', 'request timeout.')
|
||||
endtry
|
||||
|
||||
if empty(l:ctx['response'])
|
||||
return a:completion_item
|
||||
endif
|
||||
|
||||
if lsp#client#is_error(l:ctx['response'])
|
||||
return a:completion_item
|
||||
endif
|
||||
|
||||
if empty(l:ctx['response']['result'])
|
||||
return a:completion_item
|
||||
endif
|
||||
|
||||
return l:ctx['response']['result']
|
||||
endfunction
|
||||
|
||||
"
|
||||
" Remove additional inserted text
|
||||
"
|
||||
" LSP server knows only `complete_position` so we should remove inserted text until complete_position.
|
||||
"
|
||||
function! s:clear_auto_inserted_text(done_line, done_position, complete_position) abort
|
||||
let l:before = strcharpart(a:done_line, 0, a:complete_position['character'])
|
||||
let l:after = strcharpart(a:done_line, a:done_position['character'], (strchars(a:done_line) - a:done_position['character']))
|
||||
call setline('.', l:before . l:after)
|
||||
call cursor([a:done_position['line'] + 1, strlen(l:before) + 1])
|
||||
endfunction
|
||||
|
||||
"
|
||||
" Expand text
|
||||
"
|
||||
function! s:simple_expand_text(text) abort
|
||||
let l:pos = {
|
||||
\ 'line': line('.') - 1,
|
||||
\ 'character': lsp#utils#to_char('%', line('.'), col('.'))
|
||||
\ }
|
||||
|
||||
" Remove placeholders and get first placeholder position that use to cursor position.
|
||||
" e.g. `|getbufline(${1:expr}, ${2:lnum})${0}` to getbufline(|,)
|
||||
let l:text = substitute(a:text, '\$\%({[0-9]\+\%(:\(\\.\|[^}]\+\)*\)}\|[0-9]\+\)', '\=substitute(submatch(1), "\\", "", "g")', 'g')
|
||||
let l:offset = match(a:text, '\$\%({[0-9]\+\%(:\(\\.\|[^}]\+\)*\)}\|[0-9]\+\)')
|
||||
if l:offset == -1
|
||||
let l:offset = strchars(l:text)
|
||||
endif
|
||||
|
||||
call lsp#utils#text_edit#apply_text_edits(lsp#utils#get_buffer_uri(bufnr('%')), [{
|
||||
\ 'range': {
|
||||
\ 'start': l:pos,
|
||||
\ 'end': l:pos
|
||||
\ },
|
||||
\ 'newText': l:text
|
||||
\ }])
|
||||
|
||||
let l:pos = lsp#utils#position#lsp_to_vim('%', {
|
||||
\ 'line': l:pos['line'],
|
||||
\ 'character': l:pos['character'] + l:offset
|
||||
\ })
|
||||
call cursor(l:pos)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" Get completion text from CompletionItem. Fallback to label when insertText
|
||||
" is falsy
|
||||
"
|
||||
function! s:get_completion_text(completion_item) abort
|
||||
let l:text = get(a:completion_item, 'insertText', '')
|
||||
if empty(l:text)
|
||||
let l:text = a:completion_item['label']
|
||||
endif
|
||||
return l:text
|
||||
endfunction
|
||||
|
||||
"
|
||||
" Get script id that uses to call `s:` function in feedkeys.
|
||||
"
|
||||
function! s:SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')
|
||||
endfunction
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
let s:commands = {}
|
||||
|
||||
"
|
||||
" @param {name} = string
|
||||
" @param {callback} = funcref
|
||||
"
|
||||
function! lsp#ui#vim#execute_command#_register(command_name, callback) abort
|
||||
if has_key(s:commands, a:command_name)
|
||||
throw printf('lsp#ui#vim#execute_command#_register_command: %s already registered.', a:command_name)
|
||||
endif
|
||||
|
||||
let s:commands[a:command_name] = a:callback
|
||||
endfunction
|
||||
|
||||
"
|
||||
" TODO: This method does not handle any return value.
|
||||
"
|
||||
function! lsp#ui#vim#execute_command#_execute(params) abort
|
||||
let l:command_name = a:params['command_name']
|
||||
let l:command_args = get(a:params, 'command_args', v:null)
|
||||
let l:server_name = get(a:params, 'server_name', '')
|
||||
let l:bufnr = get(a:params, 'bufnr', -1)
|
||||
let l:sync = get(a:params, 'sync', v:false)
|
||||
|
||||
" create command.
|
||||
let l:command = { 'command': l:command_name }
|
||||
if l:command_args isnot v:null
|
||||
let l:command['arguments'] = l:command_args
|
||||
endif
|
||||
|
||||
" execute command on local.
|
||||
if has_key(s:commands, l:command_name)
|
||||
try
|
||||
call s:commands[l:command_name]({
|
||||
\ 'bufnr': l:bufnr,
|
||||
\ 'server_name': l:server_name,
|
||||
\ 'command': l:command,
|
||||
\ })
|
||||
catch /.*/
|
||||
call lsp#utils#error(printf('Execute command failed: %s', string(a:params)))
|
||||
endtry
|
||||
return
|
||||
endif
|
||||
|
||||
" execute command on server.
|
||||
if !empty(l:server_name)
|
||||
call lsp#send_request(l:server_name, {
|
||||
\ 'method': 'workspace/executeCommand',
|
||||
\ 'params': l:command,
|
||||
\ 'sync': l:sync,
|
||||
\ 'on_notification': function('s:handle_execute_command', [l:server_name, l:command]),
|
||||
\ })
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" handle workspace/executeCommand response
|
||||
"
|
||||
function! s:handle_execute_command(server_name, command, data) abort
|
||||
if lsp#client#is_error(a:data['response'])
|
||||
call lsp#utils#error('Execute command failed on ' . a:server_name . ': ' . string(a:command) . ' -> ' . string(a:data))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
201
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/folding.vim
Normal file
201
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/folding.vim
Normal file
@@ -0,0 +1,201 @@
|
||||
let s:folding_ranges = {}
|
||||
let s:textprop_name = 'vim-lsp-folding-linenr'
|
||||
|
||||
function! s:find_servers() abort
|
||||
return filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_folding_range_provider(v:val)')
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#folding#fold(sync) abort
|
||||
let l:servers = s:find_servers()
|
||||
|
||||
if len(l:servers) == 0
|
||||
call lsp#utils#error('Folding not supported for ' . &filetype)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:server = l:servers[0]
|
||||
call lsp#ui#vim#folding#send_request(l:server, bufnr('%'), a:sync)
|
||||
endfunction
|
||||
|
||||
function! s:set_textprops(buf) abort
|
||||
" Use zero-width text properties to act as a sort of "mark" in the buffer.
|
||||
" This is used to remember the line numbers at the time the request was
|
||||
" sent. We will let Vim handle updating the line numbers when the user
|
||||
" inserts or deletes text.
|
||||
|
||||
" Skip if the buffer doesn't exist. This might happen when a buffer is
|
||||
" opened and quickly deleted.
|
||||
if !bufloaded(a:buf) | return | endif
|
||||
|
||||
" Create text property, if not already defined
|
||||
silent! call prop_type_add(s:textprop_name, {'bufnr': a:buf, 'priority': lsp#internal#textprop#priority('folding')})
|
||||
|
||||
let l:line_count = s:get_line_count_buf(a:buf)
|
||||
|
||||
" First, clear all markers from the previous run
|
||||
call prop_remove({'type': s:textprop_name, 'bufnr': a:buf}, 1, l:line_count)
|
||||
|
||||
" Add markers to each line
|
||||
let l:i = 1
|
||||
while l:i <= l:line_count
|
||||
call prop_add(l:i, 1, {'bufnr': a:buf, 'type': s:textprop_name, 'id': l:i})
|
||||
let l:i += 1
|
||||
endwhile
|
||||
endfunction
|
||||
|
||||
function! s:get_line_count_buf(buf) abort
|
||||
if !has('patch-8.1.1967')
|
||||
return line('$')
|
||||
endif
|
||||
let l:winids = win_findbuf(a:buf)
|
||||
return empty(l:winids) ? line('$') : line('$', l:winids[0])
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#folding#send_request(server_name, buf, sync) abort
|
||||
if !lsp#capabilities#has_folding_range_provider(a:server_name)
|
||||
return
|
||||
endif
|
||||
|
||||
if !g:lsp_fold_enabled
|
||||
call lsp#log('Skip sending fold request: folding was disabled explicitly')
|
||||
return
|
||||
endif
|
||||
|
||||
if has('textprop')
|
||||
call s:set_textprops(a:buf)
|
||||
endif
|
||||
|
||||
call lsp#send_request(a:server_name, {
|
||||
\ 'method': 'textDocument/foldingRange',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(a:buf)
|
||||
\ },
|
||||
\ 'on_notification': function('s:handle_fold_request', [a:server_name]),
|
||||
\ 'sync': a:sync,
|
||||
\ 'bufnr': a:buf
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
function! s:foldexpr(server, buf, linenr) abort
|
||||
let l:foldlevel = 0
|
||||
let l:prefix = ''
|
||||
|
||||
for l:folding_range in s:folding_ranges[a:server][a:buf]
|
||||
if type(l:folding_range) == type({}) &&
|
||||
\ has_key(l:folding_range, 'startLine') &&
|
||||
\ has_key(l:folding_range, 'endLine')
|
||||
let l:start = l:folding_range['startLine'] + 1
|
||||
let l:end = l:folding_range['endLine'] + 1
|
||||
|
||||
if (l:start <= a:linenr) && (a:linenr <= l:end)
|
||||
let l:foldlevel += 1
|
||||
endif
|
||||
|
||||
if l:start == a:linenr
|
||||
let l:prefix = '>'
|
||||
elseif l:end == a:linenr
|
||||
let l:prefix = '<'
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Only return marker if a fold starts/ends at this line.
|
||||
" Otherwise, return '='.
|
||||
return (l:prefix ==# '') ? '=' : (l:prefix . l:foldlevel)
|
||||
endfunction
|
||||
|
||||
" Searches for text property of the correct type on the given line.
|
||||
" Returns the original linenr on success, or -1 if no textprop of the correct
|
||||
" type is associated with this line.
|
||||
function! s:get_textprop_line(linenr) abort
|
||||
let l:props = filter(prop_list(a:linenr), {idx, prop -> prop['type'] ==# s:textprop_name})
|
||||
|
||||
if empty(l:props)
|
||||
return -1
|
||||
else
|
||||
return l:props[0]['id']
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#folding#foldexpr() abort
|
||||
let l:servers = s:find_servers()
|
||||
|
||||
if len(l:servers) == 0
|
||||
return
|
||||
endif
|
||||
|
||||
let l:server = l:servers[0]
|
||||
|
||||
if has('textprop')
|
||||
" Does the current line have a textprop with original line info?
|
||||
let l:textprop_line = s:get_textprop_line(v:lnum)
|
||||
|
||||
if l:textprop_line == -1
|
||||
" No information for current line available, so use indent for
|
||||
" previous line.
|
||||
return '='
|
||||
else
|
||||
" Info available, use foldexpr as it would be with original line
|
||||
" number
|
||||
return s:foldexpr(l:server, bufnr('%'), l:textprop_line)
|
||||
endif
|
||||
else
|
||||
return s:foldexpr(l:server, bufnr('%'), v:lnum)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#folding#foldtext() abort
|
||||
let l:num_lines = v:foldend - v:foldstart + 1
|
||||
let l:summary = getline(v:foldstart) . '...'
|
||||
|
||||
" Join all lines in the fold
|
||||
let l:combined_lines = ''
|
||||
let l:i = v:foldstart
|
||||
while l:i <= v:foldend
|
||||
let l:combined_lines .= getline(l:i) . ' '
|
||||
let l:i += 1
|
||||
endwhile
|
||||
|
||||
" Check if we're in a comment
|
||||
let l:comment_regex = '\V' . substitute(&l:commentstring, '%s', '\\.\\*', '')
|
||||
if l:combined_lines =~? l:comment_regex
|
||||
let l:summary = l:combined_lines
|
||||
endif
|
||||
|
||||
return l:summary . ' (' . l:num_lines . ' ' . (l:num_lines == 1 ? 'line' : 'lines') . ') '
|
||||
endfunction
|
||||
|
||||
function! s:handle_fold_request(server, data) abort
|
||||
if lsp#client#is_error(a:data) || !has_key(a:data, 'response') || !has_key(a:data['response'], 'result')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:result = a:data['response']['result']
|
||||
|
||||
if type(l:result) != type([])
|
||||
return
|
||||
endif
|
||||
|
||||
let l:uri = a:data['request']['params']['textDocument']['uri']
|
||||
let l:path = lsp#utils#uri_to_path(l:uri)
|
||||
let l:bufnr = bufnr(l:path)
|
||||
|
||||
if l:bufnr < 0
|
||||
return
|
||||
endif
|
||||
|
||||
if !has_key(s:folding_ranges, a:server)
|
||||
let s:folding_ranges[a:server] = {}
|
||||
endif
|
||||
let s:folding_ranges[a:server][l:bufnr] = l:result
|
||||
|
||||
" Set 'foldmethod' back to 'expr', which forces a re-evaluation of
|
||||
" 'foldexpr'. Only do this if the user hasn't changed 'foldmethod',
|
||||
" and this is the correct buffer.
|
||||
for l:winid in win_findbuf(l:bufnr)
|
||||
if getwinvar(l:winid, '&foldmethod') ==# 'expr'
|
||||
call setwinvar(l:winid, '&foldmethod', 'expr')
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
450
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/output.vim
Normal file
450
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/output.vim
Normal file
@@ -0,0 +1,450 @@
|
||||
let s:use_vim_popup = has('patch-8.1.1517') && g:lsp_preview_float && !has('nvim')
|
||||
let s:use_nvim_float = exists('*nvim_open_win') && g:lsp_preview_float && has('nvim')
|
||||
let s:use_preview = !s:use_vim_popup && !s:use_nvim_float
|
||||
|
||||
function! s:import_modules() abort
|
||||
if exists('s:Markdown') | return | endif
|
||||
let s:Markdown = vital#lsp#import('VS.Vim.Syntax.Markdown')
|
||||
let s:MarkupContent = vital#lsp#import('VS.LSP.MarkupContent')
|
||||
let s:Window = vital#lsp#import('VS.Vim.Window')
|
||||
let s:Text = vital#lsp#import('VS.LSP.Text')
|
||||
endfunction
|
||||
|
||||
let s:winid = v:false
|
||||
let s:prevwin = v:false
|
||||
let s:preview_data = v:false
|
||||
|
||||
function! s:vim_popup_closed(...) abort
|
||||
let s:preview_data = v:false
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#closepreview() abort
|
||||
if win_getid() ==# s:winid
|
||||
" Don't close if window got focus
|
||||
return
|
||||
endif
|
||||
|
||||
if s:winid == v:false
|
||||
return
|
||||
endif
|
||||
|
||||
"closing floats in vim8.1 must use popup_close()
|
||||
"nvim must use nvim_win_close. pclose is not reliable and does not always work
|
||||
if s:use_vim_popup && s:winid
|
||||
call popup_close(s:winid)
|
||||
elseif s:use_nvim_float && s:winid
|
||||
silent! call nvim_win_close(s:winid, 0)
|
||||
else
|
||||
pclose
|
||||
endif
|
||||
let s:winid = v:false
|
||||
let s:preview_data = v:false
|
||||
augroup lsp_float_preview_close
|
||||
augroup end
|
||||
autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized *
|
||||
doautocmd <nomodeline> User lsp_float_closed
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#focuspreview() abort
|
||||
if s:is_cmdwin()
|
||||
return
|
||||
endif
|
||||
|
||||
" This does not work for vim8.1 popup but will work for nvim and old preview
|
||||
if s:winid
|
||||
if win_getid() !=# s:winid
|
||||
let s:prevwin = win_getid()
|
||||
call win_gotoid(s:winid)
|
||||
elseif s:prevwin
|
||||
" Temporarily disable hooks
|
||||
" TODO: remove this when closing logic is able to distinguish different move directions
|
||||
autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized *
|
||||
call win_gotoid(s:prevwin)
|
||||
call s:add_float_closing_hooks()
|
||||
let s:prevwin = v:false
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:bufwidth() abort
|
||||
let l:width = winwidth(0)
|
||||
let l:numberwidth = max([&numberwidth, strlen(line('$'))+1])
|
||||
let l:numwidth = (&number || &relativenumber)? l:numberwidth : 0
|
||||
let l:foldwidth = &foldcolumn
|
||||
|
||||
if &signcolumn ==? 'yes'
|
||||
let l:signwidth = 2
|
||||
elseif &signcolumn ==? 'auto'
|
||||
let l:signs = execute(printf('sign place buffer=%d', bufnr('')))
|
||||
let l:signs = split(l:signs, "\n")
|
||||
let l:signwidth = len(l:signs)>2? 2: 0
|
||||
else
|
||||
let l:signwidth = 0
|
||||
endif
|
||||
return l:width - l:numwidth - l:foldwidth - l:signwidth
|
||||
endfunction
|
||||
|
||||
|
||||
function! s:get_float_positioning(height, width) abort
|
||||
let l:height = a:height
|
||||
let l:width = a:width
|
||||
" TODO: add option to configure it 'docked' at the bottom/top/right
|
||||
|
||||
" NOTE: screencol() and screenrow() start from (1,1)
|
||||
" but the popup window co-ordinates start from (0,0)
|
||||
" Very convenient!
|
||||
" For a simple single-line 'tooltip', the following
|
||||
" two lines are enough to determine the position
|
||||
|
||||
let l:col = screencol()
|
||||
let l:row = screenrow()
|
||||
|
||||
let l:height = min([l:height, max([&lines - &cmdheight - l:row, &previewheight])])
|
||||
|
||||
let l:style = 'minimal'
|
||||
" Positioning is not window but screen relative
|
||||
let l:opts = {
|
||||
\ 'relative': 'editor',
|
||||
\ 'row': l:row,
|
||||
\ 'col': l:col,
|
||||
\ 'width': l:width,
|
||||
\ 'height': l:height,
|
||||
\ 'style': l:style,
|
||||
\ }
|
||||
return l:opts
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#floatingpreview(data) abort
|
||||
if s:use_nvim_float
|
||||
let l:buf = nvim_create_buf(v:false, v:true)
|
||||
|
||||
" Try to get as much space around the cursor, but at least 10x10
|
||||
let l:width = max([s:bufwidth(), 10])
|
||||
let l:height = max([&lines - winline() + 1, winline() - 1, 10])
|
||||
|
||||
if g:lsp_preview_max_height > 0
|
||||
let l:height = min([g:lsp_preview_max_height, l:height])
|
||||
endif
|
||||
|
||||
let l:opts = s:get_float_positioning(l:height, l:width)
|
||||
|
||||
let s:winid = nvim_open_win(l:buf, v:false, l:opts)
|
||||
call nvim_win_set_option(s:winid, 'winhl', 'Normal:Pmenu,NormalNC:Pmenu')
|
||||
call nvim_win_set_option(s:winid, 'foldenable', v:false)
|
||||
call nvim_win_set_option(s:winid, 'wrap', v:true)
|
||||
call nvim_win_set_option(s:winid, 'statusline', '')
|
||||
call nvim_win_set_option(s:winid, 'number', v:false)
|
||||
call nvim_win_set_option(s:winid, 'relativenumber', v:false)
|
||||
call nvim_win_set_option(s:winid, 'cursorline', v:false)
|
||||
call nvim_win_set_option(s:winid, 'cursorcolumn', v:false)
|
||||
call nvim_win_set_option(s:winid, 'colorcolumn', '')
|
||||
call nvim_win_set_option(s:winid, 'signcolumn', 'no')
|
||||
" Enable closing the preview with esc, but map only in the scratch buffer
|
||||
call nvim_buf_set_keymap(l:buf, 'n', '<esc>', ':pclose<cr>', {'silent': v:true})
|
||||
elseif s:use_vim_popup
|
||||
let l:options = {
|
||||
\ 'moved': 'any',
|
||||
\ 'border': [1, 1, 1, 1],
|
||||
\ 'callback': function('s:vim_popup_closed')
|
||||
\ }
|
||||
|
||||
if g:lsp_preview_max_width > 0
|
||||
let l:options['maxwidth'] = g:lsp_preview_max_width
|
||||
endif
|
||||
|
||||
if g:lsp_preview_max_height > 0
|
||||
let l:options['maxheight'] = g:lsp_preview_max_height
|
||||
endif
|
||||
|
||||
let s:winid = popup_atcursor('...', l:options)
|
||||
endif
|
||||
return s:winid
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#setcontent(winid, lines, ft) abort
|
||||
if s:use_vim_popup
|
||||
" vim popup
|
||||
call setbufline(winbufnr(a:winid), 1, a:lines)
|
||||
call setbufvar(winbufnr(a:winid), '&filetype', a:ft . '.lsp-hover')
|
||||
elseif s:use_nvim_float
|
||||
" nvim floating
|
||||
call nvim_buf_set_lines(winbufnr(a:winid), 0, -1, v:false, a:lines)
|
||||
call nvim_buf_set_option(winbufnr(a:winid), 'readonly', v:true)
|
||||
call nvim_buf_set_option(winbufnr(a:winid), 'modifiable', v:false)
|
||||
call nvim_buf_set_option(winbufnr(a:winid), 'filetype', a:ft.'.lsp-hover')
|
||||
call nvim_win_set_cursor(a:winid, [1, 0])
|
||||
elseif s:use_preview
|
||||
" preview window
|
||||
call setbufline(winbufnr(a:winid), 1, a:lines)
|
||||
call setbufvar(winbufnr(a:winid), '&filetype', a:ft . '.lsp-hover')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#adjust_float_placement(bufferlines, maxwidth) abort
|
||||
if s:use_nvim_float
|
||||
let l:win_config = {}
|
||||
let l:height = min([winheight(s:winid), a:bufferlines])
|
||||
let l:width = min([winwidth(s:winid), a:maxwidth])
|
||||
let l:win_config = s:get_float_positioning(l:height, l:width)
|
||||
call nvim_win_set_config(s:winid, l:win_config )
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:add_float_closing_hooks() abort
|
||||
if g:lsp_preview_autoclose
|
||||
augroup lsp_float_preview_close
|
||||
autocmd! lsp_float_preview_close CursorMoved,CursorMovedI,VimResized *
|
||||
autocmd CursorMoved,CursorMovedI,VimResized * call lsp#ui#vim#output#closepreview()
|
||||
augroup END
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#getpreviewwinid() abort
|
||||
return s:winid
|
||||
endfunction
|
||||
|
||||
function! s:open_preview(data) abort
|
||||
if s:use_vim_popup || s:use_nvim_float
|
||||
let l:winid = lsp#ui#vim#output#floatingpreview(a:data)
|
||||
else
|
||||
execute &previewheight.'new'
|
||||
let l:winid = win_getid()
|
||||
endif
|
||||
return l:winid
|
||||
endfunction
|
||||
|
||||
function! s:set_cursor(current_window_id, options) abort
|
||||
if !has_key(a:options, 'cursor')
|
||||
return
|
||||
endif
|
||||
|
||||
if s:use_nvim_float
|
||||
" Neovim floats
|
||||
" Go back to the preview window to set the cursor
|
||||
call win_gotoid(s:winid)
|
||||
let l:old_scrolloff = &scrolloff
|
||||
let &scrolloff = 0
|
||||
|
||||
call nvim_win_set_cursor(s:winid, [a:options['cursor']['line'], a:options['cursor']['col']])
|
||||
call s:align_preview(a:options)
|
||||
|
||||
" Finally, go back to the original window
|
||||
call win_gotoid(a:current_window_id)
|
||||
|
||||
let &scrolloff = l:old_scrolloff
|
||||
elseif s:use_vim_popup
|
||||
" Vim popups
|
||||
function! AlignVimPopup(timer) closure abort
|
||||
call s:align_preview(a:options)
|
||||
endfunction
|
||||
call timer_start(0, function('AlignVimPopup'))
|
||||
else
|
||||
" Preview
|
||||
" Don't use 'scrolloff', it might mess up the cursor's position
|
||||
let &l:scrolloff = 0
|
||||
call cursor(a:options['cursor']['line'], a:options['cursor']['col'])
|
||||
call s:align_preview(a:options)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:align_preview(options) abort
|
||||
if !has_key(a:options, 'cursor') ||
|
||||
\ !has_key(a:options['cursor'], 'align')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:align = a:options['cursor']['align']
|
||||
|
||||
if s:use_vim_popup
|
||||
" Vim popups
|
||||
let l:pos = popup_getpos(s:winid)
|
||||
let l:below = winline() < winheight(0) / 2
|
||||
if l:below
|
||||
let l:height = min([l:pos['core_height'], winheight(0) - winline() - 2])
|
||||
else
|
||||
let l:height = min([l:pos['core_height'], winline() - 3])
|
||||
endif
|
||||
let l:width = l:pos['core_width']
|
||||
|
||||
let l:options = {
|
||||
\ 'minwidth': l:width,
|
||||
\ 'maxwidth': l:width,
|
||||
\ 'minheight': l:height,
|
||||
\ 'maxheight': l:height,
|
||||
\ 'pos': l:below ? 'topleft' : 'botleft',
|
||||
\ 'line': l:below ? 'cursor+1' : 'cursor-1'
|
||||
\ }
|
||||
|
||||
if l:align ==? 'top'
|
||||
let l:options['firstline'] = a:options['cursor']['line']
|
||||
elseif l:align ==? 'center'
|
||||
let l:options['firstline'] = a:options['cursor']['line'] - (l:height - 1) / 2
|
||||
elseif l:align ==? 'bottom'
|
||||
let l:options['firstline'] = a:options['cursor']['line'] - l:height + 1
|
||||
endif
|
||||
|
||||
call popup_setoptions(s:winid, l:options)
|
||||
redraw!
|
||||
else
|
||||
" Preview and Neovim floats
|
||||
if l:align ==? 'top'
|
||||
normal! zt
|
||||
elseif l:align ==? 'center'
|
||||
normal! zz
|
||||
elseif l:align ==? 'bottom'
|
||||
normal! zb
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#get_size_info(winid) abort
|
||||
" Get size information while still having the buffer active
|
||||
let l:buffer = winbufnr(a:winid)
|
||||
let l:maxwidth = max(map(getbufline(l:buffer, 1, '$'), 'strdisplaywidth(v:val)'))
|
||||
let l:bufferlines = 0
|
||||
if g:lsp_preview_max_width > 0
|
||||
let l:maxwidth = min([g:lsp_preview_max_width, l:maxwidth])
|
||||
|
||||
" Determine, for each line, how many "virtual" lines it spans, and add
|
||||
" these together for all lines in the buffer
|
||||
for l:line in getbufline(l:buffer, 1, '$')
|
||||
let l:num_lines = str2nr(string(ceil(strdisplaywidth(l:line) * 1.0 / g:lsp_preview_max_width)))
|
||||
let l:bufferlines += max([l:num_lines, 1])
|
||||
endfor
|
||||
else
|
||||
if s:use_vim_popup
|
||||
let l:bufferlines = line('$', a:winid)
|
||||
elseif s:use_nvim_float
|
||||
let l:bufferlines = nvim_buf_line_count(winbufnr(a:winid))
|
||||
endif
|
||||
endif
|
||||
|
||||
return [l:bufferlines, l:maxwidth]
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#float_supported() abort
|
||||
return s:use_vim_popup || s:use_nvim_float
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#preview(server, data, options) abort
|
||||
if s:is_cmdwin()
|
||||
return
|
||||
endif
|
||||
|
||||
if s:winid && type(s:preview_data) ==# type(a:data)
|
||||
\ && s:preview_data ==# a:data
|
||||
\ && type(g:lsp_preview_doubletap) ==# 3
|
||||
\ && len(g:lsp_preview_doubletap) >= 1
|
||||
\ && type(g:lsp_preview_doubletap[0]) ==# 2
|
||||
\ && index(['i', 's'], mode()[0]) ==# -1
|
||||
echo ''
|
||||
return call(g:lsp_preview_doubletap[0], [])
|
||||
endif
|
||||
" Close any previously opened preview window
|
||||
call lsp#ui#vim#output#closepreview()
|
||||
|
||||
let l:current_window_id = win_getid()
|
||||
|
||||
let s:winid = s:open_preview(a:data)
|
||||
|
||||
let s:preview_data = a:data
|
||||
let l:lines = []
|
||||
let l:syntax_lines = []
|
||||
let l:ft = lsp#ui#vim#output#append(a:data, l:lines, l:syntax_lines)
|
||||
|
||||
if has_key(a:options, 'filetype')
|
||||
let l:ft = a:options['filetype']
|
||||
endif
|
||||
|
||||
let l:do_conceal = g:lsp_hover_conceal
|
||||
let l:server_info = a:server !=# '' ? lsp#get_server_info(a:server) : {}
|
||||
let l:config = get(l:server_info, 'config', {})
|
||||
let l:do_conceal = get(l:config, 'hover_conceal', l:do_conceal)
|
||||
|
||||
call setbufvar(winbufnr(s:winid), 'lsp_syntax_highlights', l:syntax_lines)
|
||||
call setbufvar(winbufnr(s:winid), 'lsp_do_conceal', l:do_conceal)
|
||||
call lsp#ui#vim#output#setcontent(s:winid, l:lines, l:ft)
|
||||
|
||||
let [l:bufferlines, l:maxwidth] = lsp#ui#vim#output#get_size_info(s:winid)
|
||||
|
||||
if s:use_preview
|
||||
" Set statusline
|
||||
if has_key(a:options, 'statusline')
|
||||
let &l:statusline = a:options['statusline']
|
||||
endif
|
||||
|
||||
call s:set_cursor(l:current_window_id, a:options)
|
||||
endif
|
||||
|
||||
" Go to the previous window to adjust positioning
|
||||
call win_gotoid(l:current_window_id)
|
||||
|
||||
echo ''
|
||||
|
||||
if s:winid && (s:use_vim_popup || s:use_nvim_float)
|
||||
if s:use_nvim_float
|
||||
" Neovim floats
|
||||
call lsp#ui#vim#output#adjust_float_placement(l:bufferlines, l:maxwidth)
|
||||
call s:set_cursor(l:current_window_id, a:options)
|
||||
call s:add_float_closing_hooks()
|
||||
elseif s:use_vim_popup
|
||||
" Vim popups
|
||||
call s:set_cursor(l:current_window_id, a:options)
|
||||
endif
|
||||
doautocmd <nomodeline> User lsp_float_opened
|
||||
endif
|
||||
|
||||
if l:ft ==? 'markdown'
|
||||
call s:import_modules()
|
||||
call s:Window.do(s:winid, {->s:Markdown.apply()})
|
||||
endif
|
||||
|
||||
if !g:lsp_preview_keep_focus
|
||||
" set the focus to the preview window
|
||||
call win_gotoid(s:winid)
|
||||
endif
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! s:escape_string_for_display(str) abort
|
||||
return substitute(substitute(a:str, '\r\n', '\n', 'g'), '\r', '\n', 'g')
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#output#append(data, lines, syntax_lines) abort
|
||||
if type(a:data) == type([])
|
||||
for l:entry in a:data
|
||||
call lsp#ui#vim#output#append(l:entry, a:lines, a:syntax_lines)
|
||||
endfor
|
||||
|
||||
return 'markdown'
|
||||
elseif type(a:data) ==# type('')
|
||||
call extend(a:lines, split(s:escape_string_for_display(a:data), "\n", v:true))
|
||||
return 'markdown'
|
||||
elseif type(a:data) ==# type({}) && has_key(a:data, 'language')
|
||||
let l:new_lines = split(s:escape_string_for_display(a:data.value), '\n')
|
||||
|
||||
let l:i = 1
|
||||
while l:i <= len(l:new_lines)
|
||||
call add(a:syntax_lines, { 'line': len(a:lines) + l:i, 'language': a:data.language })
|
||||
let l:i += 1
|
||||
endwhile
|
||||
|
||||
call extend(a:lines, l:new_lines)
|
||||
return 'markdown'
|
||||
elseif type(a:data) ==# type({}) && has_key(a:data, 'kind')
|
||||
if a:data.kind ==? 'markdown'
|
||||
call s:import_modules()
|
||||
let l:detail = s:MarkupContent.normalize(a:data.value, {
|
||||
\ 'compact': !g:lsp_preview_fixup_conceal
|
||||
\ })
|
||||
call extend(a:lines, s:Text.split_by_eol(l:detail))
|
||||
else
|
||||
call extend(a:lines, split(s:escape_string_for_display(a:data.value), '\n', v:true))
|
||||
endif
|
||||
return a:data.kind ==? 'plaintext' ? 'text' : a:data.kind
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:is_cmdwin() abort
|
||||
return getcmdwintype() !=# ''
|
||||
endfunction
|
||||
160
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/signature_help.vim
Normal file
160
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/signature_help.vim
Normal file
@@ -0,0 +1,160 @@
|
||||
" vint: -ProhibitUnusedVariable
|
||||
let s:debounce_timer_id = 0
|
||||
|
||||
function! s:not_supported(what) abort
|
||||
return lsp#utils#error(a:what.' not supported for '.&filetype)
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#signature_help#get_signature_help_under_cursor() abort
|
||||
let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_signature_help_provider(v:val)')
|
||||
|
||||
if len(l:servers) == 0
|
||||
call s:not_supported('Retrieving signature help')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:position = lsp#get_position()
|
||||
for l:server in l:servers
|
||||
call lsp#send_request(l:server, {
|
||||
\ 'method': 'textDocument/signatureHelp',
|
||||
\ 'params': {
|
||||
\ 'textDocument': lsp#get_text_document_identifier(),
|
||||
\ 'position': l:position,
|
||||
\ },
|
||||
\ 'on_notification': function('s:handle_signature_help', [l:server]),
|
||||
\ })
|
||||
endfor
|
||||
|
||||
call lsp#log('Retrieving signature help')
|
||||
return
|
||||
endfunction
|
||||
|
||||
function! s:handle_signature_help(server, data) abort
|
||||
if lsp#client#is_error(a:data['response'])
|
||||
call lsp#utils#error('Failed to retrieve signature help information for ' . a:server)
|
||||
return
|
||||
endif
|
||||
|
||||
if !has_key(a:data['response'], 'result')
|
||||
return
|
||||
endif
|
||||
|
||||
if !empty(a:data['response']['result']) && !empty(a:data['response']['result']['signatures'])
|
||||
" Get current signature.
|
||||
let l:signatures = get(a:data['response']['result'], 'signatures', [])
|
||||
let l:signature_index = get(a:data['response']['result'], 'activeSignature', 0)
|
||||
let l:signature = get(l:signatures, l:signature_index, {})
|
||||
if empty(l:signature)
|
||||
return
|
||||
endif
|
||||
|
||||
" Signature label.
|
||||
let l:label = l:signature['label']
|
||||
|
||||
" Mark current parameter.
|
||||
if has_key(a:data['response']['result'], 'activeParameter')
|
||||
let l:parameters = get(l:signature, 'parameters', [])
|
||||
let l:parameter_index = a:data['response']['result']['activeParameter']
|
||||
let l:parameter = get(l:parameters, l:parameter_index, {})
|
||||
let l:parameter_label = s:get_parameter_label(l:signature, l:parameter)
|
||||
if !empty(l:parameter_label)
|
||||
let l:label = substitute(l:label, '\V\(' . escape(l:parameter_label, '\/?') . '\)', '`\1`', 'g')
|
||||
endif
|
||||
endif
|
||||
|
||||
let l:contents = [l:label]
|
||||
|
||||
if exists('l:parameter')
|
||||
let l:parameter_doc = s:get_parameter_doc(l:parameter)
|
||||
if !empty(l:parameter_doc)
|
||||
call add(l:contents, '')
|
||||
call add(l:contents, l:parameter_doc)
|
||||
call add(l:contents, '')
|
||||
endif
|
||||
endif
|
||||
|
||||
if has_key(l:signature, 'documentation')
|
||||
call add(l:contents, l:signature['documentation'])
|
||||
endif
|
||||
|
||||
call lsp#ui#vim#output#preview(a:server, l:contents, {'statusline': ' LSP SignatureHelp'})
|
||||
return
|
||||
else
|
||||
" signature help is used while inserting. So this must be graceful.
|
||||
"call lsp#utils#error('No signature help information found')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:get_parameter_label(signature, parameter) abort
|
||||
if has_key(a:parameter, 'label')
|
||||
if type(a:parameter['label']) == type([])
|
||||
let l:string_range = a:parameter['label']
|
||||
return strcharpart(
|
||||
\ a:signature['label'],
|
||||
\ l:string_range[0],
|
||||
\ l:string_range[1] - l:string_range[0])
|
||||
endif
|
||||
return a:parameter['label']
|
||||
endif
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! s:get_parameter_doc(parameter) abort
|
||||
if !has_key(a:parameter, 'documentation')
|
||||
return ''
|
||||
endif
|
||||
|
||||
let l:doc = copy(a:parameter['documentation'])
|
||||
if type(l:doc) == type({})
|
||||
let l:doc['value'] = printf('***%s*** - %s', a:parameter['label'], l:doc['value'])
|
||||
return l:doc
|
||||
endif
|
||||
return printf('***%s*** - %s', a:parameter['label'], l:doc)
|
||||
endfunction
|
||||
|
||||
function! s:on_cursor_moved() abort
|
||||
let l:bufnr = bufnr('%')
|
||||
call timer_stop(s:debounce_timer_id)
|
||||
if g:lsp_signature_help_enabled
|
||||
let s:debounce_timer_id = timer_start(g:lsp_signature_help_delay, function('s:on_text_changed_after', [l:bufnr]), { 'repeat': 1 })
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_text_changed_after(bufnr, timer) abort
|
||||
if bufnr('%') != a:bufnr
|
||||
return
|
||||
endif
|
||||
if index(['i', 's'], mode()[0]) == -1
|
||||
return
|
||||
endif
|
||||
if win_id2win(lsp#ui#vim#output#getpreviewwinid()) >= 1
|
||||
return
|
||||
endif
|
||||
|
||||
" Cache trigger chars since this loop is heavy
|
||||
let l:chars = get(b:, 'lsp_signature_help_trigger_character', [])
|
||||
if empty(l:chars)
|
||||
for l:server_name in lsp#get_allowed_servers(a:bufnr)
|
||||
let l:chars += lsp#capabilities#get_signature_help_trigger_characters(l:server_name)
|
||||
endfor
|
||||
let b:lsp_signature_help_trigger_character = l:chars
|
||||
endif
|
||||
|
||||
if index(l:chars, lsp#utils#_get_before_char_skip_white()) >= 0
|
||||
call lsp#ui#vim#signature_help#get_signature_help_under_cursor()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#signature_help#setup() abort
|
||||
augroup _lsp_signature_help_
|
||||
autocmd!
|
||||
autocmd CursorMoved,CursorMovedI * call s:on_cursor_moved()
|
||||
augroup END
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#signature_help#_disable() abort
|
||||
augroup _lsp_signature_help_
|
||||
autocmd!
|
||||
augroup END
|
||||
endfunction
|
||||
|
||||
164
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/utils.vim
Normal file
164
dot_vim/plugged/vim-lsp/autoload/lsp/ui/vim/utils.vim
Normal file
@@ -0,0 +1,164 @@
|
||||
let s:default_symbol_kinds = {
|
||||
\ '1': 'file',
|
||||
\ '2': 'module',
|
||||
\ '3': 'namespace',
|
||||
\ '4': 'package',
|
||||
\ '5': 'class',
|
||||
\ '6': 'method',
|
||||
\ '7': 'property',
|
||||
\ '8': 'field',
|
||||
\ '9': 'constructor',
|
||||
\ '10': 'enum',
|
||||
\ '11': 'interface',
|
||||
\ '12': 'function',
|
||||
\ '13': 'variable',
|
||||
\ '14': 'constant',
|
||||
\ '15': 'string',
|
||||
\ '16': 'number',
|
||||
\ '17': 'boolean',
|
||||
\ '18': 'array',
|
||||
\ '19': 'object',
|
||||
\ '20': 'key',
|
||||
\ '21': 'null',
|
||||
\ '22': 'enum member',
|
||||
\ '23': 'struct',
|
||||
\ '24': 'event',
|
||||
\ '25': 'operator',
|
||||
\ '26': 'type parameter',
|
||||
\ }
|
||||
|
||||
let s:symbol_kinds = {}
|
||||
|
||||
let s:diagnostic_severity = {
|
||||
\ 1: 'Error',
|
||||
\ 2: 'Warning',
|
||||
\ 3: 'Information',
|
||||
\ 4: 'Hint',
|
||||
\ }
|
||||
|
||||
function! s:symbols_to_loc_list_children(server, path, list, symbols, depth) abort
|
||||
for l:symbol in a:symbols
|
||||
let [l:line, l:col] = lsp#utils#position#lsp_to_vim(a:path, l:symbol['range']['start'])
|
||||
|
||||
call add(a:list, {
|
||||
\ 'filename': a:path,
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:col,
|
||||
\ 'text': lsp#ui#vim#utils#_get_symbol_text_from_kind(a:server, l:symbol['kind']) . ' : ' . printf('%' . a:depth. 's', ' ') . l:symbol['name'],
|
||||
\ })
|
||||
if has_key(l:symbol, 'children') && !empty(l:symbol['children'])
|
||||
call s:symbols_to_loc_list_children(a:server, a:path, a:list, l:symbol['children'], a:depth + 1)
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#utils#symbols_to_loc_list(server, result) abort
|
||||
if !has_key(a:result['response'], 'result')
|
||||
return []
|
||||
endif
|
||||
|
||||
let l:list = []
|
||||
|
||||
let l:locations = type(a:result['response']['result']) == type({}) ? [a:result['response']['result']] : a:result['response']['result']
|
||||
|
||||
if !empty(l:locations) " some servers also return null so check to make sure it isn't empty
|
||||
for l:symbol in a:result['response']['result']
|
||||
if has_key(l:symbol, 'location')
|
||||
let l:location = l:symbol['location']
|
||||
if lsp#utils#is_file_uri(l:location['uri'])
|
||||
let l:path = lsp#utils#uri_to_path(l:location['uri'])
|
||||
let [l:line, l:col] = lsp#utils#position#lsp_to_vim(l:path, l:location['range']['start'])
|
||||
call add(l:list, {
|
||||
\ 'filename': l:path,
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:col,
|
||||
\ 'text': lsp#ui#vim#utils#_get_symbol_text_from_kind(a:server, l:symbol['kind']) . ' : ' . l:symbol['name'],
|
||||
\ })
|
||||
endif
|
||||
else
|
||||
let l:location = a:result['request']['params']['textDocument']['uri']
|
||||
if lsp#utils#is_file_uri(l:location)
|
||||
let l:path = lsp#utils#uri_to_path(l:location)
|
||||
let [l:line, l:col] = lsp#utils#position#lsp_to_vim(l:path, l:symbol['range']['start'])
|
||||
call add(l:list, {
|
||||
\ 'filename': l:path,
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:col,
|
||||
\ 'text': lsp#ui#vim#utils#_get_symbol_text_from_kind(a:server, l:symbol['kind']) . ' : ' . l:symbol['name'],
|
||||
\ })
|
||||
if has_key(l:symbol, 'children') && !empty(l:symbol['children'])
|
||||
call s:symbols_to_loc_list_children(a:server, l:path, l:list, l:symbol['children'], 1)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
return l:list
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#utils#diagnostics_to_loc_list(result) abort
|
||||
if !has_key(a:result['response'], 'params')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:uri = a:result['response']['params']['uri']
|
||||
let l:diagnostics = lsp#utils#iteratable(a:result['response']['params']['diagnostics'])
|
||||
|
||||
let l:list = []
|
||||
|
||||
if !empty(l:diagnostics) && lsp#utils#is_file_uri(l:uri)
|
||||
let l:path = lsp#utils#uri_to_path(l:uri)
|
||||
for l:item in l:diagnostics
|
||||
let l:severity_text = ''
|
||||
if has_key(l:item, 'severity') && !empty(l:item['severity'])
|
||||
let l:severity_text = s:get_diagnostic_severity_text(l:item['severity'])
|
||||
endif
|
||||
let l:text = ''
|
||||
if has_key(l:item, 'source') && !empty(l:item['source'])
|
||||
let l:text .= l:item['source'] . ':'
|
||||
endif
|
||||
if l:severity_text !=# ''
|
||||
let l:text .= l:severity_text . ':'
|
||||
endif
|
||||
if has_key(l:item, 'code') && !empty(l:item['code'])
|
||||
let l:text .= l:item['code'] . ':'
|
||||
endif
|
||||
let l:text .= l:item['message']
|
||||
let [l:line, l:col] = lsp#utils#position#lsp_to_vim(l:path, l:item['range']['start'])
|
||||
let l:location_item = {
|
||||
\ 'filename': l:path,
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ }
|
||||
if l:severity_text !=# ''
|
||||
" 'E' for error, 'W' for warning, 'I' for information, 'H' for hint
|
||||
let l:location_item['type'] = l:severity_text[0]
|
||||
endif
|
||||
call add(l:list, l:location_item)
|
||||
endfor
|
||||
endif
|
||||
|
||||
return l:list
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#utils#_get_symbol_text_from_kind(server, kind) abort
|
||||
if !has_key(s:symbol_kinds, a:server)
|
||||
let l:server_info = lsp#get_server_info(a:server)
|
||||
if has_key (l:server_info, 'config') && has_key(l:server_info['config'], 'symbol_kinds')
|
||||
let s:symbol_kinds[a:server] = extend(copy(s:default_symbol_kinds), l:server_info['config']['symbol_kinds'])
|
||||
else
|
||||
let s:symbol_kinds[a:server] = s:default_symbol_kinds
|
||||
endif
|
||||
endif
|
||||
return get(s:symbol_kinds[a:server], a:kind, 'unknown symbol ' . a:kind)
|
||||
endfunction
|
||||
|
||||
function! lsp#ui#vim#utils#get_symbol_kinds() abort
|
||||
return map(keys(s:default_symbol_kinds), {idx, key -> str2nr(key)})
|
||||
endfunction
|
||||
|
||||
function! s:get_diagnostic_severity_text(severity) abort
|
||||
return s:diagnostic_severity[a:severity]
|
||||
endfunction
|
||||
523
dot_vim/plugged/vim-lsp/autoload/lsp/utils.vim
Normal file
523
dot_vim/plugged/vim-lsp/autoload/lsp/utils.vim
Normal file
@@ -0,0 +1,523 @@
|
||||
let s:has_lua = has('nvim-0.4.0') || (has('lua') && has('patch-8.2.0775'))
|
||||
function! lsp#utils#has_lua() abort
|
||||
return s:has_lua
|
||||
endfunction
|
||||
|
||||
let s:has_native_lsp_client = !has('nvim') && has('patch-8.2.4780')
|
||||
function! lsp#utils#has_native_lsp_client() abort
|
||||
return s:has_native_lsp_client
|
||||
endfunction
|
||||
|
||||
let s:has_virtual_text = exists('*nvim_buf_set_virtual_text') && exists('*nvim_create_namespace')
|
||||
function! lsp#utils#_has_nvim_virtual_text() abort
|
||||
return s:has_virtual_text
|
||||
endfunction
|
||||
|
||||
let s:has_signs = exists('*sign_define') && (has('nvim') || has('patch-8.1.0772'))
|
||||
function! lsp#utils#_has_signs() abort
|
||||
return s:has_signs
|
||||
endfunction
|
||||
|
||||
let s:has_nvim_buf_highlight = exists('*nvim_buf_add_highlight') && has('nvim')
|
||||
function! lsp#utils#_has_nvim_buf_highlight() abort
|
||||
return s:has_nvim_buf_highlight
|
||||
endfunction
|
||||
|
||||
" https://github.com/prabirshrestha/vim-lsp/issues/399#issuecomment-500585549
|
||||
let s:has_textprops = exists('*prop_add') && has('patch-8.1.1035')
|
||||
function! lsp#utils#_has_textprops() abort
|
||||
return s:has_textprops
|
||||
endfunction
|
||||
|
||||
let s:has_vim9textprops = exists('*prop_add') && has('patch-9.0.0178')
|
||||
function! lsp#utils#_has_vim_virtual_text() abort
|
||||
return s:has_vim9textprops
|
||||
endfunction
|
||||
|
||||
let s:has_prop_remove_types = exists('*prop_remove') && has('patch-9.0.0233')
|
||||
function! lsp#utils#_has_prop_remove_types() abort
|
||||
return s:has_prop_remove_types
|
||||
endfunction
|
||||
|
||||
let s:has_higlights = has('nvim') ? lsp#utils#_has_nvim_buf_highlight() : lsp#utils#_has_textprops()
|
||||
function! lsp#utils#_has_highlights() abort
|
||||
return s:has_higlights
|
||||
endfunction
|
||||
|
||||
let s:has_popup_menu = exists('*popup_menu')
|
||||
function! lsp#utils#_has_popup_menu() abort
|
||||
return s:has_popup_menu
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#is_file_uri(uri) abort
|
||||
return stridx(a:uri, 'file:///') == 0
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#is_remote_uri(uri) abort
|
||||
return a:uri =~# '^\w\+::' || a:uri =~# '^[a-z][a-z0-9+.-]*://'
|
||||
endfunction
|
||||
|
||||
function! s:decode_uri(uri) abort
|
||||
let l:ret = substitute(a:uri, '[?#].*', '', '')
|
||||
return substitute(l:ret, '%\(\x\x\)', '\=printf("%c", str2nr(submatch(1), 16))', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:urlencode_char(c) abort
|
||||
return printf('%%%02X', char2nr(a:c))
|
||||
endfunction
|
||||
|
||||
function! s:get_prefix(path) abort
|
||||
return matchstr(a:path, '\(^\w\+::\|^\w\+://\)')
|
||||
endfunction
|
||||
|
||||
function! s:encode_uri(path, start_pos_encode, default_prefix) abort
|
||||
let l:prefix = s:get_prefix(a:path)
|
||||
let l:path = a:path[len(l:prefix):]
|
||||
if len(l:prefix) == 0
|
||||
let l:prefix = a:default_prefix
|
||||
endif
|
||||
|
||||
let l:result = strpart(a:path, 0, a:start_pos_encode)
|
||||
|
||||
for l:i in range(a:start_pos_encode, len(l:path) - 1)
|
||||
" Don't encode '/' here, `path` is expected to be a valid path.
|
||||
if l:path[l:i] =~# '^[a-zA-Z0-9_.~/@-]$'
|
||||
let l:result .= l:path[l:i]
|
||||
else
|
||||
let l:result .= s:urlencode_char(l:path[l:i])
|
||||
endif
|
||||
endfor
|
||||
|
||||
return l:prefix . l:result
|
||||
endfunction
|
||||
|
||||
let s:path_to_uri_cache = {}
|
||||
if has('win32') || has('win64') || has('win32unix')
|
||||
function! lsp#utils#path_to_uri(path) abort
|
||||
if has_key(s:path_to_uri_cache, a:path)
|
||||
return s:path_to_uri_cache[a:path]
|
||||
endif
|
||||
|
||||
if empty(a:path) || lsp#utils#is_remote_uri(a:path)
|
||||
let s:path_to_uri_cache[a:path] = a:path
|
||||
return s:path_to_uri_cache[a:path]
|
||||
else
|
||||
" Transform cygwin paths to windows paths
|
||||
let l:path = a:path
|
||||
if has('win32unix')
|
||||
let l:path = substitute(a:path, '\c^/\([a-z]\)/', '\U\1:/', '')
|
||||
endif
|
||||
|
||||
" You must not encode the volume information on the path if
|
||||
" present
|
||||
let l:end_pos_volume = matchstrpos(l:path, '\c[A-Z]:')[2]
|
||||
|
||||
if l:end_pos_volume == -1
|
||||
let l:end_pos_volume = 0
|
||||
endif
|
||||
|
||||
let s:path_to_uri_cache[l:path] = s:encode_uri(substitute(l:path, '\', '/', 'g'), l:end_pos_volume, 'file:///')
|
||||
return s:path_to_uri_cache[l:path]
|
||||
endif
|
||||
endfunction
|
||||
else
|
||||
function! lsp#utils#path_to_uri(path) abort
|
||||
if has_key(s:path_to_uri_cache, a:path)
|
||||
return s:path_to_uri_cache[a:path]
|
||||
endif
|
||||
|
||||
if empty(a:path) || lsp#utils#is_remote_uri(a:path)
|
||||
let s:path_to_uri_cache[a:path] = a:path
|
||||
return s:path_to_uri_cache[a:path]
|
||||
else
|
||||
let s:path_to_uri_cache[a:path] = s:encode_uri(a:path, 0, 'file://')
|
||||
return s:path_to_uri_cache[a:path]
|
||||
endif
|
||||
endfunction
|
||||
endif
|
||||
|
||||
let s:uri_to_path_cache = {}
|
||||
if has('win32') || has('win64') || has('win32unix')
|
||||
function! lsp#utils#uri_to_path(uri) abort
|
||||
if has_key(s:uri_to_path_cache, a:uri)
|
||||
return s:uri_to_path_cache[a:uri]
|
||||
endif
|
||||
|
||||
let l:path = substitute(s:decode_uri(a:uri[len('file:///'):]), '/', '\\', 'g')
|
||||
|
||||
" Transform windows paths to cygwin paths
|
||||
if has('win32unix')
|
||||
let l:path = substitute(l:path, '\c^\([A-Z]\):\\', '/\l\1/', '')
|
||||
let l:path = substitute(l:path, '\\', '/', 'g')
|
||||
endif
|
||||
|
||||
let s:uri_to_path_cache[a:uri] = l:path
|
||||
return s:uri_to_path_cache[a:uri]
|
||||
endfunction
|
||||
else
|
||||
function! lsp#utils#uri_to_path(uri) abort
|
||||
if has_key(s:uri_to_path_cache, a:uri)
|
||||
return s:uri_to_path_cache[a:uri]
|
||||
endif
|
||||
|
||||
let s:uri_to_path_cache[a:uri] = s:decode_uri(a:uri[len('file://'):])
|
||||
return s:uri_to_path_cache[a:uri]
|
||||
endfunction
|
||||
endif
|
||||
|
||||
if has('win32') || has('win64')
|
||||
function! lsp#utils#normalize_uri(uri) abort
|
||||
" Refer to https://github.com/microsoft/language-server-protocol/pull/1019 on normalization of urls.
|
||||
" TODO: after the discussion is settled, modify this function.
|
||||
let l:ret = substitute(a:uri, '^file:///[a-zA-Z]\zs%3[aA]', ':', '')
|
||||
return substitute(l:ret, '^file:///\zs\([A-Z]\)', "\\=tolower(submatch(1))", '')
|
||||
endfunction
|
||||
else
|
||||
function! lsp#utils#normalize_uri(uri) abort
|
||||
return a:uri
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! lsp#utils#get_default_root_uri() abort
|
||||
return lsp#utils#path_to_uri(getcwd())
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#get_buffer_path(...) abort
|
||||
return expand((a:0 > 0 ? '#' . a:1 : '%') . ':p')
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#get_buffer_uri(...) abort
|
||||
let l:name = a:0 > 0 ? bufname(a:1) : expand('%')
|
||||
if empty(l:name)
|
||||
let l:nr = a:0 > 0 ? a:1 : bufnr('%')
|
||||
let l:name = printf('%s/__NO_NAME_%d__', getcwd(), l:nr)
|
||||
endif
|
||||
return lsp#utils#path_to_uri(fnamemodify(l:name, ':p'))
|
||||
endfunction
|
||||
|
||||
" Find a nearest to a `path` parent directory `directoryname` by traversing the filesystem upwards
|
||||
function! lsp#utils#find_nearest_parent_directory(path, directoryname) abort
|
||||
let l:relative_path = finddir(a:directoryname, a:path . ';')
|
||||
|
||||
if !empty(l:relative_path)
|
||||
return fnamemodify(l:relative_path, ':p')
|
||||
else
|
||||
return ''
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Find a nearest to a `path` parent filename `filename` by traversing the filesystem upwards
|
||||
function! lsp#utils#find_nearest_parent_file(path, filename) abort
|
||||
let l:relative_path = findfile(a:filename, a:path . ';')
|
||||
|
||||
if !empty(l:relative_path)
|
||||
return fnamemodify(l:relative_path, ':p')
|
||||
else
|
||||
return ''
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#_compare_nearest_path(matches, lhs, rhs) abort
|
||||
let l:llhs = len(a:lhs)
|
||||
let l:lrhs = len(a:rhs)
|
||||
if l:llhs ># l:lrhs
|
||||
return -1
|
||||
elseif l:llhs <# l:lrhs
|
||||
return 1
|
||||
endif
|
||||
if a:matches[a:lhs] ># a:matches[a:rhs]
|
||||
return -1
|
||||
elseif a:matches[a:lhs] <# a:matches[a:rhs]
|
||||
return 1
|
||||
endif
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#_nearest_path(matches) abort
|
||||
return empty(a:matches) ?
|
||||
\ '' :
|
||||
\ sort(keys(a:matches), function('lsp#utils#_compare_nearest_path', [a:matches]))[0]
|
||||
endfunction
|
||||
|
||||
" Find a nearest to a `path` parent filename `filename` by traversing the filesystem upwards
|
||||
" The filename ending with '/' or '\' will be regarded as directory name,
|
||||
" otherwith as file name
|
||||
function! lsp#utils#find_nearest_parent_file_directory(path, filename) abort
|
||||
if type(a:filename) == 3
|
||||
let l:matched_paths = {}
|
||||
for l:current_name in a:filename
|
||||
let l:path = lsp#utils#find_nearest_parent_file_directory(a:path, l:current_name)
|
||||
|
||||
if !empty(l:path)
|
||||
if has_key(l:matched_paths, l:path)
|
||||
let l:matched_paths[l:path] += 1
|
||||
else
|
||||
let l:matched_paths[l:path] = 1
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
return lsp#utils#_nearest_path(l:matched_paths)
|
||||
elseif type(a:filename) == 1
|
||||
if a:filename[-1:] ==# '/' || a:filename[-1:] ==# '\'
|
||||
let l:modify_str = ':p:h:h'
|
||||
let l:path = lsp#utils#find_nearest_parent_directory(a:path, a:filename[:-2])
|
||||
else
|
||||
let l:modify_str = ':p:h'
|
||||
let l:path = lsp#utils#find_nearest_parent_file(a:path, a:filename)
|
||||
endif
|
||||
|
||||
return empty(l:path) ? '' : fnamemodify(l:path, l:modify_str)
|
||||
else
|
||||
echoerr "The type of argument \"filename\" must be String or List"
|
||||
endif
|
||||
endfunction
|
||||
|
||||
if exists('*matchstrpos')
|
||||
function! lsp#utils#matchstrpos(expr, pattern) abort
|
||||
return matchstrpos(a:expr, a:pattern)
|
||||
endfunction
|
||||
else
|
||||
function! lsp#utils#matchstrpos(expr, pattern) abort
|
||||
return [matchstr(a:expr, a:pattern), match(a:expr, a:pattern), matchend(a:expr, a:pattern)]
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! lsp#utils#empty_complete(...) abort
|
||||
return []
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#error(msg) abort
|
||||
echohl ErrorMsg
|
||||
echom a:msg
|
||||
echohl NONE
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#warning(msg) abort
|
||||
echohl WarningMsg
|
||||
echom a:msg
|
||||
echohl NONE
|
||||
endfunction
|
||||
|
||||
|
||||
function! lsp#utils#echo_with_truncation(msg) abort
|
||||
let l:msg = a:msg
|
||||
|
||||
if &laststatus == 0 || (&laststatus == 1 && tabpagewinnr(tabpagenr(), '$') == 1)
|
||||
let l:winwidth = winwidth(0)
|
||||
|
||||
if &ruler
|
||||
let l:winwidth -= 18
|
||||
endif
|
||||
else
|
||||
let l:winwidth = &columns
|
||||
endif
|
||||
|
||||
if &showcmd
|
||||
let l:winwidth -= 12
|
||||
endif
|
||||
|
||||
if l:winwidth > 5 && l:winwidth < strdisplaywidth(l:msg)
|
||||
let l:msg = l:msg[:l:winwidth - 5] . '...'
|
||||
endif
|
||||
|
||||
exec 'echo l:msg'
|
||||
endfunction
|
||||
|
||||
" Convert a byte-index (1-based) to a character-index (0-based)
|
||||
" This function requires a buffer specifier (expr, see :help bufname()),
|
||||
" a line number (lnum, 1-based), and a byte-index (char, 1-based).
|
||||
function! lsp#utils#to_char(expr, lnum, col) abort
|
||||
let l:lines = getbufline(a:expr, a:lnum)
|
||||
if l:lines == []
|
||||
if type(a:expr) != v:t_string || !filereadable(a:expr)
|
||||
" invalid a:expr
|
||||
return a:col - 1
|
||||
endif
|
||||
" a:expr is a file that is not yet loaded as a buffer
|
||||
let l:lines = readfile(a:expr, '', a:lnum)
|
||||
endif
|
||||
let l:linestr = l:lines[-1]
|
||||
return strchars(strpart(l:linestr, 0, a:col - 1))
|
||||
endfunction
|
||||
|
||||
function! s:get_base64_alphabet() abort
|
||||
let l:alphabet = []
|
||||
|
||||
" Uppercase letters
|
||||
for l:c in range(char2nr('A'), char2nr('Z'))
|
||||
call add(l:alphabet, nr2char(l:c))
|
||||
endfor
|
||||
|
||||
" Lowercase letters
|
||||
for l:c in range(char2nr('a'), char2nr('z'))
|
||||
call add(l:alphabet, nr2char(l:c))
|
||||
endfor
|
||||
|
||||
" Numbers
|
||||
for l:c in range(char2nr('0'), char2nr('9'))
|
||||
call add(l:alphabet, nr2char(l:c))
|
||||
endfor
|
||||
|
||||
" Symbols
|
||||
call add(l:alphabet, '+')
|
||||
call add(l:alphabet, '/')
|
||||
|
||||
return l:alphabet
|
||||
endfunction
|
||||
|
||||
if exists('*trim')
|
||||
function! lsp#utils#_trim(string) abort
|
||||
return trim(a:string)
|
||||
endfunction
|
||||
else
|
||||
function! lsp#utils#_trim(string) abort
|
||||
return substitute(a:string, '^\s*\|\s*$', '', 'g')
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! lsp#utils#_get_before_line() abort
|
||||
let l:text = getline('.')
|
||||
let l:idx = min([strlen(l:text), col('.') - 2])
|
||||
let l:idx = max([l:idx, -1])
|
||||
if l:idx == -1
|
||||
return ''
|
||||
endif
|
||||
return l:text[0 : l:idx]
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#_get_before_char_skip_white() abort
|
||||
let l:current_lnum = line('.')
|
||||
|
||||
let l:lnum = l:current_lnum
|
||||
while l:lnum > 0
|
||||
if l:lnum == l:current_lnum
|
||||
let l:text = lsp#utils#_get_before_line()
|
||||
else
|
||||
let l:text = getline(l:lnum)
|
||||
endif
|
||||
let l:match = matchlist(l:text, '\([^[:blank:]]\)\s*$')
|
||||
if get(l:match, 1, v:null) isnot v:null
|
||||
return l:match[1]
|
||||
endif
|
||||
let l:lnum -= 1
|
||||
endwhile
|
||||
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
let s:alphabet = s:get_base64_alphabet()
|
||||
|
||||
function! lsp#utils#base64_decode(data) abort
|
||||
let l:ret = []
|
||||
|
||||
" Process base64 string in chunks of 4 chars
|
||||
for l:group in split(a:data, '.\{4}\zs')
|
||||
let l:group_dec = 0
|
||||
|
||||
" Convert 4 chars to 3 octets
|
||||
for l:char in split(l:group, '\zs')
|
||||
let l:group_dec = l:group_dec * 64
|
||||
let l:group_dec += max([index(s:alphabet, l:char), 0])
|
||||
endfor
|
||||
|
||||
" Split the number representing the 3 octets into the individual
|
||||
" octets
|
||||
let l:octets = []
|
||||
let l:i = 0
|
||||
while l:i < 3
|
||||
call add(l:octets, l:group_dec % 256)
|
||||
let l:group_dec = l:group_dec / 256
|
||||
let l:i += 1
|
||||
endwhile
|
||||
|
||||
call extend(l:ret, reverse(l:octets))
|
||||
endfor
|
||||
|
||||
" Handle padding
|
||||
if len(a:data) >= 2
|
||||
if strpart(a:data, len(a:data) - 2) ==# '=='
|
||||
call remove(l:ret, -2, -1)
|
||||
elseif strpart(a:data, len(a:data) - 1) ==# '='
|
||||
call remove(l:ret, -1, -1)
|
||||
endif
|
||||
endif
|
||||
|
||||
return l:ret
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#make_valid_word(str) abort
|
||||
let l:str = substitute(a:str, '\$[0-9]\+\|\${\%(\\.\|[^}]\)\+}', '', 'g')
|
||||
let l:str = substitute(l:str, '\\\(.\)', '\1', 'g')
|
||||
let l:valid = matchstr(l:str, '^[^"'' (<{\[\t\r\n]\+')
|
||||
if empty(l:valid)
|
||||
return l:str
|
||||
endif
|
||||
if l:valid =~# ':$'
|
||||
return l:valid[:-2]
|
||||
endif
|
||||
return l:valid
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#_split_by_eol(text) abort
|
||||
return split(a:text, '\r\n\|\r\|\n', v:true)
|
||||
endfunction
|
||||
|
||||
" parse command options like "-key" or "-key=value"
|
||||
function! lsp#utils#parse_command_options(params) abort
|
||||
let l:result = {}
|
||||
for l:param in a:params
|
||||
let l:match = matchlist(l:param, '-\{1,2}\zs\([^=]*\)\(=\(.*\)\)\?\m')
|
||||
let l:result[l:match[1]] = l:match[3]
|
||||
endfor
|
||||
return l:result
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#is_large_window(winid) abort
|
||||
let l:buffer_size = line2byte(line('$', a:winid))
|
||||
return g:lsp_max_buffer_size >= 0 && l:buffer_size >= g:lsp_max_buffer_size
|
||||
endfunction
|
||||
|
||||
" polyfill for the neovim wait function
|
||||
if exists('*wait')
|
||||
function! lsp#utils#_wait(timeout, condition, ...) abort
|
||||
if type(a:timeout) != type(0)
|
||||
return -3
|
||||
endif
|
||||
if type(get(a:000, 0, 0)) != type(0)
|
||||
return -3
|
||||
endif
|
||||
while 1
|
||||
let l:result=call('wait', extend([a:timeout, a:condition], a:000))
|
||||
if l:result != -3 " ignore spurious errors
|
||||
return l:result
|
||||
endif
|
||||
endwhile
|
||||
endfunction
|
||||
else
|
||||
function! lsp#utils#_wait(timeout, condition, ...) abort
|
||||
try
|
||||
let l:timeout = a:timeout / 1000.0
|
||||
let l:interval = get(a:000, 0, 200)
|
||||
let l:Condition = a:condition
|
||||
if type(l:Condition) != type(function('eval'))
|
||||
let l:Condition = function('eval', l:Condition)
|
||||
endif
|
||||
let l:start = reltime()
|
||||
while l:timeout < 0 || reltimefloat(reltime(l:start)) < l:timeout
|
||||
if l:Condition()
|
||||
return 0
|
||||
endif
|
||||
|
||||
execute 'sleep ' . l:interval . 'm'
|
||||
endwhile
|
||||
return -1
|
||||
catch /^Vim:Interrupt$/
|
||||
return -2
|
||||
endtry
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! lsp#utils#iteratable(list) abort
|
||||
return type(a:list) !=# v:t_list ? [] : a:list
|
||||
endfunction
|
||||
42
dot_vim/plugged/vim-lsp/autoload/lsp/utils/args.vim
Normal file
42
dot_vim/plugged/vim-lsp/autoload/lsp/utils/args.vim
Normal file
@@ -0,0 +1,42 @@
|
||||
function! lsp#utils#args#_parse(args, opt, remainder_key) abort
|
||||
let l:result = {}
|
||||
let l:is_opts = v:true
|
||||
let l:remainder = []
|
||||
for l:item in split(a:args, ' ')
|
||||
if l:item[:1] !=# '--'
|
||||
let l:is_opts = v:false
|
||||
endif
|
||||
|
||||
if l:is_opts == v:false
|
||||
call add(l:remainder, l:item)
|
||||
continue
|
||||
endif
|
||||
|
||||
let l:parts = split(l:item, '=')
|
||||
let l:key = l:parts[0]
|
||||
let l:value = get(l:parts, 1, '')
|
||||
let l:key = l:key[2:]
|
||||
|
||||
if has_key(a:opt, l:key)
|
||||
if has_key(a:opt[l:key], 'type')
|
||||
let l:type = a:opt[l:key]['type']
|
||||
if l:type == type(v:true)
|
||||
if l:value ==# 'false' || l:value ==# '0' || l:value ==# ''
|
||||
let l:value = 0
|
||||
else
|
||||
let l:value = 1
|
||||
endif
|
||||
elseif l:type ==# type(0)
|
||||
let l:value = str2nr(l:value)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
let l:result[l:key] = l:value
|
||||
endfor
|
||||
|
||||
if a:remainder_key != v:null
|
||||
let l:result[a:remainder_key] = join(l:remainder)
|
||||
endif
|
||||
|
||||
return l:result
|
||||
endfunction
|
||||
74
dot_vim/plugged/vim-lsp/autoload/lsp/utils/buffer.vim
Normal file
74
dot_vim/plugged/vim-lsp/autoload/lsp/utils/buffer.vim
Normal file
@@ -0,0 +1,74 @@
|
||||
let s:fixendofline_exists = exists('+fixendofline')
|
||||
|
||||
function! s:get_fixendofline(buf) abort
|
||||
let l:eol = getbufvar(a:buf, '&endofline')
|
||||
let l:binary = getbufvar(a:buf, '&binary')
|
||||
|
||||
if s:fixendofline_exists
|
||||
let l:fixeol = getbufvar(a:buf, '&fixendofline')
|
||||
|
||||
if !l:binary
|
||||
" When 'binary' is off and 'fixeol' is on, 'endofline' is not used
|
||||
"
|
||||
" When 'binary' is off and 'fixeol' is off, 'endofline' is used to
|
||||
" remember the presence of a <EOL>
|
||||
return l:fixeol || l:eol
|
||||
else
|
||||
" When 'binary' is on, the value of 'fixeol' doesn't matter
|
||||
return l:eol
|
||||
endif
|
||||
else
|
||||
" When 'binary' is off the value of 'endofline' is not used
|
||||
"
|
||||
" When 'binary' is on 'endofline' is used to remember the presence of
|
||||
" a <EOL>
|
||||
return !l:binary || l:eol
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#buffer#_get_fixendofline(bufnr) abort
|
||||
return s:get_fixendofline(a:bufnr)
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#buffer#_get_lines(buf) abort
|
||||
let l:lines = getbufline(a:buf, 1, '$')
|
||||
if s:get_fixendofline(a:buf)
|
||||
let l:lines += ['']
|
||||
endif
|
||||
return l:lines
|
||||
endfunction
|
||||
|
||||
" @params {location} = {
|
||||
" 'uri': 'file://....',
|
||||
" 'range': {
|
||||
" 'start': { 'line': 1, 'character': 1 },
|
||||
" 'end': { 'line': 1, 'character': 1 },
|
||||
" }
|
||||
" }
|
||||
function! lsp#utils#buffer#_open_lsp_location(location) abort
|
||||
let l:path = lsp#utils#uri_to_path(a:location['uri'])
|
||||
let l:bufnr = bufnr(l:path)
|
||||
|
||||
let [l:start_line, l:start_col] = lsp#utils#position#lsp_to_vim(l:bufnr, a:location['range']['start'])
|
||||
let [l:end_line, l:end_col] = lsp#utils#position#lsp_to_vim(l:bufnr, a:location['range']['end'])
|
||||
|
||||
normal! m'
|
||||
if &modified && !&hidden
|
||||
let l:cmd = l:bufnr !=# -1 ? 'sb ' . l:bufnr : 'split ' . fnameescape(l:path)
|
||||
else
|
||||
let l:cmd = l:bufnr !=# -1 ? 'b ' . l:bufnr : 'edit ' . fnameescape(l:path)
|
||||
endif
|
||||
execute l:cmd . ' | call cursor('.l:start_line.','.l:start_col.')'
|
||||
|
||||
normal! V
|
||||
call setpos("'<", [l:bufnr, l:start_line, l:start_col])
|
||||
call setpos("'>", [l:bufnr, l:end_line, l:end_col])
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#buffer#get_indent_size(bufnr) abort
|
||||
let l:shiftwidth = getbufvar(a:bufnr, '&shiftwidth')
|
||||
if getbufvar(a:bufnr, '&shiftwidth')
|
||||
return l:shiftwidth
|
||||
endif
|
||||
return getbufvar(a:bufnr, '&tabstop')
|
||||
endfunction
|
||||
165
dot_vim/plugged/vim-lsp/autoload/lsp/utils/diff.vim
Normal file
165
dot_vim/plugged/vim-lsp/autoload/lsp/utils/diff.vim
Normal file
@@ -0,0 +1,165 @@
|
||||
" This is copied from https://github.com/natebosch/vim-lsc/blob/master/autoload/lsc/diff.vim
|
||||
"
|
||||
" Computes a simplistic diff between [old] and [new].
|
||||
"
|
||||
" Returns a dict with keys `range`, `rangeLength`, and `text` matching the LSP
|
||||
" definition of `TextDocumentContentChangeEvent`.
|
||||
"
|
||||
" Finds a single change between the common prefix, and common postfix.
|
||||
let s:has_lua = has('nvim-0.4.0') || (has('lua') && has('patch-8.2.0775'))
|
||||
" lua array and neovim vim list index starts with 1 while vim lists starts with 0.
|
||||
" starting patch-8.2.1066 vim lists array index was changed to start with 1.
|
||||
let s:lua_array_start_index = has('nvim-0.4.0') || has('patch-8.2.1066')
|
||||
|
||||
function! s:init_lua() abort
|
||||
lua <<EOF
|
||||
-- Returns a zero-based index of the last line that is different between
|
||||
-- old and new. If old and new are not zero indexed, pass offset to indicate
|
||||
-- the index base.
|
||||
function vimlsp_last_difference(old, new, offset, line_count)
|
||||
for i = 0, line_count - 1 do
|
||||
if old[#old - i + offset] ~= new[#new - i + offset] then
|
||||
return -1 * i
|
||||
end
|
||||
end
|
||||
return -1 * line_count
|
||||
end
|
||||
-- Returns a zero-based index of the first line that is different between
|
||||
-- old and new. If old and new are not zero indexed, pass offset to indicate
|
||||
-- the index base.
|
||||
function vimlsp_first_difference(old, new, offset, line_count)
|
||||
for i = 0, line_count - 1 do
|
||||
if old[i + offset] ~= new[i + offset] then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return line_count - 1
|
||||
end
|
||||
EOF
|
||||
let s:lua = 1
|
||||
endfunction
|
||||
|
||||
if s:has_lua && !exists('s:lua')
|
||||
call s:init_lua()
|
||||
endif
|
||||
|
||||
function! lsp#utils#diff#compute(old, new) abort
|
||||
let [l:start_line, l:start_char] = s:FirstDifference(a:old, a:new)
|
||||
let [l:end_line, l:end_char] =
|
||||
\ s:LastDifference(a:old[l:start_line :], a:new[l:start_line :], l:start_char)
|
||||
|
||||
let l:text = s:ExtractText(a:new, l:start_line, l:start_char, l:end_line, l:end_char)
|
||||
let l:length = s:Length(a:old, l:start_line, l:start_char, l:end_line, l:end_char)
|
||||
|
||||
let l:adj_end_line = len(a:old) + l:end_line
|
||||
let l:adj_end_char = l:end_line == 0 ? 0 : strchars(a:old[l:end_line]) + l:end_char + 1
|
||||
|
||||
let l:result = { 'range': {'start': {'line': l:start_line, 'character': l:start_char},
|
||||
\ 'end': {'line': l:adj_end_line, 'character': l:adj_end_char}},
|
||||
\ 'text': l:text,
|
||||
\ 'rangeLength': l:length,
|
||||
\}
|
||||
|
||||
return l:result
|
||||
endfunction
|
||||
|
||||
" Finds the line and character of the first different character between two
|
||||
" list of Strings.
|
||||
function! s:FirstDifference(old, new) abort
|
||||
let l:line_count = min([len(a:old), len(a:new)])
|
||||
if l:line_count == 0 | return [0, 0] | endif
|
||||
if g:lsp_use_lua && s:has_lua
|
||||
let l:eval = has('nvim') ? 'vim.api.nvim_eval' : 'vim.eval'
|
||||
let l:i = luaeval('vimlsp_first_difference('
|
||||
\.l:eval.'("a:old"),'.l:eval.'("a:new"),'.s:lua_array_start_index.','.l:line_count.')')
|
||||
else
|
||||
for l:i in range(l:line_count)
|
||||
if a:old[l:i] !=# a:new[l:i] | break | endif
|
||||
endfor
|
||||
endif
|
||||
if l:i >= l:line_count
|
||||
return [l:line_count - 1, strchars(a:old[l:line_count - 1])]
|
||||
endif
|
||||
let l:old_line = a:old[l:i]
|
||||
let l:new_line = a:new[l:i]
|
||||
let l:length = min([strchars(l:old_line), strchars(l:new_line)])
|
||||
let l:j = 0
|
||||
while l:j < l:length
|
||||
if strgetchar(l:old_line, l:j) != strgetchar(l:new_line, l:j) | break | endif
|
||||
let l:j += 1
|
||||
endwhile
|
||||
return [l:i, l:j]
|
||||
endfunction
|
||||
|
||||
function! s:LastDifference(old, new, start_char) abort
|
||||
let l:line_count = min([len(a:old), len(a:new)])
|
||||
if l:line_count == 0 | return [0, 0] | endif
|
||||
if g:lsp_use_lua && s:has_lua
|
||||
let l:eval = has('nvim') ? 'vim.api.nvim_eval' : 'vim.eval'
|
||||
let l:i = luaeval('vimlsp_last_difference('
|
||||
\.l:eval.'("a:old"),'.l:eval.'("a:new"),'.s:lua_array_start_index.','.l:line_count.')')
|
||||
else
|
||||
for l:i in range(-1, -1 * l:line_count, -1)
|
||||
if a:old[l:i] !=# a:new[l:i] | break | endif
|
||||
endfor
|
||||
endif
|
||||
if l:i <= -1 * l:line_count
|
||||
let l:i = -1 * l:line_count
|
||||
let l:old_line = strcharpart(a:old[l:i], a:start_char)
|
||||
let l:new_line = strcharpart(a:new[l:i], a:start_char)
|
||||
else
|
||||
let l:old_line = a:old[l:i]
|
||||
let l:new_line = a:new[l:i]
|
||||
endif
|
||||
let l:old_line_length = strchars(l:old_line)
|
||||
let l:new_line_length = strchars(l:new_line)
|
||||
let l:length = min([l:old_line_length, l:new_line_length])
|
||||
let l:j = -1
|
||||
while l:j >= -1 * l:length
|
||||
if strgetchar(l:old_line, l:old_line_length + l:j) !=
|
||||
\ strgetchar(l:new_line, l:new_line_length + l:j)
|
||||
break
|
||||
endif
|
||||
let l:j -= 1
|
||||
endwhile
|
||||
return [l:i, l:j]
|
||||
endfunction
|
||||
|
||||
function! s:ExtractText(lines, start_line, start_char, end_line, end_char) abort
|
||||
if a:start_line == len(a:lines) + a:end_line
|
||||
if a:end_line == 0 | return '' | endif
|
||||
let l:line = a:lines[a:start_line]
|
||||
let l:length = strchars(l:line) + a:end_char - a:start_char + 1
|
||||
return strcharpart(l:line, a:start_char, l:length)
|
||||
endif
|
||||
let l:result = strcharpart(a:lines[a:start_line], a:start_char) . "\n"
|
||||
for l:line in a:lines[a:start_line + 1:a:end_line - 1]
|
||||
let l:result .= l:line . "\n"
|
||||
endfor
|
||||
if a:end_line != 0
|
||||
let l:line = a:lines[a:end_line]
|
||||
let l:length = strchars(l:line) + a:end_char + 1
|
||||
let l:result .= strcharpart(l:line, 0, l:length)
|
||||
endif
|
||||
return l:result
|
||||
endfunction
|
||||
|
||||
function! s:Length(lines, start_line, start_char, end_line, end_char) abort
|
||||
let l:adj_end_line = len(a:lines) + a:end_line
|
||||
if l:adj_end_line >= len(a:lines)
|
||||
let l:adj_end_char = a:end_char - 1
|
||||
else
|
||||
let l:adj_end_char = strchars(a:lines[l:adj_end_line]) + a:end_char
|
||||
endif
|
||||
if a:start_line == l:adj_end_line
|
||||
return l:adj_end_char - a:start_char + 1
|
||||
endif
|
||||
let l:result = strchars(a:lines[a:start_line]) - a:start_char + 1
|
||||
let l:line = a:start_line + 1
|
||||
while l:line < l:adj_end_line
|
||||
let l:result += strchars(a:lines[l:line]) + 1
|
||||
let l:line += 1
|
||||
endwhile
|
||||
let l:result += l:adj_end_char + 1
|
||||
return l:result
|
||||
endfunction
|
||||
409
dot_vim/plugged/vim-lsp/autoload/lsp/utils/job.vim
Normal file
409
dot_vim/plugged/vim-lsp/autoload/lsp/utils/job.vim
Normal file
@@ -0,0 +1,409 @@
|
||||
" https://github.com/prabirshrestha/async.vim#2082d13bb195f3203d41a308b89417426a7deca1 (dirty)
|
||||
" :AsyncEmbed path=./autoload/lsp/utils/job.vim namespace=lsp#utils#job
|
||||
|
||||
" Author: Prabir Shrestha <mail at prabir dot me>
|
||||
" Website: https://github.com/prabirshrestha/async.vim
|
||||
" License: The MIT License {{{
|
||||
" The MIT License (MIT)
|
||||
"
|
||||
" Copyright (c) 2016 Prabir Shrestha
|
||||
"
|
||||
" Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
" of this software and associated documentation files (the "Software"), to deal
|
||||
" in the Software without restriction, including without limitation the rights
|
||||
" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
" copies of the Software, and to permit persons to whom the Software is
|
||||
" furnished to do so, subject to the following conditions:
|
||||
"
|
||||
" The above copyright notice and this permission notice shall be included in all
|
||||
" copies or substantial portions of the Software.
|
||||
"
|
||||
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
" SOFTWARE.
|
||||
" }}}
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
let s:jobidseq = 0
|
||||
let s:jobs = {} " { job, opts, type: 'vimjob|nvimjob'}
|
||||
let s:job_type_nvimjob = 'nvimjob'
|
||||
let s:job_type_vimjob = 'vimjob'
|
||||
let s:job_error_unsupported_job_type = -2 " unsupported job type
|
||||
|
||||
function! s:noop(...) abort
|
||||
endfunction
|
||||
|
||||
function! s:job_supported_types() abort
|
||||
let l:supported_types = []
|
||||
if has('nvim')
|
||||
let l:supported_types += [s:job_type_nvimjob]
|
||||
endif
|
||||
if !has('nvim') && has('job') && has('channel') && has('lambda')
|
||||
let l:supported_types += [s:job_type_vimjob]
|
||||
endif
|
||||
return l:supported_types
|
||||
endfunction
|
||||
|
||||
function! s:job_supports_type(type) abort
|
||||
return index(s:job_supported_types(), a:type) >= 0
|
||||
endfunction
|
||||
|
||||
function! s:out_cb(jobid, opts, job, data) abort
|
||||
call a:opts.on_stdout(a:jobid, a:data, 'stdout')
|
||||
endfunction
|
||||
|
||||
function! s:out_cb_array(jobid, opts, job, data) abort
|
||||
call a:opts.on_stdout(a:jobid, split(a:data, "\n", 1), 'stdout')
|
||||
endfunction
|
||||
|
||||
function! s:err_cb(jobid, opts, job, data) abort
|
||||
call a:opts.on_stderr(a:jobid, a:data, 'stderr')
|
||||
endfunction
|
||||
|
||||
function! s:err_cb_array(jobid, opts, job, data) abort
|
||||
call a:opts.on_stderr(a:jobid, split(a:data, "\n", 1), 'stderr')
|
||||
endfunction
|
||||
|
||||
function! s:exit_cb(jobid, opts, job, status) abort
|
||||
if has_key(a:opts, 'on_exit')
|
||||
call a:opts.on_exit(a:jobid, a:status, 'exit')
|
||||
endif
|
||||
if has_key(s:jobs, a:jobid)
|
||||
call remove(s:jobs, a:jobid)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_stdout(jobid, data, event) abort
|
||||
let l:jobinfo = s:jobs[a:jobid]
|
||||
call l:jobinfo.opts.on_stdout(a:jobid, a:data, a:event)
|
||||
endfunction
|
||||
|
||||
function! s:on_stdout_string(jobid, data, event) abort
|
||||
let l:jobinfo = s:jobs[a:jobid]
|
||||
call l:jobinfo.opts.on_stdout(a:jobid, join(a:data, "\n"), a:event)
|
||||
endfunction
|
||||
|
||||
function! s:on_stderr(jobid, data, event) abort
|
||||
let l:jobinfo = s:jobs[a:jobid]
|
||||
call l:jobinfo.opts.on_stderr(a:jobid, a:data, a:event)
|
||||
endfunction
|
||||
|
||||
function! s:on_stderr_string(jobid, data, event) abort
|
||||
let l:jobinfo = s:jobs[a:jobid]
|
||||
call l:jobinfo.opts.on_stderr(a:jobid, join(a:data, "\n"), a:event)
|
||||
endfunction
|
||||
|
||||
function! s:on_exit(jobid, status, event) abort
|
||||
if has_key(s:jobs, a:jobid)
|
||||
let l:jobinfo = s:jobs[a:jobid]
|
||||
if has_key(l:jobinfo.opts, 'on_exit')
|
||||
call l:jobinfo.opts.on_exit(a:jobid, a:status, a:event)
|
||||
endif
|
||||
if has_key(s:jobs, a:jobid)
|
||||
call remove(s:jobs, a:jobid)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:job_start(cmd, opts) abort
|
||||
let l:jobtypes = s:job_supported_types()
|
||||
let l:jobtype = ''
|
||||
|
||||
if has_key(a:opts, 'type')
|
||||
if type(a:opts.type) == type('')
|
||||
if !s:job_supports_type(a:opts.type)
|
||||
return s:job_error_unsupported_job_type
|
||||
endif
|
||||
let l:jobtype = a:opts.type
|
||||
else
|
||||
let l:jobtypes = a:opts.type
|
||||
endif
|
||||
endif
|
||||
|
||||
if empty(l:jobtype)
|
||||
" find the best jobtype
|
||||
for l:jobtype2 in l:jobtypes
|
||||
if s:job_supports_type(l:jobtype2)
|
||||
let l:jobtype = l:jobtype2
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
|
||||
if l:jobtype ==? ''
|
||||
return s:job_error_unsupported_job_type
|
||||
endif
|
||||
|
||||
" options shared by both vim and neovim
|
||||
let l:jobopt = {}
|
||||
if has_key(a:opts, 'cwd')
|
||||
let l:jobopt.cwd = a:opts.cwd
|
||||
endif
|
||||
if has_key(a:opts, 'env')
|
||||
let l:jobopt.env = a:opts.env
|
||||
endif
|
||||
|
||||
let l:normalize = get(a:opts, 'normalize', 'array') " array/string/raw
|
||||
|
||||
if l:jobtype == s:job_type_nvimjob
|
||||
if l:normalize ==# 'string'
|
||||
let l:jobopt['on_stdout'] = has_key(a:opts, 'on_stdout') ? function('s:on_stdout_string') : function('s:noop')
|
||||
let l:jobopt['on_stderr'] = has_key(a:opts, 'on_stderr') ? function('s:on_stderr_string') : function('s:noop')
|
||||
else " array or raw
|
||||
let l:jobopt['on_stdout'] = has_key(a:opts, 'on_stdout') ? function('s:on_stdout') : function('s:noop')
|
||||
let l:jobopt['on_stderr'] = has_key(a:opts, 'on_stderr') ? function('s:on_stderr') : function('s:noop')
|
||||
endif
|
||||
call extend(l:jobopt, { 'on_exit': function('s:on_exit') })
|
||||
let l:job = jobstart(a:cmd, l:jobopt)
|
||||
if l:job <= 0
|
||||
return l:job
|
||||
endif
|
||||
let l:jobid = l:job " nvimjobid and internal jobid is same
|
||||
let s:jobs[l:jobid] = {
|
||||
\ 'type': s:job_type_nvimjob,
|
||||
\ 'opts': a:opts,
|
||||
\ }
|
||||
let s:jobs[l:jobid].job = l:job
|
||||
elseif l:jobtype == s:job_type_vimjob
|
||||
let s:jobidseq = s:jobidseq + 1
|
||||
let l:jobid = s:jobidseq
|
||||
if l:normalize ==# 'array'
|
||||
let l:jobopt['out_cb'] = has_key(a:opts, 'on_stdout') ? function('s:out_cb_array', [l:jobid, a:opts]) : function('s:noop')
|
||||
let l:jobopt['err_cb'] = has_key(a:opts, 'on_stderr') ? function('s:err_cb_array', [l:jobid, a:opts]) : function('s:noop')
|
||||
else " raw or string
|
||||
let l:jobopt['out_cb'] = has_key(a:opts, 'on_stdout') ? function('s:out_cb', [l:jobid, a:opts]) : function('s:noop')
|
||||
let l:jobopt['err_cb'] = has_key(a:opts, 'on_stderr') ? function('s:err_cb', [l:jobid, a:opts]) : function('s:noop')
|
||||
endif
|
||||
call extend(l:jobopt, {
|
||||
\ 'exit_cb': function('s:exit_cb', [l:jobid, a:opts]),
|
||||
\ 'mode': 'raw',
|
||||
\ })
|
||||
if has('patch-8.1.889')
|
||||
let l:jobopt['noblock'] = 1
|
||||
endif
|
||||
let l:job = job_start(a:cmd, l:jobopt)
|
||||
if job_status(l:job) !=? 'run'
|
||||
return -1
|
||||
endif
|
||||
let s:jobs[l:jobid] = {
|
||||
\ 'type': s:job_type_vimjob,
|
||||
\ 'opts': a:opts,
|
||||
\ 'job': l:job,
|
||||
\ 'channel': job_getchannel(l:job),
|
||||
\ 'buffer': ''
|
||||
\ }
|
||||
else
|
||||
return s:job_error_unsupported_job_type
|
||||
endif
|
||||
|
||||
return l:jobid
|
||||
endfunction
|
||||
|
||||
function! s:job_stop(jobid) abort
|
||||
if has_key(s:jobs, a:jobid)
|
||||
let l:jobinfo = s:jobs[a:jobid]
|
||||
if l:jobinfo.type == s:job_type_nvimjob
|
||||
" See: vital-Whisky/System.Job
|
||||
try
|
||||
call jobstop(a:jobid)
|
||||
catch /^Vim\%((\a\+)\)\=:E900/
|
||||
" NOTE:
|
||||
" Vim does not raise exception even the job has already closed so fail
|
||||
" silently for 'E900: Invalid job id' exception
|
||||
endtry
|
||||
elseif l:jobinfo.type == s:job_type_vimjob
|
||||
if type(s:jobs[a:jobid].job) == v:t_job
|
||||
call job_stop(s:jobs[a:jobid].job)
|
||||
elseif type(s:jobs[a:jobid].job) == v:t_channel
|
||||
call ch_close(s:jobs[a:jobid].job)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:job_send(jobid, data, opts) abort
|
||||
let l:jobinfo = s:jobs[a:jobid]
|
||||
let l:close_stdin = get(a:opts, 'close_stdin', 0)
|
||||
if l:jobinfo.type == s:job_type_nvimjob
|
||||
call jobsend(a:jobid, a:data)
|
||||
if l:close_stdin
|
||||
call chanclose(a:jobid, 'stdin')
|
||||
endif
|
||||
elseif l:jobinfo.type == s:job_type_vimjob
|
||||
" There is no easy way to know when ch_sendraw() finishes writing data
|
||||
" on a non-blocking channels -- has('patch-8.1.889') -- and because of
|
||||
" this, we cannot safely call ch_close_in(). So when we find ourselves
|
||||
" in this situation (i.e. noblock=1 and close stdin after send) we fall
|
||||
" back to using s:flush_vim_sendraw() and wait for transmit buffer to be
|
||||
" empty
|
||||
"
|
||||
" Ref: https://groups.google.com/d/topic/vim_dev/UNNulkqb60k/discussion
|
||||
if has('patch-8.1.818') && (!has('patch-8.1.889') || !l:close_stdin)
|
||||
call ch_sendraw(l:jobinfo.channel, a:data)
|
||||
else
|
||||
let l:jobinfo.buffer .= a:data
|
||||
call s:flush_vim_sendraw(a:jobid, v:null)
|
||||
endif
|
||||
if l:close_stdin
|
||||
while len(l:jobinfo.buffer) != 0
|
||||
sleep 1m
|
||||
endwhile
|
||||
call ch_close_in(l:jobinfo.channel)
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:flush_vim_sendraw(jobid, timer) abort
|
||||
" https://github.com/vim/vim/issues/2548
|
||||
" https://github.com/natebosch/vim-lsc/issues/67#issuecomment-357469091
|
||||
let l:jobinfo = s:jobs[a:jobid]
|
||||
sleep 1m
|
||||
if len(l:jobinfo.buffer) <= 4096
|
||||
call ch_sendraw(l:jobinfo.channel, l:jobinfo.buffer)
|
||||
let l:jobinfo.buffer = ''
|
||||
else
|
||||
let l:to_send = l:jobinfo.buffer[:4095]
|
||||
let l:jobinfo.buffer = l:jobinfo.buffer[4096:]
|
||||
call ch_sendraw(l:jobinfo.channel, l:to_send)
|
||||
call timer_start(1, function('s:flush_vim_sendraw', [a:jobid]))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:job_wait_single(jobid, timeout, start) abort
|
||||
if !has_key(s:jobs, a:jobid)
|
||||
return -3
|
||||
endif
|
||||
|
||||
let l:jobinfo = s:jobs[a:jobid]
|
||||
if l:jobinfo.type == s:job_type_nvimjob
|
||||
let l:timeout = a:timeout - reltimefloat(reltime(a:start)) * 1000
|
||||
return jobwait([a:jobid], float2nr(l:timeout))[0]
|
||||
elseif l:jobinfo.type == s:job_type_vimjob
|
||||
let l:timeout = a:timeout / 1000.0
|
||||
try
|
||||
while l:timeout < 0 || reltimefloat(reltime(a:start)) < l:timeout
|
||||
let l:info = job_info(l:jobinfo.job)
|
||||
if l:info.status ==# 'dead'
|
||||
return l:info.exitval
|
||||
elseif l:info.status ==# 'fail'
|
||||
return -3
|
||||
endif
|
||||
sleep 1m
|
||||
endwhile
|
||||
catch /^Vim:Interrupt$/
|
||||
return -2
|
||||
endtry
|
||||
endif
|
||||
return -1
|
||||
endfunction
|
||||
|
||||
function! s:job_wait(jobids, timeout) abort
|
||||
let l:start = reltime()
|
||||
let l:exitcode = 0
|
||||
let l:ret = []
|
||||
for l:jobid in a:jobids
|
||||
if l:exitcode != -2 " Not interrupted.
|
||||
let l:exitcode = s:job_wait_single(l:jobid, a:timeout, l:start)
|
||||
endif
|
||||
let l:ret += [l:exitcode]
|
||||
endfor
|
||||
return l:ret
|
||||
endfunction
|
||||
|
||||
function! s:job_pid(jobid) abort
|
||||
if !has_key(s:jobs, a:jobid)
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:jobinfo = s:jobs[a:jobid]
|
||||
if l:jobinfo.type == s:job_type_nvimjob
|
||||
return jobpid(a:jobid)
|
||||
elseif l:jobinfo.type == s:job_type_vimjob
|
||||
let l:vimjobinfo = job_info(a:jobid)
|
||||
if type(l:vimjobinfo) == type({}) && has_key(l:vimjobinfo, 'process')
|
||||
return l:vimjobinfo['process']
|
||||
endif
|
||||
endif
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! s:callback_cb(jobid, opts, ch, data) abort
|
||||
if has_key(a:opts, 'on_stdout')
|
||||
call a:opts.on_stdout(a:jobid, a:data, 'stdout')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:callback_cb_array(jobid, opts, ch, data) abort
|
||||
if has_key(a:opts, 'on_stdout')
|
||||
call a:opts.on_stdout(a:jobid, split(a:data, "\n", 1), 'stdout')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:close_cb(jobid, opts, ch) abort
|
||||
if has_key(a:opts, 'on_exit')
|
||||
call a:opts.on_exit(a:jobid, 'closed', 'exit')
|
||||
endif
|
||||
if has_key(s:jobs, a:jobid)
|
||||
call remove(s:jobs, a:jobid)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" public apis {{{
|
||||
function! lsp#utils#job#start(cmd, opts) abort
|
||||
return s:job_start(a:cmd, a:opts)
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#job#stop(jobid) abort
|
||||
call s:job_stop(a:jobid)
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#job#send(jobid, data, ...) abort
|
||||
let l:opts = get(a:000, 0, {})
|
||||
call s:job_send(a:jobid, a:data, l:opts)
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#job#wait(jobids, ...) abort
|
||||
let l:timeout = get(a:000, 0, -1)
|
||||
return s:job_wait(a:jobids, l:timeout)
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#job#pid(jobid) abort
|
||||
return s:job_pid(a:jobid)
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#job#connect(addr, opts) abort
|
||||
let s:jobidseq = s:jobidseq + 1
|
||||
let l:jobid = s:jobidseq
|
||||
let l:retry = 0
|
||||
let l:normalize = get(a:opts, 'normalize', 'array') " array/string/raw
|
||||
while l:retry < 5
|
||||
let l:ch = ch_open(a:addr, {'waittime': 1000})
|
||||
call ch_setoptions(l:ch, {
|
||||
\ 'callback': function(l:normalize ==# 'array' ? 's:callback_cb_array' : 's:callback_cb', [l:jobid, a:opts]),
|
||||
\ 'close_cb': function('s:close_cb', [l:jobid, a:opts]),
|
||||
\ 'mode': 'raw',
|
||||
\})
|
||||
if ch_status(l:ch) ==# 'open'
|
||||
break
|
||||
endif
|
||||
sleep 100m
|
||||
let l:retry += 1
|
||||
endwhile
|
||||
let s:jobs[l:jobid] = {
|
||||
\ 'type': s:job_type_vimjob,
|
||||
\ 'opts': a:opts,
|
||||
\ 'job': l:ch,
|
||||
\ 'channel': l:ch,
|
||||
\ 'buffer': ''
|
||||
\}
|
||||
return l:jobid
|
||||
endfunction
|
||||
" }}}
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
135
dot_vim/plugged/vim-lsp/autoload/lsp/utils/location.vim
Normal file
135
dot_vim/plugged/vim-lsp/autoload/lsp/utils/location.vim
Normal file
@@ -0,0 +1,135 @@
|
||||
function! s:open_location(path, line, col, ...) abort
|
||||
normal! m'
|
||||
let l:mods = a:0 ? a:1 : ''
|
||||
let l:buffer = bufnr(a:path)
|
||||
if l:mods ==# '' && &modified && !&hidden && l:buffer != bufnr('%')
|
||||
let l:mods = &splitbelow ? 'rightbelow' : 'leftabove'
|
||||
endif
|
||||
if l:mods ==# ''
|
||||
if l:buffer == bufnr('%')
|
||||
let l:cmd = ''
|
||||
else
|
||||
let l:cmd = (l:buffer !=# -1 ? 'b ' . l:buffer : 'edit ' . fnameescape(a:path)) . ' | '
|
||||
endif
|
||||
else
|
||||
let l:cmd = l:mods . ' ' . (l:buffer !=# -1 ? 'sb ' . l:buffer : 'split ' . fnameescape(a:path)) . ' | '
|
||||
endif
|
||||
execute l:cmd . 'call cursor('.a:line.','.a:col.')'
|
||||
endfunction
|
||||
|
||||
" @param location = {
|
||||
" 'filename',
|
||||
" 'lnum',
|
||||
" 'col',
|
||||
" }
|
||||
function! lsp#utils#location#_open_vim_list_item(location, mods) abort
|
||||
call s:open_location(a:location['filename'], a:location['lnum'], a:location['col'], a:mods)
|
||||
endfunction
|
||||
|
||||
" @params {location} = {
|
||||
" 'uri': 'file://....',
|
||||
" 'range': {
|
||||
" 'start': { 'line': 1, 'character': 1 },
|
||||
" 'end': { 'line': 1, 'character': 1 },
|
||||
" }
|
||||
" }
|
||||
function! lsp#utils#location#_open_lsp_location(location) abort
|
||||
let l:path = lsp#utils#uri_to_path(a:location['uri'])
|
||||
let l:bufnr = bufnr(l:path)
|
||||
|
||||
let [l:start_line, l:start_col] = lsp#utils#position#lsp_to_vim(l:bufnr, a:location['range']['start'])
|
||||
let [l:end_line, l:end_col] = lsp#utils#position#lsp_to_vim(l:bufnr, a:location['range']['end'])
|
||||
|
||||
call s:open_location(l:path, l:start_line, l:start_col)
|
||||
|
||||
normal! V
|
||||
call setpos("'<", [l:bufnr, l:start_line, l:start_col])
|
||||
call setpos("'>", [l:bufnr, l:end_line, l:end_col])
|
||||
endfunction
|
||||
|
||||
" @param loc = Location | LocationLink
|
||||
" @param cache = {} empty dict
|
||||
" @returns {
|
||||
" 'filename',
|
||||
" 'lnum',
|
||||
" 'col',
|
||||
" 'text',
|
||||
" 'viewstart?',
|
||||
" 'viewend?',
|
||||
" }
|
||||
function! s:lsp_location_item_to_vim(loc, cache) abort
|
||||
if has_key(a:loc, 'targetUri') " LocationLink
|
||||
let l:uri = a:loc['targetUri']
|
||||
let l:range = a:loc['targetSelectionRange']
|
||||
let l:use_link = 1
|
||||
else " Location
|
||||
let l:uri = a:loc['uri']
|
||||
let l:range = a:loc['range']
|
||||
let l:use_link = 0
|
||||
endif
|
||||
|
||||
if !lsp#utils#is_file_uri(l:uri)
|
||||
return v:null
|
||||
endif
|
||||
|
||||
let l:path = lsp#utils#uri_to_path(l:uri)
|
||||
let [l:line, l:col] = lsp#utils#position#lsp_to_vim(l:path, l:range['start'])
|
||||
|
||||
let l:index = l:line - 1
|
||||
if has_key(a:cache, l:path)
|
||||
let l:text = a:cache[l:path][l:index]
|
||||
else
|
||||
let l:contents = getbufline(l:path, 1, '$')
|
||||
if !empty(l:contents)
|
||||
let l:text = get(l:contents, l:index, '')
|
||||
else
|
||||
let l:contents = readfile(l:path)
|
||||
let a:cache[l:path] = l:contents
|
||||
let l:text = get(l:contents, l:index, '')
|
||||
endif
|
||||
endif
|
||||
|
||||
if l:use_link
|
||||
" viewstart/end decremented to account for incrementing in _lsp_to_vim
|
||||
return {
|
||||
\ 'filename': l:path,
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ 'viewstart': lsp#utils#position#lsp_to_vim(l:path, a:loc['targetRange']['start'])[0] - 1,
|
||||
\ 'viewend': lsp#utils#position#lsp_to_vim(l:path, a:loc['targetRange']['end'])[0] - 1,
|
||||
\ }
|
||||
else
|
||||
return {
|
||||
\ 'filename': l:path,
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text,
|
||||
\ }
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" @summary Use this to convert loc to vim list that is compatible with
|
||||
" quickfix and locllist items
|
||||
" @param loc = v:null | Location | Location[] | LocationLink
|
||||
" @returns []
|
||||
function! lsp#utils#location#_lsp_to_vim_list(loc) abort
|
||||
let l:result = []
|
||||
let l:cache = {}
|
||||
if empty(a:loc) " v:null
|
||||
return l:result
|
||||
elseif type(a:loc) == type([]) " Location[]
|
||||
for l:location in a:loc
|
||||
let l:vim_loc = s:lsp_location_item_to_vim(l:location, l:cache)
|
||||
if !empty(l:vim_loc) " https:// uri will return empty
|
||||
call add(l:result, l:vim_loc)
|
||||
endif
|
||||
endfor
|
||||
else " Location or LocationLink
|
||||
let l:vim_loc = s:lsp_location_item_to_vim(a:loc, l:cache)
|
||||
if !empty(l:vim_loc) " https:// uri will return empty
|
||||
call add(l:result, l:vim_loc)
|
||||
endif
|
||||
endif
|
||||
return l:result
|
||||
endfunction
|
||||
91
dot_vim/plugged/vim-lsp/autoload/lsp/utils/position.vim
Normal file
91
dot_vim/plugged/vim-lsp/autoload/lsp/utils/position.vim
Normal file
@@ -0,0 +1,91 @@
|
||||
" This function can be error prone if the caller forgets to use +1 to vim line
|
||||
" so use lsp#utils#position#lsp_to_vim instead
|
||||
" Convert a character-index (0-based) to byte-index (1-based)
|
||||
" This function requires a buffer specifier (expr, see :help bufname()),
|
||||
" a line number (lnum, 1-based), and a character-index (char, 0-based).
|
||||
function! s:to_col(expr, lnum, char) abort
|
||||
let l:lines = getbufline(a:expr, a:lnum)
|
||||
if l:lines == []
|
||||
if type(a:expr) != v:t_string || !filereadable(a:expr)
|
||||
" invalid a:expr
|
||||
return a:char + 1
|
||||
endif
|
||||
" a:expr is a file that is not yet loaded as a buffer
|
||||
let l:lines = readfile(a:expr, '', a:lnum)
|
||||
if l:lines == []
|
||||
" when the file is empty. a:char should be 0 in the case
|
||||
return a:char + 1
|
||||
endif
|
||||
endif
|
||||
let l:linestr = l:lines[-1]
|
||||
return strlen(strcharpart(l:linestr, 0, a:char)) + 1
|
||||
endfunction
|
||||
|
||||
" The inverse version of `s:to_col`.
|
||||
" Convert [lnum, col] to LSP's `Position`.
|
||||
function! s:to_char(expr, lnum, col) abort
|
||||
let l:lines = getbufline(a:expr, a:lnum)
|
||||
if l:lines == []
|
||||
if type(a:expr) != v:t_string || !filereadable(a:expr)
|
||||
" invalid a:expr
|
||||
return a:col - 1
|
||||
endif
|
||||
" a:expr is a file that is not yet loaded as a buffer
|
||||
let l:lines = readfile(a:expr, '', a:lnum)
|
||||
endif
|
||||
let l:linestr = l:lines[-1]
|
||||
return strchars(strpart(l:linestr, 0, a:col - 1))
|
||||
endfunction
|
||||
|
||||
" @param expr = see :help bufname()
|
||||
" @param position = {
|
||||
" 'line': 1,
|
||||
" 'character': 1
|
||||
" }
|
||||
" @returns [
|
||||
" line,
|
||||
" col
|
||||
" ]
|
||||
function! lsp#utils#position#lsp_to_vim(expr, position) abort
|
||||
let l:line = lsp#utils#position#lsp_line_to_vim(a:expr, a:position)
|
||||
let l:col = lsp#utils#position#lsp_character_to_vim(a:expr, a:position)
|
||||
return [l:line, l:col]
|
||||
endfunction
|
||||
|
||||
" @param expr = see :help bufname()
|
||||
" @param position = {
|
||||
" 'line': 1,
|
||||
" 'character': 1
|
||||
" }
|
||||
" @returns
|
||||
" line
|
||||
function! lsp#utils#position#lsp_line_to_vim(expr, position) abort
|
||||
return a:position['line'] + 1
|
||||
endfunction
|
||||
|
||||
" @param expr = see :help bufname()
|
||||
" @param position = {
|
||||
" 'line': 1,
|
||||
" 'character': 1
|
||||
" }
|
||||
" @returns
|
||||
" line
|
||||
function! lsp#utils#position#lsp_character_to_vim(expr, position) abort
|
||||
let l:line = a:position['line'] + 1 " optimize function overhead by not calling lsp_line_to_vim
|
||||
let l:char = a:position['character']
|
||||
return s:to_col(a:expr, l:line, l:char)
|
||||
endfunction
|
||||
|
||||
" @param expr = :help bufname()
|
||||
" @param pos = [lnum, col]
|
||||
" @returns {
|
||||
" 'line': line,
|
||||
" 'character': character
|
||||
" }
|
||||
function! lsp#utils#position#vim_to_lsp(expr, pos) abort
|
||||
return {
|
||||
\ 'line': a:pos[0] - 1,
|
||||
\ 'character': s:to_char(a:expr, a:pos[0], a:pos[1])
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
82
dot_vim/plugged/vim-lsp/autoload/lsp/utils/range.vim
Normal file
82
dot_vim/plugged/vim-lsp/autoload/lsp/utils/range.vim
Normal file
@@ -0,0 +1,82 @@
|
||||
"
|
||||
" Returns recent visual-mode range.
|
||||
"
|
||||
function! lsp#utils#range#_get_recent_visual_range() abort
|
||||
let l:start_pos = getpos("'<")[1 : 2]
|
||||
let l:end_pos = getpos("'>")[1 : 2]
|
||||
let l:end_pos[1] += 1 " To exclusive
|
||||
|
||||
" Fix line selection.
|
||||
let l:end_line = getline(l:end_pos[0])
|
||||
if l:end_pos[1] > strlen(l:end_line)
|
||||
let l:end_pos[1] = strlen(l:end_line) + 1
|
||||
endif
|
||||
|
||||
let l:range = {}
|
||||
let l:range['start'] = lsp#utils#position#vim_to_lsp('%', l:start_pos)
|
||||
let l:range['end'] = lsp#utils#position#vim_to_lsp('%', l:end_pos)
|
||||
return l:range
|
||||
endfunction
|
||||
|
||||
"
|
||||
" Returns current line range.
|
||||
"
|
||||
function! lsp#utils#range#_get_current_line_range() abort
|
||||
let l:pos = getpos('.')[1 : 2]
|
||||
let l:range = {}
|
||||
let l:range['start'] = lsp#utils#position#vim_to_lsp('%', l:pos)
|
||||
let l:range['end'] = lsp#utils#position#vim_to_lsp('%', [l:pos[0], l:pos[1] + strlen(getline(l:pos[0])) + 1])
|
||||
return l:range
|
||||
endfunction
|
||||
|
||||
" Convert a LSP range to one or more vim match positions.
|
||||
" If the range spans over multiple lines, break it down to multiple
|
||||
" positions, one for each line.
|
||||
" Return a list of positions.
|
||||
function! lsp#utils#range#lsp_to_vim(bufnr, range) abort
|
||||
let l:position = []
|
||||
|
||||
let [l:start_line, l:start_col] = lsp#utils#position#lsp_to_vim(a:bufnr, a:range['start'])
|
||||
let [l:end_line, l:end_col] = lsp#utils#position#lsp_to_vim(a:bufnr, a:range['end'])
|
||||
if l:end_line == l:start_line
|
||||
let l:position = [[
|
||||
\ l:start_line,
|
||||
\ l:start_col,
|
||||
\ l:end_col - l:start_col
|
||||
\ ]]
|
||||
else
|
||||
" First line
|
||||
let l:position = [[
|
||||
\ l:start_line,
|
||||
\ l:start_col,
|
||||
\ 999
|
||||
\ ]]
|
||||
|
||||
" Last line
|
||||
call add(l:position, [
|
||||
\ l:end_line,
|
||||
\ 1,
|
||||
\ l:end_col
|
||||
\ ])
|
||||
|
||||
" Lines in the middle
|
||||
let l:middle_lines = map(
|
||||
\ range(l:start_line + 1, l:end_line - 1),
|
||||
\ {_, l -> [l, 0, 999]}
|
||||
\ )
|
||||
|
||||
call extend(l:position, l:middle_lines)
|
||||
endif
|
||||
|
||||
return l:position
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#range#get_range() abort
|
||||
let l:char = lsp#utils#to_char('%', line('$'), col('$'))
|
||||
return {'start': {'line': 0, 'character': 0}, 'end': {'line': line('$')-1, 'character': l:char}}
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#range#get_range_curline() abort
|
||||
let l:char = lsp#utils#to_char('%', line('.'), col('$'))
|
||||
return {'start': {'line': line('.')-1, 'character': 0}, 'end': {'line': line('.')-1, 'character': l:char}}
|
||||
endfunction
|
||||
19
dot_vim/plugged/vim-lsp/autoload/lsp/utils/step.vim
Normal file
19
dot_vim/plugged/vim-lsp/autoload/lsp/utils/step.vim
Normal file
@@ -0,0 +1,19 @@
|
||||
function! s:next(steps, current_index, result) abort
|
||||
if len(a:steps) == a:current_index
|
||||
return
|
||||
endif
|
||||
let l:Step = a:steps[a:current_index]
|
||||
let l:ctx = {
|
||||
\ 'callback': function('s:callback', [a:steps, a:current_index]),
|
||||
\ 'result': a:result
|
||||
\ }
|
||||
call call(l:Step, [l:ctx])
|
||||
endfunction
|
||||
|
||||
function! s:callback(steps, current_index, ...) abort
|
||||
call s:next(a:steps, a:current_index + 1, a:000)
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#step#start(steps) abort
|
||||
call s:next(a:steps, 0, [])
|
||||
endfunction
|
||||
33
dot_vim/plugged/vim-lsp/autoload/lsp/utils/tagstack.vim
Normal file
33
dot_vim/plugged/vim-lsp/autoload/lsp/utils/tagstack.vim
Normal file
@@ -0,0 +1,33 @@
|
||||
if exists('*gettagstack') && exists('*settagstack')
|
||||
function! lsp#utils#tagstack#_update() abort
|
||||
let l:bufnr = bufnr('%')
|
||||
let l:item = {'bufnr': l:bufnr, 'from': [l:bufnr, line('.'), col('.'), 0], 'tagname': expand('<cword>')}
|
||||
let l:winid = win_getid()
|
||||
|
||||
let l:stack = gettagstack(l:winid)
|
||||
if l:stack['length'] == l:stack['curidx']
|
||||
" Replace the last items with item.
|
||||
let l:action = 'r'
|
||||
let l:stack['items'][l:stack['curidx']-1] = l:item
|
||||
elseif l:stack['length'] > l:stack['curidx']
|
||||
" Replace items after used items with item.
|
||||
let l:action = 'r'
|
||||
if l:stack['curidx'] > 1
|
||||
let l:stack['items'] = add(l:stack['items'][:l:stack['curidx']-2], l:item)
|
||||
else
|
||||
let l:stack['items'] = [l:item]
|
||||
endif
|
||||
else
|
||||
" Append item.
|
||||
let l:action = 'a'
|
||||
let l:stack['items'] = [l:item]
|
||||
endif
|
||||
let l:stack['curidx'] += 1
|
||||
|
||||
call settagstack(l:winid, l:stack, l:action)
|
||||
endfunction
|
||||
else
|
||||
function! lsp#utils#tagstack#_update() abort
|
||||
" do nothing
|
||||
endfunction
|
||||
endif
|
||||
229
dot_vim/plugged/vim-lsp/autoload/lsp/utils/text_edit.vim
Normal file
229
dot_vim/plugged/vim-lsp/autoload/lsp/utils/text_edit.vim
Normal file
@@ -0,0 +1,229 @@
|
||||
function! lsp#utils#text_edit#get_range(text_edit) abort
|
||||
if type(a:text_edit) != v:t_dict
|
||||
return v:null
|
||||
endif
|
||||
let l:insert = get(a:text_edit, 'insert', v:null)
|
||||
if type(l:insert) == v:t_dict
|
||||
return l:insert
|
||||
endif
|
||||
return get(a:text_edit, 'range', v:null)
|
||||
endfunction
|
||||
|
||||
function! lsp#utils#text_edit#apply_text_edits(uri, text_edits) abort
|
||||
let l:current_bufname = bufname('%')
|
||||
let l:target_bufname = lsp#utils#uri_to_path(a:uri)
|
||||
let l:cursor_position = lsp#get_position()
|
||||
|
||||
call s:_switch(l:target_bufname)
|
||||
for l:text_edit in s:_normalize(a:text_edits)
|
||||
call s:_apply(bufnr(l:target_bufname), l:text_edit, l:cursor_position)
|
||||
endfor
|
||||
call s:_switch(l:current_bufname)
|
||||
|
||||
if bufnr(l:current_bufname) == bufnr(l:target_bufname)
|
||||
call cursor(lsp#utils#position#lsp_to_vim('%', l:cursor_position))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" @summary Use this to convert textedit to vim list that is compatible with
|
||||
" quickfix and locllist items
|
||||
" @param uri = DocumentUri
|
||||
" @param text_edit = TextEdit | TextEdit[]
|
||||
" @returns []
|
||||
function! lsp#utils#text_edit#_lsp_to_vim_list(uri, text_edit) abort
|
||||
let l:result = []
|
||||
let l:cache = {}
|
||||
if type(a:text_edit) == type([]) " TextEdit[]
|
||||
for l:text_edit in a:text_edit
|
||||
let l:vim_loc = s:lsp_text_edit_item_to_vim(a:uri, l:text_edit, l:cache)
|
||||
if !empty(l:vim_loc)
|
||||
call add(l:result, l:vim_loc)
|
||||
endif
|
||||
endfor
|
||||
else " TextEdit
|
||||
let l:vim_loc = s:lsp_text_edit_item_to_vim(a:uri, a:text_edit, l:cache)
|
||||
if !empty(l:vim_loc)
|
||||
call add(l:result, l:vim_loc)
|
||||
endif
|
||||
endif
|
||||
return l:result
|
||||
endfunction
|
||||
|
||||
" @param uri = DocumentUri
|
||||
" @param text_edit = TextEdit
|
||||
" @param cache = {} empty dict
|
||||
" @returns {
|
||||
" 'filename',
|
||||
" 'lnum',
|
||||
" 'col',
|
||||
" 'text',
|
||||
" }
|
||||
function! s:lsp_text_edit_item_to_vim(uri, text_edit, cache) abort
|
||||
if !lsp#utils#is_file_uri(a:uri)
|
||||
return v:null
|
||||
endif
|
||||
|
||||
let l:path = lsp#utils#uri_to_path(a:uri)
|
||||
let l:range = a:text_edit['range']
|
||||
let [l:line, l:col] = lsp#utils#position#lsp_to_vim(l:path, l:range['start'])
|
||||
|
||||
let l:index = l:line - 1
|
||||
if has_key(a:cache, l:path)
|
||||
let l:text = a:cache[l:path][l:index]
|
||||
else
|
||||
let l:contents = getbufline(l:path, 1, '$')
|
||||
if !empty(l:contents)
|
||||
let l:text = get(l:contents, l:index, '')
|
||||
else
|
||||
let l:contents = readfile(l:path)
|
||||
let a:cache[l:path] = l:contents
|
||||
let l:text = get(l:contents, l:index, '')
|
||||
endif
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'filename': l:path,
|
||||
\ 'lnum': l:line,
|
||||
\ 'col': l:col,
|
||||
\ 'text': l:text
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _apply
|
||||
"
|
||||
function! s:_apply(bufnr, text_edit, cursor_position) abort
|
||||
" create before/after line.
|
||||
let l:start_line = getline(a:text_edit['range']['start']['line'] + 1)
|
||||
let l:end_line = getline(a:text_edit['range']['end']['line'] + 1)
|
||||
let l:before_line = strcharpart(l:start_line, 0, a:text_edit['range']['start']['character'])
|
||||
let l:after_line = strcharpart(l:end_line, a:text_edit['range']['end']['character'], strchars(l:end_line) - a:text_edit['range']['end']['character'])
|
||||
|
||||
" create new lines.
|
||||
let l:new_lines = lsp#utils#_split_by_eol(a:text_edit['newText'])
|
||||
let l:new_lines[0] = l:before_line . l:new_lines[0]
|
||||
let l:new_lines[-1] = l:new_lines[-1] . l:after_line
|
||||
|
||||
" save length.
|
||||
let l:new_lines_len = len(l:new_lines)
|
||||
let l:range_len = (a:text_edit['range']['end']['line'] - a:text_edit['range']['start']['line']) + 1
|
||||
|
||||
" fixendofline
|
||||
let l:buffer_length = len(getbufline(a:bufnr, '^', '$'))
|
||||
let l:should_fixendofline = lsp#utils#buffer#_get_fixendofline(a:bufnr)
|
||||
let l:should_fixendofline = l:should_fixendofline && l:new_lines[-1] ==# ''
|
||||
let l:should_fixendofline = l:should_fixendofline && l:buffer_length <= a:text_edit['range']['end']['line']
|
||||
let l:should_fixendofline = l:should_fixendofline && a:text_edit['range']['end']['character'] == 0
|
||||
if l:should_fixendofline
|
||||
call remove(l:new_lines, -1)
|
||||
endif
|
||||
|
||||
" fix cursor pos
|
||||
if a:text_edit['range']['end']['line'] < a:cursor_position['line']
|
||||
" fix cursor line
|
||||
let a:cursor_position['line'] += l:new_lines_len - l:range_len
|
||||
elseif a:text_edit['range']['end']['line'] == a:cursor_position['line'] && a:text_edit['range']['end']['character'] <= a:cursor_position['character']
|
||||
" fix cursor line and col
|
||||
let a:cursor_position['line'] += l:new_lines_len - l:range_len
|
||||
let l:end_character = strchars(l:new_lines[-1]) - strchars(l:after_line)
|
||||
let l:end_offset = a:cursor_position['character'] - a:text_edit['range']['end']['character']
|
||||
let a:cursor_position['character'] = l:end_character + l:end_offset
|
||||
endif
|
||||
|
||||
" append or delete lines.
|
||||
if l:new_lines_len > l:range_len
|
||||
call append(a:text_edit['range']['start']['line'], repeat([''], l:new_lines_len - l:range_len))
|
||||
elseif l:new_lines_len < l:range_len
|
||||
let l:offset = l:range_len - l:new_lines_len
|
||||
call s:delete(a:bufnr, a:text_edit['range']['start']['line'] + 1, a:text_edit['range']['start']['line'] + l:offset)
|
||||
endif
|
||||
|
||||
" set lines.
|
||||
call setline(a:text_edit['range']['start']['line'] + 1, l:new_lines)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _normalize
|
||||
"
|
||||
function! s:_normalize(text_edits) abort
|
||||
let l:text_edits = type(a:text_edits) == type([]) ? a:text_edits : [a:text_edits]
|
||||
let l:text_edits = filter(copy(l:text_edits), { _, text_edit -> type(text_edit) == type({}) })
|
||||
let l:text_edits = s:_range(l:text_edits)
|
||||
let l:text_edits = sort(copy(l:text_edits), function('s:_compare', [], {}))
|
||||
let l:text_edits = s:_check(l:text_edits)
|
||||
return reverse(l:text_edits)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _range
|
||||
"
|
||||
function! s:_range(text_edits) abort
|
||||
for l:text_edit in a:text_edits
|
||||
if l:text_edit.range.start.line > l:text_edit.range.end.line || (
|
||||
\ l:text_edit.range.start.line == l:text_edit.range.end.line &&
|
||||
\ l:text_edit.range.start.character > l:text_edit.range.end.character
|
||||
\ )
|
||||
let l:text_edit.range = { 'start': l:text_edit.range.end, 'end': l:text_edit.range.start }
|
||||
endif
|
||||
endfor
|
||||
return a:text_edits
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _check
|
||||
"
|
||||
" LSP Spec says `multiple text edits can not overlap those ranges`.
|
||||
" This function check it. But does not throw error.
|
||||
"
|
||||
function! s:_check(text_edits) abort
|
||||
if len(a:text_edits) > 1
|
||||
let l:range = a:text_edits[0].range
|
||||
for l:text_edit in a:text_edits[1 : -1]
|
||||
if l:range.end.line > l:text_edit.range.start.line || (
|
||||
\ l:range.end.line == l:text_edit.range.start.line &&
|
||||
\ l:range.end.character > l:text_edit.range.start.character
|
||||
\ )
|
||||
call lsp#log('text_edit: range overlapped.')
|
||||
endif
|
||||
let l:range = l:text_edit.range
|
||||
endfor
|
||||
endif
|
||||
return a:text_edits
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _compare
|
||||
"
|
||||
function! s:_compare(text_edit1, text_edit2) abort
|
||||
let l:diff = a:text_edit1.range.start.line - a:text_edit2.range.start.line
|
||||
if l:diff == 0
|
||||
return a:text_edit1.range.start.character - a:text_edit2.range.start.character
|
||||
endif
|
||||
return l:diff
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _switch
|
||||
"
|
||||
function! s:_switch(path) abort
|
||||
if bufnr(a:path) >= 0
|
||||
execute printf('keepalt keepjumps %sbuffer!', bufnr(a:path))
|
||||
else
|
||||
execute printf('keepalt keepjumps edit! %s', fnameescape(a:path))
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" delete
|
||||
"
|
||||
function! s:delete(bufnr, start, end) abort
|
||||
if exists('*deletebufline')
|
||||
call deletebufline(a:bufnr, a:start, a:end)
|
||||
else
|
||||
let l:foldenable = &foldenable
|
||||
setlocal nofoldenable
|
||||
execute printf('%s,%sdelete _', a:start, a:end)
|
||||
let &foldenable = l:foldenable
|
||||
endif
|
||||
endfunction
|
||||
|
||||
295
dot_vim/plugged/vim-lsp/autoload/lsp/utils/tree.vim
Normal file
295
dot_vim/plugged/vim-lsp/autoload/lsp/utils/tree.vim
Normal file
@@ -0,0 +1,295 @@
|
||||
" This file is part of an installation of vim-yggdrasil, a vim/neovim tree viewer library.
|
||||
" The source code of vim-yggdrasil is available at https://github.com/m-pilia/vim-yggdrasil
|
||||
"
|
||||
" vim-yggdrasil is free software, distributed under the MIT license.
|
||||
" The full license is available at https://github.com/m-pilia/vim-yggdrasil/blob/master/LICENSE
|
||||
"
|
||||
" Yggdrasil version (git SHA-1): 043d0ab53dcdd0d91b7c7cd205791d64d4ed9624
|
||||
"
|
||||
" This installation was generated on 2020-03-15T14:47:27-0700 with the following vim command:
|
||||
" :YggdrasilPlant -plugin_dir=./ -namespace=lsp/utils
|
||||
|
||||
scriptencoding utf-8
|
||||
|
||||
" Callback to retrieve the tree item representation of an object.
|
||||
function! s:node_get_tree_item_cb(node, object, status, tree_item) abort
|
||||
if a:status ==? 'success'
|
||||
let l:new_node = s:node_new(a:node.tree, a:object, a:tree_item, a:node)
|
||||
call add(a:node.children, l:new_node)
|
||||
call s:tree_render(l:new_node.tree)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Callback to retrieve the children objects of a node.
|
||||
function! s:node_get_children_cb(node, status, childObjectList) abort
|
||||
for l:childObject in a:childObjectList
|
||||
let l:Callback = function('s:node_get_tree_item_cb', [a:node, l:childObject])
|
||||
call a:node.tree.provider.getTreeItem(l:Callback, l:childObject)
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" Set the node to be collapsed or expanded.
|
||||
"
|
||||
" When {collapsed} evaluates to 0 the node is expanded, when it is 1 the node is
|
||||
" collapsed, when it is equal to -1 the node is toggled (it is expanded if it
|
||||
" was collapsed, and vice versa).
|
||||
function! s:node_set_collapsed(collapsed) dict abort
|
||||
let l:self.collapsed = a:collapsed < 0 ? !l:self.collapsed : !!a:collapsed
|
||||
endfunction
|
||||
|
||||
" Given a funcref {Condition}, return a list of all nodes in the subtree of
|
||||
" {node} for which {Condition} evaluates to v:true.
|
||||
function! s:search_subtree(node, Condition) abort
|
||||
if a:Condition(a:node)
|
||||
return [a:node]
|
||||
endif
|
||||
if len(a:node.children) < 1
|
||||
return []
|
||||
endif
|
||||
let l:result = []
|
||||
for l:child in a:node.children
|
||||
let l:result = l:result + s:search_subtree(l:child, a:Condition)
|
||||
endfor
|
||||
return l:result
|
||||
endfunction
|
||||
|
||||
" Execute the action associated to a node
|
||||
function! s:node_exec() dict abort
|
||||
if has_key(l:self.tree_item, 'command')
|
||||
call l:self.tree_item.command()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Return the depth level of the node in the tree. The level is defined
|
||||
" recursively: the root has depth 0, and each node has depth equal to the depth
|
||||
" of its parent increased by 1.
|
||||
function! s:node_level() dict abort
|
||||
if l:self.parent == {}
|
||||
return 0
|
||||
endif
|
||||
return 1 + l:self.parent.level()
|
||||
endf
|
||||
|
||||
" Return the string representation of the node. The {level} argument represents
|
||||
" the depth level of the node in the tree and it is passed for convenience, to
|
||||
" simplify the implementation and to avoid re-computing the depth.
|
||||
function! s:node_render(level) dict abort
|
||||
let l:indent = repeat(' ', 2 * a:level)
|
||||
let l:mark = '• '
|
||||
|
||||
if len(l:self.children) > 0 || l:self.lazy_open != v:false
|
||||
let l:mark = l:self.collapsed ? '▸ ' : '▾ '
|
||||
endif
|
||||
|
||||
let l:label = split(l:self.tree_item.label, "\n")
|
||||
call extend(l:self.tree.index, map(range(len(l:label)), 'l:self'))
|
||||
|
||||
let l:repr = l:indent . l:mark . l:label[0]
|
||||
\ . join(map(l:label[1:], {_, l -> "\n" . l:indent . ' ' . l}))
|
||||
|
||||
let l:lines = [l:repr]
|
||||
if !l:self.collapsed
|
||||
if l:self.lazy_open
|
||||
let l:self.lazy_open = v:false
|
||||
let l:Callback = function('s:node_get_children_cb', [l:self])
|
||||
call l:self.tree.provider.getChildren(l:Callback, l:self.object)
|
||||
endif
|
||||
for l:child in l:self.children
|
||||
call add(l:lines, l:child.render(a:level + 1))
|
||||
endfor
|
||||
endif
|
||||
|
||||
return join(l:lines, "\n")
|
||||
endfunction
|
||||
|
||||
" Insert a new node in the tree, internally represented by a unique progressive
|
||||
" integer identifier {id}. The node represents a certain {object} (children of
|
||||
" {parent}) belonging to a given {tree}, having an associated action to be
|
||||
" triggered on execution defined by the function object {exec}. If {collapsed}
|
||||
" is true the node will be rendered as collapsed in the view. If {lazy_open} is
|
||||
" true, the children of the node will be fetched when the node is expanded by
|
||||
" the user.
|
||||
function! s:node_new(tree, object, tree_item, parent) abort
|
||||
let a:tree.maxid += 1
|
||||
return {
|
||||
\ 'id': a:tree.maxid,
|
||||
\ 'tree': a:tree,
|
||||
\ 'object': a:object,
|
||||
\ 'tree_item': a:tree_item,
|
||||
\ 'parent': a:parent,
|
||||
\ 'collapsed': a:tree_item.collapsibleState ==? 'collapsed',
|
||||
\ 'lazy_open': a:tree_item.collapsibleState !=? 'none',
|
||||
\ 'children': [],
|
||||
\ 'level': function('s:node_level'),
|
||||
\ 'exec': function('s:node_exec'),
|
||||
\ 'set_collapsed': function('s:node_set_collapsed'),
|
||||
\ 'render': function('s:node_render'),
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
" Callback that sets the root node of a given {tree}, creating a new node
|
||||
" with a {tree_item} representation for the given {object}. If {status} is
|
||||
" equal to 'success', the root node is set and the tree view is updated
|
||||
" accordingly, otherwise nothing happens.
|
||||
function! s:tree_set_root_cb(tree, object, status, tree_item) abort
|
||||
if a:status ==? 'success'
|
||||
let a:tree.maxid = -1
|
||||
let a:tree.root = s:node_new(a:tree, a:object, a:tree_item, {})
|
||||
call s:tree_render(a:tree)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Return the node currently under the cursor from the given {tree}.
|
||||
function! s:get_node_under_cursor(tree) abort
|
||||
let l:index = min([line('.'), len(a:tree.index) - 1])
|
||||
return a:tree.index[l:index]
|
||||
endfunction
|
||||
|
||||
" Expand or collapse the node under cursor, and render the tree.
|
||||
" Please refer to *s:node_set_collapsed()* for details about the
|
||||
" arguments and behaviour.
|
||||
function! s:tree_set_collapsed_under_cursor(collapsed) dict abort
|
||||
let l:node = s:get_node_under_cursor(l:self)
|
||||
call l:node.set_collapsed(a:collapsed)
|
||||
call s:tree_render(l:self)
|
||||
endfunction
|
||||
|
||||
" Run the action associated to the node currently under the cursor.
|
||||
function! s:tree_exec_node_under_cursor() dict abort
|
||||
call s:get_node_under_cursor(l:self).exec()
|
||||
endfunction
|
||||
|
||||
" Render the {tree}. This will replace the content of the buffer with the
|
||||
" tree view. Clear the index, setting it to a list containing a guard
|
||||
" value for index 0 (line numbers are one-based).
|
||||
function! s:tree_render(tree) abort
|
||||
if &filetype !=# 'lsp-tree'
|
||||
return
|
||||
endif
|
||||
|
||||
let l:cursor = getpos('.')
|
||||
let a:tree.index = [-1]
|
||||
let l:text = a:tree.root.render(0)
|
||||
|
||||
setlocal modifiable
|
||||
silent 1,$delete _
|
||||
silent 0put=l:text
|
||||
$d
|
||||
setlocal nomodifiable
|
||||
|
||||
call setpos('.', l:cursor)
|
||||
endfunction
|
||||
|
||||
" If {status} equals 'success', update all nodes of {tree} representing
|
||||
" an {obect} with given {tree_item} representation.
|
||||
function! s:node_update(tree, object, status, tree_item) abort
|
||||
if a:status !=? 'success'
|
||||
return
|
||||
endif
|
||||
for l:node in s:search_subtree(a:tree.root, {n -> n.object == a:object})
|
||||
let l:node.tree_item = a:tree_item
|
||||
let l:node.children = []
|
||||
let l:node.lazy_open = a:tree_item.collapsibleState !=? 'none'
|
||||
endfor
|
||||
call s:tree_render(a:tree)
|
||||
endfunction
|
||||
|
||||
" Update the view if nodes have changed. If called with no arguments,
|
||||
" update the whole tree. If called with an {object} as argument, update
|
||||
" all the subtrees of nodes corresponding to {object}.
|
||||
function! s:tree_update(...) dict abort
|
||||
if a:0 < 1
|
||||
call l:self.provider.getChildren({status, obj ->
|
||||
\ l:self.provider.getTreeItem(function('s:tree_set_root_cb', [l:self, obj[0]]), obj[0])})
|
||||
else
|
||||
call l:self.provider.getTreeItem(function('s:node_update', [l:self, a:1]), a:1)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Destroy the tree view. Wipe out the buffer containing it.
|
||||
function! s:tree_wipe() dict abort
|
||||
execute 'bwipeout' . l:self.bufnr
|
||||
endfunction
|
||||
|
||||
" Apply syntax to an lsp-tree buffer
|
||||
function! s:filetype_syntax() abort
|
||||
syntax clear
|
||||
syntax match LspTreeMarkLeaf "•" contained
|
||||
syntax match LspTreeMarkCollapsed "▸" contained
|
||||
syntax match LspTreeMarkExpanded "▾" contained
|
||||
syntax match LspTreeNode "\v^(\s|[▸▾•])*.*"
|
||||
\ contains=LspTreeMarkLeaf,LspTreeMarkCollapsed,LspTreeMarkExpanded
|
||||
|
||||
highlight def link LspTreeMarkLeaf Type
|
||||
highlight def link LspTreeMarkExpanded Type
|
||||
highlight def link LspTreeMarkCollapsed Macro
|
||||
endfunction
|
||||
|
||||
" Apply local settings to an lsp-tree buffer
|
||||
function! s:filetype_settings() abort
|
||||
setlocal bufhidden=wipe
|
||||
setlocal buftype=nofile
|
||||
setlocal foldcolumn=0
|
||||
setlocal foldmethod=manual
|
||||
setlocal nobuflisted
|
||||
setlocal nofoldenable
|
||||
setlocal nohlsearch
|
||||
setlocal nolist
|
||||
setlocal nomodifiable
|
||||
setlocal nonumber
|
||||
setlocal nospell
|
||||
setlocal noswapfile
|
||||
setlocal nowrap
|
||||
|
||||
nnoremap <silent> <buffer> <Plug>(lsp-tree-toggle-node)
|
||||
\ :call b:lsp_tree.set_collapsed_under_cursor(-1)<cr>
|
||||
|
||||
nnoremap <silent> <buffer> <Plug>(lsp-tree-open-node)
|
||||
\ :call b:lsp_tree.set_collapsed_under_cursor(v:false)<cr>
|
||||
|
||||
nnoremap <silent> <buffer> <Plug>(lsp-tree-close-node)
|
||||
\ :call b:lsp_tree.set_collapsed_under_cursor(v:true)<cr>
|
||||
|
||||
nnoremap <silent> <buffer> <Plug>(lsp-tree-execute-node)
|
||||
\ :call b:lsp_tree.exec_node_under_cursor()<cr>
|
||||
|
||||
nnoremap <silent> <buffer> <Plug>(lsp-tree-wipe-tree)
|
||||
\ :call b:lsp_tree.wipe()<cr>
|
||||
|
||||
if !exists('g:lsp_tree_no_default_maps')
|
||||
nmap <silent> <buffer> o <Plug>(lsp-tree-toggle-node)
|
||||
nmap <silent> <buffer> <cr> <Plug>(lsp-tree-execute-node)
|
||||
nmap <silent> <buffer> q <Plug>(lsp-tree-wipe-tree)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Turns the current buffer into an lsp-tree tree view. Tree data is retrieved
|
||||
" from the given {provider}, and the state of the tree is stored in a
|
||||
" buffer-local variable called b:lsp_tree.
|
||||
"
|
||||
" The {bufnr} stores the buffer number of the view, {maxid} is the highest
|
||||
" known internal identifier of the nodes. The {index} is a list that
|
||||
" maps line numbers to nodes.
|
||||
function! lsp#utils#tree#new(provider) abort
|
||||
let b:lsp_tree = {
|
||||
\ 'bufnr': bufnr('%'),
|
||||
\ 'maxid': -1,
|
||||
\ 'root': {},
|
||||
\ 'index': [],
|
||||
\ 'provider': a:provider,
|
||||
\ 'set_collapsed_under_cursor': function('s:tree_set_collapsed_under_cursor'),
|
||||
\ 'exec_node_under_cursor': function('s:tree_exec_node_under_cursor'),
|
||||
\ 'update': function('s:tree_update'),
|
||||
\ 'wipe': function('s:tree_wipe'),
|
||||
\ }
|
||||
|
||||
augroup vim_lsp_tree
|
||||
autocmd!
|
||||
autocmd FileType lsp-tree call s:filetype_syntax() | call s:filetype_settings()
|
||||
autocmd BufEnter <buffer> call s:tree_render(b:lsp_tree)
|
||||
augroup END
|
||||
|
||||
setlocal filetype=lsp-tree
|
||||
|
||||
call b:lsp_tree.update()
|
||||
endfunction
|
||||
@@ -0,0 +1,14 @@
|
||||
function! lsp#utils#workspace_config#get_value(server_name, item) abort
|
||||
try
|
||||
let l:server_info = lsp#get_server_info(a:server_name)
|
||||
let l:config = l:server_info['workspace_config']
|
||||
|
||||
for l:section in split(a:item['section'], '\.')
|
||||
let l:config = l:config[l:section]
|
||||
endfor
|
||||
|
||||
return l:config
|
||||
catch
|
||||
return v:null
|
||||
endtry
|
||||
endfunction
|
||||
@@ -0,0 +1,27 @@
|
||||
" Applies WorkspaceEdit changes.
|
||||
function! lsp#utils#workspace_edit#apply_workspace_edit(workspace_edit) abort
|
||||
let l:loclist_items = []
|
||||
|
||||
if has_key(a:workspace_edit, 'documentChanges')
|
||||
for l:text_document_edit in a:workspace_edit['documentChanges']
|
||||
let l:loclist_items += s:_apply(l:text_document_edit['textDocument']['uri'], l:text_document_edit['edits'])
|
||||
endfor
|
||||
elseif has_key(a:workspace_edit, 'changes')
|
||||
for [l:uri, l:text_edits] in items(a:workspace_edit['changes'])
|
||||
let l:loclist_items += s:_apply(l:uri, l:text_edits)
|
||||
endfor
|
||||
endif
|
||||
|
||||
if g:lsp_show_workspace_edits
|
||||
call setloclist(0, l:loclist_items, 'r')
|
||||
execute 'lopen'
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _apply
|
||||
"
|
||||
function! s:_apply(uri, text_edits) abort
|
||||
call lsp#utils#text_edit#apply_text_edits(a:uri, a:text_edits)
|
||||
return lsp#utils#text_edit#_lsp_to_vim_list(a:uri, a:text_edits)
|
||||
endfunction
|
||||
9
dot_vim/plugged/vim-lsp/autoload/vital/_lsp.vim
Normal file
9
dot_vim/plugged/vim-lsp/autoload/vital/_lsp.vim
Normal file
@@ -0,0 +1,9 @@
|
||||
let s:_plugin_name = expand('<sfile>:t:r')
|
||||
|
||||
function! vital#{s:_plugin_name}#new() abort
|
||||
return vital#{s:_plugin_name[1:]}#new()
|
||||
endfunction
|
||||
|
||||
function! vital#{s:_plugin_name}#function(funcname) abort
|
||||
silent! return function(a:funcname)
|
||||
endfunction
|
||||
@@ -0,0 +1,66 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not modify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_lsp#VS#LSP#MarkupContent#import() abort', printf("return map({'_vital_depends': '', 'normalize': '', '_vital_loaded': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" _vital_loaded
|
||||
"
|
||||
function! s:_vital_loaded(V) abort
|
||||
let s:Text = a:V.import('VS.LSP.Text')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _vital_depends
|
||||
"
|
||||
function! s:_vital_depends() abort
|
||||
return ['VS.LSP.Text']
|
||||
endfunction
|
||||
|
||||
"
|
||||
" normalize
|
||||
"
|
||||
function! s:normalize(markup_content, ...) abort
|
||||
let l:option = get(a:000, 0, {})
|
||||
let l:option.compact = get(l:option, 'compact', v:true)
|
||||
|
||||
let l:normalized = ''
|
||||
if type(a:markup_content) == type('')
|
||||
let l:normalized = a:markup_content
|
||||
elseif type(a:markup_content) == type([])
|
||||
let l:normalized = join(a:markup_content, "\n")
|
||||
elseif type(a:markup_content) == type({})
|
||||
let l:normalized = a:markup_content.value
|
||||
if has_key(a:markup_content, 'language')
|
||||
let l:normalized = join([
|
||||
\ '```' . a:markup_content.language,
|
||||
\ l:normalized,
|
||||
\ '```'
|
||||
\ ], "\n")
|
||||
endif
|
||||
endif
|
||||
let l:normalized = s:Text.normalize_eol(l:normalized)
|
||||
let l:normalized = s:_format(l:normalized, l:option.compact)
|
||||
return l:normalized
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _format
|
||||
"
|
||||
function! s:_format(string, compact) abort
|
||||
let l:string = a:string
|
||||
if a:compact
|
||||
let l:string = substitute(l:string, "\\%(\\s\\|\n\\)*```\\s*\\(\\w\\+\\)\\%(\\s\\|\n\\)\\+", "\n\n```\\1 ", 'g')
|
||||
let l:string = substitute(l:string, "\\%(\\s\\|\n\\)\\+```\\%(\\s*\\%(\\%$\\|\n\\)\\)\\+", " ```\n\n", 'g')
|
||||
else
|
||||
let l:string = substitute(l:string, "```\n\\zs\\%(\\s\\|\n\\)\\+", "", 'g')
|
||||
endif
|
||||
let l:string = substitute(l:string, "\\%^\\%(\\s\\|\n\\)*", '', 'g')
|
||||
let l:string = substitute(l:string, "\\%(\\s\\|\n\\)*\\%$", '', 'g')
|
||||
return l:string
|
||||
endfunction
|
||||
|
||||
23
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/LSP/Text.vim
Normal file
23
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/LSP/Text.vim
Normal file
@@ -0,0 +1,23 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not modify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_lsp#VS#LSP#Text#import() abort', printf("return map({'normalize_eol': '', 'split_by_eol': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" normalize_eol
|
||||
"
|
||||
function! s:normalize_eol(text) abort
|
||||
return substitute(a:text, "\r\n\\|\r", "\n", 'g')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" split_by_eol
|
||||
"
|
||||
function! s:split_by_eol(text) abort
|
||||
return split(a:text, "\r\n\\|\r\\|\n", v:true)
|
||||
endfunction
|
||||
|
||||
140
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/Vim/Buffer.vim
Normal file
140
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/Vim/Buffer.vim
Normal file
@@ -0,0 +1,140 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not modify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_lsp#VS#Vim#Buffer#import() abort', printf("return map({'add': '', 'do': '', 'create': '', 'get_line_count': '', 'pseudo': '', 'ensure': '', 'load': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
let s:Do = { -> {} }
|
||||
|
||||
let g:___VS_Vim_Buffer_id = get(g:, '___VS_Vim_Buffer_id', 0)
|
||||
|
||||
"
|
||||
" get_line_count
|
||||
"
|
||||
if exists('*nvim_buf_line_count')
|
||||
function! s:get_line_count(bufnr) abort
|
||||
return nvim_buf_line_count(a:bufnr)
|
||||
endfunction
|
||||
elseif has('patch-8.2.0019')
|
||||
function! s:get_line_count(bufnr) abort
|
||||
return getbufinfo(a:bufnr)[0].linecount
|
||||
endfunction
|
||||
else
|
||||
function! s:get_line_count(bufnr) abort
|
||||
if bufnr('%') == bufnr(a:bufnr)
|
||||
return line('$')
|
||||
endif
|
||||
return len(getbufline(a:bufnr, '^', '$'))
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" create
|
||||
"
|
||||
function! s:create(...) abort
|
||||
let g:___VS_Vim_Buffer_id += 1
|
||||
let l:bufname = printf('VS.Vim.Buffer: %s: %s',
|
||||
\ g:___VS_Vim_Buffer_id,
|
||||
\ get(a:000, 0, 'VS.Vim.Buffer.Default')
|
||||
\ )
|
||||
return s:load(l:bufname)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" ensure
|
||||
"
|
||||
function! s:ensure(expr) abort
|
||||
if !bufexists(a:expr)
|
||||
if type(a:expr) == type(0)
|
||||
throw printf('VS.Vim.Buffer: `%s` is not valid expr.', a:expr)
|
||||
endif
|
||||
call s:add(a:expr)
|
||||
endif
|
||||
return bufnr(a:expr)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" add
|
||||
"
|
||||
if exists('*bufadd')
|
||||
function! s:add(name) abort
|
||||
let l:bufnr = bufadd(a:name)
|
||||
call setbufvar(l:bufnr, '&buflisted', 1)
|
||||
endfunction
|
||||
else
|
||||
function! s:add(name) abort
|
||||
badd `=a:name`
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" load
|
||||
"
|
||||
if exists('*bufload')
|
||||
function! s:load(expr) abort
|
||||
let l:bufnr = s:ensure(a:expr)
|
||||
if !bufloaded(l:bufnr)
|
||||
call bufload(l:bufnr)
|
||||
endif
|
||||
return l:bufnr
|
||||
endfunction
|
||||
else
|
||||
function! s:load(expr) abort
|
||||
let l:curr_bufnr = bufnr('%')
|
||||
try
|
||||
let l:bufnr = s:ensure(a:expr)
|
||||
execute printf('keepalt keepjumps silent %sbuffer', l:bufnr)
|
||||
catch /.*/
|
||||
echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
|
||||
finally
|
||||
execute printf('noautocmd keepalt keepjumps silent %sbuffer', l:curr_bufnr)
|
||||
endtry
|
||||
return l:bufnr
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" do
|
||||
"
|
||||
function! s:do(bufnr, func) abort
|
||||
let l:curr_bufnr = bufnr('%')
|
||||
if l:curr_bufnr == a:bufnr
|
||||
call a:func()
|
||||
return
|
||||
endif
|
||||
|
||||
try
|
||||
execute printf('noautocmd keepalt keepjumps silent %sbuffer', a:bufnr)
|
||||
call a:func()
|
||||
catch /.*/
|
||||
echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
|
||||
finally
|
||||
execute printf('noautocmd keepalt keepjumps silent %sbuffer', l:curr_bufnr)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
"
|
||||
" pseudo
|
||||
"
|
||||
function! s:pseudo(filepath) abort
|
||||
if !filereadable(a:filepath)
|
||||
throw printf('VS.Vim.Buffer: `%s` is not valid filepath.', a:filepath)
|
||||
endif
|
||||
|
||||
" create pseudo buffer
|
||||
let l:bufname = printf('VSVimBufferPseudo://%s', a:filepath)
|
||||
if bufexists(l:bufname)
|
||||
return s:ensure(l:bufname)
|
||||
endif
|
||||
|
||||
let l:bufnr = s:ensure(l:bufname)
|
||||
let l:group = printf('VS_Vim_Buffer_pseudo:%s', l:bufnr)
|
||||
execute printf('augroup %s', l:group)
|
||||
execute printf('autocmd BufReadCmd <buffer=%s> call setline(1, readfile(bufname("%")[20 : -1])) | try | filetype detect | catch /.*/ | endtry | augroup %s | autocmd! | augroup END', l:bufnr, l:group)
|
||||
augroup END
|
||||
return l:bufnr
|
||||
endfunction
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not modify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_lsp#VS#Vim#Syntax#Markdown#import() abort', printf("return map({'apply': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" apply
|
||||
"
|
||||
" TODO: Refactor
|
||||
"
|
||||
function! s:apply(...) abort
|
||||
let l:args = get(a:000, 0, {})
|
||||
let l:text = has_key(l:args, 'text') ? l:args.text : getbufline('%', 1, '$')
|
||||
let l:text = type(l:text) == v:t_list ? join(l:text, "\n") : l:text
|
||||
|
||||
call s:_execute('syntax sync clear')
|
||||
if !exists('b:___VS_Vim_Syntax_Markdown')
|
||||
" Avoid automatic highlighting by built-in runtime syntax.
|
||||
if !has_key(g:, 'markdown_fenced_languages')
|
||||
call s:_execute('runtime! syntax/markdown.vim')
|
||||
else
|
||||
let l:markdown_fenced_languages = g:markdown_fenced_languages
|
||||
unlet g:markdown_fenced_languages
|
||||
call s:_execute('runtime! syntax/markdown.vim')
|
||||
let g:markdown_fenced_languages = l:markdown_fenced_languages
|
||||
endif
|
||||
|
||||
" Remove markdownCodeBlock because we support it manually.
|
||||
call s:_clear('markdownCodeBlock') " runtime
|
||||
call s:_clear('mkdCode') " plasticboy/vim-markdown
|
||||
|
||||
" Modify markdownCode (`codes...`)
|
||||
call s:_clear('markdownCode')
|
||||
syntax region markdownCode matchgroup=Conceal start=/\%(``\)\@!`/ matchgroup=Conceal end=/\%(``\)\@!`/ containedin=TOP keepend concealends
|
||||
|
||||
" Modify markdownEscape (_bold\_text_) @see nvim's syntax/lsp_markdown.vim
|
||||
call s:_clear('markdownEscape')
|
||||
syntax region markdownEscape matchgroup=markdownEscape start=/\\\ze[\\\x60*{}\[\]()#+\-,.!_>~|"$%&'\/:;<=?@^ ]/ end=/./ containedin=ALL keepend oneline concealends
|
||||
|
||||
" Add syntax for basic html entities.
|
||||
syntax match vital_vs_vim_syntax_markdown_entities_lt /</ containedin=ALL conceal cchar=<
|
||||
syntax match vital_vs_vim_syntax_markdown_entities_gt />/ containedin=ALL conceal cchar=>
|
||||
syntax match vital_vs_vim_syntax_markdown_entities_amp /&/ containedin=ALL conceal cchar=&
|
||||
syntax match vital_vs_vim_syntax_markdown_entities_quot /"/ containedin=ALL conceal cchar="
|
||||
syntax match vital_vs_vim_syntax_markdown_entities_nbsp / / containedin=ALL conceal cchar=
|
||||
|
||||
let b:___VS_Vim_Syntax_Markdown = {}
|
||||
let b:___VS_Vim_Syntax_Markdown.marks = {}
|
||||
let b:___VS_Vim_Syntax_Markdown.filetypes = {}
|
||||
endif
|
||||
|
||||
for [l:mark, l:filetype] in items(s:_get_filetype_map(l:text))
|
||||
try
|
||||
let l:mark_group = substitute(toupper(l:mark), '\.', '_', 'g')
|
||||
if has_key(b:___VS_Vim_Syntax_Markdown.marks, l:mark_group)
|
||||
continue
|
||||
endif
|
||||
let b:___VS_Vim_Syntax_Markdown.marks[l:mark_group] = v:true
|
||||
|
||||
let l:filetype_group = substitute(toupper(l:filetype), '\.', '_', 'g')
|
||||
if !has_key(b:___VS_Vim_Syntax_Markdown.filetypes, l:filetype_group)
|
||||
call s:_execute('syntax include @%s syntax/%s.vim', l:filetype_group, l:filetype)
|
||||
let b:___VS_Vim_Syntax_Markdown.filetypes[l:filetype_group] = v:true
|
||||
endif
|
||||
|
||||
call s:_execute('syntax region %s matchgroup=Conceal start=/%s/ matchgroup=Conceal end=/%s/ contains=@%s containedin=TOP keepend concealends',
|
||||
\ l:mark_group,
|
||||
\ printf('```\s*%s\s*', l:mark),
|
||||
\ '```\s*\%(' . "\n" . '\|$\)',
|
||||
\ l:filetype_group
|
||||
\ )
|
||||
catch /.*/
|
||||
unsilent echomsg printf('Fail to apply "syntax/%s.vim". Add "let g:markdown_fenced_languages = ["%s=$FILETYPE"]" to enable syntax', l:filetype, l:filetype)
|
||||
endtry
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _clear
|
||||
"
|
||||
function! s:_clear(group) abort
|
||||
try
|
||||
execute printf('silent! syntax clear %s', a:group)
|
||||
catch /.*/
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _execute
|
||||
"
|
||||
function! s:_execute(command, ...) abort
|
||||
let b:current_syntax = ''
|
||||
unlet b:current_syntax
|
||||
|
||||
let g:main_syntax = ''
|
||||
unlet g:main_syntax
|
||||
|
||||
execute call('printf', [a:command] + a:000)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _get_filetype_map
|
||||
"
|
||||
function! s:_get_filetype_map(text) abort
|
||||
let l:filetype_map = {}
|
||||
for l:mark in s:_find_marks(a:text)
|
||||
let l:filetype_map[l:mark] = s:_get_filetype_from_mark(l:mark)
|
||||
endfor
|
||||
return l:filetype_map
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _find_marks
|
||||
"
|
||||
function! s:_find_marks(text) abort
|
||||
let l:marks = {}
|
||||
|
||||
" find from buffer contents.
|
||||
let l:text = a:text
|
||||
let l:pos = 0
|
||||
while 1
|
||||
let l:match = matchstrpos(l:text, '```\s*\zs\w\+', l:pos, 1)
|
||||
if empty(l:match[0])
|
||||
break
|
||||
endif
|
||||
let l:marks[l:match[0]] = v:true
|
||||
let l:pos = l:match[2]
|
||||
endwhile
|
||||
|
||||
return keys(l:marks)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _get_filetype_from_mark
|
||||
"
|
||||
function! s:_get_filetype_from_mark(mark) abort
|
||||
for l:config in get(g:, 'markdown_fenced_languages', [])
|
||||
if l:config !~# '='
|
||||
if l:config ==# a:mark
|
||||
return a:mark
|
||||
endif
|
||||
else
|
||||
let l:config = split(l:config, '=')
|
||||
if l:config[0] ==# a:mark
|
||||
return l:config[1]
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
return a:mark
|
||||
endfunction
|
||||
|
||||
157
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/Vim/Window.vim
Normal file
157
dot_vim/plugged/vim-lsp/autoload/vital/_lsp/VS/Vim/Window.vim
Normal file
@@ -0,0 +1,157 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not modify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_lsp#VS#Vim#Window#import() abort', printf("return map({'info': '', 'do': '', 'is_floating': '', 'find': '', 'scroll': '', 'screenpos': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
let s:Do = { -> {} }
|
||||
|
||||
"
|
||||
" do
|
||||
"
|
||||
function! s:do(winid, func) abort
|
||||
let l:curr_winid = win_getid()
|
||||
if l:curr_winid == a:winid
|
||||
call a:func()
|
||||
return
|
||||
endif
|
||||
|
||||
if !has('nvim') && exists('*win_execute')
|
||||
let s:Do = a:func
|
||||
try
|
||||
noautocmd keepalt keepjumps call win_execute(a:winid, 'call s:Do()')
|
||||
catch /.*/
|
||||
echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
|
||||
endtry
|
||||
unlet s:Do
|
||||
return
|
||||
endif
|
||||
|
||||
noautocmd keepalt keepjumps call win_gotoid(a:winid)
|
||||
try
|
||||
call a:func()
|
||||
catch /.*/
|
||||
echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint })
|
||||
endtry
|
||||
noautocmd keepalt keepjumps call win_gotoid(l:curr_winid)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" info
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:info(winid) abort
|
||||
let l:info = getwininfo(a:winid)[0]
|
||||
return {
|
||||
\ 'width': l:info.width,
|
||||
\ 'height': l:info.height,
|
||||
\ 'topline': l:info.topline,
|
||||
\ }
|
||||
endfunction
|
||||
else
|
||||
function! s:info(winid) abort
|
||||
if s:is_floating(a:winid)
|
||||
let l:info = popup_getpos(a:winid)
|
||||
return {
|
||||
\ 'width': l:info.width,
|
||||
\ 'height': l:info.height,
|
||||
\ 'topline': l:info.firstline
|
||||
\ }
|
||||
endif
|
||||
|
||||
let l:ctx = {}
|
||||
let l:ctx.info = {}
|
||||
function! l:ctx.callback() abort
|
||||
let self.info.width = winwidth(0)
|
||||
let self.info.height = winheight(0)
|
||||
let self.info.topline = line('w0')
|
||||
endfunction
|
||||
call s:do(a:winid, { -> l:ctx.callback() })
|
||||
return l:ctx.info
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" find
|
||||
"
|
||||
function! s:find(callback) abort
|
||||
let l:winids = []
|
||||
let l:winids += map(range(1, tabpagewinnr(tabpagenr(), '$')), 'win_getid(v:val)')
|
||||
let l:winids += s:_get_visible_popup_winids()
|
||||
return filter(l:winids, 'a:callback(v:val)')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" is_floating
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:is_floating(winid) abort
|
||||
let l:config = nvim_win_get_config(a:winid)
|
||||
return empty(l:config) || !empty(get(l:config, 'relative', ''))
|
||||
endfunction
|
||||
else
|
||||
function! s:is_floating(winid) abort
|
||||
return winheight(a:winid) != -1 && win_id2win(a:winid) == 0
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" scroll
|
||||
"
|
||||
function! s:scroll(winid, topline) abort
|
||||
let l:ctx = {}
|
||||
function! l:ctx.callback(winid, topline) abort
|
||||
let l:wininfo = s:info(a:winid)
|
||||
let l:topline = a:topline
|
||||
let l:topline = min([l:topline, line('$') - l:wininfo.height + 1])
|
||||
let l:topline = max([l:topline, 1])
|
||||
|
||||
if l:topline == l:wininfo.topline
|
||||
return
|
||||
endif
|
||||
|
||||
if !has('nvim') && s:is_floating(a:winid)
|
||||
call popup_setoptions(a:winid, {
|
||||
\ 'firstline': l:topline,
|
||||
\ })
|
||||
else
|
||||
let l:delta = l:topline - l:wininfo.topline
|
||||
let l:key = l:delta > 0 ? "\<C-e>" : "\<C-y>"
|
||||
execute printf('noautocmd silent normal! %s', repeat(l:key, abs(l:delta)))
|
||||
endif
|
||||
endfunction
|
||||
call s:do(a:winid, { -> l:ctx.callback(a:winid, a:topline) })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" screenpos
|
||||
"
|
||||
" @param {[number, number]} pos - position on the current buffer.
|
||||
"
|
||||
function! s:screenpos(pos) abort
|
||||
let l:y = a:pos[0]
|
||||
let l:x = a:pos[1] + get(a:pos, 2, 0)
|
||||
|
||||
let l:view = winsaveview()
|
||||
let l:scroll_x = l:view.leftcol
|
||||
let l:scroll_y = l:view.topline
|
||||
|
||||
let l:winpos = win_screenpos(win_getid())
|
||||
let l:y = l:winpos[0] + l:y - l:scroll_y
|
||||
let l:x = l:winpos[1] + l:x - l:scroll_x
|
||||
return [l:y, l:x + (wincol() - virtcol('.')) - 1]
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _get_visible_popup_winids
|
||||
"
|
||||
function! s:_get_visible_popup_winids() abort
|
||||
if !exists('*popup_list')
|
||||
return []
|
||||
endif
|
||||
return filter(popup_list(), 'popup_getpos(v:val).visible')
|
||||
endfunction
|
||||
|
||||
@@ -0,0 +1,515 @@
|
||||
" ___vital___
|
||||
" NOTE: lines between '" ___vital___' is generated by :Vitalize.
|
||||
" Do not modify the code nor insert new lines before '" ___vital___'
|
||||
function! s:_SID() abort
|
||||
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
||||
endfunction
|
||||
execute join(['function! vital#_lsp#VS#Vim#Window#FloatingWindow#import() abort', printf("return map({'_vital_depends': '', 'is_available': '', 'new': '', '_vital_loaded': ''}, \"vital#_lsp#function('<SNR>%s_' . v:key)\")", s:_SID()), 'endfunction'], "\n")
|
||||
delfunction s:_SID
|
||||
" ___vital___
|
||||
"
|
||||
" _vital_loaded
|
||||
"
|
||||
function! s:_vital_loaded(V) abort
|
||||
let s:Window = a:V.import('VS.Vim.Window')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _vital_depends
|
||||
"
|
||||
function! s:_vital_depends() abort
|
||||
return ['VS.Vim.Window']
|
||||
endfunction
|
||||
|
||||
"
|
||||
" managed floating windows.
|
||||
"
|
||||
let s:floating_windows = {}
|
||||
|
||||
"
|
||||
" is_available
|
||||
"
|
||||
function! s:is_available() abort
|
||||
if has('nvim')
|
||||
return v:true
|
||||
endif
|
||||
return exists('*popup_create') && exists('*popup_close') && exists('*popup_move') && exists('*popup_getpos')
|
||||
endfunction
|
||||
|
||||
"
|
||||
" new
|
||||
"
|
||||
function! s:new(...) abort
|
||||
call s:_init()
|
||||
|
||||
return s:FloatingWindow.new(get(a:000, 0, {}))
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _notify_opened
|
||||
"
|
||||
" @param {number} winid
|
||||
" @param {VS.Vim.Window.FloatingWindow} floating_window
|
||||
"
|
||||
function! s:_notify_opened(winid, floating_window) abort
|
||||
let s:floating_windows[a:winid] = a:floating_window
|
||||
call a:floating_window._on_opened()
|
||||
endfunction
|
||||
|
||||
"
|
||||
" _notify_closed
|
||||
"
|
||||
function! s:_notify_closed() abort
|
||||
for [l:winid, l:floating_window] in items(s:floating_windows)
|
||||
if winheight(l:winid) == -1
|
||||
call l:floating_window._on_closed()
|
||||
unlet s:floating_windows[l:winid]
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
let s:FloatingWindow = {}
|
||||
|
||||
"
|
||||
" new
|
||||
"
|
||||
" @param {function?} args.on_opened
|
||||
" @param {function?} args.on_closed
|
||||
"
|
||||
function! s:FloatingWindow.new(args) abort
|
||||
return extend(deepcopy(s:FloatingWindow), {
|
||||
\ '_winid': v:null,
|
||||
\ '_bufnr': v:null,
|
||||
\ '_vars': {},
|
||||
\ '_on_opened': get(a:args, 'on_opened', { -> {} }),
|
||||
\ '_on_closed': get(a:args, 'on_closed', { -> {} }),
|
||||
\ })
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_size
|
||||
"
|
||||
" @param {number?} args.minwidth
|
||||
" @param {number?} args.maxwidth
|
||||
" @param {number?} args.minheight
|
||||
" @param {number?} args.maxheight
|
||||
" @param {boolean?} args.wrap
|
||||
"
|
||||
function! s:FloatingWindow.get_size(args) abort
|
||||
if self._bufnr is# v:null
|
||||
throw 'VS.Vim.Window.FloatingWindow: Failed to detect bufnr.'
|
||||
endif
|
||||
|
||||
let l:maxwidth = get(a:args, 'maxwidth', -1)
|
||||
let l:minwidth = get(a:args, 'minwidth', -1)
|
||||
let l:maxheight = get(a:args, 'maxheight', -1)
|
||||
let l:minheight = get(a:args, 'minheight', -1)
|
||||
let l:lines = getbufline(self._bufnr, '^', '$')
|
||||
|
||||
" width
|
||||
let l:width = 0
|
||||
for l:line in l:lines
|
||||
let l:width = max([l:width, strdisplaywidth(l:line)])
|
||||
endfor
|
||||
|
||||
let l:width = l:minwidth == -1 ? l:width : max([l:minwidth, l:width])
|
||||
let l:width = l:maxwidth == -1 ? l:width : min([l:maxwidth, l:width])
|
||||
|
||||
" height
|
||||
if get(a:args, 'wrap', get(self._vars, '&wrap', 0))
|
||||
let l:height = 0
|
||||
for l:line in l:lines
|
||||
let l:height += max([1, float2nr(ceil(strdisplaywidth(l:line) / str2float('' . l:width)))])
|
||||
endfor
|
||||
else
|
||||
let l:height = len(l:lines)
|
||||
endif
|
||||
let l:height = l:minheight == -1 ? l:height : max([l:minheight, l:height])
|
||||
let l:height = l:maxheight == -1 ? l:height : min([l:maxheight, l:height])
|
||||
|
||||
return {
|
||||
\ 'width': max([1, l:width]),
|
||||
\ 'height': max([1, l:height]),
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
"
|
||||
" set_bufnr
|
||||
"
|
||||
" @param {number} bufnr
|
||||
"
|
||||
function! s:FloatingWindow.set_bufnr(bufnr) abort
|
||||
let self._bufnr = a:bufnr
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_bufnr
|
||||
"
|
||||
function! s:FloatingWindow.get_bufnr() abort
|
||||
return self._bufnr
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_winid
|
||||
"
|
||||
function! s:FloatingWindow.get_winid() abort
|
||||
if self.is_visible()
|
||||
return self._winid
|
||||
endif
|
||||
return v:null
|
||||
endfunction
|
||||
|
||||
"
|
||||
" info
|
||||
"
|
||||
function! s:FloatingWindow.info() abort
|
||||
if self.is_visible()
|
||||
return s:_info(self._winid)
|
||||
endif
|
||||
return v:null
|
||||
endfunction
|
||||
|
||||
"
|
||||
" set_var
|
||||
"
|
||||
" @param {string} key
|
||||
" @param {unknown} value
|
||||
"
|
||||
function! s:FloatingWindow.set_var(key, value) abort
|
||||
let self._vars[a:key] = a:value
|
||||
if self.is_visible()
|
||||
call setwinvar(self._winid, a:key, a:value)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" get_var
|
||||
"
|
||||
" @param {string} key
|
||||
"
|
||||
function! s:FloatingWindow.get_var(key) abort
|
||||
return self._vars[a:key]
|
||||
endfunction
|
||||
|
||||
"
|
||||
" open
|
||||
"
|
||||
" @param {number} args.row 0-based indexing
|
||||
" @param {number} args.col 0-based indexing
|
||||
" @param {number} args.width
|
||||
" @param {number} args.height
|
||||
" @param {boolean|[string]?} args.border - boolean, or list of characters
|
||||
" clockwise from top-left (same as nvim_open_win() in neovim)
|
||||
" @param {number?} args.topline
|
||||
" @param {string?} args.origin - topleft/topright/botleft/botright
|
||||
"
|
||||
function! s:FloatingWindow.open(args) abort
|
||||
let l:style = {
|
||||
\ 'row': a:args.row,
|
||||
\ 'col': a:args.col,
|
||||
\ 'width': a:args.width,
|
||||
\ 'height': a:args.height,
|
||||
\ 'border': get(a:args, 'border', v:false),
|
||||
\ 'topline': get(a:args, 'topline', 1),
|
||||
\ 'origin': get(a:args, 'origin', 'topleft'),
|
||||
\ }
|
||||
|
||||
let l:will_move = self.is_visible()
|
||||
if l:will_move
|
||||
let self._winid = s:_move(self, self._winid, self._bufnr, l:style)
|
||||
else
|
||||
let self._winid = s:_open(self._bufnr, l:style, { -> self._on_closed() })
|
||||
endif
|
||||
for [l:key, l:value] in items(self._vars)
|
||||
call setwinvar(self._winid, l:key, l:value)
|
||||
endfor
|
||||
if !l:will_move
|
||||
call s:_notify_opened(self._winid, self)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
"
|
||||
" close
|
||||
"
|
||||
function! s:FloatingWindow.close() abort
|
||||
if self.is_visible()
|
||||
call s:_close(self._winid)
|
||||
endif
|
||||
let self._winid = v:null
|
||||
endfunction
|
||||
|
||||
"
|
||||
" enter
|
||||
"
|
||||
function! s:FloatingWindow.enter() abort
|
||||
call s:_enter(self._winid)
|
||||
endfunction
|
||||
|
||||
"
|
||||
" is_visible
|
||||
"
|
||||
function! s:FloatingWindow.is_visible() abort
|
||||
return s:_exists(self._winid) ? v:true : v:false
|
||||
endfunction
|
||||
|
||||
"
|
||||
" open
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_open(bufnr, style, callback) abort
|
||||
let l:winid = nvim_open_win(a:bufnr, v:false, s:_style(a:style))
|
||||
call s:Window.scroll(l:winid, a:style.topline)
|
||||
return l:winid
|
||||
endfunction
|
||||
else
|
||||
function! s:_open(bufnr, style, callback) abort
|
||||
return popup_create(a:bufnr, extend(s:_style(a:style), {
|
||||
\ 'callback': a:callback,
|
||||
\ }, 'force'))
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" close
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_close(winid) abort
|
||||
call nvim_win_close(a:winid, v:true)
|
||||
call s:_notify_closed()
|
||||
endfunction
|
||||
else
|
||||
function! s:_close(winid) abort
|
||||
call popup_close(a:winid)
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" move
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_move(self, winid, bufnr, style) abort
|
||||
call nvim_win_set_config(a:winid, s:_style(a:style))
|
||||
if a:bufnr != nvim_win_get_buf(a:winid)
|
||||
call nvim_win_set_buf(a:winid, a:bufnr)
|
||||
endif
|
||||
call s:Window.scroll(a:winid, a:style.topline)
|
||||
return a:winid
|
||||
endfunction
|
||||
else
|
||||
function! s:_move(self, winid, bufnr, style) abort
|
||||
" vim's popup window can't change bufnr so open new popup in here.
|
||||
if a:bufnr != winbufnr(a:winid)
|
||||
let l:On_closed = a:self._on_closed
|
||||
let a:self._on_closed = { -> {} }
|
||||
call s:_close(a:winid)
|
||||
let a:self._on_closed = l:On_closed
|
||||
return s:_open(a:bufnr, a:style, { -> a:self._on_closed() })
|
||||
endif
|
||||
let l:style = s:_style(a:style)
|
||||
call popup_move(a:winid, l:style)
|
||||
call popup_setoptions(a:winid, l:style)
|
||||
return a:winid
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" enter
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_enter(winid) abort
|
||||
call win_gotoid(a:winid)
|
||||
endfunction
|
||||
else
|
||||
function! s:_enter(winid) abort
|
||||
" not supported.
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" exists
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_exists(winid) abort
|
||||
try
|
||||
return type(a:winid) == type(0) && nvim_win_is_valid(a:winid) && nvim_win_get_number(a:winid) != -1
|
||||
catch /.*/
|
||||
return v:false
|
||||
endtry
|
||||
endfunction
|
||||
else
|
||||
function! s:_exists(winid) abort
|
||||
return type(a:winid) == type(0) && winheight(a:winid) != -1
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" info
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_info(winid) abort
|
||||
let l:info = getwininfo(a:winid)[0]
|
||||
return {
|
||||
\ 'row': l:info.winrow,
|
||||
\ 'col': l:info.wincol,
|
||||
\ 'width': l:info.width,
|
||||
\ 'height': l:info.height,
|
||||
\ 'topline': l:info.topline,
|
||||
\ }
|
||||
endfunction
|
||||
else
|
||||
function! s:_info(winid) abort
|
||||
let l:pos = popup_getpos(a:winid)
|
||||
return {
|
||||
\ 'row': l:pos.core_line,
|
||||
\ 'col': l:pos.core_col,
|
||||
\ 'width': l:pos.core_width,
|
||||
\ 'height': l:pos.core_height,
|
||||
\ 'topline': l:pos.firstline,
|
||||
\ }
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" style
|
||||
"
|
||||
if has('nvim')
|
||||
function! s:_style(style) abort
|
||||
let l:style = s:_resolve_origin(a:style)
|
||||
let l:style = s:_resolve_border(l:style)
|
||||
let l:style = {
|
||||
\ 'relative': 'editor',
|
||||
\ 'row': l:style.row - 1,
|
||||
\ 'col': l:style.col - 1,
|
||||
\ 'width': l:style.width,
|
||||
\ 'height': l:style.height,
|
||||
\ 'focusable': v:true,
|
||||
\ 'style': 'minimal',
|
||||
\ 'border': has_key(l:style, 'border') ? l:style.border : 'none',
|
||||
\ }
|
||||
if !exists('*win_execute') " We can't detect neovim features via patch version so we try it by function existence.
|
||||
unlet l:style.border
|
||||
endif
|
||||
return l:style
|
||||
endfunction
|
||||
else
|
||||
function! s:_style(style) abort
|
||||
let l:style = s:_resolve_origin(a:style)
|
||||
let l:style = s:_resolve_border(l:style)
|
||||
return {
|
||||
\ 'line': l:style.row,
|
||||
\ 'col': l:style.col,
|
||||
\ 'pos': 'topleft',
|
||||
\ 'wrap': v:false,
|
||||
\ 'moved': [0, 0, 0],
|
||||
\ 'scrollbar': 0,
|
||||
\ 'maxwidth': l:style.width,
|
||||
\ 'maxheight': l:style.height,
|
||||
\ 'minwidth': l:style.width,
|
||||
\ 'minheight': l:style.height,
|
||||
\ 'tabpage': 0,
|
||||
\ 'firstline': l:style.topline,
|
||||
\ 'padding': [0, 0, 0, 0],
|
||||
\ 'border': has_key(l:style, 'border') ? [1, 1, 1, 1] : [0, 0, 0, 0],
|
||||
\ 'borderchars': get(l:style, 'border', []),
|
||||
\ 'fixed': v:true,
|
||||
\ }
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" _resolve_origin
|
||||
"
|
||||
function! s:_resolve_origin(style) abort
|
||||
if index(['topleft', 'topright', 'bottomleft', 'bottomright', 'topcenter', 'bottomcenter'], a:style.origin) == -1
|
||||
let a:style.origin = 'topleft'
|
||||
endif
|
||||
|
||||
if a:style.origin ==# 'topleft'
|
||||
let a:style.col = a:style.col
|
||||
let a:style.row = a:style.row
|
||||
elseif a:style.origin ==# 'topright'
|
||||
let a:style.col = a:style.col - (a:style.width - 1)
|
||||
let a:style.row = a:style.row
|
||||
elseif a:style.origin ==# 'bottomleft'
|
||||
let a:style.col = a:style.col
|
||||
let a:style.row = a:style.row - (a:style.height - 1)
|
||||
elseif a:style.origin ==# 'bottomright'
|
||||
let a:style.col = a:style.col - (a:style.width - 1)
|
||||
let a:style.row = a:style.row - (a:style.height - 1)
|
||||
elseif a:style.origin ==# 'topcenter'
|
||||
let a:style.col = a:style.col - float2nr(a:style.width / 2)
|
||||
let a:style.row = a:style.row
|
||||
elseif a:style.origin ==# 'bottomcenter'
|
||||
let a:style.col = a:style.col - float2nr(a:style.width / 2)
|
||||
let a:style.row = a:style.row - (a:style.height - 1)
|
||||
elseif a:style.origin ==# 'centercenter'
|
||||
let a:style.col = a:style.col - float2nr(a:style.width / 2)
|
||||
let a:style.row = a:style.row - float2nr(a:style.height / 2)
|
||||
endif
|
||||
return a:style
|
||||
endfunction
|
||||
|
||||
if has('nvim')
|
||||
function! s:_resolve_border(style) abort
|
||||
let l:border = get(a:style, 'border', v:null)
|
||||
if !empty(l:border)
|
||||
if type(l:border) != type([])
|
||||
if &ambiwidth ==# 'single'
|
||||
let a:style.border = ['┌', '─', '┐', '│', '┘', '─', '└', '│']
|
||||
else
|
||||
let a:style.border = ['+', '-', '+', '|', '+', '-', '+', '|']
|
||||
endif
|
||||
endif
|
||||
elseif has_key(a:style, 'border')
|
||||
unlet a:style.border
|
||||
endif
|
||||
return a:style
|
||||
endfunction
|
||||
else
|
||||
function! s:_resolve_border(style) abort
|
||||
let l:border = get(a:style, 'border', v:null)
|
||||
if !empty(get(a:style, 'border', v:null))
|
||||
if type(l:border) != type([])
|
||||
if &ambiwidth ==# 'single'
|
||||
let a:style.border = ['─', '│', '─', '│', '┌', '┐', '┘', '└']
|
||||
else
|
||||
let a:style.border = ['-', '|', '-', '|', '+', '+', '+', '+']
|
||||
endif
|
||||
else
|
||||
" Emulate nvim behavior for lists of 1/2/4 elements
|
||||
let l:topleft = l:border[0]
|
||||
let l:top = get(l:border, 1, l:topleft)
|
||||
let l:topright = get(l:border, 2, l:topleft)
|
||||
let l:right = get(l:border, 3, l:top)
|
||||
let l:bottomright = get(l:border, 4, l:topleft)
|
||||
let l:bottom = get(l:border, 5, l:top)
|
||||
let l:bottomleft = get(l:border, 6, l:topright)
|
||||
let l:left = get(l:border, 7, l:right)
|
||||
let a:style.border = [
|
||||
\ l:top, l:right, l:bottom, l:left,
|
||||
\ l:topleft, l:topright, l:bottomright, l:bottomleft,
|
||||
\ ]
|
||||
endif
|
||||
elseif has_key(a:style, 'border')
|
||||
unlet a:style.border
|
||||
endif
|
||||
return a:style
|
||||
endfunction
|
||||
endif
|
||||
|
||||
"
|
||||
" init
|
||||
"
|
||||
let s:has_init = v:false
|
||||
let s:filepath = expand('<sfile>:p')
|
||||
function! s:_init() abort
|
||||
if s:has_init || !has('nvim')
|
||||
return
|
||||
endif
|
||||
let s:has_init = v:true
|
||||
execute printf('augroup VS_Vim_Window_FloatingWindow:%s', s:filepath)
|
||||
autocmd!
|
||||
autocmd WinEnter * call <SID>_notify_closed()
|
||||
augroup END
|
||||
endfunction
|
||||
|
||||
334
dot_vim/plugged/vim-lsp/autoload/vital/lsp.vim
Normal file
334
dot_vim/plugged/vim-lsp/autoload/vital/lsp.vim
Normal file
@@ -0,0 +1,334 @@
|
||||
let s:plugin_name = expand('<sfile>:t:r')
|
||||
let s:vital_base_dir = expand('<sfile>:h')
|
||||
let s:project_root = expand('<sfile>:h:h:h')
|
||||
let s:is_vital_vim = s:plugin_name is# 'vital'
|
||||
|
||||
let s:loaded = {}
|
||||
let s:cache_sid = {}
|
||||
|
||||
function! vital#{s:plugin_name}#new() abort
|
||||
return s:new(s:plugin_name)
|
||||
endfunction
|
||||
|
||||
function! vital#{s:plugin_name}#import(...) abort
|
||||
if !exists('s:V')
|
||||
let s:V = s:new(s:plugin_name)
|
||||
endif
|
||||
return call(s:V.import, a:000, s:V)
|
||||
endfunction
|
||||
|
||||
let s:Vital = {}
|
||||
|
||||
function! s:new(plugin_name) abort
|
||||
let base = deepcopy(s:Vital)
|
||||
let base._plugin_name = a:plugin_name
|
||||
return base
|
||||
endfunction
|
||||
|
||||
function! s:vital_files() abort
|
||||
if !exists('s:vital_files')
|
||||
let s:vital_files = map(
|
||||
\ s:is_vital_vim ? s:_global_vital_files() : s:_self_vital_files(),
|
||||
\ 'fnamemodify(v:val, ":p:gs?[\\\\/]?/?")')
|
||||
endif
|
||||
return copy(s:vital_files)
|
||||
endfunction
|
||||
let s:Vital.vital_files = function('s:vital_files')
|
||||
|
||||
function! s:import(name, ...) abort dict
|
||||
let target = {}
|
||||
let functions = []
|
||||
for a in a:000
|
||||
if type(a) == type({})
|
||||
let target = a
|
||||
elseif type(a) == type([])
|
||||
let functions = a
|
||||
endif
|
||||
unlet a
|
||||
endfor
|
||||
let module = self._import(a:name)
|
||||
if empty(functions)
|
||||
call extend(target, module, 'keep')
|
||||
else
|
||||
for f in functions
|
||||
if has_key(module, f) && !has_key(target, f)
|
||||
let target[f] = module[f]
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
return target
|
||||
endfunction
|
||||
let s:Vital.import = function('s:import')
|
||||
|
||||
function! s:load(...) abort dict
|
||||
for arg in a:000
|
||||
let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg]
|
||||
let target = split(join(as, ''), '\W\+')
|
||||
let dict = self
|
||||
let dict_type = type({})
|
||||
while !empty(target)
|
||||
let ns = remove(target, 0)
|
||||
if !has_key(dict, ns)
|
||||
let dict[ns] = {}
|
||||
endif
|
||||
if type(dict[ns]) == dict_type
|
||||
let dict = dict[ns]
|
||||
else
|
||||
unlet dict
|
||||
break
|
||||
endif
|
||||
endwhile
|
||||
if exists('dict')
|
||||
call extend(dict, self._import(name))
|
||||
endif
|
||||
unlet arg
|
||||
endfor
|
||||
return self
|
||||
endfunction
|
||||
let s:Vital.load = function('s:load')
|
||||
|
||||
function! s:unload() abort dict
|
||||
let s:loaded = {}
|
||||
let s:cache_sid = {}
|
||||
unlet! s:vital_files
|
||||
endfunction
|
||||
let s:Vital.unload = function('s:unload')
|
||||
|
||||
function! s:exists(name) abort dict
|
||||
if a:name !~# '\v^\u\w*%(\.\u\w*)*$'
|
||||
throw 'vital: Invalid module name: ' . a:name
|
||||
endif
|
||||
return s:_module_path(a:name) isnot# ''
|
||||
endfunction
|
||||
let s:Vital.exists = function('s:exists')
|
||||
|
||||
function! s:search(pattern) abort dict
|
||||
let paths = s:_extract_files(a:pattern, self.vital_files())
|
||||
let modules = sort(map(paths, 's:_file2module(v:val)'))
|
||||
return uniq(modules)
|
||||
endfunction
|
||||
let s:Vital.search = function('s:search')
|
||||
|
||||
function! s:plugin_name() abort dict
|
||||
return self._plugin_name
|
||||
endfunction
|
||||
let s:Vital.plugin_name = function('s:plugin_name')
|
||||
|
||||
function! s:_self_vital_files() abort
|
||||
let builtin = printf('%s/__%s__/', s:vital_base_dir, s:plugin_name)
|
||||
let installed = printf('%s/_%s/', s:vital_base_dir, s:plugin_name)
|
||||
let base = builtin . ',' . installed
|
||||
return split(globpath(base, '**/*.vim', 1), "\n")
|
||||
endfunction
|
||||
|
||||
function! s:_global_vital_files() abort
|
||||
let pattern = 'autoload/vital/__*__/**/*.vim'
|
||||
return split(globpath(&runtimepath, pattern, 1), "\n")
|
||||
endfunction
|
||||
|
||||
function! s:_extract_files(pattern, files) abort
|
||||
let tr = {'.': '/', '*': '[^/]*', '**': '.*'}
|
||||
let target = substitute(a:pattern, '\.\|\*\*\?', '\=tr[submatch(0)]', 'g')
|
||||
let regexp = printf('autoload/vital/[^/]\+/%s.vim$', target)
|
||||
return filter(a:files, 'v:val =~# regexp')
|
||||
endfunction
|
||||
|
||||
function! s:_file2module(file) abort
|
||||
let filename = fnamemodify(a:file, ':p:gs?[\\/]?/?')
|
||||
let tail = matchstr(filename, 'autoload/vital/_\w\+/\zs.*\ze\.vim$')
|
||||
return join(split(tail, '[\\/]\+'), '.')
|
||||
endfunction
|
||||
|
||||
" @param {string} name e.g. Data.List
|
||||
function! s:_import(name) abort dict
|
||||
if has_key(s:loaded, a:name)
|
||||
return copy(s:loaded[a:name])
|
||||
endif
|
||||
let module = self._get_module(a:name)
|
||||
if has_key(module, '_vital_created')
|
||||
call module._vital_created(module)
|
||||
endif
|
||||
let export_module = filter(copy(module), 'v:key =~# "^\\a"')
|
||||
" Cache module before calling module._vital_loaded() to avoid cyclic
|
||||
" dependences but remove the cache if module._vital_loaded() fails.
|
||||
" let s:loaded[a:name] = export_module
|
||||
let s:loaded[a:name] = export_module
|
||||
if has_key(module, '_vital_loaded')
|
||||
try
|
||||
call module._vital_loaded(vital#{s:plugin_name}#new())
|
||||
catch
|
||||
unlet s:loaded[a:name]
|
||||
throw 'vital: fail to call ._vital_loaded(): ' . v:exception . " from:\n" . s:_format_throwpoint(v:throwpoint)
|
||||
endtry
|
||||
endif
|
||||
return copy(s:loaded[a:name])
|
||||
endfunction
|
||||
let s:Vital._import = function('s:_import')
|
||||
|
||||
function! s:_format_throwpoint(throwpoint) abort
|
||||
let funcs = []
|
||||
let stack = matchstr(a:throwpoint, '^function \zs.*, .\{-} \d\+$')
|
||||
for line in split(stack, '\.\.')
|
||||
let m = matchlist(line, '^\(.\+\)\%(\[\(\d\+\)\]\|, .\{-} \(\d\+\)\)$')
|
||||
if !empty(m)
|
||||
let [name, lnum, lnum2] = m[1:3]
|
||||
if empty(lnum)
|
||||
let lnum = lnum2
|
||||
endif
|
||||
let info = s:_get_func_info(name)
|
||||
if !empty(info)
|
||||
let attrs = empty(info.attrs) ? '' : join([''] + info.attrs)
|
||||
let flnum = info.lnum == 0 ? '' : printf(' Line:%d', info.lnum + lnum)
|
||||
call add(funcs, printf('function %s(...)%s Line:%d (%s%s)',
|
||||
\ info.funcname, attrs, lnum, info.filename, flnum))
|
||||
continue
|
||||
endif
|
||||
endif
|
||||
" fallback when function information cannot be detected
|
||||
call add(funcs, line)
|
||||
endfor
|
||||
return join(funcs, "\n")
|
||||
endfunction
|
||||
|
||||
" @vimlint(EVL102, 1, l:_)
|
||||
" @vimlint(EVL102, 1, l:__)
|
||||
function! s:_get_func_info(name) abort
|
||||
let name = a:name
|
||||
if a:name =~# '^\d\+$' " is anonymous-function
|
||||
let name = printf('{%s}', a:name)
|
||||
elseif a:name =~# '^<lambda>\d\+$' " is lambda-function
|
||||
let name = printf("{'%s'}", a:name)
|
||||
endif
|
||||
if !exists('*' . name)
|
||||
return {}
|
||||
endif
|
||||
let body = execute(printf('verbose function %s', name))
|
||||
let lines = split(body, "\n")
|
||||
let signature = matchstr(lines[0], '^\s*\zs.*')
|
||||
let [_, file, lnum; __] = matchlist(lines[1],
|
||||
\ '^\t\%(Last set from\|.\{-}:\)\s*\zs\(.\{-}\)\%( \S\+ \(\d\+\)\)\?$')
|
||||
return {
|
||||
\ 'filename': substitute(file, '[/\\]\+', '/', 'g'),
|
||||
\ 'lnum': 0 + lnum,
|
||||
\ 'funcname': a:name,
|
||||
\ 'arguments': split(matchstr(signature, '(\zs.*\ze)'), '\s*,\s*'),
|
||||
\ 'attrs': filter(['dict', 'abort', 'range', 'closure'], 'signature =~# (").*" . v:val)'),
|
||||
\ }
|
||||
endfunction
|
||||
" @vimlint(EVL102, 0, l:__)
|
||||
" @vimlint(EVL102, 0, l:_)
|
||||
|
||||
" s:_get_module() returns module object wihch has all script local functions.
|
||||
function! s:_get_module(name) abort dict
|
||||
let funcname = s:_import_func_name(self.plugin_name(), a:name)
|
||||
try
|
||||
return call(funcname, [])
|
||||
catch /^Vim\%((\a\+)\)\?:E117:/
|
||||
return s:_get_builtin_module(a:name)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:_get_builtin_module(name) abort
|
||||
return s:sid2sfuncs(s:_module_sid(a:name))
|
||||
endfunction
|
||||
|
||||
if s:is_vital_vim
|
||||
" For vital.vim, we can use s:_get_builtin_module directly
|
||||
let s:Vital._get_module = function('s:_get_builtin_module')
|
||||
else
|
||||
let s:Vital._get_module = function('s:_get_module')
|
||||
endif
|
||||
|
||||
function! s:_import_func_name(plugin_name, module_name) abort
|
||||
return printf('vital#_%s#%s#import', a:plugin_name, s:_dot_to_sharp(a:module_name))
|
||||
endfunction
|
||||
|
||||
function! s:_module_sid(name) abort
|
||||
let path = s:_module_path(a:name)
|
||||
if !filereadable(path)
|
||||
throw 'vital: module not found: ' . a:name
|
||||
endif
|
||||
let vital_dir = s:is_vital_vim ? '__\w\+__' : printf('_\{1,2}%s\%%(__\)\?', s:plugin_name)
|
||||
let base = join([vital_dir, ''], '[/\\]\+')
|
||||
let p = base . substitute('' . a:name, '\.', '[/\\\\]\\+', 'g')
|
||||
let sid = s:_sid(path, p)
|
||||
if !sid
|
||||
call s:_source(path)
|
||||
let sid = s:_sid(path, p)
|
||||
if !sid
|
||||
throw printf('vital: cannot get <SID> from path: %s', path)
|
||||
endif
|
||||
endif
|
||||
return sid
|
||||
endfunction
|
||||
|
||||
function! s:_module_path(name) abort
|
||||
return get(s:_extract_files(a:name, s:vital_files()), 0, '')
|
||||
endfunction
|
||||
|
||||
function! s:_module_sid_base_dir() abort
|
||||
return s:is_vital_vim ? &rtp : s:project_root
|
||||
endfunction
|
||||
|
||||
function! s:_dot_to_sharp(name) abort
|
||||
return substitute(a:name, '\.', '#', 'g')
|
||||
endfunction
|
||||
|
||||
function! s:_source(path) abort
|
||||
execute 'source' fnameescape(a:path)
|
||||
endfunction
|
||||
|
||||
" @vimlint(EVL102, 1, l:_)
|
||||
" @vimlint(EVL102, 1, l:__)
|
||||
function! s:_sid(path, filter_pattern) abort
|
||||
let unified_path = s:_unify_path(a:path)
|
||||
if has_key(s:cache_sid, unified_path)
|
||||
return s:cache_sid[unified_path]
|
||||
endif
|
||||
for line in filter(split(execute(':scriptnames'), "\n"), 'v:val =~# a:filter_pattern')
|
||||
let [_, sid, path; __] = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$')
|
||||
if s:_unify_path(path) is# unified_path
|
||||
let s:cache_sid[unified_path] = sid
|
||||
return s:cache_sid[unified_path]
|
||||
endif
|
||||
endfor
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
if filereadable(expand('<sfile>:r') . '.VIM') " is case-insensitive or not
|
||||
let s:_unify_path_cache = {}
|
||||
" resolve() is slow, so we cache results.
|
||||
" Note: On windows, vim can't expand path names from 8.3 formats.
|
||||
" So if getting full path via <sfile> and $HOME was set as 8.3 format,
|
||||
" vital load duplicated scripts. Below's :~ avoid this issue.
|
||||
function! s:_unify_path(path) abort
|
||||
if has_key(s:_unify_path_cache, a:path)
|
||||
return s:_unify_path_cache[a:path]
|
||||
endif
|
||||
let value = tolower(fnamemodify(resolve(fnamemodify(
|
||||
\ a:path, ':p')), ':~:gs?[\\/]?/?'))
|
||||
let s:_unify_path_cache[a:path] = value
|
||||
return value
|
||||
endfunction
|
||||
else
|
||||
function! s:_unify_path(path) abort
|
||||
return resolve(fnamemodify(a:path, ':p:gs?[\\/]?/?'))
|
||||
endfunction
|
||||
endif
|
||||
|
||||
" copied and modified from Vim.ScriptLocal
|
||||
let s:SNR = join(map(range(len("\<SNR>")), '"[\\x" . printf("%0x", char2nr("\<SNR>"[v:val])) . "]"'), '')
|
||||
function! s:sid2sfuncs(sid) abort
|
||||
let fs = split(execute(printf(':function /^%s%s_', s:SNR, a:sid)), "\n")
|
||||
let r = {}
|
||||
let pattern = printf('\m^function\s<SNR>%d_\zs\w\{-}\ze(', a:sid)
|
||||
for fname in map(fs, 'matchstr(v:val, pattern)')
|
||||
let r[fname] = function(s:_sfuncname(a:sid, fname))
|
||||
endfor
|
||||
return r
|
||||
endfunction
|
||||
|
||||
"" Return funcname of script local functions with SID
|
||||
function! s:_sfuncname(sid, funcname) abort
|
||||
return printf('<SNR>%s_%s', a:sid, a:funcname)
|
||||
endfunction
|
||||
8
dot_vim/plugged/vim-lsp/autoload/vital/lsp.vital
Normal file
8
dot_vim/plugged/vim-lsp/autoload/vital/lsp.vital
Normal file
@@ -0,0 +1,8 @@
|
||||
lsp
|
||||
b1e91b41f5028d65fa3d31a425ff21591d5d957f
|
||||
|
||||
VS.LSP.MarkupContent
|
||||
VS.Vim.Window.FloatingWindow
|
||||
VS.Vim.Syntax.Markdown
|
||||
VS.Vim.Buffer
|
||||
VS.Vim.Window
|
||||
170
dot_vim/plugged/vim-lsp/doc/tags
Normal file
170
dot_vim/plugged/vim-lsp/doc/tags
Normal file
@@ -0,0 +1,170 @@
|
||||
:LspAddTreeCallHierarchyIncoming vim-lsp.txt /*:LspAddTreeCallHierarchyIncoming*
|
||||
:LspCallHierarchyIncoming vim-lsp.txt /*:LspCallHierarchyIncoming*
|
||||
:LspCallHierarchyOutgoing vim-lsp.txt /*:LspCallHierarchyOutgoing*
|
||||
:LspCodeAction vim-lsp.txt /*:LspCodeAction*
|
||||
:LspCodeActionSync vim-lsp.txt /*:LspCodeActionSync*
|
||||
:LspCodeLens vim-lsp.txt /*:LspCodeLens*
|
||||
:LspDeclaration vim-lsp.txt /*:LspDeclaration*
|
||||
:LspDefinition vim-lsp.txt /*:LspDefinition*
|
||||
:LspDocumentDiagnostics vim-lsp.txt /*:LspDocumentDiagnostics*
|
||||
:LspDocumentFold vim-lsp.txt /*:LspDocumentFold*
|
||||
:LspDocumentFoldSync vim-lsp.txt /*:LspDocumentFoldSync*
|
||||
:LspDocumentFormat vim-lsp.txt /*:LspDocumentFormat*
|
||||
:LspDocumentFormatSync vim-lsp.txt /*:LspDocumentFormatSync*
|
||||
:LspDocumentRangeFormat vim-lsp.txt /*:LspDocumentRangeFormat*
|
||||
:LspDocumentRangeFormatSync vim-lsp.txt /*:LspDocumentRangeFormatSync*
|
||||
:LspDocumentSymbol vim-lsp.txt /*:LspDocumentSymbol*
|
||||
:LspDocumentSymbolSearch vim-lsp.txt /*:LspDocumentSymbolSearch*
|
||||
:LspHover vim-lsp.txt /*:LspHover*
|
||||
:LspImplementation vim-lsp.txt /*:LspImplementation*
|
||||
:LspNextDiagnostic vim-lsp.txt /*:LspNextDiagnostic*
|
||||
:LspNextError vim-lsp.txt /*:LspNextError*
|
||||
:LspNextReference vim-lsp.txt /*:LspNextReference*
|
||||
:LspPeekDeclaration vim-lsp.txt /*:LspPeekDeclaration*
|
||||
:LspPeekDefinition vim-lsp.txt /*:LspPeekDefinition*
|
||||
:LspPeekImplementation vim-lsp.txt /*:LspPeekImplementation*
|
||||
:LspPeekTypeDefinition vim-lsp.txt /*:LspPeekTypeDefinition*
|
||||
:LspPreviousDiagnostic vim-lsp.txt /*:LspPreviousDiagnostic*
|
||||
:LspPreviousError vim-lsp.txt /*:LspPreviousError*
|
||||
:LspPreviousReference vim-lsp.txt /*:LspPreviousReference*
|
||||
:LspPreviousWarning vim-lsp.txt /*:LspPreviousWarning*
|
||||
:LspReferences vim-lsp.txt /*:LspReferences*
|
||||
:LspRename vim-lsp.txt /*:LspRename*
|
||||
:LspSemanticHighlightGroups vim-lsp.txt /*:LspSemanticHighlightGroups*
|
||||
:LspStatus vim-lsp.txt /*:LspStatus*
|
||||
:LspStopServer vim-lsp.txt /*:LspStopServer*
|
||||
:LspTypeDefinition vim-lsp.txt /*:LspTypeDefinition*
|
||||
:LspTypeHierarchy vim-lsp.txt /*:LspTypeHierarchy*
|
||||
:LspWorkspaceSymbol vim-lsp.txt /*:LspWorkspaceSymbol*
|
||||
:LspWorkspaceSymbolSearch vim-lsp.txt /*:LspWorkspaceSymbolSearch*
|
||||
<plug>(lsp-preview-close) vim-lsp.txt /*<plug>(lsp-preview-close)*
|
||||
<plug>(lsp-preview-focus) vim-lsp.txt /*<plug>(lsp-preview-focus)*
|
||||
g:lsp_auto_enable vim-lsp.txt /*g:lsp_auto_enable*
|
||||
g:lsp_completion_documentation_delay vim-lsp.txt /*g:lsp_completion_documentation_delay*
|
||||
g:lsp_completion_documentation_enabled vim-lsp.txt /*g:lsp_completion_documentation_enabled*
|
||||
g:lsp_completion_resolve_timeout vim-lsp.txt /*g:lsp_completion_resolve_timeout*
|
||||
g:lsp_diagnostics_echo_cursor vim-lsp.txt /*g:lsp_diagnostics_echo_cursor*
|
||||
g:lsp_diagnostics_echo_delay vim-lsp.txt /*g:lsp_diagnostics_echo_delay*
|
||||
g:lsp_diagnostics_enabled vim-lsp.txt /*g:lsp_diagnostics_enabled*
|
||||
g:lsp_diagnostics_float_cursor vim-lsp.txt /*g:lsp_diagnostics_float_cursor*
|
||||
g:lsp_diagnostics_float_delay vim-lsp.txt /*g:lsp_diagnostics_float_delay*
|
||||
g:lsp_diagnostics_float_insert_mode_enabled vim-lsp.txt /*g:lsp_diagnostics_float_insert_mode_enabled*
|
||||
g:lsp_diagnostics_highlights_delay vim-lsp.txt /*g:lsp_diagnostics_highlights_delay*
|
||||
g:lsp_diagnostics_highlights_enabled vim-lsp.txt /*g:lsp_diagnostics_highlights_enabled*
|
||||
g:lsp_diagnostics_highlights_insert_mode_enabled vim-lsp.txt /*g:lsp_diagnostics_highlights_insert_mode_enabled*
|
||||
g:lsp_diagnostics_signs_delay vim-lsp.txt /*g:lsp_diagnostics_signs_delay*
|
||||
g:lsp_diagnostics_signs_enabled vim-lsp.txt /*g:lsp_diagnostics_signs_enabled*
|
||||
g:lsp_diagnostics_signs_insert_mode_enabled vim-lsp.txt /*g:lsp_diagnostics_signs_insert_mode_enabled*
|
||||
g:lsp_diagnostics_signs_priority vim-lsp.txt /*g:lsp_diagnostics_signs_priority*
|
||||
g:lsp_diagnostics_signs_priority_map vim-lsp.txt /*g:lsp_diagnostics_signs_priority_map*
|
||||
g:lsp_diagnostics_virtual_text_align vim-lsp.txt /*g:lsp_diagnostics_virtual_text_align*
|
||||
g:lsp_diagnostics_virtual_text_delay vim-lsp.txt /*g:lsp_diagnostics_virtual_text_delay*
|
||||
g:lsp_diagnostics_virtual_text_enabled vim-lsp.txt /*g:lsp_diagnostics_virtual_text_enabled*
|
||||
g:lsp_diagnostics_virtual_text_insert_mode_enabled vim-lsp.txt /*g:lsp_diagnostics_virtual_text_insert_mode_enabled*
|
||||
g:lsp_diagnostics_virtual_text_padding_left vim-lsp.txt /*g:lsp_diagnostics_virtual_text_padding_left*
|
||||
g:lsp_diagnostics_virtual_text_prefix vim-lsp.txt /*g:lsp_diagnostics_virtual_text_prefix*
|
||||
g:lsp_diagnostics_virtual_text_wrap vim-lsp.txt /*g:lsp_diagnostics_virtual_text_wrap*
|
||||
g:lsp_document_code_action_signs_delay vim-lsp.txt /*g:lsp_document_code_action_signs_delay*
|
||||
g:lsp_document_code_action_signs_enabled vim-lsp.txt /*g:lsp_document_code_action_signs_enabled*
|
||||
g:lsp_document_highlight_delay vim-lsp.txt /*g:lsp_document_highlight_delay*
|
||||
g:lsp_document_highlight_enabled vim-lsp.txt /*g:lsp_document_highlight_enabled*
|
||||
g:lsp_float_max_width vim-lsp.txt /*g:lsp_float_max_width*
|
||||
g:lsp_fold_enabled vim-lsp.txt /*g:lsp_fold_enabled*
|
||||
g:lsp_format_sync_timeout vim-lsp.txt /*g:lsp_format_sync_timeout*
|
||||
g:lsp_get_supported_capabilities vim-lsp.txt /*g:lsp_get_supported_capabilities*
|
||||
g:lsp_hover_conceal vim-lsp.txt /*g:lsp_hover_conceal*
|
||||
g:lsp_hover_ui vim-lsp.txt /*g:lsp_hover_ui*
|
||||
g:lsp_ignorecase vim-lsp.txt /*g:lsp_ignorecase*
|
||||
g:lsp_inlay_hints_delay vim-lsp.txt /*g:lsp_inlay_hints_delay*
|
||||
g:lsp_inlay_hints_enabled vim-lsp.txt /*g:lsp_inlay_hints_enabled*
|
||||
g:lsp_inlay_hints_mode vim-lsp.txt /*g:lsp_inlay_hints_mode*
|
||||
g:lsp_insert_text_enabled vim-lsp.txt /*g:lsp_insert_text_enabled*
|
||||
g:lsp_log_file vim-lsp.txt /*g:lsp_log_file*
|
||||
g:lsp_log_verbose vim-lsp.txt /*g:lsp_log_verbose*
|
||||
g:lsp_max_buffer_size vim-lsp.txt /*g:lsp_max_buffer_size*
|
||||
g:lsp_peek_alignment vim-lsp.txt /*g:lsp_peek_alignment*
|
||||
g:lsp_preview_autoclose vim-lsp.txt /*g:lsp_preview_autoclose*
|
||||
g:lsp_preview_doubletap vim-lsp.txt /*g:lsp_preview_doubletap*
|
||||
g:lsp_preview_fixup_conceal vim-lsp.txt /*g:lsp_preview_fixup_conceal*
|
||||
g:lsp_preview_float vim-lsp.txt /*g:lsp_preview_float*
|
||||
g:lsp_preview_keep_focus vim-lsp.txt /*g:lsp_preview_keep_focus*
|
||||
g:lsp_preview_max_height vim-lsp.txt /*g:lsp_preview_max_height*
|
||||
g:lsp_preview_max_width vim-lsp.txt /*g:lsp_preview_max_width*
|
||||
g:lsp_semantic_delay vim-lsp.txt /*g:lsp_semantic_delay*
|
||||
g:lsp_semantic_enabled vim-lsp.txt /*g:lsp_semantic_enabled*
|
||||
g:lsp_show_message_log_level vim-lsp.txt /*g:lsp_show_message_log_level*
|
||||
g:lsp_show_message_request_enabled vim-lsp.txt /*g:lsp_show_message_request_enabled*
|
||||
g:lsp_show_workspace_edits vim-lsp.txt /*g:lsp_show_workspace_edits*
|
||||
g:lsp_signature_help_delay vim-lsp.txt /*g:lsp_signature_help_delay*
|
||||
g:lsp_signature_help_enabled vim-lsp.txt /*g:lsp_signature_help_enabled*
|
||||
g:lsp_snippet_expand vim-lsp.txt /*g:lsp_snippet_expand*
|
||||
g:lsp_tagfunc_source_methods vim-lsp.txt /*g:lsp_tagfunc_source_methods*
|
||||
g:lsp_text_document_did_save_delay vim-lsp.txt /*g:lsp_text_document_did_save_delay*
|
||||
g:lsp_text_edit_enabled vim-lsp.txt /*g:lsp_text_edit_enabled*
|
||||
g:lsp_tree_incoming_prefix vim-lsp.txt /*g:lsp_tree_incoming_prefix*
|
||||
g:lsp_untitled_buffer_enabled vim-lsp.txt /*g:lsp_untitled_buffer_enabled*
|
||||
g:lsp_use_event_queue vim-lsp.txt /*g:lsp_use_event_queue*
|
||||
g:lsp_use_native_client vim-lsp.txt /*g:lsp_use_native_client*
|
||||
g:lsp_work_done_progress_enabled vim-lsp.txt /*g:lsp_work_done_progress_enabled*
|
||||
lsp#disable() vim-lsp.txt /*lsp#disable()*
|
||||
lsp#disable_diagnostics_for_buffer() vim-lsp.txt /*lsp#disable_diagnostics_for_buffer()*
|
||||
lsp#document_hover_preview_winid() vim-lsp.txt /*lsp#document_hover_preview_winid()*
|
||||
lsp#enable() vim-lsp.txt /*lsp#enable()*
|
||||
lsp#enable_diagnostic_for_buffer() vim-lsp.txt /*lsp#enable_diagnostic_for_buffer()*
|
||||
lsp#get_buffer_diagnostics_counts() vim-lsp.txt /*lsp#get_buffer_diagnostics_counts()*
|
||||
lsp#get_buffer_first_error_line() vim-lsp.txt /*lsp#get_buffer_first_error_line()*
|
||||
lsp#get_progress() vim-lsp.txt /*lsp#get_progress()*
|
||||
lsp#get_server_status() vim-lsp.txt /*lsp#get_server_status()*
|
||||
lsp#register_command() vim-lsp.txt /*lsp#register_command()*
|
||||
lsp#register_server() vim-lsp.txt /*lsp#register_server()*
|
||||
lsp#scroll() vim-lsp.txt /*lsp#scroll()*
|
||||
lsp#stop_server() vim-lsp.txt /*lsp#stop_server()*
|
||||
lsp#stream() vim-lsp.txt /*lsp#stream()*
|
||||
lsp#utils#find_nearest_parent_file_directory() vim-lsp.txt /*lsp#utils#find_nearest_parent_file_directory()*
|
||||
lsp#utils#position#lsp_to_vim() vim-lsp.txt /*lsp#utils#position#lsp_to_vim()*
|
||||
lsp#utils#position#vim_to_lsp() vim-lsp.txt /*lsp#utils#position#vim_to_lsp()*
|
||||
lsp_buffer_enabled vim-lsp.txt /*lsp_buffer_enabled*
|
||||
lsp_complete_done vim-lsp.txt /*lsp_complete_done*
|
||||
lsp_diagnostics_updated vim-lsp.txt /*lsp_diagnostics_updated*
|
||||
lsp_float_closed vim-lsp.txt /*lsp_float_closed*
|
||||
lsp_float_focused vim-lsp.txt /*lsp_float_focused*
|
||||
lsp_float_opened vim-lsp.txt /*lsp_float_opened*
|
||||
lsp_progress_updated vim-lsp.txt /*lsp_progress_updated*
|
||||
lsp_register_server vim-lsp.txt /*lsp_register_server*
|
||||
lsp_server_exit vim-lsp.txt /*lsp_server_exit*
|
||||
lsp_server_init vim-lsp.txt /*lsp_server_init*
|
||||
lsp_setup vim-lsp.txt /*lsp_setup*
|
||||
lsp_unregister_server vim-lsp.txt /*lsp_unregister_server*
|
||||
vim-lsp vim-lsp.txt /*vim-lsp*
|
||||
vim-lsp-asyncomplete vim-lsp.txt /*vim-lsp-asyncomplete*
|
||||
vim-lsp-autocommands vim-lsp.txt /*vim-lsp-autocommands*
|
||||
vim-lsp-autocomplete vim-lsp.txt /*vim-lsp-autocomplete*
|
||||
vim-lsp-commands vim-lsp.txt /*vim-lsp-commands*
|
||||
vim-lsp-completion-filter vim-lsp.txt /*vim-lsp-completion-filter*
|
||||
vim-lsp-completion-sort vim-lsp.txt /*vim-lsp-completion-sort*
|
||||
vim-lsp-configure vim-lsp.txt /*vim-lsp-configure*
|
||||
vim-lsp-configure-wiki vim-lsp.txt /*vim-lsp-configure-wiki*
|
||||
vim-lsp-contents vim-lsp.txt /*vim-lsp-contents*
|
||||
vim-lsp-folding vim-lsp.txt /*vim-lsp-folding*
|
||||
vim-lsp-functions vim-lsp.txt /*vim-lsp-functions*
|
||||
vim-lsp-healthcheck vim-lsp.txt /*vim-lsp-healthcheck*
|
||||
vim-lsp-install vim-lsp.txt /*vim-lsp-install*
|
||||
vim-lsp-introduction vim-lsp.txt /*vim-lsp-introduction*
|
||||
vim-lsp-language-servers vim-lsp.txt /*vim-lsp-language-servers*
|
||||
vim-lsp-license vim-lsp.txt /*vim-lsp-license*
|
||||
vim-lsp-maintainers vim-lsp.txt /*vim-lsp-maintainers*
|
||||
vim-lsp-mappings vim-lsp.txt /*vim-lsp-mappings*
|
||||
vim-lsp-omnifunc vim-lsp.txt /*vim-lsp-omnifunc*
|
||||
vim-lsp-options vim-lsp.txt /*vim-lsp-options*
|
||||
vim-lsp-performance vim-lsp.txt /*vim-lsp-performance*
|
||||
vim-lsp-popup-format vim-lsp.txt /*vim-lsp-popup-format*
|
||||
vim-lsp-refresh_pattern vim-lsp.txt /*vim-lsp-refresh_pattern*
|
||||
vim-lsp-semantic vim-lsp.txt /*vim-lsp-semantic*
|
||||
vim-lsp-server_info vim-lsp.txt /*vim-lsp-server_info*
|
||||
vim-lsp-server_info-hover_conceal vim-lsp.txt /*vim-lsp-server_info-hover_conceal*
|
||||
vim-lsp-settings_plugin vim-lsp.txt /*vim-lsp-settings_plugin*
|
||||
vim-lsp-snippets vim-lsp.txt /*vim-lsp-snippets*
|
||||
vim-lsp-tagfunc vim-lsp.txt /*vim-lsp-tagfunc*
|
||||
vim-lsp-tcp vim-lsp.txt /*vim-lsp-tcp*
|
||||
vim-lsp-workspace-folders vim-lsp.txt /*vim-lsp-workspace-folders*
|
||||
vim-lsp.txt vim-lsp.txt /*vim-lsp.txt*
|
||||
2221
dot_vim/plugged/vim-lsp/doc/vim-lsp.txt
Normal file
2221
dot_vim/plugged/vim-lsp/doc/vim-lsp.txt
Normal file
File diff suppressed because it is too large
Load Diff
1
dot_vim/plugged/vim-lsp/dot_git/HEAD
Normal file
1
dot_vim/plugged/vim-lsp/dot_git/HEAD
Normal file
@@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
||||
0
dot_vim/plugged/vim-lsp/dot_git/branches/.keep
Normal file
0
dot_vim/plugged/vim-lsp/dot_git/branches/.keep
Normal file
11
dot_vim/plugged/vim-lsp/dot_git/config
Normal file
11
dot_vim/plugged/vim-lsp/dot_git/config
Normal file
@@ -0,0 +1,11 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = false
|
||||
logallrefupdates = true
|
||||
[remote "origin"]
|
||||
url = https://github.com/prabirshrestha/vim-lsp.git
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
[branch "master"]
|
||||
remote = origin
|
||||
merge = refs/heads/master
|
||||
1
dot_vim/plugged/vim-lsp/dot_git/description
Normal file
1
dot_vim/plugged/vim-lsp/dot_git/description
Normal file
@@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
||||
15
dot_vim/plugged/vim-lsp/dot_git/hooks/applypatch-msg.sample
Normal file
15
dot_vim/plugged/vim-lsp/dot_git/hooks/applypatch-msg.sample
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message taken by
|
||||
# applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit. The hook is
|
||||
# allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "applypatch-msg".
|
||||
|
||||
. git-sh-setup
|
||||
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||
:
|
||||
24
dot_vim/plugged/vim-lsp/dot_git/hooks/commit-msg.sample
Normal file
24
dot_vim/plugged/vim-lsp/dot_git/hooks/commit-msg.sample
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message.
|
||||
# Called by "git commit" with one argument, the name of the file
|
||||
# that has the commit message. The hook should exit with non-zero
|
||||
# status after issuing an appropriate message if it wants to stop the
|
||||
# commit. The hook is allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "commit-msg".
|
||||
|
||||
# Uncomment the below to add a Signed-off-by line to the message.
|
||||
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||
# hook is more suited to it.
|
||||
#
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||
|
||||
# This example catches duplicate Signed-off-by lines.
|
||||
|
||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||
echo >&2 Duplicate Signed-off-by lines.
|
||||
exit 1
|
||||
}
|
||||
174
dot_vim/plugged/vim-lsp/dot_git/hooks/fsmonitor-watchman.sample
Normal file
174
dot_vim/plugged/vim-lsp/dot_git/hooks/fsmonitor-watchman.sample
Normal file
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use IPC::Open2;
|
||||
|
||||
# An example hook script to integrate Watchman
|
||||
# (https://facebook.github.io/watchman/) with git to speed up detecting
|
||||
# new and modified files.
|
||||
#
|
||||
# The hook is passed a version (currently 2) and last update token
|
||||
# formatted as a string and outputs to stdout a new update token and
|
||||
# all files that have been modified since the update token. Paths must
|
||||
# be relative to the root of the working tree and separated by a single NUL.
|
||||
#
|
||||
# To enable this hook, rename this file to "query-watchman" and set
|
||||
# 'git config core.fsmonitor .git/hooks/query-watchman'
|
||||
#
|
||||
my ($version, $last_update_token) = @ARGV;
|
||||
|
||||
# Uncomment for debugging
|
||||
# print STDERR "$0 $version $last_update_token\n";
|
||||
|
||||
# Check the hook interface version
|
||||
if ($version ne 2) {
|
||||
die "Unsupported query-fsmonitor hook version '$version'.\n" .
|
||||
"Falling back to scanning...\n";
|
||||
}
|
||||
|
||||
my $git_work_tree = get_working_dir();
|
||||
|
||||
my $retry = 1;
|
||||
|
||||
my $json_pkg;
|
||||
eval {
|
||||
require JSON::XS;
|
||||
$json_pkg = "JSON::XS";
|
||||
1;
|
||||
} or do {
|
||||
require JSON::PP;
|
||||
$json_pkg = "JSON::PP";
|
||||
};
|
||||
|
||||
launch_watchman();
|
||||
|
||||
sub launch_watchman {
|
||||
my $o = watchman_query();
|
||||
if (is_work_tree_watched($o)) {
|
||||
output_result($o->{clock}, @{$o->{files}});
|
||||
}
|
||||
}
|
||||
|
||||
sub output_result {
|
||||
my ($clockid, @files) = @_;
|
||||
|
||||
# Uncomment for debugging watchman output
|
||||
# open (my $fh, ">", ".git/watchman-output.out");
|
||||
# binmode $fh, ":utf8";
|
||||
# print $fh "$clockid\n@files\n";
|
||||
# close $fh;
|
||||
|
||||
binmode STDOUT, ":utf8";
|
||||
print $clockid;
|
||||
print "\0";
|
||||
local $, = "\0";
|
||||
print @files;
|
||||
}
|
||||
|
||||
sub watchman_clock {
|
||||
my $response = qx/watchman clock "$git_work_tree"/;
|
||||
die "Failed to get clock id on '$git_work_tree'.\n" .
|
||||
"Falling back to scanning...\n" if $? != 0;
|
||||
|
||||
return $json_pkg->new->utf8->decode($response);
|
||||
}
|
||||
|
||||
sub watchman_query {
|
||||
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
|
||||
or die "open2() failed: $!\n" .
|
||||
"Falling back to scanning...\n";
|
||||
|
||||
# In the query expression below we're asking for names of files that
|
||||
# changed since $last_update_token but not from the .git folder.
|
||||
#
|
||||
# To accomplish this, we're using the "since" generator to use the
|
||||
# recency index to select candidate nodes and "fields" to limit the
|
||||
# output to file names only. Then we're using the "expression" term to
|
||||
# further constrain the results.
|
||||
my $last_update_line = "";
|
||||
if (substr($last_update_token, 0, 1) eq "c") {
|
||||
$last_update_token = "\"$last_update_token\"";
|
||||
$last_update_line = qq[\n"since": $last_update_token,];
|
||||
}
|
||||
my $query = <<" END";
|
||||
["query", "$git_work_tree", {$last_update_line
|
||||
"fields": ["name"],
|
||||
"expression": ["not", ["dirname", ".git"]]
|
||||
}]
|
||||
END
|
||||
|
||||
# Uncomment for debugging the watchman query
|
||||
# open (my $fh, ">", ".git/watchman-query.json");
|
||||
# print $fh $query;
|
||||
# close $fh;
|
||||
|
||||
print CHLD_IN $query;
|
||||
close CHLD_IN;
|
||||
my $response = do {local $/; <CHLD_OUT>};
|
||||
|
||||
# Uncomment for debugging the watch response
|
||||
# open ($fh, ">", ".git/watchman-response.json");
|
||||
# print $fh $response;
|
||||
# close $fh;
|
||||
|
||||
die "Watchman: command returned no output.\n" .
|
||||
"Falling back to scanning...\n" if $response eq "";
|
||||
die "Watchman: command returned invalid output: $response\n" .
|
||||
"Falling back to scanning...\n" unless $response =~ /^\{/;
|
||||
|
||||
return $json_pkg->new->utf8->decode($response);
|
||||
}
|
||||
|
||||
sub is_work_tree_watched {
|
||||
my ($output) = @_;
|
||||
my $error = $output->{error};
|
||||
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
|
||||
$retry--;
|
||||
my $response = qx/watchman watch "$git_work_tree"/;
|
||||
die "Failed to make watchman watch '$git_work_tree'.\n" .
|
||||
"Falling back to scanning...\n" if $? != 0;
|
||||
$output = $json_pkg->new->utf8->decode($response);
|
||||
$error = $output->{error};
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
# Uncomment for debugging watchman output
|
||||
# open (my $fh, ">", ".git/watchman-output.out");
|
||||
# close $fh;
|
||||
|
||||
# Watchman will always return all files on the first query so
|
||||
# return the fast "everything is dirty" flag to git and do the
|
||||
# Watchman query just to get it over with now so we won't pay
|
||||
# the cost in git to look up each individual file.
|
||||
my $o = watchman_clock();
|
||||
$error = $output->{error};
|
||||
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
output_result($o->{clock}, ("/"));
|
||||
$last_update_token = $o->{clock};
|
||||
|
||||
eval { launch_watchman() };
|
||||
return 0;
|
||||
}
|
||||
|
||||
die "Watchman: $error.\n" .
|
||||
"Falling back to scanning...\n" if $error;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub get_working_dir {
|
||||
my $working_dir;
|
||||
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
|
||||
$working_dir = Win32::GetCwd();
|
||||
$working_dir =~ tr/\\/\//;
|
||||
} else {
|
||||
require Cwd;
|
||||
$working_dir = Cwd::cwd();
|
||||
}
|
||||
|
||||
return $working_dir;
|
||||
}
|
||||
8
dot_vim/plugged/vim-lsp/dot_git/hooks/post-update.sample
Normal file
8
dot_vim/plugged/vim-lsp/dot_git/hooks/post-update.sample
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to prepare a packed repository for use over
|
||||
# dumb transports.
|
||||
#
|
||||
# To enable this hook, rename this file to "post-update".
|
||||
|
||||
exec git update-server-info
|
||||
14
dot_vim/plugged/vim-lsp/dot_git/hooks/pre-applypatch.sample
Normal file
14
dot_vim/plugged/vim-lsp/dot_git/hooks/pre-applypatch.sample
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed
|
||||
# by applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-applypatch".
|
||||
|
||||
. git-sh-setup
|
||||
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||
:
|
||||
49
dot_vim/plugged/vim-lsp/dot_git/hooks/pre-commit.sample
Normal file
49
dot_vim/plugged/vim-lsp/dot_git/hooks/pre-commit.sample
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git commit" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message if
|
||||
# it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-commit".
|
||||
|
||||
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||
then
|
||||
against=HEAD
|
||||
else
|
||||
# Initial commit: diff against an empty tree object
|
||||
against=$(git hash-object -t tree /dev/null)
|
||||
fi
|
||||
|
||||
# If you want to allow non-ASCII filenames set this variable to true.
|
||||
allownonascii=$(git config --type=bool hooks.allownonascii)
|
||||
|
||||
# Redirect output to stderr.
|
||||
exec 1>&2
|
||||
|
||||
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||
# them from being added to the repository. We exploit the fact that the
|
||||
# printable range starts at the space character and ends with tilde.
|
||||
if [ "$allownonascii" != "true" ] &&
|
||||
# Note that the use of brackets around a tr range is ok here, (it's
|
||||
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||
# the square bracket bytes happen to fall in the designated range.
|
||||
test $(git diff --cached --name-only --diff-filter=A -z $against |
|
||||
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||
then
|
||||
cat <<\EOF
|
||||
Error: Attempt to add a non-ASCII file name.
|
||||
|
||||
This can cause problems if you want to work with people on other platforms.
|
||||
|
||||
To be portable it is advisable to rename the file.
|
||||
|
||||
If you know what you are doing you can disable this check using:
|
||||
|
||||
git config hooks.allownonascii true
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If there are whitespace errors, print the offending file names and fail.
|
||||
exec git diff-index --check --cached $against --
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git merge" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message to
|
||||
# stderr if it wants to stop the merge commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-merge-commit".
|
||||
|
||||
. git-sh-setup
|
||||
test -x "$GIT_DIR/hooks/pre-commit" &&
|
||||
exec "$GIT_DIR/hooks/pre-commit"
|
||||
:
|
||||
53
dot_vim/plugged/vim-lsp/dot_git/hooks/pre-push.sample
Normal file
53
dot_vim/plugged/vim-lsp/dot_git/hooks/pre-push.sample
Normal file
@@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
|
||||
# An example hook script to verify what is about to be pushed. Called by "git
|
||||
# push" after it has checked the remote status, but before anything has been
|
||||
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||
#
|
||||
# This hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- Name of the remote to which the push is being done
|
||||
# $2 -- URL to which the push is being done
|
||||
#
|
||||
# If pushing without using a named remote those arguments will be equal.
|
||||
#
|
||||
# Information about the commits which are being pushed is supplied as lines to
|
||||
# the standard input in the form:
|
||||
#
|
||||
# <local ref> <local oid> <remote ref> <remote oid>
|
||||
#
|
||||
# This sample shows how to prevent push of commits where the log message starts
|
||||
# with "WIP" (work in progress).
|
||||
|
||||
remote="$1"
|
||||
url="$2"
|
||||
|
||||
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||
|
||||
while read local_ref local_oid remote_ref remote_oid
|
||||
do
|
||||
if test "$local_oid" = "$zero"
|
||||
then
|
||||
# Handle delete
|
||||
:
|
||||
else
|
||||
if test "$remote_oid" = "$zero"
|
||||
then
|
||||
# New branch, examine all commits
|
||||
range="$local_oid"
|
||||
else
|
||||
# Update to existing branch, examine new commits
|
||||
range="$remote_oid..$local_oid"
|
||||
fi
|
||||
|
||||
# Check for WIP commit
|
||||
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
|
||||
if test -n "$commit"
|
||||
then
|
||||
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
||||
169
dot_vim/plugged/vim-lsp/dot_git/hooks/pre-rebase.sample
Normal file
169
dot_vim/plugged/vim-lsp/dot_git/hooks/pre-rebase.sample
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2006, 2008 Junio C Hamano
|
||||
#
|
||||
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
||||
# its job, and can prevent the command from running by exiting with
|
||||
# non-zero status.
|
||||
#
|
||||
# The hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- the upstream the series was forked from.
|
||||
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
||||
#
|
||||
# This sample shows how to prevent topic branches that are already
|
||||
# merged to 'next' branch from getting rebased, because allowing it
|
||||
# would result in rebasing already published history.
|
||||
|
||||
publish=next
|
||||
basebranch="$1"
|
||||
if test "$#" = 2
|
||||
then
|
||||
topic="refs/heads/$2"
|
||||
else
|
||||
topic=`git symbolic-ref HEAD` ||
|
||||
exit 0 ;# we do not interrupt rebasing detached HEAD
|
||||
fi
|
||||
|
||||
case "$topic" in
|
||||
refs/heads/??/*)
|
||||
;;
|
||||
*)
|
||||
exit 0 ;# we do not interrupt others.
|
||||
;;
|
||||
esac
|
||||
|
||||
# Now we are dealing with a topic branch being rebased
|
||||
# on top of master. Is it OK to rebase it?
|
||||
|
||||
# Does the topic really exist?
|
||||
git show-ref -q "$topic" || {
|
||||
echo >&2 "No such branch $topic"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Is topic fully merged to master?
|
||||
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
||||
if test -z "$not_in_master"
|
||||
then
|
||||
echo >&2 "$topic is fully merged to master; better remove it."
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
fi
|
||||
|
||||
# Is topic ever merged to next? If so you should not be rebasing it.
|
||||
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
||||
only_next_2=`git rev-list ^master ${publish} | sort`
|
||||
if test "$only_next_1" = "$only_next_2"
|
||||
then
|
||||
not_in_topic=`git rev-list "^$topic" master`
|
||||
if test -z "$not_in_topic"
|
||||
then
|
||||
echo >&2 "$topic is already up to date with master"
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
||||
/usr/bin/perl -e '
|
||||
my $topic = $ARGV[0];
|
||||
my $msg = "* $topic has commits already merged to public branch:\n";
|
||||
my (%not_in_next) = map {
|
||||
/^([0-9a-f]+) /;
|
||||
($1 => 1);
|
||||
} split(/\n/, $ARGV[1]);
|
||||
for my $elem (map {
|
||||
/^([0-9a-f]+) (.*)$/;
|
||||
[$1 => $2];
|
||||
} split(/\n/, $ARGV[2])) {
|
||||
if (!exists $not_in_next{$elem->[0]}) {
|
||||
if ($msg) {
|
||||
print STDERR $msg;
|
||||
undef $msg;
|
||||
}
|
||||
print STDERR " $elem->[1]\n";
|
||||
}
|
||||
}
|
||||
' "$topic" "$not_in_next" "$not_in_master"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
<<\DOC_END
|
||||
|
||||
This sample hook safeguards topic branches that have been
|
||||
published from being rewound.
|
||||
|
||||
The workflow assumed here is:
|
||||
|
||||
* Once a topic branch forks from "master", "master" is never
|
||||
merged into it again (either directly or indirectly).
|
||||
|
||||
* Once a topic branch is fully cooked and merged into "master",
|
||||
it is deleted. If you need to build on top of it to correct
|
||||
earlier mistakes, a new topic branch is created by forking at
|
||||
the tip of the "master". This is not strictly necessary, but
|
||||
it makes it easier to keep your history simple.
|
||||
|
||||
* Whenever you need to test or publish your changes to topic
|
||||
branches, merge them into "next" branch.
|
||||
|
||||
The script, being an example, hardcodes the publish branch name
|
||||
to be "next", but it is trivial to make it configurable via
|
||||
$GIT_DIR/config mechanism.
|
||||
|
||||
With this workflow, you would want to know:
|
||||
|
||||
(1) ... if a topic branch has ever been merged to "next". Young
|
||||
topic branches can have stupid mistakes you would rather
|
||||
clean up before publishing, and things that have not been
|
||||
merged into other branches can be easily rebased without
|
||||
affecting other people. But once it is published, you would
|
||||
not want to rewind it.
|
||||
|
||||
(2) ... if a topic branch has been fully merged to "master".
|
||||
Then you can delete it. More importantly, you should not
|
||||
build on top of it -- other people may already want to
|
||||
change things related to the topic as patches against your
|
||||
"master", so if you need further changes, it is better to
|
||||
fork the topic (perhaps with the same name) afresh from the
|
||||
tip of "master".
|
||||
|
||||
Let's look at this example:
|
||||
|
||||
o---o---o---o---o---o---o---o---o---o "next"
|
||||
/ / / /
|
||||
/ a---a---b A / /
|
||||
/ / / /
|
||||
/ / c---c---c---c B /
|
||||
/ / / \ /
|
||||
/ / / b---b C \ /
|
||||
/ / / / \ /
|
||||
---o---o---o---o---o---o---o---o---o---o---o "master"
|
||||
|
||||
|
||||
A, B and C are topic branches.
|
||||
|
||||
* A has one fix since it was merged up to "next".
|
||||
|
||||
* B has finished. It has been fully merged up to "master" and "next",
|
||||
and is ready to be deleted.
|
||||
|
||||
* C has not merged to "next" at all.
|
||||
|
||||
We would want to allow C to be rebased, refuse A, and encourage
|
||||
B to be deleted.
|
||||
|
||||
To compute (1):
|
||||
|
||||
git rev-list ^master ^topic next
|
||||
git rev-list ^master next
|
||||
|
||||
if these match, topic has not merged in next at all.
|
||||
|
||||
To compute (2):
|
||||
|
||||
git rev-list master..topic
|
||||
|
||||
if this is empty, it is fully merged to "master".
|
||||
|
||||
DOC_END
|
||||
24
dot_vim/plugged/vim-lsp/dot_git/hooks/pre-receive.sample
Normal file
24
dot_vim/plugged/vim-lsp/dot_git/hooks/pre-receive.sample
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to make use of push options.
|
||||
# The example simply echoes all push options that start with 'echoback='
|
||||
# and rejects all pushes when the "reject" push option is used.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-receive".
|
||||
|
||||
if test -n "$GIT_PUSH_OPTION_COUNT"
|
||||
then
|
||||
i=0
|
||||
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
|
||||
do
|
||||
eval "value=\$GIT_PUSH_OPTION_$i"
|
||||
case "$value" in
|
||||
echoback=*)
|
||||
echo "echo from the pre-receive-hook: ${value#*=}" >&2
|
||||
;;
|
||||
reject)
|
||||
exit 1
|
||||
esac
|
||||
i=$((i + 1))
|
||||
done
|
||||
fi
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to prepare the commit log message.
|
||||
# Called by "git commit" with the name of the file that has the
|
||||
# commit message, followed by the description of the commit
|
||||
# message's source. The hook's purpose is to edit the commit
|
||||
# message file. If the hook fails with a non-zero status,
|
||||
# the commit is aborted.
|
||||
#
|
||||
# To enable this hook, rename this file to "prepare-commit-msg".
|
||||
|
||||
# This hook includes three examples. The first one removes the
|
||||
# "# Please enter the commit message..." help message.
|
||||
#
|
||||
# The second includes the output of "git diff --name-status -r"
|
||||
# into the message, just before the "git status" output. It is
|
||||
# commented because it doesn't cope with --amend or with squashed
|
||||
# commits.
|
||||
#
|
||||
# The third example adds a Signed-off-by line to the message, that can
|
||||
# still be edited. This is rarely a good idea.
|
||||
|
||||
COMMIT_MSG_FILE=$1
|
||||
COMMIT_SOURCE=$2
|
||||
SHA1=$3
|
||||
|
||||
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
|
||||
|
||||
# case "$COMMIT_SOURCE,$SHA1" in
|
||||
# ,|template,)
|
||||
# /usr/bin/perl -i.bak -pe '
|
||||
# print "\n" . `git diff --cached --name-status -r`
|
||||
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
|
||||
# *) ;;
|
||||
# esac
|
||||
|
||||
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
|
||||
# if test -z "$COMMIT_SOURCE"
|
||||
# then
|
||||
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
|
||||
# fi
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/bin/sh
|
||||
|
||||
# An example hook script to update a checked-out tree on a git push.
|
||||
#
|
||||
# This hook is invoked by git-receive-pack(1) when it reacts to git
|
||||
# push and updates reference(s) in its repository, and when the push
|
||||
# tries to update the branch that is currently checked out and the
|
||||
# receive.denyCurrentBranch configuration variable is set to
|
||||
# updateInstead.
|
||||
#
|
||||
# By default, such a push is refused if the working tree and the index
|
||||
# of the remote repository has any difference from the currently
|
||||
# checked out commit; when both the working tree and the index match
|
||||
# the current commit, they are updated to match the newly pushed tip
|
||||
# of the branch. This hook is to be used to override the default
|
||||
# behaviour; however the code below reimplements the default behaviour
|
||||
# as a starting point for convenient modification.
|
||||
#
|
||||
# The hook receives the commit with which the tip of the current
|
||||
# branch is going to be updated:
|
||||
commit=$1
|
||||
|
||||
# It can exit with a non-zero status to refuse the push (when it does
|
||||
# so, it must not modify the index or the working tree).
|
||||
die () {
|
||||
echo >&2 "$*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Or it can make any necessary changes to the working tree and to the
|
||||
# index to bring them to the desired state when the tip of the current
|
||||
# branch is updated to the new commit, and exit with a zero status.
|
||||
#
|
||||
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
|
||||
# in order to emulate git fetch that is run in the reverse direction
|
||||
# with git push, as the two-tree form of git read-tree -u -m is
|
||||
# essentially the same as git switch or git checkout that switches
|
||||
# branches while keeping the local changes in the working tree that do
|
||||
# not interfere with the difference between the branches.
|
||||
|
||||
# The below is a more-or-less exact translation to shell of the C code
|
||||
# for the default behaviour for git's push-to-checkout hook defined in
|
||||
# the push_to_deploy() function in builtin/receive-pack.c.
|
||||
#
|
||||
# Note that the hook will be executed from the repository directory,
|
||||
# not from the working tree, so if you want to perform operations on
|
||||
# the working tree, you will have to adapt your code accordingly, e.g.
|
||||
# by adding "cd .." or using relative paths.
|
||||
|
||||
if ! git update-index -q --ignore-submodules --refresh
|
||||
then
|
||||
die "Up-to-date check failed"
|
||||
fi
|
||||
|
||||
if ! git diff-files --quiet --ignore-submodules --
|
||||
then
|
||||
die "Working directory has unstaged changes"
|
||||
fi
|
||||
|
||||
# This is a rough translation of:
|
||||
#
|
||||
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
|
||||
if git cat-file -e HEAD 2>/dev/null
|
||||
then
|
||||
head=HEAD
|
||||
else
|
||||
head=$(git hash-object -t tree --stdin </dev/null)
|
||||
fi
|
||||
|
||||
if ! git diff-index --quiet --cached --ignore-submodules $head --
|
||||
then
|
||||
die "Working directory has staged changes"
|
||||
fi
|
||||
|
||||
if ! git read-tree -u -m "$commit"
|
||||
then
|
||||
die "Could not update working tree to new HEAD"
|
||||
fi
|
||||
128
dot_vim/plugged/vim-lsp/dot_git/hooks/update.sample
Normal file
128
dot_vim/plugged/vim-lsp/dot_git/hooks/update.sample
Normal file
@@ -0,0 +1,128 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to block unannotated tags from entering.
|
||||
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
||||
#
|
||||
# To enable this hook, rename this file to "update".
|
||||
#
|
||||
# Config
|
||||
# ------
|
||||
# hooks.allowunannotated
|
||||
# This boolean sets whether unannotated tags will be allowed into the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowdeletetag
|
||||
# This boolean sets whether deleting tags will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowmodifytag
|
||||
# This boolean sets whether a tag may be modified after creation. By default
|
||||
# it won't be.
|
||||
# hooks.allowdeletebranch
|
||||
# This boolean sets whether deleting branches will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.denycreatebranch
|
||||
# This boolean sets whether remotely creating branches will be denied
|
||||
# in the repository. By default this is allowed.
|
||||
#
|
||||
|
||||
# --- Command line
|
||||
refname="$1"
|
||||
oldrev="$2"
|
||||
newrev="$3"
|
||||
|
||||
# --- Safety check
|
||||
if [ -z "$GIT_DIR" ]; then
|
||||
echo "Don't run this script from the command line." >&2
|
||||
echo " (if you want, you could supply GIT_DIR then run" >&2
|
||||
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Config
|
||||
allowunannotated=$(git config --type=bool hooks.allowunannotated)
|
||||
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
|
||||
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
|
||||
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
|
||||
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
|
||||
|
||||
# check for no description
|
||||
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
||||
case "$projectdesc" in
|
||||
"Unnamed repository"* | "")
|
||||
echo "*** Project description file hasn't been set" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Check types
|
||||
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||
if [ "$newrev" = "$zero" ]; then
|
||||
newrev_type=delete
|
||||
else
|
||||
newrev_type=$(git cat-file -t $newrev)
|
||||
fi
|
||||
|
||||
case "$refname","$newrev_type" in
|
||||
refs/tags/*,commit)
|
||||
# un-annotated tag
|
||||
short_refname=${refname##refs/tags/}
|
||||
if [ "$allowunannotated" != "true" ]; then
|
||||
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
||||
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,delete)
|
||||
# delete tag
|
||||
if [ "$allowdeletetag" != "true" ]; then
|
||||
echo "*** Deleting a tag is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,tag)
|
||||
# annotated tag
|
||||
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
||||
then
|
||||
echo "*** Tag '$refname' already exists." >&2
|
||||
echo "*** Modifying a tag is not allowed in this repository." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,commit)
|
||||
# branch
|
||||
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
||||
echo "*** Creating a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,delete)
|
||||
# delete branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/remotes/*,commit)
|
||||
# tracking branch
|
||||
;;
|
||||
refs/remotes/*,delete)
|
||||
# delete tracking branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Anything else (is there anything else?)
|
||||
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Finished
|
||||
exit 0
|
||||
BIN
dot_vim/plugged/vim-lsp/dot_git/index
Normal file
BIN
dot_vim/plugged/vim-lsp/dot_git/index
Normal file
Binary file not shown.
6
dot_vim/plugged/vim-lsp/dot_git/info/exclude
Normal file
6
dot_vim/plugged/vim-lsp/dot_git/info/exclude
Normal file
@@ -0,0 +1,6 @@
|
||||
# git ls-files --others --exclude-from=.git/info/exclude
|
||||
# Lines that start with '#' are comments.
|
||||
# For a project mostly in C, the following would be a good set of
|
||||
# exclude patterns (uncomment them if you want to use them):
|
||||
# *.[oa]
|
||||
# *~
|
||||
2
dot_vim/plugged/vim-lsp/dot_git/logs/HEAD
Normal file
2
dot_vim/plugged/vim-lsp/dot_git/logs/HEAD
Normal file
@@ -0,0 +1,2 @@
|
||||
0000000000000000000000000000000000000000 65628c3b0affacd0f36a6e294b1c1f96c6fe2455 LinlyBoi <libkyy@e.email> 1676062730 +0200 clone: from https://github.com/prabirshrestha/vim-lsp.git
|
||||
65628c3b0affacd0f36a6e294b1c1f96c6fe2455 65628c3b0affacd0f36a6e294b1c1f96c6fe2455 LinlyBoi <libkyy@e.email> 1676062732 +0200 checkout: moving from master to master
|
||||
1
dot_vim/plugged/vim-lsp/dot_git/logs/refs/heads/master
Normal file
1
dot_vim/plugged/vim-lsp/dot_git/logs/refs/heads/master
Normal file
@@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 65628c3b0affacd0f36a6e294b1c1f96c6fe2455 LinlyBoi <libkyy@e.email> 1676062730 +0200 clone: from https://github.com/prabirshrestha/vim-lsp.git
|
||||
@@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 65628c3b0affacd0f36a6e294b1c1f96c6fe2455 LinlyBoi <libkyy@e.email> 1676062730 +0200 clone: from https://github.com/prabirshrestha/vim-lsp.git
|
||||
0
dot_vim/plugged/vim-lsp/dot_git/objects/info/.keep
Normal file
0
dot_vim/plugged/vim-lsp/dot_git/objects/info/.keep
Normal file
Binary file not shown.
Binary file not shown.
18
dot_vim/plugged/vim-lsp/dot_git/packed-refs
Normal file
18
dot_vim/plugged/vim-lsp/dot_git/packed-refs
Normal file
@@ -0,0 +1,18 @@
|
||||
# pack-refs with: peeled fully-peeled sorted
|
||||
c2c166975efef9b4c450fef7da97a32ded87314d refs/remotes/origin/array-perf
|
||||
293e8ae932ffb70fe444c89e7aa995eecbc5c1fa refs/remotes/origin/client-parse
|
||||
383f690e80ed9e2697eb40020532ef1f66c010e7 refs/remotes/origin/fix-completion-documentation-maxheight
|
||||
723fa3a0b6c36d5cda56f9fb9f803cc4f90b8eed refs/remotes/origin/fix-filter-text-correction
|
||||
1a84ed5f68b2ed0f35aa5999d24f96a89e6a515f refs/remotes/origin/fix-float
|
||||
49a886853e0b9e61fc1ac11802b77a601c266c6e refs/remotes/origin/fix-root_uri
|
||||
0616aab6aa1923b3cf35300a87b731fba9a7a464 refs/remotes/origin/fix-vim-popup-conceal
|
||||
1724318f4f838d7de31ad4146e5f4eed0348d317 refs/remotes/origin/get_kind_perf
|
||||
92a925346dc30074783a5125782e5bfe10c2245f refs/remotes/origin/lua-lsp-client
|
||||
65628c3b0affacd0f36a6e294b1c1f96c6fe2455 refs/remotes/origin/master
|
||||
231ab3cb230e599b83f4f2eaf4a1cc03a4cff4dd refs/remotes/origin/pr1078
|
||||
82796606f058c3f33eef6f5f881007cb62c04967 refs/remotes/origin/use-lua
|
||||
140775b3d595e92f6521bff49c62da6b5c6aa391 refs/tags/v0.1.0
|
||||
73bc4f1ceb4af56a9404a5f9d1c40e290fa16045 refs/tags/v0.1.1
|
||||
b6651468b78fb6e386a6eb4b7cca4479affbe853 refs/tags/v0.1.2
|
||||
0c2a9d34e0498988d5a783ae3da3ec8d8649613d refs/tags/v0.1.3
|
||||
3bca7e8c8a794fde38075e7df9d14c286d055a84 refs/tags/v0.1.4
|
||||
1
dot_vim/plugged/vim-lsp/dot_git/refs/heads/master
Normal file
1
dot_vim/plugged/vim-lsp/dot_git/refs/heads/master
Normal file
@@ -0,0 +1 @@
|
||||
65628c3b0affacd0f36a6e294b1c1f96c6fe2455
|
||||
1
dot_vim/plugged/vim-lsp/dot_git/refs/remotes/origin/HEAD
Normal file
1
dot_vim/plugged/vim-lsp/dot_git/refs/remotes/origin/HEAD
Normal file
@@ -0,0 +1 @@
|
||||
ref: refs/remotes/origin/master
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user