feat(picker): added preliminary support for combining finder results. More info coming soon

This commit is contained in:
Folke Lemaitre 2025-01-15 10:58:31 +01:00
parent 3e39250796
commit 000db17bf9
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
4 changed files with 65 additions and 10 deletions

View file

@ -67,8 +67,8 @@ local M = {}
---@field ui_select? boolean set `vim.ui.select` to a snacks picker
--- Source definition
---@field items? snacks.picker.finder.Item[] items to show instead of using a finder
---@field format? snacks.picker.format|string format function or preset
---@field finder? snacks.picker.finder|string finder function or preset
---@field format? string|snacks.picker.format|string format function or preset
---@field finder? string|snacks.picker.finder|snacks.picker.finder.multi finder function or preset
---@field preview? snacks.picker.preview|string preview function or preset
---@field matcher? snacks.picker.matcher.Config matcher config
---@field sort? snacks.picker.sort|snacks.picker.sort.Config sort function or config

View file

@ -76,17 +76,32 @@ function M.resolve(v, ...)
end
--- Get the finder
---@param finder string|snacks.picker.finder
---@param finder string|snacks.picker.finder|snacks.picker.finder.multi
---@return snacks.picker.finder
function M.finder(finder)
local nop = function()
Snacks.notify.error("Finder not found:\n```lua\n" .. vim.inspect(finder) .. "\n```", { title = "Snacks Picker" })
end
if not finder or type(finder) == "function" then
return finder
end
if type(finder) == "table" then
---@cast finder snacks.picker.finder.multi
---@type snacks.picker.finder[]
local finders = vim.tbl_map(function(f)
return M.finder(f)
end, finder)
return require("snacks.picker.core.finder").multi(finders)
end
---@cast finder string
local mod, fn = finder:match("^(.-)_(.+)$")
if not (mod and fn) then
mod, fn = finder, finder
end
return require("snacks.picker.source." .. mod)[fn]
local ok, ret = pcall(function()
return require("snacks.picker.source." .. mod)[fn]
end)
return ok and ret or nop
end
local did_setup = false

View file

@ -9,6 +9,7 @@ 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.multi (snacks.picker.finder|string)[]
local YIELD_FIND = 1 -- ms
@ -41,7 +42,7 @@ end
---@param picker snacks.Picker
function M:run(picker)
local score = require("snacks.picker.core.matcher").DEFAULT_SCORE
local default_score = require("snacks.picker.core.matcher").DEFAULT_SCORE
self.task:abort()
self.items = {}
local yield ---@type fun()
@ -49,12 +50,17 @@ function M:run(picker)
local finder = self._find(picker.opts, self.filter)
local limit = picker.opts.limit or math.huge
---@param item snacks.picker.finder.Item
local function add(item)
item.idx, item.score = #self.items + 1, default_score
self.items[item.idx] = item
end
-- PERF: if finder is a table, we can skip the async part
if type(finder) == "table" then
local items = finder --[[@as snacks.picker.finder.Item[] ]]
for i, item in ipairs(items) do
item.idx, item.score = i, score
self.items[i] = item
for _, item in ipairs(items) do
add(item)
end
return
end
@ -72,8 +78,7 @@ function M:run(picker)
end
return
end
item.idx, item.score = #self.items + 1, score
self.items[item.idx] = item
add(item)
picker.matcher.task:resume()
yield = yield or Async.yielder(YIELD_FIND)
yield()
@ -85,4 +90,32 @@ function M:run(picker)
end)
end
---@param finders snacks.picker.finder[]
---@return snacks.picker.finder
function M.multi(finders)
return function(opts, filter)
---@type fun(cb:async fun(item:snacks.picker.finder.Item))[]
local running = {}
local items = {} ---@type snacks.picker.finder.Item[]
for _, finder in ipairs(finders) do
local find = finder(opts, filter)
if type(find) == "table" then
vim.list_extend(items, find)
else
running[#running + 1] = find
end
end
return #running == 0 and items
or function(cb)
for _, item in ipairs(items) do
cb(item)
end
items = {} -- release memory
for _, find in ipairs(running) do
find(cb)
end
end
end
end
return M

View file

@ -6,6 +6,13 @@ local M = {}
---@param opts snacks.picker.buffers.Config
---@type snacks.picker.finder
function M.buffers(opts, filter)
opts = vim.tbl_extend("force", {
hidden = false,
unloaded = true,
current = true,
nofile = false,
sort_lastused = true,
}, opts)
local items = {} ---@type snacks.picker.finder.Item[]
local current_buf = vim.api.nvim_get_current_buf()
local alternate_buf = vim.fn.bufnr("#")