Skip to content

Commit f43fd24

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 f43fd24

File tree

14 files changed

+541
-0
lines changed

14 files changed

+541
-0
lines changed

.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: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Bufferinator.nvim
2+
3+
> Epic, humorous, and modern buffer management plugin for Neovim — nuke, blast, or yeet your buffers with style!
4+
5+
---
6+
7+
## Features
8+
9+
- 🧨 Dynamic floating menu with border for buffer actions
10+
- 🚀 Close hidden buffers, current buffer, all except current, or all buffers
11+
- 🎛️ Easily overridable keymap and options (default: `<C-q>`)
12+
- 🧩 Optionally disable built-in keymaps and use only the `:BufferinatorMenu` command
13+
- 📝 LuaDoc-style API documentation & Neovim help file (`:help bufferinator`)
14+
- 🧪 Automated tests with plenary.nvim
15+
- 🪶 No runtime plugin dependencies (except for tests)
16+
- ⚖️ MIT License
17+
18+
---
19+
20+
## Installation
21+
22+
**With [lazy.nvim](https://github.com/folke/lazy.nvim):**
23+
24+
```lua
25+
{
26+
"mthnglac/bufferinator.nvim",
27+
config = function() require("bufferinator").setup() end -- or use `config = true`
28+
}
29+
```
30+
31+
---
32+
33+
## Configuration & Usage
34+
35+
```lua
36+
require("bufferinator").setup({
37+
-- Default keymap to open the menu (normal mode)
38+
keymap = "<C-q>",
39+
40+
-- Set to true to disable built-in keymaps
41+
-- Only use the :BufferinatorMenu command or your own keymap
42+
disable_keymaps = false,
43+
})
44+
45+
-- Example: set your own keymap to open the menu via the command
46+
-- vim.keymap.set("n", "<leader>bm", function() vim.cmd("BufferinatorMenu") end)
47+
```
48+
49+
---
50+
51+
## Bufferinator Menu Options
52+
53+
1. Cancel the action
54+
2. Close hidden buffers
55+
3. Close current buffer
56+
4. Close all buffers except current
57+
5. Close all buffers (including current)
58+
59+
---
60+
61+
## Commands
62+
63+
- `:BufferinatorMenu` — Open the Bufferinator floating menu
64+
65+
---
66+
67+
## Documentation
68+
69+
- `:help bufferinator` for full help and usage details.
70+
71+
---
72+
73+
## License
74+
75+
MIT

doc/bufferinator.txt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
*bufferinator.txt* 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+
==============================================================================
18+
USAGE
19+
20+
:lua require("bufferinator").setup()
21+
22+
By default, press <C-q> to open the Bufferinator menu.
23+
24+
To customize the keymap:
25+
:lua require("bufferinator").setup({ keymap = "<leader>bb" })
26+
27+
==============================================================================
28+
MENU OPTIONS
29+
30+
1. Cancel the action
31+
2. Close hidden buffers
32+
3. Close current buffer
33+
4. Close all buffers except current
34+
5. Close all buffers (including current)
35+
36+
==============================================================================
37+
API
38+
39+
require("bufferinator").setup({ keymap = "<C-q>" })
40+
41+
==============================================================================
42+
LICENSE
43+
44+
MIT
45+
46+
==============================================================================
47+
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: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
15+
--- Setup Bufferinator.nvim
16+
-- @param opts table|nil Optional table of options:
17+
-- - keymap (string): Keymap to open the menu (default: "<C-q>")
18+
-- - disable_keymaps (boolean): If true, built-in keymaps are not set
19+
function M.setup(opts)
20+
opts = vim.tbl_deep_extend("force", {}, default_opts, opts or {})
21+
if not opts.disable_keymaps then
22+
keymaps.setup_keymaps(opts, menu.open)
23+
end
24+
commands.setup_commands()
25+
end
26+
27+
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)