feat(picker.actions): added support for action options. Fixes #598

This commit is contained in:
Folke Lemaitre 2025-01-18 10:32:06 +01:00
parent 0652591487
commit 8035398e52
No known key found for this signature in database
GPG key ID: 41F8B1FBACAE2040
2 changed files with 49 additions and 38 deletions

View file

@ -5,18 +5,27 @@ local M = {}
local SCROLL_WHEEL_DOWN = Snacks.util.keycode("<ScrollWheelDown>")
local SCROLL_WHEEL_UP = Snacks.util.keycode("<ScrollWheelUp>")
function M.jump(picker)
---@class snacks.picker.jump.Action: snacks.picker.Action
---@field cmd? string
function M.jump(picker, _, action)
---@cast action snacks.picker.jump.Action
-- if we're still in insert mode, stop it and schedule
-- it to prevent issues with cursor position
if vim.fn.mode():sub(1, 1) == "i" then
vim.cmd.stopinsert()
vim.schedule(function()
M.jump(picker)
M.jump(picker, _, action)
end)
return
end
picker:close()
if action.cmd then
vim.cmd(action.cmd)
end
local win = vim.api.nvim_get_current_win()
local current_buf = vim.api.nvim_get_current_buf()
@ -92,10 +101,12 @@ function M.jump(picker)
end
end
M.cancel = function() end
M.cancel = "close"
M.edit = M.jump
M.confirm = M.jump
M.edit_split = { action = "jump", cmd = "split" }
M.edit_vsplit = { action = "jump", cmd = "vsplit" }
M.edit_tab = { action = "jump", cmd = "tabnew" }
function M.toggle_maximize(picker)
picker.layout:maximize()
@ -189,24 +200,6 @@ function M.history_forward(picker)
picker:hist(true)
end
function M.edit_tab(picker)
picker:close()
vim.cmd("tabnew")
return picker:action("edit")
end
function M.edit_split(picker)
picker:close()
vim.cmd("split")
return picker:action("edit")
end
function M.edit_vsplit(picker)
picker:close()
vim.cmd("vsplit")
return picker:action("edit")
end
--- Toggles the selection of the current item,
--- and moves the cursor to the next item.
function M.select_and_next(picker)

View file

@ -1,12 +1,13 @@
local M = {}
---@alias snacks.picker.Action.fn fun(self: snacks.Picker, item?:snacks.picker.Item):(boolean|string?)
---@alias snacks.picker.Action.spec.one string|snacks.picker.Action|snacks.picker.Action.fn
---@alias snacks.picker.Action.fn fun(self: snacks.Picker, item?:snacks.picker.Item, action?:snacks.picker.Action):(boolean|string?)
---@alias snacks.picker.Action.spec.one string|snacks.picker.Action|snacks.picker.Action.fn|{action?:snacks.picker.Action.spec.one}
---@alias snacks.picker.Action.spec snacks.picker.Action.spec.one|snacks.picker.Action.spec.one[]
---@class snacks.picker.Action
---@field action snacks.picker.Action.fn
---@field desc? string
---@field name? string
---@param picker snacks.Picker
function M.get(picker)
@ -24,7 +25,7 @@ function M.get(picker)
if not p then
return
end
t[k] = M.resolve(k, p, k) or false
t[k] = M.wrap(k, p, k) or false
return rawget(t, k)
end,
})
@ -34,17 +35,33 @@ end
---@param action snacks.picker.Action.spec
---@param picker snacks.Picker
---@param name? string
---@return snacks.picker.Action?
---@return snacks.win.Action?
function M.wrap(action, picker, name)
action = M.resolve(action, picker, name)
action.name = name
return {
name = name,
action = function()
action.action(picker, picker:current(), action)
end,
desc = action.desc,
}
end
---@param action snacks.picker.Action.spec
---@param picker snacks.Picker
---@param name? string
---@return snacks.picker.Action
function M.resolve(action, picker, name)
if not action then
assert(name, "Missing action without name")
local fn, desc = picker.input.win[name], name
return {
action = function()
action = function(p)
if not fn then
return name
end
fn(picker.input.win)
fn(p.input.win)
end,
desc = desc,
}
@ -60,9 +77,9 @@ function M.resolve(action, picker, name)
return M.resolve(a, picker)
end, action)
return {
action = function(_, item)
action = function(p, i, aa)
for _, a in ipairs(actions) do
a.action(picker, item)
a.action(p, i, aa)
end
end,
desc = table.concat(
@ -72,17 +89,18 @@ function M.resolve(action, picker, name)
", "
),
}
elseif type(action) == "table" then
if type(action.action) ~= "function" then
action = vim.deepcopy(action)
action.action = M.resolve(action.action, picker).action
end
---@cast action snacks.picker.Action
return action
end
action = type(action) == "function" and {
assert(type(action) == "function", "Invalid action")
return {
action = action,
desc = name or nil,
} or action
---@cast action snacks.picker.Action
return {
action = function()
return action.action(picker, picker:current())
end,
desc = action.desc,
}
end