---@diagnostic disable: duplicate-set-field, need-check-nil, param-type-mismatch, assign-type-mismatch, redundant-parameter require 'bugabinga.pivi.fold' require 'bugabinga.pivi.navigate' require 'bugabinga.pivi.detail' require 'bugabinga.pivi.diff' require 'bugabinga.pivi.guide' local command = require 'bugabinga.pivi.command' local session = require 'bugabinga.pivi.session' local transcript = require 'bugabinga.pivi.transcript' local fake = dofile 'tests/helpers/pivi_fake.lua' local MODES = { 'n', 'i', 'x', } --- Keys pivi binds itself, rather than publishing for the configuration. --- These are the exceptions where the behaviour *is* the key, mirroring pi: --- `/` only takes over at the first character, and `@` only when it starts a --- word, so both remain typable everywhere else. local ALLOWED = { ['/'] = true, ['@'] = true, } local claimed = function( bufnr ) local found = {} for _, mode in ipairs( MODES ) do for _, mapping in ipairs( vim.api.nvim_buf_get_keymap( bufnr, mode ) ) do if not mapping.lhs:find( '', 1, true ) and not ALLOWED[mapping.lhs] then table.insert( found, mode .. ' ' .. mapping.lhs ) end end end return found end describe( 'pivi keys', function() after_each( function() session.stop_all() transcript.forget_all() fake.close_extra_windows() vim.cmd 'silent! %bwipeout!' end ) it( 'claims no key of its own in a transcript', function() local bufnr = transcript.ensure 'unclaimed' assert.same( {}, claimed( bufnr ) ) end ) it( 'claims no key of its own in a prompt, beyond naming a command or a file', function() local channel = fake.new() local current = session.create { spawn = channel.spawn, name = 'spec', extension = false, skill = false, executable = 'pi', env = {}, } local bufnr = command.open_prompt( current ) vim.cmd.stopinsert() assert.same( {}, claimed( bufnr ) ) end ) it( 'still types a literal @ inside a word', function() -- Naming a file opens a picker, which this test is not exercising. local original = vim.ui.select vim.ui.select = function( _, _, on_choice ) on_choice( nil ) end local channel = fake.new() local current = session.create { spawn = channel.spawn, name = 'typing', extension = false, skill = false, executable = 'pi', env = {}, } local bufnr = command.open_prompt( current ) vim.cmd.stopinsert() local at for _, mapping in ipairs( vim.api.nvim_buf_get_keymap( bufnr, 'i' ) ) do if mapping.lhs == '@' then at = mapping end end assert.is_table( at ) local win = vim.fn.bufwinid( bufnr ) assert.is_true( win > 0 ) vim.api.nvim_set_current_win( win ) -- Normal mode cannot place the cursor past the last character, so both -- positions below sit inside the line. -- Inside a word it is just a character. vim.api.nvim_buf_set_lines( bufnr, 0, -1, false, { 'mail me', } ) vim.api.nvim_win_set_cursor( win, { 1, 4, } ) assert.equal( '@', at.callback() ) -- Starting a word it names a file. vim.api.nvim_buf_set_lines( bufnr, 0, -1, false, { 'look at x', } ) vim.api.nvim_win_set_cursor( win, { 1, 8, } ) assert.equal( '', at.callback() ) vim.wait( 50, function() return false end ) vim.ui.select = original end ) it( 'publishes every behavior a key could want', function() local bufnr = transcript.ensure 'published' local published = {} for _, mode in ipairs( MODES ) do for _, mapping in ipairs( vim.api.nvim_buf_get_keymap( bufnr, mode ) ) do published[mapping.lhs] = true end end for _, intent in ipairs { '(pivi-toggle-entry)', '(pivi-next-entry)', '(pivi-previous-entry)', '(pivi-next-tool)', '(pivi-previous-tool)', '(pivi-goto-location)', '(pivi-inspect-entry)', '(pivi-compare-change)', '(pivi-guide)', } do assert.is_true( published[intent], intent .. ' is not published' ) end end ) it( 'never claims a global key', function() -- pivi describes its own mappings as `pivi ...`; the configuration -- describes its choices as `pi: ...`, and those are allowed to be global. for _, mode in ipairs( MODES ) do for _, mapping in ipairs( vim.api.nvim_get_keymap( mode ) ) do if not mapping.lhs:find( '', 1, true ) then assert.is_nil( ( mapping.desc or '' ):match '^pivi ', mapping.lhs .. ' was claimed globally by pivi' ) end end end end ) it( 'yields to a completion popup before accepting a prompt', function() local channel = fake.new() local current = session.create { spawn = channel.spawn, name = 'accepting', extension = false, skill = false, executable = 'pi', env = {}, } local bufnr = command.open_prompt( current ) vim.cmd.stopinsert() local accept for _, mapping in ipairs( vim.api.nvim_buf_get_keymap( bufnr, 'i' ) ) do if mapping.lhs == '(pivi-accept)' then accept = mapping end end assert.is_table( accept ) assert.equal( 1, accept.expr ) -- With no popup open the prompt is what gets accepted. vim.api.nvim_buf_set_lines( bufnr, 0, -1, false, { 'a question', } ) assert.equal( '', accept.callback() ) end ) end )