diff options
| author | Josh Rahm <joshuarahm@gmail.com> | 2024-03-09 15:00:41 -0700 |
|---|---|---|
| committer | Josh Rahm <joshuarahm@gmail.com> | 2024-03-09 15:00:41 -0700 |
| commit | 7a7f497b483cd65e340064f23ed1c73425ecba0a (patch) | |
| tree | d5c99ea22a1e10300d06165f8ac96df6b0dc59e1 /test/functional/api/vim_spec.lua | |
| parent | 1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (diff) | |
| parent | ade1b12f49c3b3914c74847d791eb90ea90b56b7 (diff) | |
| download | rneovim-7a7f497b483cd65e340064f23ed1c73425ecba0a.tar.gz rneovim-7a7f497b483cd65e340064f23ed1c73425ecba0a.tar.bz2 rneovim-7a7f497b483cd65e340064f23ed1c73425ecba0a.zip | |
Merge remote-tracking branch 'upstream/master' into aucmd_textputpost
Diffstat (limited to 'test/functional/api/vim_spec.lua')
| -rw-r--r-- | test/functional/api/vim_spec.lua | 3895 |
1 files changed, 2150 insertions, 1745 deletions
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 8bbadda9b0..9a4a457637 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1,22 +1,25 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local luv = require('luv') +local uv = vim.uv local fmt = string.format +local dedent = helpers.dedent local assert_alive = helpers.assert_alive -local NIL = helpers.NIL -local clear, nvim, eq, neq = helpers.clear, helpers.nvim, helpers.eq, helpers.neq +local NIL = vim.NIL +local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq local command = helpers.command +local command_output = helpers.api.nvim_command_output local exec = helpers.exec local exec_capture = helpers.exec_capture local eval = helpers.eval local expect = helpers.expect -local funcs = helpers.funcs -local meths = helpers.meths +local fn = helpers.fn +local api = helpers.api local matches = helpers.matches -local pesc = helpers.pesc +local pesc = vim.pesc local mkdir_p = helpers.mkdir_p local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed +local async_meths = helpers.async_meths local is_os = helpers.is_os local parse_context = helpers.parse_context local request = helpers.request @@ -31,203 +34,273 @@ local insert = helpers.insert local skip = helpers.skip local pcall_err = helpers.pcall_err -local format_string = helpers.format_string +local format_string = require('test.format_string').format_string local intchar2lua = helpers.intchar2lua local mergedicts_copy = helpers.mergedicts_copy -local endswith = helpers.endswith +local endswith = vim.endswith describe('API', function() before_each(clear) it('validates requests', function() -- RPC - matches('Invalid method: bogus$', - pcall_err(request, 'bogus')) - matches('Invalid method: … の り 。…$', - pcall_err(request, '… の り 。…')) - matches('Invalid method: <empty>$', - pcall_err(request, '')) + matches('Invalid method: bogus$', pcall_err(request, 'bogus')) + matches('Invalid method: … の り 。…$', pcall_err(request, '… の り 。…')) + matches('Invalid method: <empty>$', pcall_err(request, '')) -- Non-RPC: rpcrequest(v:servername) uses internal channel. - matches('Invalid method: … の り 。…$', - pcall_err(request, 'nvim_eval', - [=[rpcrequest(sockconnect('pipe', v:servername, {'rpc':1}), '… の り 。…')]=])) - matches('Invalid method: bogus$', - pcall_err(request, 'nvim_eval', - [=[rpcrequest(sockconnect('pipe', v:servername, {'rpc':1}), 'bogus')]=])) + matches( + 'Invalid method: … の り 。…$', + pcall_err( + request, + 'nvim_eval', + [=[rpcrequest(sockconnect('pipe', v:servername, {'rpc':1}), '… の り 。…')]=] + ) + ) + matches( + 'Invalid method: bogus$', + pcall_err( + request, + 'nvim_eval', + [=[rpcrequest(sockconnect('pipe', v:servername, {'rpc':1}), 'bogus')]=] + ) + ) -- XXX: This must be the last one, else next one will fail: -- "Packer instance already working. Use another Packer ..." - matches("can't serialize object of type .$", - pcall_err(request, nil)) + matches("can't serialize object of type .$", pcall_err(request, nil)) end) it('handles errors in async requests', function() - local error_types = meths.get_api_info()[2].error_types + local error_types = api.nvim_get_api_info()[2].error_types nvim_async('bogus') - eq({'notification', 'nvim_error_event', - {error_types.Exception.id, 'Invalid method: nvim_bogus'}}, next_msg()) + eq({ + 'notification', + 'nvim_error_event', + { error_types.Exception.id, 'Invalid method: bogus' }, + }, next_msg()) -- error didn't close channel. assert_alive() 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()) + local error_types = api.nvim_get_api_info()[2].error_types + async_meths.nvim_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. assert_alive() end) + it('input is processed first when followed immediately by non-fast events', function() + api.nvim_set_current_line('ab') + async_meths.nvim_input('x') + async_meths.nvim_exec_lua('_G.res1 = vim.api.nvim_get_current_line()', {}) + async_meths.nvim_exec_lua('_G.res2 = vim.api.nvim_get_current_line()', {}) + eq({ 'b', 'b' }, exec_lua('return { _G.res1, _G.res2 }')) + 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")) + command('split') + command('autocmd WinEnter * startinsert') + command('wincmd w') + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) end) describe('nvim_exec2', function() it('always returns table', function() -- In built version this results into `vim.empty_dict()` - eq({}, nvim('exec2', 'echo "Hello"', {})) - eq({}, nvim('exec2', 'echo "Hello"', { output = false })) - eq({ output = 'Hello' }, nvim('exec2', 'echo "Hello"', { output = true })) + eq({}, api.nvim_exec2('echo "Hello"', {})) + eq({}, api.nvim_exec2('echo "Hello"', { output = false })) + eq({ output = 'Hello' }, api.nvim_exec2('echo "Hello"', { output = true })) end) it('default options', function() -- Should be equivalent to { output = false } - nvim('exec2', "let x0 = 'a'", {}) - eq('a', nvim('get_var', 'x0')) + api.nvim_exec2("let x0 = 'a'", {}) + eq('a', api.nvim_get_var('x0')) end) it('one-line input', function() - nvim('exec2', "let x1 = 'a'", { output = false }) - eq('a', nvim('get_var', 'x1')) + api.nvim_exec2("let x1 = 'a'", { output = false }) + eq('a', api.nvim_get_var('x1')) end) it(':verbose set {option}?', function() - nvim('exec2', 'set nowrap', { output = false }) - eq({ output = 'nowrap\n\tLast set from anonymous :source' }, - nvim('exec2', 'verbose set wrap?', { output = true })) + api.nvim_exec2('set nowrap', { output = false }) + eq( + { output = 'nowrap\n\tLast set from anonymous :source' }, + api.nvim_exec2('verbose set wrap?', { output = true }) + ) -- Using script var to force creation of a script item - nvim('exec2', [[ + api.nvim_exec2( + [[ let s:a = 1 set nowrap - ]], { output = false }) - eq({ output = 'nowrap\n\tLast set from anonymous :source (script id 1)' }, - nvim('exec2', 'verbose set wrap?', { output = true })) + ]], + { output = false } + ) + eq( + { output = 'nowrap\n\tLast set from anonymous :source (script id 1)' }, + api.nvim_exec2('verbose set wrap?', { output = true }) + ) end) it('multiline input', function() -- Heredoc + empty lines. - nvim('exec2', "let x2 = 'a'\n", { output = false }) - eq('a', nvim('get_var', 'x2')) - nvim('exec2','lua <<EOF\n\n\n\ny=3\n\n\nEOF', { output = false }) - eq(3, nvim('eval', "luaeval('y')")) + api.nvim_exec2("let x2 = 'a'\n", { output = false }) + eq('a', api.nvim_get_var('x2')) + api.nvim_exec2('lua <<EOF\n\n\n\ny=3\n\n\nEOF', { output = false }) + eq(3, api.nvim_eval("luaeval('y')")) - eq({}, nvim('exec2', 'lua <<EOF\ny=3\nEOF', { output = false })) - eq(3, nvim('eval', "luaeval('y')")) + eq({}, api.nvim_exec2('lua <<EOF\ny=3\nEOF', { output = false })) + eq(3, api.nvim_eval("luaeval('y')")) -- Multiple statements - nvim('exec2', 'let x1=1\nlet x2=2\nlet x3=3\n', { output = false }) - eq(1, nvim('eval', 'x1')) - eq(2, nvim('eval', 'x2')) - eq(3, nvim('eval', 'x3')) + api.nvim_exec2('let x1=1\nlet x2=2\nlet x3=3\n', { output = false }) + eq(1, api.nvim_eval('x1')) + eq(2, api.nvim_eval('x2')) + eq(3, api.nvim_eval('x3')) -- Functions - nvim('exec2', 'function Foo()\ncall setline(1,["xxx"])\nendfunction', { output = false }) - eq('', nvim('get_current_line')) - nvim('exec2', 'call Foo()', { output = false }) - eq('xxx', nvim('get_current_line')) + api.nvim_exec2('function Foo()\ncall setline(1,["xxx"])\nendfunction', { output = false }) + eq('', api.nvim_get_current_line()) + api.nvim_exec2('call Foo()', { output = false }) + eq('xxx', api.nvim_get_current_line()) -- Autocmds - nvim('exec2','autocmd BufAdd * :let x1 = "Hello"', { output = false }) - nvim('command', 'new foo') + api.nvim_exec2('autocmd BufAdd * :let x1 = "Hello"', { output = false }) + command('new foo') eq('Hello', request('nvim_eval', 'g:x1')) -- Line continuations - nvim('exec2', [[ + api.nvim_exec2( + [[ let abc = #{ \ a: 1, "\ b: 2, \ c: 3 - \ }]], { output = false }) - eq({a = 1, c = 3}, request('nvim_eval', 'g:abc')) + \ }]], + { output = false } + ) + eq({ a = 1, c = 3 }, request('nvim_eval', 'g:abc')) -- try no spaces before continuations to catch off-by-one error - nvim('exec2', 'let ab = #{\n\\a: 98,\n"\\ b: 2\n\\}', { output = false }) - eq({a = 98}, request('nvim_eval', 'g:ab')) + api.nvim_exec2('let ab = #{\n\\a: 98,\n"\\ b: 2\n\\}', { output = false }) + eq({ a = 98 }, request('nvim_eval', 'g:ab')) -- Script scope (s:) - eq({ output = 'ahoy! script-scoped varrrrr' }, nvim('exec2', [[ + eq( + { output = 'ahoy! script-scoped varrrrr' }, + api.nvim_exec2( + [[ let s:pirate = 'script-scoped varrrrr' function! s:avast_ye_hades(s) abort return a:s .. ' ' .. s:pirate endfunction echo <sid>avast_ye_hades('ahoy!') - ]], { output = true })) - - eq({ output = "{'output': 'ahoy! script-scoped varrrrr'}" }, nvim('exec2', [[ + ]], + { output = true } + ) + ) + + eq( + { output = "{'output': 'ahoy! script-scoped varrrrr'}" }, + api.nvim_exec2( + [[ let s:pirate = 'script-scoped varrrrr' function! Avast_ye_hades(s) abort return a:s .. ' ' .. s:pirate endfunction echo nvim_exec2('echo Avast_ye_hades(''ahoy!'')', {'output': v:true}) - ]], { output = true })) - - matches('Vim%(echo%):E121: Undefined variable: s:pirate$', - pcall_err(request, 'nvim_exec2', [[ + ]], + { output = true } + ) + ) + + matches( + 'Vim%(echo%):E121: Undefined variable: s:pirate$', + pcall_err( + request, + 'nvim_exec2', + [[ let s:pirate = 'script-scoped varrrrr' call nvim_exec2('echo s:pirate', {'output': v:true}) - ]], { output = false })) + ]], + { output = false } + ) + ) -- Script items are created only on script var access - eq({ output = '1\n0' }, nvim('exec2', [[ + eq( + { output = '1\n0' }, + api.nvim_exec2( + [[ echo expand("<SID>")->empty() let s:a = 123 echo expand("<SID>")->empty() - ]], { output = true })) - - eq({ output = '1\n0' }, nvim('exec2', [[ + ]], + { output = true } + ) + ) + + eq( + { output = '1\n0' }, + api.nvim_exec2( + [[ echo expand("<SID>")->empty() function s:a() abort endfunction echo expand("<SID>")->empty() - ]], { output = true })) + ]], + { output = true } + ) + ) end) it('non-ASCII input', function() - nvim('exec2', [=[ + api.nvim_exec2( + [=[ new exe "normal! i ax \n Ax " :%s/ax/--a1234--/g | :%s/Ax/--A1234--/g - ]=], { output = false }) - nvim('command', '1') - eq(' --a1234-- ', nvim('get_current_line')) - nvim('command', '2') - eq(' --A1234-- ', nvim('get_current_line')) - - nvim('exec2', [[ + ]=], + { output = false } + ) + command('1') + eq(' --a1234-- ', api.nvim_get_current_line()) + command('2') + eq(' --A1234-- ', api.nvim_get_current_line()) + + api.nvim_exec2( + [[ new call setline(1,['xxx']) call feedkeys('r') call feedkeys('ñ', 'xt') - ]], { output = false }) - eq('ñxx', nvim('get_current_line')) + ]], + { output = false } + ) + eq('ñxx', api.nvim_get_current_line()) end) it('execution error', function() - eq('nvim_exec2(): Vim:E492: Not an editor command: bogus_command', - pcall_err(request, 'nvim_exec2', 'bogus_command', {})) - eq('', nvim('eval', 'v:errmsg')) -- v:errmsg was not updated. + eq( + 'nvim_exec2(): Vim:E492: Not an editor command: bogus_command', + pcall_err(request, 'nvim_exec2', 'bogus_command', {}) + ) + eq('', api.nvim_eval('v:errmsg')) -- v:errmsg was not updated. eq('', eval('v:exception')) - eq('nvim_exec2(): Vim(buffer):E86: Buffer 23487 does not exist', - pcall_err(request, 'nvim_exec2', 'buffer 23487', {})) - eq('', eval('v:errmsg')) -- v:errmsg was not updated. + eq( + 'nvim_exec2(): Vim(buffer):E86: Buffer 23487 does not exist', + pcall_err(request, 'nvim_exec2', 'buffer 23487', {}) + ) + eq('', eval('v:errmsg')) -- v:errmsg was not updated. eq('', eval('v:exception')) end) @@ -240,7 +313,7 @@ describe('API', function() request('nvim_exec2', [[ let x2 = substitute('foo','o','X','g') let x4 = 'should be overwritten' - call nvim_exec2("source ]]..fname..[[\nlet x3 = substitute('foo','foo','set by recursive nvim_exec2','g')\nlet x5='overwritten'\nlet x4=x5\n", {'output': v:false}) + call nvim_exec2("source ]] .. fname .. [[\nlet x3 = substitute('foo','foo','set by recursive nvim_exec2','g')\nlet x5='overwritten'\nlet x4=x5\n", {'output': v:false}) ]], { output = false }) eq('set from :source file', request('nvim_get_var', 'x1')) eq('fXX', request('nvim_get_var', 'x2')) @@ -254,86 +327,108 @@ describe('API', function() local fname = tmpname() write_file(fname, 'echo "hello"\n') local sourcing_fname = tmpname() - write_file(sourcing_fname, 'call nvim_exec2("source '..fname..'", {"output": v:false})\n') - meths.exec2('set verbose=2', { output = false }) - local traceback_output = 'line 0: sourcing "'..sourcing_fname..'"\n'.. - 'line 0: sourcing "'..fname..'"\n'.. - 'hello\n'.. - 'finished sourcing '..fname..'\n'.. - 'continuing in nvim_exec2() called at '..sourcing_fname..':1\n'.. - 'finished sourcing '..sourcing_fname..'\n'.. - 'continuing in nvim_exec2() called at nvim_exec2():0' - eq({ output = traceback_output }, - meths.exec2('call nvim_exec2("source '..sourcing_fname..'", {"output": v:false})', { output = true })) + write_file(sourcing_fname, 'call nvim_exec2("source ' .. fname .. '", {"output": v:false})\n') + api.nvim_exec2('set verbose=2', { output = false }) + local traceback_output = dedent([[ + line 0: sourcing "%s" + line 0: sourcing "%s" + hello + finished sourcing %s + continuing in nvim_exec2() called at %s:1 + finished sourcing %s + continuing in nvim_exec2() called at nvim_exec2():0]]):format( + sourcing_fname, + fname, + fname, + sourcing_fname, + sourcing_fname + ) + eq( + { output = traceback_output }, + api.nvim_exec2( + 'call nvim_exec2("source ' .. sourcing_fname .. '", {"output": v:false})', + { output = true } + ) + ) os.remove(fname) os.remove(sourcing_fname) end) it('returns output', function() - eq({ output = 'this is spinal tap' }, - nvim('exec2', 'lua <<EOF\n\n\nprint("this is spinal tap")\n\n\nEOF', { output = true })) - eq({ output = '' }, nvim('exec2', 'echo', { output = true })) - eq({ output = 'foo 42' }, nvim('exec2', 'echo "foo" 42', { output = true })) + eq( + { output = 'this is spinal tap' }, + api.nvim_exec2('lua <<EOF\n\n\nprint("this is spinal tap")\n\n\nEOF', { output = true }) + ) + eq({ output = '' }, api.nvim_exec2('echo', { output = true })) + eq({ output = 'foo 42' }, api.nvim_exec2('echo "foo" 42', { output = true })) end) it('displays messages when opts.output=false', function() local screen = Screen.new(40, 8) screen:attach() screen:set_default_attr_ids({ - [0] = {bold=true, foreground=Screen.colors.Blue}, + [0] = { bold = true, foreground = Screen.colors.Blue }, }) - meths.exec2("echo 'hello'", { output = false }) - screen:expect{grid=[[ + api.nvim_exec2("echo 'hello'", { output = false }) + screen:expect { + grid = [[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*6 hello | - ]]} + ]], + } end) - it('doesn\'t display messages when output=true', function() + it("doesn't display messages when output=true", function() local screen = Screen.new(40, 6) screen:attach() screen:set_default_attr_ids({ - [0] = {bold=true, foreground=Screen.colors.Blue}, + [0] = { bold = true, foreground = Screen.colors.Blue }, }) - meths.exec2("echo 'hello'", { output = true }) - screen:expect{grid=[[ + api.nvim_exec2("echo 'hello'", { output = true }) + screen:expect { + grid = [[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*4 | - ]]} + ]], + } exec([[ func Print() call nvim_exec2('echo "hello"', { 'output': v:true }) endfunc ]]) feed([[:echon 1 | call Print() | echon 5<CR>]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*4 15 | - ]]} + ]], + } + end) + + it('errors properly when command too recursive', function() + exec_lua([[ + _G.success = false + vim.api.nvim_create_user_command('Test', function() + vim.api.nvim_exec2('Test', {}) + _G.success = true + end, {}) + ]]) + pcall_err(command, 'Test') + assert_alive() + eq(false, exec_lua('return _G.success')) end) end) describe('nvim_command', function() it('works', function() local fname = tmpname() - nvim('command', 'new') - nvim('command', 'edit '..fname) - nvim('command', 'normal itesting\napi') - nvim('command', 'w') + command('new') + command('edit ' .. fname) + command('normal itesting\napi') + command('w') local f = assert(io.open(fname)) if is_os('win') then eq('testing\r\napi\r\n', f:read('*a')) @@ -345,158 +440,166 @@ describe('API', function() end) it('Vimscript validation error: fails with specific error', function() - local status, rv = pcall(nvim, "command", "bogus_command") - eq(false, status) -- nvim_command() failed. - eq("E492:", string.match(rv, "E%d*:")) -- Vimscript error was returned. - eq('', nvim('eval', 'v:errmsg')) -- v:errmsg was not updated. + local status, rv = pcall(command, 'bogus_command') + eq(false, status) -- nvim_command() failed. + eq('E492:', string.match(rv, 'E%d*:')) -- Vimscript error was returned. + eq('', api.nvim_eval('v:errmsg')) -- v:errmsg was not updated. eq('', eval('v:exception')) end) it('Vimscript execution error: fails with specific error', function() - 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. + local status, rv = pcall(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. eq('', eval('v:exception')) end) it('gives E493 instead of prompting on backwards range', function() command('split') - eq('Vim(windo):E493: Backwards range given: 2,1windo echo', - pcall_err(command, '2,1windo echo')) + eq( + 'Vim(windo):E493: Backwards range given: 2,1windo echo', + pcall_err(command, '2,1windo echo') + ) end) end) describe('nvim_command_output', function() it('does not induce hit-enter prompt', function() - nvim("ui_attach", 80, 20, {}) + api.nvim_ui_attach(80, 20, {}) -- Induce a hit-enter prompt use nvim_input (non-blocking). - nvim('command', 'set cmdheight=1') - nvim('input', [[:echo "hi\nhi2"<CR>]]) + command('set cmdheight=1') + api.nvim_input([[:echo "hi\nhi2"<CR>]]) -- Verify hit-enter prompt. - eq({mode='r', blocking=true}, nvim("get_mode")) - nvim('input', [[<C-c>]]) + eq({ mode = 'r', blocking = true }, api.nvim_get_mode()) + api.nvim_input([[<C-c>]]) -- Verify NO hit-enter prompt. - nvim('command_output', [[echo "hi\nhi2"]]) - eq({mode='n', blocking=false}, nvim("get_mode")) + command_output([[echo "hi\nhi2"]]) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end) it('captures command output', function() - eq('this is\nspinal tap', - nvim('command_output', [[echo "this is\nspinal tap"]])) - eq('no line ending!', - nvim('command_output', [[echon "no line ending!"]])) + eq('this is\nspinal tap', command_output([[echo "this is\nspinal tap"]])) + eq('no line ending!', command_output([[echon "no line ending!"]])) end) it('captures empty command output', function() - eq('', nvim('command_output', 'echo')) + eq('', command_output('echo')) end) it('captures single-char command output', function() - eq('x', nvim('command_output', 'echo "x"')) + eq('x', command_output('echo "x"')) end) it('captures multiple commands', function() - eq('foo\n 1 %a "[No Name]" line 1', - nvim('command_output', 'echo "foo" | ls')) + eq('foo\n 1 %a "[No Name]" line 1', command_output('echo "foo" | ls')) end) it('captures nested execute()', function() - eq('\nnested1\nnested2\n 1 %a "[No Name]" line 1', - nvim('command_output', - [[echo execute('echo "nested1\nnested2"') | ls]])) + eq( + '\nnested1\nnested2\n 1 %a "[No Name]" line 1', + command_output([[echo execute('echo "nested1\nnested2"') | ls]]) + ) end) it('captures nested nvim_command_output()', function() - eq('nested1\nnested2\n 1 %a "[No Name]" line 1', - nvim('command_output', - [[echo nvim_command_output('echo "nested1\nnested2"') | ls]])) + eq( + 'nested1\nnested2\n 1 %a "[No Name]" line 1', + command_output([[echo nvim_command_output('echo "nested1\nnested2"') | ls]]) + ) end) it('returns shell |:!| output', function() local win_lf = is_os('win') and '\r' or '' - eq(':!echo foo\r\n\nfoo'..win_lf..'\n', nvim('command_output', [[!echo foo]])) + eq(':!echo foo\r\n\nfoo' .. win_lf .. '\n', command_output([[!echo foo]])) end) it('Vimscript validation error: fails with specific error', function() - local status, rv = pcall(nvim, "command_output", "bogus commannnd") - eq(false, status) -- nvim_command_output() failed. - eq("E492: Not an editor command: bogus commannnd", - string.match(rv, "E%d*:.*")) - eq('', eval('v:errmsg')) -- v:errmsg was not updated. + local status, rv = pcall(command_output, 'bogus commannnd') + eq(false, status) -- nvim_command_output() failed. + eq('E492: Not an editor command: bogus commannnd', string.match(rv, 'E%d*:.*')) + eq('', eval('v:errmsg')) -- v:errmsg was not updated. -- Verify NO hit-enter prompt. - eq({mode='n', blocking=false}, nvim("get_mode")) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end) it('Vimscript execution error: fails with specific error', function() - local status, rv = pcall(nvim, "command_output", "buffer 42") - eq(false, status) -- nvim_command_output() failed. - eq("E86: Buffer 42 does not exist", string.match(rv, "E%d*:.*")) - eq('', eval('v:errmsg')) -- v:errmsg was not updated. + local status, rv = pcall(command_output, 'buffer 42') + eq(false, status) -- nvim_command_output() failed. + eq('E86: Buffer 42 does not exist', string.match(rv, 'E%d*:.*')) + eq('', eval('v:errmsg')) -- v:errmsg was not updated. -- Verify NO hit-enter prompt. - eq({mode='n', blocking=false}, nvim("get_mode")) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end) it('does not cause heap buffer overflow with large output', function() - eq(eval('string(range(1000000))'), - nvim('command_output', 'echo range(1000000)')) + eq(eval('string(range(1000000))'), command_output('echo range(1000000)')) end) end) describe('nvim_eval', function() it('works', function() - nvim('command', 'let g:v1 = "a"') - nvim('command', 'let g:v2 = [1, 2, {"v3": 3}]') - eq({v1 = 'a', v2 = { 1, 2, { v3 = 3 } } }, nvim('eval', 'g:')) + command('let g:v1 = "a"') + command('let g:v2 = [1, 2, {"v3": 3}]') + eq({ v1 = 'a', v2 = { 1, 2, { v3 = 3 } } }, api.nvim_eval('g:')) end) it('handles NULL-initialized strings correctly', function() - eq(1, nvim('eval',"matcharg(1) == ['', '']")) - eq({'', ''}, nvim('eval','matcharg(1)')) + eq(1, api.nvim_eval("matcharg(1) == ['', '']")) + eq({ '', '' }, api.nvim_eval('matcharg(1)')) end) it('works under deprecated name', function() - eq(2, request("vim_eval", "1+1")) + eq(2, request('vim_eval', '1+1')) end) - it("Vimscript error: returns error details, does NOT update v:errmsg", function() - eq('Vim:E121: Undefined variable: bogus', - pcall_err(request, 'nvim_eval', 'bogus expression')) - eq('', eval('v:errmsg')) -- v:errmsg was not updated. + it('Vimscript error: returns error details, does NOT update v:errmsg', function() + eq('Vim:E121: Undefined variable: bogus', pcall_err(request, 'nvim_eval', 'bogus expression')) + eq('', eval('v:errmsg')) -- v:errmsg was not updated. end) end) describe('nvim_call_function', function() it('works', function() - nvim('call_function', 'setqflist', { { { filename = 'something', lnum = 17 } }, 'r' }) - eq(17, nvim('call_function', 'getqflist', {})[1].lnum) - eq(17, nvim('call_function', 'eval', {17})) - eq('foo', nvim('call_function', 'simplify', {'this/./is//redundant/../../../foo'})) - end) - - it("Vimscript validation error: returns specific error, does NOT update v:errmsg", function() - eq('Vim:E117: Unknown function: bogus function', - pcall_err(request, 'nvim_call_function', 'bogus function', {'arg1'})) - eq('Vim:E119: Not enough arguments for function: atan', - pcall_err(request, 'nvim_call_function', 'atan', {})) + api.nvim_call_function('setqflist', { { { filename = 'something', lnum = 17 } }, 'r' }) + eq(17, api.nvim_call_function('getqflist', {})[1].lnum) + eq(17, api.nvim_call_function('eval', { 17 })) + eq('foo', api.nvim_call_function('simplify', { 'this/./is//redundant/../../../foo' })) + end) + + it('Vimscript validation error: returns specific error, does NOT update v:errmsg', function() + eq( + 'Vim:E117: Unknown function: bogus function', + pcall_err(request, 'nvim_call_function', 'bogus function', { 'arg1' }) + ) + eq( + 'Vim:E119: Not enough arguments for function: atan', + pcall_err(request, 'nvim_call_function', 'atan', {}) + ) eq('', eval('v:exception')) - eq('', eval('v:errmsg')) -- v:errmsg was not updated. - end) - - it("Vimscript error: returns error details, does NOT update v:errmsg", function() - eq('Vim:E808: Number or Float required', - pcall_err(request, 'nvim_call_function', 'atan', {'foo'})) - eq('Vim:Invalid channel stream "xxx"', - pcall_err(request, 'nvim_call_function', 'chanclose', {999, 'xxx'})) - eq('Vim:E900: Invalid channel id', - pcall_err(request, 'nvim_call_function', 'chansend', {999, 'foo'})) + eq('', eval('v:errmsg')) -- v:errmsg was not updated. + end) + + it('Vimscript error: returns error details, does NOT update v:errmsg', function() + eq( + 'Vim:E808: Number or Float required', + pcall_err(request, 'nvim_call_function', 'atan', { 'foo' }) + ) + eq( + 'Vim:Invalid channel stream "xxx"', + pcall_err(request, 'nvim_call_function', 'chanclose', { 999, 'xxx' }) + ) + eq( + 'Vim:E900: Invalid channel id', + pcall_err(request, 'nvim_call_function', 'chansend', { 999, 'foo' }) + ) eq('', eval('v:exception')) - eq('', eval('v:errmsg')) -- v:errmsg was not updated. + eq('', eval('v:errmsg')) -- v:errmsg was not updated. end) - it("Vimscript exception: returns exception details, does NOT update v:errmsg", function() + it('Vimscript exception: returns exception details, does NOT update v:errmsg', function() source([[ function! Foo() abort throw 'wtf' @@ -504,10 +607,11 @@ describe('API', function() ]]) eq('function Foo, line 1: wtf', pcall_err(request, 'nvim_call_function', 'Foo', {})) eq('', eval('v:exception')) - eq('', eval('v:errmsg')) -- v:errmsg was not updated. + eq('', eval('v:errmsg')) -- v:errmsg was not updated. end) it('validation', function() + -- stylua: ignore local too_many_args = { 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x' } source([[ function! Foo(...) abort @@ -515,8 +619,10 @@ describe('API', function() endfunction ]]) -- E740 - eq('Function called with too many arguments', - pcall_err(request, 'nvim_call_function', 'Foo', too_many_args)) + eq( + 'Function called with too many arguments', + pcall_err(request, 'nvim_call_function', 'Foo', too_many_args) + ) end) end) @@ -535,40 +641,55 @@ describe('API', function() ]]) -- :help Dictionary-function - eq('Hello, World!', nvim('call_dict_function', 'g:test_dict_fn', 'F', {'World'})) + eq('Hello, World!', api.nvim_call_dict_function('g:test_dict_fn', 'F', { 'World' })) -- Funcref is sent as NIL over RPC. - eq({ greeting = 'Hello', F = NIL }, nvim('get_var', 'test_dict_fn')) + eq({ greeting = 'Hello', F = NIL }, api.nvim_get_var('test_dict_fn')) -- :help numbered-function - eq('Hi, Moon ...', nvim('call_dict_function', 'g:test_dict_fn2', 'F2', {'Moon'})) + eq('Hi, Moon ...', api.nvim_call_dict_function('g:test_dict_fn2', 'F2', { 'Moon' })) -- Funcref is sent as NIL over RPC. - eq({ greeting = 'Hi', F2 = NIL }, nvim('get_var', 'test_dict_fn2')) + eq({ greeting = 'Hi', F2 = NIL }, api.nvim_get_var('test_dict_fn2')) -- Function specified via RPC dict. source('function! G() dict\n return "@".(self.result)."@"\nendfunction') - eq('@it works@', nvim('call_dict_function', { result = 'it works', G = 'G'}, 'G', {})) + eq('@it works@', api.nvim_call_dict_function({ result = 'it works', G = 'G' }, 'G', {})) end) it('validation', function() command('let g:d={"baz":"zub","meep":[]}') - eq('Not found: bogus', - pcall_err(request, 'nvim_call_dict_function', 'g:d', 'bogus', {1,2})) - eq('Not a function: baz', - pcall_err(request, 'nvim_call_dict_function', 'g:d', 'baz', {1,2})) - eq('Not a function: meep', - pcall_err(request, 'nvim_call_dict_function', 'g:d', 'meep', {1,2})) - eq('Vim:E117: Unknown function: f', - pcall_err(request, 'nvim_call_dict_function', { f = '' }, 'f', {1,2})) - eq('Not a function: f', - pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", 'f', {1,2})) - eq('dict argument type must be String or Dictionary', - pcall_err(request, 'nvim_call_dict_function', 42, 'f', {1,2})) - eq('Failed to evaluate dict expression', - pcall_err(request, 'nvim_call_dict_function', 'foo', 'f', {1,2})) - eq('dict not found', - pcall_err(request, 'nvim_call_dict_function', '42', 'f', {1,2})) - eq('Invalid (empty) function name', - pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", '', {1,2})) + eq( + 'Not found: bogus', + pcall_err(request, 'nvim_call_dict_function', 'g:d', 'bogus', { 1, 2 }) + ) + eq( + 'Not a function: baz', + pcall_err(request, 'nvim_call_dict_function', 'g:d', 'baz', { 1, 2 }) + ) + eq( + 'Not a function: meep', + pcall_err(request, 'nvim_call_dict_function', 'g:d', 'meep', { 1, 2 }) + ) + eq( + 'Vim:E117: Unknown function: f', + pcall_err(request, 'nvim_call_dict_function', { f = '' }, 'f', { 1, 2 }) + ) + eq( + 'Not a function: f', + pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", 'f', { 1, 2 }) + ) + eq( + 'dict argument type must be String or Dictionary', + pcall_err(request, 'nvim_call_dict_function', 42, 'f', { 1, 2 }) + ) + eq( + 'Failed to evaluate dict expression', + pcall_err(request, 'nvim_call_dict_function', 'foo', 'f', { 1, 2 }) + ) + eq('dict not found', pcall_err(request, 'nvim_call_dict_function', '42', 'f', { 1, 2 })) + eq( + 'Invalid (empty) function name', + pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", '', { 1, 2 }) + ) end) end) @@ -576,85 +697,95 @@ describe('API', function() local |