repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
neovim/lua/bugabinga/pivi/detail.lua
Rawlocal entry = require 'bugabinga.pivi.entry'
local transcript = require 'bugabinga.pivi.transcript'
local navigate = require 'bugabinga.pivi.navigate'
local MAX_RESULT_LINES = 60
local TITLES = {
prompt = 'submission',
answer = 'answer',
tool = 'tool call',
error = 'error',
}
--- One readable value.
--- A JSON fence would be concealed by the markdown rendering of the float, so
--- arguments are listed rather than encoded.
local readable = function( value )
if type( value ) == 'string' then return value end
if type( value ) ~= 'table' then return tostring( value ) end
return ( vim.inspect( value, { newline = ' ', indent = '', } ) )
end
local result_text = function( result )
if type( result ) ~= 'table' then return nil end
local pieces = {}
for _, block in ipairs( result.content or {} ) do
if block.type == 'text' and type( block.text ) == 'string' then
table.insert( pieces, block.text )
end
end
local joined = vim.trim( table.concat( pieces, '\n' ) )
if joined == '' then return nil end
return joined
end
--- Everything known about one entry, as readable text.
local describe = function( bufnr, item )
if not item then return {} end
local meta = item.meta or {}
local lines = { '# ' .. ( TITLES[item.kind] or item.kind ), '', }
if meta.tool then table.insert( lines, '- tool: `' .. tostring( meta.tool ) .. '`' ) end
if meta.failed ~= nil then
table.insert( lines, '- outcome: ' .. ( meta.failed and 'failed' or 'succeeded' ) )
end
local location = navigate.location_of( item )
if location then
local place = location.path
if location.line then place = place .. ':' .. tostring( location.line ) end
table.insert( lines, '- location: `' .. place .. '`' )
end
table.insert( lines, '- lines: ' .. tostring( item.first ) .. '-' .. tostring( item.last ) )
if type( meta.args ) == 'table' and next( meta.args ) ~= nil then
table.insert( lines, '' )
table.insert( lines, '## arguments' )
table.insert( lines, '' )
local names = vim.tbl_keys( meta.args )
table.sort( names, function( left, right ) return tostring( left ) < tostring( right ) end )
for _, name in ipairs( names ) do
table.insert( lines, '- ' .. tostring( name ) .. ': ' .. readable( meta.args[name] ) )
end
end
if meta.error then
vim.list_extend( lines, { '', '## error', '', tostring( meta.error ), } )
end
local produced = result_text( meta.result )
if produced then
local shown = vim.split( produced, '\n', { plain = true, } )
local truncated = #shown > MAX_RESULT_LINES
if truncated then shown = vim.list_slice( shown, 1, MAX_RESULT_LINES ) end
vim.list_extend( lines, { '', '## result', '', } )
vim.list_extend( lines, shown )
if truncated then
table.insert( lines, '' )
table.insert( lines, '_the entry itself holds the rest_' )
end
end
if item.kind ~= 'tool' and not meta.error then
local content = vim.api.nvim_buf_get_lines( bufnr, item.first - 1, item.last, false )
vim.list_extend( lines, { '', '## text', '', } )
vim.list_extend( lines, content )
end
return lines
end
--- Inspects the entry under the cursor without leaving the transcript.
--- @return number? bufnr the floating buffer
--- @return number? winid the floating window
local inspect = function( bufnr, line_number )
local item = entry.at( bufnr, line_number or vim.api.nvim_win_get_cursor( 0 )[1] )
if not item then return nil end
local lines = describe( bufnr, item )
if #lines == 0 then return nil end
-- A nameless buffer makes a statusline fall back to the working directory,
-- so even a transient float says what it is.
local ok, float, window = pcall( vim.lsp.util.open_floating_preview, lines, 'markdown', {
border = 'rounded',
focus = false,
focusable = true,
max_width = 100,
max_height = 30,
} )
if not ok then return nil end
if float and vim.api.nvim_buf_is_valid( float ) then
pcall( vim.api.nvim_buf_set_name, float, 'pivi://' .. ( item.meta.tool or item.kind ) .. '/detail' )
end
return float, window
end
local bind = function( bufnr )
vim.keymap.set( 'n', '<Plug>(pivi-inspect-entry)', function() inspect( bufnr ) end,
{ buffer = bufnr, desc = 'pivi inspect the entry', } )
end
transcript.on_buffer( bind )
return {
describe = describe,
inspect = inspect,
bind = bind,
}