Skip to content

Commit 4d8a275

Browse files
authored
Inlay hint (#1347)
* inlay hint * implement inlayHints * implement inlayHints * update doc * fix * fix * separate highlights * update/clear * use callbag * remove from doc * disable default * update doc * check version * check label array * call prop_remove() * use lsp#utils#range#get_range() * add comma * add lsp_inlay_hints_mode * own highlight * update doc * fix style check * rename lsp#utils#_has_virtual_text to lsp#utils#_has_nvim_virtual_text lsp#utils#_has_vim9textprops to lsp#utils#_has_vim_virtual_text * update doc * fix version * remove all
1 parent e5d2d3f commit 4d8a275

File tree

8 files changed

+210
-4
lines changed

8 files changed

+210
-4
lines changed

autoload/lsp.vim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ function! lsp#enable() abort
6969
call lsp#internal#show_message#_enable()
7070
call lsp#internal#work_done_progress#_enable()
7171
call lsp#internal#completion#documentation#_enable()
72+
call lsp#internal#inlay_hints#_enable()
7273
call s:register_events()
7374
endfunction
7475

@@ -540,6 +541,9 @@ function! lsp#default_get_supported_capabilities(server_info) abort
540541
\ 'dynamicRegistration': v:false,
541542
\ 'contentFormat': ['markdown', 'plaintext'],
542543
\ },
544+
\ 'inlayHint': {
545+
\ 'dynamicRegistration': v:false,
546+
\ },
543547
\ 'implementation': {
544548
\ 'dynamicRegistration': v:false,
545549
\ 'linkSupport' : v:true

autoload/lsp/capabilities.vim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,7 @@ endfunction
192192
function! lsp#capabilities#has_completion_resolve_provider(server_name) abort
193193
return s:has_provider(a:server_name, 'completionProvider', 'resolveProvider')
194194
endfunction
195+
196+
function! lsp#capabilities#has_inlay_hint_provider(server_name) abort
197+
return s:has_provider(a:server_name, 'inlayHintProvider')
198+
endfunction

autoload/lsp/internal/diagnostics/virtual_text.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ 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_virtual_text() | return | endif
45+
if !lsp#utils#_has_nvim_virtual_text() | return | endif
4646
if !g:lsp_diagnostics_virtual_text_enabled | return | endif
4747

4848
if s:enabled | return | endif
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
let s:use_vim_textprops = lsp#utils#_has_vim_virtual_text() && !has('nvim')
2+
3+
function! s:set_inlay_hints(data) abort
4+
let l:bufnr = bufnr('%')
5+
6+
call s:clear_inlay_hints()
7+
8+
if mode() !=# 'n' | return | endif
9+
10+
if lsp#client#is_error(a:data['response']) | return | endif
11+
12+
" Get hints from the response
13+
let l:hints = a:data['response']['result']
14+
if empty(l:hints)
15+
return
16+
endif
17+
18+
let l:not_curline = s:has_inlay_hints_mode('!curline')
19+
for l:hint in l:hints
20+
if l:not_curline && l:hint.position.line+1 ==# line('.')
21+
continue
22+
endif
23+
let l:label = ''
24+
if type(l:hint.label) ==# v:t_list
25+
let l:label = join(map(copy(l:hint.label), {_,v -> v.value}), ', ')
26+
else
27+
let l:label = l:hint.label
28+
endif
29+
let l:text = (get(l:hint, 'paddingLeft', v:false) ? ' ' : '') . l:label . (get(l:hint, 'paddingRight', v:false) ? ' ' : '')
30+
if !has_key(l:hint, 'kind') || l:hint.kind ==# 1
31+
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})
32+
elseif l:hint.kind ==# 2
33+
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})
34+
endif
35+
endfor
36+
endfunction
37+
38+
function! s:init_inlay_hints() abort
39+
if index(prop_type_list(), 'vim_lsp_inlay_hint_type') ==# -1
40+
call prop_type_add('vim_lsp_inlay_hint_type', { 'highlight': 'lspInlayHintsType' })
41+
call prop_type_add('vim_lsp_inlay_hint_parameter', { 'highlight': 'lspInlayHintsParameter' })
42+
endif
43+
endfunction
44+
45+
function! lsp#internal#inlay_hints#_disable() abort
46+
if exists('s:Dispose')
47+
call s:Dispose()
48+
unlet s:Dispose
49+
endif
50+
endfunction
51+
52+
function! s:clear_inlay_hints() abort
53+
let l:bufnr = bufnr('%')
54+
call prop_remove({'type': 'vim_lsp_inlay_hint_type', 'bufnr': l:bufnr, 'all': v:true})
55+
call prop_remove({'type': 'vim_lsp_inlay_hint_parameter', 'bufnr': l:bufnr, 'all': v:true})
56+
endfunction
57+
58+
function! s:has_inlay_hints_mode(value) abort
59+
let l:m = get(g:, 'lsp_inlay_hints_mode', {})
60+
if type(l:m) != v:t_dict | return v:false | endif
61+
if mode() ==# 'i'
62+
let l:a = get(l:m, 'insert', [])
63+
elseif mode() ==# 'n'
64+
let l:a = get(l:m, 'normal', [])
65+
else
66+
return v:false
67+
endif
68+
if type(l:a) != v:t_list | return v:false | endif
69+
return index(l:a, a:value) != -1 ? v:true : v:false
70+
endfunction
71+
72+
function! s:send_inlay_hints_request() abort
73+
let l:capability = 'lsp#capabilities#has_inlay_hint_provider(v:val)'
74+
let l:servers = filter(lsp#get_allowed_servers(), l:capability)
75+
76+
if empty(l:servers)
77+
return lsp#callbag#empty()
78+
endif
79+
80+
if s:has_inlay_hints_mode('curline')
81+
let l:range = lsp#utils#range#get_range_curline()
82+
else
83+
let l:range = lsp#utils#range#get_range()
84+
endif
85+
return lsp#request(l:servers[0], {
86+
\ 'method': 'textDocument/inlayHint',
87+
\ 'params': {
88+
\ 'textDocument': lsp#get_text_document_identifier(),
89+
\ 'range': l:range,
90+
\ },
91+
\ })
92+
endfunction
93+
94+
function! lsp#internal#inlay_hints#_enable() abort
95+
if !s:use_vim_textprops | return | endif
96+
if !g:lsp_inlay_hints_enabled | return | endif
97+
98+
if !hlexists('lspInlayHintsType')
99+
highlight link lspInlayHintsType Label
100+
endif
101+
if !hlexists('lspInlayHintsParameter')
102+
highlight link lspInlayHintsParameter Todo
103+
endif
104+
105+
call s:init_inlay_hints()
106+
let s:Dispose = lsp#callbag#pipe(
107+
\ lsp#callbag#merge(
108+
\ lsp#callbag#fromEvent(['CursorMoved', 'CursorHold']),
109+
\ lsp#callbag#pipe(
110+
\ lsp#callbag#fromEvent(['InsertEnter', 'BufLeave']),
111+
\ lsp#callbag#tap({_ -> s:clear_inlay_hints() }),
112+
\ )
113+
\ ),
114+
\ lsp#callbag#filter({_ -> g:lsp_inlay_hints_enabled }),
115+
\ lsp#callbag#debounceTime(g:lsp_inlay_hints_delay),
116+
\ lsp#callbag#filter({_->getbufvar(bufnr('%'), '&buftype') !~# '^(help\|terminal\|prompt\|popup)$'}),
117+
\ lsp#callbag#switchMap({_->
118+
\ lsp#callbag#pipe(
119+
\ s:send_inlay_hints_request(),
120+
\ lsp#callbag#materialize(),
121+
\ lsp#callbag#filter({x->lsp#callbag#isNextNotification(x)}),
122+
\ lsp#callbag#map({x->x['value']})
123+
\ )
124+
\ }),
125+
\ lsp#callbag#subscribe({x->s:set_inlay_hints(x)}),
126+
\)
127+
endfunction

