---@diagnostic disable: duplicate-set-field, need-check-nil, param-type-mismatch, assign-type-mismatch
local context = require 'bugabinga.pivi.context'
local scratch = function( lines )
vim.cmd 'enew'
local bufnr = vim.api.nvim_get_current_buf()
vim.api.nvim_buf_set_name( bufnr, vim.fn.tempname() .. '.lua' )
vim.api.nvim_buf_set_lines( bufnr, 0, -1, false, lines )
return bufnr
end
describe( 'pivi context', function()
after_each( function()
vim.cmd 'silent! %bwipeout!'
end )
it( 'captures buffer identity, revision, and cursor', function()
local bufnr = scratch { 'one', 'two', 'three', }
vim.api.nvim_win_set_cursor( 0, { 2, 1, } )
local shot = context.snapshot()
assert.equal( bufnr, shot.buffer )
assert.equal( vim.api.nvim_buf_get_changedtick( bufnr ), shot.revision )
assert.equal( 2, shot.cursor[1] )
assert.equal( 1, shot.cursor[2] )
assert.equal( 3, shot.line_count )
end )
it( 'captures unsaved content', function()
local bufnr = scratch { 'unsaved line', }
local shot = context.snapshot()
assert.is_true( shot.modified )
assert.is_true( shot.surrounding:find( 'unsaved line', 1, true ) ~= nil )
end )
it( 'refuses mutation of a snapshot', function()
scratch { 'a', }
local shot = context.snapshot()
assert.has_error( function() shot.path = 'elsewhere' end )
assert.has_error( function() shot.cursor[1] = 99 end )
end )
it( 'keeps its own values when the buffer changes later', function()
local bufnr = scratch { 'before', }
local shot = context.snapshot()
local revision = shot.revision
vim.api.nvim_buf_set_lines( bufnr, 0, -1, false, { 'after', 'more', } )
assert.equal( revision, shot.revision )
assert.equal( 1, shot.line_count )
assert.is_true( shot.surrounding:find( 'before', 1, true ) ~= nil )
assert.is_nil( shot.surrounding:find( 'after', 1, true ) )
end )
it( 'captures a selected range and its text', function()
scratch { 'one', 'two', 'three', }
local shot = context.snapshot { range = { kind = 'V', first = { 1, 0, }, last = { 2, 0, }, }, }
assert.equal( 'V', shot.selection_kind )
assert.equal( 'one\ntwo', shot.selected_text )
end )
it( 'renders a stable prompt preamble', function()
scratch { 'one', 'two', }
local rendered = context.render( context.snapshot() )
assert.is_true( rendered:find( '', 1, true ) == 1 )
assert.is_true( rendered:find( 'revision:', 1, true ) ~= nil )
assert.is_true( rendered:find( '', 1, true ) ~= nil )
end )
it( 'renders nothing without a snapshot', function()
assert.equal( '', context.render( nil ) )
end )
it( 'skips buffers that are not editable files', function()
local bufnr = vim.api.nvim_create_buf( false, true )
vim.bo[bufnr].buftype = 'nofile'
assert.is_nil( context.snapshot { bufnr = bufnr, } )
end )
describe( 'visible view', function()
it( 'captures only the region the user can see', function()
local many = {}
for index = 1, 500 do many[index] = 'line ' .. index end
scratch( many )
vim.api.nvim_win_set_cursor( 0, { 250, 0, } )
vim.cmd 'normal! zz'
local view = context.visible()
assert.is_true( view.first_line >= 1 )
assert.is_true( view.last_line <= 500 )
assert.equal( 500, view.line_count )
assert.equal( view.last_line - view.first_line + 1, #view.lines )
assert.is_true( #view.lines < 500 )
assert.is_true( #view.lines <= context.visible_lines )
end )
it( 'describes the current buffer, cursor, and mode', function()
local bufnr = scratch { 'alpha', 'beta', }
vim.api.nvim_win_set_cursor( 0, { 2, 1, } )
local view = context.visible()
assert.equal( bufnr, view.buffer )
assert.equal( 2, view.cursor[1] )
assert.is_true( view.modified )
assert.is_string( view.mode )
assert.is_string( view.cwd )
end )
it( 'lists the windows of the current tabpage', function()
scratch { 'one', }
vim.cmd 'vsplit'
local view = context.visible()
vim.cmd 'only'
assert.is_true( #view.windows >= 2 )
local current = 0
for _, entry in ipairs( view.windows ) do
if entry.current then current = current + 1 end
end
assert.equal( 1, current )
end )
it( 'renders a bounded numbered preamble', function()
scratch { 'alpha', 'beta', }
local rendered = context.render_visible( context.visible() )
assert.is_true( rendered:find( '', 1, true ) == 1 )
assert.is_true( rendered:find( 'on screen (lines', 1, true ) ~= nil )
assert.is_true( rendered:find( '1\talpha', 1, true ) ~= nil )
assert.is_true( rendered:find( '', 1, true ) ~= nil )
end )
it( 'renders nothing without a view', function()
assert.equal( '', context.render_visible( nil ) )
end )
it( 'carries recent messages and the last error', function()
vim.v.errmsg = 'E42: something broke'
vim.api.nvim_echo( { { 'a distinctive notice', }, }, true, {} )
scratch { 'x', }
local rendered = context.render_visible( context.visible() )
assert.is_true( rendered:find( 'E42: something broke', 1, true ) ~= nil )
assert.is_true( rendered:find( 'a distinctive notice', 1, true ) ~= nil )
vim.v.errmsg = ''
end )
end )
it( 'reports ambient editor state on demand', function()
local bufnr = scratch { 'ambient', }
local state = context.editor()
assert.equal( bufnr, state.current_buffer )
assert.is_string( state.mode )
assert.is_true( #state.buffers > 0 )
assert.is_true( #state.windows > 0 )
local found = false
for _, entry in ipairs( state.buffers ) do
if entry.buffer == bufnr then
found = true
assert.is_true( entry.modified )
end
end
assert.is_true( found )
end )
end )