folke / trouble.nvim

🚦 A pretty diagnostics, references, telescope results, quickfix and location list to help you solve all the trouble your code is causing.
Apache License 2.0
5.11k stars 173 forks source link

bug: Running actions always refreshes sources #488

Closed AThePeanut4 closed 3 weeks ago

AThePeanut4 commented 3 weeks ago

Did you check docs and existing issues?

Neovim version (nvim -v)

NVIM v0.11.0-dev-196+g2ce4a4d91e

Operating system/version

Arch Linux

Describe the bug

Due to 39595e883e2f91456413ca4df287575d31665940 (which fixed #485), running actions always refreshes the Trouble window, even if auto_refresh = false.

The specific case that's a problem for me is the next/prev actions. I use <C-j> and <C-k> as a Trouble analog to :cnext and :cprev - they jump to the next/previous item without the cursor having to be in the Trouble window. However if I use them with e.g. an LSP source, the source refreshes every time, potentially changing the items in the window.

Steps To Reproduce

  1. Run nvim -u repro.lua
  2. Move the cursor to the first foo() call
  3. Run :Trouble lsp_references or use gd to show references
  4. Move the cursor to the bar() call
  5. Run :Trouble next jump=true or use <C-j>
  6. Observe the cursor correctly moved to the second foo() call, but the Trouble window has refreshed to now show references to the bar() call.

Expected Behavior

If auto_refresh = false, the view should not refresh when actions are run, except for when calling open (i.e. #485).

It would also be nice to have a function that does exactly the same as open(), but without actually opening the view or creating a new one, to be able to get at the view object without refreshing it. Using trouble.view.get() works, but it doesn't support mode = "last", and I'm not sure if it's considered part of the public API? Basically a non-private _find and _find_last, without the opts return value.

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  "folke/trouble.nvim",
  -- add any other plugins here
  "neovim/nvim-lspconfig",
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

require("trouble").setup {
  modes = {
    diagnostics = {
      format = "{severity_icon} {message:md} {item.source} {hl:Comment}({code}){hl} {pos}",
    },
    lsp_base = {
      -- doesn't work here, overridden by lsp_* default configs
      -- auto_jump = false,
      auto_refresh = false,
      params = {
        -- include the current location in the results
        include_current = true,
      },
      format = "{text:ts} {item.client:Comment} {pos}",
    },
    lsp_references = {
      auto_jump = false,
    },
  },
  keys = {
    -- this is just the default gb keymap, but with a nicer display similar to the severity filter
    b = {
      ---@param view trouble.View
      action = function(view)
        view:filter({ buf = 0 }, {
          id = "current_buffer",
          template = "{hl:Title}Filter:{hl} Current Buffer",
          toggle = true,
        })
      end,
      desc = "Toggle Current Buffer Filter",
    },
  },
}

vim.keymap.set("n", "gd", "<Cmd>Trouble lsp_definitions<CR>")
vim.keymap.set("n", "gr", "<Cmd>Trouble lsp_references<CR>")
vim.keymap.set("n", "gi", "<Cmd>Trouble lsp_implementations<CR>")
vim.keymap.set("n", "gD", "<Cmd>Trouble lsp_type_definitions<CR>")
vim.keymap.set("n", "<C-j>", function()
  local trouble = require("trouble")
  if trouble.is_open() then
    -- doesn't work with a count for whatever reason
    -- the type for this is wrong, wants a view and a ctx
    -- trouble.next({ jump = true })

    -- effectively the same thing, same issue
    local view = assert(trouble.open())
    view:move({ down = vim.v.count1, jump = true })
  end

  -- this works correctly
  -- local views = require("trouble.view").get()
  -- if #views ~= 0 then
  --   local view = views[#views].view
  --   view:move({ down = vim.v.count1, jump = true })
  -- end
end)
vim.keymap.set("n", "<C-k>", function()
  local trouble = require("trouble")
  if trouble.is_open() then
    -- doesn't work with a count for whatever reason
    -- the type for this is wrong, wants a view and a ctx
    -- trouble.prev({ jump = true })

    -- effectively the same thing, same issue
    local view = assert(trouble.open())
    view:move({ up = vim.v.count1, jump = true })
  end

  -- this works correctly
  -- local views = require("trouble.view").get()
  -- if #views ~= 0 then
  --   local view = views[#views].view
  --   view:move({ up = vim.v.count1, jump = true })
  -- end
end)

require("lspconfig").lua_ls.setup {}

vim.bo.filetype = "lua"
vim.api.nvim_buf_set_lines(0, 0, -1, false, {
  "function foo()",
  "  print('foo')",
  "end",
  "function bar()",
  "  print('bar')",
  "end",
  "",
  "foo()",
  "bar()",
  "foo()",
})
vim.cmd.file("test.lua")
AThePeanut4 commented 3 weeks ago

Sidenote:

I should probably make a separate discussion/bug about this, but I had issues with auto_jump not working at all because I didn't understand how Trouble merges opts for modes. For the lsp_references mode, for example, the priority seems to be custom lsp_references opts - default lsp_references opts - custom lsp_base opts - default lsp_base opts - custom global opts - default global opts.

It means that if I wanted to disable auto_jump for all modes, just setting auto_jump = false in the global setup table is not enough, because the lsp_* modes set auto_jump = true in their own default opts tables. I would have to set auto_jump = false in each lsp_* custom opts table for it to work. Is this intentional? At least for options like auto_jump, auto_refresh, focus, etc I think it would make more sense to have any custom settings have priority over all default settings. Doing that for all opts might be a bad idea though. Either way, it should probably be documented somewhere :)