From 3238cfb952eebc532d6a9b12089460b3992b5327 Mon Sep 17 00:00:00 2001 From: Avimitin Date: Tue, 21 Feb 2023 15:24:36 +0800 Subject: [PATCH] keymap: add buffer delete key mappings Signed-off-by: Avimitin Former-commit-id: 7ad80c8df1b868783b3c4d6fd34ef25b91d87e40 Former-commit-id: 10e13a55e0d91241e19e56372d92c97552bb615e Former-commit-id: 30d58a38375e7f0866521f66da0be689fb0a939c --- lua/core/keymap.lua | 2 +- lua/libs/bufdel.lua | 87 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 lua/libs/bufdel.lua diff --git a/lua/core/keymap.lua b/lua/core/keymap.lua index a1e7201b..1a7133a2 100644 --- a/lua/core/keymap.lua +++ b/lua/core/keymap.lua @@ -16,7 +16,7 @@ map_utils.nmap({ { "q", function() - print("Unimplemented") + require("libs.bufdel").delete_buffer_expr("", false) end, desc = "Close current buffer", }, diff --git a/lua/libs/bufdel.lua b/lua/libs/bufdel.lua new file mode 100644 index 00000000..6a90fc9a --- /dev/null +++ b/lua/libs/bufdel.lua @@ -0,0 +1,87 @@ +-- nvim-bufdel +-- By Olivier Roques +-- github.com/ojroques + +local M = {} + +-- Switch to buffer 'buf' on each window from list 'windows' +local function switch_buffer(windows, buf) + local cur_win = vim.fn.winnr() + for _, winid in ipairs(windows) do + vim.cmd(string.format("%d wincmd w", vim.fn.win_id2win(winid))) + vim.cmd(string.format("buffer %d", buf)) + end + vim.cmd(string.format("%d wincmd w", cur_win)) +end + +-- Select the next buffer to display +local function get_next_buf(buf) + -- build table mapping buffers to their actual position + local buffers, buf_index = {}, 1 + for i, bufinfo in ipairs(vim.fn.getbufinfo({ buflisted = 1 })) do + if buf == bufinfo.bufnr then + buf_index = i + end + table.insert(buffers, bufinfo.bufnr) + end + -- select next buffer according to user choice + if buf_index == #buffers and #buffers > 1 then + return buffers[#buffers - 1] + end + return buffers[buf_index % #buffers + 1] +end + +-- Delete a buffer, ignoring changes if 'force' is set +local function delete_buffer(buf, force) + if vim.fn.buflisted(buf) == 0 then + return + end + -- retrieve buffer and delete it while preserving window layout + local next_buf = get_next_buf(buf) + local windows = vim.fn.getbufinfo(buf)[1].windows + switch_buffer(windows, next_buf) + -- force deletion of terminal buffers + if force or vim.fn.getbufvar(buf, "&buftype") == "terminal" then + vim.cmd(string.format("bd! %d", buf)) + else + vim.cmd(string.format("silent! confirm bd %d", buf)) + end + -- revert buffer switches if deletion was cancelled + if vim.fn.buflisted(buf) == 1 then + switch_buffer(windows, buf) + end +end + +-- Delete a given buffer, ignoring changes if 'force' is set +function M.delete_buffer_expr(bufexpr, force) + if #vim.fn.getbufinfo({ buflisted = 1 }) < 2 then + -- exit when there is only one buffer left + if force then + vim.cmd("qall!") + else + vim.cmd("confirm qall") + end + return + end + -- retrieve buffer number from buffer expression + if not bufexpr then + delete_buffer(vim.fn.bufnr(), force) + end + if tonumber(bufexpr) then + delete_buffer(tonumber(bufexpr), force) + end + bufexpr = string.gsub(bufexpr, [[^['"]+]], "") -- escape any start quote + bufexpr = string.gsub(bufexpr, [[['"]+$]], "") -- escape any end quote + delete_buffer(vim.fn.bufnr(bufexpr), force) +end + +-- Delete all listed buffers except current, ignoring changes if 'force' is set +function M.delete_buffer_others(force) + for _, bufinfo in ipairs(vim.fn.getbufinfo({ buflisted = 1 })) do + if bufinfo.bufnr ~= vim.fn.bufnr() then + delete_buffer(bufinfo.bufnr, force) + end + end +end + +return M