Skip to content

Commit 76fe4a0

Browse files
committed
feat: initial commit of Bufferinator.nvim
- Modern, modular Neovim buffer management plugin - Dynamic floating menu with border for buffer actions: - Close hidden buffers - Close current buffer - Close all buffers except current - Close all buffers (including current) - Easily overridable keymap and options (default: <C-q>) - :BufferinatorMenu command to open the menu - LuaDoc-style API documentation - Neovim help file (doc/bufferinator.txt) - Automated tests using plenary.nvim (tests/) - MIT license and detailed README - No runtime plugin dependencies (except for tests)
0 parents  commit 76fe4a0

14 files changed

Lines changed: 497 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Install Neovim
16+
uses: rhysd/action-setup-vim@v1
17+
with:
18+
neovim: true
19+
version: stable
20+
21+
- name: Install plenary.nvim
22+
run: |
23+
mkdir -p ~/.local/share/nvim/site/pack/test/start
24+
git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/test/start/plenary.nvim
25+
26+
- name: Run tests
27+
run: |
28+
nvim --headless -c "PlenaryBustedDirectory tests/" +qall

.gitignore

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Lua bytecode
2+
*.luac
3+
4+
# Neovim swap, backup, undo files
5+
*.swp
6+
*.swo
7+
*.swn
8+
*.bak
9+
*.tmp
10+
*.undo
11+
12+
# OS-specific files
13+
.DS_Store
14+
Thumbs.db
15+
16+
# Test output
17+
test_output/
18+
output/
19+
*.log
20+
21+
# Node/npm (bazı kullanıcılar için)
22+
node_modules/
23+
package-lock.json
24+
npm-debug.log
25+
26+
# Neovim package manager artifacts (optional)
27+
site/
28+
plugged/
29+
pack/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 YOUR NAME
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Bufferinator.nvim
2+
3+
🔥 The epic buffer destroyer for Neovim!
4+
Quickly close hidden, current, or all buffers with a slick floating menu.
5+
6+
## Features
7+
8+
- Floating window menu with border
9+
- Close hidden buffers, current buffer, all except current, or all buffers
10+
- Customizable keybind (default: `<C-q>`)
11+
- Lua API for advanced users
12+
13+
## Installation
14+
15+
**lazy.nvim**
16+
```lua
17+
{
18+
"yourname/bufferinator.nvim",
19+
config = true
20+
}
21+
```
22+
23+
**packer.nvim**
24+
```lua
25+
use { "yourname/bufferinator.nvim" }
26+
```
27+
28+
## Usage
29+
30+
```lua
31+
require("bufferinator").setup()
32+
```
33+
34+
### Custom Keybind
35+
36+
```lua
37+
require("bufferinator").setup({
38+
keymap = "<leader>bb"
39+
})
40+
```
41+
42+
## License
43+
44+
MIT

doc/bufferinator.txt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
*bufferinator.nvim* Epic buffer management for Neovim
2+
3+
==============================================================================
4+
NAME
5+
Bufferinator.nvim
6+
7+
DESCRIPTION
8+
Bufferinator.nvim is an epic, humorous buffer management plugin for Neovim.
9+
It provides a floating menu to quickly close hidden, current, or all buffers.
10+
11+
==============================================================================
12+
INSTALLATION
13+
14+
" With lazy.nvim
15+
{ "mthnglac/bufferinator.nvim", config = true }
16+
17+
" With packer.nvim
18+
use { "mthnglac/bufferinator.nvim" }
19+
20+
==============================================================================
21+
USAGE
22+
23+
:lua require("bufferinator").setup()
24+
25+
By default, press <C-q> to open the Bufferinator menu.
26+
27+
To customize the keymap:
28+
:lua require("bufferinator").setup({ keymap = "<leader>bb" })
29+
30+
==============================================================================
31+
MENU OPTIONS
32+
33+
1. Cancel the action
34+
2. Close hidden buffers
35+
3. Close current buffer
36+
4. Close all buffers except current
37+
5. Close all buffers (including current)
38+
39+
==============================================================================
40+
API
41+
42+
require("bufferinator").setup({ keymap = "<C-q>" })
43+
44+
==============================================================================
45+
LICENSE
46+
47+
MIT
48+
49+
==============================================================================
50+
vim:tw=78:ts=8:ft=help:norl:

lua/bufferinator/actions.lua

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--- Bufferinator buffer actions
2+
-- @module bufferinator.actions
3+
4+
local M = {}
5+
6+
--- Close all hidden buffers except the current one.
7+
function M.close_hidden_buffers()
8+
local current_buf = vim.api.nvim_get_current_buf()
9+
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
10+
if buf ~= current_buf and vim.api.nvim_buf_is_loaded(buf) and vim.fn.bufwinnr(buf) == -1 then
11+
vim.api.nvim_buf_delete(buf, { force = true })
12+
end
13+
end
14+
vim.notify("Hidden buffers closed", vim.log.levels.INFO)
15+
end
16+
17+
--- Close all buffers except the current one.
18+
function M.close_other_buffers()
19+
local current_buf = vim.api.nvim_get_current_buf()
20+
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
21+
if buf ~= current_buf and vim.api.nvim_buf_is_loaded(buf) then
22+
vim.api.nvim_buf_delete(buf, { force = true })
23+
end
24+
end
25+
vim.notify("Other buffers closed", vim.log.levels.INFO)
26+
end
27+
28+
--- Close all buffers, including the current one.
29+
function M.close_all_buffers()
30+
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
31+
if vim.api.nvim_buf_is_loaded(buf) then
32+
vim.api.nvim_buf_delete(buf, { force = true })
33+
end
34+
end
35+
vim.notify("All buffers closed", vim.log.levels.INFO)
36+
end
37+
38+
--- Close the current buffer.
39+
function M.close_current_buffer()
40+
vim.cmd("bd")
41+
vim.notify("Current buffer closed", vim.log.levels.INFO)
42+
end
43+
44+
return M

