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 !getbufvar(bnr, 'LspInlayHintsNeedsUpdate', true)
83 var timerid = getbufvar(bnr, '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 = getbufvar(bnr, '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
135 var acmds: list<dict<any>> = []
137 # Update the inlay hints (if needed) when the cursor is not moved for some
139 acmds->add({bufnr: bnr,
140 event: ['CursorHold'],
141 group: 'LspInlayHints',
142 cmd: $'LspInlayHintsUpdate({bnr})'})
143 # After the text in the current buffer is modified, the inlay hints need to
145 acmds->add({bufnr: bnr,
146 event: ['TextChanged'],
147 group: 'LspInlayHints',
148 cmd: $'LspInlayHintsChanged({bnr})'})
149 # Editing a file should trigger an inlay hint update.
150 acmds->add({bufnr: bnr,
151 event: ['BufReadPost'],
152 group: 'LspInlayHints',
153 cmd: $'LspInlayHintsUpdateNow({bnr})'})
154 # Inlay hints need not be updated if a buffer is no longer active.
155 acmds->add({bufnr: bnr,
157 group: 'LspInlayHints',
158 cmd: $'LspInlayHintsUpdateStop({bnr})'})
163 # Track the current inlay hints enabled/disabled state. Used when the
164 # "showInlayHints" option value is changed.
165 var save_showInlayHints = opt.lspOptions.showInlayHints
167 # Enable inlay hints. For all the buffers with an attached language server
168 # that supports inlay hints, refresh the inlay hints.
169 export def InlayHintsEnable()
170 opt.lspOptions.showInlayHints = true
171 for binfo in getbufinfo()
172 var lspservers: list<dict<any>> = buf.BufLspServersGet(binfo.bufnr)
173 if lspservers->empty()
176 for lspserver in lspservers
177 if !lspserver.isInlayHintProvider &&
178 !lspserver.isClangdInlayHintsProvider
181 BufferInit(lspserver, binfo.bufnr)
182 LspInlayHintsUpdateNow(binfo.bufnr)
185 save_showInlayHints = true
188 # Disable inlay hints for the current Vim session. Clear the inlay hints in
190 export def InlayHintsDisable()
191 opt.lspOptions.showInlayHints = false
192 for binfo in getbufinfo()
193 var lspserver: dict<any> = buf.BufLspServerGet(binfo.bufnr, 'inlayHint')
194 if lspserver->empty()
197 LspInlayHintsUpdateStop(binfo.bufnr)
198 :silent! autocmd_delete([{bufnr: binfo.bufnr, group: 'LspInlayHints'}])
199 InlayHintsClear(binfo.bufnr)
201 save_showInlayHints = false
204 # Some options are changed. If 'showInlayHints' option is changed, then
205 # either enable or disable inlay hints.
206 export def LspInlayHintsOptionsChanged()
207 if save_showInlayHints && !opt.lspOptions.showInlayHints
209 elseif !save_showInlayHints && opt.lspOptions.showInlayHints
214 # vim: tabstop=8 shiftwidth=2 softtabstop=2