diff --git a/lua/snacks/picker/config/init.lua b/lua/snacks/picker/config/init.lua index 289654d2..9bd55a91 100644 --- a/lua/snacks/picker/config/init.lua +++ b/lua/snacks/picker/config/init.lua @@ -300,6 +300,19 @@ function M.finder(finder) return M.field(finder) or nop end +---@param picker snacks.Picker +---@param action string +function M.action(picker, action) + local ret = (picker.opts.actions or {})[action] or require("snacks.picker.actions")[action] + if ret then + return ret + end + local source = action:match("^(.-)_") + if source then -- source specific action + return (M.field(("%s_actions"):format(source)) or {})[action] + end +end + --- Resolves a module field ---@param spec string function M.field(spec) diff --git a/lua/snacks/picker/config/sources.lua b/lua/snacks/picker/config/sources.lua index 331b5704..fd63b9ed 100644 --- a/lua/snacks/picker/config/sources.lua +++ b/lua/snacks/picker/config/sources.lua @@ -807,6 +807,21 @@ M.registers = { -- Special picker that resumes the last picker M.resume = {} +-- Open or create scratch buffers +M.scratch = { + finder = "scratch", + format = "scratch_format", + confirm = "scratch_open", + win = { + input = { + keys = { + [""] = { "scratch_delete", mode = { "n", "i" } }, + [""] = { "scratch_new", mode = { "n", "i" } }, + }, + }, + }, +} + -- Neovim search history ---@type snacks.picker.history.Config M.search_history = { diff --git a/lua/snacks/picker/core/actions.lua b/lua/snacks/picker/core/actions.lua index 95af42da..feb651ef 100644 --- a/lua/snacks/picker/core/actions.lua +++ b/lua/snacks/picker/core/actions.lua @@ -81,16 +81,8 @@ function M.resolve(action, picker, name, stack) end end stack[#stack + 1] = action - return M.resolve( - (picker.opts.actions or {})[action] - or require("snacks.picker.actions")[action] - or require("snacks.explorer.actions").actions[action], - picker, - action, - stack - ) + return M.resolve(Snacks.picker.config.action(picker, action), picker, action, stack) elseif type(action) == "table" and svim.islist(action) then - ---@type snacks.picker.Action[] local actions = vim.tbl_map(function(a) return M.resolve(a, picker, nil, stack) end, action) diff --git a/lua/snacks/picker/source/explorer.lua b/lua/snacks/picker/source/explorer.lua index 5b241b5b..1839904b 100644 --- a/lua/snacks/picker/source/explorer.lua +++ b/lua/snacks/picker/source/explorer.lua @@ -4,6 +4,8 @@ local Tree = require("snacks.explorer.tree") local M = {} +M.actions = Actions.actions + ---@type table M._state = setmetatable({}, { __mode = "k" }) local uv = vim.uv or vim.loop diff --git a/lua/snacks/picker/source/scratch.lua b/lua/snacks/picker/source/scratch.lua new file mode 100644 index 00000000..e1333fb7 --- /dev/null +++ b/lua/snacks/picker/source/scratch.lua @@ -0,0 +1,62 @@ +local M = {} + +---@class snacks.scratch.actions +---@field [string] snacks.picker.Action.spec +M.actions = { + scratch_open = function(picker, item) + picker:close() + if not item then + return + end + Snacks.scratch.open({ icon = item.item.icon, file = item.item.file, name = item.item.name, ft = item.item.ft }) + end, + scratch_delete = function(picker, item) + local current = item.file + os.remove(current) + picker.list:set_selected() + picker.list:set_target() + picker:find() + end, + scratch_new = function(picker) + picker:close() + Snacks.scratch.open() + end, +} + +---@param opts snacks.picker.proc.Config +---@type snacks.picker.finder +function M.scratch(opts) + local list = Snacks.scratch.list() + local items = {} ---@type snacks.picker.finder.Item[] + for _, item in ipairs(list) do + items[#items + 1] = { + file = item.file, + item = item, + title = item.name, + text = Snacks.picker.util.text(item, { "name", "branch", "ft" }), + branch = item.branch and ("branch:%s"):format(item.branch) or "", + } + end + return items +end + +---@type snacks.picker.format +function M.format(item, picker) + local file = item.item + local ret = {} ---@type snacks.picker.Highlight[] + local a = Snacks.picker.util.align + local icon, icon_hl = file.icon, nil + if not icon then + icon, icon_hl = Snacks.util.icon(file.ft, "filetype") + end + ret[#ret + 1] = { a(icon, 3), icon_hl } + ret[#ret + 1] = { a(file.name, 20, { truncate = true }) } + ret[#ret + 1] = { " " } + ret[#ret + 1] = { a(item.branch, 20, { truncate = true }), "Number" } + ret[#ret + 1] = { " " } + ---@diagnostic disable-next-line: missing-fields + vim.list_extend(ret, Snacks.picker.format.filename({ text = "", dir = true, file = file.cwd }, picker)) + return ret +end + +return M diff --git a/lua/snacks/scratch.lua b/lua/snacks/scratch.lua index 0ca22aad..7495318f 100644 --- a/lua/snacks/scratch.lua +++ b/lua/snacks/scratch.lua @@ -119,32 +119,7 @@ end --- Select a scratch buffer from a list of scratch buffers. function M.select() - local widths = { 0, 0, 0, 0 } - local items = M.list() - for _, item in ipairs(items) do - item.icon = item.icon or Snacks.util.icon(item.ft, "filetype") - item.branch = item.branch and ("branch:%s"):format(item.branch) or "" - item.cwd = item.cwd and vim.fn.fnamemodify(item.cwd, ":p:~") or "" - widths[1] = math.max(widths[1], vim.api.nvim_strwidth(item.cwd)) - widths[2] = math.max(widths[2], vim.api.nvim_strwidth(item.icon)) - widths[3] = math.max(widths[3], vim.api.nvim_strwidth(item.name)) - widths[4] = math.max(widths[4], vim.api.nvim_strwidth(item.branch)) - end - vim.ui.select(items, { - prompt = "Select Scratch Buffer", - ---@param item snacks.scratch.File - format_item = function(item) - local parts = { item.cwd, item.icon, item.name, item.branch } - for i, part in ipairs(parts) do - parts[i] = part .. string.rep(" ", widths[i] - vim.api.nvim_strwidth(part)) - end - return table.concat(parts, " ") - end, - }, function(selected) - if selected then - M.open({ icon = selected.icon, file = selected.file, name = selected.name, ft = selected.ft }) - end - end) + return Snacks.picker.scratch() end --- Open a scratch buffer with the given options.