lua/bufferinator/commands.lua

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--- Bufferinator command setup
2+
-- @module bufferinator.commands
3+
4+
local menu = require("bufferinator.menu")
5+
6+
local M = {}
7+
8+
--- Setup Bufferinator user commands
9+
-- Defines :BufferinatorMenu command to open the menu.
10+
function M.setup_commands()
11+
vim.api.nvim_create_user_command("BufferinatorMenu", function()
12+
menu.open()
13+
end, { desc = "Open Bufferinator menu" })
14+
end
15+
16+
return M

lua/bufferinator/init.lua

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--- Bufferinator.nvim main module
2+
-- @module bufferinator
3+
4+
local menu = require("bufferinator.menu")
5+
local keymaps = require("bufferinator.keymaps")
6+
local commands = require("bufferinator.commands")
7+
8+
local default_opts = {
9+
keymap = "<C-q>",
10+
disable_keymaps = false,
11+
}
12+
13+
local M = {}
14+
local configured = false
15+
16+
--- Setup Bufferinator.nvim
17+
-- @param opts table|nil Optional table of options:
18+
-- - keymap (string): Keymap to open the menu (default: "<C-q>")
19+
-- - disable_keymaps (boolean): If true, built-in keymaps are not set
20+
function M.setup(opts)
21+
opts = vim.tbl_deep_extend("force", {}, default_opts, opts or {})
22+
if not opts.disable_keymaps then
23+
keymaps.setup_keymaps(opts, menu.open)
24+
end
25+
commands.setup_commands()
26+
configured = true
27+
end
28+
29+
vim.schedule(function()
30+
if not configured then
31+
M.setup()
32+
end
33+
end)
34+
35+
return M

lua/bufferinator/keymaps.lua

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--- Bufferinator keymap setup
2+
-- @module bufferinator.keymaps
3+
4+
local M = {}
5+
6+
--- Setup Bufferinator keymaps
7+
-- @param opts table Options table (expects 'keymap' key)
8+
-- @param menu_open_fn function Function to call when keymap is triggered
9+
function M.setup_keymaps(opts, menu_open_fn)
10+
local key = opts.keymap or "<C-q>"
11+
vim.keymap.set("n", key, menu_open_fn, {
12+
noremap = true,
13+
silent = true,
14+
desc = "Open Bufferinator menu",
15+
})
16+
end
17+
18+
return M

lua/bufferinator/menu.lua

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
--- Bufferinator menu module
2+
-- @module bufferinator.menu
3+
local actions = require("bufferinator.actions")
4+
5+
local M = {}
6+
7+
--- Open the Bufferinator floating menu.
8+
-- Shows buffer management options in a floating window.
9+
function M.open()
10+
local menu = {
11+
{
12+
desc = "Cancel the action",
13+
action = function()
14+
vim.notify("Cancelled", vim.log.levels.INFO)
15+
end,
16+
},
17+
{ desc = "Close hidden buffers", action = actions.close_hidden_buffers },
18+
{ desc = "Close current buffer", action = actions.close_current_buffer },
19+
{ desc = "Close all buffers except current", action = actions.close_other_buffers },
20+
{ desc = "Close all buffers (including current)", action = actions.close_all_buffers },
21+
}
22+
23+
local lines = {
24+
"Select action:",
25+
"1: " .. menu[1].desc,
26+
"2: " .. menu[2].desc,
27+
"3: " .. menu[3].desc,
28+
"4: " .. menu[4].desc,
29+
"5: " .. menu[5].desc,
30+
"",
31+
"Press number or q/Esc/Ctrl+C to cancel",
32+
}
33+
34+
local width = 0
35+
for _, line in ipairs(lines) do
36+
width = math.max(width, #line)
37+
end
38+
width = width + 4
39+
40+
local height = #lines + 2
41+
42+
local buf = vim.api.nvim_create_buf(false, true)
43+
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
44+
vim.bo[buf].modifiable = false
45+
vim.bo[buf].buftype = "nofile"
46+
vim.bo[buf].bufhidden = "wipe"
47+
vim.bo[buf].swapfile = false
48+
49+
local win = vim.api.nvim_open_win(buf, true, {
50+
relative = "editor",
51+
width = width,
52+
height = height,
53+
row = math.floor((vim.o.lines - height) / 2),
54+
col = math.floor((vim.o.columns - width) / 2),
55+
style = "minimal",
56+
border = "rounded",
57+
zindex = 1000,
58+
})
59+
60+
local function close_menu()
61+
if vim.api.nvim_win_is_valid(win) then
62+
vim.api.nvim_win_close(win, true)
63+
end
64+
end
65+
66+
for i = 1, #menu do
67+
vim.keymap.set("n", tostring(i), function()
68+
close_menu()
69+
menu[i].action()
70+
end, { buffer = buf, nowait = true, noremap = true, silent = true })
71+
end
72+
vim.keymap.set("n", "q", close_menu, { buffer = buf, nowait = true, noremap = true, silent = true })
73+
vim.keymap.set("n", "<Esc>", close_menu, { buffer = buf, nowait = true, noremap = true, silent = true })
74+
vim.keymap.set("n", "<C-c>", close_menu, { buffer = buf, nowait = true, noremap = true, silent = true })
75+
76+
vim.cmd("normal! gg")
77+
end
78+
79+
return M

0 commit comments

Comments
 (0)