- 为什么再写一个 bufdelete 插件
- bufdel.nvim 的核心设计
- 删除之后,切换到哪个 buffer?
- 用户命令
Bdelete/Bwipeout - 一个 Vim 本身的限制说明
- 自定义用户事件
- 和其他插件的简单对比
- 写在最后
在使用 Neovim 的过程中,「删除 buffer 但不破坏窗口布局」一直是一个高频需求。
社区里已经有不少相关插件,比如 bufdelete.nvim、nvim-bufdel、mini.bufremove,以及 snacks.bufdelete。
但在我自己的长期使用中,总觉得缺少了我需要的功能。
于是,我写了一个新的插件:bufdel.nvim。
这篇文章简单聊聊它解决了什么问题、有哪些设计取舍,以及它和现有方案的区别。
为什么再写一个 bufdelete 插件
先说结论:bufdel.nvim 设计初衷是为了删除 buffer 这个操作的每一步更加可控。
我写这个插件,主要有几个原因:
-
bufdelete.nvim 已经 archived
bufdelete.nvim 是一个非常优秀的插件,我也长期在用。但它目前已经被标记为 archived,不再维护。
我希望有一个持续维护、可扩展的替代方案,同时保留它最核心、最优雅的设计。
-
我需要更灵活的 buffer 选择方式
很多插件只支持按照 buffer number 删除,但是再实际使用中,我经常需要:
- 按照 buffer name 删除
- 按照正则表达式匹配到的 buffer 名称删除
- 按照特定的条件函数删除(比如:未修改、已列出、非当前 buffer)
-
删除之后,切换到哪个 buffer,应该是可控的
前面提到的几个插件大多数在删除 buffer 后,选择切换到
bufnr('#')。但我更希望能明确指定下一个 buffer 是哪个或者通过函数,完全自定义切换逻辑。
bufdel.nvim 的核心设计
-
一个核心 API:delete(buffers, opt)
bufdel.nvim 只暴露一个核心函数:
require('bufdel').delete(buffers, opt)
但它的参数非常灵活。
-
buffers 参数:你想怎么选 buffer 都行
buffers 支持多种形式:
- 单个 buffer number
- buffer 名称(字符串)
- Vim 正则(匹配 buffer name)
- table(混合 bufnr / bufname / regex)
- 函数过滤器
比如,用函数删除所有“已保存但不是当前”的 buffer:
require('bufdel').delete(function(buf) return not vim.bo[buf].modified and vim.bo[buf].buflisted and buf ~= vim.api.nvim_get_current_buf() end, { wipe = true })这类逻辑,在很多插件里是做不到的。
-
正则匹配 buffer 名称
如果你想清理一类文件,比如所有 .txt buffer:
require('bufdel').delete('.txt$', { wipe = true })这在日常清理临时文件、日志文件时非常方便。
删除之后,切换到哪个 buffer?
这是 bufdel.nvim 的一个重点特性。
-
使用函数自定义切换逻辑(推荐)
require('bufdel').delete(filter, { wipe = true, switch = function(deleted_buf) return vim.fn.bufnr('#') -- 切换到 alternate buffer end, })你可以在这里实现任何策略,只要返回一个有效的 buffer number。
-
内置几种常用策略
如果不想写函数,也可以直接用字符串:
switch = 'alt'当前支持:
alt:alternate buffer(#)current:保持当前 bufferlastused:最近使用的 buffernext/prev:下一个 / 上一个 buffer
-
直接指定 bufnr
```lua switch = 3 ```
用户命令Bdelete/Bwipeout
bufdel.nvim 提供了两个命令:
:Bdelete
:Bwipeout
行为和 :bdelete / :bwipeout 一致,但不会改变窗口布局。
示例:
:Bdelete
:Bdelete 3
:Bdelete 2 5 7
:3,6Bdelete
一个 Vim 本身的限制说明
和原生 :bdelete 一样:
纯数字的 buffer 名称不能作为用户命令参数使用。
比如:
:e 123
:Bdelete 123
这时必须使用 bufnr,而不是 bufname。
自定义用户事件
bufdel.nvim 会在删除 buffer 前后触发两个事件:
User BufDelPre
User BufDelPost
示例:
vim.api.nvim_create_autocmd('User', {
pattern = 'BufDelPost',
callback = function(ev)
-- 被删除的 bufnr 在 ev.data.buf 中
end,
})
如果删除失败,BufDelPost 不会触发。
和其他插件的简单对比
下面是基于我个人使用需求的一个对比表:
| Feature / Plugin | bufdel.nvim | bufdelete.nvim | nvim-bufdel | snacks.bufdelete | mini.bufremove |
|---|---|---|---|---|---|
| Preserve window layout | ✓ | ✓ | ✓ | ✓ | ✓ |
| Delete by bufnr | ✓ | ✓ | ✓ | ✓ | ✓ |
| Delete by bufname | ✓ | ✓ | ✓ | ✓ | ✗ |
| User Command | ✓ | ✓ | ✓ | ✗ | ✗ |
| Lua filter function | ✓ | ✗ | ✗ | ✓ | ✗ |
| Regex buffer matching | ✓ | ✗ | ✗ | ✗ | ✗ |
| Post-delete buffer switch | ✓ | ✓ | ✓ | ✗ | ✗ |
| User autocmd hooks | ✓ | ✓ | ✗ | ✗ | ✗ |
如果你发现表格里有不准确的地方,欢迎直接提 issue。
写在最后
bufdel.nvim 并不是一个“什么都做”的插件,相反,我刻意让它保持:
- 功能边界清晰
- API 简单
- 逻辑可控
如果你:
- 经常清理 buffer
- 在意窗口布局
- 希望对 buffer 删除过程有更多掌控
那它可能正好适合你。
👉 GitHub:wsdjeg/budel.nvim
如果你觉得有用,欢迎 star ⭐