3 # Functions for dealing with inlay hints
6 import './buffer.vim' as buf
7 import './options.vim' as opt
9 # Initialize the highlight group and the text property type used for
13 {name: 'LspInlayHintsType', default: true, linksto: 'Label'},
14 {name: 'LspInlayHintsParam', default: true, linksto: 'Conceal'}
16 prop_type_add('LspInlayHintsType', {highlight: 'LspInlayHintsType'})
17 prop_type_add('LspInlayHintsParam', {highlight: 'LspInlayHintsParam'})
19 autocmd_add([{group: 'LspOptionsChanged',
22 cmd: 'LspInlayHintsOptionsChanged()'}])
25 # Clear all the inlay hints text properties in the current buffer
26 def InlayHintsClear(bnr: number)
27 prop_remove({type: 'LspInlayHintsType', bufnr: bnr, all: true})
28 prop_remove({type: 'LspInlayHintsParam', bufnr: bnr, all: true})
31 # LSP inlay hints reply message handler
32 export def InlayHintsReply(lspserver: dict<any>, bnr: number, inlayHints: any)
33 if inlayHints->empty()
40 # Update inlay hints only in normal mode
44 for hint in inlayHints
46 if hint.label->type() == v:t_list
47 label = hint.label->copy()->map((_, v) => v.value)->join(', ')
52 var kind = hint->has_key('kind') ? hint.kind->string() : '1'
54 lspserver.decodePosition(bnr, hint.position)
55 var byteIdx = util.GetLineByteFromPos(bnr, hint.position)
56 if kind == "'type'" || kind == '1'
57 prop_add(hint.position.line + 1, byteIdx + 1,
58 {type: 'LspInlayHintsType', text: label, bufnr: bnr})
59 elseif kind == "'parameter'" || kind == '2'
60 prop_add(hint.position.line + 1, byteIdx + 1,
61 {type: 'LspInlayHintsParam', text: label, bufnr: bnr})
63 catch /E966\|E964/ # Invalid lnum | Invalid col
64 # Inlay hints replies arrive asynchronously and the document might have
65 # been modified in the mean time. As the reply is stale, ignore invalid
66 # line number and column number errors.
71 # Timer callback to display the inlay hints.
72 def InlayHintsTimerCb(lspserver: dict<any>, bnr: number, timerid: number)
73 lspserver.inlayHintsShow(bnr)
74 setbufvar(bnr, 'LspInlayHintsNeedsUpdate', false)
77 # Update all the inlay hints. A timer is used to throttle the updates.
78 def LspInlayHintsUpdate(bnr: number)
79 if !bnr->getbufvar('LspInlayHintsNeedsUpdate', true)
83 var timerid = bnr->getbufvar('LspInlayHintsTimer', -1)
86 setbufvar(bnr, 'LspInlayHintsTimer', -1)
89 var lspserver: dict<any> = buf.BufLspServerGet(bnr, 'inlayHint')
95 # When running tests, update the inlay hints immediately
96 InlayHintsTimerCb(lspserver, bnr, -1)
98 timerid = timer_start(300, function('InlayHintsTimerCb', [lspserver, bnr]))
99 setbufvar(bnr, 'LspInlayHintsTimer', timerid)
103 # Text is modified. Need to update the inlay hints.
104 def LspInlayHintsChanged(bnr: number)
105 setbufvar(bnr, 'LspInlayHintsNeedsUpdate', true)
108 # Trigger an update of the inlay hints in the current buffer.
109 export def LspInlayHintsUpdateNow(bnr: number)
110 setbufvar(bnr, 'LspInlayHintsNeedsUpdate', true)
111 LspInlayHintsUpdate(bnr)
114 # Stop updating the inlay hints.
115 def LspInlayHintsUpdateStop(bnr: number)
116 var timerid = bnr->getbufvar('LspInlayHintsTimer', -1)
118 timerid->timer_stop()
119 setbufvar(bnr, 'LspInlayHintsTimer', -1)
123 # Do buffer-local initialization for displaying inlay hints
124 export def BufferInit(lspserver: dict<any>, bnr: number)
125 if !lspserver.isInlayHintProvider && !lspserver.isClangdInlayHintsProvider
126 # no support for inlay hints
130 # Inlays hints are disabled
131 if !opt.lspOptions.showInlayHints
132 || !lspserver.featureEnabled('inlayHint')
136 var acmds: list<dict<any>> = []
138 # Update the inlay hints (if needed) when the cursor is not moved for some
140 acmds->add({bufnr: bnr,
141 event: ['CursorHold'],
142 group: 'LspInlayHints',
143 cmd: $'LspInlayHintsUpdate({bnr})'})
144 # After the text in the current buffer is modified, the inlay hints need to
146 acmds->add({bufnr: bnr,
147 event: ['TextChanged'],
148 group: 'LspInlayHints',
149 cmd: $'LspInlayHintsChanged({bnr})'})
150 # Editing a file should trigger an inlay hint update.
151 acmds->add({bufnr: bnr,
152 event: ['BufReadPost'],
153 group: 'LspInlayHints',
154 cmd: $'LspInlayHintsUpdateNow({bnr})'})
155 # Inlay hints need not be updated if a buffer is no longer active.
156 acmds->add({bufnr: bnr,
158 group: 'LspInlayHints',
159 cmd: $'LspInlayHintsUpdateStop({bnr})'})
164 # Track the current inlay hints enabled/disabled state. Used when the
165 # "showInlayHints" option value is changed.
166 var save_showInlayHints = opt.lspOptions.showInlayHints
168 # Enable inlay hints. For all the buffers with an attached language server
169 # that supports inlay hints, refresh the inlay hints.
170 export def InlayHintsEnable()
171 opt.lspOptions.showInlayHints = true
172 for binfo in getbufinfo()
173 var lspservers: list<dict<any>> = buf.BufLspServersGet(binfo.bufnr)
174 if lspservers->empty()
177 for lspserver in lspservers
178 if !lspserver.featureEnabled('inlayHint')
179 || (!lspserver.isInlayHintProvider &&
180 !lspserver.isClangdInlayHintsProvider)
183 BufferInit(lspserver, binfo.bufnr)
184 LspInlayHintsUpdateNow(binfo.bufnr)
187 save_showInlayHints = true
190 # Disable inlay hints for the current Vim session. Clear the inlay hints in
192 export def InlayHintsDisable()
193 opt.lspOptions.showInlayHints = false
194 for binfo in getbufinfo()
195 var lspserver: dict<any> = buf.BufLspServerGet(binfo.bufnr, 'inlayHint')
196 if lspserver->empty()
199 LspInlayHintsUpdateStop(binfo.bufnr)
200 :silent! autocmd_delete([{bufnr: binfo.bufnr, group: 'LspInlayHints'}])
201 InlayHintsClear(binfo.bufnr)
203 save_showInlayHints = false
206 # Some options are changed. If 'showInlayHints' option is changed, then
207 # either enable or disable inlay hints.
208 export def LspInlayHintsOptionsChanged()
209 if save_showInlayHints && !opt.lspOptions.showInlayHints
211 elseif !save_showInlayHints && opt.lspOptions.showInlayHints
216 # vim: tabstop=8 shiftwidth=2 softtabstop=2