mirror of
https://github.com/folke/snacks.nvim
synced 2025-08-04 02:38:46 +00:00
feat(picker): added preliminary support for combining finder results. More info coming soon
This commit is contained in:
parent
3e39250796
commit
000db17bf9
4 changed files with 65 additions and 10 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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("#")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue