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
This commit is contained in:
mattn
2022-08-25 02:02:42 +09:00
committed by GitHub
parent e5d2d3f744
commit 4d8a27513d
8 changed files with 210 additions and 4 deletions

View File

@@ -69,6 +69,7 @@ function! lsp#enable() abort
call lsp#internal#show_message#_enable() call lsp#internal#show_message#_enable()
call lsp#internal#work_done_progress#_enable() call lsp#internal#work_done_progress#_enable()
call lsp#internal#completion#documentation#_enable() call lsp#internal#completion#documentation#_enable()
call lsp#internal#inlay_hints#_enable()
call s:register_events() call s:register_events()
endfunction endfunction
@@ -540,6 +541,9 @@ function! lsp#default_get_supported_capabilities(server_info) abort
\ 'dynamicRegistration': v:false, \ 'dynamicRegistration': v:false,
\ 'contentFormat': ['markdown', 'plaintext'], \ 'contentFormat': ['markdown', 'plaintext'],
\ }, \ },
\ 'inlayHint': {
\ 'dynamicRegistration': v:false,
\ },
\ 'implementation': { \ 'implementation': {
\ 'dynamicRegistration': v:false, \ 'dynamicRegistration': v:false,
\ 'linkSupport' : v:true \ 'linkSupport' : v:true

View File

@@ -192,3 +192,7 @@ endfunction
function! lsp#capabilities#has_completion_resolve_provider(server_name) abort function! lsp#capabilities#has_completion_resolve_provider(server_name) abort
return s:has_provider(a:server_name, 'completionProvider', 'resolveProvider') return s:has_provider(a:server_name, 'completionProvider', 'resolveProvider')
endfunction endfunction
function! lsp#capabilities#has_inlay_hint_provider(server_name) abort
return s:has_provider(a:server_name, 'inlayHintProvider')
endfunction

View File

@@ -42,7 +42,7 @@ endif
function! lsp#internal#diagnostics#virtual_text#_enable() abort function! lsp#internal#diagnostics#virtual_text#_enable() abort
" don't even bother registering if the feature is disabled " don't even bother registering if the feature is disabled
if !lsp#utils#_has_virtual_text() | return | endif if !lsp#utils#_has_nvim_virtual_text() | return | endif
if !g:lsp_diagnostics_virtual_text_enabled | return | endif if !g:lsp_diagnostics_virtual_text_enabled | return | endif
if s:enabled | return | endif if s:enabled | return | endif

View File

@@ -0,0 +1,127 @@
let s:use_vim_textprops = lsp#utils#_has_vim_virtual_text() && !has('nvim')
function! s:set_inlay_hints(data) abort
let l:bufnr = bufnr('%')
call s:clear_inlay_hints()
if mode() !=# 'n' | return | endif
if lsp#client#is_error(a:data['response']) | return | endif
" Get hints from the response
let l:hints = a:data['response']['result']
if empty(l:hints)
return
endif
let l:not_curline = s:has_inlay_hints_mode('!curline')
for l:hint in l:hints
if l:not_curline && l:hint.position.line+1 ==# line('.')
continue
endif
let l:label = ''
if type(l:hint.label) ==# v:t_list
let l:label = join(map(copy(l:hint.label), {_,v -> v.value}), ', ')
else
let l:label = l:hint.label
endif
let l:text = (get(l:hint, 'paddingLeft', v:false) ? ' ' : '') . l:label . (get(l:hint, 'paddingRight', v:false) ? ' ' : '')
if !has_key(l:hint, 'kind') || l:hint.kind ==# 1
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})
elseif l:hint.kind ==# 2
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})
endif
endfor
endfunction
function! s:init_inlay_hints() abort
if index(prop_type_list(), 'vim_lsp_inlay_hint_type') ==# -1
call prop_type_add('vim_lsp_inlay_hint_type', { 'highlight': 'lspInlayHintsType' })
call prop_type_add('vim_lsp_inlay_hint_parameter', { 'highlight': 'lspInlayHintsParameter' })
endif
endfunction
function! lsp#internal#inlay_hints#_disable() abort
if exists('s:Dispose')
call s:Dispose()
unlet s:Dispose
endif
endfunction
function! s:clear_inlay_hints() abort
let l:bufnr = bufnr('%')
call prop_remove({'type': 'vim_lsp_inlay_hint_type', 'bufnr': l:bufnr, 'all': v:true})
call prop_remove({'type': 'vim_lsp_inlay_hint_parameter', 'bufnr': l:bufnr, 'all': v:true})
endfunction
function! s:has_inlay_hints_mode(value) abort
let l:m = get(g:, 'lsp_inlay_hints_mode', {})
if type(l:m) != v:t_dict | return v:false | endif
if mode() ==# 'i'
let l:a = get(l:m, 'insert', [])
elseif mode() ==# 'n'
let l:a = get(l:m, 'normal', [])
else
return v:false
endif
if type(l:a) != v:t_list | return v:false | endif
return index(l:a, a:value) != -1 ? v:true : v:false
endfunction
function! s:send_inlay_hints_request() abort
let l:capability = 'lsp#capabilities#has_inlay_hint_provider(v:val)'
let l:servers = filter(lsp#get_allowed_servers(), l:capability)
if empty(l:servers)
return lsp#callbag#empty()
endif
if s:has_inlay_hints_mode('curline')
let l:range = lsp#utils#range#get_range_curline()
else
let l:range = lsp#utils#range#get_range()
endif
return lsp#request(l:servers[0], {
\ 'method': 'textDocument/inlayHint',
\ 'params': {
\ 'textDocument': lsp#get_text_document_identifier(),
\ 'range': l:range,
\ },
\ })
endfunction
function! lsp#internal#inlay_hints#_enable() abort
if !s:use_vim_textprops | return | endif
if !g:lsp_inlay_hints_enabled | return | endif
if !hlexists('lspInlayHintsType')
highlight link lspInlayHintsType Label
endif
if !hlexists('lspInlayHintsParameter')
highlight link lspInlayHintsParameter Todo
endif
call s:init_inlay_hints()
let s:Dispose = lsp#callbag#pipe(
\ lsp#callbag#merge(
\ lsp#callbag#fromEvent(['CursorMoved', 'CursorHold']),
\ lsp#callbag#pipe(
\ lsp#callbag#fromEvent(['InsertEnter', 'BufLeave']),
\ lsp#callbag#tap({_ -> s:clear_inlay_hints() }),
\ )
\ ),
\ lsp#callbag#filter({_ -> g:lsp_inlay_hints_enabled }),
\ lsp#callbag#debounceTime(g:lsp_inlay_hints_delay),
\ lsp#callbag#filter({_->getbufvar(bufnr('%'), '&buftype') !~# '^(help\|terminal\|prompt\|popup)$'}),
\ lsp#callbag#switchMap({_->
\ lsp#callbag#pipe(
\ s:send_inlay_hints_request(),
\ lsp#callbag#materialize(),
\ lsp#callbag#filter({x->lsp#callbag#isNextNotification(x)}),
\ lsp#callbag#map({x->x['value']})
\ )
\ }),
\ lsp#callbag#subscribe({x->s:set_inlay_hints(x)}),
\)
endfunction

