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 " internal state for whether it is enabled or not to avoid multiple subscriptions
3 let s:sign_group = 'vim_lsp'
5 let s:severity_sign_names_mapping = {
12 if !hlexists('LspErrorText')
13 highlight link LspErrorText Error
16 if !hlexists('LspWarningText')
17 highlight link LspWarningText Todo
20 if !hlexists('LspInformationText')
21 highlight link LspInformationText Normal
24 if !hlexists('LspHintText')
25 highlight link LspHintText Normal
29 let s:Buffer = vital#lsp#import('VS.Vim.Buffer')
31 function! lsp#internal#diagnostics#signs#_enable() abort
32 " don't even bother registering if the feature is disabled
33 if !lsp#utils#_has_signs() | return | endif
34 if !g:lsp_diagnostics_signs_enabled | return | endif
36 if s:enabled | return | endif
39 call s:define_sign('LspError', 'E>', g:lsp_diagnostics_signs_error)
40 call s:define_sign('LspWarning', 'W>', g:lsp_diagnostics_signs_warning)
41 call s:define_sign('LspInformation', 'I>', g:lsp_diagnostics_signs_information)
42 call s:define_sign('LspHint', 'H>', g:lsp_diagnostics_signs_hint)
44 let s:Dispose = lsp#callbag#pipe(
48 \ lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
49 \ && has_key(x['response'], 'method') && x['response']['method'] ==# '$/vimlsp/lsp_diagnostics_updated'
50 \ && !lsp#client#is_error(x['response'])}),
51 \ lsp#callbag#map({x->x['response']['params']}),
54 \ lsp#callbag#fromEvent(['InsertEnter', 'InsertLeave']),
55 \ lsp#callbag#filter({_->!g:lsp_diagnostics_signs_insert_mode_enabled}),
56 \ lsp#callbag#map({_->{ 'uri': lsp#utils#get_buffer_uri() }}),
59 \ lsp#callbag#filter({_->g:lsp_diagnostics_signs_enabled}),
60 \ lsp#callbag#debounceTime(g:lsp_diagnostics_signs_delay),
61 \ lsp#callbag#tap({x->s:clear_signs(x)}),
62 \ lsp#callbag#tap({x->s:set_signs(x)}),
63 \ lsp#callbag#subscribe(),
67 function! lsp#internal#diagnostics#signs#_disable() abort
68 if !s:enabled | return | endif
69 if exists('s:Dispose')
73 call s:clear_all_signs()
74 call s:undefine_signs()
78 " Set default sign text to handle case when user provides empty dict
79 function! s:define_sign(sign_name, sign_default_text, sign_options) abort
81 \ 'text': get(a:sign_options, 'text', a:sign_default_text),
82 \ 'texthl': a:sign_name . 'Text',
83 \ 'linehl': a:sign_name . 'Line',
85 let l:sign_icon = get(a:sign_options, 'icon', '')
86 if !empty(l:sign_icon)
87 let l:options['icon'] = l:sign_icon
89 call sign_define(a:sign_name, l:options)
92 function! s:undefine_signs() abort
93 call sign_undefine('LspError')
94 call sign_undefine('LspWarning')
95 call sign_undefine('LspInformation')
96 call sign_undefine('LspHint')
99 function! s:clear_all_signs() abort
100 call sign_unplace(s:sign_group)
104 " server: '' " optional
107 function! s:clear_signs(params) abort
108 " TODO: optimize by looking at params
109 call s:clear_all_signs()
113 " server: '' " optional
116 function! s:set_signs(params) abort
117 " TODO: optimize by looking at params
118 if !g:lsp_diagnostics_signs_insert_mode_enabled
119 if mode()[0] ==# 'i' | return | endif
122 for l:bufnr in range(1, bufnr('$'))
123 if lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr) && bufexists(l:bufnr) && bufloaded(l:bufnr)
124 let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
125 for [l:server, l:diagnostics_response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
126 call s:place_signs(l:server, l:diagnostics_response, l:bufnr)
132 function! s:place_signs(server, diagnostics_response, bufnr) abort
133 let l:linecount = s:Buffer.get_line_count(a:bufnr)
134 for l:item in lsp#utils#iteratable(a:diagnostics_response['params']['diagnostics'])
135 let l:line = lsp#utils#position#lsp_line_to_vim(a:bufnr, l:item['range']['start'])
137 " Some language servers report an unexpected EOF one line past the end
138 if l:line == l:linecount + 1
139 let l:line = l:line - 1
142 if has_key(l:item, 'severity') && !empty(l:item['severity'])
143 let l:sign_name = get(s:severity_sign_names_mapping, l:item['severity'], 'LspError')
144 let l:sign_priority = get(g:lsp_diagnostics_signs_priority_map, l:sign_name, g:lsp_diagnostics_signs_priority)
145 let l:sign_priority = get(g:lsp_diagnostics_signs_priority_map,
146 \ a:server . '_' . l:sign_name, l:sign_priority)
147 " pass 0 and let vim generate sign id
148 let l:sign_id = sign_place(0, s:sign_group, l:sign_name, a:bufnr,
149 \{ 'lnum': l:line, 'priority': l:sign_priority })