Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,47 @@ header parts:
}
```

### Customizing Buffer Names

By default, buffer names mirror the window header titles. You can override them
independently via the `buffer_name` field in each window's config, for example
to show cleaner names in your statusline or buffer switcher:

```lua
{
"carlos-algms/agentic.nvim",
opts = {
windows = {
chat = { buffer_name = "Agentic Chat" },
input = { buffer_name = "Agentic Prompt" },
code = { buffer_name = "Code Snippets" },
files = { buffer_name = "Files" },
diagnostics = { buffer_name = "Diagnostics" },
todos = { buffer_name = "Tasks" },
},
},
}
```

You can also use a function that receives the header parts and returns a string:

```lua
{
"carlos-algms/agentic.nvim",
opts = {
windows = {
chat = {
buffer_name = function(parts)
return "AI: " .. parts.title
end,
},
},
},
}
```

When a panel has no `buffer_name` set, it falls back to the header title.

### Folding

Completed tool call outputs are automatically folded to keep the chat buffer
Expand Down
4 changes: 4 additions & 0 deletions doc/agentic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,10 @@ windows ~
`height` Height when position is `"bottom"`. String
percentage or number. Default: `"30%"`.
`stack_width_ratio` Ratio for stacked panels. Default: `0.4`.
`buffer_name` Name of the window buffer. String title
or function returning string title.
Default: window header title.
See |agentic-config-headers|.

Sub-panel options (each accepts `win_opts` table):

Expand Down
8 changes: 8 additions & 0 deletions lua/agentic/config_default.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,26 +85,34 @@
--- Overrides default options (wrap, linebreak, winfixheight)
--- @alias agentic.UserConfig.WinOpts table<string, any>

--- @alias agentic.UserConfig.BufferNameFn fun(header: agentic.ui.ChatWidget.HeaderParts): string|nil

--- @class agentic.UserConfig.Windows.Chat
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
--- @field win_opts? agentic.UserConfig.WinOpts

--- @class agentic.UserConfig.Windows.Input
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
--- @field height number
--- @field win_opts? agentic.UserConfig.WinOpts

--- @class agentic.UserConfig.Windows.Code
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
--- @field max_height number
--- @field win_opts? agentic.UserConfig.WinOpts

--- @class agentic.UserConfig.Windows.Files
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
--- @field max_height number
--- @field win_opts? agentic.UserConfig.WinOpts

--- @class agentic.UserConfig.Windows.Diagnostics
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
--- @field max_height number
--- @field win_opts? agentic.UserConfig.WinOpts

--- @class agentic.UserConfig.Windows.Todos
--- @field buffer_name? string|agentic.UserConfig.BufferNameFn
--- @field display boolean
--- @field max_height number
--- @field win_opts? agentic.UserConfig.WinOpts
Expand Down
80 changes: 75 additions & 5 deletions lua/agentic/ui/window_decoration.lua
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,76 @@ function WindowDecoration._set_buffer_name(bufnr, buf_name)
vim.api.nvim_buf_set_name(bufnr, buf_name)
end

--- Resolves the buffer name from config, supporting string or function values
--- @param window_name string Window name for Config.windows[name].buffer_name lookup
--- @param header_parts agentic.ui.ChatWidget.HeaderParts Header parts passed to function-type buffer_name
--- @param fallback string|nil Fallback name (resolved header text) when buffer_name is not set
--- @return string|nil name
local function resolve_buffer_name(window_name, header_parts, fallback)
local win_cfg = Config.windows[window_name]
local buffer_name = win_cfg and win_cfg.buffer_name

if buffer_name == nil then
return fallback
end

if type(buffer_name) == "string" then
return buffer_name
end

if type(buffer_name) == "function" then
local ok, result = pcall(buffer_name, header_parts)
if not ok then
Logger.notify(
string.format(
"Error in buffer_name function for '%s': %s",
window_name,
result
)
)
return fallback
end
if result == nil then
return fallback
end
if type(result) ~= "string" then
Logger.notify(
string.format(
"buffer_name function for '%s' must return string|nil, got %s",
window_name,
type(result)
)
)
return fallback
end
return result
end
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Logger.notify(
string.format(
"buffer_name for '%s' must be string|function|nil, got %s",
window_name,
type(buffer_name)
)
)
return fallback
end

--- Sets the buffer name based on header text and tab count
--- @param bufnr integer Buffer number
--- @param header_text string|nil Resolved header text
--- @param tab_page_id integer Tab page ID for suffix
local function set_buffer_name(bufnr, header_text, tab_page_id)
if not header_text or header_text == "" then
--- @param window_name string Window name for Config.windows[name].buffer_name lookup
--- @param header_parts agentic.ui.ChatWidget.HeaderParts Header parts for function-type buffer_name
local function set_buffer_name(
bufnr,
header_text,
tab_page_id,
window_name,
header_parts
)
local name = resolve_buffer_name(window_name, header_parts, header_text)
if not name or name == "" then
return
end

Expand All @@ -266,9 +330,9 @@ local function set_buffer_name(bufnr, header_text, tab_page_id)
--- @type string
local buf_name
if total_tabs > 1 then
buf_name = string.format("%s (Tab %d)", header_text, tab_page_id)
buf_name = string.format("%s (Tab %d)", name, tab_page_id)
else
buf_name = header_text
buf_name = name
end

WindowDecoration._set_buffer_name(bufnr, buf_name)
Expand Down Expand Up @@ -319,7 +383,13 @@ function WindowDecoration.render_header(bufnr, window_name, context)
local text = (header_text and header_text ~= "") and header_text or ""

set_winbar(winid, text)
set_buffer_name(bufnr, header_text, tab_page_id)
set_buffer_name(
bufnr,
header_text,
tab_page_id,
window_name,
dynamic_header
)
end)
end

Expand Down
105 changes: 105 additions & 0 deletions tests/integration/test_buffer_naming.lua
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,111 @@ end)()
assert.equal(5, session_count)
end)

it("uses custom buffer_name from windows config when set", function()
child.lua([[
require("agentic").setup({ windows = { chat = { buffer_name = "My Chat" } } })
require("agentic").toggle()
]])
child.flush()

local basename = get_panel_basename("chat")
assert.is_true(vim.startswith(basename, "My Chat"))
end)

it("uses buffer_name function to derive name from header parts", function()
child.lua([[
require("agentic").setup({
windows = {
chat = {
buffer_name = function(parts)
return "Custom: " .. parts.title
end,
},
},
})
require("agentic").toggle()
]])
child.flush()

local basename = get_panel_basename("chat")
assert.is_true(vim.startswith(basename, "Custom: 󰻞 Agentic Chat"))
end)

it("falls back to header title when buffer_name not set", function()
child.lua([[
require("agentic").setup({})
require("agentic").toggle()
]])
child.flush()

local basename = get_panel_basename("chat")
assert.is_true(vim.startswith(basename, "󰻞 Agentic Chat"))
end)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

it("falls back to header title when buffer_name function throws", function()
child.lua([[
require("agentic").setup({
windows = {
chat = {
buffer_name = function()
error("intentional error")
end,
},
},
})
require("agentic").toggle()
]])
child.flush()

local basename = get_panel_basename("chat")
assert.is_true(vim.startswith(basename, "󰻞 Agentic Chat"))
end)

it(
"falls back to header title when buffer_name function returns nil",
function()
child.lua([[
require("agentic").setup({
windows = {
chat = {
buffer_name = function()
return nil
end,
},
},
})
require("agentic").toggle()
]])
child.flush()

local basename = get_panel_basename("chat")
assert.is_true(vim.startswith(basename, "󰻞 Agentic Chat"))
end
)

it(
"assigns unique names when two panels share the same buffer_name",
function()
child.lua([[
require("agentic").setup({
windows = {
chat = { buffer_name = "Shared Name" },
input = { buffer_name = "Shared Name" },
},
})
require("agentic").toggle()
]])
child.flush()

local chat_basename = get_panel_basename("chat")
local input_basename = get_panel_basename("input")

assert.is_true(vim.startswith(chat_basename, "Shared Name"))
assert.is_true(vim.startswith(input_basename, "Shared Name"))
assert.is_not.equal(chat_basename, input_basename)
end
)

it("each panel has distinct buffer name prefix", function()
child.lua([[ require("agentic").toggle() ]])
child.flush()
Expand Down
Loading