9

I was looking for a solution similar to CoC's coc-fix-current but using native lsp for Neovim 0.5 but I did not find such thing in the documentation, is there any way to achieve this through other method?

Oscar Lastra
  • 93
  • 1
  • 5

4 Answers4

5

As of neovim 0.8, thanks to this PR, there's an apply boolean which does just that.

To make sure you only apply relevant fixes, you can use the filter attribute and look for the "prefered" fixes.

Here's what I've put in my config :

local opts = { noremap=true, silent=true }

local function quickfix()
    vim.lsp.buf.code_action({
        filter = function(a) return a.isPreferred end,
        apply = true
    })
end

vim.keymap.set('n', '<leader>qf', quickfix, opts)
ShellCode
  • 1,072
  • 8
  • 17
3

I had this problem and by hacking up the code that the telescope.nvim plugin uses to list and run code actions, came up with this monstrosity:

local function run_action(action, offse)
    if action.edit or type(action.command) == "table" then
        if action.edit then
            vim.lsp.util.apply_workspace_edit(action.edit, offse)
        end
        if type(action.command) == "table" then
            vim.lsp.buf.execute_command(action.command)
        end
    else
        vim.lsp.buf.execute_command(action)
    end
end

local function do_action(action, client)
    if
      not action.edit
      and client
      and type(client.resolved_capabilities.code_action) == "table"
      and client.resolved_capabilities.code_action.resolveProvider
    then
        client.request("codeAction/resolve", action, function(err, real)
            if err then
                return
            end
            if real then
                run_action(real, client.offset_encoding)
            else
                run_action(action, client.offset_encoding)
            end
        end)
    else
        run_action(action, client.offset_encoding) 
    end
end

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 results, err = vim.lsp.buf_request_sync(
        0, -- current buffer
        "textDocument/codeAction", -- get code actions
        params,
        900
    )

    if err then return end

    if not results or vim.tbl_isempty(results) then
        print "No quickfixes!"
        return
    end

    -- we have an action!
    for cid, resp in pairs(results) do
        if resp.result then
            for _, result in pairs(resp.result) do 
                -- this is the first action, run it
                do_action(result, vim.lsp.get_client_by_id(cid))
                return
            end
        end 
    end

    print "No quickfixes!"
end

Since it's lua, you'll need to place it in a .lua file somewhere that nvim searches for modules (for example, as ~/.config/nvim/lua/lsp_fixcurrent.lua) and then bind to :lua require("lsp_fixcurrent")()

mincrmatt12
  • 382
  • 3
  • 12
1

Maybe you are looking for: vim.lsp.buf.code_action()?

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
KnairWang
  • 19
  • 1
  • 1
    As far as I understand this is providing a valid answer to the question. Using this function I was able to fix fixable lsp errors. – Sassan Aug 08 '21 at 17:04
  • 2
    While this opens a window to select a code action, it's not actually what I was searching for, i'm searching for a feature like coc's "coc-fix-current" which automatically selects the correct code action upon function invoke, I appreciate the answer anyways. – Oscar Lastra Aug 09 '21 at 03:48
  • In my case I'm using ccls for c++ as lsp server, and I have cases where coc's `coc-fix-current` fixes the issue and the native lsp `vim.lsp.buf.code_action({"quickfix"})` claims there is no code-action, not sure what is going on here (maybe bug, or just something I don't understand). Also haven't tried to accepted answer yet. – Emile Vrijdags Jan 27 '22 at 13:16
  • As for Rust, it seems like `coc-fix-current` will change code to what `cargo clippy` says, but `vim.lsp.buf.code_action()` won't. :( – MrZ Sep 03 '22 at 14:11
1

mincrmatt12 answer, updated for newer neovim (0.8?) which complains client.resolved_capabilities should not be used.

local function run_action(action, offse)
    if action.edit or type(action.command) == "table" then
        if action.edit then
            vim.lsp.util.apply_workspace_edit(action.edit, offse)
        end
        if type(action.command) == "table" then
            vim.lsp.buf.execute_command(action.command)
        end
    else
        vim.lsp.buf.execute_command(action)
    end
end

local function do_action(action, client)
    if
        not action.edit
        and client
        and type(client.server_capabilities) == "table"
        and client.server_capabilities.resolveProvider
    then
        client.request("codeAction/resolve", action, function(err, real)
            if err then
                return
            end
            if real then
                run_action(real, client.offset_encoding)
            else
                run_action(action, client.offset_encoding)
            end
        end)
    else
        run_action(action, client.offset_encoding)
    end
end

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 results, err = vim.lsp.buf_request_sync(
        0, -- current buffer
        "textDocument/codeAction", -- get code actions
        params,
        900
    )

    if err then
        return
    end

    if not results or vim.tbl_isempty(results) then
        print("No quickfixes!")
        return
    end

    -- we have an action!
    for cid, resp in pairs(results) do
        if resp.result then
            for _, result in pairs(resp.result) do
                -- this is the first action, run it
                do_action(result, vim.lsp.get_client_by_id(cid))
                return
            end
        end
    end

    print("No quickfixes!")
end
alextes
  • 1,817
  • 2
  • 15
  • 22