autoload/lsp/utils.vim

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ function! lsp#utils#has_lua() abort
44
endfunction
55

66
let s:has_virtual_text = exists('*nvim_buf_set_virtual_text') && exists('*nvim_create_namespace')
7-
function! lsp#utils#_has_virtual_text() abort
7+
function! lsp#utils#_has_nvim_virtual_text() abort
88
return s:has_virtual_text
99
endfunction
1010

@@ -24,6 +24,11 @@ function! lsp#utils#_has_textprops() abort
2424
return s:has_textprops
2525
endfunction
2626

27+
let s:has_vim9textprops = exists('*prop_add') && has('patch-9.0.0178')
28+
function! lsp#utils#_has_vim_virtual_text() abort
29+
return s:has_vim9textprops
30+
endfunction
31+
2732
let s:has_higlights = has('nvim') ? lsp#utils#_has_nvim_buf_highlight() : lsp#utils#_has_textprops()
2833
function! lsp#utils#_has_highlights() abort
2934
return s:has_higlights

autoload/lsp/utils/range.vim

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,13 @@ function! lsp#utils#range#lsp_to_vim(bufnr, range) abort
7070

7171
return l:position
7272
endfunction
73+
74+
function! lsp#utils#range#get_range() abort
75+
let l:char = lsp#utils#to_char('%', line('$'), col('$'))
76+
return {'start': {'line': 0, 'character': 0}, 'end': {'line': line('$')-1, 'character': l:char}}
77+
endfunction
78+
79+
function! lsp#utils#range#get_range_curline() abort
80+
let l:char = lsp#utils#to_char('%', line('.'), col('$'))
81+
return {'start': {'line': line('.')-1, 'character': 0}, 'end': {'line': line('.')-1, 'character': l:char}}
82+
endfunction

