diff options
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 start_dir before_each(function() - funcs.mkdir("Xtestdir") - start_dir = funcs.getcwd() + fn.mkdir('Xtestdir') + start_dir = fn.getcwd() end) after_each(function() - helpers.rmdir("Xtestdir") + helpers.rmdir('Xtestdir') end) it('works', function() - meths.set_current_dir("Xtestdir") - eq(funcs.getcwd(), start_dir .. helpers.get_pathsep() .. "Xtestdir") + api.nvim_set_current_dir('Xtestdir') + eq(fn.getcwd(), start_dir .. helpers.get_pathsep() .. 'Xtestdir') end) it('sets previous directory', function() - meths.set_current_dir("Xtestdir") + api.nvim_set_current_dir('Xtestdir') command('cd -') - eq(funcs.getcwd(), start_dir) + eq(fn.getcwd(), start_dir) end) end) describe('nvim_exec_lua', function() it('works', function() - meths.exec_lua('vim.api.nvim_set_var("test", 3)', {}) - eq(3, meths.get_var('test')) + api.nvim_exec_lua('vim.api.nvim_set_var("test", 3)', {}) + eq(3, api.nvim_get_var('test')) - eq(17, meths.exec_lua('a, b = ...\nreturn a + b', {10,7})) + eq(17, api.nvim_exec_lua('a, b = ...\nreturn a + b', { 10, 7 })) - eq(NIL, meths.exec_lua('function xx(a,b)\nreturn a..b\nend',{})) - eq("xy", meths.exec_lua('return xx(...)', {'x','y'})) + eq(NIL, api.nvim_exec_lua('function xx(a,b)\nreturn a..b\nend', {})) + eq('xy', api.nvim_exec_lua('return xx(...)', { 'x', 'y' })) -- Deprecated name: nvim_execute_lua. - eq("xy", meths.execute_lua('return xx(...)', {'x','y'})) + eq('xy', api.nvim_execute_lua('return xx(...)', { 'x', 'y' })) end) it('reports errors', function() - eq([[Error loading lua: [string "<nvim>"]:0: '=' expected near '+']], - pcall_err(meths.exec_lua, 'a+*b', {})) + eq( + [[Error loading lua: [string "<nvim>"]:0: '=' expected near '+']], + pcall_err(api.nvim_exec_lua, 'a+*b', {}) + ) - eq([[Error loading lua: [string "<nvim>"]:0: unexpected symbol near '1']], - pcall_err(meths.exec_lua, '1+2', {})) + eq( + [[Error loading lua: [string "<nvim>"]:0: unexpected symbol near '1']], + pcall_err(api.nvim_exec_lua, '1+2', {}) + ) - eq([[Error loading lua: [string "<nvim>"]:0: unexpected symbol]], - pcall_err(meths.exec_lua, 'aa=bb\0', {})) + eq( + [[Error loading lua: [string "<nvim>"]:0: unexpected symbol]], + pcall_err(api.nvim_exec_lua, 'aa=bb\0', {}) + ) - eq([[attempt to call global 'bork' (a nil value)]], - pcall_err(meths.exec_lua, 'bork()', {})) + eq( + [[attempt to call global 'bork' (a nil value)]], + pcall_err(api.nvim_exec_lua, 'bork()', {}) + ) - eq('did\nthe\nfail', - pcall_err(meths.exec_lua, 'error("did\\nthe\\nfail")', {})) + eq('did\nthe\nfail', pcall_err(api.nvim_exec_lua, 'error("did\\nthe\\nfail")', {})) end) it('uses native float values', function() - eq(2.5, meths.exec_lua("return select(1, ...)", {2.5})) - eq("2.5", meths.exec_lua("return vim.inspect(...)", {2.5})) + eq(2.5, api.nvim_exec_lua('return select(1, ...)', { 2.5 })) + eq('2.5', api.nvim_exec_lua('return vim.inspect(...)', { 2.5 })) -- "special" float values are still accepted as return values. - eq(2.5, meths.exec_lua("return vim.api.nvim_eval('2.5')", {})) - eq("{\n [false] = 2.5,\n [true] = 3\n}", meths.exec_lua("return vim.inspect(vim.api.nvim_eval('2.5'))", {})) + eq(2.5, api.nvim_exec_lua("return vim.api.nvim_eval('2.5')", {})) + eq( + '{\n [false] = 2.5,\n [true] = 3\n}', + api.nvim_exec_lua("return vim.inspect(vim.api.nvim_eval('2.5'))", {}) + ) end) end) describe('nvim_notify', function() it('can notify a info message', function() - nvim("notify", "hello world", 2, {}) + api.nvim_notify('hello world', 2, {}) end) it('can be overridden', function() - command("lua vim.notify = function(...) return 42 end") - eq(42, meths.exec_lua("return vim.notify('Hello world')", {})) - nvim("notify", "hello world", 4, {}) + command('lua vim.notify = function(...) return 42 end') + eq(42, api.nvim_exec_lua("return vim.notify('Hello world')", {})) + api.nvim_notify('hello world', 4, {}) end) end) describe('nvim_input', function() - it("Vimscript error: does NOT fail, updates v:errmsg", function() - local status, _ = pcall(nvim, "input", ":call bogus_fn()<CR>") - local v_errnum = string.match(nvim("eval", "v:errmsg"), "E%d*:") - eq(true, status) -- nvim_input() did not fail. - eq("E117:", v_errnum) -- v:errmsg was updated. + it('Vimscript error: does NOT fail, updates v:errmsg', function() + local status, _ = pcall(api.nvim_input, ':call bogus_fn()<CR>') + local v_errnum = string.match(api.nvim_eval('v:errmsg'), 'E%d*:') + eq(true, status) -- nvim_input() did not fail. + eq('E117:', v_errnum) -- v:errmsg was updated. end) it('does not crash even if trans_special result is largest #11788, #12287', function() @@ -665,30 +796,28 @@ describe('API', function() describe('nvim_paste', function() it('validation', function() - eq("Invalid 'phase': -2", - pcall_err(request, 'nvim_paste', 'foo', true, -2)) - eq("Invalid 'phase': 4", - pcall_err(request, 'nvim_paste', 'foo', true, 4)) + eq("Invalid 'phase': -2", pcall_err(request, 'nvim_paste', 'foo', true, -2)) + eq("Invalid 'phase': 4", pcall_err(request, 'nvim_paste', 'foo', true, 4)) end) local function run_streamed_paste_tests() it('stream: multiple chunks form one undo-block', function() - nvim('paste', '1/chunk 1 (start)\n', true, 1) - nvim('paste', '1/chunk 2 (end)\n', true, 3) + api.nvim_paste('1/chunk 1 (start)\n', true, 1) + api.nvim_paste('1/chunk 2 (end)\n', true, 3) local expected1 = [[ 1/chunk 1 (start) 1/chunk 2 (end) ]] expect(expected1) - nvim('paste', '2/chunk 1 (start)\n', true, 1) - nvim('paste', '2/chunk 2\n', true, 2) + api.nvim_paste('2/chunk 1 (start)\n', true, 1) + api.nvim_paste('2/chunk 2\n', true, 2) expect([[ 1/chunk 1 (start) 1/chunk 2 (end) 2/chunk 1 (start) 2/chunk 2 ]]) - nvim('paste', '2/chunk 3\n', true, 2) - nvim('paste', '2/chunk 4 (end)\n', true, 3) + api.nvim_paste('2/chunk 3\n', true, 2) + api.nvim_paste('2/chunk 4 (end)\n', true, 3) expect([[ 1/chunk 1 (start) 1/chunk 2 (end) @@ -697,17 +826,17 @@ describe('API', function() 2/chunk 3 2/chunk 4 (end) ]]) - feed('u') -- Undo. + feed('u') -- Undo. expect(expected1) end) it('stream: Insert mode', function() -- If nvim_paste() calls :undojoin without making any changes, this makes it an error. feed('afoo<Esc>u') feed('i') - nvim('paste', 'aaaaaa', false, 1) - nvim('paste', 'bbbbbb', false, 2) - nvim('paste', 'cccccc', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa', false, 1) + api.nvim_paste('bbbbbb', false, 2) + api.nvim_paste('cccccc', false, 2) + api.nvim_paste('dddddd', false, 3) expect('aaaaaabbbbbbccccccdddddd') feed('<Esc>u') expect('') @@ -723,17 +852,17 @@ describe('API', function() expect('') end) it('pasting one line', function() - nvim('paste', 'aaaaaa', false, 1) - nvim('paste', 'bbbbbb', false, 2) - nvim('paste', 'cccccc', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa', false, 1) + api.nvim_paste('bbbbbb', false, 2) + api.nvim_paste('cccccc', false, 2) + api.nvim_paste('dddddd', false, 3) expect('aaaaaabbbbbbccccccdddddd') end) it('pasting multiple lines', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd', false, 3) expect([[ aaaaaa bbbbbb @@ -753,17 +882,17 @@ describe('API', function() expect('||') end) it('pasting one line', function() - nvim('paste', 'aaaaaa', false, 1) - nvim('paste', 'bbbbbb', false, 2) - nvim('paste', 'cccccc', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa', false, 1) + api.nvim_paste('bbbbbb', false, 2) + api.nvim_paste('cccccc', false, 2) + api.nvim_paste('dddddd', false, 3) expect('|aaaaaabbbbbbccccccdddddd|') end) it('pasting multiple lines', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd', false, 3) expect([[ |aaaaaa bbbbbb @@ -783,17 +912,17 @@ describe('API', function() expect('||') end) it('pasting one line', function() - nvim('paste', 'aaaaaa', false, 1) - nvim('paste', 'bbbbbb', false, 2) - nvim('paste', 'cccccc', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa', false, 1) + api.nvim_paste('bbbbbb', false, 2) + api.nvim_paste('cccccc', false, 2) + api.nvim_paste('dddddd', false, 3) expect('||aaaaaabbbbbbccccccdddddd') end) it('pasting multiple lines', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd', false, 3) expect([[ ||aaaaaa bbbbbb @@ -817,24 +946,24 @@ describe('API', function() xxx|]]) end) it('with non-empty chunks', function() - nvim('paste', 'aaaaaa', false, 1) - nvim('paste', 'bbbbbb', false, 2) - nvim('paste', 'cccccc', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa', false, 1) + api.nvim_paste('bbbbbb', false, 2) + api.nvim_paste('cccccc', false, 2) + api.nvim_paste('dddddd', false, 3) expect('|aaaaaabbbbbbccccccdddddd|') end) it('with empty first chunk', function() - nvim('paste', '', false, 1) - nvim('paste', 'bbbbbb', false, 2) - nvim('paste', 'cccccc', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('', false, 1) + api.nvim_paste('bbbbbb', false, 2) + api.nvim_paste('cccccc', false, 2) + api.nvim_paste('dddddd', false, 3) expect('|bbbbbbccccccdddddd|') end) it('with all chunks empty', function() - nvim('paste', '', false, 1) - nvim('paste', '', false, 2) - nvim('paste', '', false, 2) - nvim('paste', '', false, 3) + api.nvim_paste('', false, 1) + api.nvim_paste('', false, 2) + api.nvim_paste('', false, 2) + api.nvim_paste('', false, 3) expect('||') end) end) @@ -852,17 +981,17 @@ describe('API', function() xxx]]) end) it('with non-empty chunks', function() - nvim('paste', 'aaaaaa', false, 1) - nvim('paste', 'bbbbbb', false, 2) - nvim('paste', 'cccccc', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa', false, 1) + api.nvim_paste('bbbbbb', false, 2) + api.nvim_paste('cccccc', false, 2) + api.nvim_paste('dddddd', false, 3) expect('||aaaaaabbbbbbccccccdddddd') end) it('with empty first chunk', function() - nvim('paste', '', false, 1) - nvim('paste', 'bbbbbb', false, 2) - nvim('paste', 'cccccc', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('', false, 1) + api.nvim_paste('bbbbbb', false, 2) + api.nvim_paste('cccccc', false, 2) + api.nvim_paste('dddddd', false, 3) expect('||bbbbbbccccccdddddd') end) end) @@ -880,17 +1009,17 @@ describe('API', function() xxx]]) end) it('with non-empty chunks', function() - nvim('paste', 'aaaaaa', false, 1) - nvim('paste', 'bbbbbb', false, 2) - nvim('paste', 'cccccc', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa', false, 1) + api.nvim_paste('bbbbbb', false, 2) + api.nvim_paste('cccccc', false, 2) + api.nvim_paste('dddddd', false, 3) expect('||aaaaaabbbbbbccccccdddddd') end) it('with empty first chunk', function() - nvim('paste', '', false, 1) - nvim('paste', 'bbbbbb', false, 2) - nvim('paste', 'cccccc', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('', false, 1) + api.nvim_paste('bbbbbb', false, 2) + api.nvim_paste('cccccc', false, 2) + api.nvim_paste('dddddd', false, 3) expect('||bbbbbbccccccdddddd') end) end) @@ -913,10 +1042,10 @@ describe('API', function() feed('ggV') end) it('pasting text without final new line', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd', false, 3) expect([[ aaaaaa bbbbbb @@ -925,10 +1054,10 @@ describe('API', function() 123456789]]) end) it('pasting text with final new line', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd\n', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd\n', false, 3) expect([[ aaaaaa bbbbbb @@ -943,10 +1072,10 @@ describe('API', function() feed('2ggV') end) it('pasting text without final new line', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd', false, 3) expect([[ 123456789 aaaaaa @@ -955,10 +1084,10 @@ describe('API', function() dddddd123456789]]) end) it('pasting text with final new line', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd\n', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd\n', false, 3) expect([[ 123456789 aaaaaa @@ -973,10 +1102,10 @@ describe('API', function() feed('3ggV') end) it('pasting text without final new line', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd', false, 3) expect([[ 123456789 987654321 @@ -986,10 +1115,10 @@ describe('API', function() dddddd]]) end) it('pasting text with final new line', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd\n', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd\n', false, 3) expect([[ 123456789 987654321 @@ -1005,10 +1134,10 @@ describe('API', function() feed('ggVG') end) it('pasting text without final new line', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd', false, 3) expect([[ aaaaaa bbbbbb @@ -1016,10 +1145,10 @@ describe('API', function() dddddd]]) end) it('pasting text with final new line', function() - nvim('paste', 'aaaaaa\n', false, 1) - nvim('paste', 'bbbbbb\n', false, 2) - nvim('paste', 'cccccc\n', false, 2) - nvim('paste', 'dddddd\n', false, 3) + api.nvim_paste('aaaaaa\n', false, 1) + api.nvim_paste('bbbbbb\n', false, 2) + api.nvim_paste('cccccc\n', false, 2) + api.nvim_paste('dddddd\n', false, 3) expect([[ aaaaaa bbbbbb @@ -1041,71 +1170,71 @@ describe('API', function() end) it('non-streaming', function() -- With final "\n". - nvim('paste', 'line 1\nline 2\nline 3\n', true, -1) + api.nvim_paste('line 1\nline 2\nline 3\n', true, -1) expect([[ line 1 line 2 line 3 ]]) - eq({0,4,1,0}, funcs.getpos('.')) -- Cursor follows the paste. - eq(false, nvim('get_option_value', 'paste', {})) + eq({ 0, 4, 1, 0 }, fn.getpos('.')) -- Cursor follows the paste. + eq(false, api.nvim_get_option_value('paste', {})) command('%delete _') -- Without final "\n". - nvim('paste', 'line 1\nline 2\nline 3', true, -1) + api.nvim_paste('line 1\nline 2\nline 3', true, -1) expect([[ line 1 line 2 line 3]]) - eq({0,3,6,0}, funcs.getpos('.')) + eq({ 0, 3, 6, 0 }, fn.getpos('.')) command('%delete _') -- CRLF #10872 - nvim('paste', 'line 1\r\nline 2\r\nline 3\r\n', true, -1) + api.nvim_paste('line 1\r\nline 2\r\nline 3\r\n', true, -1) expect([[ line 1 line 2 line 3 ]]) - eq({0,4,1,0}, funcs.getpos('.')) + eq({ 0, 4, 1, 0 }, fn.getpos('.')) command('%delete _') -- CRLF without final "\n". - nvim('paste', 'line 1\r\nline 2\r\nline 3\r', true, -1) + api.nvim_paste('line 1\r\nline 2\r\nline 3\r', true, -1) expect([[ line 1 line 2 line 3 ]]) - eq({0,4,1,0}, funcs.getpos('.')) + eq({ 0, 4, 1, 0 }, fn.getpos('.')) command('%delete _') -- CRLF without final "\r\n". - nvim('paste', 'line 1\r\nline 2\r\nline 3', true, -1) + api.nvim_paste('line 1\r\nline 2\r\nline 3', true, -1) expect([[ line 1 line 2 line 3]]) - eq({0,3,6,0}, funcs.getpos('.')) + eq({ 0, 3, 6, 0 }, fn.getpos('.')) command('%delete _') -- Various other junk. - nvim('paste', 'line 1\r\n\r\rline 2\nline 3\rline 4\r', true, -1) + api.nvim_paste('line 1\r\n\r\rline 2\nline 3\rline 4\r', true, -1) expect('line 1\n\n\nline 2\nline 3\nline 4\n') - eq({0,7,1,0}, funcs.getpos('.')) - eq(false, nvim('get_option_value', 'paste', {})) + eq({ 0, 7, 1, 0 }, fn.getpos('.')) + eq(false, api.nvim_get_option_value('paste', {})) end) it('Replace-mode', function() -- Within single line - nvim('put', {'aabbccdd', 'eeffgghh', 'iijjkkll'}, "c", true, false) + api.nvim_put({ 'aabbccdd', 'eeffgghh', 'iijjkkll' }, 'c', true, false) command('normal l') command('startreplace') - nvim('paste', '123456', true, -1) + api.nvim_paste('123456', true, -1) expect([[ a123456d eeffgghh iijjkkll]]) command('%delete _') -- Across lines - nvim('put', {'aabbccdd', 'eeffgghh', 'iijjkkll'}, "c", true, false) + api.nvim_put({ 'aabbccdd', 'eeffgghh', 'iijjkkll' }, 'c', true, false) command('normal l') command('startreplace') - nvim('paste', '123\n456', true, -1) + api.nvim_paste('123\n456', true, -1) expect([[ a123 456d @@ -1114,34 +1243,33 @@ describe('API', function() end) it('when searching in Visual mode', function() feed('v/') - nvim('paste', 'aabbccdd', true, -1) - eq('aabbccdd', funcs.getcmdline()) + api.nvim_paste('aabbccdd', true, -1) + eq('aabbccdd', fn.getcmdline()) expect('') end) it('mappings are disabled in Cmdline mode', function() command('cnoremap a b') feed(':') - nvim('paste', 'a', true, -1) - eq('a', funcs.getcmdline()) + api.nvim_paste('a', true, -1) + eq('a', fn.getcmdline()) end) it('pasted text is saved in cmdline history when <CR> comes from mapping #20957', function() command('cnoremap <CR> <CR>') feed(':') - nvim('paste', 'echo', true, -1) - eq('', funcs.histget(':')) + api.nvim_paste('echo', true, -1) + eq('', fn.histget(':')) feed('<CR>') - eq('echo', funcs.histget(':')) + eq('echo', fn.histget(':')) end) it('pasting with empty last chunk in Cmdline mode', function() local screen = Screen.new(20, 4) screen:attach() feed(':') - nvim('paste', 'Foo', true, 1) - nvim('paste', '', true, 3) + api.nvim_paste('Foo', true, 1) + api.nvim_paste('', true, 3) screen:expect([[ | - ~ | - ~ | + ~ |*2 :Foo^ | ]]) end) @@ -1149,112 +1277,113 @@ describe('API', function() local screen = Screen.new(20, 4) screen:attach() feed(':') - nvim('paste', 'normal! \023\022\006\027', true, -1) + api.nvim_paste('normal! \023\022\006\027', true, -1) screen:expect([[ | - ~ | - ~ | + ~ |*2 :normal! ^W^V^F^[^ | ]]) end) it('crlf=false does not break lines at CR, CRLF', function() - nvim('paste', 'line 1\r\n\r\rline 2\nline 3\rline 4\r', false, -1) + api.nvim_paste('line 1\r\n\r\rline 2\nline 3\rline 4\r', false, -1) expect('line 1\r\n\r\rline 2\nline 3\rline 4\r') - eq({0,3,14,0}, funcs.getpos('.')) + eq({ 0, 3, 14, 0 }, fn.getpos('.')) end) it('vim.paste() failure', function() - nvim('exec_lua', 'vim.paste = (function(lines, phase) error("fake fail") end)', {}) - eq('fake fail', - pcall_err(request, 'nvim_paste', 'line 1\nline 2\nline 3', false, 1)) + api.nvim_exec_lua('vim.paste = (function(lines, phase) error("fake fail") end)', {}) + eq('fake fail', pcall_err(request, 'nvim_paste', 'line 1\nline 2\nline 3', false, 1)) end) end) describe('nvim_put', function() it('validation', function() - eq("Invalid 'line': expected String, got Integer", - pcall_err(request, 'nvim_put', {42}, 'l', false, false)) - eq("Invalid 'type': 'x'", - pcall_err(request, 'nvim_put', {'foo'}, 'x', false, false)) + eq( + "Invalid 'line': expected String, got Integer", + pcall_err(request, 'nvim_put', { 42 }, 'l', false, false) + ) + eq("Invalid 'type': 'x'", pcall_err(request, 'nvim_put', { 'foo' }, 'x', false, false)) end) it("fails if 'nomodifiable'", function() command('set nomodifiable') - eq([[Vim:E21: Cannot make changes, 'modifiable' is off]], - pcall_err(request, 'nvim_put', {'a','b'}, 'l', true, true)) + eq( + [[Vim:E21: Cannot make changes, 'modifiable' is off]], + pcall_err(request, 'nvim_put', { 'a', 'b' }, 'l', true, true) + ) end) it('inserts text', function() -- linewise - nvim('put', {'line 1','line 2','line 3'}, 'l', true, true) + api.nvim_put({ 'line 1', 'line 2', 'line 3' }, 'l', true, true) expect([[ line 1 line 2 line 3]]) - eq({0,4,1,0}, funcs.getpos('.')) + eq({ 0, 4, 1, 0 }, fn.getpos('.')) command('%delete _') -- charwise - nvim('put', {'line 1','line 2','line 3'}, 'c', true, false) + api.nvim_put({ 'line 1', 'line 2', 'line 3' }, 'c', true, false) expect([[ line 1 line 2 line 3]]) - eq({0,1,1,0}, funcs.getpos('.')) -- follow=false + eq({ 0, 1, 1, 0 }, fn.getpos('.')) -- follow=false -- blockwise - nvim('put', {'AA','BB'}, 'b', true, true) + api.nvim_put({ 'AA', 'BB' }, 'b', true, true) expect([[ lAAine 1 lBBine 2 line 3]]) - eq({0,2,4,0}, funcs.getpos('.')) + eq({ 0, 2, 4, 0 }, fn.getpos('.')) command('%delete _') -- Empty lines list. - nvim('put', {}, 'c', true, true) - eq({0,1,1,0}, funcs.getpos('.')) + api.nvim_put({}, 'c', true, true) + eq({ 0, 1, 1, 0 }, fn.getpos('.')) expect([[]]) -- Single empty line. - nvim('put', {''}, 'c', true, true) - eq({0,1,1,0}, funcs.getpos('.')) + api.nvim_put({ '' }, 'c', true, true) + eq({ 0, 1, 1, 0 }, fn.getpos('.')) expect([[ ]]) - nvim('put', {'AB'}, 'c', true, true) + api.nvim_put({ 'AB' }, 'c', true, true) -- after=false, follow=true - nvim('put', {'line 1','line 2'}, 'c', false, true) + api.nvim_put({ 'line 1', 'line 2' }, 'c', false, true) expect([[ Aline 1 line 2B]]) - eq({0,2,7,0}, funcs.getpos('.')) + eq({ 0, 2, 7, 0 }, fn.getpos('.')) command('%delete _') - nvim('put', {'AB'}, 'c', true, true) + api.nvim_put({ 'AB' }, 'c', true, true) -- after=false, follow=false - nvim('put', {'line 1','line 2'}, 'c', false, false) + api.nvim_put({ 'line 1', 'line 2' }, 'c', false, false) expect([[ Aline 1 line 2B]]) - eq({0,1,2,0}, funcs.getpos('.')) - eq('', nvim('eval', 'v:errmsg')) + eq({ 0, 1, 2, 0 }, fn.getpos('.')) + eq('', api.nvim_eval('v:errmsg')) end) it('detects charwise/linewise text (empty {type})', function() -- linewise (final item is empty string) - nvim('put', {'line 1','line 2','line 3',''}, '', true, true) + api.nvim_put({ 'line 1', 'line 2', 'line 3', '' }, '', true, true) expect([[ line 1 line 2 line 3]]) - eq({0,4,1,0}, funcs.getpos('.')) + eq({ 0, 4, 1, 0 }, fn.getpos('.')) command('%delete _') -- charwise (final item is non-empty) - nvim('put', {'line 1','line 2','line 3'}, '', true, true) + api.nvim_put({ 'line 1', 'line 2', 'line 3' }, '', true, true) expect([[ line 1 line 2 line 3]]) - eq({0,3,6,0}, funcs.getpos('.')) + eq({ 0, 3, 6, 0 }, fn.getpos('.')) end) it('allows block width', function() -- behave consistently with setreg(); support "\022{NUM}" return by getregtype() - meths.put({'line 1','line 2','line 3'}, 'l', false, false) + api.nvim_put({ 'line 1', 'line 2', 'line 3' }, 'l', false, false) expect([[ line 1 line 2 @@ -1262,67 +1391,69 @@ describe('API', function() ]]) -- larger width create spaces - meths.put({'a', 'bc'}, 'b3', false, false) + api.nvim_put({ 'a', 'bc' }, 'b3', false, false) expect([[ a line 1 bc line 2 line 3 ]]) -- smaller width is ignored - meths.put({'xxx', 'yyy'}, '\0221', false, true) + api.nvim_put({ 'xxx', 'yyy' }, '\0221', false, true) expect([[ xxxa line 1 yyybc line 2 line 3 ]]) - eq("Invalid 'type': 'bx'", - pcall_err(meths.put, {'xxx', 'yyy'}, 'bx', false, true)) - eq("Invalid 'type': 'b3x'", - pcall_err(meths.put, {'xxx', 'yyy'}, 'b3x', false, true)) + eq("Invalid 'type': 'bx'", pcall_err(api.nvim_put, { 'xxx', 'yyy' }, 'bx', false, true)) + eq("Invalid 'type': 'b3x'", pcall_err(api.nvim_put, { 'xxx', 'yyy' }, 'b3x', false, true)) end) end) describe('nvim_strwidth', function() it('works', function() - eq(3, nvim('strwidth', 'abc')) + eq(3, api.nvim_strwidth('abc')) -- 6 + (neovim) -- 19 * 2 (each japanese character occupies two cells) - eq(44, nvim('strwidth', 'neovimのデザインかなりまともなのになってる。')) + eq(44, api.nvim_strwidth('neovimのデザインかなりまともなのになってる。')) end) it('cannot handle NULs', function() - eq(0, nvim('strwidth', '\0abc')) + eq(0, api.nvim_strwidth('\0abc')) end) end) describe('nvim_get_current_line, nvim_set_current_line', function() it('works', function() - eq('', nvim('get_current_line')) - nvim('set_current_line', 'abc') - eq('abc', nvim('get_current_line')) + eq('', api.nvim_get_current_line()) + api.nvim_set_current_line('abc') + eq('abc', api.nvim_get_current_line()) end) end) describe('set/get/del variables', function() it('validation', function() - eq('Key not found: bogus', pcall_err(meths.get_var, 'bogus')) - eq('Key not found: bogus', pcall_err(meths.del_var, 'bogus')) + eq('Key not found: bogus', pcall_err(api.nvim_get_var, 'bogus')) + eq('Key not found: bogus', pcall_err(api.nvim_del_var, 'bogus')) end) it('nvim_get_var, nvim_set_var, nvim_del_var', function() - nvim('set_var', 'lua', {1, 2, {['3'] = 1}}) - eq({1, 2, {['3'] = 1}}, nvim('get_var', 'lua')) - eq({1, 2, {['3'] = 1}}, nvim('eval', 'g:lua')) - eq(1, funcs.exists('g:lua')) - meths.del_var('lua') - eq(0, funcs.exists('g:lua')) - eq("Key not found: lua", pcall_err(meths.del_var, 'lua')) - meths.set_var('lua', 1) + api.nvim_set_var('lua', { 1, 2, { ['3'] = 1 } }) + eq({ 1, 2, { ['3'] = 1 } }, api.nvim_get_var('lua')) + eq({ 1, 2, { ['3'] = 1 } }, api.nvim_eval('g:lua')) + eq(1, fn.exists('g:lua')) + api.nvim_del_var('lua') + eq(0, fn.exists('g:lua')) + eq('Key not found: lua', pcall_err(api.nvim_del_var, 'lua')) + api.nvim_set_var('lua', 1) + + -- Empty keys are allowed in Vim dicts (and msgpack). + api.nvim_set_var('dict_empty_key', { [''] = 'empty key' }) + eq({ [''] = 'empty key' }, api.nvim_get_var('dict_empty_key')) -- Set locked g: var. command('lockvar lua') - eq('Key is locked: lua', pcall_err(meths.del_var, 'lua')) - eq('Key is locked: lua', pcall_err(meths.set_var, 'lua', 1)) + eq('Key is locked: lua', pcall_err(api.nvim_del_var, 'lua')) + eq('Key is locked: lua', pcall_err(api.nvim_set_var, 'lua', 1)) exec([[ function Test() @@ -1332,260 +1463,281 @@ describe('API', function() let g:Unknown_func = function('Test') let g:Unknown_script_func = function('s:Test') ]]) - eq(NIL, meths.get_var('Unknown_func')) - eq(NIL, meths.get_var('Unknown_script_func')) + eq(NIL, api.nvim_get_var('Unknown_func')) + eq(NIL, api.nvim_get_var('Unknown_script_func')) -- Check if autoload works properly local pathsep = helpers.get_pathsep() local xconfig = 'Xhome' .. pathsep .. 'Xconfig' local xdata = 'Xhome' .. pathsep .. 'Xdata' - local autoload_folder = table.concat({xconfig, 'nvim', 'autoload'}, pathsep) - local autoload_file = table.concat({autoload_folder , 'testload.vim'}, pathsep) + local autoload_folder = table.concat({ xconfig, 'nvim', 'autoload' }, pathsep) + local autoload_file = table.concat({ autoload_folder, 'testload.vim' }, pathsep) mkdir_p(autoload_folder) - write_file(autoload_file , [[let testload#value = 2]]) + write_file(autoload_file, [[let testload#value = 2]]) - clear{ args_rm={'-u'}, env={ XDG_CONFIG_HOME=xconfig, XDG_DATA_HOME=xdata } } - eq(2, meths.get_var('testload#value')) + clear { args_rm = { '-u' }, env = { XDG_CONFIG_HOME = xconfig, XDG_DATA_HOME = xdata } } + eq(2, api.nvim_get_var('testload#value')) rmdir('Xhome') end) it('nvim_get_vvar, nvim_set_vvar', function() eq('Key is read-only: count', pcall_err(request, 'nvim_set_vvar', 'count', 42)) eq('Dictionary is locked', pcall_err(request, 'nvim_set_vvar', 'nosuchvar', 42)) - meths.set_vvar('errmsg', 'set by API') - eq('set by API', meths.get_vvar('errmsg')) - meths.set_vvar('errmsg', 42) + api.nvim_set_vvar('errmsg', 'set by API') + eq('set by API', api.nvim_get_vvar('errmsg')) + api.nvim_set_vvar('errmsg', 42) eq('42', eval('v:errmsg')) - meths.set_vvar('oldfiles', { 'one', 'two' }) + api.nvim_set_vvar('oldfiles', { 'one', 'two' }) eq({ 'one', 'two' }, eval('v:oldfiles')) - meths.set_vvar('oldfiles', {}) + api.nvim_set_vvar('oldfiles', {}) eq({}, eval('v:oldfiles')) - eq('Setting v:oldfiles to value with wrong type', pcall_err(meths.set_vvar, 'oldfiles', 'a')) + eq( + 'Setting v:oldfiles to value with wrong type', + pcall_err(api.nvim_set_vvar, 'oldfiles', 'a') + ) eq({}, eval('v:oldfiles')) feed('i foo foo foo<Esc>0/foo<CR>') - eq({1, 1}, meths.win_get_cursor(0)) + eq({ 1, 1 }, api.nvim_win_get_cursor(0)) eq(1, eval('v:searchforward')) feed('n') - eq({1, 5}, meths.win_get_cursor(0)) - meths.set_vvar('searchforward', 0) + eq({ 1, 5 }, api.nvim_win_get_cursor(0)) + api.nvim_set_vvar('searchforward', 0) eq(0, eval('v:searchforward')) feed('n') - eq({1, 1}, meths.win_get_cursor(0)) - meths.set_vvar('searchforward', 1) + eq({ 1, 1 }, api.nvim_win_get_cursor(0)) + api.nvim_set_vvar('searchforward', 1) eq(1, eval('v:searchforward')) feed('n') - eq({1, 5}, meths.win_get_cursor(0)) + eq({ 1, 5 }, api.nvim_win_get_cursor(0)) local screen = Screen.new(60, 3) screen:set_default_attr_ids({ - [0] = {bold = true, foreground = Screen.colors.Blue}, - [1] = {background = Screen.colors.Yellow}, + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { background = Screen.colors.Yellow }, }) screen:attach() eq(1, eval('v:hlsearch')) - screen:expect{grid=[[ + screen:expect { + grid = [[ {1:foo} {1:^foo} {1:foo} | {0:~ }| | - ]]} - meths.set_vvar('hlsearch', 0) + ]], + } + api.nvim_set_vvar('hlsearch', 0) eq(0, eval('v:hlsearch')) - screen:expect{grid=[[ + screen:expect { + grid = [[ foo ^foo foo | {0:~ }| | - ]]} - meths.set_vvar('hlsearch', 1) + ]], + } + api.nvim_set_vvar('hlsearch', 1) eq(1, eval('v:hlsearch')) - screen:expect{grid=[[ + screen:expect { + grid = [[ {1:foo} {1:^foo} {1:foo} | {0:~ }| | - ]]} + ]], + } end) it('vim_set_var returns the old value', function() - local val1 = {1, 2, {['3'] = 1}} - local val2 = {4, 7} + local val1 = { 1, 2, { ['3'] = 1 } } + local val2 = { 4, 7 } eq(NIL, request('vim_set_var', 'lua', val1)) eq(val1, request('vim_set_var', 'lua', val2)) end) it('vim_del_var returns the old value', function() - local val1 = {1, 2, {['3'] = 1}} - local val2 = {4, 7} - eq(NIL, request('vim_set_var', 'lua', val1)) + local val1 = { 1, 2, { ['3'] = 1 } } + local val2 = { 4, 7 } + eq(NIL, request('vim_set_var', 'lua', val1)) eq(val1, request('vim_set_var', 'lua', val2)) eq(val2, request('vim_del_var', 'lua')) end) it('truncates values with NULs in them', function() - nvim('set_var', 'xxx', 'ab\0cd') - eq('ab', nvim('get_var', 'xxx')) + api.nvim_set_var('xxx', 'ab\0cd') + eq('ab', api.nvim_get_var('xxx')) end) end) describe('nvim_get_option_value, nvim_set_option_value', function() it('works', function() - ok(nvim('get_option_value', 'equalalways', {})) - nvim('set_option_value', 'equalalways', false, {}) - ok(not nvim('get_option_value', 'equalalways', {})) + ok(api.nvim_get_option_value('equalalways', {})) + api.nvim_set_option_value('equalalways', false, {}) + ok(not api.nvim_get_option_value('equalalways', {})) end) it('works to get global value of local options', function() - eq(false, nvim('get_option_value', 'lisp', {})) - eq(8, nvim('get_option_value', 'shiftwidth', {})) + eq(false, api.nvim_get_option_value('lisp', {})) + eq(8, api.nvim_get_option_value('shiftwidth', {})) end) it('works to set global value of local options', function() - nvim('set_option_value', 'lisp', true, {scope='global'}) - eq(true, nvim('get_option_value', 'lisp', {scope='global'})) - eq(false, nvim('get_option_value', 'lisp', {})) - eq(nil, nvim('command_output', 'setglobal lisp?'):match('nolisp')) - eq('nolisp', nvim('command_output', 'setlocal lisp?'):match('nolisp')) - nvim('set_option_value', 'shiftwidth', 20, {scope='global'}) - eq('20', nvim('command_output', 'setglobal shiftwidth?'):match('%d+')) - eq('8', nvim('command_output', 'setlocal shiftwidth?'):match('%d+')) + api.nvim_set_option_value('lisp', true, { scope = 'global' }) + eq(true, api.nvim_get_option_value('lisp', { scope = 'global' })) + eq(false, api.nvim_get_option_value('lisp', {})) + eq(nil, command_output('setglobal lisp?'):match('nolisp')) + eq('nolisp', command_output('setlocal lisp?'):match('nolisp')) + api.nvim_set_option_value('shiftwidth', 20, { scope = 'global' }) + eq('20', command_output('setglobal shiftwidth?'):match('%d+')) + eq('8', command_output('setlocal shiftwidth?'):match('%d+')) end) it('updates where the option was last set from', function() - nvim('set_option_value', 'equalalways', false, {}) - local status, rv = pcall(nvim, 'command_output', - 'verbose set equalalways?') + api.nvim_set_option_value('equalalways', false, {}) + local status, rv = pcall(command_output, 'verbose set equalalways?') eq(true, status) - ok(nil ~= string.find(rv, 'noequalalways\n'.. - '\tLast set from API client %(channel id %d+%)')) + ok( + nil ~= string.find(rv, 'noequalalways\n' .. '\tLast set from API client %(channel id %d+%)') + ) - nvim('exec_lua', 'vim.api.nvim_set_option_value("equalalways", true, {})', {}) - status, rv = pcall(nvim, 'command_output', - 'verbose set equalalways?') + api.nvim_exec_lua('vim.api.nvim_set_option_value("equalalways", true, {})', {}) + status, rv = pcall(command_output, 'verbose set equalalways?') eq(true, status) eq(' equalalways\n\tLast set from Lua', rv) end) it('updates whether the option has ever been set #25025', function() - eq(false, nvim('get_option_info2', 'autochdir', {}).was_set) - nvim('set_option_value', 'autochdir', true, {}) - eq(true, nvim('get_option_info2', 'autochdir', {}).was_set) + eq(false, api.nvim_get_option_info2('autochdir', {}).was_set) + api.nvim_set_option_value('autochdir', true, {}) + eq(true, api.nvim_get_option_info2('autochdir', {}).was_set) - eq(false, nvim('get_option_info2', 'cmdwinheight', {}).was_set) - nvim('set_option_value', 'cmdwinheight', 10, {}) - eq(true, nvim('get_option_info2', 'cmdwinheight', {}).was_set) + eq(false, api.nvim_get_option_info2('cmdwinheight', {}).was_set) + api.nvim_set_option_value('cmdwinheight', 10, {}) + eq(true, api.nvim_get_option_info2('cmdwinheight', {}).was_set) - eq(false, nvim('get_option_info2', 'debug', {}).was_set) - nvim('set_option_value', 'debug', 'beep', {}) - eq(true, nvim('get_option_info2', 'debug', {}).was_set) + eq(false, api.nvim_get_option_info2('debug', {}).was_set) + api.nvim_set_option_value('debug', 'beep', {}) + eq(true, api.nvim_get_option_info2('debug', {}).was_set) end) it('validation', function() - eq("Invalid 'scope': expected 'local' or 'global'", - pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 'bogus'})) - eq("Invalid 'scope': expected 'local' or 'global'", - pcall_err(nvim, 'set_option_value', 'scrolloff', 1, {scope = 'bogus'})) - eq("Invalid 'scope': expected String, got Integer", - pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 42})) - eq("Invalid 'value': expected valid option type, got Array", - pcall_err(nvim, 'set_option_value', 'scrolloff', {}, {})) - eq("Invalid value for option 'scrolloff': expected Number, got Boolean true", - pcall_err(nvim, 'set_option_value', 'scrolloff', true, {})) - eq("Invalid value for option 'scrolloff': expected Number, got String \"wrong\"", - pcall_err(nvim, 'set_option_value', 'scrolloff', 'wrong', {})) + eq( + "Invalid 'scope': expected 'local' or 'global'", + pcall_err(api.nvim_get_option_value, 'scrolloff', { scope = 'bogus' }) + ) + eq( + "Invalid 'scope': expected 'local' or 'global'", + pcall_err(api.nvim_set_option_value, 'scrolloff', 1, { scope = 'bogus' }) + ) + eq( + "Invalid 'scope': expected String, got Integer", + pcall_err(api.nvim_get_option_value, 'scrolloff', { scope = 42 }) + ) + eq( + "Invalid 'value': expected valid option type, got Array", + pcall_err(api.nvim_set_option_value, 'scrolloff', {}, {}) + ) + eq( + "Invalid value for option 'scrolloff': expected number, got boolean true", + pcall_err(api.nvim_set_option_value, 'scrolloff', true, {}) + ) + eq( + 'Invalid value for option \'scrolloff\': expected number, got string "wrong"', + pcall_err(api.nvim_set_option_value, 'scrolloff', 'wrong', {}) + ) end) it('can get local values when global value is set', function() - eq(0, nvim('get_option_value', 'scrolloff', {})) - eq(-1, nvim('get_option_value', 'scrolloff', {scope = 'local'})) + eq(0, api.nvim_get_option_value('scrolloff', {})) + eq(-1, api.nvim_get_option_value('scrolloff', { scope = 'local' })) end) it('can set global and local values', function() - nvim('set_option_value', 'makeprg', 'hello', {}) - eq('hello', nvim('get_option_value', 'makeprg', {})) - eq('', nvim('get_option_value', 'makeprg', {scope = 'local'})) - nvim('set_option_value', 'makeprg', 'world', {scope = 'local'}) - eq('world', nvim('get_option_value', 'makeprg', {scope = 'local'})) - nvim('set_option_value', 'makeprg', 'goodbye', {scope = 'global'}) - eq('goodbye', nvim('get_option_value', 'makeprg', {scope = 'global'})) - nvim('set_option_value', 'makeprg', 'hello', {}) - eq('hello', nvim('get_option_value', 'makeprg', {scope = 'global'})) - eq('hello', nvim('get_option_value', 'makeprg', {})) - eq('', nvim('get_option_value', 'makeprg', {scope = 'local'})) + api.nvim_set_option_value('makeprg', 'hello', {}) + eq('hello', api.nvim_get_option_value('makeprg', {})) + eq('', api.nvim_get_option_value('makeprg', { scope = 'local' })) + api.nvim_set_option_value('makeprg', 'world', { scope = 'local' }) + eq('world', api.nvim_get_option_value('makeprg', { scope = 'local' })) + api.nvim_set_option_value('makeprg', 'goodbye', { scope = 'global' }) + eq('goodbye', api.nvim_get_option_value('makeprg', { scope = 'global' })) + api.nvim_set_option_value('makeprg', 'hello', {}) + eq('hello', api.nvim_get_option_value('makeprg', { scope = 'global' })) + eq('hello', api.nvim_get_option_value('makeprg', {})) + eq('', api.nvim_get_option_value('makeprg', { scope = 'local' })) end) it('clears the local value of an option with nil', function() -- Set global value - nvim('set_option_value', 'shiftwidth', 42, {}) - eq(42, nvim('get_option_value', 'shiftwidth', {})) + api.nvim_set_option_value('shiftwidth', 42, {}) + eq(42, api.nvim_get_option_value('shiftwidth', {})) -- Set local value - nvim('set_option_value', 'shiftwidth', 8, {scope = 'local'}) - eq(8, nvim('get_option_value', 'shiftwidth', {})) - eq(8, nvim('get_option_value', 'shiftwidth', {scope = 'local'})) - eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'global'})) + api.nvim_set_option_value('shiftwidth', 8, { scope = 'local' }) + eq(8, api.nvim_get_option_value('shiftwidth', {})) + eq(8, api.nvim_get_option_value('shiftwidth', { scope = 'local' })) + eq(42, api.nvim_get_option_value('shiftwidth', { scope = 'global' })) -- Clear value without scope - nvim('set_option_value', 'shiftwidth', NIL, {}) - eq(42, nvim('get_option_value', 'shiftwidth', {})) - eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'local'})) + api.nvim_set_option_value('shiftwidth', NIL, {}) + eq(42, api.nvim_get_option_value('shiftwidth', {})) + eq(42, api.nvim_get_option_value('shiftwidth', { scope = 'local' })) -- Clear value with explicit scope - nvim('set_option_value', 'shiftwidth', 8, {scope = 'local'}) - nvim('set_option_value', 'shiftwidth', NIL, {scope = 'local'}) - eq(42, nvim('get_option_value', 'shiftwidth', {})) - eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'local'})) + api.nvim_set_option_value('shiftwidth', 8, { scope = 'local' }) + api.nvim_set_option_value('shiftwidth', NIL, { scope = 'local' }) + eq(42, api.nvim_get_option_value('shiftwidth', {})) + eq(42, api.nvim_get_option_value('shiftwidth', { scope = 'local' })) -- Now try with options with a special "local is unset" value (e.g. 'undolevels') - nvim('set_option_value', 'undolevels', 1000, {}) - nvim('set_option_value', 'undolevels', 1200, {scope = 'local'}) - eq(1200, nvim('get_option_value', 'undolevels', {scope = 'local'})) - nvim('set_option_value', 'undolevels', NIL, {scope = 'local'}) - eq(-123456, nvim('get_option_value', 'undolevels', {scope = 'local'})) - eq(1000, nvim('get_option_value', 'undolevels', {})) + api.nvim_set_option_value('undolevels', 1000, {}) + api.nvim_set_option_value('undolevels', 1200, { scope = 'local' }) + eq(1200, api.nvim_get_option_value('undolevels', { scope = 'local' })) + api.nvim_set_option_value('undolevels', NIL, { scope = 'local' }) + eq(-123456, api.nvim_get_option_value('undolevels', { scope = 'local' })) + eq(1000, api.nvim_get_option_value('undolevels', {})) - nvim('set_option_value', 'autoread', true, {}) - nvim('set_option_value', 'autoread', false, {scope = 'local'}) - eq(false, nvim('get_option_value', 'autoread', {scope = 'local'})) - nvim('set_option_value', 'autoread', NIL, {scope = 'local'}) - eq(NIL, nvim('get_option_value', 'autoread', {scope = 'local'})) - eq(true, nvim('get_option_value', 'autoread', {})) + api.nvim_set_option_value('autoread', true, {}) + api.nvim_set_option_value('autoread', false, { scope = 'local' }) + eq(false, api.nvim_get_option_value('autoread', { scope = 'local' })) + api.nvim_set_option_value('autoread', NIL, { scope = 'local' }) + eq(NIL, api.nvim_get_option_value('autoread', { scope = 'local' })) + eq(true, api.nvim_get_option_value('autoread', {})) end) it('set window options', function() - nvim('set_option_value', 'colorcolumn', '4,3', {}) - eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'})) - command("set modified hidden") - command("enew") -- edit new buffer, window option is preserved - eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'})) + api.nvim_set_option_value('colorcolumn', '4,3', {}) + eq('4,3', api.nvim_get_option_value('colorcolumn', { scope = 'local' })) + command('set modified hidden') + command('enew') -- edit new buffer, window option is preserved + eq('4,3', api.nvim_get_option_value('colorcolumn', { scope = 'local' })) end) it('set local window options', function() - nvim('set_option_value', 'colorcolumn', '4,3', {win=0, scope='local'}) - eq('4,3', nvim('get_option_value', 'colorcolumn', {win = 0, scope = 'local'})) - command("set modified hidden") - command("enew") -- edit new buffer, window option is reset - eq('', nvim('get_option_value', 'colorcolumn', {win = 0, scope = 'local'})) + api.nvim_set_option_value('colorcolumn', '4,3', { win = 0, scope = 'local' }) + eq('4,3', api.nvim_get_option_value('colorcolumn', { win = 0, scope = 'local' })) + command('set modified hidden') + command('enew') -- edit new buffer, window option is reset + eq('', api.nvim_get_option_value('colorcolumn', { win = 0, scope = 'local' })) end) it('get buffer or window-local options', function() - nvim('command', 'new') - local buf = nvim('get_current_buf').id - nvim('set_option_value', 'tagfunc', 'foobar', {buf=buf}) - eq('foobar', nvim('get_option_value', 'tagfunc', {buf = buf})) + command('new') + local buf = api.nvim_get_current_buf() + api.nvim_set_option_value('tagfunc', 'foobar', { buf = buf }) + eq('foobar', api.nvim_get_option_value('tagfunc', { buf = buf })) - local win = nvim('get_current_win').id - nvim('set_option_value', 'number', true, {win=win}) - eq(true, nvim('get_option_value', 'number', {win = win})) + local win = api.nvim_get_current_win() + api.nvim_set_option_value('number', true, { win = win }) + eq(true, api.nvim_get_option_value('number', { win = win })) end) it('getting current buffer option does not adjust cursor #19381', function() - nvim('command', 'new') - local buf = nvim('get_current_buf').id - local win = nvim('get_current_win').id + command('new') + local buf = api.nvim_get_current_buf() + print(vim.inspect(api.nvim_get_current_buf())) + local win = api.nvim_get_current_win() insert('some text') feed('0v$') - eq({1, 9}, nvim('win_get_cursor', win)) - nvim('get_option_value', 'filetype', {buf = buf}) - eq({1, 9}, nvim('win_get_cursor', win)) + eq({ 1, 9 }, api.nvim_win_get_cursor(win)) + api.nvim_get_option_value('filetype', { buf = buf }) + eq({ 1, 9 }, api.nvim_win_get_cursor(win)) end) it('can get default option values for filetypes', function() @@ -1593,158 +1745,160 @@ describe('API', function() for ft, opts in pairs { lua = { commentstring = '-- %s' }, vim = { commentstring = '"%s' }, - man = { tagfunc = 'v:lua.require\'man\'.goto_tag' }, - xml = { formatexpr = 'xmlformat#Format()' } + man = { tagfunc = "v:lua.require'man'.goto_tag" }, + xml = { formatexpr = 'xmlformat#Format()' }, } do for option, value in pairs(opts) do - eq(value, nvim('get_option_value', option, { filetype = ft })) + eq(value, api.nvim_get_option_value(option, { filetype = ft })) end end - command'au FileType lua setlocal commentstring=NEW\\ %s' + command 'au FileType lua setlocal commentstring=NEW\\ %s' - eq('NEW %s', nvim('get_option_value', 'commentstring', { filetype = 'lua' })) + eq('NEW %s', api.nvim_get_option_value('commentstring', { filetype = 'lua' })) end) it('errors for bad FileType autocmds', function() - command'au FileType lua setlocal commentstring=BAD' - eq([[FileType Autocommands for "lua": Vim(setlocal):E537: 'commentstring' must be empty or contain %s: commentstring=BAD]], - pcall_err(nvim, 'get_option_value', 'commentstring', { filetype = 'lua' })) + command 'au FileType lua setlocal commentstring=BAD' + eq( + [[FileType Autocommands for "lua": Vim(setlocal):E537: 'commentstring' must be empty or contain %s: commentstring=BAD]], + pcall_err(api.nvim_get_option_value, 'commentstring', { filetype = 'lua' }) + ) end) it("value of 'modified' is always false for scratch buffers", function() - nvim('set_current_buf', nvim('create_buf', true, true)) + api.nvim_set_current_buf(api.nvim_create_buf(true, true)) insert([[ foo bar baz ]]) - eq(false, nvim('get_option_value', 'modified', {})) + eq(false, api.nvim_get_option_value('modified', {})) end) end) describe('nvim_{get,set}_current_buf, nvim_list_bufs', function() it('works', function() - eq(1, #nvim('list_bufs')) - eq(nvim('list_bufs')[1], nvim('get_current_buf')) - nvim('command', 'new') - eq(2, #nvim('list_bufs')) - eq(nvim('list_bufs')[2], nvim('get_current_buf')) - nvim('set_current_buf', nvim('list_bufs')[1]) - eq(nvim('list_bufs')[1], nvim('get_current_buf')) + eq(1, #api.nvim_list_bufs()) + eq(api.nvim_list_bufs()[1], api.nvim_get_current_buf()) + command('new') + eq(2, #api.nvim_list_bufs()) + eq(api.nvim_list_bufs()[2], api.nvim_get_current_buf()) + api.nvim_set_current_buf(api.nvim_list_bufs()[1]) + eq(api.nvim_list_bufs()[1], api.nvim_get_current_buf()) end) end) describe('nvim_{get,set}_current_win, nvim_list_wins', function() it('works', function() - eq(1, #nvim('list_wins')) - eq(nvim('list_wins')[1], nvim('get_current_win')) - nvim('command', 'vsplit') - nvim('command', 'split') - eq(3, #nvim('list_wins')) - eq(nvim('list_wins')[1], nvim('get_current_win')) - nvim('set_current_win', nvim('list_wins')[2]) - eq(nvim('list_wins')[2], nvim('get_current_win')) + eq(1, #api.nvim_list_wins()) + eq(api.nvim_list_wins()[1], api.nvim_get_current_win()) + command('vsplit') + command('split') + eq(3, #api.nvim_list_wins()) + eq(api.nvim_list_wins()[1], api.nvim_get_current_win()) + api.nvim_set_current_win(api.nvim_list_wins()[2]) + eq(api.nvim_list_wins()[2], api.nvim_get_current_win()) end) end) describe('nvim_{get,set}_current_tabpage, nvim_list_tabpages', function() it('works', function() - eq(1, #nvim('list_tabpages')) - eq(nvim('list_tabpages')[1], nvim('get_current_tabpage')) - nvim('command', 'tabnew') - eq(2, #nvim('list_tabpages')) - eq(2, #nvim('list_wins')) - eq(nvim('list_wins')[2], nvim('get_current_win')) - eq(nvim('list_tabpages')[2], nvim('get_current_tabpage')) - nvim('set_current_win', nvim('list_wins')[1]) + eq(1, #api.nvim_list_tabpages()) + eq(api.nvim_list_tabpages()[1], api.nvim_get_current_tabpage()) + command('tabnew') + eq(2, #api.nvim_list_tabpages()) + eq(2, #api.nvim_list_wins()) + eq(api.nvim_list_wins()[2], api.nvim_get_current_win()) + eq(api.nvim_list_tabpages()[2], api.nvim_get_current_tabpage()) + api.nvim_set_current_win(api.nvim_list_wins()[1]) -- Switching window also switches tabpages if necessary - eq(nvim('list_tabpages')[1], nvim('get_current_tabpage')) - eq(nvim('list_wins')[1], nvim('get_current_win')) - nvim('set_current_tabpage', nvim('list_tabpages')[2]) - eq(nvim('list_tabpages')[2], nvim('get_current_tabpage')) - eq(nvim('list_wins')[2], nvim('get_current_win')) + eq(api.nvim_list_tabpages()[1], api.nvim_get_current_tabpage()) + eq(api.nvim_list_wins()[1], api.nvim_get_current_win()) + api.nvim_set_current_tabpage(api.nvim_list_tabpages()[2]) + eq(api.nvim_list_tabpages()[2], api.nvim_get_current_tabpage()) + eq(api.nvim_list_wins()[2], api.nvim_get_current_win()) end) end) describe('nvim_get_mode', function() - it("during normal-mode `g` returns blocking=true", function() - nvim("input", "o") -- add a line - eq({mode='i', blocking=false}, nvim("get_mode")) - nvim("input", [[<C-\><C-N>]]) - eq(2, nvim("eval", "line('.')")) - eq({mode='n', blocking=false}, nvim("get_mode")) + it('during normal-mode `g` returns blocking=true', function() + api.nvim_input('o') -- add a line + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) + api.nvim_input([[<C-\><C-N>]]) + eq(2, api.nvim_eval("line('.')")) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) - nvim("input", "g") - eq({mode='n', blocking=true}, nvim("get_mode")) + api.nvim_input('g') + eq({ mode = 'n', blocking = true }, api.nvim_get_mode()) - nvim("input", "k") -- complete the operator - eq(1, nvim("eval", "line('.')")) -- verify the completed operator - eq({mode='n', blocking=false}, nvim("get_mode")) + api.nvim_input('k') -- complete the operator + eq(1, api.nvim_eval("line('.')")) -- verify the completed operator + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end) - it("returns the correct result multiple consecutive times", function() - for _ = 1,5 do - eq({mode='n', blocking=false}, nvim("get_mode")) + it('returns the correct result multiple consecutive times', function() + for _ = 1, 5 do + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end - nvim("input", "g") - for _ = 1,4 do - eq({mode='n', blocking=true}, nvim("get_mode")) + api.nvim_input('g') + for _ = 1, 4 do + eq({ mode = 'n', blocking = true }, api.nvim_get_mode()) end - nvim("input", "g") - for _ = 1,7 do - eq({mode='n', blocking=false}, nvim("get_mode")) + api.nvim_input('g') + for _ = 1, 7 do + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end end) - it("during normal-mode CTRL-W, returns blocking=true", function() - nvim("input", "<C-W>") - eq({mode='n', blocking=true}, nvim("get_mode")) + it('during normal-mode CTRL-W, returns blocking=true', function() + api.nvim_input('<C-W>') + eq({ mode = 'n', blocking = true }, api.nvim_get_mode()) - nvim("input", "s") -- complete the operator - eq(2, nvim("eval", "winnr('$')")) -- verify the completed operator - eq({mode='n', blocking=false}, nvim("get_mode")) + api.nvim_input('s') -- complete the operator + eq(2, api.nvim_eval("winnr('$')")) -- verify the completed operator + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end) - it("during press-enter prompt without UI returns blocking=false", function() - eq({mode='n', blocking=false}, nvim("get_mode")) + it('during press-enter prompt without UI returns blocking=false', function() + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) command("echom 'msg1'") command("echom 'msg2'") command("echom 'msg3'") command("echom 'msg4'") command("echom 'msg5'") - eq({mode='n', blocking=false}, nvim("get_mode")) - nvim("input", ":messages<CR>") - eq({mode='n', blocking=false}, nvim("get_mode")) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) + api.nvim_input(':messages<CR>') + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end) - it("during press-enter prompt returns blocking=true", function() - nvim("ui_attach", 80, 20, {}) - eq({mode='n', blocking=false}, nvim("get_mode")) + it('during press-enter prompt returns blocking=true', function() + api.nvim_ui_attach(80, 20, {}) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) command("echom 'msg1'") command("echom 'msg2'") command("echom 'msg3'") command("echom 'msg4'") command("echom 'msg5'") - eq({mode='n', blocking=false}, nvim("get_mode")) - nvim("input", ":messages<CR>") - eq({mode='r', blocking=true}, nvim("get_mode")) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) + api.nvim_input(':messages<CR>') + eq({ mode = 'r', blocking = true }, api.nvim_get_mode()) end) - it("during getchar() returns blocking=false", function() - nvim("input", ":let g:test_input = nr2char(getchar())<CR>") + it('during getchar() returns blocking=false', function() + api.nvim_input(':let g:test_input = nr2char(getchar())<CR>') -- Events are enabled during getchar(), RPC calls are *not* blocked. #5384 - eq({mode='n', blocking=false}, nvim("get_mode")) - eq(0, nvim("eval", "exists('g:test_input')")) - nvim("input", "J") - eq("J", nvim("eval", "g:test_input")) - eq({mode='n', blocking=false}, nvim("get_mode")) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) + eq(0, api.nvim_eval("exists('g:test_input')")) + api.nvim_input('J') + eq('J', api.nvim_eval('g:test_input')) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end) -- TODO: bug #6247#issuecomment-286403810 - it("batched with input", function() - nvim("ui_attach", 80, 20, {}) - eq({mode='n', blocking=false}, nvim("get_mode")) + it('batched with input', function() + api.nvim_ui_attach(80, 20, {}) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) command("echom 'msg1'") command("echom 'msg2'") command("echom 'msg3'") @@ -1752,44 +1906,48 @@ describe('API', function() command("echom 'msg5'") local req = { - {'nvim_get_mode', {}}, - {'nvim_input', {':messages<CR>'}}, - {'nvim_get_mode', {}}, - {'nvim_eval', {'1'}}, + { 'nvim_get_mode', {} }, + { 'nvim_input', { ':messages<CR>' } }, + { 'nvim_get_mode', {} }, + { 'nvim_eval', { '1' } }, } - eq({ { {mode='n', blocking=false}, - 13, - {mode='n', blocking=false}, -- TODO: should be blocked=true ? - 1 }, - NIL}, meths.call_atomic(req)) - eq({mode='r', blocking=true}, nvim("get_mode")) + eq({ + { + { mode = 'n', blocking = false }, + 13, + { mode = 'n', blocking = false }, -- TODO: should be blocked=true ? + 1, + }, + NIL, + }, api.nvim_call_atomic(req)) + eq({ mode = 'r', blocking = true }, api.nvim_get_mode()) end) - it("during insert-mode map-pending, returns blocking=true #6166", function() - command("inoremap xx foo") - nvim("input", "ix") - eq({mode='i', blocking=true}, nvim("get_mode")) + it('during insert-mode map-pending, returns blocking=true #6166', function() + command('inoremap xx foo') + api.nvim_input('ix') + eq({ mode = 'i', blocking = true }, api.nvim_get_mode()) end) - it("during normal-mode gU, returns blocking=false #6166", function() - nvim("input", "gu") - eq({mode='no', blocking=false}, nvim("get_mode")) + it('during normal-mode gU, returns blocking=false #6166', function() + api.nvim_input('gu') + eq({ mode = 'no', blocking = false }, api.nvim_get_mode()) end) it("at '-- More --' prompt returns blocking=true #11899", function() command('set more') feed(':digraphs<cr>') - eq({mode='rm', blocking=true}, nvim("get_mode")) + eq({ mode = 'rm', blocking = true }, api.nvim_get_mode()) end) it('after <Nop> mapping returns blocking=false #17257', function() command('nnoremap <F2> <Nop>') feed('<F2>') - eq({mode='n', blocking=false}, nvim("get_mode")) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end) it('after empty string <expr> mapping returns blocking=false #17257', function() command('nnoremap <expr> <F2> ""') feed('<F2>') - eq({mode='n', blocking=false}, nvim("get_mode")) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) end) end) @@ -1798,16 +1956,16 @@ describe('API', function() helpers.insert([[ FIRST LINE SECOND LINE]]) - nvim('input', 'gg') - nvim('input', 'gu') + api.nvim_input('gg') + api.nvim_input('gu') -- Make any RPC request (can be non-async: op-pending does not block). - nvim('get_current_buf') + api.nvim_get_current_buf() -- Buffer should not change. expect([[ FIRST LINE SECOND LINE]]) -- Now send input to complete the operator. - nvim('input', 'j') + api.nvim_input('j') expect([[ first line second line]]) @@ -1821,7 +1979,7 @@ describe('API', function() feed('ia<cr>b<cr>c<cr><Esc>kkk') feed('d') -- Make any RPC request (can be non-async: op-pending does not block). - nvim('get_current_buf') + api.nvim_get_current_buf() screen:expect([[ ^a$ | b$ | @@ -1835,12 +1993,12 @@ describe('API', function() helpers.insert([[ FIRST LINE SECOND LINE]]) - nvim('input', 'gg') - nvim('input', 'd') + api.nvim_input('gg') + api.nvim_input('d') -- Make any RPC request (must be async, because map-pending blocks). - nvim('get_api_info') + api.nvim_get_api_info() -- Send input to complete the mapping. - nvim('input', 'd') + api.nvim_input('d') expect([[ FIRST LINE SECOND LINE]]) @@ -1853,11 +2011,11 @@ describe('API', function() helpers.insert([[ FIRST LINE SECOND LINE]]) - nvim('input', 'ix') + api.nvim_input('ix') -- Make any RPC request (must be async, because map-pending blocks). - nvim('get_api_info') + api.nvim_get_api_info() -- Send input to complete the mapping. - nvim('input', 'x') + api.nvim_input('x') expect([[ FIRST LINE SECOND LINfooE]]) @@ -1865,158 +2023,168 @@ describe('API', function() it('does not interrupt Insert mode i_CTRL-O #10035', function() feed('iHello World<c-o>') - eq({mode='niI', blocking=false}, meths.get_mode()) -- fast event - eq(2, eval('1+1')) -- causes K_EVENT key - eq({mode='niI', blocking=false}, meths.get_mode()) -- still in ctrl-o mode + eq({ mode = 'niI', blocking = false }, api.nvim_get_mode()) -- fast event + eq(2, eval('1+1')) -- causes K_EVENT key + eq({ mode = 'niI', blocking = false }, api.nvim_get_mode()) -- still in ctrl-o mode feed('dd') - eq({mode='i', blocking=false}, meths.get_mode()) -- left ctrl-o mode + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- left ctrl-o mode expect('') -- executed the command end) it('does not interrupt Select mode v_CTRL-O #15688', function() feed('iHello World<esc>gh<c-o>') - eq({mode='vs', blocking=false}, meths.get_mode()) -- fast event - eq({mode='vs', blocking=false}, meths.get_mode()) -- again #15288 - eq(2, eval('1+1')) -- causes K_EVENT key - eq({mode='vs', blocking=false}, meths.get_mode()) -- still in ctrl-o mode + eq({ mode = 'vs', blocking = false }, api.nvim_get_mode()) -- fast event + eq({ mode = 'vs', blocking = false }, api.nvim_get_mode()) -- again #15288 + eq(2, eval('1+1')) -- causes K_EVENT key + eq({ mode = 'vs', blocking = false }, api.nvim_get_mode()) -- still in ctrl-o mode feed('^') - eq({mode='s', blocking=false}, meths.get_mode()) -- left ctrl-o mode + eq({ mode = 's', blocking = false }, api.nvim_get_mode()) -- left ctrl-o mode feed('h') - eq({mode='i', blocking=false}, meths.get_mode()) -- entered insert mode - expect('h') -- selection is the whole line and is replaced + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- entered insert mode + expect('h') -- selection is the whole line and is replaced end) it('does not interrupt Insert mode i_0_CTRL-D #13997', function() command('set timeoutlen=9999') feed('i<Tab><Tab>a0') - eq(2, eval('1+1')) -- causes K_EVENT key + eq(2, eval('1+1')) -- causes K_EVENT key feed('<C-D>') - expect('a') -- recognized i_0_CTRL-D + expect('a') -- recognized i_0_CTRL-D end) it("does not interrupt with 'digraph'", function() command('set digraph') feed('i,') - eq(2, eval('1+1')) -- causes K_EVENT key + eq(2, eval('1+1')) -- causes K_EVENT key feed('<BS>') - eq(2, eval('1+1')) -- causes K_EVENT key + eq(2, eval('1+1')) -- causes K_EVENT key feed('.') - expect('…') -- digraph ",." worked + expect('…') -- digraph ",." worked feed('<Esc>') feed(':,') - eq(2, eval('1+1')) -- causes K_EVENT key + eq(2, eval('1+1')) -- causes K_EVENT key feed('<BS>') - eq(2, eval('1+1')) -- causes K_EVENT key + eq(2, eval('1+1')) -- causes K_EVENT key feed('.') - eq('…', funcs.getcmdline()) -- digraph ",." worked + eq('…', fn.getcmdline()) -- digraph ",." worked end) end) describe('nvim_get_context', function() it('validation', function() - eq("Invalid key: 'blah'", - pcall_err(nvim, 'get_context', {blah={}})) - eq("Invalid 'types': expected Array, got Integer", - pcall_err(nvim, 'get_context', {types=42})) - eq("Invalid 'type': 'zub'", - pcall_err(nvim, 'get_context', {types={'jumps', 'zub', 'zam',}})) + eq("Invalid key: 'blah'", pcall_err(api.nvim_get_context, { blah = {} })) + eq( + "Invalid 'types': expected Array, got Integer", + pcall_err(api.nvim_get_context, { types = 42 }) + ) + eq( + "Invalid 'type': 'zub'", + pcall_err(api.nvim_get_context, { types = { 'jumps', 'zub', 'zam' } }) + ) end) it('returns map of current editor state', function() - local opts = {types={'regs', 'jumps', 'bufs', 'gvars'}} - eq({}, parse_context(nvim('get_context', {}))) + local opts = { types = { 'regs', 'jumps', 'bufs', 'gvars' } } + eq({}, parse_context(api.nvim_get_context({}))) feed('i1<cr>2<cr>3<c-[>ddddddqahjklquuu') feed('gg') feed('G') command('edit! BUF1') command('edit BUF2') - nvim('set_var', 'one', 1) - nvim('set_var', 'Two', 2) - nvim('set_var', 'THREE', 3) + api.nvim_set_var('one', 1) + api.nvim_set_var('Two', 2) + api.nvim_set_var('THREE', 3) local expected_ctx = { ['regs'] = { - {['rt'] = 1, ['rc'] = {'1'}, ['n'] = 49, ['ru'] = true}, - {['rt'] = 1, ['rc'] = {'2'}, ['n'] = 50}, - {['rt'] = 1, ['rc'] = {'3'}, ['n'] = 51}, - {['rc'] = {'hjkl'}, ['n'] = 97}, + { ['rt'] = 1, ['rc'] = { '1' }, ['n'] = 49, ['ru'] = true }, + { ['rt'] = 1, ['rc'] = { '2' }, ['n'] = 50 }, + { ['rt'] = 1, ['rc'] = { '3' }, ['n'] = 51 }, + { ['rc'] = { 'hjkl' }, ['n'] = 97 }, }, - ['jumps'] = eval(([[ + ['jumps'] = eval((([[ filter(map(add( getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }), 'filter( { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum }, { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)') - ]]):gsub('\n', '')), + ]]):gsub('\n', ''))), ['bufs'] = eval([[ filter(map(getbufinfo(), '{ "f": v:val.name }'), '!empty(v:val.f)') ]]), - ['gvars'] = {{'one', 1}, {'Two', 2}, {'THREE', 3}}, + ['gvars'] = { { 'one', 1 }, { 'Two', 2 }, { 'THREE', 3 } }, } - eq(expected_ctx, parse_context(nvim('get_context', opts))) - eq(expected_ctx, parse_context(nvim('get_context', {}))) - eq(expected_ctx, parse_context(nvim('get_context', {types={}}))) + eq(expected_ctx, parse_context(api.nvim_get_context(opts))) + eq(expected_ctx, parse_context(api.nvim_get_context({}))) + eq(expected_ctx, parse_context(api.nvim_get_context({ types = {} }))) end) end) describe('nvim_load_context', function() it('sets current editor state to given context dictionary', function() - local opts = {types={'regs', 'jumps', 'bufs', 'gvars'}} - eq({}, parse_context(nvim('get_context', opts))) + local opts = { types = { 'regs', 'jumps', 'bufs', 'gvars' } } + eq({}, parse_context(api.nvim_get_context(opts))) - nvim('set_var', 'one', 1) - nvim('set_var', 'Two', 2) - nvim('set_var', 'THREE', 3) - local ctx = nvim('get_context', opts) - nvim('set_var', 'one', 'a') - nvim('set_var', 'Two', 'b') - nvim('set_var', 'THREE', 'c') - eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]')) - nvim('load_context', ctx) - eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]')) + api.nvim_set_var('one', 1) + api.nvim_set_var('Two', 2) + api.nvim_set_var('THREE', 3) + local ctx = api.nvim_get_context(opts) + api.nvim_set_var('one', 'a') + api.nvim_set_var('Two', 'b') + api.nvim_set_var('THREE', 'c') + eq({ 'a', 'b', 'c' }, eval('[g:one, g:Two, g:THREE]')) + api.nvim_load_context(ctx) + eq({ 1, 2, 3 }, eval('[g:one, g:Two, g:THREE]')) end) it('errors when context dictionary is invalid', function() - eq('E474: Failed to convert list to msgpack string buffer', - pcall_err(nvim, 'load_context', { regs = { {} }, jumps = { {} } })) - eq("Empty dictionary keys aren't allowed", - pcall_err(nvim, 'load_context', { regs = { { [''] = '' } } })) + eq( + 'E474: Failed to convert list to msgpack string buffer', + pcall_err(api.nvim_load_context, { regs = { {} }, jumps = { {} } }) + ) + eq( + 'E474: Failed to convert list to msgpack string buffer', + pcall_err(api.nvim_load_context, { regs = { { [''] = '' } } }) + ) end) end) describe('nvim_replace_termcodes', function() it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function() - eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true)) + eq('\128\254X', helpers.api.nvim_replace_termcodes('\128', true, true, true)) end) it('leaves non-K_SPECIAL string unchanged', function() - eq('abc', helpers.nvim('replace_termcodes', 'abc', true, true, true)) + eq('abc', helpers.api.nvim_replace_termcodes('abc', true, true, true)) end) it('converts <expressions>', function() - eq('\\', helpers.nvim('replace_termcodes', '<Leader>', true, true, true)) + eq('\\', helpers.api.nvim_replace_termcodes('<Leader>', true, true, true)) end) it('converts <LeftMouse> to K_SPECIAL KS_EXTRA KE_LEFTMOUSE', function() -- K_SPECIAL KS_EXTRA KE_LEFTMOUSE -- 0x80 0xfd 0x2c -- 128 253 44 - eq('\128\253\44', helpers.nvim('replace_termcodes', - '<LeftMouse>', true, true, true)) + eq('\128\253\44', helpers.api.nvim_replace_termcodes('<LeftMouse>', true, true, true)) end) it('converts keycodes', function() - eq('\nx\27x\rx<x', helpers.nvim('replace_termcodes', - '<NL>x<Esc>x<CR>x<lt>x', true, true, true)) + eq( + '\nx\27x\rx<x', + helpers.api.nvim_replace_termcodes('<NL>x<Esc>x<CR>x<lt>x', true, true, true) + ) end) it('does not convert keycodes if special=false', function() - eq('<NL>x<Esc>x<CR>x<lt>x', helpers.nvim('replace_termcodes', - '<NL>x<Esc>x<CR>x<lt>x', true, true, false)) + eq( + '<NL>x<Esc>x<CR>x<lt>x', + helpers.api.nvim_replace_termcodes('<NL>x<Esc>x<CR>x<lt>x', true, true, false) + ) end) it('does not crash when transforming an empty string', function() @@ -2027,13 +2195,13 @@ describe('API', function() -- then `return str` in vim_replace_termcodes body will make Neovim free -- `str.data` twice: once when freeing arguments, then when freeing return -- value. - eq('', meths.replace_termcodes('', true, true, true)) + eq('', api.nvim_replace_termcodes('', true, true, true)) end) -- Not exactly the case, as nvim_replace_termcodes() escapes K_SPECIAL in Unicode it('translates the result of keytrans() on string with 0x80 byte back', function() local s = 'ff\128\253\097tt' - eq(s, meths.replace_termcodes(funcs.keytrans(s), true, true, true)) + eq(s, api.nvim_replace_termcodes(fn.keytrans(s), true, true, true)) end) end) @@ -2041,15 +2209,15 @@ describe('API', function() it('K_SPECIAL escaping', function() local function on_setup() -- notice the special char(…) \xe2\80\xa6 - nvim('feedkeys', ':let x1="…"\n', '', true) + api.nvim_feedkeys(':let x1="…"\n', '', true) -- Both nvim_replace_termcodes and nvim_feedkeys escape \x80 - local inp = helpers.nvim('replace_termcodes', ':let x2="…"<CR>', true, true, true) - nvim('feedkeys', inp, '', true) -- escape_ks=true + local inp = helpers.api.nvim_replace_termcodes(':let x2="…"<CR>', true, true, true) + api.nvim_feedkeys(inp, '', true) -- escape_ks=true -- nvim_feedkeys with K_SPECIAL escaping disabled - inp = helpers.nvim('replace_termcodes', ':let x3="…"<CR>', true, true, true) - nvim('feedkeys', inp, '', false) -- escape_ks=false + inp = helpers.api.nvim_replace_termcodes(':let x3="…"<CR>', true, true, true) + api.nvim_feedkeys(inp, '', false) -- escape_ks=false helpers.stop() end @@ -2057,10 +2225,10 @@ describe('API', function() -- spin the loop a bit helpers.run(nil, nil, on_setup) - eq('…', nvim('get_var', 'x1')) + eq('…', api.nvim_get_var('x1')) -- Because of the double escaping this is neq - neq('…', nvim('get_var', 'x2')) - eq('…', nvim('get_var', 'x3')) + neq('…', api.nvim_get_var('x2')) + eq('…', api.nvim_get_var('x3')) end) end) @@ -2071,10 +2239,10 @@ describe('API', function() screen = Screen.new(40, 8) screen:attach() screen:set_default_attr_ids({ - [0] = {bold = true, foreground = Screen.colors.Blue}, - [1] = {bold = true, foreground = Screen.colors.SeaGreen}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Blue}, + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { bold = true, foreground = Screen.colors.SeaGreen }, + [2] = { bold = true, reverse = true }, + [3] = { foreground = Screen.colors.Blue }, }) end) @@ -2095,47 +2263,48 @@ describe('API', function() silent! call nvim_out_write("\n") redir END ]]) - eq('\naaa\n' .. ('a'):rep(5002) .. '\naaa', meths.get_var('out')) + eq('\naaa\n' .. ('a'):rep(5002) .. '\naaa', api.nvim_get_var('out')) end) it('blank line in message', function() feed([[:call nvim_out_write("\na\n")<CR>]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*3 {2: }| | a | {1:Press ENTER or type command to continue}^ | - ]]} + ]], + } feed('<CR>') feed([[:call nvim_out_write("b\n\nc\n")<CR>]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| + {0:~ }|*2 {2: }| b | | c | {1:Press ENTER or type command to continue}^ | - ]]} + ]], + } end) it('NUL bytes in message', function() feed([[:lua vim.api.nvim_out_write('aaa\0bbb\0\0ccc\nddd\0\0\0eee\n')<CR>]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*3 {2: }| aaa{3:^@}bbb{3:^@^@}ccc | ddd{3:^@^@^@}eee | {1:Press ENTER or type command to continue}^ | - ]]} + ]], + } end) end) @@ -2146,34 +2315,27 @@ describe('API', function() screen = Screen.new(40, 8) screen:attach() screen:set_default_attr_ids({ - [0] = {bold=true, foreground=Screen.colors.Blue}, - [1] = {foreground = Screen.colors.White, background = Screen.colors.Red}, - [2] = {bold = true, foreground = Screen.colors.SeaGreen}, - [3] = {bold = true, reverse = true}, + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { foreground = Screen.colors.White, background = Screen.colors.Red }, + [2] = { bold = true, foreground = Screen.colors.SeaGreen }, + [3] = { bold = true, reverse = true }, }) end) it('can show one line', function() - nvim_async('err_write', 'has bork\n') + async_meths.nvim_err_write('has bork\n') screen:expect([[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*6 {1:has bork} | ]]) end) it('shows return prompt when more than &cmdheight lines', function() - nvim_async('err_write', 'something happened\nvery bad\n') + async_meths.nvim_err_write('something happened\nvery bad\n') screen:expect([[ | - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*3 {3: }| {1:something happened} | {1:very bad} | @@ -2182,7 +2344,7 @@ describe('API', function() end) it('shows return prompt after all lines are shown', function() - nvim_async('err_write', 'FAILURE\nERROR\nEXCEPTION\nTRACEBACK\n') + async_meths.nvim_err_write('FAILURE\nERROR\nEXCEPTION\nTRACEBACK\n') screen:expect([[ | {0:~ }| @@ -2197,47 +2359,40 @@ describe('API', function() it('handles multiple calls', function() -- without linebreak text is joined to one line - nvim_async('err_write', 'very ') - nvim_async('err_write', 'fail\n') + async_meths.nvim_err_write('very ') + async_meths.nvim_err_write('fail\n') screen:expect([[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*6 {1:very fail} | ]]) helpers.poke_eventloop() -- shows up to &cmdheight lines - nvim_async('err_write', 'more fail\ntoo fail\n') + async_meths.nvim_err_write('more fail\ntoo fail\n') screen:expect([[ | - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*3 {3: }| {1:more fail} | {1:too fail} | {2:Press ENTER or type command to continue}^ | ]]) - feed('<cr>') -- exit the press ENTER screen + feed('<cr>') -- exit the press ENTER screen end) it('NUL bytes in message', function() - nvim_async('err_write', 'aaa\0bbb\0\0ccc\nddd\0\0\0eee\n') - screen:expect{grid=[[ + async_meths.nvim_err_write('aaa\0bbb\0\0ccc\nddd\0\0\0eee\n') + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*3 {3: }| {1:aaa^@bbb^@^@ccc} | {1:ddd^@^@^@eee} | {2:Press ENTER or type command to continue}^ | - ]]} + ]], + } end) end) @@ -2248,15 +2403,15 @@ describe('API', function() screen = Screen.new(40, 8) screen:attach() screen:set_default_attr_ids({ - [0] = {bold=true, foreground=Screen.colors.Blue}, - [1] = {foreground = Screen.colors.White, background = Screen.colors.Red}, - [2] = {bold = true, foreground = Screen.colors.SeaGreen}, - [3] = {bold = true, reverse = true}, + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { foreground = Screen.colors.White, background = Screen.colors.Red }, + [2] = { bold = true, foreground = Screen.colors.SeaGreen }, + [3] = { bold = true, reverse = true }, }) end) it('shows only one return prompt after all lines are shown', function() - nvim_async('err_writeln', 'FAILURE\nERROR\nEXCEPTION\nTRACEBACK') + async_meths.nvim_err_writeln('FAILURE\nERROR\nEXCEPTION\nTRACEBACK') screen:expect([[ | {0:~ }| @@ -2270,12 +2425,7 @@ describe('API', function() feed('<CR>') screen:expect([[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*6 | ]]) end) @@ -2299,116 +2449,126 @@ describe('API', function() } it('returns {} for invalid channel', function() - eq({}, meths.get_chan_info(0)) - eq({}, meths.get_chan_info(-1)) + eq({}, api.nvim_get_chan_info(-1)) -- more preallocated numbers might be added, try something high - eq({}, meths.get_chan_info(10)) + eq({}, api.nvim_get_chan_info(10)) end) it('stream=stdio channel', function() - eq({[1]=testinfo,[2]=stderr}, meths.list_chans()) - eq(testinfo, meths.get_chan_info(1)) - eq(stderr, meths.get_chan_info(2)) - - meths.set_client_info("functionaltests", - {major=0, minor=3, patch=17}, - 'ui', - {do_stuff={n_args={2,3}}}, - {license= 'Apache2'}) + eq({ [1] = testinfo, [2] = stderr }, api.nvim_list_chans()) + -- 0 should return current channel + eq(testinfo, api.nvim_get_chan_info(0)) + eq(testinfo, api.nvim_get_chan_info(1)) + eq(stderr, api.nvim_get_chan_info(2)) + + api.nvim_set_client_info( + 'functionaltests', + { major = 0, minor = 3, patch = 17 }, + 'ui', + { do_stuff = { n_args = { 2, 3 } } }, + { license = 'Apache2' } + ) local info = { stream = 'stdio', id = 1, mode = 'rpc', client = { - name='functionaltests', - version={major=0, minor=3, patch=17}, - type='ui', - methods={do_stuff={n_args={2,3}}}, - attributes={license='Apache2'}, + name = 'functionaltests', + version = { major = 0, minor = 3, patch = 17 }, + type = 'ui', + methods = { do_stuff = { n_args = { 2, 3 } } }, + attributes = { license = 'Apache2' }, }, } - eq({info=info}, meths.get_var("info_event")) - eq({[1]=info, [2]=stderr}, meths.list_chans()) - eq(info, meths.get_chan_info(1)) + eq({ info = info }, api.nvim_get_var('info_event')) + eq({ [1] = info, [2] = stderr }, api.nvim_list_chans()) + eq(info, api.nvim_get_chan_info(1)) end) it('stream=job channel', function() eq(3, eval("jobstart(['cat'], {'rpc': v:true})")) local catpath = eval('exepath("cat")') local info = { - stream='job', - id=3, - argv={ catpath }, - mode='rpc', - client={}, + stream = 'job', + id = 3, + argv = { catpath }, + mode = 'rpc', + client = {}, } - eq({info=info}, meths.get_var("opened_event")) - eq({[1]=testinfo,[2]=stderr,[3]=info}, meths.list_chans()) - eq(info, meths.get_chan_info(3)) - eval('rpcrequest(3, "nvim_set_client_info", "amazing-cat", {}, "remote",'.. - '{"nvim_command":{"n_args":1}},'.. -- and so on - '{"description":"The Amazing Cat"})') + eq({ info = info }, api.nvim_get_var('opened_event')) + eq({ [1] = testinfo, [2] = stderr, [3] = info }, api.nvim_list_chans()) + eq(info, api.nvim_get_chan_info(3)) + eval( + 'rpcrequest(3, "nvim_set_client_info", "amazing-cat", {}, "remote",' + .. '{"nvim_command":{"n_args":1}},' -- and so on + .. '{"description":"The Amazing Cat"})' + ) info = { - stream='job', - id=3, - argv={ catpath }, - mode='rpc', + stream = 'job', + id = 3, + argv = { catpath }, + mode = 'rpc', client = { - name='amazing-cat', - version={major=0}, - type='remote', - methods={nvim_command={n_args=1}}, - attributes={description="The Amazing Cat"}, + name = 'amazing-cat', + version = { major = 0 }, + type = 'remote', + methods = { nvim_command = { n_args = 1 } }, + attributes = { description = 'The Amazing Cat' }, }, } - eq({info=info}, meths.get_var("info_event")) - eq({[1]=testinfo,[2]=stderr,[3]=info}, meths.list_chans()) + eq({ info = info }, api.nvim_get_var('info_event')) + eq({ [1] = testinfo, [2] = stderr, [3] = info }, api.nvim_list_chans()) - eq("Vim:Error invoking 'nvim_set_current_buf' on channel 3 (amazing-cat):\nWrong type for argument 1 when calling nvim_set_current_buf, expecting Buffer", - pcall_err(eval, 'rpcrequest(3, "nvim_set_current_buf", -1)')) + eq( + "Vim:Error invoking 'nvim_set_current_buf' on channel 3 (amazing-cat):\nWrong type for argument 1 when calling nvim_set_current_buf, expecting Buffer", + pcall_err(eval, 'rpcrequest(3, "nvim_set_current_buf", -1)') + ) + eq(info, eval('rpcrequest(3, "nvim_get_chan_info", 0)')) end) it('stream=job :terminal channel', function() command(':terminal') - eq({id=1}, meths.get_current_buf()) - eq(3, meths.get_option_value('channel', {buf=1})) + eq(1, api.nvim_get_current_buf()) + eq(3, api.nvim_get_option_value('channel', { buf = 1 })) local info = { - stream='job', - id=3, - argv={ eval('exepath(&shell)') }, - mode='terminal', + stream = 'job', + id = 3, + argv = { eval('exepath(&shell)') }, + mode = 'terminal', buffer = 1, - pty='?', + pty = '?', } - local event = meths.get_var("opened_event") + local event = api.nvim_get_var('opened_event') if not is_os('win') then info.pty = event.info.pty - neq(nil, string.match(info.pty, "^/dev/")) + neq(nil, string.match(info.pty, '^/dev/')) end - eq({info=info}, event) - info.buffer = {id=1} - eq({[1]=testinfo,[2]=stderr,[3]=info}, meths.list_chans()) - eq(info, meths.get_chan_info(3)) + eq({ info = info }, event) + info.buffer = 1 + eq({ [1] = testinfo, [2] = stderr, [3] = info }, api.nvim_list_chans()) + eq(info, api.nvim_get_chan_info(3)) -- :terminal with args + running process. - command(':exe "terminal" shellescape(v:progpath) "-u NONE -i NONE"') - eq(-1, eval('jobwait([&channel], 0)[0]')) -- Running? + command('enew') + local progpath_esc = eval('shellescape(v:progpath)') + fn.termopen(('%s -u NONE -i NONE'):format(progpath_esc), { + env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }, + }) + eq(-1, eval('jobwait([&channel], 0)[0]')) -- Running? local expected2 = { stream = 'job', id = 4, - argv = ( - is_os('win') and { - eval('&shell'), - '/s', - '/c', - fmt('"%s -u NONE -i NONE"', eval('shellescape(v:progpath)')), - } or { - eval('&shell'), - eval('&shellcmdflag'), - fmt('%s -u NONE -i NONE', eval('shellescape(v:progpath)')), - } - ), + argv = (is_os('win') and { + eval('&shell'), + '/s', + '/c', + fmt('"%s -u NONE -i NONE"', progpath_esc), + } or { + eval('&shell'), + eval('&shellcmdflag'), + fmt('%s -u NONE -i NONE', progpath_esc), + }), mode = 'terminal', buffer = 2, pty = '?', @@ -2419,163 +2579,172 @@ describe('API', function() -- :terminal with args + stopped process. eq(1, eval('jobstop(&channel)')) - eval('jobwait([&channel], 1000)') -- Wait. - expected2.pty = (is_os('win') and '?' or '') -- pty stream was closed. + eval('jobwait([&channel], 1000)') -- Wait. + expected2.pty = (is_os('win') and '?' or '') -- pty stream was closed. eq(expected2, eval('nvim_get_chan_info(&channel)')) end) end) describe('nvim_call_atomic', function() it('works', function() - meths.buf_set_lines(0, 0, -1, true, {'first'}) + api.nvim_buf_set_lines(0, 0, -1, true, { 'first' }) local req = { - {'nvim_get_current_line', {}}, - {'nvim_set_current_line', {'second'}}, + { 'nvim_get_current_line', {} }, + { 'nvim_set_current_line', { 'second' } }, } - eq({{'first', NIL}, NIL}, meths.call_atomic(req)) - eq({'second'}, meths.buf_get_lines(0, 0, -1, true)) + eq({ { 'first', NIL }, NIL }, api.nvim_call_atomic(req)) + eq({ 'second' }, api.nvim_buf_get_lines(0, 0, -1, true)) end) it('allows multiple return values', function() local req = { - {'nvim_set_var', {'avar', true}}, - {'nvim_set_var', {'bvar', 'string'}}, - {'nvim_get_var', {'avar'}}, - {'nvim_get_var', {'bvar'}}, + { 'nvim_set_var', { 'avar', true } }, + { 'nvim_set_var', { 'bvar', 'string' } }, + { 'nvim_get_var', { 'avar' } }, + { 'nvim_get_var', { 'bvar' } }, } - eq({{NIL, NIL, true, 'string'}, NIL}, meths.call_atomic(req)) + eq({ { NIL, NIL, true, 'string' }, NIL }, api.nvim_call_atomic(req)) end) it('is aborted by errors in call', function() - local error_types = meths.get_api_info()[2].error_types + local error_types = api.nvim_get_api_info()[2].error_types local req = { - {'nvim_set_var', {'one', 1}}, - {'nvim_buf_set_lines', {}}, - {'nvim_set_var', {'two', 2}}, + { 'nvim_set_var', { 'one', 1 } }, + { 'nvim_buf_set_lines', {} }, + { 'nvim_set_var', { 'two', 2 } }, } - eq({{NIL}, {1, error_types.Exception.id, - 'Wrong number of arguments: expecting 5 but got 0'}}, - meths.call_atomic(req)) - eq(1, meths.get_var('one')) - eq(false, pcall(meths.get_var, 'two')) + eq({ + { NIL }, + { + 1, + error_types.Exception.id, + 'Wrong number of arguments: expecting 5 but got 0', + }, + }, api.nvim_call_atomic(req)) + eq(1, api.nvim_get_var('one')) + eq(false, pcall(api.nvim_get_var, 'two')) -- still returns all previous successful calls req = { - {'nvim_set_var', {'avar', 5}}, - {'nvim_set_var', {'bvar', 'string'}}, - {'nvim_get_var', {'avar'}}, - {'nvim_buf_get_lines', {0, 10, 20, true}}, - {'nvim_get_var', {'bvar'}}, + { 'nvim_set_var', { 'avar', 5 } }, + { 'nvim_set_var', { 'bvar', 'string' } }, + { 'nvim_get_var', { 'avar' } }, + { 'nvim_buf_get_lines', { 0, 10, 20, true } }, + { 'nvim_get_var', { 'bvar' } }, } - eq({{NIL, NIL, 5}, {3, error_types.Validation.id, 'Index out of bounds'}}, - meths.call_atomic(req)) + eq( + { { NIL, NIL, 5 }, { 3, error_types.Validation.id, 'Index out of bounds' } }, + api.nvim_call_atomic(req) + ) req = { - {'i_am_not_a_method', {'xx'}}, - {'nvim_set_var', {'avar', 10}}, + { 'i_am_not_a_method', { 'xx' } }, + { 'nvim_set_var', { 'avar', 10 } }, } - eq({{}, {0, error_types.Exception.id, 'Invalid method: i_am_not_a_method'}}, - meths.call_atomic(req)) - eq(5, meths.get_var('avar')) + eq( + { {}, { 0, error_types.Exception.id, 'Invalid method: i_am_not_a_method' } }, + api.nvim_call_atomic(req) + ) + eq(5, api.nvim_get_var('avar')) end) it('validation', function() local req = { - {'nvim_set_var', {'avar', 1}}, - {'nvim_set_var'}, - {'nvim_set_var', {'avar', 2}}, + { 'nvim_set_var', { 'avar', 1 } }, + { 'nvim_set_var' }, + { 'nvim_set_var', { 'avar', 2 } }, } - eq("Invalid 'calls' item: expected 2-item Array", - pcall_err(meths.call_atomic, req)) + eq("Invalid 'calls' item: expected 2-item Array", pcall_err(api.nvim_call_atomic, req)) -- call before was done, but not after - eq(1, meths.get_var('avar')) + eq(1, api.nvim_get_var('avar')) req = { { 'nvim_set_var', { 'bvar', { 2, 3 } } }, 12, } - eq("Invalid 'calls' item: expected Array, got Integer", - pcall_err(meths.call_atomic, req)) - eq({2,3}, meths.get_var('bvar')) + eq("Invalid 'calls' item: expected Array, got Integer", pcall_err(api.nvim_call_atomic, req)) + eq({ 2, 3 }, api.nvim_get_var('bvar')) req = { - {'nvim_set_current_line', 'little line'}, - {'nvim_set_var', {'avar', 3}}, + { 'nvim_set_current_line', 'little line' }, + { 'nvim_set_var', { 'avar', 3 } }, } - eq("Invalid call args: expected Array, got String", - pcall_err(meths.call_atomic, req)) + eq('Invalid call args: expected Array, got String', pcall_err(api.nvim_call_atomic, req)) -- call before was done, but not after - eq(1, meths.get_var('avar')) - eq({''}, meths.buf_get_lines(0, 0, -1, true)) + eq(1, api.nvim_get_var('avar')) + eq({ '' }, api.nvim_buf_get_lines(0, 0, -1, true)) end) end) describe('nvim_list_runtime_paths', function() setup(function() local pathsep = helpers.get_pathsep() - mkdir_p('Xtest'..pathsep..'a') - mkdir_p('Xtest'..pathsep..'b') + mkdir_p('Xtest' .. pathsep .. 'a') + mkdir_p('Xtest' .. pathsep .. 'b') end) teardown(function() rmdir 'Xtest' end) before_each(function() - meths.set_current_dir 'Xtest' + api.nvim_set_current_dir 'Xtest' end) it('returns nothing with empty &runtimepath', function() - meths.set_option_value('runtimepath', '', {}) - eq({}, meths.list_runtime_paths()) + api.nvim_set_option_value('runtimepath', '', {}) + eq({}, api.nvim_list_runtime_paths()) end) it('returns single runtimepath', function() - meths.set_option_value('runtimepath', 'a', {}) - eq({'a'}, meths.list_runtime_paths()) + api.nvim_set_option_value('runtimepath', 'a', {}) + eq({ 'a' }, api.nvim_list_runtime_paths()) end) it('returns two runtimepaths', function() - meths.set_option_value('runtimepath', 'a,b', {}) - eq({'a', 'b'}, meths.list_runtime_paths()) + api.nvim_set_option_value('runtimepath', 'a,b', {}) + eq({ 'a', 'b' }, api.nvim_list_runtime_paths()) end) it('returns empty strings when appropriate', function() - meths.set_option_value('runtimepath', 'a,,b', {}) - eq({'a', '', 'b'}, meths.list_runtime_paths()) - meths.set_option_value('runtimepath', ',a,b', {}) - eq({'', 'a', 'b'}, meths.list_runtime_paths()) + api.nvim_set_option_value('runtimepath', 'a,,b', {}) + eq({ 'a', '', 'b' }, api.nvim_list_runtime_paths()) + api.nvim_set_option_value('runtimepath', ',a,b', {}) + eq({ '', 'a', 'b' }, api.nvim_list_runtime_paths()) -- Trailing "," is ignored. Use ",," if you really really want CWD. - meths.set_option_value('runtimepath', 'a,b,', {}) - eq({'a', 'b'}, meths.list_runtime_paths()) - meths.set_option_value('runtimepath', 'a,b,,', {}) - eq({'a', 'b', ''}, meths.list_runtime_paths()) + api.nvim_set_option_value('runtimepath', 'a,b,', {}) + eq({ 'a', 'b' }, api.nvim_list_runtime_paths()) + api.nvim_set_option_value('runtimepath', 'a,b,,', {}) + eq({ 'a', 'b', '' }, api.nvim_list_runtime_paths()) end) it('truncates too long paths', function() local long_path = ('/a'):rep(8192) - meths.set_option_value('runtimepath', long_path, {}) - local paths_list = meths.list_runtime_paths() + api.nvim_set_option_value('runtimepath', long_path, {}) + local paths_list = api.nvim_list_runtime_paths() eq({}, paths_list) end) end) it('can throw exceptions', function() - local status, err = pcall(nvim, 'get_option_value', 'invalid-option', {}) + local status, err = pcall(api.nvim_get_option_value, 'invalid-option', {}) eq(false, status) ok(err:match("Unknown option 'invalid%-option'") ~= nil) end) it('does not truncate error message <1 MB #5984', function() - local very_long_name = 'A'..('x'):rep(10000)..'Z' - local status, err = pcall(nvim, 'get_option_value', very_long_name, {}) + local very_long_name = 'A' .. ('x'):rep(10000) .. 'Z' + local status, err = pcall(api.nvim_get_option_value, very_long_name, {}) eq(false, status) eq(very_long_name, err:match('Ax+Z?')) end) - it("does not leak memory on incorrect argument types", function() - local status, err = pcall(nvim, 'set_current_dir',{'not', 'a', 'dir'}) + it('does not leak memory on incorrect argument types', function() + local status, err = pcall(api.nvim_set_current_dir, { 'not', 'a', 'dir' }) eq(false, status) - ok(err:match(': Wrong type for argument 1 when calling nvim_set_current_dir, expecting String') ~= nil) + ok( + err:match(': Wrong type for argument 1 when calling nvim_set_current_dir, expecting String') + ~= nil + ) end) describe('nvim_parse_expression', function() before_each(function() - meths.set_option_value('isident', '', {}) + api.nvim_set_option_value('isident', '', {}) end) local function simplify_east_api_node(line, east_api_node) @@ -2589,21 +2758,26 @@ describe('API', function() end local typ = east_api_node.type if typ == 'Register' then - typ = typ .. ('(name=%s)'):format( - tostring(intchar2lua(east_api_node.name))) + typ = typ .. ('(name=%s)'):format(tostring(intchar2lua(east_api_node.name))) east_api_node.name = nil elseif typ == 'PlainIdentifier' then - typ = typ .. ('(scope=%s,ident=%s)'):format( - tostring(intchar2lua(east_api_node.scope)), east_api_node.ident) + typ = typ + .. ('(scope=%s,ident=%s)'):format( + tostring(intchar2lua(east_api_node.scope)), + east_api_node.ident + ) east_api_node.scope = nil east_api_node.ident = nil elseif typ == 'PlainKey' then typ = typ .. ('(key=%s)'):format(east_api_node.ident) east_api_node.ident = nil elseif typ == 'Comparison' then - typ = typ .. ('(type=%s,inv=%u,ccs=%s)'):format( - east_api_node.cmp_type, east_api_node.invert and 1 or 0, - east_api_node.ccs_strategy) + typ = typ + .. ('(type=%s,inv=%u,ccs=%s)'):format( + east_api_node.cmp_type, + east_api_node.invert and 1 or 0, + east_api_node.ccs_strategy + ) east_api_node.ccs_strategy = nil east_api_node.cmp_type = nil east_api_node.invert = nil @@ -2620,7 +2794,8 @@ describe('API', function() typ = ('%s(scope=%s,ident=%s)'):format( typ, tostring(intchar2lua(east_api_node.scope)), - east_api_node.ident) + east_api_node.ident + ) east_api_node.ident = nil east_api_node.scope = nil elseif typ == 'Environment' then @@ -2628,24 +2803,30 @@ describe('API', function() east_api_node.ident = nil elseif typ == 'Assignment' then local aug = east_api_node.augmentation - if aug == '' then aug = 'Plain' end + if aug == '' then + aug = 'Plain' + end typ = ('%s(%s)'):format(typ, aug) east_api_node.augmentation = nil end typ = ('%s:%u:%u:%s'):format( - typ, east_api_node.start[1], east_api_node.start[2], - line:sub(east_api_node.start[2] + 1, - east_api_node.start[2] + 1 + east_api_node.len - 1)) + typ, + east_api_node.start[1], + east_api_node.start[2], + line:sub(east_api_node.start[2] + 1, east_api_node.start[2] + 1 + east_api_node.len - 1) + ) assert(east_api_node.start[2] + east_api_node.len - 1 <= #line) for k, _ in pairs(east_api_node.start) do - assert(({true, true})[k]) + assert(({ true, true })[k]) end east_api_node.start = nil east_api_node.type = nil east_api_node.len = nil local can_simplify = true for _, _ in pairs(east_api_node) do - if can_simplify then can_simplify = false end + if can_simplify then + can_simplify = false + end end if can_simplify then return typ @@ -2662,7 +2843,7 @@ describe('API', function() east_api.err.message = nil end if east_api.ast then - east_api.ast = {simplify_east_api_node(line, east_api.ast)} + east_api.ast = { simplify_east_api_node(line, east_api.ast) } if #east_api.ast == 0 then east_api.ast = nil end @@ -2674,26 +2855,21 @@ describe('API', function() end local function simplify_east_hl(line, east_hl) for i, v in ipairs(east_hl) do - east_hl[i] = ('%s:%u:%u:%s'):format( - v[4], - v[1], - v[2], - line:sub(v[2] + 1, v[3])) + east_hl[i] = ('%s:%u:%u:%s'):format(v[4], v[1], v[2], line:sub(v[2] + 1, v[3])) end return east_hl end local FLAGS_TO_STR = { - [0] = "", - [1] = "m", - [2] = "E", - [3] = "mE", - [4] = "l", - [5] = "lm", - [6] = "lE", - [7] = "lmE", + [0] = '', + [1] = 'm', + [2] = 'E', + [3] = 'mE', + [4] = 'l', + [5] = 'lm', + [6] = 'lE', + [7] = 'lmE', } - local function _check_parsing(opts, str, exp_ast, exp_highlighting_fs, - nz_flags_exps) + local function _check_parsing(opts, str, exp_ast, exp_highlighting_fs, nz_flags_exps) if type(str) ~= 'string' then return end @@ -2701,7 +2877,7 @@ describe('API', function() nz_flags_exps = nz_flags_exps or {} for _, flags in ipairs(opts.flags) do local err, msg = pcall(function() - local east_api = meths.parse_expression(str, FLAGS_TO_STR[flags], true) + local east_api = api.nvim_parse_expression(str, FLAGS_TO_STR[flags], true) local east_hl = east_api.highlight east_api.highlight = nil local ast = simplify_east_api(str, east_api) @@ -2734,37 +2910,39 @@ describe('API', function() end) if not err then if type(msg) == 'table' then - local merr, new_msg = pcall( - format_string, 'table error:\n%s\n\n(%r)', msg.message, msg) + local merr, new_msg = pcall(format_string, 'table error:\n%s\n\n(%r)', msg.message, msg) if merr then msg = new_msg else - msg = format_string('table error without .message:\n(%r)', - msg) + msg = format_string('table error without .message:\n(%r)', msg) end elseif type(msg) ~= 'string' then msg = format_string('non-string non-table error:\n%r', msg) end - error(format_string('Error while processing test (%r, %s):\n%s', - str, FLAGS_TO_STR[flags], msg)) + error( + format_string( + 'Error while processing test (%r, %s):\n%s', + str, + FLAGS_TO_STR[flags], + msg + ) + ) end end end local function hl(group, str, shift) return function(next_col) local col = next_col + (shift or 0) - return (('%s:%u:%u:%s'):format( - 'Nvim' .. group, - 0, - col, - str)), (col + #str) + return (('%s:%u:%u:%s'):format('Nvim' .. group, 0, col, str)), (col + #str) end end local function fmtn(typ, args, rest) - if (typ == 'UnknownFigure' - or typ == 'DictLiteral' - or typ == 'CurlyBracesIdentifier' - or typ == 'Lambda') then + if + typ == 'UnknownFigure' + or typ == 'DictLiteral' + or typ == 'CurlyBracesIdentifier' + or typ == 'Lambda' + then return ('%s%s'):format(typ, rest) elseif typ == 'DoubleQuotedString' or typ == 'SingleQuotedString' then if args:sub(-4) == 'NULL' then @@ -2773,18 +2951,17 @@ describe('API', function() return ('%s(%s)%s'):format(typ, args, rest) end end - require('test.unit.viml.expressions.parser_tests')( - it, _check_parsing, hl, fmtn) + require('test.unit.viml.expressions.parser_tests')(it, _check_parsing, hl, fmtn) end) describe('nvim_list_uis', function() it('returns empty if --headless', function() -- Test runner defaults to --headless. - eq({}, nvim("list_uis")) + eq({}, api.nvim_list_uis()) end) it('returns attached UIs', function() local screen = Screen.new(20, 4) - screen:attach({override=true}) + screen:attach({ override = true }) local expected = { { chan = 1, @@ -2806,10 +2983,10 @@ describe('API', function() term_colors = 0, term_name = '', width = 20, - } + }, } - eq(expected, nvim("list_uis")) + eq(expected, api.nvim_list_uis()) screen:detach() screen = Screen.new(44, 99) @@ -2818,96 +2995,102 @@ describe('API', function() expected[1].override = false expected[1].width = 44 expected[1].height = 99 - eq(expected, nvim("list_uis")) + eq(expected, api.nvim_list_uis()) end) end) describe('nvim_create_namespace', function() it('works', function() - eq({}, meths.get_namespaces()) - eq(1, meths.create_namespace("ns-1")) - eq(2, meths.create_namespace("ns-2")) - eq(1, meths.create_namespace("ns-1")) - eq({["ns-1"]=1, ["ns-2"]=2}, meths.get_namespaces()) - eq(3, meths.create_namespace("")) - eq(4, meths.create_namespace("")) - eq({["ns-1"]=1, ["ns-2"]=2}, meths.get_namespaces()) + eq({}, api.nvim_get_namespaces()) + eq(1, api.nvim_create_namespace('ns-1')) + eq(2, api.nvim_create_namespace('ns-2')) + eq(1, api.nvim_create_namespace('ns-1')) + eq({ ['ns-1'] = 1, ['ns-2'] = 2 }, api.nvim_get_namespaces()) + eq(3, api.nvim_create_namespace('')) + eq(4, api.nvim_create_namespace('')) + eq({ ['ns-1'] = 1, ['ns-2'] = 2 }, api.nvim_get_namespaces()) end) end) describe('nvim_create_buf', function() it('works', function() - eq({id=2}, meths.create_buf(true, false)) - eq({id=3}, meths.create_buf(false, false)) - eq(' 1 %a "[No Name]" line 1\n'.. - ' 2 h "[No Name]" line 0', - meths.command_output("ls")) + eq(2, api.nvim_create_buf(true, false)) + eq(3, api.nvim_create_buf(false, false)) + eq( + ' 1 %a "[No Name]" line 1\n' + .. ' 2 h "[No Name]" line 0', + command_output('ls') + ) -- current buffer didn't change - eq({id=1}, meths.get_current_buf()) + eq(1, api.nvim_get_current_buf()) local screen = Screen.new(20, 4) screen:attach() - meths.buf_set_lines(2, 0, -1, true, {"some text"}) - meths.set_current_buf(2) - screen:expect([[ + api.nvim_buf_set_lines(2, 0, -1, true, { 'some text' }) + api.nvim_set_current_buf(2) + screen:expect( + [[ ^some text | - {1:~ }| - {1:~ }| + {1:~ }|*2 | - ]], { - [1] = {bold = true, foreground = Screen.colors.Blue1}, - }) + ]], + { + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + } + ) end) it('can change buftype before visiting', function() - meths.set_option_value("hidden", false, {}) - eq({id=2}, meths.create_buf(true, false)) - meths.set_option_value("buftype", "nofile", {buf=2}) - meths.buf_set_lines(2, 0, -1, true, {"test text"}) - command("split | buffer 2") - eq({id=2}, meths.get_current_buf()) + api.nvim_set_option_value('hidden', false, {}) + eq(2, api.nvim_create_buf(true, false)) + api.nvim_set_option_value('buftype', 'nofile', { buf = 2 }) + api.nvim_buf_set_lines(2, 0, -1, true, { 'test text' }) + command('split | buffer 2') + eq(2, api.nvim_get_current_buf()) -- if the buf_set_option("buftype") didn't work, this would error out. - command("close") - eq({id=1}, meths.get_current_buf()) + command('close') + eq(1, api.nvim_get_current_buf()) end) - it("does not trigger BufEnter, BufWinEnter", function() - command("let g:fired = v:false") - command("au BufEnter,BufWinEnter * let g:fired = v:true") + it('does not trigger BufEnter, BufWinEnter', function() + command('let g:fired = v:false') + command('au BufEnter,BufWinEnter * let g:fired = v:true') - eq({id=2}, meths.create_buf(true, false)) - meths.buf_set_lines(2, 0, -1, true, {"test", "text"}) + eq(2, api.nvim_create_buf(true, false)) + api.nvim_buf_set_lines(2, 0, -1, true, { 'test', 'text' }) eq(false, eval('g:fired')) end) it('TextChanged and TextChangedI do not trigger without changes', function() - local buf = meths.create_buf(true, false) + local buf = api.nvim_create_buf(true, false) command([[let g:changed = '']]) - meths.create_autocmd({'TextChanged', 'TextChangedI'}, { + api.nvim_create_autocmd({ 'TextChanged', 'TextChangedI' }, { buffer = buf, command = 'let g:changed ..= mode()', }) - meths.set_current_buf(buf) + api.nvim_set_current_buf(buf) feed('i') - eq('', meths.get_var('changed')) + eq('', api.nvim_get_var('changed')) end) it('scratch-buffer', function() - eq({id=2}, meths.create_buf(false, true)) - eq({id=3}, meths.create_buf(true, true)) - eq({id=4}, meths.create_buf(true, true)) + eq(2, api.nvim_create_buf(false, true)) + eq(3, api.nvim_create_buf(true, true)) + eq(4, api.nvim_create_buf(true, true)) local scratch_bufs = { 2, 3, 4 } - eq(' 1 %a "[No Name]" line 1\n'.. - ' 3 h "[Scratch]" line 0\n'.. - ' 4 h "[Scratch]" line 0', - exec_capture('ls')) + eq( + ' 1 %a "[No Name]" line 1\n' + .. ' 3 h "[Scratch]" line 0\n' + .. ' 4 h "[Scratch]" line 0', + exec_capture('ls') + ) -- current buffer didn't change - eq({id=1}, meths.get_current_buf()) + eq(1, api.nvim_get_current_buf()) local screen = Screen.new(20, 4) screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, + [1] = { bold = true, foreground = Screen.colors.Blue1 }, }) screen:attach() @@ -2915,35 +3098,33 @@ describe('API', function() -- Editing a scratch-buffer does NOT change its properties. -- local edited_buf = 2 - meths.buf_set_lines(edited_buf, 0, -1, true, {"some text"}) - for _,b in ipairs(scratch_bufs) do - eq('nofile', meths.get_option_value('buftype', {buf=b})) - eq('hide', meths.get_option_value('bufhidden', {buf=b})) - eq(false, meths.get_option_value('swapfile', {buf=b})) - eq(false, meths.get_option_value('modeline', {buf=b})) + api.nvim_buf_set_lines(edited_buf, 0, -1, true, { 'some text' }) + for _, b in ipairs(scratch_bufs) do + eq('nofile', api.nvim_get_option_value('buftype', { buf = b })) + eq('hide', api.nvim_get_option_value('bufhidden', { buf = b })) + eq(false, api.nvim_get_option_value('swapfile', { buf = b })) + eq(false, api.nvim_get_option_value('modeline', { buf = b })) end -- -- Visiting a scratch-buffer DOES NOT change its properties. -- - meths.set_current_buf(edited_buf) + api.nvim_set_current_buf(edited_buf) screen:expect([[ ^some text | - {1:~ }| - {1:~ }| + {1:~ }|*2 | ]]) - eq('nofile', meths.get_option_value('buftype', {buf=edited_buf})) - eq('hide', meths.get_option_value('bufhidden', {buf=edited_buf})) - eq(false, meths.get_option_value('swapfile', {buf=edited_buf})) - eq(false, meths.get_option_value('modeline', {buf=edited_buf})) + eq('nofile', api.nvim_get_option_value('buftype', { buf = edited_buf })) + eq('hide', api.nvim_get_option_value('bufhidden', { buf = edited_buf })) + eq(false, api.nvim_get_option_value('swapfile', { buf = edited_buf })) + eq(false, api.nvim_get_option_value('modeline', { buf = edited_buf })) -- Scratch buffer can be wiped without error. command('bwipe') screen:expect([[ ^ | - {1:~ }| - {1:~ }| + {1:~ }|*2 | ]]) end) @@ -2959,117 +3140,121 @@ describe('API', function() describe('nvim_get_runtime_file', function() local p = helpers.alter_slashes it('can find files', function() - eq({}, meths.get_runtime_file("bork.borkbork", false)) - eq({}, meths.get_runtime_file("bork.borkbork", true)) - eq(1, #meths.get_runtime_file("autoload/msgpack.vim", false)) - eq(1, #meths.get_runtime_file("autoload/msgpack.vim", true)) - local val = meths.get_runtime_file("autoload/remote/*.vim", true) + eq({}, api.nvim_get_runtime_file('bork.borkbork', false)) + eq({}, api.nvim_get_runtime_file('bork.borkbork', true)) + eq(1, #api.nvim_get_runtime_file('autoload/msgpack.vim', false)) + eq(1, #api.nvim_get_runtime_file('autoload/msgpack.vim', true)) + local val = api.nvim_get_runtime_file('autoload/remote/*.vim', true) eq(2, #val) - if endswith(val[1], "define.vim") then - ok(endswith(val[1], p"autoload/remote/define.vim")) - ok(endswith(val[2], p"autoload/remote/host.vim")) + if endswith(val[1], 'define.vim') then + ok(endswith(val[1], p 'autoload/remote/define.vim')) + ok(endswith(val[2], p 'autoload/remote/host.vim')) else - ok(endswith(val[1], p"autoload/remote/host.vim")) - ok(endswith(val[2], p"autoload/remote/define.vim")) + ok(endswith(val[1], p 'autoload/remote/host.vim')) + ok(endswith(val[2], p 'autoload/remote/define.vim')) end - val = meths.get_runtime_file("autoload/remote/*.vim", false) + val = api.nvim_get_runtime_file('autoload/remote/*.vim', false) eq(1, #val) - ok(endswith(val[1], p"autoload/remote/define.vim") - or endswith(val[1], p"autoload/remote/host.vim")) + ok( + endswith(val[1], p 'autoload/remote/define.vim') + or endswith(val[1], p 'autoload/remote/host.vim') + ) - val = meths.get_runtime_file("lua", true) + val = api.nvim_get_runtime_file('lua', true) eq(1, #val) - ok(endswith(val[1], p"lua")) + ok(endswith(val[1], p 'lua')) - val = meths.get_runtime_file("lua/vim", true) + val = api.nvim_get_runtime_file('lua/vim', true) eq(1, #val) - ok(endswith(val[1], p"lua/vim")) + ok(endswith(val[1], p 'lua/vim')) end) it('can find directories', function() - local val = meths.get_runtime_file("lua/", true) + local val = api.nvim_get_runtime_file('lua/', true) eq(1, #val) - ok(endswith(val[1], p"lua/")) + ok(endswith(val[1], p 'lua/')) - val = meths.get_runtime_file("lua/vim/", true) + val = api.nvim_get_runtime_file('lua/vim/', true) eq(1, #val) - ok(endswith(val[1], p"lua/vim/")) + ok(endswith(val[1], p 'lua/vim/')) - eq({}, meths.get_runtime_file("foobarlang/", true)) + eq({}, api.nvim_get_runtime_file('foobarlang/', true)) end) it('can handle bad patterns', function() skip(is_os('win')) - eq("Vim:E220: Missing }.", pcall_err(meths.get_runtime_file, "{", false)) + eq('Vim:E220: Missing }.', pcall_err(api.nvim_get_runtime_file, '{', false)) - eq('Vim(echo):E5555: API call: Vim:E220: Missing }.', - exc_exec("echo nvim_get_runtime_file('{', v:false)")) + eq( + 'Vim(echo):E5555: API call: Vim:E220: Missing }.', + exc_exec("echo nvim_get_runtime_file('{', v:false)") + ) end) end) describe('nvim_get_all_options_info', function() it('should have key value pairs of option names', function() - local options_info = meths.get_all_options_info() + local options_info = api.nvim_get_all_options_info() neq(nil, options_info.listchars) neq(nil, options_info.tabstop) - eq(meths.get_option_info'winhighlight', options_info.winhighlight) + eq(api.nvim_get_option_info 'winhighlight', options_info.winhighlight) end) it('should not crash when echoed', function() - meths.exec2("echo nvim_get_all_options_info()", { output = true }) + api.nvim_exec2('echo nvim_get_all_options_info()', { output = true }) end) end) describe('nvim_get_option_info', function() it('should error for unknown options', function() - eq("Invalid option (not found): 'bogus'", pcall_err(meths.get_option_info, 'bogus')) + eq("Invalid option (not found): 'bogus'", pcall_err(api.nvim_get_option_info, 'bogus')) end) it('should return the same options for short and long name', function() - eq(meths.get_option_info'winhl', meths.get_option_info'winhighlight') + eq(api.nvim_get_option_info 'winhl', api.nvim_get_option_info 'winhighlight') end) it('should have information about window options', function() eq({ allows_duplicates = false, - commalist = true; - default = ""; - flaglist = false; - global_local = false; - last_set_chan = 0; - last_set_linenr = 0; - last_set_sid = 0; - name = "winhighlight"; - scope = "win"; - shortname = "winhl"; - type = "string"; - was_set = false; - }, meths.get_option_info'winhl') + commalist = true, + default = '', + flaglist = false, + global_local = false, + last_set_chan = 0, + last_set_linenr = 0, + last_set_sid = 0, + name = 'winhighlight', + scope = 'win', + shortname = 'winhl', + type = 'string', + was_set = false, + }, api.nvim_get_option_info 'winhl') end) it('should have information about buffer options', function() eq({ allows_duplicates = true, commalist = false, - default = "", + default = '', flaglist = false, global_local = false, last_set_chan = 0, last_set_linenr = 0, last_set_sid = 0, - name = "filetype", - scope = "buf", - shortname = "ft", - type = "string", - was_set = false - }, meths.get_option_info'filetype') + name = 'filetype', + scope = 'buf', + shortname = 'ft', + type = 'string', + was_set = false, + }, api.nvim_get_option_info 'filetype') end) it('should have information about global options', function() -- precondition: the option was changed from its default -- in test setup. - eq(false, meths.get_option_value('showcmd', {})) + eq(false, api.nvim_get_option_value('showcmd', {})) eq({ allows_duplicates = true, @@ -3080,14 +3265,14 @@ describe('API', function() last_set_chan = 0, last_set_linenr = 0, last_set_sid = -2, - name = "showcmd", - scope = "global", - shortname = "sc", - type = "boolean", - was_set = true - }, meths.get_option_info'showcmd') + name = 'showcmd', + scope = 'global', + shortname = 'sc', + type = 'boolean', + was_set = true, + }, api.nvim_get_option_info 'showcmd') - meths.set_option_value('showcmd', true, {}) + api.nvim_set_option_value('showcmd', true, {}) eq({ allows_duplicates = true, @@ -3098,12 +3283,12 @@ describe('API', function() last_set_chan = 1, last_set_linenr = 0, last_set_sid = -9, - name = "showcmd", - scope = "global", - shortname = "sc", - type = "boolean", - was_set = true - }, meths.get_option_info'showcmd') + name = 'showcmd', + scope = 'global', + shortname = 'sc', + type = 'boolean', + was_set = true, + }, api.nvim_get_option_info 'showcmd') end) end) @@ -3114,7 +3299,9 @@ describe('API', function() before_each(function() fname = tmpname() - write_file(fname, [[ + write_file( + fname, + [[ setglobal dictionary=mydict " 1, global-local (buffer) setlocal formatprg=myprg " 2, global-local (buffer) setglobal equalprg=prg1 " 3, global-local (buffer) @@ -3124,21 +3311,22 @@ describe('API', function() setglobal showbreak=aaa " 7, global-local (window) setlocal showbreak=bbb " 8, global-local (window) setglobal completeopt=menu " 9, global - ]]) + ]] + ) exec_lua 'vim.cmd.vsplit()' - meths.create_buf(false, false) + api.nvim_create_buf(false, false) - bufs = meths.list_bufs() - wins = meths.list_wins() + bufs = api.nvim_list_bufs() + wins = api.nvim_list_wins() - meths.win_set_buf(wins[1].id, bufs[1].id) - meths.win_set_buf(wins[2].id, bufs[2].id) + api.nvim_win_set_buf(wins[1], bufs[1]) + api.nvim_win_set_buf(wins[2], bufs[2]) - meths.set_current_win(wins[2].id) - meths.exec('source ' .. fname, false) + api.nvim_set_current_win(wins[2]) + api.nvim_exec('source ' .. fname, false) - meths.set_current_win(wins[1].id) + api.nvim_set_current_win(wins[1]) end) after_each(function() @@ -3146,12 +3334,13 @@ describe('API', function() end) it('should return option information', function() - eq(meths.get_option_info('dictionary'), meths.get_option_info2('dictionary', {})) -- buffer - eq(meths.get_option_info('fillchars'), meths.get_option_info2('fillchars', {})) -- window - eq(meths.get_option_info('completeopt'), meths.get_option_info2('completeopt', {})) -- global + eq(api.nvim_get_option_info('dictionary'), api.nvim_get_option_info2('dictionary', {})) -- buffer + eq(api.nvim_get_option_info('fillchars'), api.nvim_get_option_info2('fillchars', {})) -- window + eq(api.nvim_get_option_info('completeopt'), api.nvim_get_option_info2('completeopt', {})) -- global end) describe('last set', function() + -- stylua: ignore local tests = { {desc="(buf option, global requested, global set) points to global", linenr=1, sid=1, args={'dictionary', {scope='global'}}}, {desc="(buf option, global requested, local set) is not set", linenr=0, sid=0, args={'formatprg', {scope='global'}}}, @@ -3179,21 +3368,21 @@ describe('API', function() for _, t in pairs(tests) do it(t.desc, function() -- Switch to the target buffer/window so that curbuf/curwin are used. - meths.set_current_win(wins[2].id) - local info = meths.get_option_info2(unpack(t.args)) + api.nvim_set_current_win(wins[2]) + local info = api.nvim_get_option_info2(unpack(t.args)) eq(t.linenr, info.last_set_linenr) eq(t.sid, info.last_set_sid) end) end it('is provided for cross-buffer requests', function() - local info = meths.get_option_info2('formatprg', {buf=bufs[2].id}) + local info = api.nvim_get_option_info2('formatprg', { buf = bufs[2] }) eq(2, info.last_set_linenr) eq(1, info.last_set_sid) end) it('is provided for cross-window requests', function() - local info = meths.get_option_info2('listchars', {win=wins[2].id}) + local info = api.nvim_get_option_info2('listchars', { win = wins[2] }) eq(6, info.last_set_linenr) eq(1, info.last_set_sid) end) @@ -3207,11 +3396,11 @@ describe('API', function() screen = Screen.new(40, 8) screen:attach() screen:set_default_attr_ids({ - [0] = {bold = true, foreground = Screen.colors.Blue}, - [1] = {bold = true, foreground = Screen.colors.SeaGreen}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Brown, bold = true}, -- Statement - [4] = {foreground = Screen.colors.SlateBlue}, -- Special + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { bold = true, foreground = Screen.colors.SeaGreen }, + [2] = { bold = true, reverse = true }, + [3] = { foreground = Screen.colors.Brown, bold = true }, -- Statement + [4] = { foreground = Screen.colors.SlateBlue }, -- Special }) command('highlight Statement gui=bold guifg=Brown') command('highlight Special guifg=SlateBlue') @@ -3219,60 +3408,57 @@ describe('API', function() it('should clear cmdline message before echo', function() feed(':call nvim_echo([["msg"]], v:false, {})<CR>') - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*6 msg | - ]]} + ]], + } end) it('can show highlighted line', function() - nvim_async("echo", {{"msg_a"}, {"msg_b", "Statement"}, {"msg_c", "Special"}}, true, {}) - screen:expect{grid=[[ + async_meths.nvim_echo( + { { 'msg_a' }, { 'msg_b', 'Statement' }, { 'msg_c', 'Special' } }, + true, + {} + ) + screen:expect { + grid = [[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*6 msg_a{3:msg_b}{4:msg_c} | - ]]} + ]], + } end) it('can show highlighted multiline', function() - nvim_async("echo", {{"msg_a\nmsg_a", "Statement"}, {"msg_b", "Special"}}, true, {}) - screen:expect{grid=[[ + async_meths.nvim_echo({ { 'msg_a\nmsg_a', 'Statement' }, { 'msg_b', 'Special' } }, true, {}) + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*3 {2: }| {3:msg_a} | {3:msg_a}{4:msg_b} | {1:Press ENTER or type command to continue}^ | - ]]} + ]], + } end) it('can save message history', function() - nvim('command', 'set cmdheight=2') -- suppress Press ENTER - nvim("echo", {{"msg\nmsg"}, {"msg"}}, true, {}) - eq("msg\nmsgmsg", exec_capture('messages')) + command('set cmdheight=2') -- suppress Press ENTER + api.nvim_echo({ { 'msg\nmsg' }, { 'msg' } }, true, {}) + eq('msg\nmsgmsg', exec_capture('messages')) end) it('can disable saving message history', function() - nvim('command', 'set cmdheight=2') -- suppress Press ENTER - nvim_async("echo", {{"msg\nmsg"}, {"msg"}}, false, {}) - eq("", exec_capture('messages')) + command('set cmdheight=2') -- suppress Press ENTER + async_meths.nvim_echo({ { 'msg\nmsg' }, { 'msg' } }, false, {}) + eq('', exec_capture('messages')) end) end) - describe('nvim_open_term', function() local screen @@ -3280,24 +3466,37 @@ describe('API', function() screen = Screen.new(100, 35) screen:attach() screen:set_default_attr_ids({ - [0] = {bold=true, foreground=Screen.colors.Blue}, - [1] = {background = Screen.colors.Plum1}; - [2] = {background = tonumber('0xffff40'), bg_indexed = true}; - [3] = {background = Screen.colors.Plum1, fg_indexed = true, foreground = tonumber('0x00e000')}; - [4] = {bold = true, reverse = true, background = Screen.colors.Plum1}; - [5] = {foreground = Screen.colors.Blue, background = Screen.colors.LightMagenta, bold = true}; - [6] = {bold = true}; - [7] = {reverse = true, background = Screen.colors.LightMagenta}; + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { background = Screen.colors.Plum1 }, + [2] = { background = tonumber('0xffff40'), bg_indexed = true }, + [3] = { + background = Screen.colors.Plum1, + fg_indexed = true, + foreground = tonumber('0x00e000'), + }, + [4] = { bold = true, reverse = true, background = Screen.colors.Plum1 }, + [5] = { + foreground = Screen.colors.Blue, + background = Screen.colors.LightMagenta, + bold = true, + }, + [6] = { bold = true }, + [7] = { reverse = true, background = Screen.colors.LightMagenta }, }) end) it('can batch process sequences', function() - local b = meths.create_buf(true,true) - meths.open_win(b, false, {width=79, height=31, row=1, col=1, relative='editor'}) - local t = meths.open_term(b, {}) - - meths.chan_send(t, io.open("test/functional/fixtures/smile2.cat", "r"):read("*a")) - screen:expect{grid=[[ + local b = api.nvim_create_buf(true, true) + api.nvim_open_win( + b, + false, + { width = 79, height = 31, row = 1, col = 1, relative = 'editor' } + ) + local t = api.nvim_open_term(b, {}) + + api.nvim_chan_send(t, io.open('test/functional/fixtures/smile2.cat', 'r'):read('*a')) + screen:expect { + grid = [[ ^ | {0:~}{1::smile }{0: }| {0:~}{1: }{2:oooo$$$$$$$$$$$$oooo}{1: }{0: }| @@ -3330,15 +3529,17 @@ describe('API', function() {0:~}{3:Press ENTER or type command to continue}{1: }{0: }| {0:~}{4:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{0: }| {0:~}{1::call nvim__screenshot("smile2.cat") }{0: }| - {0:~ }| - {0:~ }| + {0:~ }|*2 | - ]]} + ]], + } end) it('can handle input', function() screen:try_resize(50, 10) - eq({3, 2}, exec_lua [[ + eq( + { 3, 2 }, + exec_lua [[ buf = vim.api.nvim_create_buf(1,1) stream = '' @@ -3354,251 +3555,297 @@ describe('API', function() term = vim.api.nvim_open_term(buf, {on_input=input}) vim.api.nvim_open_win(buf, true, {width=40, height=5, row=1, col=1, relative='editor'}) return {term, buf} - ]]) + ]] + ) - screen:expect{grid=[[ + screen:expect { + grid = [[ | {0:~}{1:^ }{0: }| - {0:~}{1: }{0: }| - {0:~}{1: }{0: }| - {0:~}{1: }{0: }| - {0:~}{1: }{0: }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~}{1: }{0: }|*4 + {0:~ }|*3 | - ]]} + ]], + } feed 'iba<c-x>bla' - screen:expect{grid=[[ + screen:expect { + grid = [[ | {0:~}{7: }{1: }{0: }| - {0:~}{1: }{0: }| - {0:~}{1: }{0: }| - {0:~}{1: }{0: }| - {0:~}{1: }{0: }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~}{1: }{0: }|*4 + {0:~ }|*3 {6:-- TERMINAL --} | - ]]} + ]], + } eq('ba\024bla', exec_lua [[ return stream ]]) - eq({3,2}, exec_lua [[ return vals ]]) + eq({ 3, 2 }, exec_lua [[ return vals ]]) exec_lua [[ do_the_echo = true ]] feed 'herrejösses!' - screen:expect{grid=[[ + screen:expect { + grid = [[ | {0:~}{1:herrejösses!}{7: }{1: }{0: }| - {0:~}{1: }{0: }| - {0:~}{1: }{0: }| - {0:~}{1: }{0: }| - {0:~}{1: }{0: }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~}{1: }{0: }|*4 + {0:~ }|*3 {6:-- TERMINAL --} | - ]]} + ]], + } eq('ba\024blaherrejösses!', exec_lua [[ return stream ]]) end) end) describe('nvim_del_mark', function() it('works', function() - local buf = meths.create_buf(false,true) - meths.buf_set_lines(buf, -1, -1, true, {'a', 'bit of', 'text'}) - eq(true, meths.buf_set_mark(buf, 'F', 2, 2, {})) - eq(true, meths.del_mark('F')) - eq({0, 0}, meths.buf_get_mark(buf, 'F')) + local buf = api.nvim_create_buf(false, true) + api.nvim_buf_set_lines(buf, -1, -1, true, { 'a', 'bit of', 'text' }) + eq(true, api.nvim_buf_set_mark(buf, 'F', 2, 2, {})) + eq(true, api.nvim_del_mark('F')) + eq({ 0, 0 }, api.nvim_buf_get_mark(buf, 'F')) end) it('validation', function() - eq("Invalid mark name (must be file/uppercase): 'f'", pcall_err(meths.del_mark, 'f')) - eq("Invalid mark name (must be file/uppercase): '!'", pcall_err(meths.del_mark, '!')) - eq("Invalid mark name (must be a single char): 'fail'", pcall_err(meths.del_mark, 'fail')) + eq("Invalid mark name (must be file/uppercase): 'f'", pcall_err(api.nvim_del_mark, 'f')) + eq("Invalid mark name (must be file/uppercase): '!'", pcall_err(api.nvim_del_mark, '!')) + eq("Invalid mark name (must be a single char): 'fail'", pcall_err(api.nvim_del_mark, 'fail')) end) end) describe('nvim_get_mark', function() it('works', function() - local buf = meths.create_buf(false,true) - meths.buf_set_lines(buf, -1, -1, true, {'a', 'bit of', 'text'}) - meths.buf_set_mark(buf, 'F', 2, 2, {}) - meths.buf_set_name(buf, "mybuf") - local mark = meths.get_mark('F', {}) + local buf = api.nvim_create_buf(false, true) + api.nvim_buf_set_lines(buf, -1, -1, true, { 'a', 'bit of', 'text' }) + api.nvim_buf_set_mark(buf, 'F', 2, 2, {}) + api.nvim_buf_set_name(buf, 'mybuf') + local mark = api.nvim_get_mark('F', {}) -- Compare the path tail only - assert(string.find(mark[4], "mybuf$")) - eq({2, 2, buf.id, mark[4]}, mark) + assert(string.find(mark[4], 'mybuf$')) + eq({ 2, 2, buf, mark[4] }, mark) end) it('validation', function() - eq("Invalid mark name (must be file/uppercase): 'f'", pcall_err(meths.get_mark, 'f', {})) - eq("Invalid mark name (must be file/uppercase): '!'", pcall_err(meths.get_mark, '!', {})) - eq("Invalid mark name (must be a single char): 'fail'", pcall_err(meths.get_mark, 'fail', {})) + eq("Invalid mark name (must be file/uppercase): 'f'", pcall_err(api.nvim_get_mark, 'f', {})) + eq("Invalid mark name (must be file/uppercase): '!'", pcall_err(api.nvim_get_mark, '!', {})) + eq( + "Invalid mark name (must be a single char): 'fail'", + pcall_err(api.nvim_get_mark, 'fail', {}) + ) end) it('returns the expected when mark is not set', function() - eq(true, meths.del_mark('A')) - eq({0, 0, 0, ''}, meths.get_mark('A', {})) + eq(true, api.nvim_del_mark('A')) + eq({ 0, 0, 0, '' }, api.nvim_get_mark('A', {})) end) it('works with deleted buffers', function() local fname = tmpname() write_file(fname, 'a\nbit of\text') - nvim("command", "edit " .. fname) - local buf = meths.get_current_buf() + command('edit ' .. fname) + local buf = api.nvim_get_current_buf() - meths.buf_set_mark(buf, 'F', 2, 2, {}) - nvim("command", "new") -- Create new buf to avoid :bd failing - nvim("command", "bd! " .. buf.id) + api.nvim_buf_set_mark(buf, 'F', 2, 2, {}) + command('new') -- Create new buf to avoid :bd failing + command('bd! ' .. buf) os.remove(fname) - local mark = meths.get_mark('F', {}) + local mark = api.nvim_get_mark('F', {}) -- To avoid comparing relative vs absolute path local mfname = mark[4] local tail_patt = [[[\/][^\/]*$]] -- tail of paths should be equals eq(fname:match(tail_patt), mfname:match(tail_patt)) - eq({2, 2, buf.id, mark[4]}, mark) + eq({ 2, 2, buf, mark[4] }, mark) end) end) + describe('nvim_eval_statusline', function() it('works', function() eq({ - str = '%StatusLineStringWithHighlights', - width = 31 - }, - meths.eval_statusline( - '%%StatusLineString%#WarningMsg#WithHighlights', - {})) + str = '%StatusLineStringWithHighlights', + width = 31, + }, api.nvim_eval_statusline('%%StatusLineString%#WarningMsg#WithHighlights', {})) end) - it('doesn\'t exceed maxwidth', function() + + it("doesn't exceed maxwidth", function() eq({ - str = 'Should be trun>', - width = 15 - }, - meths.eval_statusline( - 'Should be truncated%<', - { maxwidth = 15 })) - end) - it('supports ASCII fillchar', function() - eq({ str = 'a~~~b', width = 5 }, - meths.eval_statusline('a%=b', { fillchar = '~', maxwidth = 5 })) - end) - it('supports single-width multibyte fillchar', function() - eq({ str = 'a━━━b', width = 5 }, - meths.eval_statusline('a%=b', { fillchar = '━', maxwidth = 5 })) - end) - it('treats double-width fillchar as single-width', function() - eq({ str = 'a哦哦哦b', width = 5 }, - meths.eval_statusline('a%=b', { fillchar = '哦', maxwidth = 5 })) - end) - it('treats control character fillchar as single-width', function() - eq({ str = 'a\031\031\031b', width = 5 }, - meths.eval_statusline('a%=b', { fillchar = '\031', maxwidth = 5 })) - end) + str = 'Should be trun>', + width = 15, + }, api.nvim_eval_statusline('Should be truncated%<', { maxwidth = 15 })) + end) + + it('has correct default fillchar', function() + local oldwin = api.nvim_get_current_win() + command('set fillchars=stl:#,stlnc:$,wbr:%') + command('new') + eq({ str = 'a###b', width = 5 }, api.nvim_eval_statusline('a%=b', { maxwidth = 5 })) + eq( + { str = 'a$$$b', width = 5 }, + api.nvim_eval_statusline('a%=b', { winid = oldwin, maxwidth = 5 }) + ) + eq( + { str = 'a%%%b', width = 5 }, + api.nvim_eval_statusline('a%=b', { use_winbar = true, maxwidth = 5 }) + ) + eq( + { str = 'a b', width = 5 }, + api.nvim_eval_statusline('a%=b', { use_tabline = true, maxwidth = 5 }) + ) + eq( + { str = 'a b', width = 5 }, + api.nvim_eval_statusline('a%=b', { use_statuscol_lnum = 1, maxwidth = 5 }) + ) + end) + + for fc, desc in pairs({ + ['~'] = 'supports ASCII fillchar', + ['━'] = 'supports single-width multibyte fillchar', + ['c̳'] = 'supports single-width fillchar with composing', + ['哦'] = 'treats double-width fillchar as single-width', + ['\031'] = 'treats control character fillchar as single-width', + }) do + it(desc, function() + eq( + { str = 'a' .. fc:rep(3) .. 'b', width = 5 }, + api.nvim_eval_statusline('a%=b', { fillchar = fc, maxwidth = 5 }) + ) + eq( + { str = 'a' .. fc:rep(3) .. 'b', width = 5 }, + api.nvim_eval_statusline('a%=b', { fillchar = fc, use_winbar = true, maxwidth = 5 }) + ) + eq( + { str = 'a' .. fc:rep(3) .. 'b', width = 5 }, + api.nvim_eval_statusline('a%=b', { fillchar = fc, use_tabline = true, maxwidth = 5 }) + ) + eq( + { str = 'a' .. fc:rep(3) .. 'b', width = 5 }, + api.nvim_eval_statusline('a%=b', { fillchar = fc, use_statuscol_lnum = 1, maxwidth = 5 }) + ) + end) + end + it('rejects multiple-character fillchar', function() - eq("Invalid 'fillchar': expected single character", - pcall_err(meths.eval_statusline, '', { fillchar = 'aa' })) + eq( + "Invalid 'fillchar': expected single character", + pcall_err(api.nvim_eval_statusline, '', { fillchar = 'aa' }) + ) end) + it('rejects empty string fillchar', function() - eq("Invalid 'fillchar': expected single character", - pcall_err(meths.eval_statusline, '', { fillchar = '' })) + eq( + "Invalid 'fillchar': expected single character", + pcall_err(api.nvim_eval_statusline, '', { fillchar = '' }) + ) end) + it('rejects non-string fillchar', function() - eq("Invalid 'fillchar': expected String, got Integer", - pcall_err(meths.eval_statusline, '', { fillchar = 1 })) + eq( + "Invalid 'fillchar': expected String, got Integer", + pcall_err(api.nvim_eval_statusline, '', { fillchar = 1 }) + ) end) + it('rejects invalid string', function() - eq('E539: Illegal character <}>', - pcall_err(meths.eval_statusline, '%{%}', {})) + eq('E539: Illegal character <}>', pcall_err(api.nvim_eval_statusline, '%{%}', {})) end) + it('supports various items', function() - eq({ str = '0', width = 1 }, - meths.eval_statusline('%l', { maxwidth = 5 })) + eq({ str = '0', width = 1 }, api.nvim_eval_statusline('%l', { maxwidth = 5 })) command('set readonly') - eq({ str = '[RO]', width = 4 }, - meths.eval_statusline('%r', { maxwidth = 5 })) + eq({ str = '[RO]', width = 4 }, api.nvim_eval_statusline('%r', { maxwidth = 5 })) local screen = Screen.new(80, 24) screen:attach() command('set showcmd') feed('1234') - screen:expect({any = '1234'}) - eq({ str = '1234', width = 4 }, - meths.eval_statusline('%S', { maxwidth = 5 })) + screen:expect({ any = '1234' }) + eq({ str = '1234', width = 4 }, api.nvim_eval_statusline('%S', { maxwidth = 5 })) feed('56') - screen:expect({any = '123456'}) - eq({ str = '<3456', width = 5 }, - meths.eval_statusline('%S', { maxwidth = 5 })) + screen:expect({ any = '123456' }) + eq({ str = '<3456', width = 5 }, api.nvim_eval_statusline('%S', { maxwidth = 5 })) end) + describe('highlight parsing', function() it('works', function() - eq({ - str = "TextWithWarningHighlightTextWithUserHighlight", + eq( + { + str = 'TextWithWarningHighlightTextWithUserHighlight', width = 45, highlights = { { start = 0, group = 'WarningMsg' }, - { start = 24, group = 'User1' } + { start = 24, group = 'User1' }, }, }, - meths.eval_statusline( + api.nvim_eval_statusline( '%#WarningMsg#TextWithWarningHighlight%1*TextWithUserHighlight', - { highlights = true })) + { highlights = true } + ) + ) end) + it('works with no highlight', function() eq({ - str = "TextWithNoHighlight", - width = 19, - highlights = { - { start = 0, group = 'StatusLine' }, - }, + str = 'TextWithNoHighlight', + width = 19, + highlights = { + { start = 0, group = 'StatusLine' }, }, - meths.eval_statusline( - 'TextWithNoHighlight', - { highlights = true })) + }, api.nvim_eval_statusline('TextWithNoHighlight', { highlights = true })) end) + it('works with inactive statusline', function() command('split') - - eq({ + eq( + { str = 'TextWithNoHighlightTextWithWarningHighlight', width = 43, highlights = { { start = 0, group = 'StatusLineNC' }, - { start = 19, group = 'WarningMsg' } - } + { start = 19, group = 'WarningMsg' }, + }, }, - meths.eval_statusline( + api.nvim_eval_statusline( 'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight', - { winid = meths.list_wins()[2].id, highlights = true })) + { winid = api.nvim_list_wins()[2], highlights = true } + ) + ) end) + it('works with tabline', function() - eq({ + eq( + { str = 'TextWithNoHighlightTextWithWarningHighlight', width = 43, highlights = { { start = 0, group = 'TabLineFill' }, - { start = 19, group = 'WarningMsg' } - } + { start = 19, group = 'WarningMsg' }, + }, }, - meths.eval_statusline( + api.nvim_eval_statusline( 'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight', - { use_tabline = true, highlights = true })) + { use_tabline = true, highlights = true } + ) + ) end) + it('works with winbar', function() - eq({ + eq( + { str = 'TextWithNoHighlightTextWithWarningHighlight', width = 43, highlights = { { start = 0, group = 'WinBar' }, - { start = 19, group = 'WarningMsg' } - } + { start = 19, group = 'WarningMsg' }, + }, }, - meths.eval_statusline( + api.nvim_eval_statusline( 'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight', - { use_winbar = true, highlights = true })) + { use_winbar = true, highlights = true } + ) + ) end) + it('works with statuscolumn', function() exec([[ let &stc='%C%s%=%l ' - set cul nu nuw=3 scl=yes:2 fdc=2 + " should not use "stl" from 'fillchars' + set cul nu nuw=3 scl=yes:2 fdc=2 fillchars=stl:# call setline(1, repeat(['aaaaa'], 5)) let g:ns = nvim_create_namespace('') call sign_define('a', {'text':'aa', 'texthl':'IncSearch', 'numhl':'Normal'}) @@ -3615,28 +3862,31 @@ describe('API', function() { group = 'Normal', start = 6 }, { group = 'IncSearch', start = 6 }, { group = 'ErrorMsg', start = 8 }, - { group = 'Normal', start = 10 } - } - }, meths.eval_statusline('%C%s%=%l ', { use_statuscol_lnum = 4, highlights = true })) - eq({ - str = '3 ' , - width = 2, - highlights = { - { group = 'LineNr', start = 0 }, - { group = 'ErrorMsg', start = 1 } - } - }, meths.eval_statusline('%l%#ErrorMsg# ', { use_statuscol_lnum = 3, highlights = true })) + { group = 'Normal', start = 10 }, + }, + }, api.nvim_eval_statusline( + '%C%s%=%l ', + { use_statuscol_lnum = 4, highlights = true } + )) + eq( + { + str = '3 ', + width = 2, + highlights = { + { group = 'LineNr', start = 0 }, + { group = 'ErrorMsg', start = 1 }, + }, + }, + api.nvim_eval_statusline('%l%#ErrorMsg# ', { use_statuscol_lnum = 3, highlights = true }) + ) end) + it('no memory leak with click functions', function() - meths.eval_statusline('%@ClickFunc@StatusLineStringWithClickFunc%T', {}) + api.nvim_eval_statusline('%@ClickFunc@StatusLineStringWithClickFunc%T', {}) eq({ - str = 'StatusLineStringWithClickFunc', - width = 29 - }, - meths.eval_statusline( - '%@ClickFunc@StatusLineStringWithClickFunc%T', - {}) - ) + str = 'StatusLineStringWithClickFunc', + width = 29, + }, api.nvim_eval_statusline('%@ClickFunc@StatusLineStringWithClickFunc%T', {})) end) end) end) @@ -3649,8 +3899,8 @@ describe('API', function() bang = false, addr = 'none', magic = { - file = false, - bar = false + file = false, + bar = false, }, nargs = '*', nextcmd = '', @@ -3659,8 +3909,8 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", - force = false + pattern = '', + force = false, }, hide = false, horizontal = false, @@ -3673,13 +3923,13 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, - } - }, meths.parse_cmd('echo foo', {})) + }, + }, api.nvim_parse_cmd('echo foo', {})) end) it('works with ranges', function() eq({ @@ -3689,8 +3939,8 @@ describe('API', function() range = { 4, 6 }, addr = 'line', magic = { - file = false, - bar = false + file = false, + bar = false, }, nargs = '*', nextcmd = '', @@ -3699,8 +3949,8 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", - force = false + pattern = '', + force = false, }, hide = false, horizontal = false, @@ -3713,13 +3963,13 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, - } - }, meths.parse_cmd('4,6s/math.random/math.max/', {})) + }, + }, api.nvim_parse_cmd('4,6s/math.random/math.max/', {})) end) it('works with count', function() eq({ @@ -3730,8 +3980,8 @@ describe('API', function() count = 1, addr = 'buf', magic = { - file = false, - bar = true + file = false, + bar = true, }, nargs = '*', nextcmd = '', @@ -3740,8 +3990,8 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", - force = false + pattern = '', + force = false, }, hide = false, horizontal = false, @@ -3754,13 +4004,13 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, - } - }, meths.parse_cmd('buffer 1', {})) + }, + }, api.nvim_parse_cmd('buffer 1', {})) end) it('works with register', function() eq({ @@ -3771,8 +4021,8 @@ describe('API', function() reg = '+', addr = 'line', magic = { - file = false, - bar = true + file = false, + bar = true, }, nargs = '0', nextcmd = '', @@ -3781,8 +4031,8 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", - force = false + pattern = '', + force = false, }, hide = false, horizontal = false, @@ -3795,13 +4045,13 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, - } - }, meths.parse_cmd('put +', {})) + }, + }, api.nvim_parse_cmd('put +', {})) eq({ cmd = 'put', args = {}, @@ -3810,8 +4060,8 @@ describe('API', function() reg = '', addr = 'line', magic = { - file = false, - bar = true + file = false, + bar = true, }, nargs = '0', nextcmd = '', @@ -3820,8 +4070,8 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", - force = false + pattern = '', + force = false, }, hide = false, horizontal = false, @@ -3834,13 +4084,13 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, - } - }, meths.parse_cmd('put', {})) + }, + }, api.nvim_parse_cmd('put', {})) end) it('works with range, count and register', function() eq({ @@ -3852,8 +4102,8 @@ describe('API', function() reg = '*', addr = 'line', magic = { - file = false, - bar = true + file = false, + bar = true, }, nargs = '0', nextcmd = '', @@ -3862,8 +4112,8 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", - force = false + pattern = '', + force = false, }, hide = false, horizontal = false, @@ -3876,13 +4126,13 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, - } - }, meths.parse_cmd('1,3delete * 5', {})) + }, + }, api.nvim_parse_cmd('1,3delete * 5', {})) end) it('works with bang', function() eq({ @@ -3892,8 +4142,8 @@ describe('API', function() range = {}, addr = 'line', magic = { - file = true, - bar = true + file = true, + bar = true, }, nargs = '?', nextcmd = '', @@ -3902,8 +4152,8 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", - force = false + pattern = '', + force = false, }, hide = false, horizontal = false, @@ -3916,91 +4166,103 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, }, - }, meths.parse_cmd('w!', {})) + }, api.nvim_parse_cmd('w!', {})) end) it('works with modifiers', function() - eq({ - cmd = 'split', - args = { 'foo.txt' }, - bang = false, - range = {}, - addr = '?', - magic = { + eq( + { + cmd = 'split', + args = { 'foo.txt' }, + bang = false, + range = {}, + addr = '?', + magic = { file = true, - bar = true - }, - nargs = '?', - nextcmd = '', - mods = { - browse = false, - confirm = false, - emsg_silent = true, - filter = { - pattern = "foo", - force = false + bar = true, + }, + nargs = '?', + nextcmd = '', + mods = { + browse = false, + confirm = false, + emsg_silent = true, + filter = { + pattern = 'foo', + force = false, + }, + hide = false, + horizontal = true, + keepalt = false, + keepjumps = false, + keepmarks = false, + keeppatterns = false, + lockmarks = false, + noautocmd = false, + noswapfile = false, + sandbox = false, + silent = true, + split = 'topleft', + tab = 1, + unsilent = false, + verbose = 15, + vertical = false, }, - hide = false, - horizontal = true, - keepalt = false, - keepjumps = false, - keepmarks = false, - keeppatterns = false, - lockmarks = false, - noautocmd = false, - noswapfile = false, - sandbox = false, - silent = true, - split = "topleft", - tab = 1, - unsilent = false, - verbose = 15, - vertical = false, }, - }, meths.parse_cmd('15verbose silent! horizontal topleft tab filter /foo/ split foo.txt', {})) - eq({ - cmd = 'split', - args = { 'foo.txt' }, - bang = false, - range = {}, - addr = '?', - magic = { + api.nvim_parse_cmd( + '15verbose silent! horizontal topleft tab filter /foo/ split foo.txt', + {} + ) + ) + eq( + { + cmd = 'split', + args = { 'foo.txt' }, + bang = false, + range = {}, + addr = '?', + magic = { file = true, - bar = true - }, - nargs = '?', - nextcmd = '', - mods = { - browse = false, - confirm = true, - emsg_silent = false, - filter = { - pattern = "foo", - force = true + bar = true, + }, + nargs = '?', + nextcmd = '', + mods = { + browse = false, + confirm = true, + emsg_silent = false, + filter = { + pattern = 'foo', + force = true, + }, + hide = false, + horizontal = false, + keepalt = false, + keepjumps = false, + keepmarks = false, + keeppatterns = false, + lockmarks = false, + noautocmd = false, + noswapfile = false, + sandbox = false, + silent = false, + split = 'botright', + tab = 0, + unsilent = true, + verbose = 0, + vertical = false, }, - hide = false, - horizontal = false, - keepalt = false, - keepjumps = false, - keepmarks = false, - keeppatterns = false, - lockmarks = false, - noautocmd = false, - noswapfile = false, - sandbox = false, - silent = false, - split = "botright", - tab = 0, - unsilent = true, - verbose = 0, - vertical = false, }, - }, meths.parse_cmd('0verbose unsilent botright 0tab confirm filter! /foo/ split foo.txt', {})) + api.nvim_parse_cmd( + '0verbose unsilent botright 0tab confirm filter! /foo/ split foo.txt', + {} + ) + ) end) it('works with user commands', function() command('command -bang -nargs=+ -range -addr=lines MyCommand echo foo') @@ -4011,8 +4273,8 @@ describe('API', function() range = { 4, 6 }, addr = 'line', magic = { - file = false, - bar = false + file = false, + bar = false, }, nargs = '+', nextcmd = '', @@ -4021,8 +4283,8 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", - force = false + pattern = '', + force = false, }, hide = false, horizontal = false, @@ -4035,13 +4297,13 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, - } - }, meths.parse_cmd('4,6MyCommand! test it', {})) + }, + }, api.nvim_parse_cmd('4,6MyCommand! test it', {})) end) it('works for commands separated by bar', function() eq({ @@ -4051,8 +4313,8 @@ describe('API', function() range = {}, addr = 'arg', magic = { - file = true, - bar = true + file = true, + bar = true, }, nargs = '*', nextcmd = 'argadd b.txt', @@ -4061,8 +4323,8 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", - force = false + pattern = '', + force = false, }, hide = false, horizontal = false, @@ -4075,13 +4337,13 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, - } - }, meths.parse_cmd('argadd a.txt | argadd b.txt', {})) + }, + }, api.nvim_parse_cmd('argadd a.txt | argadd b.txt', {})) end) it('works for nargs=1', function() command('command -nargs=1 MyCommand echo <q-args>') @@ -4091,8 +4353,8 @@ describe('API', function() bang = false, addr = 'none', magic = { - file = false, - bar = false + file = false, + bar = false, }, nargs = '1', nextcmd = '', @@ -4101,8 +4363,8 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", - force = false + pattern = '', + force = false, }, hide = false, horizontal = false, @@ -4115,33 +4377,41 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, - } - }, meths.parse_cmd('MyCommand test it', {})) + }, + }, api.nvim_parse_cmd('MyCommand test it', {})) end) it('validates command', function() - eq('Error while parsing command line', pcall_err(meths.parse_cmd, '', {})) - eq('Error while parsing command line', pcall_err(meths.parse_cmd, '" foo', {})) - eq('Error while parsing command line: E492: Not an editor command: Fubar', - pcall_err(meths.parse_cmd, 'Fubar', {})) + eq('Error while parsing command line', pcall_err(api.nvim_parse_cmd, '', {})) + eq('Error while parsing command line', pcall_err(api.nvim_parse_cmd, '" foo', {})) + eq( + 'Error while parsing command line: E492: Not an editor command: Fubar', + pcall_err(api.nvim_parse_cmd, 'Fubar', {}) + ) command('command! Fubar echo foo') - eq('Error while parsing command line: E477: No ! allowed', - pcall_err(meths.parse_cmd, 'Fubar!', {})) - eq('Error while parsing command line: E481: No range allowed', - pcall_err(meths.parse_cmd, '4,6Fubar', {})) + eq( + 'Error while parsing command line: E477: No ! allowed', + pcall_err(api.nvim_parse_cmd, 'Fubar!', {}) + ) + eq( + 'Error while parsing command line: E481: No range allowed', + pcall_err(api.nvim_parse_cmd, '4,6Fubar', {}) + ) command('command! Foobar echo foo') - eq('Error while parsing command line: E464: Ambiguous use of user-defined command', - pcall_err(meths.parse_cmd, 'F', {})) + eq( + 'Error while parsing command line: E464: Ambiguous use of user-defined command', + pcall_err(api.nvim_parse_cmd, 'F', {}) + ) end) it('does not interfere with printing line in Ex mode #19400', function() local screen = Screen.new(60, 7) screen:set_default_attr_ids({ - [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText - [1] = {bold = true, reverse = true}, -- MsgSeparator + [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText + [1] = { bold = true, reverse = true }, -- MsgSeparator }) screen:attach() insert([[ @@ -4151,13 +4421,12 @@ describe('API', function() screen:expect([[ foo | bar | - {0:~ }| - {0:~ }| + {0:~ }|*2 {1: }| Entering Ex mode. Type "visual" to go to Normal mode. | :1^ | ]]) - eq('Error while parsing command line', pcall_err(meths.parse_cmd, '', {})) + eq('Error while parsing command line', pcall_err(api.nvim_parse_cmd, '', {})) feed('<CR>') screen:expect([[ foo | @@ -4170,16 +4439,16 @@ describe('API', function() ]]) end) it('does not move cursor or change search history/pattern #19878 #19890', function() - meths.buf_set_lines(0, 0, -1, true, {'foo', 'bar', 'foo', 'bar'}) - eq({1, 0}, meths.win_get_cursor(0)) - eq('', funcs.getreg('/')) - eq('', funcs.histget('search')) - feed(':') -- call the API in cmdline mode to test whether it changes search history + api.nvim_buf_set_lines(0, 0, -1, true, { 'foo', 'bar', 'foo', 'bar' }) + eq({ 1, 0 }, api.nvim_win_get_cursor(0)) + eq('', fn.getreg('/')) + eq('', fn.histget('search')) + feed(':') -- call the API in cmdline mode to test whether it changes search history eq({ cmd = 'normal', - args = {'x'}, + args = { 'x' }, bang = true, - range = {3, 4}, + range = { 3, 4 }, addr = 'line', magic = { file = false, @@ -4192,7 +4461,7 @@ describe('API', function() confirm = false, emsg_silent = false, filter = { - pattern = "", + pattern = '', force = false, }, hide = false, @@ -4206,101 +4475,134 @@ describe('API', function() noswapfile = false, sandbox = false, silent = false, - split = "", + split = '', tab = -1, unsilent = false, verbose = -1, vertical = false, - } - }, meths.parse_cmd('+2;/bar/normal! x', {})) - eq({1, 0}, meths.win_get_cursor(0)) - eq('', funcs.getreg('/')) - eq('', funcs.histget('search')) + }, + }, api.nvim_parse_cmd('+2;/bar/normal! x', {})) + eq({ 1, 0 }, api.nvim_win_get_cursor(0)) + eq('', fn.getreg('/')) + eq('', fn.histget('search')) end) it('result can be used directly by nvim_cmd #20051', function() - eq("foo", meths.cmd(meths.parse_cmd('echo "foo"', {}), { output = true })) - meths.cmd(meths.parse_cmd("set cursorline", {}), {}) - eq(true, meths.get_option_value("cursorline", {})) + eq('foo', api.nvim_cmd(api.nvim_parse_cmd('echo "foo"', {}), { output = true })) + api.nvim_cmd(api.nvim_parse_cmd('set cursorline', {}), {}) + eq(true, api.nvim_get_option_value('cursorline', {})) end) it('no side-effects (error messages) in pcall() #20339', function() - eq({ false, 'Error while parsing command line: E16: Invalid range' }, - exec_lua([=[return {pcall(vim.api.nvim_parse_cmd, "'<,'>n", {})}]=])) + eq( + { false, 'Error while parsing command line: E16: Invalid range' }, + exec_lua([=[return {pcall(vim.api.nvim_parse_cmd, "'<,'>n", {})}]=]) + ) eq('', eval('v:errmsg')) end) end) describe('nvim_cmd', function() - it('works', function () - meths.cmd({ cmd = "set", args = { "cursorline" } }, {}) - eq(true, meths.get_option_value("cursorline", {})) + it('works', function() + api.nvim_cmd({ cmd = 'set', args = { 'cursorline' } }, {}) + eq(true, api.nvim_get_option_value('cursorline', {})) end) it('validation', function() - eq("Invalid 'cmd': expected non-empty String", - pcall_err(meths.cmd, { cmd = ""}, {})) - eq("Invalid 'cmd': expected String, got Array", - pcall_err(meths.cmd, { cmd = {}}, {})) - eq("Invalid 'args': expected Array, got Boolean", - pcall_err(meths.cmd, { cmd = "set", args = true }, {})) - eq("Invalid command arg: expected non-whitespace", - pcall_err(meths.cmd, { cmd = "set", args = {' '}, }, {})) - eq("Invalid command arg: expected valid type, got Array", - pcall_err(meths.cmd, { cmd = "set", args = {{}}, }, {})) - eq("Wrong number of arguments", - pcall_err(meths.cmd, { cmd = "aboveleft", args = {}, }, {})) - eq("Command cannot accept bang: print", - pcall_err(meths.cmd, { cmd = "print", args = {}, bang = true }, {})) - - eq("Command cannot accept range: set", - pcall_err(meths.cmd, { cmd = "set", args = {}, range = {1} }, {})) - eq("Invalid 'range': expected Array, got Boolean", - pcall_err(meths.cmd, { cmd = "print", args = {}, range = true }, {})) - eq("Invalid 'range': expected <=2 elements", - pcall_err(meths.cmd, { cmd = "print", args = {}, range = {1,2,3,4} }, {})) - eq("Invalid range element: expected non-negative Integer", - pcall_err(meths.cmd, { cmd = "print", args = {}, range = {-1} }, {})) - - eq("Command cannot accept count: set", - pcall_err(meths.cmd, { cmd = "set", args = {}, count = 1 }, {})) - eq("Invalid 'count': expected Integer, got Boolean", - pcall_err(meths.cmd, { cmd = "print", args = {}, count = true }, {})) - eq("Invalid 'count': expected non-negative Integer", - pcall_err(meths.cmd, { cmd = "print", args = {}, count = -1 }, {})) - - eq("Command cannot accept register: set", - pcall_err(meths.cmd, { cmd = "set", args = {}, reg = 'x' }, {})) - eq('Cannot use register "=', - pcall_err(meths.cmd, { cmd = "put", args = {}, reg = '=' }, {})) - eq("Invalid 'reg': expected single character, got xx", - pcall_err(meths.cmd, { cmd = "put", args = {}, reg = 'xx' }, {})) + eq("Invalid 'cmd': expected non-empty String", pcall_err(api.nvim_cmd, { cmd = '' }, {})) + eq("Invalid 'cmd': expected String, got Array", pcall_err(api.nvim_cmd, { cmd = {} }, {})) + eq( + "Invalid 'args': expected Array, got Boolean", + pcall_err(api.nvim_cmd, { cmd = 'set', args = true }, {}) + ) + eq( + 'Invalid command arg: expected non-whitespace', + pcall_err(api.nvim_cmd, { cmd = 'set', args = { ' ' } }, {}) + ) + eq( + 'Invalid command arg: expected valid type, got Array', + pcall_err(api.nvim_cmd, { cmd = 'set', args = { {} } }, {}) + ) + eq('Wrong number of arguments', pcall_err(api.nvim_cmd, { cmd = 'aboveleft', args = {} }, {})) + eq( + 'Command cannot accept bang: print', + pcall_err(api.nvim_cmd, { cmd = 'print', args = {}, bang = true }, {}) + ) + + eq( + 'Command cannot accept range: set', + pcall_err(api.nvim_cmd, { cmd = 'set', args = {}, range = { 1 } }, {}) + ) + eq( + "Invalid 'range': expected Array, got Boolean", + pcall_err(api.nvim_cmd, { cmd = 'print', args = {}, range = true }, {}) + ) + eq( + "Invalid 'range': expected <=2 elements", + pcall_err(api.nvim_cmd, { cmd = 'print', args = {}, range = { 1, 2, 3, 4 } }, {}) + ) + eq( + 'Invalid range element: expected non-negative Integer', + pcall_err(api.nvim_cmd, { cmd = 'print', args = {}, range = { -1 } }, {}) + ) + + eq( + 'Command cannot accept count: set', + pcall_err(api.nvim_cmd, { cmd = 'set', args = {}, count = 1 }, {}) + ) + eq( + "Invalid 'count': expected Integer, got Boolean", + pcall_err(api.nvim_cmd, { cmd = 'print', args = {}, count = true }, {}) + ) + eq( + "Invalid 'count': expected non-negative Integer", + pcall_err(api.nvim_cmd, { cmd = 'print', args = {}, count = -1 }, {}) + ) + + eq( + 'Command cannot accept register: set', + pcall_err(api.nvim_cmd, { cmd = 'set', args = {}, reg = 'x' }, {}) + ) + eq( + 'Cannot use register "=', + pcall_err(api.nvim_cmd, { cmd = 'put', args = {}, reg = '=' }, {}) + ) + eq( + "Invalid 'reg': expected single character, got xx", + pcall_err(api.nvim_cmd, { cmd = 'put', args = {}, reg = 'xx' }, {}) + ) -- #20681 - eq('Invalid command: "win_getid"', pcall_err(meths.cmd, { cmd = 'win_getid'}, {})) - eq('Invalid command: "echo "hi""', pcall_err(meths.cmd, { cmd = 'echo "hi"'}, {})) + eq('Invalid command: "win_getid"', pcall_err(api.nvim_cmd, { cmd = 'win_getid' }, {})) + eq('Invalid command: "echo "hi""', pcall_err(api.nvim_cmd, { cmd = 'echo "hi"' }, {})) eq('Invalid command: "win_getid"', pcall_err(exec_lua, [[return vim.cmd.win_getid{}]])) -- Lua call allows empty {} for dict item. eq('', exec_lua([[return vim.cmd{ cmd = "set", args = {}, magic = {} }]])) eq('', exec_lua([[return vim.cmd{ cmd = "set", args = {}, mods = {} }]])) - eq('', meths.cmd({ cmd = "set", args = {}, magic = {} }, {})) + eq('', api.nvim_cmd({ cmd = 'set', args = {}, magic = {} }, {})) -- Lua call does not allow non-empty list-like {} for dict item. - eq("Invalid 'magic': Expected Dict-like Lua table", - pcall_err(exec_lua, [[return vim.cmd{ cmd = "set", args = {}, magic = { 'a' } }]])) - eq("Invalid key: 'bogus'", - pcall_err(exec_lua, [[return vim.cmd{ cmd = "set", args = {}, magic = { bogus = true } }]])) - eq("Invalid key: 'bogus'", - pcall_err(exec_lua, [[return vim.cmd{ cmd = "set", args = {}, mods = { bogus = true } }]])) + eq( + "Invalid 'magic': Expected Dict-like Lua table", + pcall_err(exec_lua, [[return vim.cmd{ cmd = "set", args = {}, magic = { 'a' } }]]) + ) + eq( + "Invalid key: 'bogus'", + pcall_err(exec_lua, [[return vim.cmd{ cmd = "set", args = {}, magic = { bogus = true } }]]) + ) + eq( + "Invalid key: 'bogus'", + pcall_err(exec_lua, [[return vim.cmd{ cmd = "set", args = {}, mods = { bogus = true } }]]) + ) end) it('captures output', function() - eq("foo", meths.cmd({ cmd = "echo", args = { '"foo"' } }, { output = true })) + eq('foo', api.nvim_cmd({ cmd = 'echo', args = { '"foo"' } }, { output = true })) end) it('sets correct script context', function() - meths.cmd({ cmd = "set", args = { "cursorline" } }, {}) + api.nvim_cmd({ cmd = 'set', args = { 'cursorline' } }, {}) local str = exec_capture([[verbose set cursorline?]]) - neq(nil, str:find("cursorline\n\tLast set from API client %(channel id %d+%)")) + neq(nil, str:find('cursorline\n\tLast set from API client %(channel id %d+%)')) end) it('works with range', function() @@ -4313,7 +4615,7 @@ describe('API', function() line5 line6 ]] - meths.cmd({ cmd = "del", range = {2, 4} }, {}) + api.nvim_cmd({ cmd = 'del', range = { 2, 4 } }, {}) expect [[ line1 you didn't expect this @@ -4321,6 +4623,7 @@ describe('API', function() line6 ]] end) + it('works with count', function() insert [[ line1 @@ -4331,13 +4634,14 @@ describe('API', function() line5 line6 ]] - meths.cmd({ cmd = "del", range = { 2 }, count = 4 }, {}) + api.nvim_cmd({ cmd = 'del', range = { 2 }, count = 4 }, {}) expect [[ line1 line5 line6 ]] end) + it('works with register', function() insert [[ line1 @@ -4348,7 +4652,7 @@ describe('API', function() line5 line6 ]] - meths.cmd({ cmd = "del", range = { 2, 4 }, reg = 'a' }, {}) + api.nvim_cmd({ cmd = 'del', range = { 2, 4 }, reg = 'a' }, {}) command('1put a') expect [[ line1 @@ -4360,192 +4664,293 @@ describe('API', function() line6 ]] end) - it('works with bang', function () - meths.create_user_command("Foo", 'echo "<bang>"', { bang = true }) - eq("!", meths.cmd({ cmd = "Foo", bang = true }, { output = true })) - eq("", meths.cmd({ cmd = "Foo", bang = false }, { output = true })) + + it('works with bang', function() + api.nvim_create_user_command('Foo', 'echo "<bang>"', { bang = true }) + eq('!', api.nvim_cmd({ cmd = 'Foo', bang = true }, { output = true })) + eq('', api.nvim_cmd({ cmd = 'Foo', bang = false }, { output = true })) end) + it('works with modifiers', function() -- with silent = true output is still captured - eq('1', - meths.cmd({ cmd = 'echomsg', args = { '1' }, mods = { silent = true } }, - { output = true })) + eq( + '1', + api.nvim_cmd( + { cmd = 'echomsg', args = { '1' }, mods = { silent = true } }, + { output = true } + ) + ) -- but message isn't added to message history - eq('', meths.cmd({ cmd = 'messages' }, { output = true })) - - meths.create_user_command("Foo", 'set verbose', {}) - eq(" verbose=1", meths.cmd({ cmd = "Foo", mods = { verbose = 1 } }, { output = true })) - - meths.create_user_command("Mods", "echo '<mods>'", {}) - eq('keepmarks keeppatterns silent 3verbose aboveleft horizontal', - meths.cmd({ cmd = "Mods", mods = { - horizontal = true, - keepmarks = true, - keeppatterns = true, - silent = true, - split = 'aboveleft', - verbose = 3, - } }, { output = true })) - eq(0, meths.get_option_value("verbose", {})) + eq('', api.nvim_cmd({ cmd = 'messages' }, { output = true })) + + api.nvim_create_user_command('Foo', 'set verbose', {}) + eq(' verbose=1', api.nvim_cmd({ cmd = 'Foo', mods = { verbose = 1 } }, { output = true })) + + api.nvim_create_user_command('Mods', "echo '<mods>'", {}) + eq( + 'keepmarks keeppatterns silent 3verbose aboveleft horizontal', + api.nvim_cmd({ + cmd = 'Mods', + mods = { + horizontal = true, + keepmarks = true, + keeppatterns = true, + silent = true, + split = 'aboveleft', + verbose = 3, + }, + }, { output = true }) + ) + eq(0, api.nvim_get_option_value('verbose', {})) command('edit foo.txt | edit bar.txt') - eq(' 1 #h "foo.txt" line 1', - meths.cmd({ cmd = "buffers", mods = { filter = { pattern = "foo", force = false } } }, - { output = true })) - eq(' 2 %a "bar.txt" line 1', - meths.cmd({ cmd = "buffers", mods = { filter = { pattern = "foo", force = true } } }, - { output = true })) + eq( + ' 1 #h "foo.txt" line 1', + api.nvim_cmd( + { cmd = 'buffers', mods = { filter = { pattern = 'foo', force = false } } }, + { output = true } + ) + ) + eq( + ' 2 %a "bar.txt" line 1', + api.nvim_cmd( + { cmd = 'buffers', mods = { filter = { pattern = 'foo', force = true } } }, + { output = true } + ) + ) -- with emsg_silent = true error is suppressed feed([[:lua vim.api.nvim_cmd({ cmd = 'call', mods = { emsg_silent = true } }, {})<CR>]]) - eq('', meths.cmd({ cmd = 'messages' }, { output = true })) + eq('', api.nvim_cmd({ cmd = 'messages' }, { output = true })) -- error from the next command typed is not suppressed #21420 feed(':call<CR><CR>') - eq('E471: Argument required', meths.cmd({ cmd = 'messages' }, { output = true })) + eq('E471: Argument required', api.nvim_cmd({ cmd = 'messages' }, { output = true })) end) + it('works with magic.file', function() exec_lua([[ vim.api.nvim_create_user_command("Foo", function(opts) vim.api.nvim_echo({{ opts.fargs[1] }}, false, {}) end, { nargs = 1 }) ]]) - eq(luv.cwd(), - meths.cmd({ cmd = "Foo", args = { '%:p:h' }, magic = { file = true } }, - { output = true })) + eq( + uv.cwd(), + api.nvim_cmd( + { cmd = 'Foo', args = { '%:p:h' }, magic = { file = true } }, + { output = true } + ) + ) end) + it('splits arguments correctly', function() exec([[ function! FooFunc(...) echo a:000 endfunction ]]) - meths.create_user_command("Foo", "call FooFunc(<f-args>)", { nargs = '+' }) - eq([=[['a quick', 'brown fox', 'jumps over the', 'lazy dog']]=], - meths.cmd({ cmd = "Foo", args = { "a quick", "brown fox", "jumps over the", "lazy dog"}}, - { output = true })) - eq([=[['test \ \\ \"""\', 'more\ tests\" ']]=], - meths.cmd({ cmd = "Foo", args = { [[test \ \\ \"""\]], [[more\ tests\" ]] } }, - { output = true })) + api.nvim_create_user_command('Foo', 'call FooFunc(<f-args>)', { nargs = '+' }) + eq( + [=[['a quick', 'brown fox', 'jumps over the', 'lazy dog']]=], + api.nvim_cmd( + { cmd = 'Foo', args = { 'a quick', 'brown fox', 'jumps over the', 'lazy dog' } }, + { output = true } + ) + ) + eq( + [=[['test \ \\ \"""\', 'more\ tests\" ']]=], + api.nvim_cmd( + { cmd = 'Foo', args = { [[test \ \\ \"""\]], [[more\ tests\" ]] } }, + { output = true } + ) + ) end) + it('splits arguments correctly for Lua callback', function() - meths.exec_lua([[ + api.nvim_exec_lua( + [[ local function FooFunc(opts) vim.print(opts.fargs) end vim.api.nvim_create_user_command("Foo", FooFunc, { nargs = '+' }) - ]], {}) - eq([[{ "a quick", "brown fox", "jumps over the", "lazy dog" }]], - meths.cmd({ cmd = "Foo", args = { "a quick", "brown fox", "jumps over the", "lazy dog"}}, - { output = true })) - eq([[{ 'test \\ \\\\ \\"""\\', 'more\\ tests\\" ' }]], - meths.cmd({ cmd = "Foo", args = { [[test \ \\ \"""\]], [[more\ tests\" ]] } }, - { output = true })) + ]], + {} + ) + eq( + [[{ "a quick", "brown fox", "jumps over the", "lazy dog" }]], + api.nvim_cmd( + { cmd = 'Foo', args = { 'a quick', 'brown fox', 'jumps over the', 'lazy dog' } }, + { output = true } + ) + ) + eq( + [[{ 'test \\ \\\\ \\"""\\', 'more\\ tests\\" ' }]], + api.nvim_cmd( + { cmd = 'Foo', args = { [[test \ \\ \"""\]], [[more\ tests\" ]] } }, + { output = true } + ) + ) end) + it('works with buffer names', function() - command("edit foo.txt | edit bar.txt") - meths.cmd({ cmd = "buffer", args = { "foo.txt" } }, {}) - eq("foo.txt", funcs.fnamemodify(meths.buf_get_name(0), ":t")) - meths.cmd({ cmd = "buffer", args = { "bar.txt" } }, {}) - eq("bar.txt", funcs.fnamemodify(meths.buf_get_name(0), ":t")) + command('edit foo.txt | edit bar.txt') + api.nvim_cmd({ cmd = 'buffer', args = { 'foo.txt' } }, {}) + eq('foo.txt', fn.fnamemodify(api.nvim_buf_get_name(0), ':t')) + api.nvim_cmd({ cmd = 'buffer', args = { 'bar.txt' } }, {}) + eq('bar.txt', fn.fnamemodify(api.nvim_buf_get_name(0), ':t')) end) + it('triggers CmdUndefined event if command is not found', function() - meths.exec_lua([[ + api.nvim_exec_lua( + [[ vim.api.nvim_create_autocmd("CmdUndefined", { pattern = "Foo", callback = function() vim.api.nvim_create_user_command("Foo", "echo 'foo'", {}) end }) - ]], {}) - eq("foo", meths.cmd({ cmd = "Foo" }, { output = true })) + ]], + {} + ) + eq('foo', api.nvim_cmd({ cmd = 'Foo' }, { output = true })) end) + it('errors if command is not implemented', function() - eq("Command not implemented: winpos", pcall_err(meths.cmd, { cmd = "winpos" }, {})) + eq('Command not implemented: winpos', pcall_err(api.nvim_cmd, { cmd = 'winpos' }, {})) end) + it('works with empty arguments list', function() - meths.cmd({ cmd = "update" }, {}) - meths.cmd({ cmd = "buffer", count = 0 }, {}) + api.nvim_cmd({ cmd = 'update' }, {}) + api.nvim_cmd({ cmd = 'buffer', count = 0 }, {}) end) - it('doesn\'t suppress errors when used in keymapping', function() - meths.exec_lua([[ + + it("doesn't suppress errors when used in keymapping", function() + api.nvim_exec_lua( + [[ vim.keymap.set("n", "[l", function() vim.api.nvim_cmd({ cmd = "echo", args = {"foo"} }, {}) end) - ]], {}) - feed("[l") - neq(nil, string.find(eval("v:errmsg"), "E5108:")) + ]], + {} + ) + feed('[l') + neq(nil, string.find(eval('v:errmsg'), 'E5108:')) end) + it('handles 0 range #19608', function() - meths.buf_set_lines(0, 0, -1, false, { "aa" }) - meths.cmd({ cmd = 'delete', range = { 0 } }, {}) + api.nvim_buf_set_lines(0, 0, -1, false, { 'aa' }) + api.nvim_cmd({ cmd = 'delete', range = { 0 } }, {}) command('undo') - eq({'aa'}, meths.buf_get_lines(0, 0, 1, false)) + eq({ 'aa' }, api.nvim_buf_get_lines(0, 0, 1, false)) assert_alive() end) + it('supports filename expansion', function() - meths.cmd({ cmd = 'argadd', args = { '%:p:h:t', '%:p:h:t' } }, {}) - local arg = funcs.expand('%:p:h:t') - eq({ arg, arg }, funcs.argv()) + api.nvim_cmd({ cmd = 'argadd', args = { '%:p:h:t', '%:p:h:t' } }, {}) + local arg = fn.expand('%:p:h:t') + eq({ arg, arg }, fn.argv()) end) - it("'make' command works when argument count isn't 1 #19696", function() + + it(":make command works when argument count isn't 1 #19696", function() command('set makeprg=echo') command('set shellquote=') - matches('^:!echo ', - meths.cmd({ cmd = 'make' }, { output = true })) + matches('^:!echo ', api.nvim_cmd({ cmd = 'make' }, { output = true })) assert_alive() - matches('^:!echo foo bar', - meths.cmd({ cmd = 'make', args = { 'foo', 'bar' } }, { output = true })) + matches( + '^:!echo foo bar', + api.nvim_cmd({ cmd = 'make', args = { 'foo', 'bar' } }, { output = true }) + ) assert_alive() - local arg_pesc = pesc(funcs.expand('%:p:h:t')) - matches(('^:!echo %s %s'):format(arg_pesc, arg_pesc), - meths.cmd({ cmd = 'make', args = { '%:p:h:t', '%:p:h:t' } }, { output = true })) + local arg_pesc = pesc(fn.expand('%:p:h:t')) + matches( + ('^:!echo %s %s'):format(arg_pesc, arg_pesc), + api.nvim_cmd({ cmd = 'make', args = { '%:p:h:t', '%:p:h:t' } }, { output = true }) + ) assert_alive() 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.cmd({cmd = 'echo', args = {[['hello']]}}, {output = true}) - screen:expect{grid=[[ + api.nvim_cmd({ cmd = 'echo', args = { [['hello']] } }, { output = true }) + screen:expect { + grid = [[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*4 | - ]]} + ]], + } exec([[ func Print() call nvim_cmd(#{cmd: 'echo', args: ['"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('works with non-String args', function() - eq('2', meths.cmd({cmd = 'echo', args = {2}}, {output = true})) - eq('1', meths.cmd({cmd = 'echo', args = {true}}, {output = true})) + eq('2', api.nvim_cmd({ cmd = 'echo', args = { 2 } }, { output = true })) + eq('1', api.nvim_cmd({ cmd = 'echo', args = { true } }, { output = true })) end) + describe('first argument as count', function() it('works', function() command('vsplit | enew') - meths.cmd({cmd = 'bdelete', args = {meths.get_current_buf()}}, {}) - eq(1, meths.get_current_buf().id) + api.nvim_cmd({ cmd = 'bdelete', args = { api.nvim_get_current_buf() } }, {}) + eq(1, api.nvim_get_current_buf()) end) + it('works with :sleep using milliseconds', function() - local start = luv.now() - meths.cmd({cmd = 'sleep', args = {'100m'}}, {}) - ok(luv.now() - start <= 300) + local start = uv.now() + api.nvim_cmd({ cmd = 'sleep', args = { '100m' } }, {}) + ok(uv.now() - start <= 300) end) end) + + it(':call with unknown function does not crash #26289', function() + eq( + 'Vim:E117: Unknown function: UnknownFunc', + pcall_err(api.nvim_cmd, { cmd = 'call', args = { 'UnknownFunc()' } }, {}) + ) + end) + + it(':throw does not crash #24556', function() + eq('42', pcall_err(api.nvim_cmd, { cmd = 'throw', args = { '42' } }, {})) + end) + + it('can use :return #24556', function() + exec([[ + func Foo() + let g:pos = 'before' + call nvim_cmd({'cmd': 'return', 'args': ['[1, 2, 3]']}, {}) + let g:pos = 'after' + endfunc + let g:result = Foo() + ]]) + eq('before', api.nvim_get_var('pos')) + eq({ 1, 2, 3 }, api.nvim_get_var('result')) + end) + + it('errors properly when command too recursive #27210', function() + exec_lua([[ + _G.success = false + vim.api.nvim_create_user_command('Test', function() + vim.api.nvim_cmd({ cmd = 'Test' }, {}) + _G.success = true + end, {}) + ]]) + pcall_err(command, 'Test') + assert_alive() + eq(false, exec_lua('return _G.success')) + end) end) end) |