thank you for your love and support for buvvers! 😊❤️
buvvers is stable now, but some config options may change slightly
if you run into issues, check this readme
i won't modify configurable options unless absolutely necessary—rest assured!
20250306-204524-531969752.mp4
display buffers vertically
minimal, robust, highly customizable, easily modifiable source code
inspired by vuffers
{
buvvers_buf_name = "[buvvers]",
-- buvvers buffer name displayed on status line
buvvers_buf_opt = {
-- buvvers buffer local options
filetype = "buvvers",
},
buvvers_win = {
-- the `config` parameter of `vim.api.nvim_open_win`
win = -1,
split = "right",
width = math.ceil(vim.o.columns / 8),
style = "minimal",
},
buvvers_win_enter = false,
-- if true, let buvvers window get focus after being opened, otherwise focus will stay in current window
buvvers_win_opt = {
-- buvvers window local options
winfixbuf = true,
winfixwidth = true,
winfixheight = true,
wrap = true,
},
highlight_group_current_buffer = "Visual",
-- inside buvvers buffer, the current buffer is highlighted with this highlight group
buffer_handle_list_to_buffer_name_list = require("buvvers.buffer_handle_list_to_buffer_name_list"),
-- this is the core function of buvvers, see details below
}
require("buvvers").setup()
that's it!
you can call these functions:
function | description |
---|---|
require("buvvers").open |
enable buvvers |
require("buvvers").close |
disable buvvers |
require("buvvers").toggle |
toggle buvvers |
for example, you can run :lua require("buvvers").open()
to enable buvvers
Note
you can disable buvvers by:
- call
require("buvvers").close
orrequire("buvvers").toggle
- delete buvvers buffer
- close buvvers window
these ways are equivalent
they completely clear everything related to buvvers (buffer, window, and autocmd), as if buvvers was never opened before
if you want to bind a key to toggle buvvers, and enable buvvers at startup:
require("buvvers").setup()
vim.keymap.set("n", "<leader>bl", require("buvvers").toggle)
-- bind `<leader>bl` to toggle buvvers
vim.schedule(require("buvvers").open)
-- enable buvvers at startup
Note
since vim.api.nvim_open_win
is not allowed when textlock
is active, we need to wrap require("buvvers").open
with vim.schedule
during startup, otherwise config.buvvers_win_enter
will have no effect
okay! you can use buvvers happily now!
the following content provides detailed customization information for buvvers, which you can safely ignore
if you want to change how the buvvers window looks:
require("buvvers").setup({
buvvers_win = {
-- the `config` parameter of `vim.api.nvim_open_win`
split = "below",
height = 4,
},
})
vim.schedule(require("buvvers").open)
you can even use a floating window thanks to the power of vim.api.nvim_open_win
require("buvvers").setup({
buvvers_win = {
-- the `config` parameter of `vim.api.nvim_open_win`
relative = "editor",
row = 3,
col = 3,
width = 40,
height = 20,
style = "minimal",
},
buvvers_win_enter = true,
})
vim.schedule(require("buvvers").open)
however, this won't work as expected because the config table is merged via vim.tbl_deep_extend
, not vim.tbl_extend
instead, we should:
require("buvvers").setup()
require("buvvers").config = vim.tbl_extend(
"force",
require("buvvers").config,
{
buvvers_win = {
-- the `config` parameter of `vim.api.nvim_open_win`
relative = "editor",
row = 3,
col = 3,
width = 40,
height = 20,
style = "minimal",
},
buvvers_win_enter = true,
}
)
vim.schedule(require("buvvers").open)
you can customize the display buffer names by modifying buffer_handle_list_to_buffer_name_list
function
the function's input is a buffer_handle_list
, for example:
-- example 1:
{1, 6, 7, 8}
-- example 2:
{1, 6, 7, 8, 9, 10}
the function's output is a buffer_name_list
, for example:
-- example 1:
{
"dwm.c",
"buvvers.lua",
}
-- example 2:
{
{
" ",
"dwm.c",
},
{
" ",
"buvvers.lua",
},
}
-- example 3:
{
{
{" ", "DiffAdd"}, -- DiffAdd is a highlight group
"dwm.c",
},
{
{" ", "DiffDelete"},
"buvvers.lua",
},
}
-- example 4:
{
{
{" ", "DiffAdd"},
"dwm.c",
" love",
{" you", "DiffAdd"},
},
{
{" ", "DiffDelete"},
"buvvers.lua",
" love",
{" you", "DiffDelete"},
},
}
the length of buffer_name_list
should be equal to buffer_handle_list
, of course
you can view the display result by:
require("buvvers").setup({
buffer_handle_list_to_buffer_name_list = function(handle_l)
return
{
{
{" ", "DiffAdd"},
"dwm.c",
" love",
{" you", "DiffAdd"},
},
{
{" ", "DiffDelete"},
"buvvers.lua",
" love",
{" you", "DiffDelete"},
},
}
end,
})
vim.schedule(require("buvvers").open)
now, if you were the author of buvvers, how can you write such function?
you may say: "ahh, this is easy"
require("buvvers").setup({
buffer_handle_list_to_buffer_name_list = function(handle_l)
local name_l = {}
for _, i in ipairs(handle_l) do
table.insert(name_l, vim.fn.bufname(i))
end
return name_l
end,
})
this implementation has many limitations, but you're encouraged to give it a try :)
buvvers has a default implementation built in, these 2 setups are equivalent:
require("buvvers").setup()
require("buvvers").setup({
buffer_handle_list_to_buffer_name_list = require("buvvers.buffer_handle_list_to_buffer_name_list"),
})
the default implementation features:
- unique name
- handle unnamed buffers
- handle special buftype
typically, you want to adjust the default function:
if you want to add a
prefix
require("buvvers").setup({
buffer_handle_list_to_buffer_name_list = function(handle_l)
local name_l
local default_function = require("buvvers.buffer_handle_list_to_buffer_name_list")
name_l = default_function(handle_l)
for n, name in ipairs(name_l) do
name_l[n] = " " .. name
end
return name_l
end,
})
if you want to add a
prefix, highlight with "ErrorMsg" highlight group
require("buvvers").setup({
buffer_handle_list_to_buffer_name_list = function(handle_l)
local name_l
local default_function = require("buvvers.buffer_handle_list_to_buffer_name_list")
name_l = default_function(handle_l)
for n, name in ipairs(name_l) do
name_l[n] = {
{" ", "ErrorMsg"},
name,
}
end
return name_l
end,
})
if you want to add a prefix decided by mini.icons
require("buvvers").setup({
buffer_handle_list_to_buffer_name_list = function(handle_l)
local name_l
local default_function = require("buvvers.buffer_handle_list_to_buffer_name_list")
name_l = default_function(handle_l)
for n, name in ipairs(name_l) do
local icon, hl = MiniIcons.get("file", name)
name_l[n] = {
{icon .. " ", hl},
name,
}
end
return name_l
end,
})
if you want to add a prefix that indicate whether a buffer is modified
require("buvvers").setup({
buffer_handle_list_to_buffer_name_list = function(handle_l)
local name_l
local default_function = require("buvvers.buffer_handle_list_to_buffer_name_list")
name_l = default_function(handle_l)
for n, name in ipairs(name_l) do
local is_modified = vim.api.nvim_get_option_value("modified", {buf = handle_l[n]})
local prefix
if is_modified then
prefix = "[+]"
else
prefix = "[ ]"
end
name_l[n] = {
prefix,
" ",
name,
}
end
return name_l
end,
})
however, this won't work as expected because buvvers doesn't refresh when a buffer's modification state changes
to refresh buvvers, use:
function | description |
---|---|
require("buvvers").buvvers_open |
refresh buvvers |
note the function name is require("buvvers").buvvers_open
, not require("buvvers").open
i will cover how to set an autocmd to refresh automatically later
the buvvers buffer does not have any keybindings by default
you can add keybindings yourself with these functions
function | description |
---|---|
require("buvvers").buvvers_get_buf |
get buvvers buffer |
require("buvvers").buvvers_get_win |
get buvvers window |
require("buvvers").buvvers_buf_get_buf |
inside the buvvers buffer, get the buffer of line number n |
for example:
- bind "q" to disable buvvers
- bind "d" to delete buffer
mini.bufremove is required
- bind "o" to open buffer
require("buvvers").setup()
vim.keymap.set("n", "<leader>bl", require("buvvers").toggle)
-- bind `<leader>bl` to toggle buvvers
local add_buffer_keybindings = function()
vim.keymap.set(
"n",
"q",
require("buvvers").close,
{
buffer = require("buvvers").buvvers_get_buf(),
nowait = true,
}
)
vim.keymap.set(
"n",
"d",
function()
local cursor_buf_handle = require("buvvers").buvvers_buf_get_buf(vim.fn.line("."))
MiniBufremove.delete(cursor_buf_handle, false)
end,
{
buffer = require("buvvers").buvvers_get_buf(),
nowait = true,
}
)
vim.keymap.set(
"n",
"o",
function()
local cursor_buf_handle = require("buvvers").buvvers_buf_get_buf(vim.fn.line("."))
local previous_win_handle = vim.fn.win_getid(vim.fn.winnr("#"))
-- https://github.com/nvim-neo-tree/neo-tree.nvim/blob/0b44040ec7b8472dfc504bbcec735419347797ad/lua/neo-tree/utils/init.lua#L643
vim.api.nvim_win_set_buf(previous_win_handle, cursor_buf_handle)
vim.api.nvim_set_current_win(previous_win_handle)
end,
{
buffer = require("buvvers").buvvers_get_buf(),
nowait = true,
}
)
end
vim.api.nvim_create_augroup("buvvers_config", {clear = true})
vim.api.nvim_create_autocmd(
"User",
{
group = "buvvers_config",
pattern = "BuvversBufEnabled",
callback = add_buffer_keybindings,
}
)
-- use `BuvversBufEnabled` to add buffer local keybindings
vim.schedule(require("buvvers").open)
-- enable buvvers at startup
the reason why we need "BuvversBufEnabled" autocmd in this example is:
when buvvers is closed, its buffer is deleted, causing the buffer-local keybindings to be lost
these are the supported autocmds:
autocmd | description |
---|---|
BuvversBufEnabled | when buvvers buffer is enabled |
BuvversWinEnabled | when buvvers window is enabled |
BuvversAutocmdEnabled | when buvvers autocmd is enabled |
this is the full setup of the setup mentioned before
require("buvvers").setup({
buffer_handle_list_to_buffer_name_list = function(handle_l)
local name_l
local default_function = require("buvvers.buffer_handle_list_to_buffer_name_list")
name_l = default_function(handle_l)
for n, name in ipairs(name_l) do
local is_modified = vim.api.nvim_get_option_value("modified", {buf = handle_l[n]})
local prefix
if is_modified then
prefix = "[+]"
else
prefix = "[ ]"
end
name_l[n] = {
prefix,
" ",
name,
}
end
return name_l
end,
})
vim.keymap.set("n", "<leader>bl", require("buvvers").toggle)
-- bind `<leader>bl` to toggle buvvers
local add_autocmds = function()
vim.api.nvim_create_autocmd(
{
"BufModifiedSet",
},
{
group = "buvvers",
callback = require("buvvers").buvvers_open,
}
)
end
vim.api.nvim_create_augroup("buvvers_config", {clear = true})
vim.api.nvim_create_autocmd(
"User",
{
group = "buvvers_config",
pattern = "BuvversAutocmdEnabled",
callback = add_autocmds,
}
)
-- use `BuvversAutocmdEnabled` to add a autocmd that refresh buvvers when `BufModifiedSet` event is triggered
vim.schedule(require("buvvers").open)
-- enable buvvers at startup
the reason why we need "BuvversAutocmdEnabled" autocmd in this example is:
when buvvers is closed, its autocmds are deleted