doc/vim-lsp.txt

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ CONTENTS *vim-lsp-contents*
5353
|g:lsp_document_code_actions_signs_enabled|
5454
g:lsp_document_code_action_signs_delay
5555
|g:lsp_document_code_actions_signs_delay|
56+
g:lsp_inlay_hints_enabled
57+
|g:lsp_inlay_hints_enabled|
58+
g:lsp_inlay_hints_delay
59+
|g:lsp_inlay_hints_delay|
60+
g:lsp_inlay_hints_mode
61+
|g:lsp_inlay_hints_mode|
5662
g:lsp_tree_incoming_prefix |g:lsp_tree_incoming_prefix|
5763
g:lsp_format_sync_timeout |g:lsp_format_sync_timeout|
5864
g:lsp_use_event_queue |g:lsp_use_event_queue|
@@ -728,6 +734,54 @@ g:lsp_document_code_action_signs_delay
728734
let g:lsp_document_code_action_signs_delay = 200
729735
let g:lsp_document_code_action_signs_delay = 1000
730736
>
737+
g:lsp_inlay_hints_enabled
738+
*g:lsp_inlay_hints_enabled*
739+
Type: |Number|
740+
Default: `1`
741+
742+
Enables inlay-hints. Requires Vim9 with |virtualtext|.
743+
patch 9.0.0167 or newer.
744+
745+
Example: >
746+
let g:lsp_inlay_hints_enabled = 1
747+
let g:lsp_inlay_hints_enabled = 0
748+
<
749+
To change the style of the inlay-hints, you can set or link the
750+
`lspInlayHintsType` and `lspInlayHintsParameter` highlight group.
751+
752+
Example: >
753+
highlight lspInlayHintsType ctermfg=red guifg=red
754+
\ ctermbg=green guibg=green
755+
highlight lspInlayHintsParameter ctermfg=red guifg=red
756+
\ ctermbg=green guibg=green
757+
758+
g:lsp_inlay_hints_delay
759+
*g:lsp_inlay_hints_delay*
760+
Type: |Number|
761+
Default: `350`
762+
763+
Delay milliseconds to update inlay-hints. Requires
764+
|g:lsp_inlay_hints_enabled|.
765+
766+
Example: >
767+
let g:lsp_inlay_hints_delay = 200
768+
let g:lsp_inlay_hints_delay = 1000
769+
>
770+
g:lsp_inlay_hints_mode
771+
*g:lsp_inlay_hints_mode*
772+
Type: |Dict|
773+
Default: `{}`
774+
775+
This mode currently only include "curline" and "!curline".
776+
777+
Example: >
778+
let g:lsp_inlay_hints_mode = {
779+
\ 'normal': ['curline'],
780+
\}
781+
<
782+
"curline" show hint only for current line. "!curline" show hints except
783+
current line. Default show all hints.
784+
>
731785
g:lsp_tree_incoming_prefix *g:lsp_tree_incoming_prefix*
732786
Type: |String|
733787
Default: `"<= "`
@@ -1478,7 +1532,7 @@ lsp#get_progress() *lsp#get_progress()*
14781532
Type: |Number|
14791533
0 - 100 or not exist
14801534

1481-
lsp#document_hover_preview_winid() *lsp#document_hover_preview_winid()*
1535+
lsp#document_hover_preview_winid() *lsp#document_hover_preview_winid()*
14821536

14831537
Returns |windowid| of the current hover preview window or |v:null| if it does not
14841538
exist.

plugin/lsp.vim

Lines changed: 3 additions & 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_virtual_text())
35+
let g:lsp_diagnostics_virtual_text_enabled = get(g:, 'lsp_diagnostics_virtual_text_enabled', lsp#utils#_has_nvim_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', '')
@@ -72,6 +72,8 @@ let g:lsp_show_message_request_enabled = get(g:, 'lsp_show_message_request_enabl
7272
let g:lsp_show_message_log_level = get(g:, 'lsp_show_message_log_level', 'warning')
7373
let g:lsp_work_done_progress_enabled = get(g:, 'lsp_work_done_progress_enabled', 0)
7474
let g:lsp_untitled_buffer_enabled = get(g:, 'lsp_untitled_buffer_enabled', 1)
75+
let g:lsp_inlay_hints_enabled = get(g:, 'lsp_inlay_hints_enabled', 0)
76+
let g:lsp_inlay_hints_delay = get(g:, 'lsp_inlay_hints_delay', 350)
7577

7678
let g:lsp_get_supported_capabilities = get(g:, 'lsp_get_supported_capabilities', [function('lsp#default_get_supported_capabilities')])
7779

0 commit comments

Comments
 (0)