Skip to content

Commit ed2c818

Browse files
authored
Add support for virtual text diagnostics in Vim9 (#1358)
* Fix virtual-text link in lsp_inlay_hints_enabled docs * Add support for virtual text diagnostics in Vim9
1 parent 0a8d2df commit ed2c818

File tree

4 files changed

+79
-24
lines changed

4 files changed

+79
-24
lines changed

autoload/lsp/internal/diagnostics/virtual_text.vim

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,23 @@ endif
4242

4343
function! lsp#internal#diagnostics#virtual_text#_enable() abort
4444
" don't even bother registering if the feature is disabled
45-
if !lsp#utils#_has_nvim_virtual_text() | return | endif
45+
if !lsp#utils#_has_nvim_virtual_text() && !lsp#utils#_has_vim_virtual_text() | return | endif
4646
if !g:lsp_diagnostics_virtual_text_enabled | return | endif
4747

4848
if s:enabled | return | endif
4949
let s:enabled = 1
5050

51-
if empty(s:namespace_id)
52-
let s:namespace_id = nvim_create_namespace('vim_lsp_diagnostic_virtual_text')
51+
if has('nvim')
52+
if empty(s:namespace_id)
53+
let s:namespace_id = nvim_create_namespace('vim_lsp_diagnostic_virtual_text')
54+
endif
55+
else
56+
if index(prop_type_list(), 'vim_lsp_LspError_virtual_text') ==# -1
57+
call prop_type_add('vim_lsp_LspError_virtual_text', { 'highlight': 'LspErrorVirtualText' })
58+
call prop_type_add('vim_lsp_LspWarning_virtual_text', { 'highlight': 'LspWarningVirtualText' })
59+
call prop_type_add('vim_lsp_LspInformation_virtual_text', { 'highlight': 'LspInformationVirtualText' })
60+
call prop_type_add('vim_lsp_LspHint_virtual_text', { 'highlight': 'LspHintVirtualText' })
61+
endif
5362
endif
5463

5564
let s:Dispose = lsp#callbag#pipe(
@@ -86,11 +95,24 @@ function! lsp#internal#diagnostics#virtual_text#_disable() abort
8695
endfunction
8796

8897
function! s:clear_all_virtual_text() abort
89-
for l:bufnr in nvim_list_bufs()
90-
if bufexists(l:bufnr) && bufloaded(l:bufnr)
91-
call nvim_buf_clear_namespace(l:bufnr, s:namespace_id, 0, -1)
92-
endif
93-
endfor
98+
if has('nvim')
99+
for l:bufnr in nvim_list_bufs()
100+
if bufexists(l:bufnr) && bufloaded(l:bufnr)
101+
call nvim_buf_clear_namespace(l:bufnr, s:namespace_id, 0, -1)
102+
endif
103+
endfor
104+
else
105+
let l:types = ['vim_lsp_LspError_virtual_text', 'vim_lsp_LspWarning_virtual_text', 'vim_lsp_LspInformation_virtual_text', 'vim_lsp_LspHint_virtual_text']
106+
for l:bufnr in map(copy(getbufinfo()), 'v:val.bufnr')
107+
if lsp#utils#_has_prop_remove_types()
108+
call prop_remove({'types': l:types, 'bufnr': l:bufnr, 'all': v:true})
109+
else
110+
for l:type in l:types
111+
call prop_remove({'type': l:type, 'bufnr': l:bufnr, 'all': v:true})
112+
endfor
113+
endif
114+
endfor
115+
endif
94116
endfunction
95117

96118
" params => {
@@ -112,23 +134,50 @@ function! s:set_virtual_text(params) abort
112134
if mode()[0] ==# 'i' | return | endif
113135
endif
114136

115-
for l:bufnr in nvim_list_bufs()
116-
if lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr) && bufexists(l:bufnr) && bufloaded(l:bufnr)
117-
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
118-
for [l:server, l:diagnostics_response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
119-
call s:place_virtual_text(l:server, l:diagnostics_response, l:bufnr)
120-
endfor
121-
endif
122-
endfor
137+
if has('nvim')
138+
for l:bufnr in nvim_list_bufs()
139+
if lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr) && bufexists(l:bufnr) && bufloaded(l:bufnr)
140+
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
141+
for [l:server, l:diagnostics_response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
142+
call s:place_virtual_text(l:server, l:diagnostics_response, l:bufnr)
143+
endfor
144+
endif
145+
endfor
146+
else
147+
for l:bufnr in map(copy(getbufinfo()), 'v:val.bufnr')
148+
if lsp#internal#diagnostics#state#_is_enabled_for_buffer(l:bufnr) && bufexists(l:bufnr) && bufloaded(l:bufnr)
149+
let l:uri = lsp#utils#get_buffer_uri(l:bufnr)
150+
for [l:server, l:diagnostics_response] in items(lsp#internal#diagnostics#state#_get_all_diagnostics_grouped_by_server_for_uri(l:uri))
151+
call s:place_virtual_text(l:server, l:diagnostics_response, l:bufnr)
152+
endfor
153+
endif
154+
endfor
155+
endif
123156
endfunction
124157

125158
function! s:place_virtual_text(server, diagnostics_response, bufnr) abort
126159
for l:item in lsp#utils#iteratable(a:diagnostics_response['params']['diagnostics'])
127-
" need to do -1 for virtual text
128-
let l:line = lsp#utils#position#lsp_line_to_vim(a:bufnr, l:item['range']['start']) - 1
160+
let l:line = lsp#utils#position#lsp_line_to_vim(a:bufnr, l:item['range']['start'])
129161
let l:name = get(s:severity_sign_names_mapping, get(l:item, 'severity', 3), 'LspError')
130-
let l:hl_name = l:name . 'VirtualText'
131-
call nvim_buf_set_virtual_text(a:bufnr, s:namespace_id, l:line,
132-
\ [[g:lsp_diagnostics_virtual_text_prefix . l:item['message'], l:hl_name]], {})
162+
let l:text = g:lsp_diagnostics_virtual_text_prefix . l:item['message']
163+
164+
" Some language servers report an unexpected EOF one line past the end
165+
if l:line == getbufinfo(a:bufnr)[0].linecount + 1
166+
let l:line = l:line - 1
167+
endif
168+
169+
if has('nvim')
170+
let l:hl_name = l:name . 'VirtualText'
171+
" need to do -1 for virtual text
172+
call nvim_buf_set_virtual_text(a:bufnr, s:namespace_id, l:line - 1,
173+
\ [[l:text, l:hl_name]], {})
174+
else
175+
" it's an error to add virtual text on lines that don't exist
176+
" anymore due to async processing, just skip such diagnostics
177+
if l:line <= getbufinfo(a:bufnr)[0].linecount
178+
let l:type = 'vim_lsp_' . l:name . '_virtual_text'
179+
call prop_add(l:line, 0, {'type': l:type, 'text': l:text, 'text_padding_left': 1, 'bufnr': a:bufnr})
180+
endif
181+
endif
133182
endfor
134183
endfunction

autoload/lsp/utils.vim

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ function! lsp#utils#_has_vim_virtual_text() abort
2929
return s:has_vim9textprops
3030
endfunction
3131

32+
let s:has_prop_remove_types = exists('*prop_remove') && has('patch-9.0.0233')
33+
function! lsp#utils#_has_prop_remove_types() abort
34+
return s:has_prop_remove_types
35+
endfunction
36+
3237
let s:has_higlights = has('nvim') ? lsp#utils#_has_nvim_buf_highlight() : lsp#utils#_has_textprops()
3338
function! lsp#utils#_has_highlights() abort
3439
return s:has_higlights

doc/vim-lsp.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,8 @@ g:lsp_diagnostics_virtual_text_enabled
657657
Default: `1` for neovim 0.3+
658658

659659
Enables virtual text to be shown next to diagnostic errors. Requires
660-
NeoVim with version 0.3 or newer and |g:lsp_diagnostics_enabled| set to `1`.
660+
NeoVim with version 0.3 or newer or Vim with |virtual-text| and
661+
patch 9.0.0178, and |g:lsp_diagnostics_enabled| set to `1`.
661662
Virtual text uses the same highlight groups used for signs (eg LspErrorText),
662663
but can be uniquely defined if you want to have different highlight groups
663664
for signs and virtual text. To set unique virtual text highlighting, you
@@ -748,7 +749,7 @@ g:lsp_inlay_hints_enabled
748749
Type: |Number|
749750
Default: `0`
750751

751-
Enables inlay-hints. Requires Vim9 with |virtualtext|.
752+
Enables inlay-hints. Requires Vim9 with |virtual-text|.
752753
patch 9.0.0167 or newer.
753754

754755
Example: >

plugin/lsp.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ let g:lsp_diagnostics_signs_information = get(g:, 'lsp_diagnostics_signs_informa
3232
let g:lsp_diagnostics_signs_hint = get(g:, 'lsp_diagnostics_signs_hint', {})
3333
let g:lsp_diagnostics_signs_priority = get(g:, 'lsp_diagnostics_signs_priority', 10)
3434
let g:lsp_diagnostics_signs_priority_map = get(g:, 'lsp_diagnostics_signs_priority_map', {})
35-
let g:lsp_diagnostics_virtual_text_enabled = get(g:, 'lsp_diagnostics_virtual_text_enabled', lsp#utils#_has_nvim_virtual_text())
35+
let g:lsp_diagnostics_virtual_text_enabled = get(g:, 'lsp_diagnostics_virtual_text_enabled', lsp#utils#_has_nvim_virtual_text() || lsp#utils#_has_vim_virtual_text())
3636
let g:lsp_diagnostics_virtual_text_insert_mode_enabled = get(g:, 'lsp_diagnostics_virtual_text_insert_mode_enabled', 0)
3737
let g:lsp_diagnostics_virtual_text_delay = get(g:, 'lsp_diagnostics_virtual_text_delay', 500)
3838
let g:lsp_diagnostics_virtual_text_prefix = get(g:, 'lsp_diagnostics_virtual_text_prefix', '')

0 commit comments

Comments
 (0)