diff --git a/lua/trouble/item.lua b/lua/trouble/item.lua index 740a2f4b..c062e281 100644 --- a/lua/trouble/item.lua +++ b/lua/trouble/item.lua @@ -36,6 +36,27 @@ function M.new(opts) return setmetatable(self, M) end +---@param items trouble.Item[] +---@param fields? string[] +function M.add_id(items, fields) + for _, item in ipairs(items) do + if not item.id then + local id = { + item.source, + item.filename, + item.pos[1] or "", + item.pos[2] or "", + item.end_pos[1] or "", + item.end_pos[2] or "", + } + for _, field in ipairs(fields or {}) do + table.insert(id, item[field] or "") + end + item.id = table.concat(id, ":") + end + end +end + ---@return string? function M:get_ft() if self.buf and vim.api.nvim_buf_is_loaded(self.buf) then diff --git a/lua/trouble/sources/diagnostics.lua b/lua/trouble/sources/diagnostics.lua index b23c5b82..308f4dfc 100644 --- a/lua/trouble/sources/diagnostics.lua +++ b/lua/trouble/sources/diagnostics.lua @@ -79,6 +79,7 @@ function M.setup() if buf and vim.api.nvim_buf_is_valid(buf) then cache[buf] = cache[buf] or {} table.insert(cache[buf], M.item(diag)) + Item.add_id(cache[buf], { "item.source", "severity", "code" }) end end end diff --git a/lua/trouble/sources/qf.lua b/lua/trouble/sources/qf.lua index b8a3aa58..1d0dc6d4 100644 --- a/lua/trouble/sources/qf.lua +++ b/lua/trouble/sources/qf.lua @@ -92,6 +92,7 @@ function M.get_list(opts) ret[#ret].item.text = ret[#ret].item.text .. "\n" .. item.text end end + Item.add_id(ret, { "severity" }) Item.add_text(ret, { mode = "full" }) return ret end diff --git a/lua/trouble/tree.lua b/lua/trouble/tree.lua index 0178c5da..ece06492 100644 --- a/lua/trouble/tree.lua +++ b/lua/trouble/tree.lua @@ -83,7 +83,10 @@ end function M:add(node) if node.id then - assert(self.index[node.id] == nil, "node already exists") + if self.index[node.id] then + Util.debug("node already exists:\n" .. node.id) + node.id = node.id .. "_" + end self.index[node.id] = node end node.parent = self @@ -95,6 +98,40 @@ function M:is_leaf() return self.children == nil or #self.children == 0 end +---@param other? trouble.Node +function M:is(other) + if not other then + return false + end + + if self == other then + return true + end + + if self.id ~= other.id then + return false + end + + if self.group ~= other.group then + return false + end + + if self.group then + return true + end + assert(self.item, "missing item") + + if not other.item then + return false + end + + if self.item == other.item then + return true + end + + return self.item.id and (self.item.id == other.item.id) +end + --- Build a tree from a list of items and a section. ---@param items trouble.Item[] ---@param section trouble.Section.opts diff --git a/lua/trouble/view/init.lua b/lua/trouble/view/init.lua index 08e03a84..61915026 100644 --- a/lua/trouble/view/init.lua +++ b/lua/trouble/view/init.lua @@ -464,6 +464,7 @@ function M:render() return end + -- fast exit when cursor is already on the right item local new_loc = self:at() if new_loc.node and loc.node and new_loc.node.id == loc.node.id then return @@ -472,17 +473,16 @@ function M:render() -- Move cursor to the same item local cursor = vim.api.nvim_win_get_cursor(self.win.win) local item_row ---@type number? - for row, l in pairs(self.renderer._locations) do - if loc.node and loc.item then - if l.node and l.item and loc.node.id == l.node.id and l.item == loc.item then + if loc.node then + for row, l in pairs(self.renderer._locations) do + if loc.node:is(l.node) then item_row = row break end - elseif loc.node and l.node and loc.node.id == l.node.id then - item_row = row - break end end + + -- Move cursor to the actual item when found if item_row and item_row ~= cursor[1] then vim.api.nvim_win_set_cursor(self.win.win, { item_row, cursor[2] }) return