feat(win): added actions to easily combine actions in keymaps

This commit is contained in:
Folke Lemaitre 2024-12-10 07:33:49 +01:00
parent 72eba84180
commit 46362a5a9c

View file

@ -15,7 +15,7 @@ local M = setmetatable({}, {
---@class snacks.win.Keys: vim.api.keyset.keymap
---@field [1]? string
---@field [2]? string|fun(self: snacks.win): any
---@field [2]? string|string[]|fun(self: snacks.win): string?
---@field mode? string|string[]
---@class snacks.win.Backdrop
@ -27,8 +27,8 @@ local M = setmetatable({}, {
---@class snacks.win.Config: vim.api.keyset.win_config
---@field style? string merges with config from `Snacks.config.styles[style]`
---@field show? boolean Show the window immediately (default: true)
---@field height? number|fun():number Height of the window. Use <1 for relative height. 0 means full height. (default: 0.9)
---@field width? number|fun():number Width of the window. Use <1 for relative width. 0 means full width. (default: 0.9)
---@field height? number|fun(self:snacks.win):number Height of the window. Use <1 for relative height. 0 means full height. (default: 0.9)
---@field width? number|fun(self:snacks.win):number Width of the window. Use <1 for relative width. 0 means full width. (default: 0.9)
---@field minimal? boolean Disable a bunch of options to make the window minimal (default: true)
---@field position? "float"|"bottom"|"top"|"left"|"right"
---@field buf? number If set, use this buffer instead of creating a new one
@ -43,6 +43,7 @@ local M = setmetatable({}, {
---@field on_win? fun(self: snacks.win) Callback after opening the window
---@field fixbuf? boolean don't allow other buffers to be opened in this window
---@field text? string|string[]|fun():(string[]|string) Initial lines to set in the buffer
---@field actions? table<string, fun(self: snacks.win):(boolean|string?)> Actions that can be used in key mappings
local defaults = {
show = true,
fixbuf = true,
@ -192,7 +193,7 @@ function M.new(opts)
for key, spec in pairs(opts.keys) do
if spec then
if type(spec) == "string" then
spec = { key, self[spec] and self[spec] or spec, desc = spec }
spec = { key, spec, desc = spec }
elseif type(spec) == "function" then
spec = { key, spec }
end
@ -208,6 +209,28 @@ function M.new(opts)
return self
end
---@param actions string|string[]
---@return fun(): boolean|string?
function M:action(actions)
actions = type(actions) == "string" and { actions } or actions
---@cast actions string[]
return function()
for _, action in ipairs(actions) do
if self.opts.actions and self.opts.actions[action] then
local ret = self.opts.actions[action](self)
if ret then
return type(ret) == "string" and ret or nil
end
elseif self[action] then
self[action](self)
return
else
return action
end
end
end
end
function M:focus()
if self:valid() then
vim.api.nvim_set_current_win(self.win)
@ -485,10 +508,12 @@ function M:show()
opts.buffer = self.buf
opts.nowait = true
local rhs = spec[2]
if type(rhs) == "function" then
rhs = function()
return spec[2](self)
end
local is_action = type(rhs) == "string" or type(rhs) == "table"
if is_action then
opts.expr = true
end
rhs = is_action and self:action(rhs) or function()
return spec[2](self)
end
---@cast spec snacks.win.Keys
vim.keymap.set(spec.mode or "n", spec[1], rhs, opts)
@ -600,8 +625,8 @@ function M:win_opts()
opts[k] = self.opts[k]
end
local parent = self:parent_size()
opts.height = type(opts.height) == "function" and opts.height() or opts.height
opts.width = type(opts.width) == "function" and opts.width() or opts.width
opts.height = type(opts.height) == "function" and opts.height(self) or opts.height
opts.width = type(opts.width) == "function" and opts.width(self) or opts.width
-- Special case for 0, which means 100%
opts.height = opts.height == 0 and parent.height or opts.height
opts.width = opts.width == 0 and parent.width or opts.width