View File

@@ -4,7 +4,7 @@ function! lsp#utils#has_lua() abort
endfunction endfunction
let s:has_virtual_text = exists('*nvim_buf_set_virtual_text') && exists('*nvim_create_namespace') let s:has_virtual_text = exists('*nvim_buf_set_virtual_text') && exists('*nvim_create_namespace')
function! lsp#utils#_has_virtual_text() abort function! lsp#utils#_has_nvim_virtual_text() abort
return s:has_virtual_text return s:has_virtual_text
endfunction endfunction
@@ -24,6 +24,11 @@ function! lsp#utils#_has_textprops() abort
return s:has_textprops return s:has_textprops
endfunction endfunction
let s:has_vim9textprops = exists('*prop_add') && has('patch-9.0.0178')
function! lsp#utils#_has_vim_virtual_text() abort
return s:has_vim9textprops
endfunction
let s:has_higlights = has('nvim') ? lsp#utils#_has_nvim_buf_highlight() : lsp#utils#_has_textprops() let s:has_higlights = has('nvim') ? lsp#utils#_has_nvim_buf_highlight() : lsp#utils#_has_textprops()
function! lsp#utils#_has_highlights() abort function! lsp#utils#_has_highlights() abort
return s:has_higlights return s:has_higlights

View File

