Skip to content

Instantly share code, notes, and snippets.

@alextes
Last active September 20, 2023 13:09
Show Gist options
  • Save alextes/e6704e5376709d194d21f615f8542ccb to your computer and use it in GitHub Desktop.
Save alextes/e6704e5376709d194d21f615f8542ccb to your computer and use it in GitHub Desktop.
FixCurrent script for code actions in neovim in Lua
return function()
local params = vim.lsp.util.make_range_params() -- get params for current position
params.context = {
diagnostics = vim.lsp.diagnostic.get_line_diagnostics(),
only = { "quickfix" },
}
local actions_per_client, err = vim.lsp.buf_request_sync(
0,
"textDocument/codeAction",
params,
900
)
if err then
return
end
if actions_per_client == nil or vim.tbl_isempty(actions_per_client) or #actions_per_client == 0 then
vim.notify("no quickfixes available")
return
end
-- Collect the available actions
local actions = {}
for cid, resp in pairs(actions_per_client) do
if resp.result ~= nil then
for _, result in pairs(resp.result) do
-- add the actions with a cid to the table
local action = {}
action["cid"] = cid
for k, v in pairs(result) do
action[k] = v
end
table.insert(actions, action)
end
end
end
-- Try to find a preferred action.
local preferred_action = nil
for _, action in ipairs(actions) do
if action.isPreferred then
preferred_action = action
break
end
end
-- If we failed to find a preferred action, try to find a non-null-ls action.
local non_null_ls_action = nil
for _, action in ipairs(actions) do
if action.command ~= "NULL_LS_CODE_ACTION" then
non_null_ls_action = action
break
end
end
-- If we failed to find a non-null-ls action, use the first one.
local first_action = nil
if #actions > 0 then
first_action = actions[1]
end
-- Using null-ls a lot of quickfixes are returned but all tend to be
-- worse than what the real LSP is offering, we try to use other
-- actions first, then only fall back to whatever null-ls is offering.
local top_action = preferred_action or non_null_ls_action or first_action
-- print(vim.inspect(top_action))
local picked_one = false
vim.lsp.buf.code_action({
context = {
only = { "quickfix" },
},
filter = function(action, ctx)
if picked_one then
return true
elseif top_action ~= nil and action.title == top_action.title then
picked_one = true
return false
else
return true
end
end,
apply = true,
})
end
local on_attach = function(client, bufnr)
local nmap = function(keys, func, desc)
if desc then
desc = "LSP: " .. desc
end
vim.keymap.set("n", keys, func, { buffer = bufnr, desc = desc })
end
nmap("gq", require("fixcurrent"), "[G]o [Q]uickfix")
end
local servers = {
gopls = {},
-- pyright = {},
rust_analyzer = {},
tsserver = {},
lua_ls = {
Lua = {
workspace = { checkThirdParty = false },
telemetry = { enable = false },
},
},
}
local capabilities = vim.lsp.protocol.make_client_capabilities()
-- Setup mason so it can manage external tooling
require("mason").setup()
-- Ensure the servers above are installed
local mason_lspconfig = require("mason-lspconfig")
mason_lspconfig.setup({
ensure_installed = vim.tbl_keys(servers),
})
mason_lspconfig.setup_handlers({
function(server_name)
require("lspconfig")[server_name].setup({
capabilities = capabilities,
on_attach = on_attach,
settings = servers[server_name],
})
end,
})
@duongdominhchau
Copy link

Yes, it does. I removed the part about null-ls as I use jdtls with neovim-lsp directly, so it's just local top_action = actions[1]. The error I got is

E5108: Error executing lua: /usr/share/nvim/runtime/lua/vim/lsp/buf.lua:796: command: expected string, got nil

and a stack trace pointing to https://gist.github.com/alextes/e6704e5376709d194d21f615f8542ccb#file-init-lua-L10. Seems like a validate() call inside vim.lsp.buf.execute_command expects the argument passed in to be a table containing command key, but the action object here does not have that key.

{
  cid = 1,
  data = {
    pid = "0",
    rid = "0"
  },
  diagnostics = { {
      code = "570425394",
      data = { "Micronaut" },
      message = "Micronaut cannot be resolved",
      range = {
        ["end"] = {
          character = 17,
          line = 4
        },
        start = {
          character = 8,
          line = 4
        }
      },
      severity = 1,
      source = "Java"
    } },
  kind = "quickfix",
  title = "Import 'Micronaut' (io.micronaut.runtime)"
}

I don't know much about LSP or Neovim API, so I can't fix it for now. Just commented to show appreciation, as all the language servers I used advertised isPreferred support, but none have that key in the action :|

@alextes
Copy link
Author

alextes commented Sep 19, 2023

@duongdominhchau my bad! I didn't notice what you're looking at is very old!! I'll update the gist right now.

Thanks for the appreciation 💛

@duongdominhchau
Copy link

duongdominhchau commented Sep 20, 2023

Thank you for the update. I tried this new config but cannot autofix with Ruff, to make it works, I flipped the boolean value returned from filter and remove the only = "quickfix". It sounds reasonable to me, not sure why it needs to be removed 🤷

Writing it here in case someone else gets into the same issue as me.

Edit: Wonderful, the new solution works with both jdtls and ruff_lsp. Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment