All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
1 " https://microsoft.github.io/language-server-protocol/specification#textDocument_codeAction
3 " internal state for whether it is enabled or not to avoid multiple subscriptions
6 let s:sign_group = 'vim_lsp_document_code_action_signs'
8 if !hlexists('LspCodeActionText')
9 highlight link LspCodeActionText Normal
12 function! lsp#internal#document_code_action#signs#_enable() abort
13 if !lsp#utils#_has_signs() | return | endif
14 " don't even bother registering if the feature is disabled
15 if !g:lsp_document_code_action_signs_enabled | return | endif
17 if s:enabled | return | endif
20 call s:define_sign('LspCodeAction', 'A>', g:lsp_document_code_action_signs_hint)
23 " - update CodeAction signs when CusorMoved or CursorHold
24 " - clear signs when InsertEnter or BufLeave
25 " - debounce code action requests
26 " - automatically switch to latest code action request via switchMap()
27 " - cancel code action request via takeUntil() when BufLeave
28 let s:Dispose = lsp#callbag#pipe(
30 \ lsp#callbag#fromEvent(['CursorMoved', 'CursorHold']),
32 \ lsp#callbag#fromEvent(['InsertEnter', 'BufLeave']),
33 \ lsp#callbag#tap({_ -> s:clear_signs() }),
36 \ lsp#callbag#filter({_ -> g:lsp_document_code_action_signs_enabled }),
37 \ lsp#callbag#debounceTime(g:lsp_document_code_action_signs_delay),
38 \ lsp#callbag#map({_->{'bufnr': bufnr('%'), 'curpos': getcurpos()[0:2], 'changedtick': b:changedtick }}),
39 \ lsp#callbag#distinctUntilChanged({a,b -> a['bufnr'] == b['bufnr'] && a['curpos'] == b['curpos'] && a['changedtick'] == b['changedtick']}),
40 \ lsp#callbag#filter({_->mode() is# 'n' && getbufvar(bufnr('%'), '&buftype') !=# 'terminal' }),
41 \ lsp#callbag#switchMap({_->
44 \ lsp#callbag#materialize(),
45 \ lsp#callbag#filter({x->lsp#callbag#isNextNotification(x)}),
46 \ lsp#callbag#map({x->x['value']}),
47 \ lsp#callbag#takeUntil(
48 \ lsp#callbag#fromEvent('BufLeave')
52 \ lsp#callbag#subscribe({x->s:set_signs(x)}),
56 function! lsp#internal#document_code_action#signs#_disable() abort
57 if !s:enabled | return | endif
58 if exists('s:Dispose')
64 function! s:send_request() abort
65 let l:servers = filter(lsp#get_allowed_servers(), 'lsp#capabilities#has_code_action_provider(v:val)')
68 return lsp#callbag#empty()
71 let l:range = lsp#utils#range#_get_current_line_range()
72 return lsp#callbag#pipe(
73 \ lsp#callbag#fromList(l:servers),
74 \ lsp#callbag#flatMap({server->
75 \ lsp#request(server, {
76 \ 'method': 'textDocument/codeAction',
78 \ 'textDocument': lsp#get_text_document_identifier(),
82 \ 'only': ['', 'quickfix', 'refactor', 'refactor.extract', 'refactor.inline', 'refactor.rewrite'],
87 \ lsp#callbag#filter({x-> !lsp#client#is_error(x['response']) && !empty(x['response']['result'])}),
88 \ lsp#callbag#take(1),
92 function! s:clear_signs() abort
93 call sign_unplace(s:sign_group)
96 function! s:set_signs(data) abort
99 if lsp#client#is_error(a:data['response']) | return | endif
101 if empty(a:data['response']['result'])
105 let l:bufnr = bufnr(lsp#utils#uri_to_path(a:data['request']['params']['textDocument']['uri']))
106 call s:place_signs(a:data, l:bufnr)
109 " Set default sign text to handle case when user provides empty dict
110 function! s:define_sign(sign_name, sign_default_text, sign_options) abort
112 \ 'text': get(a:sign_options, 'text', a:sign_default_text),
113 \ 'texthl': a:sign_name . 'Text',
114 \ 'linehl': a:sign_name . 'Line',
116 let l:sign_icon = get(a:sign_options, 'icon', '')
117 if !empty(l:sign_icon)
118 let l:options['icon'] = l:sign_icon
120 call sign_define(a:sign_name, l:options)
123 function! s:place_signs(data, bufnr) abort
124 if !bufexists(a:bufnr) || !bufloaded(a:bufnr)
127 let l:sign_priority = g:lsp_document_code_action_signs_priority
128 let l:line = lsp#utils#position#lsp_line_to_vim(a:bufnr, a:data['request']['params']['range']['start'])
129 let l:sign_id = sign_place(0, s:sign_group, 'LspCodeAction', a:bufnr,
130 \ { 'lnum': l:line, 'priority': l:sign_priority })