]> git.madduck.net Git - etc/vim.git/blob - autoload/lsp/internal/diagnostics/highlights.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

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.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Squashed '.vim/bundle/vim-lsp/' content from commit 04428c92
[etc/vim.git] / autoload / lsp / internal / diagnostics / highlights.vim
1 " internal state for whether it is enabled or not to avoid multiple subscriptions
2 let s:enabled = 0
3 let s:namespace_id = '' " will be set when enabled
4
5 let s:severity_sign_names_mapping = {
6     \ 1: 'LspError',
7     \ 2: 'LspWarning',
8     \ 3: 'LspInformation',
9     \ 4: 'LspHint',
10     \ }
11
12 if !hlexists('LspErrorHighlight')
13     highlight link LspErrorHighlight Error
14 endif
15
16 if !hlexists('LspWarningHighlight')
17     highlight link LspWarningHighlight Todo
18 endif
19
20 if !hlexists('LspInformationHighlight')
21     highlight link LspInformationHighlight Normal
22 endif
23
24 if !hlexists('LspHintHighlight')
25     highlight link LspHintHighlight Normal
26 endif
27
28 function! lsp#internal#diagnostics#highlights#_enable() abort
29     " don't even bother registering if the feature is disabled
30     if !lsp#utils#_has_highlights() | return | endif
31     if !g:lsp_diagnostics_highlights_enabled | return | endif
32
33     if s:enabled | return | endif
34     let s:enabled = 1
35
36     if empty(s:namespace_id)
37         if has('nvim')
38             let s:namespace_id = nvim_create_namespace('vim_lsp_diagnostics_highlights')
39         else
40             let s:namespace_id = 'vim_lsp_diagnostics_highlights'
41             for l:severity in keys(s:severity_sign_names_mapping)
42                 let l:hl_group = s:severity_sign_names_mapping[l:severity] . 'Highlight'
43                 call prop_type_add(s:get_prop_type_name(l:severity),
44                     \ {'highlight': l:hl_group, 'combine': v:true, 'priority': lsp#internal#textprop#priority('diagnostics_highlight') })
45             endfor
46         endif
47     endif
48
49     let s:Dispose = lsp#callbag#pipe(
50         \ lsp#callbag#merge(
51         \   lsp#callbag#pipe(
52         \       lsp#stream(),
53         \       lsp#callbag#filter({x->has_key(x, 'server') && has_key(x, 'response')
54         \       && has_key(x['response'], 'method') && x['response']['method'] ==# '$/vimlsp/lsp_diagnostics_updated'
55         \       && !lsp#client#is_error(x['response'])}),
56         \       lsp#callbag#map({x->x['response']['params']}),
57         \   ),
58         \   lsp#callbag#pipe(
59         \       lsp#callbag#fromEvent(['InsertEnter', 'InsertLeave']),
60         \       lsp#callbag#filter({_->!g:lsp_diagnostics_highlights_insert_mode_enabled}),
61         \       lsp#callbag#map({_->{ 'uri': lsp#utils#get_buffer_uri() }}),
62         \   ),
63         \ ),
64         \ lsp#callbag#filter({_->g:lsp_diagnostics_highlights_enabled}),
65         \ lsp#callbag#debounceTime(g:lsp_diagnostics_highlights_delay),
66         \ lsp#callbag#tap({x->s:clear_highlights(x)}),
67         \ lsp#callbag#tap({x->s:set_highlights(x)}),
68         \ lsp#callbag#subscribe(),
69         \ )
70 endfunction
71
72 function! lsp#internal#diagnostics#highlights#_disable() abort
73     if !s:enabled | return | endif
74     if exists('s:Dispose')
75         call s:Dispose()
76         unlet s:Dispose
77     endif
78     call s:clear_all_highlights()
79     let s:enabled = 0
80 endfunction
81
82 function! s:get_prop_type_name(severity) abort
83     return s:namespace_id . '_' . get(s:severity_sign_names_mapping, a:severity, 'LspError')
84 endfunction
85
86 function! s:clear_all_highlights() abort
87     for l:bufnr in range(1, bufnr('$'))
88         if bufexists(l:bufnr) && bufloaded(l:bufnr)
89             if has('nvim')
90                 call nvim_buf_clear_namespace(l:bufnr, s:namespace_id, 0, -1)
91             else
92                 for l:severity in keys(s:severity_sign_names_mapping)
93                     try
94                         " TODO: need to check for valid range before calling prop_add
95                         " See https://github.com/prabirshrestha/vim-lsp/pull/721
96                         silent! call prop_remove({
97                             \ 'type': s:get_prop_type_name(l:severity),
98                             \ 'bufnr': l:bufnr,
99                             \ 'all': v:true })
100                     catch
101                         call lsp#log('diagnostics', 'clear_all_highlights', 'prop_remove', v:exception, v:throwpoint)
102                     endtry
103                 endfor
104             endif
105         endif
106     endfor
107 endfunction
108
109 function! s:clear_highlights(params) abort
110     " TODO: optimize by looking at params
111     call s:clear_all_highlights()
112 endfunction
113
114 function! s:set_highlights(params) abort
115     " TODO: optimize by looking at params
116     if !g:lsp_diagnostics_highlights_insert_mode_enabled
117         if mode()[0] ==# 'i' | return | endif
118     endif
119
120     for l:bufnr in range(1, bufnr('$'))
121         if lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr) && bufexists(l:bufnr) && bufloaded(l:bufnr)
122             let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
123             for [l:server, l:diagnostics_response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
124                 call s:place_highlights(l:server, l:diagnostics_response, l:bufnr)
125             endfor
126         endif
127     endfor
128 endfunction
129
130 function! s:place_highlights(server, diagnostics_response, bufnr) abort
131     " TODO: make diagnostics highlights same across vim and neovim
132     for l:item in lsp#utils#iteratable(a:diagnostics_response['params']['diagnostics'])
133         let [l:start_line, l:start_col] = lsp#utils#position#lsp_to_vim(a:bufnr, l:item['range']['start'])
134         let [l:end_line, l:end_col] = lsp#utils#position#lsp_to_vim(a:bufnr, l:item['range']['end'])
135         let l:severity = get(l:item, 'severity', 3)
136         let l:hl_group = get(s:severity_sign_names_mapping, l:severity, 'LspError') . 'Highlight'
137         if has('nvim')
138             for l:line in range(l:start_line, l:end_line)
139                 if l:line == l:start_line
140                     let l:highlight_start_col = l:start_col
141                 else
142                     let l:highlight_start_col = 1
143                 endif
144
145                 if l:line == l:end_line
146                     let l:highlight_end_col = l:end_col
147                 else
148                     " neovim treats -1 as end of line, special handle it later
149                     " when calling nvim_buf_add_higlight
150                     let l:highlight_end_col = -1
151                 endif
152
153                 if l:start_line == l:end_line && l:highlight_start_col == l:highlight_end_col
154                     " higlighting same start col and end col on same line
155                     " doesn't work so use -1 for start col
156                     let l:highlight_start_col -= 1
157                     if l:highlight_start_col <= 0
158                         let l:highlight_start_col = 1
159                     endif
160                 endif
161
162                 call nvim_buf_add_highlight(a:bufnr, s:namespace_id, l:hl_group,
163                    \ l:line - 1, l:highlight_start_col - 1, l:highlight_end_col == -1 ? -1 : l:highlight_end_col - 1)
164             endfor
165         else
166             if l:start_line == l:end_line
167                 try
168                      " TODO: need to check for valid range before calling prop_add
169                      " See https://github.com/prabirshrestha/vim-lsp/pull/721
170                      silent! call prop_add(l:start_line, l:start_col, {
171                      \ 'end_col': l:end_col,
172                      \ 'bufnr': a:bufnr,
173                      \ 'type': s:get_prop_type_name(l:severity),
174                      \ })
175                 catch
176                      call lsp#log('diagnostics', 'place_highlights', 'prop_add', v:exception, v:throwpoint)
177                 endtry
178             else
179                 for l:line in range(l:start_line, l:end_line)
180                     if l:line == l:start_line
181                         let l:highlight_start_col = l:start_col
182                     else
183                         let l:highlight_start_col = 1
184                     endif
185
186                     if l:line == l:end_line
187                         let l:highlight_end_col = l:end_col
188                     else
189                         if has('patch-9.0.0916')
190                             let l:highlight_end_col = strlen(getbufoneline(a:bufnr, l:line)) + 1
191                         else
192                             let l:highlight_end_col = strlen(getbufline(a:bufnr, l:line)[0]) + 1
193                         endif
194                     endif
195
196                     try
197                         " TODO: need to check for valid range before calling prop_add
198                         " See https://github.com/prabirshrestha/vim-lsp/pull/721
199                         silent! call prop_add(l:line, l:highlight_start_col, {
200                         \ 'end_col': l:highlight_end_col,
201                         \ 'bufnr': a:bufnr,
202                         \ 'type': s:get_prop_type_name(l:severity),
203                         \ })
204                     catch
205                         call lsp#log('diagnostics', 'place_highlights', 'prop_add', v:exception, v:throwpoint)
206                     endtry
207                 endfor
208             endif
209         endif
210     endfor
211 endfunction