diff options
Diffstat (limited to 'runtime/lua/vim/lsp/semantic_tokens.lua')
-rw-r--r-- | runtime/lua/vim/lsp/semantic_tokens.lua | 110 |
1 files changed, 65 insertions, 45 deletions
diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index 8182457dd0..215e5f41aa 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -99,11 +99,12 @@ local function tokens_to_ranges(data, bufnr, client, request) local legend = client.server_capabilities.semanticTokensProvider.legend local token_types = legend.tokenTypes local token_modifiers = legend.tokenModifiers + local encoding = client.offset_encoding local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false) local ranges = {} ---@type STTokenRange[] local start = uv.hrtime() - local ms_to_ns = 1000 * 1000 + local ms_to_ns = 1e6 local yield_interval_ns = 5 * ms_to_ns local co, is_main = coroutine.running() @@ -135,20 +136,13 @@ local function tokens_to_ranges(data, bufnr, client, request) -- data[i+3] +1 because Lua tables are 1-indexed local token_type = token_types[data[i + 3] + 1] - local modifiers = modifiers_from_number(data[i + 4], token_modifiers) - - local function _get_byte_pos(col) - if col > 0 then - local buf_line = lines[line + 1] or '' - return util._str_byteindex_enc(buf_line, col, client.offset_encoding) - end - return col - end - - local start_col = _get_byte_pos(start_char) - local end_col = _get_byte_pos(start_char + data[i + 2]) if token_type then + local modifiers = modifiers_from_number(data[i + 4], token_modifiers) + local end_char = start_char + data[i + 2] + local buf_line = lines and lines[line + 1] or '' + local start_col = vim.str_byteindex(buf_line, encoding, start_char, false) + local end_col = vim.str_byteindex(buf_line, encoding, end_char, false) ranges[#ranges + 1] = { line = line, start_col = start_col, @@ -386,6 +380,37 @@ function STHighlighter:process_response(response, client, version) api.nvim__redraw({ buf = self.bufnr, valid = true }) end +--- @param bufnr integer +--- @param ns integer +--- @param token STTokenRange +--- @param hl_group string +--- @param priority integer +local function set_mark(bufnr, ns, token, hl_group, priority) + vim.api.nvim_buf_set_extmark(bufnr, ns, token.line, token.start_col, { + hl_group = hl_group, + end_col = token.end_col, + priority = priority, + strict = false, + }) +end + +--- @param lnum integer +--- @param foldend integer? +--- @return boolean, integer? +local function check_fold(lnum, foldend) + if foldend and lnum <= foldend then + return true, foldend + end + + local folded = vim.fn.foldclosed(lnum) + + if folded == -1 then + return false, nil + end + + return folded ~= lnum, vim.fn.foldclosedend(lnum) +end + --- on_win handler for the decoration provider (see |nvim_set_decoration_provider|) --- --- If there is a current result for the buffer and the version matches the @@ -439,13 +464,14 @@ function STHighlighter:on_win(topline, botline) -- finishes, clangd sends a refresh request which lets the client -- re-synchronize the tokens. - local set_mark = function(token, hl_group, delta) - vim.api.nvim_buf_set_extmark(self.bufnr, state.namespace, token.line, token.start_col, { - hl_group = hl_group, - end_col = token.end_col, - priority = vim.highlight.priorities.semantic_tokens + delta, - strict = false, - }) + local function set_mark0(token, hl_group, delta) + set_mark( + self.bufnr, + state.namespace, + token, + hl_group, + vim.hl.priorities.semantic_tokens + delta + ) end local ft = vim.bo[self.bufnr].filetype @@ -453,13 +479,19 @@ function STHighlighter:on_win(topline, botline) local first = lower_bound(highlights, topline, 1, #highlights + 1) local last = upper_bound(highlights, botline, first, #highlights + 1) - 1 + --- @type boolean?, integer? + local is_folded, foldend + for i = first, last do local token = highlights[i] - if not token.marked then - set_mark(token, string.format('@lsp.type.%s.%s', token.type, ft), 0) - for modifier, _ in pairs(token.modifiers) do - set_mark(token, string.format('@lsp.mod.%s.%s', modifier, ft), 1) - set_mark(token, string.format('@lsp.typemod.%s.%s.%s', token.type, modifier, ft), 2) + + is_folded, foldend = check_fold(token.line + 1, foldend) + + if not is_folded and not token.marked then + set_mark0(token, string.format('@lsp.type.%s.%s', token.type, ft), 0) + for modifier in pairs(token.modifiers) do + set_mark0(token, string.format('@lsp.mod.%s.%s', modifier, ft), 1) + set_mark0(token, string.format('@lsp.typemod.%s.%s.%s', token.type, modifier, ft), 2) end token.marked = true @@ -565,10 +597,8 @@ local M = {} --- - debounce (integer, default: 200): Debounce token requests --- to the server by the given number in milliseconds function M.start(bufnr, client_id, opts) - vim.validate({ - bufnr = { bufnr, 'n', false }, - client_id = { client_id, 'n', false }, - }) + vim.validate('bufnr', bufnr, 'number') + vim.validate('client_id', client_id, 'number') if bufnr == 0 then bufnr = api.nvim_get_current_buf() @@ -622,10 +652,8 @@ end ---@param bufnr (integer) Buffer number, or `0` for current buffer ---@param client_id (integer) The ID of the |vim.lsp.Client| function M.stop(bufnr, client_id) - vim.validate({ - bufnr = { bufnr, 'n', false }, - client_id = { client_id, 'n', false }, - }) + vim.validate('bufnr', bufnr, 'number') + vim.validate('client_id', client_id, 'number') if bufnr == 0 then bufnr = api.nvim_get_current_buf() @@ -708,9 +736,7 @@ end ---@param bufnr (integer|nil) filter by buffer. All buffers if nil, current --- buffer if 0 function M.force_refresh(bufnr) - vim.validate({ - bufnr = { bufnr, 'n', true }, - }) + vim.validate('bufnr', bufnr, 'number', true) local buffers = bufnr == nil and vim.tbl_keys(STHighlighter.active) or bufnr == 0 and { api.nvim_get_current_buf() } @@ -729,7 +755,7 @@ end --- @inlinedoc --- --- Priority for the applied extmark. ---- (Default: `vim.highlight.priorities.semantic_tokens + 3`) +--- (Default: `vim.hl.priorities.semantic_tokens + 3`) --- @field priority? integer --- Highlight a semantic token. @@ -757,15 +783,9 @@ function M.highlight_token(token, bufnr, client_id, hl_group, opts) return end - opts = opts or {} - local priority = opts.priority or vim.highlight.priorities.semantic_tokens + 3 + local priority = opts and opts.priority or vim.hl.priorities.semantic_tokens + 3 - vim.api.nvim_buf_set_extmark(bufnr, state.namespace, token.line, token.start_col, { - hl_group = hl_group, - end_col = token.end_col, - priority = priority, - strict = false, - }) + set_mark(bufnr, state.namespace, token, hl_group, priority) end --- |lsp-handler| for the method `workspace/semanticTokens/refresh` |