User Interface
CodeCompanion aims to keep any changes to the user's UI to a minimum. Aesthetics, especially in Neovim, are highly subjective. So whilst it won't set much by default, it does endeavour to allow users to hook into the plugin and customize the UI to their liking via Events.
CodeCompanion exposes a global dictionary, _G.codecompanion_chat_metadata
which users can leverage throughout their configuration. Using the chat buffer's buffer number as the key, the dictionary contains:
adapter
- Thename
andmodel
of the chat buffer's current adaptercontext_items
- The number of context items current in the chat buffercycles
- The number of cycles (User->LLM->User) that have taken place in the chat bufferid
- The ID of the chat buffertokens
- The running total of tokens for the chat buffertools
- The number of tools in the chat buffer
You can also leverage _G.codecompanion_current_context
to fetch the number of the buffer which the #{buffer}
variable points at.
Below are some examples of how you can customize the UI related to CodeCompanion.
Progress updates with Fidget.nvim by @jessevdp
As per the discussion over at #813.
Inline spinner with Fidget.nvim by @yuhua99
As per the comment on #640.
Status column extmarks with the inline assistant by @lucobellic
As per the discussion over at #1297.
Lualine.nvim integration
The plugin can be integrated with lualine.nvim to show an icon in the statusline when a request is being sent to an LLM:
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 M
Heirline.nvim integration
The plugin can also be integrated into heirline.nvim to show an icon when a request is being sent to an LLM and also to show useful meta information about the chat buffer.
In the video at the top of this page, you can see the fidget spinner alongside the heirline.nvim integration below:
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,
},
}