snacks.nvim/lua/snacks/bufdelete.lua

85 lines
2.2 KiB
Lua

---@class snacks.bufdelete
---@hide
---@overload fun(buf?: number)
local M = setmetatable({}, {
__call = function(t, ...)
return t.delete(...)
end,
})
--- Delete a buffer:
--- - either the current buffer if `buf` is not provided
--- - or the buffer `buf` if it is a number
--- - or every buffer for which `buf` returns true if it is a function
---@param buf? number | fun(buf: number): boolean
function M.delete(buf)
if type(buf) == "function" then
for _, b in ipairs(vim.api.nvim_list_bufs()) do
if vim.bo[b].buflisted and buf(b) then
M.delete(b)
end
end
return
end
buf = buf or 0
buf = buf == 0 and vim.api.nvim_get_current_buf() or buf
-- Ensure we always run in the target buffer
if buf ~= vim.api.nvim_get_current_buf() then
return vim.api.nvim_buf_call(buf, M.delete)
end
if vim.bo.modified then
local choice = vim.fn.confirm(("Save changes to %q?"):format(vim.fn.bufname()), "&Yes\n&No\n&Cancel")
if choice == 0 or choice == 3 then -- 0 for <Esc>/<C-c> and 3 for Cancel
return
end
if choice == 1 then -- Yes
vim.cmd.write()
end
end
for _, win in ipairs(vim.fn.win_findbuf(buf)) do
vim.api.nvim_win_call(win, function()
if not vim.api.nvim_win_is_valid(win) or vim.api.nvim_win_get_buf(win) ~= buf then
return
end
-- Try using alternate buffer
local alt = vim.fn.bufnr("#")
if alt ~= buf and vim.fn.buflisted(alt) == 1 then
vim.api.nvim_win_set_buf(win, alt)
return
end
-- Try using previous buffer
local has_previous = pcall(vim.cmd, "bprevious")
if has_previous and buf ~= vim.api.nvim_win_get_buf(win) then
return
end
-- Create new listed buffer
local new_buf = vim.api.nvim_create_buf(true, false)
vim.api.nvim_win_set_buf(win, new_buf)
end)
end
if vim.api.nvim_buf_is_valid(buf) then
pcall(vim.cmd, "bdelete! " .. buf)
end
end
--- Delete all buffers
function M.all()
return M.delete(function()
return true
end)
end
--- Delete all buffers except the current one
function M.other()
return M.delete(function(b)
return b ~= vim.api.nvim_get_current_buf()
end)
end
return M