@@ -70,3 +70,13 @@ function! lsp#utils#range#lsp_to_vim(bufnr, range) abort
return l:position return l:position
endfunction endfunction
function! lsp#utils#range#get_range() abort
let l:char = lsp#utils#to_char('%', line('$'), col('$'))
return {'start': {'line': 0, 'character': 0}, 'end': {'line': line('$')-1, 'character': l:char}}
endfunction
function! lsp#utils#range#get_range_curline() abort
let l:char = lsp#utils#to_char('%', line('.'), col('$'))
return {'start': {'line': line('.')-1, 'character': 0}, 'end': {'line': line('.')-1, 'character': l:char}}
endfunction

View File

@@ -53,6 +53,12 @@ CONTENTS *vim-lsp-contents*
|g:lsp_document_code_actions_signs_enabled| |g:lsp_document_code_actions_signs_enabled|
g:lsp_document_code_action_signs_delay g:lsp_document_code_action_signs_delay
|g:lsp_document_code_actions_signs_delay| |g:lsp_document_code_actions_signs_delay|
g:lsp_inlay_hints_enabled
|g:lsp_inlay_hints_enabled|
g:lsp_inlay_hints_delay
|g:lsp_inlay_hints_delay|
g:lsp_inlay_hints_mode
|g:lsp_inlay_hints_mode|
g:lsp_tree_incoming_prefix |g:lsp_tree_incoming_prefix| g:lsp_tree_incoming_prefix |g:lsp_tree_incoming_prefix|
g:lsp_format_sync_timeout |g:lsp_format_sync_timeout| g:lsp_format_sync_timeout |g:lsp_format_sync_timeout|
g:lsp_use_event_queue |g:lsp_use_event_queue| g:lsp_use_event_queue |g:lsp_use_event_queue|
@@ -728,6 +734,54 @@ g:lsp_document_code_action_signs_delay
let g:lsp_document_code_action_signs_delay = 200 let g:lsp_document_code_action_signs_delay = 200
let g:lsp_document_code_action_signs_delay = 1000 let g:lsp_document_code_action_signs_delay = 1000
> >
g:lsp_inlay_hints_enabled
*g:lsp_inlay_hints_enabled*
Type: |Number|
Default: `1`
Enables inlay-hints. Requires Vim9 with |virtualtext|.
patch 9.0.0167 or newer.
Example: >
let g:lsp_inlay_hints_enabled = 1
let g:lsp_inlay_hints_enabled = 0
<
To change the style of the inlay-hints, you can set or link the
`lspInlayHintsType` and `lspInlayHintsParameter` highlight group.
Example: >
highlight lspInlayHintsType ctermfg=red guifg=red
\ ctermbg=green guibg=green
highlight lspInlayHintsParameter ctermfg=red guifg=red
\ ctermbg=green guibg=green
g:lsp_inlay_hints_delay
*g:lsp_inlay_hints_delay*
Type: |Number|
Default: `350`
Delay milliseconds to update inlay-hints. Requires
|g:lsp_inlay_hints_enabled|.
Example: >
let g:lsp_inlay_hints_delay = 200
let g:lsp_inlay_hints_delay = 1000
>
g:lsp_inlay_hints_mode
*g:lsp_inlay_hints_mode*
Type: |Dict|
Default: `{}`
This mode currently only include "curline" and "!curline".
Example: >
let g:lsp_inlay_hints_mode = {
\ 'normal': ['curline'],
\}
<
"curline" show hint only for current line. "!curline" show hints except
current line. Default show all hints.
>
g:lsp_tree_incoming_prefix *g:lsp_tree_incoming_prefix* g:lsp_tree_incoming_prefix *g:lsp_tree_incoming_prefix*
Type: |String| Type: |String|
Default: `"<= "` Default: `"<= "`
@@ -1478,7 +1532,7 @@ lsp#get_progress() *lsp#get_progress()*
Type: |Number| Type: |Number|
0 - 100 or not exist 0 - 100 or not exist
lsp#document_hover_preview_winid() *lsp#document_hover_preview_winid()* lsp#document_hover_preview_winid() *lsp#document_hover_preview_winid()*
Returns |windowid| of the current hover preview window or |v:null| if it does not Returns |windowid| of the current hover preview window or |v:null| if it does not
exist. exist.

