diff options
Diffstat (limited to 'lua/blink/cmp/completion/brackets/semantic.lua')
| -rw-r--r-- | lua/blink/cmp/completion/brackets/semantic.lua | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/lua/blink/cmp/completion/brackets/semantic.lua b/lua/blink/cmp/completion/brackets/semantic.lua new file mode 100644 index 0000000..c64afbd --- /dev/null +++ b/lua/blink/cmp/completion/brackets/semantic.lua @@ -0,0 +1,109 @@ +local config = require('blink.cmp.config').completion.accept.auto_brackets +local utils = require('blink.cmp.completion.brackets.utils') + +local semantic = {} + +--- Asynchronously use semantic tokens to determine if brackets should be added +--- @param filetype string +--- @param item blink.cmp.CompletionItem +--- @param callback fun() +function semantic.add_brackets_via_semantic_token(filetype, item, callback) + if not utils.should_run_resolution(filetype, 'semantic_token') then return callback() end + + local text_edit = item.textEdit + assert(text_edit ~= nil, 'Got nil text edit while adding brackets via semantic tokens') + local client = vim.lsp.get_client_by_id(item.client_id) + if client == nil then return callback() end + + local capabilities = client.server_capabilities.semanticTokensProvider + if not capabilities or not capabilities.legend or (not capabilities.range and not capabilities.full) then + return callback() + end + + local token_types = client.server_capabilities.semanticTokensProvider.legend.tokenTypes + local params = { + textDocument = vim.lsp.util.make_text_document_params(), + range = capabilities.range and { + start = { line = text_edit.range.start.line, character = text_edit.range.start.character }, + ['end'] = { line = text_edit.range.start.line + 1, character = 0 }, + } or nil, + } + + local cursor_before_call = vim.api.nvim_win_get_cursor(0) + + local start_time = vim.uv.hrtime() + client.request( + capabilities.range and 'textDocument/semanticTokens/range' or 'textDocument/semanticTokens/full', + params, + function(err, result) + if err ~= nil or result == nil or #result.data == 0 then return callback() end + + -- cancel if it's been too long, or if the cursor moved + local ms_since_call = (vim.uv.hrtime() - start_time) / 1000000 + local cursor_after_call = vim.api.nvim_win_get_cursor(0) + if + ms_since_call > config.semantic_token_resolution.timeout_ms + or cursor_before_call[1] ~= cursor_after_call[1] + or cursor_before_call[2] ~= cursor_after_call[2] + then + return callback() + end + + for _, token in ipairs(semantic.process_semantic_token_data(result.data, token_types)) do + if + cursor_after_call[1] == token.line + and cursor_after_call[2] >= token.start_col + and cursor_after_call[2] <= token.end_col + and (token.type == 'function' or token.type == 'method') + then + -- add the brackets + local brackets_for_filetype = utils.get_for_filetype(filetype, item) + local line = vim.api.nvim_get_current_line() + local start_col = text_edit.range.start.character + #text_edit.newText + local new_line = line:sub(1, start_col) + .. brackets_for_filetype[1] + .. brackets_for_filetype[2] + .. line:sub(start_col + 1) + vim.api.nvim_set_current_line(new_line) + vim.api.nvim_win_set_cursor(0, { cursor_after_call[1], start_col + #brackets_for_filetype[1] }) + callback() + return + end + end + + callback() + end + ) +end + +function semantic.process_semantic_token_data(data, token_types) + local tokens = {} + local idx = 0 + local token_line = 0 + local token_start_col = 0 + + while (idx + 1) * 5 <= #data do + local delta_token_line = data[idx * 5 + 1] + local delta_token_start_col = data[idx * 5 + 2] + local delta_token_length = data[idx * 5 + 3] + local type = token_types[data[idx * 5 + 4] + 1] + + if delta_token_line > 0 then token_start_col = 0 end + token_line = token_line + delta_token_line + token_start_col = token_start_col + delta_token_start_col + + table.insert(tokens, { + line = token_line + 1, + start_col = token_start_col, + end_col = token_start_col + delta_token_length, + type = type, + }) + + token_start_col = token_start_col + delta_token_length + idx = idx + 1 + end + + return tokens +end + +return semantic.add_brackets_via_semantic_token |
