repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
neovim/lua/bugabinga/pivi_status.lua
Raw--- Statusline consumer for pivi.
--- It reads the published cache only and never requires pivi, so the
--- statusline keeps working when pivi is absent, unloaded, or broken.
local statusline = require 'bugabinga.statusline'
local auto = require 'std.auto'
local glyph = require 'std.icon'
-- The progress frames the rest of the configuration already animates with.
local SPINNER = {
glyph.progress_0, glyph.progress_1, glyph.progress_2, glyph.progress_3, glyph.progress_4,
glyph.progress_5, glyph.progress_6, glyph.progress_7, glyph.progress_8, glyph.progress_9,
}
local INTERVAL = 90
local state = {
frame = 1,
timer = nil,
}
local sessions = function()
local value = vim.g.pivi
if type( value ) ~= 'table' then return nil, {} end
return value.active, value.sessions or {}
end
local busy = function( entry )
return entry ~= nil
and entry.connection ~= 'stopped'
and ( entry.run == 'running' or entry.run == 'retrying' or entry.compacting == true )
end
local pending = function( entry )
if not entry or type( entry.queue ) ~= 'table' then return 0 end
return #( entry.queue.steering or {} ) + #( entry.queue.follow_up or {} )
end
local label = function( entry )
if entry.error then
return '%#ErrorMsg#' .. glyph.error .. ' ' .. ( entry.tool and entry.tool.name or 'error' ) .. '%*'
end
if entry.compacting then return '%#WarningMsg#π ' .. glyph.lazy .. ' compacting%*' end
if entry.run == 'retrying' then return '%#WarningMsg#π ' .. glyph.warn .. ' retry%*' end
if entry.tool then return '%#DiffChange#π ' .. tostring( entry.tool.name ) .. '%*' end
if entry.run == 'running' then return '%#DiffChange#π ' .. glyph.star .. ' thinking%*' end
return 'π'
end
local stop_spinner = function()
if not state.timer then return end
state.timer:stop()
state.timer:close()
state.timer = nil
end
local start_spinner = function()
if state.timer then return end
state.timer = vim.uv.new_timer()
state.timer:start( INTERVAL, INTERVAL, vim.schedule_wrap( function()
state.frame = state.frame % #SPINNER + 1
vim.cmd.redrawstatus()
end ) )
end
--- Cached only: evaluating the statusline never talks to Pi.
local component = function()
local active, all = sessions()
if not active then return '' end
local entry = all[active]
if not entry then return '' end
local pieces = { label( entry ), }
if busy( entry ) then table.insert( pieces, 1, SPINNER[state.frame] ) end
local waiting = pending( entry )
if waiting > 0 then table.insert( pieces, '+' .. tostring( waiting ) ) end
return table.concat( pieces, ' ' )
end
statusline.register( component )
auto 'pivi_statusline' {
events = 'User',
pattern = 'PiviStatus',
description = 'Animate the pivi statusline while a run is active.',
command = function()
local active, all = sessions()
local entry = active and all[active] or nil
if busy( entry ) then
start_spinner()
else
stop_spinner()
end
vim.cmd.redrawstatus()
end,
}
auto 'pivi_activity' {
events = 'User',
pattern = 'PiviActivity',
description = 'Announce agent findings that landed in a native list.',
command = function( event )
local data = event.data
if type( data ) ~= 'table' or data.kind ~= 'findings' then return end
local count = tonumber( data.count ) or 0
if count == 0 then return end
vim.notify(
( 'π %d finding%s in the quickfix list' ):format( count, count == 1 and '' or 's' ),
vim.log.levels.INFO
)
end,
}
_G.BugabingaPiviStatus = {
component = component,
busy = busy,
pending = pending,
label = label,
}
return _G.BugabingaPiviStatus