Eric's Blog 时光荏苒,岁月如梭

Neovim buffer 删除插件 bufdel.nvim

2026-01-28
Eric Wong

在使用 Neovim 的过程中,「删除 buffer 但不破坏窗口布局」一直是一个高频需求。

社区里已经有不少相关插件,比如 bufdelete.nvimnvim-bufdelmini.bufremove,以及 snacks.bufdelete。 但在我自己的长期使用中,总觉得缺少了我需要的功能。

于是,我写了一个新的插件:bufdel.nvim

这篇文章简单聊聊它解决了什么问题、有哪些设计取舍,以及它和现有方案的区别。

为什么再写一个 bufdelete 插件

先说结论:bufdel.nvim 设计初衷是为了删除 buffer 这个操作的每一步更加可控。

我写这个插件,主要有几个原因:

  1. bufdelete.nvim 已经 archived

    bufdelete.nvim 是一个非常优秀的插件,我也长期在用。但它目前已经被标记为 archived,不再维护。

    我希望有一个持续维护、可扩展的替代方案,同时保留它最核心、最优雅的设计。

  2. 我需要更灵活的 buffer 选择方式

    很多插件只支持按照 buffer number 删除,但是再实际使用中,我经常需要:

    • 按照 buffer name 删除
    • 按照正则表达式匹配到的 buffer 名称删除
    • 按照特定的条件函数删除(比如:未修改、已列出、非当前 buffer)
  3. 删除之后,切换到哪个 buffer,应该是可控的

    前面提到的几个插件大多数在删除 buffer 后,选择切换到 bufnr('#')。但我更希望能明确指定下一个 buffer 是哪个或者通过函数,完全自定义切换逻辑。

bufdel.nvim 的核心设计

  1. 一个核心 API:delete(buffers, opt)

    bufdel.nvim 只暴露一个核心函数:

    require('bufdel').delete(buffers, opt)
    

但它的参数非常灵活。

  1. 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 })
    

    这类逻辑,在很多插件里是做不到的。

  2. 正则匹配 buffer 名称

    如果你想清理一类文件,比如所有 .txt buffer:

    require('bufdel').delete('.txt$', { wipe = true })
    

    这在日常清理临时文件、日志文件时非常方便。

删除之后,切换到哪个 buffer?

这是 bufdel.nvim 的一个重点特性。

  1. 使用函数自定义切换逻辑(推荐)

    require('bufdel').delete(filter, {
      wipe = true,
      switch = function(deleted_buf)
        return vim.fn.bufnr('#') -- 切换到 alternate buffer
      end,
    })
    

    你可以在这里实现任何策略,只要返回一个有效的 buffer number。

  2. 内置几种常用策略

    如果不想写函数,也可以直接用字符串:

    switch = 'alt'
    

    当前支持:

    • alt:alternate buffer(#)
    • current:保持当前 buffer
    • lastused:最近使用的 buffer
    • next / prev:下一个 / 上一个 buffer
  3. 直接指定 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 ⭐


版权声明:本文为原创文章,遵循 署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)版权协议,转载请附上原文出处链接和本声明。


延生阅读

分享到:

评论