diff options
Diffstat (limited to 'test/functional/api')
| -rw-r--r-- | test/functional/api/buffer_spec.lua | 91 | ||||
| -rw-r--r-- | test/functional/api/keymap_spec.lua | 508 | ||||
| -rw-r--r-- | test/functional/api/rpc_fixture.lua | 6 | ||||
| -rw-r--r-- | test/functional/api/server_requests_spec.lua | 5 | ||||
| -rw-r--r-- | test/functional/api/vim_spec.lua | 34 |
5 files changed, 606 insertions, 38 deletions
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 93599c04f1..9d6cfb99ab 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -24,8 +24,8 @@ describe('api/buf', function() end - describe('line_count, insert and del_line', function() - it('works', function() + describe('nvim_buf_set_lines, nvim_buf_line_count', function() + it('deprecated forms', function() eq(1, curbuf_depr('line_count')) curbuf_depr('insert', -1, {'line'}) eq(2, curbuf_depr('line_count')) @@ -39,6 +39,41 @@ describe('api/buf', function() eq(1, curbuf_depr('line_count')) end) + it('cursor position is maintained after lines are inserted #9961', function() + -- replace the buffer contents with these three lines. + request('nvim_buf_set_lines', 0, 0, -1, 1, {"line1", "line2", "line3", "line4"}) + -- Set the current cursor to {3, 2}. + curwin('set_cursor', {3, 2}) + + -- add 2 lines and delete 1 line above the current cursor position. + request('nvim_buf_set_lines', 0, 1, 2, 1, {"line5", "line6"}) + -- check the current set of lines in the buffer. + eq({"line1", "line5", "line6", "line3", "line4"}, buffer('get_lines', 0, 0, -1, 1)) + -- cursor should be moved below by 1 line. + eq({4, 2}, curwin('get_cursor')) + + -- add a line after the current cursor position. + request('nvim_buf_set_lines', 0, 5, 5, 1, {"line7"}) + -- check the current set of lines in the buffer. + eq({"line1", "line5", "line6", "line3", "line4", "line7"}, buffer('get_lines', 0, 0, -1, 1)) + -- cursor position is unchanged. + eq({4, 2}, curwin('get_cursor')) + + -- overwrite current cursor line. + request('nvim_buf_set_lines', 0, 3, 5, 1, {"line8", "line9"}) + -- check the current set of lines in the buffer. + eq({"line1", "line5", "line6", "line8", "line9", "line7"}, buffer('get_lines', 0, 0, -1, 1)) + -- cursor position is unchanged. + eq({4, 2}, curwin('get_cursor')) + + -- delete current cursor line. + request('nvim_buf_set_lines', 0, 3, 5, 1, {}) + -- check the current set of lines in the buffer. + eq({"line1", "line5", "line6", "line7"}, buffer('get_lines', 0, 0, -1, 1)) + -- cursor position is unchanged. + eq({4, 2}, curwin('get_cursor')) + end) + it('line_count has defined behaviour for unloaded buffers', function() -- we'll need to know our bufnr for when it gets unloaded local bufnr = curbuf('get_number') @@ -70,7 +105,7 @@ describe('api/buf', function() end) end) - describe('{get,set,del}_line', function() + describe('deprecated: {get,set,del}_line', function() it('works', function() eq('', curbuf_depr('get_line', 0)) curbuf_depr('set_line', 0, 'line1') @@ -102,7 +137,7 @@ describe('api/buf', function() end) end) - describe('{get,set}_line_slice', function() + describe('deprecated: {get,set}_line_slice', function() it('get_line_slice: out-of-bounds returns empty array', function() curbuf_depr('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'}) eq({'a', 'b', 'c'}, curbuf_depr('get_line_slice', 0, 2, true, true)) --sanity @@ -149,7 +184,7 @@ describe('api/buf', function() end) end) - describe('{get,set}_lines', function() + describe('nvim_buf_get_lines, nvim_buf_set_lines', function() local get_lines, set_lines = curbufmeths.get_lines, curbufmeths.set_lines local line_count = curbufmeths.line_count @@ -272,7 +307,7 @@ describe('api/buf', function() eq({}, get_lines(-3, -4, true)) end) - it('set_line_slice: out-of-bounds can extend past end', function() + it('set_lines: out-of-bounds can extend past end', function() set_lines(0, -1, true, {'a', 'b', 'c'}) eq({'a', 'b', 'c'}, get_lines(0, -1, true)) --sanity @@ -286,7 +321,7 @@ describe('api/buf', function() eq({'e', 'a', 'b', 'c', 'd'}, get_lines(0, -1, true)) end) - it("set_line on alternate buffer does not access invalid line (E315)", function() + it("set_lines on alternate buffer does not access invalid line (E315)", function() feed_command('set hidden') insert('Initial file') command('enew') @@ -334,9 +369,27 @@ describe('api/buf', function() {2:-- INSERT --} | ]]) end) + + it('set_lines on hidden buffer preserves "previous window" #9741', function() + insert([[ + visible buffer line 1 + line 2 + ]]) + local hiddenbuf = meths.create_buf(false,true) + command('vsplit') + command('vsplit') + feed('<c-w>l<c-w>l<c-w>l') + eq(3, funcs.winnr()) + feed('<c-w>h') + eq(2, funcs.winnr()) + meths.buf_set_lines(hiddenbuf, 0, -1, true, + {'hidden buffer line 1', 'line 2'}) + feed('<c-w>p') + eq(3, funcs.winnr()) + end) end) - describe('get_offset', function() + describe('nvim_buf_get_offset', function() local get_offset = curbufmeths.get_offset it('works', function() curbufmeths.set_lines(0,-1,true,{'Some\r','exa\000mple', '', 'buf\rfer', 'text'}) @@ -373,7 +426,7 @@ describe('api/buf', function() end) end) - describe('{get,set,del}_var', function() + describe('nvim_buf_get_var, nvim_buf_set_var, nvim_buf_del_var', function() it('works', function() curbuf('set_var', 'lua', {1, 2, {['3'] = 1}}) eq({1, 2, {['3'] = 1}}, curbuf('get_var', 'lua')) @@ -393,7 +446,7 @@ describe('api/buf', function() end) end) - describe('get_changedtick', function() + describe('nvim_buf_get_changedtick', function() it('works', function() eq(2, curbufmeths.get_changedtick()) curbufmeths.set_lines(0, 1, false, {'abc\0', '\0def', 'ghi'}) @@ -417,7 +470,7 @@ describe('api/buf', function() end) end) - describe('{get,set}_option', function() + describe('nvim_buf_get_option, nvim_buf_set_option', function() it('works', function() eq(8, curbuf('get_option', 'shiftwidth')) curbuf('set_option', 'shiftwidth', 4) @@ -430,7 +483,7 @@ describe('api/buf', function() end) end) - describe('{get,set}_name', function() + describe('nvim_buf_get_name, nvim_buf_set_name', function() it('works', function() nvim('command', 'new') eq('', curbuf('get_name')) @@ -438,14 +491,12 @@ describe('api/buf', function() curbuf('set_name', new_name) eq(new_name, curbuf('get_name')) nvim('command', 'w!') - local f = io.open(new_name) - ok(f ~= nil) - f:close() + eq(1, funcs.filereadable(new_name)) os.remove(new_name) end) end) - describe('is_loaded', function() + describe('nvim_buf_is_loaded', function() it('works', function() -- record our buffer number for when we unload it local bufnr = curbuf('get_number') @@ -470,7 +521,7 @@ describe('api/buf', function() end) end) - describe('is_valid', function() + describe('nvim_buf_is_valid', function() it('works', function() nvim('command', 'new') local b = nvim('get_current_buf') @@ -480,12 +531,12 @@ describe('api/buf', function() end) end) - describe('get_mark', function() + describe('nvim_buf_get_mark', function() it('works', function() curbuf('set_lines', -1, -1, true, {'a', 'bit of', 'text'}) curwin('set_cursor', {3, 4}) - nvim('command', 'mark V') - eq({3, 0}, curbuf('get_mark', 'V')) + nvim('command', 'mark v') + eq({3, 0}, curbuf('get_mark', 'v')) end) end) end) diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index f52372bee3..b3f6bb7895 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -1,15 +1,18 @@ local helpers = require('test.functional.helpers')(after_each) -local global_helpers = require('test.helpers') +local bufmeths = helpers.bufmeths local clear = helpers.clear local command = helpers.command local curbufmeths = helpers.curbufmeths -local eq = helpers.eq +local eq, neq = helpers.eq, helpers.neq +local expect_err = helpers.expect_err +local feed = helpers.feed local funcs = helpers.funcs local meths = helpers.meths local source = helpers.source -local shallowcopy = global_helpers.shallowcopy +local shallowcopy = helpers.shallowcopy +local sleep = helpers.sleep describe('nvim_get_keymap', function() before_each(clear) @@ -308,3 +311,502 @@ describe('nvim_get_keymap', function() eq({space_table}, meths.get_keymap('n')) end) end) + +describe('nvim_set_keymap, nvim_del_keymap', function() + before_each(clear) + + -- `generate_expected` is truthy: for generating an expected output for + -- maparg(), which does not accept "!" (though it returns "!" in its output + -- if getting a mapping set with |:map!|). + local function normalize_mapmode(mode, generate_expected) + if not generate_expected and mode == '!' then + -- Cannot retrieve mapmode-ic mappings with "!", but can with "i" or "c". + mode = 'i' + elseif mode == '' then + mode = generate_expected and ' ' or mode + end + return mode + end + + -- Generate a mapargs dict, for comparison against the mapping that was + -- actually set + local function generate_mapargs(mode, lhs, rhs, opts) + if not opts then + opts = {} + end + + local to_return = {} + to_return.mode = normalize_mapmode(mode, true) + to_return.noremap = not opts.noremap and 0 or 1 + to_return.lhs = lhs + to_return.rhs = rhs + to_return.silent = not opts.silent and 0 or 1 + to_return.nowait = not opts.nowait and 0 or 1 + to_return.expr = not opts.expr and 0 or 1 + to_return.sid = not opts.sid and 0 or opts.sid + to_return.buffer = not opts.buffer and 0 or opts.buffer + + -- mode 't' doesn't print when calling maparg + if mode == 't' then + to_return.mode = '' + end + + return to_return + end + + -- Gets a maparg() dict from Nvim, if one exists. + local function get_mapargs(mode, lhs) + return funcs.maparg(lhs, normalize_mapmode(mode), false, true) + end + + it('error on empty LHS', function() + -- escape parentheses in lua string, else comparison fails erroneously + expect_err('Invalid %(empty%) LHS', + meths.set_keymap, '', '', 'rhs', {}) + expect_err('Invalid %(empty%) LHS', + meths.set_keymap, '', '', '', {}) + + expect_err('Invalid %(empty%) LHS', meths.del_keymap, '', '') + end) + + it('error if LHS longer than MAXMAPLEN', function() + -- assume MAXMAPLEN of 50 chars, as declared in vim.h + local MAXMAPLEN = 50 + local lhs = '' + for i=1,MAXMAPLEN do + lhs = lhs..(i % 10) + end + + -- exactly 50 chars should be fine + meths.set_keymap('', lhs, 'rhs', {}) + + -- del_keymap should unmap successfully + meths.del_keymap('', lhs) + eq({}, get_mapargs('', lhs)) + + -- 51 chars should produce an error + lhs = lhs..'1' + expect_err('LHS exceeds maximum map length: '..lhs, + meths.set_keymap, '', lhs, 'rhs', {}) + expect_err('LHS exceeds maximum map length: '..lhs, + meths.del_keymap, '', lhs) + end) + + it('does not throw errors when rhs is longer than MAXMAPLEN', function() + local MAXMAPLEN = 50 + local rhs = '' + for i=1,MAXMAPLEN do + rhs = rhs..(i % 10) + end + rhs = rhs..'1' + meths.set_keymap('', 'lhs', rhs, {}) + eq(generate_mapargs('', 'lhs', rhs), + get_mapargs('', 'lhs')) + end) + + it('throws errors when given too-long mode shortnames', function() + expect_err('Shortname is too long: map', + meths.set_keymap, 'map', 'lhs', 'rhs', {}) + + expect_err('Shortname is too long: vmap', + meths.set_keymap, 'vmap', 'lhs', 'rhs', {}) + + expect_err('Shortname is too long: xnoremap', + meths.set_keymap, 'xnoremap', 'lhs', 'rhs', {}) + + expect_err('Shortname is too long: map', meths.del_keymap, 'map', 'lhs') + expect_err('Shortname is too long: vmap', meths.del_keymap, 'vmap', 'lhs') + expect_err('Shortname is too long: xnoremap', meths.del_keymap, 'xnoremap', 'lhs') + end) + + it('error on invalid mode shortname', function() + expect_err('Invalid mode shortname: " "', + meths.set_keymap, ' ', 'lhs', 'rhs', {}) + expect_err('Invalid mode shortname: "m"', + meths.set_keymap, 'm', 'lhs', 'rhs', {}) + expect_err('Invalid mode shortname: "?"', + meths.set_keymap, '?', 'lhs', 'rhs', {}) + expect_err('Invalid mode shortname: "y"', + meths.set_keymap, 'y', 'lhs', 'rhs', {}) + expect_err('Invalid mode shortname: "p"', + meths.set_keymap, 'p', 'lhs', 'rhs', {}) + expect_err('Invalid mode shortname: "?"', meths.del_keymap, '?', 'lhs') + expect_err('Invalid mode shortname: "y"', meths.del_keymap, 'y', 'lhs') + expect_err('Invalid mode shortname: "p"', meths.del_keymap, 'p', 'lhs') + end) + + it('error on invalid optnames', function() + expect_err('Invalid key: silentt', + meths.set_keymap, 'n', 'lhs', 'rhs', {silentt = true}) + expect_err('Invalid key: sidd', + meths.set_keymap, 'n', 'lhs', 'rhs', {sidd = false}) + expect_err('Invalid key: nowaiT', + meths.set_keymap, 'n', 'lhs', 'rhs', {nowaiT = false}) + end) + + it('error on <buffer> option key', function() + expect_err('Invalid key: buffer', + meths.set_keymap, 'n', 'lhs', 'rhs', {buffer = true}) + end) + + local optnames = {'nowait', 'silent', 'script', 'expr', 'unique'} + for _, opt in ipairs(optnames) do + -- note: need '%' to escape hyphens, which have special meaning in lua + it('throws an error when given non-boolean value for '..opt, function() + local opts = {} + opts[opt] = 2 + expect_err('Gave non%-boolean value for an opt: '..opt, + meths.set_keymap, 'n', 'lhs', 'rhs', opts) + end) + end + + -- Perform tests of basic functionality + it('sets ordinary mappings', function() + meths.set_keymap('n', 'lhs', 'rhs', {}) + eq(generate_mapargs('n', 'lhs', 'rhs'), get_mapargs('n', 'lhs')) + + meths.set_keymap('v', 'lhs', 'rhs', {}) + eq(generate_mapargs('v', 'lhs', 'rhs'), get_mapargs('v', 'lhs')) + end) + + it('does not throw when LHS or RHS have leading/trailing whitespace', function() + meths.set_keymap('n', ' lhs', 'rhs', {}) + eq(generate_mapargs('n', '<Space><Space><Space>lhs', 'rhs'), + get_mapargs('n', ' lhs')) + + meths.set_keymap('n', 'lhs ', 'rhs', {}) + eq(generate_mapargs('n', 'lhs<Space><Space><Space><Space>', 'rhs'), + get_mapargs('n', 'lhs ')) + + meths.set_keymap('v', ' lhs ', '\trhs\t\f', {}) + eq(generate_mapargs('v', '<Space>lhs<Space><Space>', '\trhs\t\f'), + get_mapargs('v', ' lhs ')) + end) + + it('can set noremap mappings', function() + meths.set_keymap('x', 'lhs', 'rhs', {noremap = true}) + eq(generate_mapargs('x', 'lhs', 'rhs', {noremap = true}), + get_mapargs('x', 'lhs')) + + meths.set_keymap('t', 'lhs', 'rhs', {noremap = true}) + eq(generate_mapargs('t', 'lhs', 'rhs', {noremap = true}), + get_mapargs('t', 'lhs')) + end) + + it('can unmap mappings', function() + meths.set_keymap('v', 'lhs', 'rhs', {}) + meths.del_keymap('v', 'lhs') + eq({}, get_mapargs('v', 'lhs')) + + meths.set_keymap('t', 'lhs', 'rhs', {noremap = true}) + meths.del_keymap('t', 'lhs') + eq({}, get_mapargs('t', 'lhs')) + end) + + -- Test some edge cases + it('"!" and empty string are synonyms for mapmode-nvo', function() + local nvo_shortnames = {'', '!'} + for _, name in ipairs(nvo_shortnames) do + meths.set_keymap(name, 'lhs', 'rhs', {}) + meths.del_keymap(name, 'lhs') + eq({}, get_mapargs(name, 'lhs')) + end + end) + + local special_chars = {'<C-U>', '<S-Left>', '<F12><F2><Tab>', '<Space><Tab>'} + for _, lhs in ipairs(special_chars) do + for _, rhs in ipairs(special_chars) do + local mapmode = '!' + it('can set mappings with special characters, lhs: '..lhs..', rhs: '..rhs, + function() + meths.set_keymap(mapmode, lhs, rhs, {}) + eq(generate_mapargs(mapmode, lhs, rhs), get_mapargs(mapmode, lhs)) + end) + end + end + + it('can set mappings containing literal keycodes', function() + meths.set_keymap('n', '\n\r\n', 'rhs', {}) + local expected = generate_mapargs('n', '<NL><CR><NL>', 'rhs') + eq(expected, get_mapargs('n', '<C-j><CR><C-j>')) + end) + + it('can set mappings whose RHS is a <Nop>', function() + meths.set_keymap('i', 'lhs', '<Nop>', {}) + command('normal ilhs') + eq({''}, curbufmeths.get_lines(0, -1, 0)) -- imap to <Nop> does nothing + eq(generate_mapargs('i', 'lhs', '<Nop>', {}), + get_mapargs('i', 'lhs')) + + -- also test for case insensitivity + meths.set_keymap('i', 'lhs', '<nOp>', {}) + command('normal ilhs') + eq({''}, curbufmeths.get_lines(0, -1, 0)) + -- note: RHS in returned mapargs() dict reflects the original RHS + -- provided by the user + eq(generate_mapargs('i', 'lhs', '<nOp>', {}), + get_mapargs('i', 'lhs')) + + meths.set_keymap('i', 'lhs', '<NOP>', {}) + command('normal ilhs') + eq({''}, curbufmeths.get_lines(0, -1, 0)) + eq(generate_mapargs('i', 'lhs', '<NOP>', {}), + get_mapargs('i', 'lhs')) + end) + + it('treats an empty RHS in a mapping like a <Nop>', function() + meths.set_keymap('i', 'lhs', '', {}) + command('normal ilhs') + eq({''}, curbufmeths.get_lines(0, -1, 0)) + eq(generate_mapargs('i', 'lhs', '', {}), + get_mapargs('i', 'lhs')) + end) + + it('can set and unset <M-">', function() + -- Taken from the legacy test: test_mapping.vim. Exposes a bug in which + -- replace_termcodes changes the length of the mapping's LHS, but + -- do_map continues to use the *old* length of LHS. + meths.set_keymap('i', '<M-">', 'foo', {}) + meths.del_keymap('i', '<M-">') + eq({}, get_mapargs('i', '<M-">')) + end) + + it('interprets control sequences in expr-quotes correctly when called ' + ..'inside vim', function() + command([[call nvim_set_keymap('i', "\<space>", "\<tab>", {})]]) + eq(generate_mapargs('i', '<Space>', '\t', {}), + get_mapargs('i', '<Space>')) + feed('i ') + eq({'\t'}, curbufmeths.get_lines(0, -1, 0)) + end) + + it('throws appropriate error messages when setting <unique> maps', function() + meths.set_keymap('l', 'lhs', 'rhs', {}) + expect_err('E227: mapping already exists for lhs', + meths.set_keymap, 'l', 'lhs', 'rhs', {unique = true}) + -- different mapmode, no error should be thrown + meths.set_keymap('t', 'lhs', 'rhs', {unique = true}) + end) + + it('can set <expr> mappings whose RHS change dynamically', function() + meths.command_output([[ + function! FlipFlop() abort + if !exists('g:flip') | let g:flip = 0 | endif + let g:flip = !g:flip + return g:flip + endfunction + ]]) + eq(1, meths.call_function('FlipFlop', {})) + eq(0, meths.call_function('FlipFlop', {})) + eq(1, meths.call_function('FlipFlop', {})) + eq(0, meths.call_function('FlipFlop', {})) + + meths.set_keymap('i', 'lhs', 'FlipFlop()', {expr = true}) + command('normal ilhs') + eq({'1'}, curbufmeths.get_lines(0, -1, 0)) + + command('normal! ggVGd') + + command('normal ilhs') + eq({'0'}, curbufmeths.get_lines(0, -1, 0)) + end) + + it('can set mappings that do trigger other mappings', function() + meths.set_keymap('i', 'mhs', 'rhs', {}) + meths.set_keymap('i', 'lhs', 'mhs', {}) + + command('normal imhs') + eq({'rhs'}, curbufmeths.get_lines(0, -1, 0)) + + command('normal! ggVGd') + + command('normal ilhs') + eq({'rhs'}, curbufmeths.get_lines(0, -1, 0)) + end) + + it("can set noremap mappings that don't trigger other mappings", function() + meths.set_keymap('i', 'mhs', 'rhs', {}) + meths.set_keymap('i', 'lhs', 'mhs', {noremap = true}) + + command('normal imhs') + eq({'rhs'}, curbufmeths.get_lines(0, -1, 0)) + + command('normal! ggVGd') + + command('normal ilhs') -- shouldn't trigger mhs-to-rhs mapping + eq({'mhs'}, curbufmeths.get_lines(0, -1, 0)) + end) + + it("can set nowait mappings that fire without waiting", function() + meths.set_keymap('i', '123456', 'longer', {}) + meths.set_keymap('i', '123', 'shorter', {nowait = true}) + + -- feed keys one at a time; if all keys arrive atomically, the longer + -- mapping will trigger + local keys = 'i123456' + for c in string.gmatch(keys, '.') do + feed(c) + sleep(5) + end + eq({'shorter456'}, curbufmeths.get_lines(0, -1, 0)) + end) + + -- Perform exhaustive tests of basic functionality + local mapmodes = {'n', 'v', 'x', 's', 'o', '!', 'i', 'l', 'c', 't', ''} + for _, mapmode in ipairs(mapmodes) do + it('can set/unset normal mappings in mapmode '..mapmode, function() + meths.set_keymap(mapmode, 'lhs', 'rhs', {}) + eq(generate_mapargs(mapmode, 'lhs', 'rhs'), + get_mapargs(mapmode, 'lhs')) + + -- some mapmodes (like 'o') will prevent other mapmodes (like '!') from + -- taking effect, so unmap after each mapping + meths.del_keymap(mapmode, 'lhs') + eq({}, get_mapargs(mapmode, 'lhs')) + end) + end + + for _, mapmode in ipairs(mapmodes) do + it('can set/unset noremap mappings using mapmode '..mapmode, function() + meths.set_keymap(mapmode, 'lhs', 'rhs', {noremap = true}) + eq(generate_mapargs(mapmode, 'lhs', 'rhs', {noremap = true}), + get_mapargs(mapmode, 'lhs')) + + meths.del_keymap(mapmode, 'lhs') + eq({}, get_mapargs(mapmode, 'lhs')) + end) + end + + -- Test map-arguments, using optnames from above + -- remove some map arguments that are harder to test, or were already tested + optnames = {'nowait', 'silent', 'expr', 'noremap'} + for _, mapmode in ipairs(mapmodes) do + local printable_mode = normalize_mapmode(mapmode) + + -- Test with single mappings + for _, maparg in ipairs(optnames) do + it('can set/unset '..printable_mode..'-mappings with maparg: '..maparg, + function() + meths.set_keymap(mapmode, 'lhs', 'rhs', {[maparg] = true}) + eq(generate_mapargs(mapmode, 'lhs', 'rhs', {[maparg] = true}), + get_mapargs(mapmode, 'lhs')) + meths.del_keymap(mapmode, 'lhs') + eq({}, get_mapargs(mapmode, 'lhs')) + end) + it ('can set/unset '..printable_mode..'-mode mappings with maparg '.. + maparg..', whose value is false', function() + meths.set_keymap(mapmode, 'lhs', 'rhs', {[maparg] = false}) + eq(generate_mapargs(mapmode, 'lhs', 'rhs'), + get_mapargs(mapmode, 'lhs')) + meths.del_keymap(mapmode, 'lhs') + eq({}, get_mapargs(mapmode, 'lhs')) + end) + end + + -- Test with triplets of mappings, one of which is false + for i = 1, (#optnames - 2) do + local opt1, opt2, opt3 = optnames[i], optnames[i + 1], optnames[i + 2] + it('can set/unset '..printable_mode..'-mode mappings with mapargs '.. + opt1..', '..opt2..', '..opt3, function() + local opts = {[opt1] = true, [opt2] = false, [opt3] = true} + meths.set_keymap(mapmode, 'lhs', 'rhs', opts) + eq(generate_mapargs(mapmode, 'lhs', 'rhs', opts), + get_mapargs(mapmode, 'lhs')) + meths.del_keymap(mapmode, 'lhs') + eq({}, get_mapargs(mapmode, 'lhs')) + end) + end + end +end) + +describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function() + before_each(clear) + + -- nvim_set_keymap is implemented as a wrapped call to nvim_buf_set_keymap, + -- so its tests also effectively test nvim_buf_set_keymap + + -- here, we mainly test for buffer specificity and other special cases + + -- switch to the given buffer, abandoning any changes in the current buffer + local function switch_to_buf(bufnr) + command(bufnr..'buffer!') + end + + -- `set hidden`, then create two buffers and return their bufnr's + -- If start_from_first is truthy, the first buffer will be open when + -- the function returns; if falsy, the second buffer will be open. + local function make_two_buffers(start_from_first) + command('set hidden') + + local first_buf = meths.call_function('bufnr', {'%'}) + command('new') + local second_buf = meths.call_function('bufnr', {'%'}) + neq(second_buf, first_buf) -- sanity check + + if start_from_first then + switch_to_buf(first_buf) + end + + return first_buf, second_buf + end + + it('rejects negative bufnr values', function() + expect_err('Wrong type for argument 1, expecting Buffer', + bufmeths.set_keymap, -1, '', 'lhs', 'rhs', {}) + end) + + it('can set mappings active in the current buffer but not others', function() + local first, second = make_two_buffers(true) + + bufmeths.set_keymap(0, '', 'lhs', 'irhs<Esc>', {}) + command('normal lhs') + eq({'rhs'}, bufmeths.get_lines(0, 0, 1, 1)) + + -- mapping should have no effect in new buffer + switch_to_buf(second) + command('normal lhs') + eq({''}, bufmeths.get_lines(0, 0, 1, 1)) + + -- mapping should remain active in old buffer + switch_to_buf(first) + command('normal ^lhs') + eq({'rhsrhs'}, bufmeths.get_lines(0, 0, 1, 1)) + end) + + it('can set local mappings in buffer other than current', function() + local first = make_two_buffers(false) + bufmeths.set_keymap(first, '', 'lhs', 'irhs<Esc>', {}) + + -- shouldn't do anything + command('normal lhs') + eq({''}, bufmeths.get_lines(0, 0, 1, 1)) + + -- should take effect + switch_to_buf(first) + command('normal lhs') + eq({'rhs'}, bufmeths.get_lines(0, 0, 1, 1)) + end) + + it('can disable mappings made in another buffer, inside that buffer', function() + local first = make_two_buffers(false) + bufmeths.set_keymap(first, '', 'lhs', 'irhs<Esc>', {}) + bufmeths.del_keymap(first, '', 'lhs') + switch_to_buf(first) + + -- shouldn't do anything + command('normal lhs') + eq({''}, bufmeths.get_lines(0, 0, 1, 1)) + end) + + it("can't disable mappings given wrong buffer handle", function() + local first, second = make_two_buffers(false) + bufmeths.set_keymap(first, '', 'lhs', 'irhs<Esc>', {}) + expect_err('E31: No such mapping', + bufmeths.del_keymap, second, '', 'lhs') + + -- should still work + switch_to_buf(first) + command('normal lhs') + eq({'rhs'}, bufmeths.get_lines(0, 0, 1, 1)) + end) +end) diff --git a/test/functional/api/rpc_fixture.lua b/test/functional/api/rpc_fixture.lua index e885a525af..87f5a91115 100644 --- a/test/functional/api/rpc_fixture.lua +++ b/test/functional/api/rpc_fixture.lua @@ -1,7 +1,5 @@ -local deps_prefix = './.deps/usr' -if os.getenv('DEPS_PREFIX') then - deps_prefix = os.getenv('DEPS_PREFIX') -end +local deps_prefix = (os.getenv('DEPS_PREFIX') and os.getenv('DEPS_PREFIX') + or './.deps/usr') package.path = deps_prefix .. '/share/lua/5.1/?.lua;' .. deps_prefix .. '/share/lua/5.1/?/init.lua;' .. diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 4d25ba0819..7d9a8269d9 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -1,7 +1,6 @@ -- Test server -> client RPC scenarios. Note: unlike `rpcnotify`, to evaluate -- `rpcrequest` calls we need the client event loop to be running. local helpers = require('test.functional.helpers')(after_each) -local Paths = require('test.config.paths') local clear, nvim, eval = helpers.clear, helpers.nvim, helpers.eval local eq, neq, run, stop = helpers.eq, helpers.neq, helpers.run, helpers.stop @@ -243,8 +242,8 @@ describe('server -> client', function() \ 'rpc': v:true \ } ]]) - local lua_prog = Paths.test_lua_prg - meths.set_var("args", {lua_prog, 'test/functional/api/rpc_fixture.lua'}) + meths.set_var("args", {helpers.test_lua_prg, + 'test/functional/api/rpc_fixture.lua'}) jobid = eval("jobstart(g:args, g:job_opts)") neq(0, 'jobid') end) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 75b9fb71c9..a7d8dc59ec 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1,6 +1,5 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local global_helpers = require('test.helpers') local NIL = helpers.NIL local clear, nvim, eq, neq = helpers.clear, helpers.nvim, helpers.eq, helpers.neq @@ -16,10 +15,10 @@ local request = helpers.request local source = helpers.source local next_msg = helpers.next_msg -local expect_err = global_helpers.expect_err -local format_string = global_helpers.format_string -local intchar2lua = global_helpers.intchar2lua -local mergedicts_copy = global_helpers.mergedicts_copy +local expect_err = helpers.expect_err +local format_string = helpers.format_string +local intchar2lua = helpers.intchar2lua +local mergedicts_copy = helpers.mergedicts_copy describe('API', function() before_each(clear) @@ -49,13 +48,30 @@ describe('API', function() it('handles errors in async requests', function() local error_types = meths.get_api_info()[2].error_types - nvim_async("bogus") + nvim_async('bogus') eq({'notification', 'nvim_error_event', {error_types.Exception.id, 'Invalid method: nvim_bogus'}}, next_msg()) -- error didn't close channel. eq(2, eval('1+1')) end) + it('failed async request emits nvim_error_event', function() + local error_types = meths.get_api_info()[2].error_types + nvim_async('command', 'bogus') + eq({'notification', 'nvim_error_event', + {error_types.Exception.id, 'Vim:E492: Not an editor command: bogus'}}, + next_msg()) + -- error didn't close channel. + eq(2, eval('1+1')) + end) + + it('does not set CA_COMMAND_BUSY #7254', function() + nvim('command', 'split') + nvim('command', 'autocmd WinEnter * startinsert') + nvim('command', 'wincmd w') + eq({mode='i', blocking=false}, nvim("get_mode")) + end) + describe('nvim_command', function() it('works', function() local fname = helpers.tmpname() @@ -83,7 +99,7 @@ describe('API', function() end) it('VimL execution error: fails with specific error', function() - local status, rv = pcall(nvim, "command_output", "buffer 23487") + local status, rv = pcall(nvim, "command", "buffer 23487") eq(false, status) -- nvim_command() failed. eq("E86: Buffer 23487 does not exist", string.match(rv, "E%d*:.*")) eq('', eval('v:errmsg')) -- v:errmsg was not updated. @@ -1267,7 +1283,7 @@ describe('API', function() end) it('returns attached UIs', function() local screen = Screen.new(20, 4) - screen:attach() + screen:attach({override=true}) local expected = { { chan = 1, @@ -1282,6 +1298,7 @@ describe('API', function() ext_messages = false, height = 4, rgb = true, + override = true, width = 20, } } @@ -1291,6 +1308,7 @@ describe('API', function() screen = Screen.new(44, 99) screen:attach({ rgb = false }) expected[1].rgb = false + expected[1].override = false expected[1].width = 44 expected[1].height = 99 eq(expected, nvim("list_uis")) |