aboutsummaryrefslogtreecommitdiff
path: root/test/functional/api
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/api')
-rw-r--r--test/functional/api/buffer_spec.lua91
-rw-r--r--test/functional/api/keymap_spec.lua508
-rw-r--r--test/functional/api/rpc_fixture.lua6
-rw-r--r--test/functional/api/server_requests_spec.lua5
-rw-r--r--test/functional/api/vim_spec.lua34
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"))