mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 20:55:18 -07:00
[Backport release-0.9] perf(lsp): process semantic tokens response in a coroutine that yields every 5ms (#23414)
perf(lsp): process semantic tokens response in a coroutine that yields every 5ms
(cherry picked from commit 46cd1d957c
)
Co-authored-by: John Drouhard <john@drouhard.dev>
This commit is contained in:
parent
fc2822a819
commit
98a90abca9
@ -1,7 +1,8 @@
|
|||||||
local api = vim.api
|
local api = vim.api
|
||||||
|
local bit = require('bit')
|
||||||
local handlers = require('vim.lsp.handlers')
|
local handlers = require('vim.lsp.handlers')
|
||||||
local util = require('vim.lsp.util')
|
local util = require('vim.lsp.util')
|
||||||
local bit = require('bit')
|
local uv = vim.loop
|
||||||
|
|
||||||
--- @class STTokenRange
|
--- @class STTokenRange
|
||||||
--- @field line integer line number 0-based
|
--- @field line integer line number 0-based
|
||||||
@ -94,15 +95,38 @@ end
|
|||||||
---
|
---
|
||||||
---@private
|
---@private
|
||||||
---@return STTokenRange[]
|
---@return STTokenRange[]
|
||||||
local function tokens_to_ranges(data, bufnr, client)
|
local function tokens_to_ranges(data, bufnr, client, request)
|
||||||
local legend = client.server_capabilities.semanticTokensProvider.legend
|
local legend = client.server_capabilities.semanticTokensProvider.legend
|
||||||
local token_types = legend.tokenTypes
|
local token_types = legend.tokenTypes
|
||||||
local token_modifiers = legend.tokenModifiers
|
local token_modifiers = legend.tokenModifiers
|
||||||
local ranges = {}
|
local ranges = {}
|
||||||
|
|
||||||
|
local start = uv.hrtime()
|
||||||
|
local ms_to_ns = 1000 * 1000
|
||||||
|
local yield_interval_ns = 5 * ms_to_ns
|
||||||
|
local co, is_main = coroutine.running()
|
||||||
|
|
||||||
local line
|
local line
|
||||||
local start_char = 0
|
local start_char = 0
|
||||||
for i = 1, #data, 5 do
|
for i = 1, #data, 5 do
|
||||||
|
-- if this function is called from the main coroutine, let it run to completion with no yield
|
||||||
|
if not is_main then
|
||||||
|
local elapsed_ns = uv.hrtime() - start
|
||||||
|
|
||||||
|
if elapsed_ns > yield_interval_ns then
|
||||||
|
vim.schedule(function()
|
||||||
|
coroutine.resume(co, util.buf_versions[bufnr])
|
||||||
|
end)
|
||||||
|
if request.version ~= coroutine.yield() then
|
||||||
|
-- request became stale since the last time the coroutine ran.
|
||||||
|
-- abandon it by yielding without a way to resume
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
|
||||||
|
start = uv.hrtime()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local delta_line = data[i]
|
local delta_line = data[i]
|
||||||
line = line and line + delta_line or delta_line
|
line = line and line + delta_line or delta_line
|
||||||
local delta_start = data[i + 1]
|
local delta_start = data[i + 1]
|
||||||
@ -280,7 +304,7 @@ function STHighlighter:send_request()
|
|||||||
local c = vim.lsp.get_client_by_id(ctx.client_id)
|
local c = vim.lsp.get_client_by_id(ctx.client_id)
|
||||||
local highlighter = STHighlighter.active[ctx.bufnr]
|
local highlighter = STHighlighter.active[ctx.bufnr]
|
||||||
if not err and c and highlighter then
|
if not err and c and highlighter then
|
||||||
highlighter:process_response(response, c, version)
|
coroutine.wrap(STHighlighter.process_response)(highlighter, response, c, version)
|
||||||
end
|
end
|
||||||
end, self.bufnr)
|
end, self.bufnr)
|
||||||
|
|
||||||
@ -315,11 +339,9 @@ function STHighlighter:process_response(response, client, version)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- reset active request
|
|
||||||
state.active_request = {}
|
|
||||||
|
|
||||||
-- skip nil responses
|
-- skip nil responses
|
||||||
if response == nil then
|
if response == nil then
|
||||||
|
state.active_request = {}
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -347,12 +369,19 @@ function STHighlighter:process_response(response, client, version)
|
|||||||
tokens = response.data
|
tokens = response.data
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Update the state with the new results
|
-- convert token list to highlight ranges
|
||||||
|
-- this could yield and run over multiple event loop iterations
|
||||||
|
local highlights = tokens_to_ranges(tokens, self.bufnr, client, state.active_request)
|
||||||
|
|
||||||
|
-- reset active request
|
||||||
|
state.active_request = {}
|
||||||
|
|
||||||
|
-- update the state with the new results
|
||||||
local current_result = state.current_result
|
local current_result = state.current_result
|
||||||
current_result.version = version
|
current_result.version = version
|
||||||
current_result.result_id = response.resultId
|
current_result.result_id = response.resultId
|
||||||
current_result.tokens = tokens
|
current_result.tokens = tokens
|
||||||
current_result.highlights = tokens_to_ranges(tokens, self.bufnr, client)
|
current_result.highlights = highlights
|
||||||
current_result.namespace_cleared = false
|
current_result.namespace_cleared = false
|
||||||
|
|
||||||
-- redraw all windows displaying buffer
|
-- redraw all windows displaying buffer
|
||||||
|
Loading…
Reference in New Issue
Block a user