Skip to content

Commit b588907

Browse files
committed
feat: Add configurable buffer names for Agentic panels
Signed-off-by: Chance Zibolski <chance.zibolski@gmail.com>
1 parent 5234e93 commit b588907

4 files changed

Lines changed: 164 additions & 5 deletions

File tree

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,47 @@ header parts:
495495
}
496496
```
497497

498+
### Customizing Buffer Names
499+
500+
By default, buffer names mirror the window header titles. You can override them
501+
independently via the `buffer_name` field in each window's config, for example
502+
to show cleaner names in your statusline or buffer switcher:
503+
504+
```lua
505+
{
506+
"carlos-algms/agentic.nvim",
507+
opts = {
508+
windows = {
509+
chat = { buffer_name = "Agentic Chat" },
510+
input = { buffer_name = "Agentic Prompt" },
511+
code = { buffer_name = "Code Snippets" },
512+
files = { buffer_name = "Files" },
513+
diagnostics = { buffer_name = "Diagnostics" },
514+
todos = { buffer_name = "Tasks" },
515+
},
516+
},
517+
}
518+
```
519+
520+
You can also use a function that receives the header parts and returns a string:
521+
522+
```lua
523+
{
524+
"carlos-algms/agentic.nvim",
525+
opts = {
526+
windows = {
527+
chat = {
528+
buffer_name = function(parts)
529+
return "AI: " .. parts.title
530+
end,
531+
},
532+
},
533+
},
534+
}
535+
```
536+
537+
When a panel has no `buffer_name` set, it falls back to the header title.
538+
498539
## 🚀 Usage (Public Lua API)
499540

500541
### Commands

lua/agentic/config_default.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,34 @@
5757
--- Overrides default options (wrap, linebreak, winfixbuf, winfixheight)
5858
--- @alias agentic.UserConfig.WinOpts table<string, any>
5959

60+
--- @alias agentic.UserConfig.BufferNameFn fun(header: agentic.ui.ChatWidget.HeaderParts): string|nil
61+
6062
--- @class agentic.UserConfig.Windows.Chat
63+
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
6164
--- @field win_opts? agentic.UserConfig.WinOpts
6265

6366
--- @class agentic.UserConfig.Windows.Input
67+
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
6468
--- @field height number
6569
--- @field win_opts? agentic.UserConfig.WinOpts
6670

6771
--- @class agentic.UserConfig.Windows.Code
72+
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
6873
--- @field max_height number
6974
--- @field win_opts? agentic.UserConfig.WinOpts
7075

7176
--- @class agentic.UserConfig.Windows.Files
77+
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
7278
--- @field max_height number
7379
--- @field win_opts? agentic.UserConfig.WinOpts
7480

7581
--- @class agentic.UserConfig.Windows.Diagnostics
82+
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
7683
--- @field max_height number
7784
--- @field win_opts? agentic.UserConfig.WinOpts
7885

7986
--- @class agentic.UserConfig.Windows.Todos
87+
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
8088
--- @field display boolean
8189
--- @field max_height number
8290
--- @field win_opts? agentic.UserConfig.WinOpts
@@ -419,6 +427,8 @@ local ConfigDefault = {
419427

420428
headers = {},
421429

430+
--- Control various behaviors and features of the plugin
431+
--- @class agentic.UserConfig.Settings
422432
settings = {
423433
move_cursor_to_chat_on_submit = true,
424434
},

lua/agentic/ui/window_decoration.lua

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,73 @@ local function set_winbar(winid, text)
195195
vim.api.nvim_set_option_value("winbar", winbar_text, { win = winid })
196196
end
197197

198+
--- Resolves the buffer name from config, supporting string or function values
199+
--- @param window_name string Window name for Config.windows[name].buffer_name lookup
200+
--- @param header_parts agentic.ui.ChatWidget.HeaderParts Header parts passed to function-type buffer_name
201+
--- @param fallback string|nil Fallback name (resolved header text) when buffer_name is not set
202+
--- @return string|nil name
203+
local function resolve_buffer_name(window_name, header_parts, fallback)
204+
local win_cfg = Config.windows[window_name]
205+
local buffer_name = win_cfg and win_cfg.buffer_name
206+
207+
if buffer_name == nil then
208+
return fallback
209+
end
210+
211+
if type(buffer_name) == "string" then
212+
return buffer_name
213+
end
214+
215+
if type(buffer_name) == "function" then
216+
local ok, result = pcall(buffer_name, header_parts)
217+
if not ok then
218+
Logger.notify(
219+
string.format(
220+
"Error in buffer_name function for '%s': %s",
221+
window_name,
222+
result
223+
)
224+
)
225+
return fallback
226+
end
227+
if result ~= nil and type(result) ~= "string" then
228+
Logger.notify(
229+
string.format(
230+
"buffer_name function for '%s' must return string|nil, got %s",
231+
window_name,
232+
type(result)
233+
)
234+
)
235+
return fallback
236+
end
237+
return result
238+
end
239+
240+
Logger.notify(
241+
string.format(
242+
"buffer_name for '%s' must be string|function|nil, got %s",
243+
window_name,
244+
type(buffer_name)
245+
)
246+
)
247+
return fallback
248+
end
249+
198250
--- Sets the buffer name based on header text and tab count
199251
--- @param bufnr integer Buffer number
200252
--- @param header_text string|nil Resolved header text
201253
--- @param tab_page_id integer Tab page ID for suffix
202-
local function set_buffer_name(bufnr, header_text, tab_page_id)
203-
if not header_text or header_text == "" then
254+
--- @param window_name string Window name for Config.windows[name].buffer_name lookup
255+
--- @param header_parts agentic.ui.ChatWidget.HeaderParts Header parts for function-type buffer_name
256+
local function set_buffer_name(
257+
bufnr,
258+
header_text,
259+
tab_page_id,
260+
window_name,
261+
header_parts
262+
)
263+
local name = resolve_buffer_name(window_name, header_parts, header_text)
264+
if not name or name == "" then
204265
return
205266
end
206267

@@ -210,9 +271,9 @@ local function set_buffer_name(bufnr, header_text, tab_page_id)
210271
--- @type string|nil
211272
local buf_name
212273
if total_tabs > 1 then
213-
buf_name = string.format("%s (Tab %d)", header_text, tab_page_id)
274+
buf_name = string.format("%s (Tab %d)", name, tab_page_id)
214275
else
215-
buf_name = header_text
276+
buf_name = name
216277
end
217278

218279
vim.api.nvim_buf_set_name(bufnr, buf_name)
@@ -263,7 +324,13 @@ function WindowDecoration.render_header(bufnr, window_name, context)
263324
local text = (header_text and header_text ~= "") and header_text or ""
264325

265326
set_winbar(winid, text)
266-
set_buffer_name(bufnr, header_text, tab_page_id)
327+
set_buffer_name(
328+
bufnr,
329+
header_text,
330+
tab_page_id,
331+
window_name,
332+
dynamic_header
333+
)
267334
end)
268335
end
269336

tests/integration/test_buffer_naming.lua

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,47 @@ end)()
7878
assert.equal(5, session_count)
7979
end)
8080

81+
it("uses custom buffer_name from windows config when set", function()
82+
child.lua([[
83+
require("agentic").setup({ windows = { chat = { buffer_name = "My Chat" } } })
84+
require("agentic").toggle()
85+
]])
86+
child.flush()
87+
88+
local basename = get_panel_basename("chat")
89+
assert.is_true(vim.startswith(basename, "My Chat"))
90+
end)
91+
92+
it("uses buffer_name function to derive name from header parts", function()
93+
child.lua([[
94+
require("agentic").setup({
95+
windows = {
96+
chat = {
97+
buffer_name = function(parts)
98+
return "Custom: " .. parts.title
99+
end,
100+
},
101+
},
102+
})
103+
require("agentic").toggle()
104+
]])
105+
child.flush()
106+
107+
local basename = get_panel_basename("chat")
108+
assert.is_true(vim.startswith(basename, "Custom: 󰻞 Agentic Chat"))
109+
end)
110+
111+
it("falls back to header title when buffer_name not set", function()
112+
child.lua([[
113+
require("agentic").setup({})
114+
require("agentic").toggle()
115+
]])
116+
child.flush()
117+
118+
local basename = get_panel_basename("chat")
119+
assert.is_true(vim.startswith(basename, "󰻞 Agentic Chat"))
120+
end)
121+
81122
it("each panel has distinct buffer name prefix", function()
82123
child.lua([[ require("agentic").toggle() ]])
83124
child.flush()

0 commit comments

Comments
 (0)