---@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 )