|
| 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 |
0 commit comments