The User Interface
Below are some examples of how you can extend CodeCompanion and modify the user interface to suit your needs.
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:
lua
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 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:
lua
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,
},
}