mirror of
https://github.com/folke/snacks.nvim
synced 2025-08-05 19:28:24 +00:00
perf(picker.list): only re-render when visible items changed
This commit is contained in:
parent
22da4bd511
commit
c72e62ef90
1 changed files with 28 additions and 9 deletions
|
@ -16,6 +16,7 @@
|
|||
---@field matcher snacks.picker.Matcher matcher for formatting list items
|
||||
---@field matcher_regex snacks.picker.Matcher matcher for formatting list items
|
||||
---@field target? {cursor: number, top?: number}
|
||||
---@field visible snacks.picker.Item[]
|
||||
local M = {}
|
||||
M.__index = M
|
||||
|
||||
|
@ -37,6 +38,8 @@ local SCROLL_WHEEL_DOWN = Snacks.util.keycode("<ScrollWheelDown>")
|
|||
---@type table<number, snacks.picker.list>
|
||||
local lists = setmetatable({}, { __mode = "v" })
|
||||
|
||||
local stats = { render = 0, render_full = 0 }
|
||||
|
||||
-- track mouse scrolling
|
||||
vim.on_key(function(key, typed)
|
||||
key = typed or key
|
||||
|
@ -85,6 +88,8 @@ function M.new(picker)
|
|||
breakindent = true,
|
||||
},
|
||||
})
|
||||
self.visible = {}
|
||||
self.visible_count = 0
|
||||
self.win = Snacks.win(win_opts)
|
||||
self.top, self.cursor = 1, 1
|
||||
self.items = {}
|
||||
|
@ -300,20 +305,22 @@ end
|
|||
function M:add(item, sort)
|
||||
local idx = #self.items + 1
|
||||
self.items[idx] = item
|
||||
-- if the visible items are less than the height, then we need to render
|
||||
self.dirty = self.dirty or #self.visible < (self.state.height or 50)
|
||||
if sort ~= false then
|
||||
local added, prev = self.topk:add(item)
|
||||
if added then
|
||||
-- check if item is before the last visible item
|
||||
if not self.dirty and #self.visible > 0 then
|
||||
self.dirty = self.topk.cmp(item, self.visible[#self.visible])
|
||||
end
|
||||
item.match_topk = item.match_tick
|
||||
self.dirty = true
|
||||
if prev then
|
||||
-- replace with previous item, since new item is now in topk
|
||||
self.items[idx] = prev
|
||||
prev.match_topk = nil
|
||||
end
|
||||
end
|
||||
if prev then
|
||||
-- replace with previous item, since new item is now in topk
|
||||
self.items[idx] = prev
|
||||
prev.match_topk = nil
|
||||
end
|
||||
end
|
||||
if not self.dirty then
|
||||
self.dirty = idx >= self.top and idx <= self.top + (self.state.height or 50)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -544,6 +551,7 @@ function M:update_cursorline()
|
|||
end
|
||||
|
||||
function M:render()
|
||||
stats.render = stats.render + 1
|
||||
if self.target then
|
||||
self:view(self.target.cursor, self.target.top, false)
|
||||
if not self.picker:is_active() then
|
||||
|
@ -555,6 +563,7 @@ function M:render()
|
|||
|
||||
local redraw = false
|
||||
if self.dirty then
|
||||
stats.render_full = stats.render_full + 1
|
||||
local height = self:height()
|
||||
self.dirty = false
|
||||
vim.api.nvim_win_call(self.win.win, function()
|
||||
|
@ -577,9 +586,11 @@ function M:render()
|
|||
self.matcher_regex:init(search)
|
||||
end
|
||||
|
||||
self.visible = {}
|
||||
-- render items
|
||||
for i = self.top, math.min(self:count(), self.top + height - 1) do
|
||||
local item = assert(self:get(i), "item not found")
|
||||
self.visible[i - self.top + 1] = item
|
||||
local row = self:idx2row(i)
|
||||
self:_render(item, row)
|
||||
end
|
||||
|
@ -618,4 +629,12 @@ function M:render()
|
|||
end
|
||||
end
|
||||
|
||||
-- vim.uv.new_timer():start(
|
||||
-- 500,
|
||||
-- 500,
|
||||
-- vim.schedule_wrap(function()
|
||||
-- Snacks.notify(vim.inspect(stats), { ft = "lua", id = "list_stats" })
|
||||
-- end)
|
||||
-- )
|
||||
|
||||
return M
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue