diff options
| author | Barrett Ruth <62671086+barrettruth@users.noreply.github.com> | 2026-04-23 06:46:59 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-23 06:46:59 -0400 |
| commit | ecb8402197f1883feec1c7a9f9d02a39912ae04a (patch) | |
| tree | e041e062a43fa92efc1a91fc790b3554351213d7 /runtime/lua | |
| parent | 19ef632decf7e5d3d9bb70f347c88b92c138b45e (diff) | |
fix(lsp): filter code_action diagnostics to the cursor #38988
Problem:
Cursor-position `vim.lsp.buf.code_action()` requests include all diagnostics on the current line, so unrelated same-line diagnostics affect the returned actions.
Solution:
Filter same-line diagnostics to the cursor position for cursor-position requests.
Diffstat (limited to 'runtime/lua')
| -rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 43 |
1 files changed, 34 insertions, 9 deletions
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index ad98356ecf..926d82c986 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -1309,6 +1309,24 @@ local function on_code_action_results(results, opts) vim.ui.select(actions, select_opts, on_user_choice) end +---@param diagnostic vim.Diagnostic +---@param bufnr integer +---@param lnum integer +---@param col integer +---@return boolean +local function diagnostic_contains_cursor(diagnostic, bufnr, lnum, col) + local start = vim.pos(bufnr, diagnostic.lnum, diagnostic.col) + local finish = + vim.pos(bufnr, diagnostic.end_lnum or diagnostic.lnum, diagnostic.end_col or diagnostic.col) + local cursor = vim.pos(bufnr, lnum, col) + + if start == finish then + return cursor == start + end + + return start <= cursor and cursor < finish +end + --- Selects a code action (LSP: "textDocument/codeAction" request) available at cursor position. --- ---@param opts? vim.lsp.buf.code_action.Opts @@ -1330,6 +1348,13 @@ function M.code_action(opts) local mode = api.nvim_get_mode().mode local bufnr = api.nvim_get_current_buf() local win = api.nvim_get_current_win() + local range = opts.range + if range == nil and (mode == 'v' or mode == 'V') then + range = range_from_selection(bufnr, mode) + end + local cursor = api.nvim_win_get_cursor(win) + local lnum = cursor[1] - 1 + local col = cursor[2] local clients = lsp.get_clients({ bufnr = bufnr, method = 'textDocument/codeAction' }) if not next(clients) then vim.notify(lsp._unsupported_method('textDocument/codeAction'), vim.log.levels.WARN) @@ -1340,15 +1365,11 @@ function M.code_action(opts) ---@type lsp.CodeActionParams local params - if opts.range then - assert(type(opts.range) == 'table', 'code_action range must be a table') - local start = assert(opts.range.start, 'range must have a `start` property') - local end_ = assert(opts.range['end'], 'range must have a `end` property') + if range then + assert(type(range) == 'table', 'code_action range must be a table') + local start = assert(range.start, 'range must have a `start` property') + local end_ = assert(range['end'], 'range must have a `end` property') params = util.make_given_range_params(start, end_, bufnr, client.offset_encoding) - elseif mode == 'v' or mode == 'V' then - local range = range_from_selection(bufnr, mode) - params = - util.make_given_range_params(range.start, range['end'], bufnr, client.offset_encoding) else params = util.make_range_params(win, client.offset_encoding) end @@ -1360,7 +1381,6 @@ function M.code_action(opts) else local ns_push = lsp.diagnostic.get_namespace(client.id) local diagnostics = {} - local lnum = api.nvim_win_get_cursor(0)[1] - 1 client:_provider_foreach('textDocument/diagnostic', function(cap) local ns_pull = lsp.diagnostic.get_namespace(client.id, true, cap.identifier) @@ -1371,6 +1391,11 @@ function M.code_action(opts) end) vim.list_extend(diagnostics, vim.diagnostic.get(bufnr, { namespace = ns_push, lnum = lnum })) + if range == nil then + diagnostics = vim.tbl_filter(function(diagnostic) + return diagnostic_contains_cursor(diagnostic, bufnr, lnum, col) + end, diagnostics) + end params.context = vim.tbl_extend('force', context, { ---@diagnostic disable-next-line: no-unknown diagnostics = vim.tbl_map(function(d) |
