aboutsummaryrefslogtreecommitdiff
path: root/test/functional/lua/vim_spec.lua
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/lua/vim_spec.lua')
-rw-r--r--test/functional/lua/vim_spec.lua376
1 files changed, 326 insertions, 50 deletions
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 3c65ec664e..3cfbfe167a 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -28,6 +28,7 @@ local rmdir = n.rmdir
local write_file = t.write_file
local poke_eventloop = n.poke_eventloop
local assert_alive = n.assert_alive
+local expect = n.expect
describe('lua stdlib', function()
before_each(clear)
@@ -155,10 +156,10 @@ describe('lua stdlib', function()
end)
it('plugin=nil, no error if soft-deprecated', function()
- eq(
- vim.NIL,
- exec_lua('return vim.deprecate(...)', 'foo.baz()', 'foo.better_baz()', '0.99.0')
- )
+ eq(vim.NIL, exec_lua [[return vim.deprecate('old1', 'new1', '0.99.0')]])
+ -- Major version > current Nvim major is always "soft-deprecated".
+ -- XXX: This is also a reminder to update the hardcoded `nvim_major`, when Nvim reaches 1.0.
+ eq(vim.NIL, exec_lua [[return vim.deprecate('old2', 'new2', '1.0.0')]])
end)
it('plugin=nil, show error if hard-deprecated', function()
@@ -175,13 +176,6 @@ describe('lua stdlib', function()
)
end)
- it('plugin=nil, to be deleted in the next major version (1.0)', function()
- eq(
- [[foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]],
- exec_lua [[ return vim.deprecate('foo.baz()', nil, '1.0') ]]
- )
- end)
-
it('plugin specified', function()
-- When `plugin` is specified, don't show ":help deprecated". #22235
eq(
@@ -319,21 +313,106 @@ describe('lua stdlib', function()
49,
51,
}
+ local indices8 = {
+ [0] = 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16,
+ 17,
+ 18,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 24,
+ 25,
+ 26,
+ 27,
+ 28,
+ 29,
+ 30,
+ 31,
+ 32,
+ 33,
+ 34,
+ 35,
+ 36,
+ 37,
+ 38,
+ 39,
+ 40,
+ 41,
+ 42,
+ 43,
+ 44,
+ 45,
+ 46,
+ 47,
+ 48,
+ 49,
+ 50,
+ 51,
+ }
for i, k in pairs(indices32) do
eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ...)', i), i)
+ eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., false)', i), i)
+ eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-32", ...)', i), i)
end
for i, k in pairs(indices16) do
eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., true)', i), i)
+ eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-16", ...)', i), i)
end
- eq(
+ for i, k in pairs(indices8) do
+ eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-8", ...)', i), i)
+ end
+ matches(
'index out of range',
pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ...)', #indices32 + 1)
)
- eq(
+ matches(
'index out of range',
pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ..., true)', #indices16 + 1)
)
- local i32, i16 = 0, 0
+ matches(
+ 'index out of range',
+ pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, "utf-16", ...)', #indices16 + 1)
+ )
+ matches(
+ 'index out of range',
+ pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, "utf-32", ...)', #indices32 + 1)
+ )
+ matches(
+ 'invalid encoding',
+ pcall_err(exec_lua, 'return vim.str_byteindex("hello", "madeupencoding", 1)')
+ )
+ eq(
+ indices32[#indices32],
+ exec_lua('return vim.str_byteindex(_G.test_text, "utf-32", 99999, false)')
+ )
+ eq(
+ indices16[#indices16],
+ exec_lua('return vim.str_byteindex(_G.test_text, "utf-16", 99999, false)')
+ )
+ eq(
+ indices8[#indices8],
+ exec_lua('return vim.str_byteindex(_G.test_text, "utf-8", 99999, false)')
+ )
+ eq(2, exec_lua('return vim.str_byteindex("é", "utf-16", 2, false)'))
+ local i32, i16, i8 = 0, 0, 0
local len = 51
for k = 0, len do
if indices32[i32] < k then
@@ -345,9 +424,29 @@ describe('lua stdlib', function()
i16 = i16 + 1
end
end
+ if indices8[i8] < k then
+ i8 = i8 + 1
+ end
eq({ i32, i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, ...)}', k), k)
+ eq({ i32 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-32", ...)}', k), k)
+ eq({ i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-16", ...)}', k), k)
+ eq({ i8 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-8", ...)}', k), k)
end
- eq(
+
+ eq({ #indices32, #indices16 }, exec_lua('return {vim.str_utfindex(_G.test_text)}'))
+
+ eq(#indices32, exec_lua('return vim.str_utfindex(_G.test_text, "utf-32", math.huge, false)'))
+ eq(#indices16, exec_lua('return vim.str_utfindex(_G.test_text, "utf-16", math.huge, false)'))
+ eq(#indices8, exec_lua('return vim.str_utfindex(_G.test_text, "utf-8", math.huge, false)'))
+
+ eq(#indices32, exec_lua('return vim.str_utfindex(_G.test_text, "utf-32")'))
+ eq(#indices16, exec_lua('return vim.str_utfindex(_G.test_text, "utf-16")'))
+ eq(#indices8, exec_lua('return vim.str_utfindex(_G.test_text, "utf-8")'))
+ matches(
+ 'invalid encoding',
+ pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, "madeupencoding", ...)', 1)
+ )
+ matches(
'index out of range',
pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, ...)', len + 1)
)
@@ -538,7 +637,6 @@ describe('lua stdlib', function()
matches('big failure\nvery async', remove_trace(eval('v:errmsg')))
local screen = Screen.new(60, 5)
- screen:attach()
screen:expect {
grid = [[
^ |
@@ -1304,7 +1402,6 @@ describe('lua stdlib', function()
end)
local screen = Screen.new(50, 7)
- screen:attach()
exec_lua([[
timer = vim.uv.new_timer()
timer:start(20, 0, function ()
@@ -1317,7 +1414,7 @@ describe('lua stdlib', function()
screen:expect {
grid = [[
{9:[string "<nvim>"]:6: E5560: rpcrequest must not be}|
- {9: called in a lua loop callback} |
+ {9: called in a fast event context} |
{9:stack traceback:} |
{9: [C]: in function 'rpcrequest'} |
{9: [string "<nvim>"]:6: in function <[string }|
@@ -1326,7 +1423,9 @@ describe('lua stdlib', function()
]],
}
feed('<cr>')
- eq({ 3, NIL }, api.nvim_get_var('yy'))
+ retry(10, nil, function()
+ eq({ 3, NIL }, api.nvim_get_var('yy'))
+ end)
exec_lua([[timer:close()]])
end)
@@ -1363,7 +1462,79 @@ describe('lua stdlib', function()
eq('{"a": {}, "b": []}', exec_lua([[ return vim.fn.json_encode({a=vim.empty_dict(), b={}}) ]]))
end)
- it('vim.validate', function()
+ it('vim.validate (fast form)', function()
+ exec_lua("vim.validate('arg1', {}, 'table')")
+ exec_lua("vim.validate('arg1', nil, 'table', true)")
+ exec_lua("vim.validate('arg1', { foo='foo' }, 'table')")
+ exec_lua("vim.validate('arg1', { 'foo' }, 'table')")
+ exec_lua("vim.validate('arg1', 'foo', 'string')")
+ exec_lua("vim.validate('arg1', nil, 'string', true)")
+ exec_lua("vim.validate('arg1', 1, 'number')")
+ exec_lua("vim.validate('arg1', 0, 'number')")
+ exec_lua("vim.validate('arg1', 0.1, 'number')")
+ exec_lua("vim.validate('arg1', nil, 'number', true)")
+ exec_lua("vim.validate('arg1', true, 'boolean')")
+ exec_lua("vim.validate('arg1', false, 'boolean')")
+ exec_lua("vim.validate('arg1', nil, 'boolean', true)")
+ exec_lua("vim.validate('arg1', function()end, 'function')")
+ exec_lua("vim.validate('arg1', nil, 'function', true)")
+ exec_lua("vim.validate('arg1', nil, 'nil')")
+ exec_lua("vim.validate('arg1', nil, 'nil', true)")
+ exec_lua("vim.validate('arg1', coroutine.create(function()end), 'thread')")
+ exec_lua("vim.validate('arg1', nil, 'thread', true)")
+ exec_lua("vim.validate('arg1', 2, function(a) return (a % 2) == 0 end, 'even number')")
+ exec_lua("vim.validate('arg1', 5, {'number', 'string'})")
+ exec_lua("vim.validate('arg2', 'foo', {'number', 'string'})")
+
+ matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number'))
+ matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string'))
+ matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table'))
+ matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function'))
+ matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string'))
+ matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table'))
+ matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function'))
+ matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number'))
+ matches('arg1: expected x, got number', pcall_err(exec_lua, "vim.validate('arg1', 1, 'x')"))
+ matches('invalid validator: 1', pcall_err(exec_lua, "vim.validate('arg1', 1, 1)"))
+ matches('invalid arguments', pcall_err(exec_lua, "vim.validate('arg1', { 1 })"))
+
+ -- Validated parameters are required by default.
+ matches(
+ 'arg1: expected string, got nil',
+ pcall_err(exec_lua, "vim.validate('arg1', nil, 'string')")
+ )
+ -- Explicitly required.
+ matches(
+ 'arg1: expected string, got nil',
+ pcall_err(exec_lua, "vim.validate('arg1', nil, 'string', false)")
+ )
+
+ matches(
+ 'arg1: expected table, got number',
+ pcall_err(exec_lua, "vim.validate('arg1', 1, 'table')")
+ )
+
+ matches(
+ 'arg1: expected even number, got 3',
+ pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1 end, 'even number')")
+ )
+ matches(
+ 'arg1: expected %?, got 3',
+ pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1 end)")
+ )
+ matches(
+ 'arg1: expected number|string, got nil',
+ pcall_err(exec_lua, "vim.validate('arg1', nil, {'number', 'string'})")
+ )
+
+ -- Pass an additional message back.
+ matches(
+ 'arg1: expected %?, got 3. Info: TEST_MSG',
+ pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1, 'TEST_MSG' end)")
+ )
+ end)
+
+ it('vim.validate (spec form)', function()
exec_lua("vim.validate{arg1={{}, 'table' }}")
exec_lua("vim.validate{arg1={{}, 't' }}")
exec_lua("vim.validate{arg1={nil, 't', true }}")
@@ -1392,29 +1563,11 @@ describe('lua stdlib', function()
exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}")
exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}")
exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}")
- vim.validate('arg1', 5, 'number')
- vim.validate('arg1', '5', 'string')
- vim.validate('arg1', { 5 }, 'table')
- vim.validate('arg1', function()
- return 5
- end, 'function')
- vim.validate('arg1', nil, 'number', true)
- vim.validate('arg1', nil, 'string', true)
- vim.validate('arg1', nil, 'table', true)
- vim.validate('arg1', nil, 'function', true)
- matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number'))
- matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string'))
- matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table'))
- matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function'))
- matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string'))
- matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table'))
- matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function'))
- matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number'))
matches('expected table, got number', pcall_err(exec_lua, "vim.validate{ 1, 'x' }"))
- matches('invalid type name: x', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
- matches('invalid type name: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}'))
- matches('invalid type name: nil', pcall_err(exec_lua, 'vim.validate{ arg1={ 1 }}'))
+ matches('arg1: expected x, got number', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
+ matches('invalid validator: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}'))
+ matches('invalid validator: nil', pcall_err(exec_lua, 'vim.validate{ arg1={ 1 }}'))
-- Validated parameters are required by default.
matches(
@@ -1975,7 +2128,6 @@ describe('lua stdlib', function()
eq({ 1, 5 }, api.nvim_win_get_cursor(0))
local screen = Screen.new(60, 3)
- screen:attach()
eq(1, eval('v:hlsearch'))
screen:expect {
grid = [[
@@ -3157,10 +3309,17 @@ describe('lua stdlib', function()
eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]])
end)
- it('skips any function that caused an error', function()
+ it('skips any function that caused an error and shows stacktrace', function()
insert([[hello world]])
exec_lua [[
+ local function ErrF2()
+ error("Dumb Error")
+ end
+ local function ErrF1()
+ ErrF2()
+ end
+
keys = {}
return vim.on_key(function(buf)
@@ -3171,7 +3330,7 @@ describe('lua stdlib', function()
table.insert(keys, buf)
if buf == 'l' then
- error("Dumb Error")
+ ErrF1()
end
end)
]]
@@ -3181,6 +3340,19 @@ describe('lua stdlib', function()
-- Only the first letter gets added. After that we remove the callback
eq('inext l', exec_lua [[ return table.concat(keys, '') ]])
+
+ local errmsg = api.nvim_get_vvar('errmsg')
+ matches(
+ [[
+^Error executing vim%.on%_key%(%) callbacks:.*
+With ns%_id %d+: .*: Dumb Error
+stack traceback:
+.*: in function 'error'
+.*: in function 'ErrF2'
+.*: in function 'ErrF1'
+.*]],
+ errmsg
+ )
end)
it('argument 1 is keys after mapping, argument 2 is typed keys', function()
@@ -3223,6 +3395,109 @@ describe('lua stdlib', function()
feed('<C-C>')
eq('/', exec_lua([[return _G.ctrl_c_cmdtype]]))
end)
+
+ it('callback is not invoked recursively #30752', function()
+ local screen = Screen.new(60, 10)
+ exec_lua([[
+ vim.on_key(function(key, typed)
+ vim.api.nvim_echo({
+ { 'key_cb\n' },
+ { ("KEYCB: key '%s', typed '%s'\n"):format(key, typed) },
+ }, false, {})
+ end)
+ ]])
+ feed('^')
+ screen:expect([[
+ |
+ {1:~ }|*5
+ {3: }|
+ key_cb |
+ KEYCB: key '^', typed '^' |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<C-C>')
+ screen:expect([[
+ |
+ {1:~ }|*3
+ {3: }|
+ key_cb |
+ KEYCB: key '^', typed '^' |
+ key_cb |
+ KEYCB: key '{18:^C}', typed '{18:^C}' |
+ {6:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<C-C>')
+ screen:expect([[
+ ^ |
+ {1:~ }|*8
+ |
+ ]])
+ end)
+
+ it('can discard input', function()
+ clear()
+ -- discard every other normal 'x' command
+ exec_lua [[
+ n_key = 0
+
+ vim.on_key(function(buf, typed_buf)
+ if typed_buf == 'x' then
+ n_key = n_key + 1
+ end
+ return (n_key % 2 == 0) and "" or nil
+ end)
+ ]]
+
+ api.nvim_buf_set_lines(0, 0, -1, true, { '54321' })
+
+ feed('x')
+ expect('4321')
+ feed('x')
+ expect('4321')
+ feed('x')
+ expect('321')
+ feed('x')
+ expect('321')
+ end)
+
+ it('callback invalid return', function()
+ clear()
+ -- second key produces an error which removes the callback
+ exec_lua [[
+ n_call = 0
+
+ vim.on_key(function(buf, typed_buf)
+ if typed_buf == 'x' then
+ n_call = n_call + 1
+ end
+ return n_call >= 2 and '!' or nil
+ end)
+ ]]
+
+ api.nvim_buf_set_lines(0, 0, -1, true, { '54321' })
+
+ local function cleanup_msg(msg)
+ return msg:gsub('^Error .*\nWith ns%_id %d+: ', '')
+ end
+
+ feed('x')
+ eq(1, exec_lua [[ return n_call ]])
+
+ eq(1, exec_lua [[ return vim.on_key(nil, nil) ]])
+
+ eq('', cleanup_msg(eval('v:errmsg')))
+ feed('x')
+ eq(2, exec_lua [[ return n_call ]])
+ eq('return string must be empty', cleanup_msg(eval('v:errmsg')))
+ command('let v:errmsg = ""')
+
+ eq(0, exec_lua [[ return vim.on_key(nil, nil) ]])
+
+ feed('x')
+ eq(2, exec_lua [[ return n_call ]])
+ expect('21')
+ eq('', cleanup_msg(eval('v:errmsg')))
+ end)
end)
describe('vim.wait', function()
@@ -3500,7 +3775,6 @@ describe('lua stdlib', function()
it('fails in fast callbacks #26122', function()
local screen = Screen.new(80, 10)
- screen:attach()
exec_lua([[
local timer = vim.uv.new_timer()
timer:start(0, 0, function()
@@ -3509,7 +3783,7 @@ describe('lua stdlib', function()
end)
]])
screen:expect({
- any = pesc('E5560: vim.wait must not be called in a lua loop callback'),
+ any = pesc('E5560: vim.wait must not be called in a fast event context'),
})
feed('<CR>')
assert_alive()
@@ -3518,7 +3792,6 @@ describe('lua stdlib', function()
it('vim.notify_once', function()
local screen = Screen.new(60, 5)
- screen:attach()
screen:expect {
grid = [[
^ |
@@ -3715,7 +3988,6 @@ describe('lua stdlib', function()
it('updates ruler if cursor moved', function()
-- Fixed for win_execute in vim-patch:8.1.2124, but should've applied to nvim_win_call too!
local screen = Screen.new(30, 5)
- screen:attach()
exec_lua [[
_G.api = vim.api
vim.opt.ruler = true
@@ -3858,7 +4130,6 @@ describe('lua stdlib', function()
it('vim.lua_omnifunc', function()
local screen = Screen.new(60, 5)
- screen:attach()
command [[ set omnifunc=v:lua.vim.lua_omnifunc ]]
-- Note: the implementation is shared with lua command line completion.
@@ -4060,11 +4331,16 @@ describe('vim.keymap', function()
)
matches(
- 'opts: expected table, got function',
+ 'rhs: expected string|function, got number',
pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 42, function() end)]])
)
matches(
+ 'opts: expected table, got function',
+ pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 'x', function() end)]])
+ )
+
+ matches(
'rhs: expected string|function, got number',
pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 42)]])
)