Extending with UI Recipes
CodeCompanion fires events and exposes chat metadata rather than changing your UI itself. These recipes, many from the community, use them to show progress and chat details in Neovim.
Fidget.nvim Progress Updates
By @jessevdp. See discussion #813 for the code.
Fidget.nvim Inline Spinner
By @yuhua99. See this comment on discussion #640 for the code.
Status Column Extmarks
By @lucobellic, for the inline interaction. See discussion #1297 for the code.
Lualine.nvim
To show a spinner in lualine.nvim while a request is running:
local M = require("lualine.component"):extend()
M.processing = false
M.spinner_index = 1
local spinner_symbols = {
"⠋",
"⠙",
"⠹",
"⠸",
"⠼",
"⠴",
"⠦",
"⠧",
"⠇",
"⠏",
}
local spinner_symbols_len = 10
-- Initializer
function M:init(options)
M.super.init(self, options)
local group = vim.api.nvim_create_augroup("CodeCompanionHooks", {})
vim.api.nvim_create_autocmd({ "User" }, {
pattern = "CodeCompanionRequest*",
group = group,
callback = function(request)
if request.match == "CodeCompanionRequestStarted" then
self.processing = true
elseif request.match == "CodeCompanionRequestFinished" then
self.processing = false
end
end,
})
end
-- Function that runs every time statusline is updated
function M:update_status()
if self.processing then
self.spinner_index = (self.spinner_index % spinner_symbols_len) + 1
return spinner_symbols[self.spinner_index]
else
return nil
end
end
return MHeirline.nvim
The first video on this page shows this recipe alongside the Fidget.nvim progress updates. To show an icon in heirline.nvim while a request is running, along with the buffer that #{buffer} shares and the chat's token and cycle counts:
local CodeCompanion = {
static = {
processing = false,
},
update = {
"User",
pattern = "CodeCompanionRequest*",
callback = function(self, args)
if args.match == "CodeCompanionRequestStarted" then
self.processing = true
elseif args.match == "CodeCompanionRequestFinished" then
self.processing = false
end
vim.cmd("redrawstatus")
end,
},
{
condition = function(self)
return self.processing
end,
provider = " ",
hl = { fg = "yellow" },
},
}
local IsCodeCompanion = function()
return package.loaded.codecompanion and vim.bo.filetype == "codecompanion"
end
local CodeCompanionCurrentContext = {
static = {
enabled = true,
},
condition = function(self)
return IsCodeCompanion() and _G.codecompanion_current_context ~= nil and self.enabled
end,
provider = function()
local bufname = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(_G.codecompanion_current_context), ":t")
return "[ " .. bufname .. " ] "
end,
hl = { fg = "gray", bg = "bg" },
update = {
"User",
pattern = { "CodeCompanionRequest*", "CodeCompanionContextChanged" },
callback = vim.schedule_wrap(function(self, args)
if args.match == "CodeCompanionRequestStarted" then
self.enabled = false
elseif args.match == "CodeCompanionRequestFinished" then
self.enabled = true
end
vim.cmd("redrawstatus")
end),
},
}
local CodeCompanionStats = {
condition = function(self)
return IsCodeCompanion()
end,
static = {
chat_values = {},
},
init = function(self)
local bufnr = vim.api.nvim_get_current_buf()
self.chat_values = _G.codecompanion_chat_metadata[bufnr]
end,
-- Tokens block
{
condition = function(self)
return self.chat_values.tokens > 0
end,
RightSlantStart,
{
provider = function(self)
return " " .. self.chat_values.tokens .. " "
end,
hl = { fg = "gray", bg = "statusline_bg" },
update = {
"User",
pattern = { "CodeCompanionChatOpened", "CodeCompanionRequestFinished" },
callback = vim.schedule_wrap(function()
vim.cmd("redrawstatus")
end),
},
},
RightSlantEnd,
},
-- Cycles block
{
condition = function(self)
return self.chat_values.cycles > 0
end,
RightSlantStart,
{
provider = function(self)
return " " .. self.chat_values.cycles .. " "
end,
hl = { fg = "gray", bg = "statusline_bg" },
update = {
"User",
pattern = { "CodeCompanionChatOpened", "CodeCompanionRequestFinished" },
callback = vim.schedule_wrap(function()
vim.cmd("redrawstatus")
end),
},
},
RightSlantEnd,
},
}RightSlantStart and RightSlantEnd are separator components from your own heirline.nvim config.