View File

@@ -32,7 +32,7 @@ let g:lsp_diagnostics_signs_information = get(g:, 'lsp_diagnostics_signs_informa
let g:lsp_diagnostics_signs_hint = get(g:, 'lsp_diagnostics_signs_hint', {}) let g:lsp_diagnostics_signs_hint = get(g:, 'lsp_diagnostics_signs_hint', {})
let g:lsp_diagnostics_signs_priority = get(g:, 'lsp_diagnostics_signs_priority', 10) let g:lsp_diagnostics_signs_priority = get(g:, 'lsp_diagnostics_signs_priority', 10)
let g:lsp_diagnostics_signs_priority_map = get(g:, 'lsp_diagnostics_signs_priority_map', {}) let g:lsp_diagnostics_signs_priority_map = get(g:, 'lsp_diagnostics_signs_priority_map', {})
let g:lsp_diagnostics_virtual_text_enabled = get(g:, 'lsp_diagnostics_virtual_text_enabled', lsp#utils#_has_virtual_text()) let g:lsp_diagnostics_virtual_text_enabled = get(g:, 'lsp_diagnostics_virtual_text_enabled', lsp#utils#_has_nvim_virtual_text())
let g:lsp_diagnostics_virtual_text_insert_mode_enabled = get(g:, 'lsp_diagnostics_virtual_text_insert_mode_enabled', 0) let g:lsp_diagnostics_virtual_text_insert_mode_enabled = get(g:, 'lsp_diagnostics_virtual_text_insert_mode_enabled', 0)
let g:lsp_diagnostics_virtual_text_delay = get(g:, 'lsp_diagnostics_virtual_text_delay', 500) let g:lsp_diagnostics_virtual_text_delay = get(g:, 'lsp_diagnostics_virtual_text_delay', 500)
let g:lsp_diagnostics_virtual_text_prefix = get(g:, 'lsp_diagnostics_virtual_text_prefix', '') 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
let g:lsp_show_message_log_level = get(g:, 'lsp_show_message_log_level', 'warning') let g:lsp_show_message_log_level = get(g:, 'lsp_show_message_log_level', 'warning')
let g:lsp_work_done_progress_enabled = get(g:, 'lsp_work_done_progress_enabled', 0) let g:lsp_work_done_progress_enabled = get(g:, 'lsp_work_done_progress_enabled', 0)
let g:lsp_untitled_buffer_enabled = get(g:, 'lsp_untitled_buffer_enabled', 1) let g:lsp_untitled_buffer_enabled = get(g:, 'lsp_untitled_buffer_enabled', 1)
let g:lsp_inlay_hints_enabled = get(g:, 'lsp_inlay_hints_enabled', 0)
let g:lsp_inlay_hints_delay = get(g:, 'lsp_inlay_hints_delay', 350)
let g:lsp_get_supported_capabilities = get(g:, 'lsp_get_supported_capabilities', [function('lsp#default_get_supported_capabilities')]) let g:lsp_get_supported_capabilities = get(g:, 'lsp_get_supported_capabilities', [function('lsp#default_get_supported_capabilities')])