Skip to content

Commit 08f0583

Browse files
Semantic tokens performance improvements (#1342)
* improve clear_highlights performance and robustness * improve semantic tokens performance by removing regexes * cache semantic tokens legend * reduce copying of batched highlights * add defaults for 3.17 semantic token types Co-authored-by: Prabir Shrestha <[email protected]>
1 parent 23728ad commit 08f0583

File tree

1 file changed

+27
-26
lines changed

1 file changed

+27
-26
lines changed

autoload/lsp/internal/semantic.vim

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function! lsp#internal#semantic#_enable() abort
2727
\ lsp#callbag#fromEvent(l:events),
2828
\ lsp#callbag#filter({_->lsp#internal#semantic#is_enabled()}),
2929
\ lsp#callbag#debounceTime(g:lsp_semantic_delay),
30-
\ lsp#callbag#filter({_->getbufvar(bufnr('%'), '&buftype') !~# '^(help\|terminal\|prompt\|popup)$'}),
30+
\ lsp#callbag#filter({_->index(['help', 'terminal', 'prompt', 'popup'], getbufvar(bufnr('%'), '&buftype')) ==# -1}),
3131
\ lsp#callbag#filter({_->!lsp#utils#is_large_window(win_getid())}),
3232
\ lsp#callbag#switchMap({_->
3333
\ lsp#callbag#pipe(
@@ -212,8 +212,10 @@ endfunction
212212

213213
function! s:handle_semantic_tokens_response(server, buf, result) abort
214214
let l:highlights = {}
215+
let l:legend = lsp#internal#semantic#get_legend(a:server)
215216
for l:token in s:decode_tokens(a:result['data'])
216-
let l:highlights = s:add_highlight(l:highlights, a:server, a:buf, l:token)
217+
let [l:key, l:value] = s:add_highlight(a:server, l:legend, a:buf, l:token)
218+
let l:highlights[l:key] = get(l:highlights, l:key, []) + l:value
217219
endfor
218220
call s:apply_highlights(a:server, a:buf, l:highlights)
219221

@@ -241,8 +243,10 @@ function! s:handle_semantic_tokens_delta_response(server, buf, result) abort
241243
call setbufvar(a:buf, 'lsp_semantic_local_data', l:localdata)
242244

243245
let l:highlights = {}
246+
let l:legend = lsp#internal#semantic#get_legend(a:server)
244247
for l:token in s:decode_tokens(l:localdata)
245-
let l:highlights = s:add_highlight(l:highlights, a:server, a:buf, l:token)
248+
let [l:key, l:value] = s:add_highlight(a:server, l:legend, a:buf, l:token)
249+
let l:highlights[l:key] = get(l:highlights, l:key, []) + l:value
246250
endfor
247251
call s:apply_highlights(a:server, a:buf, l:highlights)
248252
endfunction
@@ -275,36 +279,32 @@ endfunction
275279

276280
function! s:clear_highlights(server, buf) abort
277281
if s:use_vim_textprops
278-
let l:IsSemanticTextprop = {textprop -> textprop['type'] =~ '^' . s:textprop_type_prefix . '.*'}
279-
let l:textprop_types = prop_list(1, {'bufnr': a:buf, 'end_lnum': -1})
282+
let l:BeginsWith = {str, prefix -> str[0:len(prefix) - 1] ==# prefix}
283+
let l:IsSemanticTextprop = {_, textprop -> l:BeginsWith(textprop, s:textprop_type_prefix)}
284+
let l:textprop_types = prop_type_list()
280285
call filter(l:textprop_types, l:IsSemanticTextprop)
281286
for l:textprop_type in l:textprop_types
282-
silent! call prop_remove({'type': l:textprop_type, 'bufnr': a:buf, 'all': v:true}, 1, line('$'))
287+
silent! call prop_remove({'type': l:textprop_type, 'bufnr': a:buf, 'all': v:true})
283288
endfor
284289
elseif s:use_nvim_highlight
285290
call nvim_buf_clear_namespace(a:buf, s:namespace_id, 0, line('$'))
286291
endif
287292
endfunction
288293

289-
function! s:add_highlight(highlights, server, buf, token) abort
290-
let l:legend = lsp#internal#semantic#get_legend(a:server)
294+
function! s:add_highlight(server, legend, buf, token) abort
291295
let l:startpos = lsp#utils#position#lsp_to_vim(a:buf, a:token['pos'])
292296
let l:endpos = a:token['pos']
293297
let l:endpos['character'] = l:endpos['character'] + a:token['length']
294298
let l:endpos = lsp#utils#position#lsp_to_vim(a:buf, l:endpos)
295299

296300
if s:use_vim_textprops
297-
let l:textprop_name = s:get_textprop_type(a:server, a:token['token_idx'], a:token['token_modifiers'])
298-
let a:highlights[l:textprop_name] = get(a:highlights, l:textprop_name, [])
299-
\ + [[l:startpos[0], l:startpos[1], l:endpos[0], l:endpos[1]]]
301+
let l:textprop_name = s:get_textprop_type(a:server, a:legend, a:token['token_idx'], a:token['token_modifiers'])
302+
return [l:textprop_name, [[l:startpos[0], l:startpos[1], l:endpos[0], l:endpos[1]]]]
300303
elseif s:use_nvim_highlight
301304
let l:char = a:token['pos']['character']
302-
let l:hl_name = s:get_hl_group(a:server, a:token['token_idx'], a:token['token_modifiers'])
303-
let a:highlights[l:hl_name] = get(a:highlights, l:hl_name, [])
304-
\ + [[l:startpos[0] - 1, l:startpos[1] - 1, l:endpos[1] - 1]]
305+
let l:hl_name = s:get_hl_group(a:server, a:legend, a:token['token_idx'], a:token['token_modifiers'])
306+
return [l:hl_name, [[l:startpos[0] - 1, l:startpos[1] - 1, l:endpos[1] - 1]]]
305307
endif
306-
307-
return a:highlights
308308
endfunction
309309

310310
function! s:apply_highlights(server, buf, highlights) abort
@@ -342,28 +342,29 @@ let s:default_highlight_groups = {
342342
\ s:hl_group_prefix . 'Variable': 'Identifier',
343343
\ s:hl_group_prefix . 'Property': 'Identifier',
344344
\ s:hl_group_prefix . 'EnumMember': 'Constant',
345-
\ s:hl_group_prefix . 'Events': 'Identifier',
345+
\ s:hl_group_prefix . 'Event': 'Identifier',
346346
\ s:hl_group_prefix . 'Function': 'Function',
347347
\ s:hl_group_prefix . 'Method': 'Function',
348+
\ s:hl_group_prefix . 'Macro': 'Macro',
348349
\ s:hl_group_prefix . 'Keyword': 'Keyword',
349350
\ s:hl_group_prefix . 'Modifier': 'Type',
350351
\ s:hl_group_prefix . 'Comment': 'Comment',
351352
\ s:hl_group_prefix . 'String': 'String',
352353
\ s:hl_group_prefix . 'Number': 'Number',
353354
\ s:hl_group_prefix . 'Regexp': 'String',
354-
\ s:hl_group_prefix . 'Operator': 'Operator'
355+
\ s:hl_group_prefix . 'Operator': 'Operator',
356+
\ s:hl_group_prefix . 'Decorator': 'Macro'
355357
\ }
356358

357-
function! s:get_hl_group(server, token_idx, token_modifiers) abort
359+
function! s:get_hl_group(server, legend, token_idx, token_modifiers) abort
358360
" get highlight group name
359-
let l:legend = lsp#internal#semantic#get_legend(a:server)
360361
let l:Capitalise = {str -> toupper(str[0]) . str[1:]}
361-
let l:token_name = l:Capitalise(l:legend['tokenTypes'][a:token_idx])
362+
let l:token_name = l:Capitalise(a:legend['tokenTypes'][a:token_idx])
362363
let l:token_modifiers = []
363-
for l:modifier_idx in range(len(l:legend['tokenModifiers']))
364+
for l:modifier_idx in range(len(a:legend['tokenModifiers']))
364365
" float2nr(pow(2, a)) is 1 << a
365366
if and(a:token_modifiers, float2nr(pow(2, l:modifier_idx)))
366-
let l:modifier_name = l:legend['tokenModifiers'][l:modifier_idx]
367+
let l:modifier_name = a:legend['tokenModifiers'][l:modifier_idx]
367368
call add(l:token_modifiers, l:Capitalise(l:modifier_name))
368369
endif
369370
endfor
@@ -378,7 +379,7 @@ function! s:get_hl_group(server, token_idx, token_modifiers) abort
378379
exec 'highlight link' l:hl_group s:default_highlight_groups[l:hl_group]
379380
else
380381
if a:token_modifiers != 0
381-
let l:base_hl_group = s:get_hl_group(a:server, a:token_idx, 0)
382+
let l:base_hl_group = s:get_hl_group(a:server, a:legend, a:token_idx, 0)
382383
exec 'highlight link' l:hl_group l:base_hl_group
383384
else
384385
exec 'highlight link' l:hl_group 'Normal'
@@ -391,13 +392,13 @@ endfunction
391392

392393
let s:textprop_type_prefix = 'vim-lsp-semantic-'
393394

394-
function! s:get_textprop_type(server, token_idx, token_modifiers) abort
395+
function! s:get_textprop_type(server, legend, token_idx, token_modifiers) abort
395396
" get textprop type name
396397
let l:textprop_type = s:textprop_type_prefix . a:server . '-' . a:token_idx . '-' . a:token_modifiers
397398

398399
" create the textprop type if it does not already exist
399400
if prop_type_get(l:textprop_type) ==# {}
400-
let l:hl_group = s:get_hl_group(a:server, a:token_idx, a:token_modifiers)
401+
let l:hl_group = s:get_hl_group(a:server, a:legend, a:token_idx, a:token_modifiers)
401402
silent! call prop_type_add(l:textprop_type, {
402403
\ 'highlight': l:hl_group,
403404
\ 'combine': v:true,

0 commit comments

Comments
 (0)