---@diagnostic disable: duplicate-set-field, need-check-nil, param-type-mismatch, assign-type-mismatch local activity = require 'bugabinga.pivi.activity' 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 activity', function() after_each( function() vim.cmd 'silent! %bwipeout!' activity.clear_trail() vim.fn.setqflist( {}, 'r' ) end ) it( 'marks changed lines in its own namespace', function() local bufnr = scratch { 'one', 'two', 'three', } activity.mark_edit( bufnr, { { first = 0, last = 2, }, } ) assert.equal( 2, #activity.marks( bufnr ) ) assert.same( { { buffer = bufnr, first = 1, last = 2, }, }, activity.trail() ) end ) it( 'leaves foreign extmark namespaces untouched', function() local bufnr = scratch { 'one', 'two', } local foreign = vim.api.nvim_create_namespace 'some-language-server' vim.api.nvim_buf_set_extmark( bufnr, foreign, 0, 0, {} ) activity.mark_edit( bufnr, { { first = 0, last = 1, }, } ) activity.clear_trail( bufnr ) assert.equal( 1, #vim.api.nvim_buf_get_extmarks( bufnr, foreign, 0, -1, {} ) ) assert.equal( 0, #activity.marks( bufnr ) ) end ) it( 'keeps the trail across further agent edits', function() local bufnr = scratch { 'one', 'two', 'three', } activity.mark_edit( bufnr, { { first = 0, last = 1, }, } ) activity.mark_edit( bufnr, { { first = 2, last = 3, }, } ) vim.api.nvim_exec_autocmds( 'TextChanged', { buffer = bufnr, } ) assert.equal( 2, #activity.marks( bufnr ) ) end ) it( 'clears the trail once the user changes the buffer', function() local bufnr = scratch { 'one', 'two', } activity.mark_edit( bufnr, { { first = 0, last = 1, }, } ) assert.equal( 1, #activity.marks( bufnr ) ) vim.api.nvim_buf_set_lines( bufnr, 0, 1, false, { 'edited by hand', } ) vim.api.nvim_exec_autocmds( 'TextChanged', { buffer = bufnr, } ) assert.equal( 0, #activity.marks( bufnr ) ) assert.same( {}, activity.trail() ) end ) it( 'renders ghost text without mutating the buffer', function() local bufnr = scratch { 'one', 'two', } local revision = vim.api.nvim_buf_get_changedtick( bufnr ) local before = vim.api.nvim_buf_get_lines( bufnr, 0, -1, false ) activity.ghost( bufnr, 0, 'proposed\nchange' ) assert.equal( 1, #activity.ghost_marks( bufnr ) ) assert.equal( revision, vim.api.nvim_buf_get_changedtick( bufnr ) ) assert.same( before, vim.api.nvim_buf_get_lines( bufnr, 0, -1, false ) ) end ) it( 'replaces earlier ghost text and clears on demand', function() local bufnr = scratch { 'one', } activity.ghost( bufnr, 0, 'first' ) activity.ghost( bufnr, 0, 'second' ) assert.equal( 1, #activity.ghost_marks( bufnr ) ) activity.ghost_clear( bufnr ) assert.equal( 0, #activity.ghost_marks( bufnr ) ) end ) it( 'ignores empty ghost text', function() local bufnr = scratch { 'one', } activity.ghost( bufnr, 0, '' ) assert.equal( 0, #activity.ghost_marks( bufnr ) ) end ) it( 'publishes cross file findings to the quickfix list', function() local entries = activity.findings( { { path = 'a.lua', line = 3, column = 2, text = 'first', severity = 'error', }, { path = 'b.lua', line = 1, text = 'second', }, }, 'review' ) assert.equal( 2, #entries ) local list = vim.fn.getqflist() assert.equal( 2, #list ) assert.equal( 3, list[1].lnum ) assert.equal( 'first', list[1].text ) assert.equal( 'review', vim.fn.getqflist( { title = 0, } ).title ) end ) it( 'publishes window findings to the location list', function() activity.window_findings( 0, { { path = 'a.lua', line = 2, text = 'local', }, }, 'local review' ) local list = vim.fn.getloclist( 0 ) assert.equal( 1, #list ) assert.equal( 2, list[1].lnum ) end ) it( 'keeps agent diagnostics distinguishable from other producers', function() local bufnr = scratch { 'one', 'two', } local foreign = vim.api.nvim_create_namespace 'pretend-language-server' vim.diagnostic.set( foreign, bufnr, { { lnum = 0, col = 0, message = 'from the language server', severity = vim.diagnostic.severity.ERROR, }, } ) activity.diagnose( bufnr, { { line = 2, text = 'from the agent', severity = 'warning', }, } ) local mine = activity.diagnostics( bufnr ) assert.equal( 1, #mine ) assert.equal( 'from the agent', mine[1].message ) assert.equal( 'pi', mine[1].source ) assert.equal( 1, mine[1].lnum ) assert.equal( 2, #vim.diagnostic.get( bufnr ) ) activity.clear_diagnostics( bufnr ) assert.equal( 0, #activity.diagnostics( bufnr ) ) assert.equal( 1, #vim.diagnostic.get( bufnr ) ) end ) it( 'ignores invalid buffers', function() local bufnr = vim.api.nvim_create_buf( false, true ) vim.api.nvim_buf_delete( bufnr, { force = true, } ) activity.mark_edit( bufnr, { { first = 0, last = 1, }, } ) activity.ghost( bufnr, 0, 'text' ) activity.diagnose( bufnr, { { line = 1, text = 'x', }, } ) assert.same( {}, activity.marks( bufnr ) ) end ) end )