From f2f05e5cffcedf153ff5c669dab79454618f8cbb Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Tue, 28 Oct 2025 08:45:02 +0100 Subject: [PATCH] refactor(picker.proc): `ctx:opts()` to pass custom options between finders --- lua/snacks/picker/core/finder.lua | 72 +++++++++++++---------------- lua/snacks/picker/source/files.lua | 20 ++++---- lua/snacks/picker/source/git.lua | 60 ++++++++++++------------ lua/snacks/picker/source/grep.lua | 10 ++-- lua/snacks/picker/source/proc.lua | 15 +----- lua/snacks/picker/source/system.lua | 20 ++++---- 6 files changed, 88 insertions(+), 109 deletions(-) diff --git a/lua/snacks/picker/core/finder.lua b/lua/snacks/picker/core/finder.lua index d5bb7911..3d3eb387 100644 --- a/lua/snacks/picker/core/finder.lua +++ b/lua/snacks/picker/core/finder.lua @@ -13,6 +13,23 @@ M.__index = M ---@field filter snacks.picker.Filter ---@field async snacks.picker.Async ---@field meta table +local Ctx = {} +Ctx.__index = Ctx + +---@generic T: snacks.picker.Config +---@param opts T +---@return T +function Ctx:opts(opts) + return Snacks.config.merge(vim.deepcopy(self.picker.opts), opts) +end + +function Ctx:cwd() + return self.filter.cwd +end + +function Ctx:git_root() + return Snacks.git.get_root(self:cwd()) or self:cwd() +end ---@alias snacks.picker.finder.async fun(cb:async fun(item:snacks.picker.finder.Item)) ---@alias snacks.picker.finder.result snacks.picker.finder.Item[] | snacks.picker.finder.async @@ -53,21 +70,18 @@ end ---@param picker snacks.Picker function M:ctx(picker) local notified = false - ---@type snacks.picker.finder.ctx - local ret = { - picker = picker, - async = setmetatable({}, { - __index = function() - if not notified then - notified = true - Snacks.notify.warn("You can only use the `async` object in async functions") - end - end, - }), - filter = self.filter, - meta = {}, - } - setmetatable(ret, { __index = M:deprecated(self.filter) }) + local ret = setmetatable({}, Ctx) + ret.picker = picker + ret.filter = self.filter + ret.meta = {} + ret.async = setmetatable({}, { + __index = function() + if not notified then + notified = true + Snacks.notify.warn("You can only use the `async` object in async functions") + end + end, + }) return ret end @@ -79,30 +93,6 @@ function M:init(filter) return ret end ----@generic T: table ----@param t T ----@return T -function M:deprecated(t) - local notified = false - return setmetatable({}, { - __index = function(_, k) - if not notified then - notified = true - Snacks.notify.warn({ - "# API changed", - "", - "- Snacks finder signature changed.", - "```lua", - "fun(opts: snacks.picker.Config, ctx: snacks.picker.finder.ctx)", - "```", - }) - Snacks.debug.backtrace() - end - return t[k] - end, - }) -end - ---@param picker snacks.Picker function M:run(picker) local default_score = require("snacks.picker.core.matcher").DEFAULT_SCORE @@ -110,7 +100,7 @@ function M:run(picker) self.items = {} local yield ---@type fun() local ctx = self:ctx(picker) - local finder = self._find(picker.opts, ctx, self:deprecated(picker)) + local finder = self._find(picker.opts, ctx) local limit = (picker.opts.live and picker.opts.limit_live or picker.opts.limit) or math.huge ---@param item snacks.picker.finder.Item @@ -169,7 +159,7 @@ function M:run(picker) picker.matcher.task:resume() yield = yield or Async.yielder(YIELD_FIND) yield() - end, self:deprecated(ctx.async)) + end) end):on("done", function() collectgarbage("restart") if not self.task:aborted() then diff --git a/lua/snacks/picker/source/files.lua b/lua/snacks/picker/source/files.lua index faec299b..46e5253f 100644 --- a/lua/snacks/picker/source/files.lua +++ b/lua/snacks/picker/source/files.lua @@ -163,9 +163,8 @@ function M.files(opts, ctx) if opts.debug.files then Snacks.notify(cmd .. " " .. table.concat(args or {}, " ")) end - return require("snacks.picker.source.proc").proc({ - opts, - { + return require("snacks.picker.source.proc").proc( + ctx:opts({ cmd = cmd, args = args, notify = not opts.live, @@ -174,16 +173,16 @@ function M.files(opts, ctx) item.cwd = cwd item.file = item.text end, - }, - }, ctx) + }), + ctx + ) end ---@param opts snacks.picker.proc.Config ---@type snacks.picker.finder function M.zoxide(opts, ctx) - return require("snacks.picker.source.proc").proc({ - opts, - { + return require("snacks.picker.source.proc").proc( + ctx:opts({ cmd = "zoxide", args = { "query", "--list" }, ---@param item snacks.picker.finder.Item @@ -191,8 +190,9 @@ function M.zoxide(opts, ctx) item.file = item.text item.dir = true end, - }, - }, ctx) + }), + ctx + ) end return M diff --git a/lua/snacks/picker/source/git.lua b/lua/snacks/picker/source/git.lua index 7ea763de..4c7e376f 100644 --- a/lua/snacks/picker/source/git.lua +++ b/lua/snacks/picker/source/git.lua @@ -44,9 +44,8 @@ function M.files(opts, ctx) ctx.picker:set_cwd(opts.cwd) end local cwd = svim.fs.normalize(opts.cwd) or nil - return require("snacks.picker.source.proc").proc({ - opts, - { + return require("snacks.picker.source.proc").proc( + ctx:opts({ cmd = "git", args = args, ---@param item snacks.picker.finder.Item @@ -54,8 +53,9 @@ function M.files(opts, ctx) item.cwd = cwd item.file = item.text end, - }, - }, ctx) + }), + ctx + ) end ---@param opts snacks.picker.git.grep.Config @@ -89,9 +89,8 @@ function M.grep(opts, ctx) ctx.picker:set_cwd(opts.cwd) end local cwd = svim.fs.normalize(opts.cwd) or nil - return require("snacks.picker.source.proc").proc({ - opts, - { + return require("snacks.picker.source.proc").proc( + ctx:opts({ cmd = "git", args = args, notify = false, @@ -110,8 +109,9 @@ function M.grep(opts, ctx) item.pos = { tonumber(line), tonumber(col) - 1 } end end, - }, - }, ctx) + }), + ctx + ) end ---@param opts snacks.picker.git.log.Config @@ -190,9 +190,8 @@ function M.log(opts, ctx) end) end - Proc.proc({ - opts, - { + Proc.proc( + ctx:opts({ cwd = cwd, cmd = "git", args = args, @@ -211,8 +210,9 @@ function M.log(opts, ctx) item.file = file item.files = renames end, - }, - }, ctx)(cb) + }), + ctx + )(cb) end end @@ -227,9 +227,8 @@ function M.status(opts, ctx) local cwd = svim.fs.normalize(opts and opts.cwd or uv.cwd() or ".") or nil cwd = Snacks.git.get_root(cwd) local prev ---@type snacks.picker.finder.Item? - return require("snacks.picker.source.proc").proc({ - opts, - { + return require("snacks.picker.source.proc").proc( + ctx:opts({ sep = "\0", cwd = cwd, cmd = "git", @@ -249,8 +248,9 @@ function M.status(opts, ctx) return false end end, - }, - }, ctx) + }), + ctx + ) end ---@param opts snacks.picker.git.diff.Config @@ -334,9 +334,8 @@ function M.branches(opts, ctx) -- stylua: ignore end } ---@type string[] - return require("snacks.picker.source.proc").proc({ - opts, - { + return require("snacks.picker.source.proc").proc( + ctx:opts({ cwd = cwd, cmd = "git", args = args, @@ -361,8 +360,9 @@ function M.branches(opts, ctx) Snacks.notify.warn("failed to parse branch: " .. item.text) return false -- skip items we could not parse end, - }, - }, ctx) + }), + ctx + ) end ---@param opts snacks.picker.git.Config @@ -372,9 +372,8 @@ function M.stash(opts, ctx) local cwd = svim.fs.normalize(opts and opts.cwd or uv.cwd() or ".") or nil cwd = Snacks.git.get_root(cwd) - return require("snacks.picker.source.proc").proc({ - opts, - { + return require("snacks.picker.source.proc").proc( + ctx:opts({ cwd = cwd, cmd = "git", args = args, @@ -396,8 +395,9 @@ function M.stash(opts, ctx) Snacks.notify.warn("failed to parse stash:\n```git\n" .. item.text .. "\n```") return false -- skip items we could not parse end, - }, - }, ctx) + }), + ctx + ) end ---@class snacks.picker.git.Status diff --git a/lua/snacks/picker/source/grep.lua b/lua/snacks/picker/source/grep.lua index c713a3cc..f8bb6950 100644 --- a/lua/snacks/picker/source/grep.lua +++ b/lua/snacks/picker/source/grep.lua @@ -112,9 +112,8 @@ function M.grep(opts, ctx) if opts.debug.grep then Snacks.notify.info("grep: " .. cmd .. " " .. table.concat(args, " ")) end - return require("snacks.picker.source.proc").proc({ - opts, - { + return require("snacks.picker.source.proc").proc( + ctx:opts({ notify = false, -- never notify on grep errors, since it's impossible to know if the error is due to the search pattern cmd = cmd, args = args, @@ -170,8 +169,9 @@ function M.grep(opts, ctx) item.file = file end, - }, - }, ctx) + }), + ctx + ) end return M diff --git a/lua/snacks/picker/source/proc.lua b/lua/snacks/picker/source/proc.lua index 262b2007..1ef4920c 100644 --- a/lua/snacks/picker/source/proc.lua +++ b/lua/snacks/picker/source/proc.lua @@ -16,21 +16,9 @@ M.USE_QUEUE = true ---@field transform? snacks.picker.transform ---@field raw? boolean Return raw output without processing ----@param opts snacks.picker.proc.Config|{[1]: snacks.picker.Config, [2]: snacks.picker.proc.Config} -local function get_opts(opts) - if svim.islist(opts) then - local transform = opts[2].transform - opts = Snacks.config.merge(unpack(vim.deepcopy(opts))) --[[@as snacks.picker.proc.Config]] - opts.transform = transform - end - ---@cast opts snacks.picker.proc.Config - return opts -end - ----@param opts snacks.picker.proc.Config|{[1]: snacks.picker.Config, [2]: snacks.picker.proc.Config} +---@param opts snacks.picker.proc.Config ---@type snacks.picker.finder function M.proc(opts, ctx) - opts = get_opts(opts) ---@cast opts snacks.picker.proc.Config assert(opts.cmd, "`opts.cmd` is required") ---@async @@ -48,6 +36,7 @@ function M.proc(opts, ctx) if ctx.picker.opts.debug.proc then vim.schedule(function() + ---@diagnostic disable-next-line: param-type-mismatch Snacks.debug.cmd(Snacks.config.merge(opts, { group = true })) end) end diff --git a/lua/snacks/picker/source/system.lua b/lua/snacks/picker/source/system.lua index 47d8b66c..36bdaa72 100644 --- a/lua/snacks/picker/source/system.lua +++ b/lua/snacks/picker/source/system.lua @@ -3,9 +3,8 @@ local M = {} ---@param opts snacks.picker.proc.Config ---@type snacks.picker.finder function M.cliphist(opts, ctx) - return require("snacks.picker.source.proc").proc({ - opts, - { + return require("snacks.picker.source.proc").proc( + ctx:opts({ cmd = "cliphist", args = { "list" }, ---@param item snacks.picker.finder.Item @@ -34,16 +33,16 @@ function M.cliphist(opts, ctx) return false end end, - }, - }, ctx) + }), + ctx + ) end ---@param opts snacks.picker.proc.Config ---@type snacks.picker.finder function M.man(opts, ctx) - return require("snacks.picker.source.proc").proc({ - opts, - { + return require("snacks.picker.source.proc").proc( + ctx:opts({ cmd = "man", args = { "-k", "." }, ---@param item snacks.picker.finder.Item @@ -59,8 +58,9 @@ function M.man(opts, ctx) return false end end, - }, - }, ctx) + }), + ctx + ) end return M