feat(picker): added support for item.resolve that gets called if needed during list rendering / preview

This commit is contained in:
Folke Lemaitre 2025-01-19 21:53:18 +01:00
parent eb0e5b7efe
commit b0d3266985
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
4 changed files with 37 additions and 3 deletions

View file

@ -9,7 +9,7 @@ local Async = require("snacks.picker.util.async")
local M = {}
M.__index = M
---@alias snacks.picker.finder fun(opts:snacks.picker.Config, filter:snacks.picker.Filter): (snacks.picker.finder.Item[] | fun(cb:async fun(item:snacks.picker.finder.Item)))
---@alias snacks.picker.finder fun(opts:snacks.picker.Config, filter:snacks.picker.Filter): (snacks.picker.finder.Item[] | fun(cb:async fun(item:snacks.picker.finder.Item), task:snacks.picker.Async))
---@alias snacks.picker.finder.multi (snacks.picker.finder|string)[]
local YIELD_FIND = 1 -- ms
@ -69,9 +69,10 @@ function M:run(picker)
end
collectgarbage("stop") -- moar speed
---@cast finder fun(cb:async fun(item:snacks.picker.finder.Item))
---@cast finder fun(cb:async fun(item:snacks.picker.finder.Item), task:snacks.picker.Async)
---@diagnostic disable-next-line: await-in-sync
self.task = Async.new(function()
local async = Async.running()
---@async
finder(function(item)
if #self.items >= limit then
@ -85,7 +86,7 @@ function M:run(picker)
picker.matcher.task:resume()
yield = yield or Async.yielder(YIELD_FIND)
yield()
end)
end, async)
end):on("done", function()
collectgarbage("restart")
picker.matcher.task:resume()

View file

@ -47,6 +47,7 @@ function M.new(picker)
bo = { modifiable = false, filetype = "snacks_picker_list" },
wo = {
foldenable = false,
foldmethod = "manual",
cursorline = false,
winhighlight = Snacks.picker.highlight.winhl("SnacksPickerList", { CursorLine = "Visual" }),
},
@ -329,6 +330,7 @@ end
---@param item snacks.picker.Item
function M:format(item)
Snacks.picker.util.resolve(item)
-- Add selected and debug info
local prefix = {} ---@type snacks.picker.Highlight[]
if #self.selected > 0 or self.picker.opts.formatters.selected.show_always then

View file

@ -97,6 +97,7 @@ function M:show(picker)
if self.item == item then
return
end
Snacks.picker.util.resolve(item)
self.item = item
if item then
local buf = self.win.buf

View file

@ -181,4 +181,34 @@ function M.parse(str)
return t, args
end
---@param item snacks.picker.Item
function M.resolve(item)
if item.resolve then
item.resolve(item)
item.resolve = nil
end
return item
end
--- Returns the relative time from a given time
--- as ... ago
---@param time number in seconds
function M.reltime(time)
local delta = os.time() - time
local tpl = {
{ 1, 60, "just now", "just now" },
{ 60, 3600, "a minute ago", "%d minutes ago" },
{ 3600, 3600 * 24, "an hour ago", "%d hours ago" },
{ 3600 * 24, 3600 * 24 * 7, "yesterday", "%d days ago" },
{ 3600 * 24 * 7, 3600 * 24 * 7 * 4, "a week ago", "%d weeks ago" },
}
for _, v in ipairs(tpl) do
if delta < v[2] then
local value = math.floor(delta / v[1] + 0.5)
return value == 1 and v[3] or v[4]:format(value)
end
end
return os.date("%b %d, %Y", time) ---@type string
end
return M