2017-01-20 14:00:47 -07:00
|
|
|
-- Test suite for testing luaeval() function
|
2024-04-20 08:44:13 -07:00
|
|
|
local t = require('test.testutil')
|
|
|
|
local n = require('test.functional.testnvim')()
|
2019-10-30 12:53:09 -07:00
|
|
|
local Screen = require('test.functional.ui.screen')
|
2017-01-20 14:00:47 -07:00
|
|
|
|
2024-04-08 02:03:20 -07:00
|
|
|
local pcall_err = t.pcall_err
|
2024-04-20 08:44:13 -07:00
|
|
|
local exc_exec = n.exc_exec
|
2024-04-08 02:03:20 -07:00
|
|
|
local remove_trace = t.remove_trace
|
2024-04-20 08:44:13 -07:00
|
|
|
local exec_lua = n.exec_lua
|
|
|
|
local command = n.command
|
|
|
|
local api = n.api
|
|
|
|
local fn = n.fn
|
|
|
|
local clear = n.clear
|
|
|
|
local eval = n.eval
|
|
|
|
local feed = n.feed
|
2024-01-12 04:28:20 -07:00
|
|
|
local NIL = vim.NIL
|
2024-04-08 02:03:20 -07:00
|
|
|
local eq = t.eq
|
2017-01-20 14:00:47 -07:00
|
|
|
|
|
|
|
before_each(clear)
|
|
|
|
|
2017-01-20 15:10:44 -07:00
|
|
|
local function startswith(expected, actual)
|
|
|
|
eq(expected, actual:sub(1, #expected))
|
|
|
|
end
|
|
|
|
|
2017-01-20 14:00:47 -07:00
|
|
|
describe('luaeval()', function()
|
2017-01-20 15:10:44 -07:00
|
|
|
local nested_by_level = {}
|
|
|
|
local nested = {}
|
|
|
|
local nested_s = '{}'
|
|
|
|
for i=1,100 do
|
|
|
|
if i % 2 == 0 then
|
|
|
|
nested = {nested}
|
|
|
|
nested_s = '{' .. nested_s .. '}'
|
|
|
|
else
|
|
|
|
nested = {nested=nested}
|
|
|
|
nested_s = '{nested=' .. nested_s .. '}'
|
|
|
|
end
|
|
|
|
nested_by_level[i] = {o=nested, s=nested_s}
|
|
|
|
end
|
|
|
|
|
2017-01-20 14:00:47 -07:00
|
|
|
describe('second argument', function()
|
|
|
|
it('is successfully received', function()
|
2024-04-08 02:03:20 -07:00
|
|
|
local q = {t=true, f=false, --[[n=NIL,]] d={l={'string', 42, 0.42}}}
|
|
|
|
eq(q, fn.luaeval("_A", q))
|
2017-01-29 08:40:39 -07:00
|
|
|
-- Not tested: nil, funcrefs, returned object identity: behaviour will
|
2017-01-20 14:00:47 -07:00
|
|
|
-- most likely change.
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
describe('lua values', function()
|
|
|
|
it('are successfully transformed', function()
|
|
|
|
eq({n=1, f=1.5, s='string', l={4, 2}},
|
2024-01-12 10:59:57 -07:00
|
|
|
fn.luaeval('{n=1, f=1.5, s="string", l={4, 2}}'))
|
2017-01-20 14:00:47 -07:00
|
|
|
-- Not tested: nil inside containers: behaviour will most likely change.
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(NIL, fn.luaeval('nil'))
|
|
|
|
eq({['']=1}, fn.luaeval('{[""]=1}'))
|
2017-01-20 14:00:47 -07:00
|
|
|
end)
|
|
|
|
end)
|
|
|
|
describe('recursive lua values', function()
|
|
|
|
it('are successfully transformed', function()
|
2018-05-06 18:24:01 -07:00
|
|
|
command('lua rawset(_G, "d", {})')
|
|
|
|
command('lua rawset(d, "d", d)')
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('\n{\'d\': {...@0}}', fn.execute('echo luaeval("d")'))
|
2017-01-20 14:00:47 -07:00
|
|
|
|
2018-05-06 18:24:01 -07:00
|
|
|
command('lua rawset(_G, "l", {})')
|
|
|
|
command('lua table.insert(l, l)')
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('\n[[...@0]]', fn.execute('echo luaeval("l")'))
|
2017-01-20 14:00:47 -07:00
|
|
|
end)
|
|
|
|
end)
|
2021-07-31 13:45:58 -07:00
|
|
|
describe('strings with NULs', function()
|
|
|
|
it('are successfully converted to blobs', function()
|
2017-01-20 14:00:47 -07:00
|
|
|
command([[let s = luaeval('"\0"')]])
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('\000', api.nvim_get_var('s'))
|
2017-01-20 14:00:47 -07:00
|
|
|
end)
|
2023-12-17 21:14:37 -07:00
|
|
|
it('are successfully converted to special dictionaries in table keys', function()
|
2017-01-20 14:00:47 -07:00
|
|
|
command([[let d = luaeval('{["\0"]=1}')]])
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n'}}, 1}}}, api.nvim_get_var('d'))
|
|
|
|
eq(1, fn.eval('d._TYPE is v:msgpack_types.map'))
|
|
|
|
eq(1, fn.eval('d._VAL[0][0]._TYPE is v:msgpack_types.string'))
|
2017-01-20 14:00:47 -07:00
|
|
|
end)
|
2023-12-17 21:14:37 -07:00
|
|
|
it('are successfully converted to blobs from a list', function()
|
2017-01-20 14:00:47 -07:00
|
|
|
command([[let l = luaeval('{"abc", "a\0b", "c\0d", "def"}')]])
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({'abc', 'a\000b', 'c\000d', 'def'}, api.nvim_get_var('l'))
|
2017-01-20 14:00:47 -07:00
|
|
|
end)
|
|
|
|
end)
|
2017-01-20 15:10:44 -07:00
|
|
|
|
|
|
|
-- Not checked: funcrefs converted to NIL. To be altered to something more
|
|
|
|
-- meaningful later.
|
|
|
|
|
|
|
|
it('correctly evaluates scalars', function()
|
2021-08-31 15:49:43 -07:00
|
|
|
-- Also test method call (->) syntax
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(1, fn.luaeval('1'))
|
2021-08-31 15:49:43 -07:00
|
|
|
eq(0, eval('"1"->luaeval()->type()'))
|
2017-01-20 15:10:44 -07:00
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(1.5, fn.luaeval('1.5'))
|
2021-08-31 15:49:43 -07:00
|
|
|
eq(5, eval('"1.5"->luaeval()->type()'))
|
2017-01-20 15:10:44 -07:00
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
eq("test", fn.luaeval('"test"'))
|
2021-08-31 15:49:43 -07:00
|
|
|
eq(1, eval('"\'test\'"->luaeval()->type()'))
|
2017-01-20 15:10:44 -07:00
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
eq('', fn.luaeval('""'))
|
|
|
|
eq('\000', fn.luaeval([['\0']]))
|
|
|
|
eq('\000\n\000', fn.luaeval([['\0\n\0']]))
|
2021-07-31 13:45:58 -07:00
|
|
|
eq(10, eval([[type(luaeval("'\\0\\n\\0'"))]]))
|
2017-01-20 15:10:44 -07:00
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(true, fn.luaeval('true'))
|
|
|
|
eq(false, fn.luaeval('false'))
|
|
|
|
eq(NIL, fn.luaeval('nil'))
|
2017-01-20 15:10:44 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('correctly evaluates containers', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({}, fn.luaeval('{}'))
|
2017-01-20 15:10:44 -07:00
|
|
|
eq(3, eval('type(luaeval("{}"))'))
|
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({test=1, foo=2}, fn.luaeval('{test=1, foo=2}'))
|
2017-01-20 15:10:44 -07:00
|
|
|
eq(4, eval('type(luaeval("{test=1, foo=2}"))'))
|
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({4, 2}, fn.luaeval('{4, 2}'))
|
2017-01-20 15:10:44 -07:00
|
|
|
eq(3, eval('type(luaeval("{4, 2}"))'))
|
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({NIL, 20}, fn.luaeval('{[2] = 20}'))
|
2023-12-17 21:14:37 -07:00
|
|
|
eq(3, eval('type(luaeval("{[2] = 20}"))'))
|
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({10, NIL, 30}, fn.luaeval('{[1] = 10, [3] = 30}'))
|
2023-12-17 21:14:37 -07:00
|
|
|
eq(3, eval('type(luaeval("{[1] = 10, [3] = 30}"))'))
|
|
|
|
|
2017-01-20 15:10:44 -07:00
|
|
|
local level = 30
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(nested_by_level[level].o, fn.luaeval(nested_by_level[level].s))
|
2017-01-20 15:10:44 -07:00
|
|
|
|
2021-07-31 13:45:58 -07:00
|
|
|
eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}},
|
2024-01-12 10:59:57 -07:00
|
|
|
fn.luaeval([[{['\0\n\0']='\0\n\0\0'}]]))
|
2017-01-20 15:10:44 -07:00
|
|
|
eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._TYPE is v:msgpack_types.map]]))
|
|
|
|
eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0]._TYPE is v:msgpack_types.string]]))
|
2021-07-31 13:45:58 -07:00
|
|
|
eq({nested={{_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}}}},
|
2024-01-12 10:59:57 -07:00
|
|
|
fn.luaeval([[{nested={{['\0\n\0']='\0\n\0\0'}}}]]))
|
2017-01-20 15:10:44 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('correctly passes scalars as argument', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(1, fn.luaeval('_A', 1))
|
|
|
|
eq(1.5, fn.luaeval('_A', 1.5))
|
|
|
|
eq('', fn.luaeval('_A', ''))
|
|
|
|
eq('test', fn.luaeval('_A', 'test'))
|
|
|
|
eq(NIL, fn.luaeval('_A', NIL))
|
|
|
|
eq(true, fn.luaeval('_A', true))
|
|
|
|
eq(false, fn.luaeval('_A', false))
|
2017-01-20 15:10:44 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('correctly passes containers as argument', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({}, fn.luaeval('_A', {}))
|
|
|
|
eq({test=1}, fn.luaeval('_A', {test=1}))
|
|
|
|
eq({4, 2}, fn.luaeval('_A', {4, 2}))
|
2017-01-20 15:10:44 -07:00
|
|
|
local level = 28
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(nested_by_level[level].o, fn.luaeval('_A', nested_by_level[level].o))
|
2017-01-20 15:10:44 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
local function sp(typ, val)
|
|
|
|
return ('{"_TYPE": v:msgpack_types.%s, "_VAL": %s}'):format(typ, val)
|
|
|
|
end
|
|
|
|
local function mapsp(...)
|
|
|
|
local val = ''
|
|
|
|
for i=1,(select('#', ...)/2) do
|
|
|
|
val = ('%s[%s,%s],'):format(val, select(i * 2 - 1, ...),
|
|
|
|
select(i * 2, ...))
|
|
|
|
end
|
|
|
|
return sp('map', '[' .. val .. ']')
|
|
|
|
end
|
|
|
|
local function luaevalarg(argexpr, expr)
|
2024-01-15 09:10:51 -07:00
|
|
|
return eval((([=[
|
2017-01-20 15:10:44 -07:00
|
|
|
[
|
|
|
|
extend(g:, {'_ret': luaeval(%s, %s)})._ret,
|
|
|
|
type(g:_ret)==type({})&&has_key(g:_ret, '_TYPE')
|
|
|
|
? [
|
|
|
|
get(keys(filter(copy(v:msgpack_types), 'v:val is g:_ret._TYPE')), 0,
|
|
|
|
g:_ret._TYPE),
|
|
|
|
get(g:_ret, '_VAL', g:_ret)
|
|
|
|
]
|
|
|
|
: [0, g:_ret]][1]
|
2024-01-15 09:10:51 -07:00
|
|
|
]=]):format(expr or '"_A"', argexpr):gsub('\n', '')))
|
2017-01-20 15:10:44 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
it('correctly passes special dictionaries', function()
|
2021-07-31 13:45:58 -07:00
|
|
|
eq({0, '\000\n\000'}, luaevalarg(sp('binary', '["\\n", "\\n"]')))
|
|
|
|
eq({0, '\000\n\000'}, luaevalarg(sp('string', '["\\n", "\\n"]')))
|
2017-01-20 15:10:44 -07:00
|
|
|
eq({0, true}, luaevalarg(sp('boolean', 1)))
|
|
|
|
eq({0, false}, luaevalarg(sp('boolean', 0)))
|
|
|
|
eq({0, NIL}, luaevalarg(sp('nil', 0)))
|
|
|
|
eq({0, {[""]=""}}, luaevalarg(mapsp(sp('binary', '[""]'), '""')))
|
|
|
|
eq({0, {[""]=""}}, luaevalarg(mapsp(sp('string', '[""]'), '""')))
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('issues an error in some cases', function()
|
2023-12-17 21:14:37 -07:00
|
|
|
eq("Vim(call):E5100: Cannot convert given lua table: table should contain either only integer keys or only string keys",
|
2017-01-20 15:10:44 -07:00
|
|
|
exc_exec('call luaeval("{1, foo=2}")'))
|
2020-06-18 21:23:30 -07:00
|
|
|
|
2019-10-30 12:53:09 -07:00
|
|
|
startswith("Vim(call):E5107: Error loading lua [string \"luaeval()\"]:",
|
2017-01-20 15:10:44 -07:00
|
|
|
exc_exec('call luaeval("1, 2, 3")'))
|
2019-10-30 12:53:09 -07:00
|
|
|
startswith("Vim(call):E5108: Error executing lua [string \"luaeval()\"]:",
|
2017-01-20 15:10:44 -07:00
|
|
|
exc_exec('call luaeval("(nil)()")'))
|
2020-06-18 21:23:30 -07:00
|
|
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('should handle sending lua functions to viml', function()
|
|
|
|
eq(true, exec_lua [[
|
|
|
|
can_pass_lua_callback_to_vim_from_lua_result = nil
|
|
|
|
|
|
|
|
vim.fn.call(function()
|
|
|
|
can_pass_lua_callback_to_vim_from_lua_result = true
|
|
|
|
end, {})
|
|
|
|
|
|
|
|
return can_pass_lua_callback_to_vim_from_lua_result
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('run functions even in timers', function()
|
|
|
|
eq(true, exec_lua [[
|
|
|
|
can_pass_lua_callback_to_vim_from_lua_result = nil
|
|
|
|
|
|
|
|
vim.fn.timer_start(50, function()
|
|
|
|
can_pass_lua_callback_to_vim_from_lua_result = true
|
|
|
|
end)
|
|
|
|
|
|
|
|
vim.wait(1000, function()
|
|
|
|
return can_pass_lua_callback_to_vim_from_lua_result
|
|
|
|
end)
|
|
|
|
|
|
|
|
return can_pass_lua_callback_to_vim_from_lua_result
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('can run named functions more than once', function()
|
|
|
|
eq(5, exec_lua [[
|
|
|
|
count_of_vals = 0
|
|
|
|
|
|
|
|
vim.fn.timer_start(5, function()
|
|
|
|
count_of_vals = count_of_vals + 1
|
|
|
|
end, {['repeat'] = 5})
|
|
|
|
|
|
|
|
vim.fn.wait(1000, function()
|
|
|
|
return count_of_vals >= 5
|
|
|
|
end)
|
|
|
|
|
|
|
|
return count_of_vals
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('can handle clashing names', function()
|
|
|
|
eq(1, exec_lua [[
|
|
|
|
local f_loc = function() return 1 end
|
|
|
|
|
|
|
|
local result = nil
|
|
|
|
vim.fn.timer_start(100, function()
|
|
|
|
result = f_loc()
|
|
|
|
end)
|
|
|
|
|
|
|
|
local f_loc = function() return 2 end
|
|
|
|
vim.wait(1000, function() return result ~= nil end)
|
|
|
|
|
|
|
|
return result
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
2020-07-19 14:16:48 -07:00
|
|
|
it('can handle functions with errors', function()
|
|
|
|
eq(true, exec_lua [[
|
|
|
|
vim.fn.timer_start(10, function()
|
|
|
|
error("dead function")
|
|
|
|
end)
|
|
|
|
|
|
|
|
vim.wait(1000, function() return false end)
|
|
|
|
|
|
|
|
return true
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
2020-06-18 21:23:30 -07:00
|
|
|
it('should handle passing functions around', function()
|
|
|
|
command [[
|
|
|
|
function VimCanCallLuaCallbacks(Concat, Cb)
|
|
|
|
let message = a:Concat("Hello Vim", "I'm Lua")
|
|
|
|
call a:Cb(message)
|
|
|
|
endfunction
|
|
|
|
]]
|
|
|
|
|
|
|
|
eq("Hello Vim I'm Lua", exec_lua [[
|
|
|
|
can_pass_lua_callback_to_vim_from_lua_result = ""
|
|
|
|
|
|
|
|
vim.fn.VimCanCallLuaCallbacks(
|
|
|
|
function(greeting, message) return greeting .. " " .. message end,
|
|
|
|
function(message) can_pass_lua_callback_to_vim_from_lua_result = message end
|
|
|
|
)
|
|
|
|
|
|
|
|
return can_pass_lua_callback_to_vim_from_lua_result
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('should handle funcrefs', function()
|
|
|
|
command [[
|
|
|
|
function VimCanCallLuaCallbacks(Concat, Cb)
|
|
|
|
let message = a:Concat("Hello Vim", "I'm Lua")
|
|
|
|
call a:Cb(message)
|
|
|
|
endfunction
|
|
|
|
]]
|
|
|
|
|
|
|
|
eq("Hello Vim I'm Lua", exec_lua [[
|
|
|
|
can_pass_lua_callback_to_vim_from_lua_result = ""
|
|
|
|
|
|
|
|
vim.funcref('VimCanCallLuaCallbacks')(
|
|
|
|
function(greeting, message) return greeting .. " " .. message end,
|
|
|
|
function(message) can_pass_lua_callback_to_vim_from_lua_result = message end
|
|
|
|
)
|
|
|
|
|
|
|
|
return can_pass_lua_callback_to_vim_from_lua_result
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
2020-06-29 23:05:06 -07:00
|
|
|
it('should work with metatables using __call', function()
|
|
|
|
eq(1, exec_lua [[
|
2020-06-18 21:23:30 -07:00
|
|
|
local this_is_local_variable = false
|
2020-06-29 23:05:06 -07:00
|
|
|
local callable_table = setmetatable({x = 1}, {
|
|
|
|
__call = function(t, ...)
|
|
|
|
this_is_local_variable = t.x
|
2020-06-18 21:23:30 -07:00
|
|
|
end
|
|
|
|
})
|
|
|
|
|
|
|
|
vim.fn.timer_start(5, callable_table)
|
|
|
|
|
|
|
|
vim.wait(1000, function()
|
|
|
|
return this_is_local_variable
|
|
|
|
end)
|
|
|
|
|
|
|
|
return this_is_local_variable
|
|
|
|
]])
|
2017-01-20 15:10:44 -07:00
|
|
|
end)
|
|
|
|
|
2020-06-29 23:05:06 -07:00
|
|
|
it('should handle being called from a timer once.', function()
|
|
|
|
eq(3, exec_lua [[
|
|
|
|
local this_is_local_variable = false
|
|
|
|
local callable_table = setmetatable({5, 4, 3, 2, 1}, {
|
|
|
|
__call = function(t, ...) this_is_local_variable = t[3] end
|
|
|
|
})
|
|
|
|
|
|
|
|
vim.fn.timer_start(5, callable_table)
|
|
|
|
vim.wait(1000, function()
|
|
|
|
return this_is_local_variable
|
|
|
|
end)
|
|
|
|
|
|
|
|
return this_is_local_variable
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('should call functions once with __call metamethod', function()
|
|
|
|
eq(true, exec_lua [[
|
|
|
|
local this_is_local_variable = false
|
|
|
|
local callable_table = setmetatable({a = true, b = false}, {
|
|
|
|
__call = function(t, ...) this_is_local_variable = t.a end
|
|
|
|
})
|
|
|
|
|
|
|
|
assert(getmetatable(callable_table).__call)
|
|
|
|
vim.fn.call(callable_table, {})
|
|
|
|
|
|
|
|
return this_is_local_variable
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('should work with lists using __call', function()
|
|
|
|
eq(3, exec_lua [[
|
|
|
|
local this_is_local_variable = false
|
|
|
|
local mt = {
|
|
|
|
__call = function(t, ...)
|
|
|
|
this_is_local_variable = t[3]
|
|
|
|
end
|
|
|
|
}
|
|
|
|
local callable_table = setmetatable({5, 4, 3, 2, 1}, mt)
|
|
|
|
|
|
|
|
-- Call it once...
|
|
|
|
vim.fn.timer_start(5, callable_table)
|
|
|
|
vim.wait(1000, function()
|
|
|
|
return this_is_local_variable
|
|
|
|
end)
|
|
|
|
|
|
|
|
assert(this_is_local_variable)
|
|
|
|
this_is_local_variable = false
|
|
|
|
|
|
|
|
vim.fn.timer_start(5, callable_table)
|
|
|
|
vim.wait(1000, function()
|
|
|
|
return this_is_local_variable
|
|
|
|
end)
|
|
|
|
|
|
|
|
return this_is_local_variable
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('should not work with tables not using __call', function()
|
|
|
|
eq({false, 'Vim:E921: Invalid callback argument'}, exec_lua [[
|
|
|
|
local this_is_local_variable = false
|
|
|
|
local callable_table = setmetatable({x = 1}, {})
|
|
|
|
|
|
|
|
return {pcall(function() vim.fn.timer_start(5, callable_table) end)}
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
2017-01-20 15:10:44 -07:00
|
|
|
it('correctly converts containers with type_idx', function()
|
|
|
|
eq(5, eval('type(luaeval("{[vim.type_idx]=vim.types.float, [vim.val_idx]=0}"))'))
|
|
|
|
eq(4, eval([[type(luaeval('{[vim.type_idx]=vim.types.dictionary}'))]]))
|
|
|
|
eq(3, eval([[type(luaeval('{[vim.type_idx]=vim.types.array}'))]]))
|
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({}, fn.luaeval('{[vim.type_idx]=vim.types.array}'))
|
2017-01-20 15:10:44 -07:00
|
|
|
|
|
|
|
-- Presence of type_idx makes Vim ignore some keys
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({42}, fn.luaeval('{[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}'))
|
|
|
|
eq({foo=2}, fn.luaeval('{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}'))
|
|
|
|
eq(10, fn.luaeval('{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}'))
|
2017-01-20 15:10:44 -07:00
|
|
|
|
|
|
|
-- The following should not crash
|
2024-01-12 10:59:57 -07:00
|
|
|
eq({}, fn.luaeval('{[vim.type_idx]=vim.types.dictionary}'))
|
2017-01-20 15:10:44 -07:00
|
|
|
end)
|
|
|
|
|
|
|
|
it('correctly converts self-containing containers', function()
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_var('l', {})
|
2017-01-20 15:10:44 -07:00
|
|
|
eval('add(l, l)')
|
|
|
|
eq(true, eval('luaeval("_A == _A[1]", l)'))
|
|
|
|
eq(true, eval('luaeval("_A[1] == _A[1][1]", [l])'))
|
|
|
|
eq(true, eval('luaeval("_A.d == _A.d[1]", {"d": l})'))
|
|
|
|
eq(true, eval('luaeval("_A ~= _A[1]", [l])'))
|
|
|
|
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_var('d', {foo=42})
|
2017-01-20 15:10:44 -07:00
|
|
|
eval('extend(d, {"d": d})')
|
|
|
|
eq(true, eval('luaeval("_A == _A.d", d)'))
|
|
|
|
eq(true, eval('luaeval("_A[1] == _A[1].d", [d])'))
|
|
|
|
eq(true, eval('luaeval("_A.d == _A.d.d", {"d": d})'))
|
|
|
|
eq(true, eval('luaeval("_A ~= _A.d", {"d": d})'))
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('errors out correctly when doing incorrect things in lua', function()
|
|
|
|
-- Conversion errors
|
2019-10-30 12:53:09 -07:00
|
|
|
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: attempt to call field \'xxx_nonexistent_key_xxx\' (a nil value)',
|
2021-11-06 07:26:10 -07:00
|
|
|
remove_trace(exc_exec([[call luaeval("vim.xxx_nonexistent_key_xxx()")]])))
|
2019-10-30 12:53:09 -07:00
|
|
|
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: ERROR',
|
2021-11-06 07:26:10 -07:00
|
|
|
remove_trace(exc_exec([[call luaeval("error('ERROR')")]])))
|
2019-10-30 12:53:09 -07:00
|
|
|
eq('Vim(call):E5108: Error executing lua [NULL]',
|
2021-11-06 07:26:10 -07:00
|
|
|
remove_trace(exc_exec([[call luaeval("error(nil)")]])))
|
2017-01-20 15:10:44 -07:00
|
|
|
end)
|
2017-01-20 15:52:19 -07:00
|
|
|
|
2017-01-29 09:32:01 -07:00
|
|
|
it('does not leak memory when called with too long line',
|
2017-01-20 15:52:19 -07:00
|
|
|
function()
|
|
|
|
local s = ('x'):rep(65536)
|
2019-10-30 12:53:09 -07:00
|
|
|
eq('Vim(call):E5107: Error loading lua [string "luaeval()"]:1: unexpected symbol near \')\'',
|
2017-01-20 15:52:19 -07:00
|
|
|
exc_exec([[call luaeval("(']] .. s ..[[' + )")]]))
|
2024-01-12 10:59:57 -07:00
|
|
|
eq(s, fn.luaeval('"' .. s .. '"'))
|
2017-01-20 15:52:19 -07:00
|
|
|
end)
|
2017-01-20 14:00:47 -07:00
|
|
|
end)
|
2019-10-30 12:53:09 -07:00
|
|
|
|
|
|
|
describe('v:lua', function()
|
|
|
|
before_each(function()
|
|
|
|
exec_lua([[
|
|
|
|
function _G.foo(a,b,n)
|
|
|
|
_G.val = n
|
|
|
|
return a+b
|
|
|
|
end
|
|
|
|
mymod = {}
|
|
|
|
function mymod.noisy(name)
|
|
|
|
vim.api.nvim_set_current_line("hey "..name)
|
|
|
|
end
|
|
|
|
function mymod.crashy()
|
|
|
|
nonexistent()
|
|
|
|
end
|
2021-08-02 11:35:06 -07:00
|
|
|
function mymod.whatis(value)
|
|
|
|
return type(value) .. ": " .. tostring(value)
|
|
|
|
end
|
2019-10-30 12:53:09 -07:00
|
|
|
function mymod.omni(findstart, base)
|
|
|
|
if findstart == 1 then
|
|
|
|
return 5
|
|
|
|
else
|
|
|
|
if base == 'st' then
|
|
|
|
return {'stuff', 'steam', 'strange things'}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
]])
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('works in expressions', function()
|
|
|
|
eq(7, eval('v:lua.foo(3,4,v:null)'))
|
|
|
|
eq(true, exec_lua([[return _G.val == vim.NIL]]))
|
|
|
|
eq(NIL, eval('v:lua.mymod.noisy("eval")'))
|
2024-01-12 10:59:57 -07:00
|
|
|
eq("hey eval", api.nvim_get_current_line())
|
2021-08-02 11:35:06 -07:00
|
|
|
eq("string: abc", eval('v:lua.mymod.whatis(0z616263)'))
|
|
|
|
eq("string: ", eval('v:lua.mymod.whatis(v:_null_blob)'))
|
2019-10-30 12:53:09 -07:00
|
|
|
|
2020-09-12 19:04:22 -07:00
|
|
|
eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
|
2019-10-30 12:53:09 -07:00
|
|
|
pcall_err(eval, 'v:lua.mymod.crashy()'))
|
|
|
|
end)
|
|
|
|
|
2021-08-11 05:47:33 -07:00
|
|
|
it('works when called as a method', function()
|
|
|
|
eq(123, eval('110->v:lua.foo(13)'))
|
|
|
|
eq(true, exec_lua([[return _G.val == nil]]))
|
|
|
|
|
|
|
|
eq(321, eval('300->v:lua.foo(21, "boop")'))
|
|
|
|
eq("boop", exec_lua([[return _G.val]]))
|
|
|
|
|
|
|
|
eq(NIL, eval('"there"->v:lua.mymod.noisy()'))
|
2024-01-12 10:59:57 -07:00
|
|
|
eq("hey there", api.nvim_get_current_line())
|
2021-08-11 05:47:33 -07:00
|
|
|
eq({5, 10, 15, 20}, eval('[[1], [2, 3], [4]]->v:lua.vim.tbl_flatten()->map({_, v -> v * 5})'))
|
|
|
|
|
|
|
|
eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
|
|
|
|
pcall_err(eval, '"huh?"->v:lua.mymod.crashy()'))
|
|
|
|
end)
|
|
|
|
|
2019-10-30 12:53:09 -07:00
|
|
|
it('works in :call', function()
|
|
|
|
command(":call v:lua.mymod.noisy('command')")
|
2024-01-12 10:59:57 -07:00
|
|
|
eq("hey command", api.nvim_get_current_line())
|
2020-09-12 19:04:22 -07:00
|
|
|
eq("Vim(call):E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
|
2019-10-30 12:53:09 -07:00
|
|
|
pcall_err(command, 'call v:lua.mymod.crashy()'))
|
|
|
|
end)
|
|
|
|
|
|
|
|
it('works in func options', function()
|
|
|
|
local screen = Screen.new(60, 8)
|
|
|
|
screen:set_default_attr_ids({
|
|
|
|
[1] = {bold = true, foreground = Screen.colors.Blue1},
|
|
|
|
[2] = {background = Screen.colors.WebGray},
|
|
|
|
[3] = {background = Screen.colors.LightMagenta},
|
|
|
|
[4] = {bold = true},
|
|
|
|
[5] = {bold = true, foreground = Screen.colors.SeaGreen4},
|
|
|
|
})
|
|
|
|
screen:attach()
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_option_value('omnifunc', 'v:lua.mymod.omni', {})
|
2019-10-30 12:53:09 -07:00
|
|
|
feed('isome st<c-x><c-o>')
|
|
|
|
screen:expect{grid=[[
|
|
|
|
some stuff^ |
|
|
|
|
{1:~ }{2: stuff }{1: }|
|
|
|
|
{1:~ }{3: steam }{1: }|
|
|
|
|
{1:~ }{3: strange things }{1: }|
|
2023-12-09 05:42:00 -07:00
|
|
|
{1:~ }|*3
|
2019-10-30 12:53:09 -07:00
|
|
|
{4:-- Omni completion (^O^N^P) }{5:match 1 of 3} |
|
|
|
|
]]}
|
2024-01-12 10:59:57 -07:00
|
|
|
api.nvim_set_option_value('operatorfunc', 'v:lua.mymod.noisy', {})
|
2022-08-20 00:52:35 -07:00
|
|
|
feed('<Esc>g@g@')
|
2024-01-12 10:59:57 -07:00
|
|
|
eq("hey line", api.nvim_get_current_line())
|
2019-10-30 12:53:09 -07:00
|
|
|
end)
|
|
|
|
|
2021-10-23 09:20:19 -07:00
|
|
|
it('supports packages', function()
|
|
|
|
command('set pp+=test/functional/fixtures')
|
|
|
|
eq('\tbadval', eval("v:lua.require'leftpad'('badval')"))
|
|
|
|
eq(9003, eval("v:lua.require'bar'.doit()"))
|
2022-01-26 21:35:12 -07:00
|
|
|
eq(9004, eval("v:lua.require'baz-quux'.doit()"))
|
2024-02-18 04:11:44 -07:00
|
|
|
eq(9003, eval("1 ? v:lua.require'bar'.doit() : v:lua.require'baz-quux'.doit()"))
|
|
|
|
eq(9004, eval("0 ? v:lua.require'bar'.doit() : v:lua.require'baz-quux'.doit()"))
|
2021-10-23 09:20:19 -07:00
|
|
|
end)
|
|
|
|
|
2019-10-30 12:53:09 -07:00
|
|
|
it('throw errors for invalid use', function()
|
2023-04-16 03:27:33 -07:00
|
|
|
eq([[Vim(let):E15: Invalid expression: "v:lua.func"]], pcall_err(command, "let g:Func = v:lua.func"))
|
|
|
|
eq([[Vim(let):E15: Invalid expression: "v:lua"]], pcall_err(command, "let g:Func = v:lua"))
|
|
|
|
eq([[Vim(let):E15: Invalid expression: "v:['lua']"]], pcall_err(command, "let g:Func = v:['lua']"))
|
2019-10-30 12:53:09 -07:00
|
|
|
|
2023-04-16 03:27:33 -07:00
|
|
|
eq([[Vim:E15: Invalid expression: "v:['lua'].foo()"]], pcall_err(eval, "v:['lua'].foo()"))
|
2019-10-30 12:53:09 -07:00
|
|
|
eq("Vim(call):E461: Illegal variable name: v:['lua']", pcall_err(command, "call v:['lua'].baar()"))
|
2023-04-15 17:54:07 -07:00
|
|
|
eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "v:lua()"))
|
2019-10-30 12:53:09 -07:00
|
|
|
|
|
|
|
eq("Vim(let):E46: Cannot change read-only variable \"v:['lua']\"", pcall_err(command, "let v:['lua'] = 'xx'"))
|
|
|
|
eq("Vim(let):E46: Cannot change read-only variable \"v:lua\"", pcall_err(command, "let v:lua = 'xx'"))
|
2021-08-11 05:47:33 -07:00
|
|
|
|
|
|
|
eq("Vim:E107: Missing parentheses: v:lua.func", pcall_err(eval, "'bad'->v:lua.func"))
|
|
|
|
eq("Vim:E274: No white space allowed before parenthesis", pcall_err(eval, "'bad'->v:lua.func ()"))
|
|
|
|
eq("Vim:E107: Missing parentheses: v:lua", pcall_err(eval, "'bad'->v:lua"))
|
2023-04-15 17:54:07 -07:00
|
|
|
eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "'bad'->v:lua()"))
|
2023-04-16 03:27:33 -07:00
|
|
|
eq([[Vim:E15: Invalid expression: "v:lua.()"]], pcall_err(eval, "'bad'->v:lua.()"))
|
2019-10-30 12:53:09 -07:00
|
|
|
end)
|
|
|
|
end)
|