diff options
Diffstat (limited to 'test/functional/lua')
34 files changed, 5225 insertions, 3046 deletions
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index d808693a9e..acd56a0ddb 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -3,10 +3,10 @@ local helpers = require('test.functional.helpers')(after_each) local exc_exec = helpers.exc_exec local remove_trace = helpers.remove_trace -local funcs = helpers.funcs +local fn = helpers.fn local clear = helpers.clear local eval = helpers.eval -local NIL = helpers.NIL +local NIL = vim.NIL local eq = helpers.eq local exec_lua = helpers.exec_lua local pcall_err = helpers.pcall_err @@ -17,64 +17,77 @@ describe('luaeval(vim.api.…)', function() describe('with channel_id and buffer handle', function() describe('nvim_buf_get_lines', function() it('works', function() - funcs.setline(1, {"abc", "def", "a\nb", "ttt"}) - eq({'a\000b'}, - funcs.luaeval('vim.api.nvim_buf_get_lines(1, 2, 3, false)')) + fn.setline(1, { 'abc', 'def', 'a\nb', 'ttt' }) + eq({ 'a\000b' }, fn.luaeval('vim.api.nvim_buf_get_lines(1, 2, 3, false)')) end) end) describe('nvim_buf_set_lines', function() it('works', function() - funcs.setline(1, {"abc", "def", "a\nb", "ttt"}) - eq(NIL, funcs.luaeval('vim.api.nvim_buf_set_lines(1, 1, 2, false, {"b\\0a"})')) - eq({'abc', 'b\000a', 'a\000b', 'ttt'}, - funcs.luaeval('vim.api.nvim_buf_get_lines(1, 0, 4, false)')) + fn.setline(1, { 'abc', 'def', 'a\nb', 'ttt' }) + eq(NIL, fn.luaeval('vim.api.nvim_buf_set_lines(1, 1, 2, false, {"b\\0a"})')) + eq( + { 'abc', 'b\000a', 'a\000b', 'ttt' }, + fn.luaeval('vim.api.nvim_buf_get_lines(1, 0, 4, false)') + ) end) end) end) describe('with errors', function() it('transforms API error from nvim_buf_set_lines into lua error', function() - funcs.setline(1, {"abc", "def", "a\nb", "ttt"}) - eq({false, "'replacement string' item contains newlines"}, - funcs.luaeval('{pcall(vim.api.nvim_buf_set_lines, 1, 1, 2, false, {"b\\na"})}')) + fn.setline(1, { 'abc', 'def', 'a\nb', 'ttt' }) + eq( + { false, "'replacement string' item contains newlines" }, + fn.luaeval('{pcall(vim.api.nvim_buf_set_lines, 1, 1, 2, false, {"b\\na"})}') + ) end) it('transforms API error from nvim_win_set_cursor into lua error', function() - eq({false, 'Argument "pos" must be a [row, col] array'}, - funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {1, 2, 3})}')) + eq( + { false, 'Argument "pos" must be a [row, col] array' }, + fn.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {1, 2, 3})}') + ) -- Used to produce a memory leak due to a bug in nvim_win_set_cursor - eq({false, 'Invalid window id: -1'}, - funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, -1, {1, 2, 3})}')) + eq( + { false, 'Invalid window id: -1' }, + fn.luaeval('{pcall(vim.api.nvim_win_set_cursor, -1, {1, 2, 3})}') + ) end) - it('transforms API error from nvim_win_set_cursor + same array as in first test into lua error', - function() - eq({false, 'Argument "pos" must be a [row, col] array'}, - funcs.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {"b\\na"})}')) - end) + it( + 'transforms API error from nvim_win_set_cursor + same array as in first test into lua error', + function() + eq( + { false, 'Argument "pos" must be a [row, col] array' }, + fn.luaeval('{pcall(vim.api.nvim_win_set_cursor, 0, {"b\\na"})}') + ) + end + ) end) it('correctly evaluates API code which calls luaeval', function() - local str = (([===[vim.api.nvim_eval([==[ + local str = ( + ([===[vim.api.nvim_eval([==[ luaeval('vim.api.nvim_eval([=[ luaeval("vim.api.nvim_eval([[ luaeval(1) ]])") ]=])') - ]==])]===]):gsub('\n', ' ')) - eq(1, funcs.luaeval(str)) + ]==])]===]):gsub('\n', ' ') + ) + eq(1, fn.luaeval(str)) end) it('correctly converts from API objects', function() - eq(1, funcs.luaeval('vim.api.nvim_eval("1")')) - eq('1', funcs.luaeval([[vim.api.nvim_eval('"1"')]])) - eq('Blobby', funcs.luaeval('vim.api.nvim_eval("0z426c6f626279")')) - eq({}, funcs.luaeval('vim.api.nvim_eval("[]")')) - eq({}, funcs.luaeval('vim.api.nvim_eval("{}")')) - eq(1, funcs.luaeval('vim.api.nvim_eval("1.0")')) - eq('\000', funcs.luaeval('vim.api.nvim_eval("0z00")')) - eq(true, funcs.luaeval('vim.api.nvim_eval("v:true")')) - eq(false, funcs.luaeval('vim.api.nvim_eval("v:false")')) - eq(NIL, funcs.luaeval('vim.api.nvim_eval("v:null")')) + eq(1, fn.luaeval('vim.api.nvim_eval("1")')) + eq('1', fn.luaeval([[vim.api.nvim_eval('"1"')]])) + eq('Blobby', fn.luaeval('vim.api.nvim_eval("0z426c6f626279")')) + eq({}, fn.luaeval('vim.api.nvim_eval("[]")')) + eq({}, fn.luaeval('vim.api.nvim_eval("{}")')) + eq(1, fn.luaeval('vim.api.nvim_eval("1.0")')) + eq('\000', fn.luaeval('vim.api.nvim_eval("0z00")')) + eq(true, fn.luaeval('vim.api.nvim_eval("v:true")')) + eq(false, fn.luaeval('vim.api.nvim_eval("v:false")')) + eq(NIL, fn.luaeval('vim.api.nvim_eval("v:null")')) eq(0, eval([[type(luaeval('vim.api.nvim_eval("1")'))]])) eq(1, eval([[type(luaeval('vim.api.nvim_eval("''1''")'))]])) @@ -86,28 +99,32 @@ describe('luaeval(vim.api.…)', function() eq(6, eval([[type(luaeval('vim.api.nvim_eval("v:false")'))]])) eq(7, eval([[type(luaeval('vim.api.nvim_eval("v:null")'))]])) - eq({foo=42}, funcs.luaeval([[vim.api.nvim_eval('{"foo": 42}')]])) - eq({42}, funcs.luaeval([[vim.api.nvim_eval('[42]')]])) + eq({ foo = 42 }, fn.luaeval([[vim.api.nvim_eval('{"foo": 42}')]])) + eq({ 42 }, fn.luaeval([[vim.api.nvim_eval('[42]')]])) - eq({foo={bar=42}, baz=50}, funcs.luaeval([[vim.api.nvim_eval('{"foo": {"bar": 42}, "baz": 50}')]])) - eq({{42}, {}}, funcs.luaeval([=[vim.api.nvim_eval('[[42], []]')]=])) + eq( + { foo = { bar = 42 }, baz = 50 }, + fn.luaeval([[vim.api.nvim_eval('{"foo": {"bar": 42}, "baz": 50}')]]) + ) + eq({ { 42 }, {} }, fn.luaeval([=[vim.api.nvim_eval('[[42], []]')]=])) end) it('correctly converts to API objects', function() - eq(1, funcs.luaeval('vim.api.nvim__id(1)')) - eq('1', funcs.luaeval('vim.api.nvim__id("1")')) - eq({1}, funcs.luaeval('vim.api.nvim__id({1})')) - eq({foo=1}, funcs.luaeval('vim.api.nvim__id({foo=1})')) - eq(1.5, funcs.luaeval('vim.api.nvim__id(1.5)')) - eq(true, funcs.luaeval('vim.api.nvim__id(true)')) - eq(false, funcs.luaeval('vim.api.nvim__id(false)')) - eq(NIL, funcs.luaeval('vim.api.nvim__id(nil)')) + eq(1, fn.luaeval('vim.api.nvim__id(1)')) + eq('1', fn.luaeval('vim.api.nvim__id("1")')) + eq({ 1 }, fn.luaeval('vim.api.nvim__id({1})')) + eq({ foo = 1 }, fn.luaeval('vim.api.nvim__id({foo=1})')) + eq(1.5, fn.luaeval('vim.api.nvim__id(1.5)')) + eq(true, fn.luaeval('vim.api.nvim__id(true)')) + eq(false, fn.luaeval('vim.api.nvim__id(false)')) + eq(NIL, fn.luaeval('vim.api.nvim__id(nil)')) -- API strings from Blobs can work as NUL-terminated C strings - eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ""', - exc_exec('call nvim_eval(v:_null_blob)')) - eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ""', - exc_exec('call nvim_eval(0z)')) + eq( + 'Vim(call):E5555: API call: Vim:E15: Invalid expression: ""', + exc_exec('call nvim_eval(v:_null_blob)') + ) + eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ""', exc_exec('call nvim_eval(0z)')) eq(1, eval('nvim_eval(0z31)')) eq(0, eval([[type(luaeval('vim.api.nvim__id(1)'))]])) @@ -119,68 +136,152 @@ describe('luaeval(vim.api.…)', function() eq(6, eval([[type(luaeval('vim.api.nvim__id(false)'))]])) eq(7, eval([[type(luaeval('vim.api.nvim__id(nil)'))]])) - eq({foo=1, bar={42, {{baz=true}, 5}}}, funcs.luaeval('vim.api.nvim__id({foo=1, bar={42, {{baz=true}, 5}}})')) + eq( + { foo = 1, bar = { 42, { { baz = true }, 5 } } }, + fn.luaeval('vim.api.nvim__id({foo=1, bar={42, {{baz=true}, 5}}})') + ) - eq(true, funcs.luaeval('vim.api.nvim__id(vim.api.nvim__id)(true)')) - eq(42, exec_lua [[ + eq(true, fn.luaeval('vim.api.nvim__id(vim.api.nvim__id)(true)')) + eq( + 42, + exec_lua [[ local f = vim.api.nvim__id({42, vim.api.nvim__id}) return f[2](f[1]) - ]]) + ]] + ) end) it('correctly converts container objects with type_idx to API objects', function() - eq(5, eval('type(luaeval("vim.api.nvim__id({[vim.type_idx]=vim.types.float, [vim.val_idx]=0})"))')) + eq( + 5, + eval('type(luaeval("vim.api.nvim__id({[vim.type_idx]=vim.types.float, [vim.val_idx]=0})"))') + ) eq(4, eval([[type(luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.dictionary})'))]])) eq(3, eval([[type(luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array})'))]])) - eq({}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array})')) + eq({}, fn.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array})')) -- Presence of type_idx makes Vim ignore some keys - eq({42}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq({foo=2}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq(10, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq({}, funcs.luaeval('vim.api.nvim__id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})')) + eq( + { 42 }, + fn.luaeval( + 'vim.api.nvim__id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})' + ) + ) + eq( + { foo = 2 }, + fn.luaeval( + 'vim.api.nvim__id({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})' + ) + ) + eq( + 10, + fn.luaeval( + 'vim.api.nvim__id({[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})' + ) + ) + eq( + {}, + fn.luaeval( + 'vim.api.nvim__id({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})' + ) + ) end) it('correctly converts arrays with type_idx to API objects', function() eq(3, eval([[type(luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array})'))]])) - eq({}, funcs.luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array})')) - - eq({42}, funcs.luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq({{foo=2}}, funcs.luaeval('vim.api.nvim__id_array({{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) - eq({10}, funcs.luaeval('vim.api.nvim__id_array({{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) - eq({}, funcs.luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})')) - - eq({}, funcs.luaeval('vim.api.nvim__id_array({})')) + eq({}, fn.luaeval('vim.api.nvim__id_array({[vim.type_idx]=vim.types.array})')) + + eq( + { 42 }, + fn.luaeval( + 'vim.api.nvim__id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})' + ) + ) + eq( + { { foo = 2 } }, + fn.luaeval( + 'vim.api.nvim__id_array({{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' + ) + ) + eq( + { 10 }, + fn.luaeval( + 'vim.api.nvim__id_array({{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' + ) + ) + eq( + {}, + fn.luaeval( + 'vim.api.nvim__id_array({[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2})' + ) + ) + + eq({}, fn.luaeval('vim.api.nvim__id_array({})')) eq(3, eval([[type(luaeval('vim.api.nvim__id_array({})'))]])) end) it('correctly converts dictionaries with type_idx to API objects', function() - eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]])) - - eq({}, funcs.luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})')) - - eq({v={42}}, funcs.luaeval('vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) - eq({foo=2}, funcs.luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})')) - eq({v=10}, funcs.luaeval('vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})')) - eq({v={}}, funcs.luaeval('vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})')) + eq( + 4, + eval([[type(luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})'))]]) + ) + + eq({}, fn.luaeval('vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary})')) + + eq( + { v = { 42 } }, + fn.luaeval( + 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' + ) + ) + eq( + { foo = 2 }, + fn.luaeval( + 'vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42})' + ) + ) + eq( + { v = 10 }, + fn.luaeval( + 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}})' + ) + ) + eq( + { v = {} }, + fn.luaeval( + 'vim.api.nvim__id_dictionary({v={[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2}})' + ) + ) -- If API requests dictionary, then empty table will be the one. This is not -- the case normally because empty table is an empty array. - eq({}, funcs.luaeval('vim.api.nvim__id_dictionary({})')) + eq({}, fn.luaeval('vim.api.nvim__id_dictionary({})')) eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({})'))]])) end) it('converts booleans in positional args', function() - eq({''}, exec_lua [[ return vim.api.nvim_buf_get_lines(0, 0, 10, false) ]]) - eq({''}, exec_lua [[ return vim.api.nvim_buf_get_lines(0, 0, 10, nil) ]]) - eq('Index out of bounds', pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, true) ]])) - eq('Index out of bounds', pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, 1) ]])) + eq({ '' }, exec_lua [[ return vim.api.nvim_buf_get_lines(0, 0, 10, false) ]]) + eq({ '' }, exec_lua [[ return vim.api.nvim_buf_get_lines(0, 0, 10, nil) ]]) + eq( + 'Index out of bounds', + pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, true) ]]) + ) + eq( + 'Index out of bounds', + pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, 1) ]]) + ) -- this follows lua conventions for bools (not api convention for Boolean) - eq('Index out of bounds', pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, 0) ]])) - eq('Index out of bounds', pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, {}) ]])) + eq( + 'Index out of bounds', + pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, 0) ]]) + ) + eq( + 'Index out of bounds', + pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, {}) ]]) + ) end) it('converts booleans in optional args', function() @@ -190,50 +291,92 @@ describe('luaeval(vim.api.…)', function() -- API conventions (not lua conventions): zero is falsy eq({}, exec_lua [[ return vim.api.nvim_exec2("echo 'foobar'", {output=0}) ]]) - eq({output='foobar'}, exec_lua [[ return vim.api.nvim_exec2("echo 'foobar'", {output=true}) ]]) - eq({output='foobar'}, exec_lua [[ return vim.api.nvim_exec2("echo 'foobar'", {output=1}) ]]) - eq([[Invalid 'output': not a boolean]], pcall_err(exec_lua, [[ return vim.api.nvim_exec2("echo 'foobar'", {output={}}) ]])) + eq( + { output = 'foobar' }, + exec_lua [[ return vim.api.nvim_exec2("echo 'foobar'", {output=true}) ]] + ) + eq({ output = 'foobar' }, exec_lua [[ return vim.api.nvim_exec2("echo 'foobar'", {output=1}) ]]) + eq( + [[Invalid 'output': not a boolean]], + pcall_err(exec_lua, [[ return vim.api.nvim_exec2("echo 'foobar'", {output={}}) ]]) + ) end) it('errors out correctly when working with API', function() -- Conversion errors - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'obj': Cannot convert given Lua table]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]]))) + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'obj': Cannot convert given Lua table]], + remove_trace(exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]])) + ) -- Errors in number of arguments - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument', - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id()")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument', - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id(1, 2)")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 2 arguments', - remove_trace(exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2, 3)")]]))) + eq( + 'Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument', + remove_trace(exc_exec([[call luaeval("vim.api.nvim__id()")]])) + ) + eq( + 'Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument', + remove_trace(exc_exec([[call luaeval("vim.api.nvim__id(1, 2)")]])) + ) + eq( + 'Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 2 arguments', + remove_trace(exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2, 3)")]])) + ) -- Error in argument types - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'name': Expected Lua string]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2)")]]))) - - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'start': Expected Lua number]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]]))) - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'start': Number is not integral]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]]))) - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'window': Expected Lua number]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim_win_is_valid(nil)")]]))) - - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'flt': Expected Lua number]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]]))) - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'flt': Expected Float-like Lua table]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_float({[vim.type_idx]=vim.types.dictionary})")]]))) - - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'arr': Expected Lua table]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_array(1)")]]))) - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'arr': Expected Array-like Lua table]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_array({[vim.type_idx]=vim.types.dictionary})")]]))) - - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Lua table]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]]))) - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Dict-like Lua table]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]]))) - - eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected Lua table]], - remove_trace(exc_exec([[call luaeval("vim.api.nvim_set_keymap('', '', '', '')")]]))) + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'name': Expected Lua string]], + remove_trace(exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2)")]])) + ) + + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'start': Expected Lua number]], + remove_trace(exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]])) + ) + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'start': Number is not integral]], + remove_trace(exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]])) + ) + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'window': Expected Lua number]], + remove_trace(exc_exec([[call luaeval("vim.api.nvim_win_is_valid(nil)")]])) + ) + + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'flt': Expected Lua number]], + remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]])) + ) + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'flt': Expected Float-like Lua table]], + remove_trace( + exc_exec([[call luaeval("vim.api.nvim__id_float({[vim.type_idx]=vim.types.dictionary})")]]) + ) + ) + + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'arr': Expected Lua table]], + remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_array(1)")]])) + ) + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'arr': Expected Array-like Lua table]], + remove_trace( + exc_exec([[call luaeval("vim.api.nvim__id_array({[vim.type_idx]=vim.types.dictionary})")]]) + ) + ) + + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Lua table]], + remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]])) + ) + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Dict-like Lua table]], + remove_trace( + exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]]) + ) + ) + + eq( + [[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected Lua table]], + remove_trace(exc_exec([[call luaeval("vim.api.nvim_set_keymap('', '', '', '')")]])) + ) -- TODO: check for errors with Tabpage argument -- TODO: check for errors with Window argument @@ -241,8 +384,15 @@ describe('luaeval(vim.api.…)', function() end) it('accepts any value as API Boolean', function() - eq('', funcs.luaeval('vim.api.nvim_replace_termcodes("", vim, false, nil)')) - eq('', funcs.luaeval('vim.api.nvim_replace_termcodes("", 0, 1.5, "test")')) - eq('', funcs.luaeval('vim.api.nvim_replace_termcodes("", true, {}, {[vim.type_idx]=vim.types.array})')) + eq('', fn.luaeval('vim.api.nvim_replace_termcodes("", vim, false, nil)')) + eq('', fn.luaeval('vim.api.nvim_replace_termcodes("", 0, 1.5, "test")')) + eq( + '', + fn.luaeval('vim.api.nvim_replace_termcodes("", true, {}, {[vim.type_idx]=vim.types.array})') + ) + end) + + it('serializes sparse arrays in Lua', function() + eq({ [1] = vim.NIL, [2] = 2 }, exec_lua [[ return { [2] = 2 } ]]) end) end) diff --git a/test/functional/lua/base64_spec.lua b/test/functional/lua/base64_spec.lua index f0d112c23e..21fd536a98 100644 --- a/test/functional/lua/base64_spec.lua +++ b/test/functional/lua/base64_spec.lua @@ -49,12 +49,15 @@ describe('vim.base64', function() end -- Explicitly check encoded output - eq('VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZwo=', encode('The quick brown fox jumps over the lazy dog\n')) + eq( + 'VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZwo=', + encode('The quick brown fox jumps over the lazy dog\n') + ) -- Test vectors from rfc4648 local rfc4648 = { { '', '' }, - { 'f', 'Zg==', }, + { 'f', 'Zg==' }, { 'fo', 'Zm8=' }, { 'foo', 'Zm9v' }, { 'foob', 'Zm9vYg==' }, diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 51e4548edb..714e1b951f 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -1,10 +1,9 @@ -- Test suite for testing interactions with API bindings local helpers = require('test.functional.helpers')(after_each) -local luv = require('luv') local command = helpers.command -local meths = helpers.meths -local funcs = helpers.funcs +local api = helpers.api +local fn = helpers.fn local clear = helpers.clear local eq = helpers.eq local fail = helpers.fail @@ -14,15 +13,17 @@ local expect_events = helpers.expect_events local write_file = helpers.write_file local dedent = helpers.dedent -local origlines = {"original line 1", - "original line 2", - "original line 3", - "original line 4", - "original line 5", - "original line 6", - " indented line"} - -before_each(function () +local origlines = { + 'original line 1', + 'original line 2', + 'original line 3', + 'original line 4', + 'original line 5', + 'original line 6', + ' indented line', +} + +before_each(function() clear() exec_lua [[ local evname = ... @@ -53,15 +54,15 @@ end) describe('lua buffer event callbacks: on_lines', function() local function setup_eventcheck(verify, utf_sizes, lines) local lastsize - meths.buf_set_lines(0, 0, -1, true, lines) + api.nvim_buf_set_lines(0, 0, -1, true, lines) if verify then - lastsize = meths.buf_get_offset(0, meths.buf_line_count(0)) + lastsize = api.nvim_buf_get_offset(0, api.nvim_buf_line_count(0)) end - exec_lua("return test_register(...)", 0, "on_lines", "test1",false,utf_sizes) - local verify_name = "test1" + exec_lua('return test_register(...)', 0, 'on_lines', 'test1', false, utf_sizes) + local verify_name = 'test1' local function check_events(expected) - local events = exec_lua("return get_events(...)" ) + local events = exec_lua('return get_events(...)') if utf_sizes then -- this test case uses ASCII only, so sizes should be the same. -- Unicode is tested below. @@ -70,13 +71,14 @@ describe('lua buffer event callbacks: on_lines', function() event[10] = event[10] or event[9] end end - expect_events(expected, events, "line updates") + expect_events(expected, events, 'line updates') if verify then for _, event in ipairs(events) do - if event[1] == verify_name and event[2] == "lines" then + if event[1] == verify_name and event[2] == 'lines' then local startline, endline = event[5], event[7] - local newrange = meths.buf_get_offset(0, endline) - meths.buf_get_offset(0, startline) - local newsize = meths.buf_get_offset(0, meths.buf_line_count(0)) + local newrange = api.nvim_buf_get_offset(0, endline) + - api.nvim_buf_get_offset(0, startline) + local newsize = api.nvim_buf_get_offset(0, api.nvim_buf_line_count(0)) local oldrange = newrange + lastsize - newsize eq(oldrange, event[8]) lastsize = newsize @@ -84,101 +86,102 @@ describe('lua buffer event callbacks: on_lines', function() end end end - return check_events, function(new) verify_name = new end + return check_events, function(new) + verify_name = new + end end - -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot -- assert the wrong thing), but masks errors with unflushed lines (as -- nvim_buf_get_offset forces a flush of the memline). To be safe run the -- test both ways. - local function check(verify,utf_sizes) + local function check(verify, utf_sizes) local check_events, verify_name = setup_eventcheck(verify, utf_sizes, origlines) - local tick = meths.buf_get_changedtick(0) + local tick = api.nvim_buf_get_changedtick(0) command('set autoindent') command('normal! GyyggP') tick = tick + 1 - check_events {{ "test1", "lines", 1, tick, 0, 0, 1, 0}} + check_events { { 'test1', 'lines', 1, tick, 0, 0, 1, 0 } } - meths.buf_set_lines(0, 3, 5, true, {"changed line"}) + api.nvim_buf_set_lines(0, 3, 5, true, { 'changed line' }) tick = tick + 1 - check_events {{ "test1", "lines", 1, tick, 3, 5, 4, 32 }} + check_events { { 'test1', 'lines', 1, tick, 3, 5, 4, 32 } } - exec_lua("return test_register(...)", 0, "on_lines", "test2", true, utf_sizes) + exec_lua('return test_register(...)', 0, 'on_lines', 'test2', true, utf_sizes) tick = tick + 1 command('undo') -- plugins can opt in to receive changedtick events, or choose -- to only receive actual changes. check_events { - { "test1", "lines", 1, tick, 3, 4, 5, 13 }; - { "test2", "lines", 1, tick, 3, 4, 5, 13 }; - { "test2", "changedtick", 1, tick+1 }; + { 'test1', 'lines', 1, tick, 3, 4, 5, 13 }, + { 'test2', 'lines', 1, tick, 3, 4, 5, 13 }, + { 'test2', 'changedtick', 1, tick + 1 }, } tick = tick + 1 tick = tick + 1 command('redo') check_events { - { "test1", "lines", 1, tick, 3, 5, 4, 32 }; - { "test2", "lines", 1, tick, 3, 5, 4, 32 }; - { "test2", "changedtick", 1, tick+1 }; + { 'test1', 'lines', 1, tick, 3, 5, 4, 32 }, + { 'test2', 'lines', 1, tick, 3, 5, 4, 32 }, + { 'test2', 'changedtick', 1, tick + 1 }, } tick = tick + 1 tick = tick + 1 command('undo!') check_events { - { "test1", "lines", 1, tick, 3, 4, 5, 13 }; - { "test2", "lines", 1, tick, 3, 4, 5, 13 }; - { "test2", "changedtick", 1, tick+1 }; + { 'test1', 'lines', 1, tick, 3, 4, 5, 13 }, + { 'test2', 'lines', 1, tick, 3, 4, 5, 13 }, + { 'test2', 'changedtick', 1, tick + 1 }, } tick = tick + 1 -- simulate next callback returning true exec_lua("test_unreg = 'test1'") - meths.buf_set_lines(0, 6, 7, true, {"x1","x2","x3"}) + api.nvim_buf_set_lines(0, 6, 7, true, { 'x1', 'x2', 'x3' }) tick = tick + 1 -- plugins can opt in to receive changedtick events, or choose -- to only receive actual changes. check_events { - { "test1", "lines", 1, tick, 6, 7, 9, 16 }; - { "test2", "lines", 1, tick, 6, 7, 9, 16 }; + { 'test1', 'lines', 1, tick, 6, 7, 9, 16 }, + { 'test2', 'lines', 1, tick, 6, 7, 9, 16 }, } - verify_name "test2" + verify_name 'test2' - meths.buf_set_lines(0, 1, 1, true, {"added"}) + api.nvim_buf_set_lines(0, 1, 1, true, { 'added' }) tick = tick + 1 - check_events {{ "test2", "lines", 1, tick, 1, 1, 2, 0 }} + check_events { { 'test2', 'lines', 1, tick, 1, 1, 2, 0 } } feed('wix') tick = tick + 1 - check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 16 }} + check_events { { 'test2', 'lines', 1, tick, 4, 5, 5, 16 } } -- check hot path for multiple insert feed('yz') tick = tick + 1 - check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 17 }} + check_events { { 'test2', 'lines', 1, tick, 4, 5, 5, 17 } } feed('<bs>') tick = tick + 1 - check_events {{ "test2", "lines", 1, tick, 4, 5, 5, 19 }} + check_events { { 'test2', 'lines', 1, tick, 4, 5, 5, 19 } } feed('<esc>Go') tick = tick + 1 - check_events {{ "test2", "lines", 1, tick, 11, 11, 12, 0 }} + check_events { { 'test2', 'lines', 1, tick, 11, 11, 12, 0 } } feed('x') tick = tick + 1 - check_events {{ "test2", "lines", 1, tick, 11, 12, 12, 5 }} + check_events { { 'test2', 'lines', 1, tick, 11, 12, 12, 5 } } command('bwipe!') - check_events {{ "test2", "detach", 1 }} - end + check_events { { 'test2', 'detach', 1 } } + end it('works', function() check(false) @@ -189,54 +192,56 @@ describe('lua buffer event callbacks: on_lines', function() end) it('works with utf_sizes and ASCII text', function() - check(false,true) + check(false, true) end) local function check_unicode(verify) - local unicode_text = {"ascii text", - "latin text åäö", - "BMP text ɧ αλφά", - "BMP text 汉语 ↥↧", - "SMP 🤦 🦄🦃", - "combining å بِيَّة"} + local unicode_text = { + 'ascii text', + 'latin text åäö', + 'BMP text ɧ αλφά', + 'BMP text 汉语 ↥↧', + 'SMP 🤦 🦄🦃', + 'combining å بِيَّة', + } local check_events, verify_name = setup_eventcheck(verify, true, unicode_text) - local tick = meths.buf_get_changedtick(0) + local tick = api.nvim_buf_get_changedtick(0) feed('ggdd') tick = tick + 1 - check_events {{ "test1", "lines", 1, tick, 0, 1, 0, 11, 11, 11 }} + check_events { { 'test1', 'lines', 1, tick, 0, 1, 0, 11, 11, 11 } } feed('A<bs>') tick = tick + 1 - check_events {{ "test1", "lines", 1, tick, 0, 1, 1, 18, 15, 15 }} + check_events { { 'test1', 'lines', 1, tick, 0, 1, 1, 18, 15, 15 } } feed('<esc>jylp') tick = tick + 1 - check_events {{ "test1", "lines", 1, tick, 1, 2, 2, 21, 16, 16 }} + check_events { { 'test1', 'lines', 1, tick, 1, 2, 2, 21, 16, 16 } } feed('+eea<cr>') tick = tick + 1 - check_events {{ "test1", "lines", 1, tick, 2, 3, 4, 23, 15, 15 }} + check_events { { 'test1', 'lines', 1, tick, 2, 3, 4, 23, 15, 15 } } feed('<esc>jdw') tick = tick + 1 -- non-BMP chars count as 2 UTF-2 codeunits - check_events {{ "test1", "lines", 1, tick, 4, 5, 5, 18, 9, 12 }} + check_events { { 'test1', 'lines', 1, tick, 4, 5, 5, 18, 9, 12 } } feed('+rx') tick = tick + 1 -- count the individual codepoints of a composed character. - check_events {{ "test1", "lines", 1, tick, 5, 6, 6, 27, 20, 20 }} + check_events { { 'test1', 'lines', 1, tick, 5, 6, 6, 27, 20, 20 } } feed('kJ') tick = tick + 1 -- verification fails with multiple line updates, sorry about that - verify_name "" + verify_name '' -- NB: this is inefficient (but not really wrong). check_events { - { "test1", "lines", 1, tick, 4, 5, 5, 14, 5, 8 }; - { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 }; + { 'test1', 'lines', 1, tick, 4, 5, 5, 14, 5, 8 }, + { 'test1', 'lines', 1, tick + 1, 5, 6, 5, 27, 20, 20 }, } end @@ -248,9 +253,8 @@ describe('lua buffer event callbacks: on_lines', function() check_unicode(true) end) - it('has valid cursor position while shifting', function() - meths.buf_set_lines(0, 0, -1, true, {'line1'}) + api.nvim_buf_set_lines(0, 0, -1, true, { 'line1' }) exec_lua([[ vim.api.nvim_buf_attach(0, false, { on_lines = function() @@ -259,15 +263,15 @@ describe('lua buffer event callbacks: on_lines', function() }) ]]) feed('>>') - eq(1, meths.get_var('listener_cursor_line')) + eq(1, api.nvim_get_var('listener_cursor_line')) end) it('has valid cursor position while deleting lines', function() - meths.buf_set_lines(0, 0, -1, true, { "line_1", "line_2", "line_3", "line_4"}) - meths.win_set_cursor(0, {2, 0}) - eq(2, meths.win_get_cursor(0)[1]) - meths.buf_set_lines(0, 0, -1, true, { "line_1", "line_2", "line_3"}) - eq(2, meths.win_get_cursor(0)[1]) + api.nvim_buf_set_lines(0, 0, -1, true, { 'line_1', 'line_2', 'line_3', 'line_4' }) + api.nvim_win_set_cursor(0, { 2, 0 }) + eq(2, api.nvim_win_get_cursor(0)[1]) + api.nvim_buf_set_lines(0, 0, -1, true, { 'line_1', 'line_2', 'line_3' }) + eq(2, api.nvim_win_get_cursor(0)[1]) end) it('does not SEGFAULT when accessing window buffer info in on_detach #14998', function() @@ -286,16 +290,16 @@ describe('lua buffer event callbacks: on_lines', function() ]] exec_lua(code) - command("q!") + command('q!') helpers.assert_alive() exec_lua(code) - command("bd!") + command('bd!') helpers.assert_alive() end) it('#12718 lnume', function() - meths.buf_set_lines(0, 0, -1, true, {'1', '2', '3'}) + api.nvim_buf_set_lines(0, 0, -1, true, { '1', '2', '3' }) exec_lua([[ vim.api.nvim_buf_attach(0, false, { on_lines = function(...) @@ -308,28 +312,31 @@ describe('lua buffer event callbacks: on_lines', function() feed('G0') feed('p') -- Is the last arg old_byte_size correct? Doesn't matter for this PR - eq(meths.get_var('linesev'), { "lines", 1, 4, 2, 3, 5, 4 }) + eq(api.nvim_get_var('linesev'), { 'lines', 1, 4, 2, 3, 5, 4 }) feed('2G0') feed('p') - eq(meths.get_var('linesev'), { "lines", 1, 5, 1, 4, 4, 8 }) + eq(api.nvim_get_var('linesev'), { 'lines', 1, 5, 1, 4, 4, 8 }) feed('1G0') feed('P') - eq(meths.get_var('linesev'), { "lines", 1, 6, 0, 3, 3, 9 }) + eq(api.nvim_get_var('linesev'), { 'lines', 1, 6, 0, 3, 3, 9 }) end) - it('calling nvim_buf_call() from callback does not cause Normal mode CTRL-A to misbehave #16729', function() - exec_lua([[ + it( + 'calling nvim_buf_call() from callback does not cause Normal mode CTRL-A to misbehave #16729', + function() + exec_lua([[ vim.api.nvim_buf_attach(0, false, { on_lines = function(...) vim.api.nvim_buf_call(0, function() end) end, }) ]]) - feed('itest123<Esc><C-A>') - eq('test124', meths.get_current_line()) - end) + feed('itest123<Esc><C-A>') + eq('test124', api.nvim_get_current_line()) + end + ) end) describe('lua: nvim_buf_attach on_bytes', function() @@ -339,24 +346,24 @@ describe('lua: nvim_buf_attach on_bytes', function() -- test both ways. local function setup_eventcheck(verify, start_txt) if start_txt then - meths.buf_set_lines(0, 0, -1, true, start_txt) + api.nvim_buf_set_lines(0, 0, -1, true, start_txt) else - start_txt = meths.buf_get_lines(0, 0, -1, true) + start_txt = api.nvim_buf_get_lines(0, 0, -1, true) end local shadowbytes = table.concat(start_txt, '\n') .. '\n' -- TODO: while we are brewing the real strong coffee, -- verify should check buf_get_offset after every check_events if verify then - local len = meths.buf_get_offset(0, meths.buf_line_count(0)) + local len = api.nvim_buf_get_offset(0, api.nvim_buf_line_count(0)) eq(len == -1 and 1 or len, string.len(shadowbytes)) end - exec_lua("return test_register(...)", 0, "on_bytes", "test1", false, false, true) - meths.buf_get_changedtick(0) + exec_lua('return test_register(...)', 0, 'on_bytes', 'test1', false, false, true) + api.nvim_buf_get_changedtick(0) - local verify_name = "test1" + local verify_name = 'test1' local function check_events(expected) - local events = exec_lua("return get_events(...)" ) - expect_events(expected, events, "byte updates") + local events = exec_lua('return get_events(...)') + expect_events(expected, events, 'byte updates') if not verify then return @@ -364,12 +371,12 @@ describe('lua: nvim_buf_attach on_bytes', function() for _, event in ipairs(events) do for _, elem in ipairs(event) do - if type(elem) == "number" and elem < 0 then - fail(string.format("Received event has negative values")) + if type(elem) == 'number' and elem < 0 then + fail(string.format('Received event has negative values')) end end - if event[1] == verify_name and event[2] == "bytes" then + if event[1] == verify_name and event[2] == 'bytes' then local _, _, _, _, _, _, start_byte, _, _, old_byte, _, _, new_byte = unpack(event) local before = string.sub(shadowbytes, 1, start_byte) -- no text in the tests will contain 0xff bytes (invalid UTF-8) @@ -377,15 +384,19 @@ describe('lua: nvim_buf_attach on_bytes', function() local unknown = string.rep('\255', new_byte) local after = string.sub(shadowbytes, start_byte + old_byte + 1) shadowbytes = before .. unknown .. after - elseif event[1] == verify_name and event[2] == "reload" then - shadowbytes = table.concat(meths.buf_get_lines(0, 0, -1, true), '\n') .. '\n' + elseif event[1] == verify_name and event[2] == 'reload' then + shadowbytes = table.concat(api.nvim_buf_get_lines(0, 0, -1, true), '\n') .. '\n' end end - local text = meths.buf_get_lines(0, 0, -1, true) + local text = api.nvim_buf_get_lines(0, 0, -1, true) local bytes = table.concat(text, '\n') .. '\n' - eq(string.len(bytes), string.len(shadowbytes), '\non_bytes: total bytecount of buffer is wrong') + eq( + string.len(bytes), + string.len(shadowbytes), + '\non_bytes: total bytecount of buffer is wrong' + ) for i = 1, string.len(shadowbytes) do local shadowbyte = string.sub(shadowbytes, i, i) if shadowbyte ~= '\255' then @@ -400,89 +411,89 @@ describe('lua: nvim_buf_attach on_bytes', function() -- Yes, we can do both local function do_both(verify) it('single and multiple join', function() - local check_events = setup_eventcheck(verify, origlines) - feed 'ggJ' - check_events { - {'test1', 'bytes', 1, 3, 0, 15, 15, 1, 0, 1, 0, 1, 1}; - } + local check_events = setup_eventcheck(verify, origlines) + feed 'ggJ' + check_events { + { 'test1', 'bytes', 1, 3, 0, 15, 15, 1, 0, 1, 0, 1, 1 }, + } - feed '3J' - check_events { - {'test1', 'bytes', 1, 5, 0, 31, 31, 1, 0, 1, 0, 1, 1}; - {'test1', 'bytes', 1, 5, 0, 47, 47, 1, 0, 1, 0, 1, 1}; - } + feed '3J' + check_events { + { 'test1', 'bytes', 1, 5, 0, 31, 31, 1, 0, 1, 0, 1, 1 }, + { 'test1', 'bytes', 1, 5, 0, 47, 47, 1, 0, 1, 0, 1, 1 }, + } end) it('opening lines', function() - local check_events = setup_eventcheck(verify, origlines) - -- meths.set_option_value('autoindent', true, {}) - feed 'Go' - check_events { - { "test1", "bytes", 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 1 }; - } - feed '<cr>' - check_events { - { "test1", "bytes", 1, 5, 7, 0, 114, 0, 0, 0, 1, 0, 1 }; - } + local check_events = setup_eventcheck(verify, origlines) + -- api.nvim_set_option_value('autoindent', true, {}) + feed 'Go' + check_events { + { 'test1', 'bytes', 1, 3, 7, 0, 114, 0, 0, 0, 1, 0, 1 }, + } + feed '<cr>' + check_events { + { 'test1', 'bytes', 1, 5, 7, 0, 114, 0, 0, 0, 1, 0, 1 }, + } end) it('opening lines with autoindent', function() - local check_events = setup_eventcheck(verify, origlines) - meths.set_option_value('autoindent', true, {}) - feed 'Go' - check_events { - { "test1", "bytes", 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 5 }; - } - feed '<cr>' - check_events { - { "test1", "bytes", 1, 4, 7, 0, 114, 0, 4, 4, 0, 0, 0 }; - { "test1", "bytes", 1, 5, 7, 0, 114, 0, 0, 0, 1, 4, 5 }; - } + local check_events = setup_eventcheck(verify, origlines) + api.nvim_set_option_value('autoindent', true, {}) + feed 'Go' + check_events { + { 'test1', 'bytes', 1, 3, 7, 0, 114, 0, 0, 0, 1, 0, 5 }, + } + feed '<cr>' + check_events { + { 'test1', 'bytes', 1, 4, 7, 0, 114, 0, 4, 4, 0, 0, 0 }, + { 'test1', 'bytes', 1, 5, 7, 0, 114, 0, 0, 0, 1, 4, 5 }, + } end) it('setline(num, line)', function() local check_events = setup_eventcheck(verify, origlines) - funcs.setline(2, "babla") + fn.setline(2, 'babla') check_events { - { "test1", "bytes", 1, 3, 1, 0, 16, 0, 15, 15, 0, 5, 5 }; + { 'test1', 'bytes', 1, 3, 1, 0, 16, 0, 15, 15, 0, 5, 5 }, } - funcs.setline(2, {"foo", "bar"}) + fn.setline(2, { 'foo', 'bar' }) check_events { - { "test1", "bytes", 1, 4, 1, 0, 16, 0, 5, 5, 0, 3, 3 }; - { "test1", "bytes", 1, 5, 2, 0, 20, 0, 15, 15, 0, 3, 3 }; + { 'test1', 'bytes', 1, 4, 1, 0, 16, 0, 5, 5, 0, 3, 3 }, + { 'test1', 'bytes', 1, 5, 2, 0, 20, 0, 15, 15, 0, 3, 3 }, } - local buf_len = meths.buf_line_count(0) - funcs.setline(buf_len + 1, "baz") + local buf_len = api.nvim_buf_line_count(0) + fn.setline(buf_len + 1, 'baz') check_events { - { "test1", "bytes", 1, 6, 7, 0, 90, 0, 0, 0, 1, 0, 4 }; + { 'test1', 'bytes', 1, 6, 7, 0, 90, 0, 0, 0, 1, 0, 4 }, } end) it('continuing comments with fo=or', function() - local check_events = setup_eventcheck(verify, {'// Comment'}) - meths.set_option_value('formatoptions', 'ro', {}) - meths.set_option_value('filetype', 'c', {}) + local check_events = setup_eventcheck(verify, { '// Comment' }) + api.nvim_set_option_value('formatoptions', 'ro', {}) + api.nvim_set_option_value('filetype', 'c', {}) feed 'A<CR>' check_events { - { "test1", "bytes", 1, 4, 0, 10, 10, 0, 0, 0, 1, 3, 4 }; + { 'test1', 'bytes', 1, 4, 0, 10, 10, 0, 0, 0, 1, 3, 4 }, } feed '<ESC>' check_events { - { "test1", "bytes", 1, 4, 1, 2, 13, 0, 1, 1, 0, 0, 0 }; + { 'test1', 'bytes', 1, 4, 1, 2, 13, 0, 1, 1, 0, 0, 0 }, } feed 'ggo' -- goto first line to continue testing check_events { - { "test1", "bytes", 1, 6, 1, 0, 11, 0, 0, 0, 1, 0, 4 }; + { 'test1', 'bytes', 1, 5, 1, 0, 11, 0, 0, 0, 1, 0, 4 }, } feed '<CR>' check_events { - { "test1", "bytes", 1, 6, 1, 2, 13, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 7, 1, 2, 13, 0, 0, 0, 1, 3, 4 }; + { 'test1', 'bytes', 1, 6, 1, 2, 13, 0, 1, 1, 0, 0, 0 }, + { 'test1', 'bytes', 1, 7, 1, 2, 13, 0, 0, 0, 1, 3, 4 }, } end) @@ -491,757 +502,775 @@ describe('lua: nvim_buf_attach on_bytes', function() feed 'ia' check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 }, } end) - it("deleting lines", function() + it('deleting lines', function() local check_events = setup_eventcheck(verify, origlines) - feed("dd") + feed('dd') check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 }, } - feed("d2j") + feed('d2j') check_events { - { "test1", "bytes", 1, 4, 0, 0, 0, 3, 0, 48, 0, 0, 0 }; + { 'test1', 'bytes', 1, 4, 0, 0, 0, 3, 0, 48, 0, 0, 0 }, } - feed("ld<c-v>2j") + feed('ld<c-v>2j') check_events { - { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 5, 1, 1, 16, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 5, 2, 1, 31, 0, 1, 1, 0, 0, 0 }; + { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 0, 0 }, + { 'test1', 'bytes', 1, 5, 1, 1, 16, 0, 1, 1, 0, 0, 0 }, + { 'test1', 'bytes', 1, 5, 2, 1, 31, 0, 1, 1, 0, 0, 0 }, } - feed("vjwd") + feed('vjwd') check_events { - { "test1", "bytes", 1, 10, 0, 1, 1, 1, 9, 23, 0, 0, 0 }; + { 'test1', 'bytes', 1, 10, 0, 1, 1, 1, 9, 23, 0, 0, 0 }, } end) - it("changing lines", function() + it('changing lines', function() local check_events = setup_eventcheck(verify, origlines) - feed "cc" + feed 'cc' check_events { - { "test1", "bytes", 1, 4, 0, 0, 0, 0, 15, 15, 0, 0, 0 }; + { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 15, 15, 0, 0, 0 }, } - feed "<ESC>" + feed '<ESC>' check_events {} - feed "c3j" + feed 'c3j' check_events { - { "test1", "bytes", 1, 4, 1, 0, 1, 3, 0, 48, 0, 0, 0 }; + { 'test1', 'bytes', 1, 4, 1, 0, 1, 3, 0, 48, 0, 0, 0 }, } end) - it("visual charwise paste", function() - local check_events = setup_eventcheck(verify, {'1234567890'}) - funcs.setreg('a', '___') + it('visual charwise paste', function() + local check_events = setup_eventcheck(verify, { '1234567890' }) + fn.setreg('a', '___') feed '1G1|vll' check_events {} feed '"ap' check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 0, 3, 3, 0, 0, 0 }; - { "test1", "bytes", 1, 5, 0, 0, 0, 0, 0, 0, 0, 3, 3 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 0, 0, 0 }, + { 'test1', 'bytes', 1, 5, 0, 0, 0, 0, 0, 0, 0, 3, 3 }, } end) it('blockwise paste', function() - local check_events = setup_eventcheck(verify, {'1', '2', '3'}) + local check_events = setup_eventcheck(verify, { '1', '2', '3' }) feed('1G0') feed('y<C-v>2j') feed('G0') feed('p') check_events { - { "test1", "bytes", 1, 3, 2, 1, 5, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 3, 3, 0, 7, 0, 0, 0, 0, 3, 3 }; - { "test1", "bytes", 1, 3, 4, 0, 10, 0, 0, 0, 0, 3, 3 }; + { 'test1', 'bytes', 1, 3, 2, 1, 5, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 3, 3, 0, 7, 0, 0, 0, 0, 3, 3 }, + { 'test1', 'bytes', 1, 3, 4, 0, 10, 0, 0, 0, 0, 3, 3 }, } feed('2G0') feed('p') check_events { - { "test1", "bytes", 1, 4, 1, 1, 3, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 4, 2, 1, 6, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 4, 3, 1, 10, 0, 0, 0, 0, 1, 1 }; + { 'test1', 'bytes', 1, 4, 1, 1, 3, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 4, 2, 1, 6, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 4, 3, 1, 10, 0, 0, 0, 0, 1, 1 }, } feed('1G0') feed('P') check_events { - { "test1", "bytes", 1, 5, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 5, 1, 0, 3, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 5, 2, 0, 7, 0, 0, 0, 0, 1, 1 }; + { 'test1', 'bytes', 1, 5, 0, 0, 0, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 5, 1, 0, 3, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 5, 2, 0, 7, 0, 0, 0, 0, 1, 1 }, } - end) - it("linewise paste", function() + it('linewise paste', function() local check_events = setup_eventcheck(verify, origlines) - feed'yyp' + feed 'yyp' check_events { - { "test1", "bytes", 1, 3, 1, 0, 16, 0, 0, 0, 1, 0, 16 }; + { 'test1', 'bytes', 1, 3, 1, 0, 16, 0, 0, 0, 1, 0, 16 }, } - feed'Gyyp' + feed 'Gyyp' check_events { - { "test1", "bytes", 1, 4, 8, 0, 130, 0, 0, 0, 1, 0, 18 }; + { 'test1', 'bytes', 1, 4, 8, 0, 130, 0, 0, 0, 1, 0, 18 }, } end) it('inccomand=nosplit and substitute', function() - local check_events = setup_eventcheck(verify, - {"abcde", "12345"}) - meths.set_option_value('inccommand', 'nosplit', {}) + local check_events = setup_eventcheck(verify, { 'abcde', '12345' }) + api.nvim_set_option_value('inccommand', 'nosplit', {}) -- linewise substitute feed(':%s/bcd/') check_events { - { "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 0, 0 }; - { "test1", "bytes", 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 }; + { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 3, 3, 0, 0, 0 }, + { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 }, } feed('a') check_events { - { "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 1, 1 }; - { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 3, 3 }; + { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 3, 3, 0, 1, 1 }, + { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 3, 3 }, } - feed("<esc>") + feed('<esc>') -- splitting lines feed([[:%s/abc/\r]]) check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 0, 3, 3, 1, 0, 1 }; - { "test1", "bytes", 1, 6, 0, 0, 0, 1, 0, 1, 0, 3, 3 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 1, 0, 1 }, + { 'test1', 'bytes', 1, 6, 0, 0, 0, 1, 0, 1, 0, 3, 3 }, } - feed("<esc>") + feed('<esc>') -- multi-line regex feed([[:%s/de\n123/a]]) check_events { - { "test1", "bytes", 1, 3, 0, 3, 3, 1, 3, 6, 0, 1, 1 }; - { "test1", "bytes", 1, 6, 0, 3, 3, 0, 1, 1, 1, 3, 6 }; + { 'test1', 'bytes', 1, 3, 0, 3, 3, 1, 3, 6, 0, 1, 1 }, + { 'test1', 'bytes', 1, 6, 0, 3, 3, 0, 1, 1, 1, 3, 6 }, } - feed("<esc>") + feed('<esc>') -- replacing with unicode - feed(":%s/b/→") + feed(':%s/b/→') check_events { - { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 3, 3 }; - { "test1", "bytes", 1, 5, 0, 1, 1, 0, 3, 3, 0, 1, 1 }; + { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 3, 3 }, + { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 3, 3, 0, 1, 1 }, } - feed("<esc>") + feed('<esc>') -- replacing with expression register feed([[:%s/b/\=5+5]]) check_events { - { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 }; - { "test1", "bytes", 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 }; + { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 }, + { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 }, } - feed("<esc>") + feed('<esc>') -- replacing with backslash feed([[:%s/b/\\]]) check_events { - { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 }; - { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 }; + { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 }, + { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 }, } - feed("<esc>") + feed('<esc>') -- replacing with backslash from expression register feed([[:%s/b/\='\']]) check_events { - { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 }; - { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 }; + { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 }, + { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 }, } - feed("<esc>") + feed('<esc>') -- replacing with backslash followed by another character feed([[:%s/b/\\!]]) check_events { - { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 }; - { "test1", "bytes", 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 }; + { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 }, + { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 }, } - feed("<esc>") + feed('<esc>') -- replacing with backslash followed by another character from expression register feed([[:%s/b/\='\!']]) check_events { - { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 }; - { "test1", "bytes", 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 }; + { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 }, + { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 }, } end) it('nvim_buf_set_text insert', function() - local check_events = setup_eventcheck(verify, {"bastext"}) - meths.buf_set_text(0, 0, 3, 0, 3, {"fiol","kontra"}) + local check_events = setup_eventcheck(verify, { 'bastext' }) + api.nvim_buf_set_text(0, 0, 3, 0, 3, { 'fiol', 'kontra' }) check_events { - { "test1", "bytes", 1, 3, 0, 3, 3, 0, 0, 0, 1, 6, 11 }; + { 'test1', 'bytes', 1, 3, 0, 3, 3, 0, 0, 0, 1, 6, 11 }, } - meths.buf_set_text(0, 1, 6, 1, 6, {"punkt","syntgitarr","övnings"}) + api.nvim_buf_set_text(0, 1, 6, 1, 6, { 'punkt', 'syntgitarr', 'övnings' }) check_events { - { "test1", "bytes", 1, 4, 1, 6, 14, 0, 0, 0, 2, 8, 25 }; + { 'test1', 'bytes', 1, 4, 1, 6, 14, 0, 0, 0, 2, 8, 25 }, } - eq({ "basfiol", "kontrapunkt", "syntgitarr", "övningstext" }, - meths.buf_get_lines(0, 0, -1, true)) + eq( + { 'basfiol', 'kontrapunkt', 'syntgitarr', 'övningstext' }, + api.nvim_buf_get_lines(0, 0, -1, true) + ) end) it('nvim_buf_set_text replace', function() local check_events = setup_eventcheck(verify, origlines) - meths.buf_set_text(0, 2, 3, 2, 8, {"very text"}) + api.nvim_buf_set_text(0, 2, 3, 2, 8, { 'very text' }) check_events { - { "test1", "bytes", 1, 3, 2, 3, 35, 0, 5, 5, 0, 9, 9 }; + { 'test1', 'bytes', 1, 3, 2, 3, 35, 0, 5, 5, 0, 9, 9 }, } - meths.buf_set_text(0, 3, 5, 3, 7, {" splitty","line "}) + api.nvim_buf_set_text(0, 3, 5, 3, 7, { ' splitty', 'line ' }) check_events { - { "test1", "bytes", 1, 4, 3, 5, 57, 0, 2, 2, 1, 5, 14 }; + { 'test1', 'bytes', 1, 4, 3, 5, 57, 0, 2, 2, 1, 5, 14 }, } - meths.buf_set_text(0, 0, 8, 1, 2, {"JOINY"}) + api.nvim_buf_set_text(0, 0, 8, 1, 2, { 'JOINY' }) check_events { - { "test1", "bytes", 1, 5, 0, 8, 8, 1, 2, 10, 0, 5, 5 }; + { 'test1', 'bytes', 1, 5, 0, 8, 8, 1, 2, 10, 0, 5, 5 }, } - meths.buf_set_text(0, 4, 0, 6, 0, {"was 5,6",""}) + api.nvim_buf_set_text(0, 4, 0, 6, 0, { 'was 5,6', '' }) check_events { - { "test1", "bytes", 1, 6, 4, 0, 75, 2, 0, 32, 1, 0, 8 }; + { 'test1', 'bytes', 1, 6, 4, 0, 75, 2, 0, 32, 1, 0, 8 }, } - eq({ "originalJOINYiginal line 2", "orivery text line 3", "origi splitty", - "line l line 4", "was 5,6", " indented line" }, - meths.buf_get_lines(0, 0, -1, true)) - + eq({ + 'originalJOINYiginal line 2', + 'orivery text line 3', + 'origi splitty', + 'line l line 4', + 'was 5,6', + ' indented line', + }, api.nvim_buf_get_lines(0, 0, -1, true)) end) it('nvim_buf_set_text delete', function() local check_events = setup_eventcheck(verify, origlines) -- really {""} but accepts {} as a shorthand - meths.buf_set_text(0, 0, 0, 1, 0, {}) + api.nvim_buf_set_text(0, 0, 0, 1, 0, {}) check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 }, } -- TODO(bfredl): this works but is not as convenient as set_lines - meths.buf_set_text(0, 4, 15, 5, 17, {""}) + api.nvim_buf_set_text(0, 4, 15, 5, 17, { '' }) check_events { - { "test1", "bytes", 1, 4, 4, 15, 79, 1, 17, 18, 0, 0, 0 }; + { 'test1', 'bytes', 1, 4, 4, 15, 79, 1, 17, 18, 0, 0, 0 }, } - eq({ "original line 2", "original line 3", "original line 4", - "original line 5", "original line 6" }, - meths.buf_get_lines(0, 0, -1, true)) + eq({ + 'original line 2', + 'original line 3', + 'original line 4', + 'original line 5', + 'original line 6', + }, api.nvim_buf_get_lines(0, 0, -1, true)) end) it('checktime autoread', function() - write_file("Xtest-reload", dedent [[ + write_file( + 'Xtest-reload', + dedent [[ old line 1 - old line 2]]) + old line 2]] + ) local atime = os.time() - 10 - luv.fs_utime("Xtest-reload", atime, atime) - command "e Xtest-reload" - command "set autoread" + vim.uv.fs_utime('Xtest-reload', atime, atime) + command 'e Xtest-reload' + command 'set autoread' local check_events = setup_eventcheck(verify, nil) - write_file("Xtest-reload", dedent [[ + write_file( + 'Xtest-reload', + dedent [[ new line 1 new line 2 - new line 3]]) + new line 3]] + ) - command "checktime" + command 'checktime' check_events { - { "test1", "reload", 1 }; + { 'test1', 'reload', 1 }, } feed 'ggJ' check_events { - { "test1", "bytes", 1, 5, 0, 10, 10, 1, 0, 1, 0, 1, 1 }; + { 'test1', 'bytes', 1, 5, 0, 10, 10, 1, 0, 1, 0, 1, 1 }, } - eq({'new line 1 new line 2', 'new line 3'}, meths.buf_get_lines(0, 0, -1, true)) + eq({ 'new line 1 new line 2', 'new line 3' }, api.nvim_buf_get_lines(0, 0, -1, true)) -- check we can undo and redo a reload event. feed 'u' check_events { - { "test1", "bytes", 1, 8, 0, 10, 10, 0, 1, 1, 1, 0, 1 }; + { 'test1', 'bytes', 1, 8, 0, 10, 10, 0, 1, 1, 1, 0, 1 }, } feed 'u' check_events { - { "test1", "reload", 1 }; + { 'test1', 'reload', 1 }, } feed '<c-r>' check_events { - { "test1", "reload", 1 }; + { 'test1', 'reload', 1 }, } feed '<c-r>' check_events { - { "test1", "bytes", 1, 14, 0, 10, 10, 1, 0, 1, 0, 1, 1 }; + { 'test1', 'bytes', 1, 14, 0, 10, 10, 1, 0, 1, 0, 1, 1 }, } end) - it("tab with noexpandtab and softtabstop", function() - command("set noet") - command("set ts=4") - command("set sw=2") - command("set sts=4") + it('tab with noexpandtab and softtabstop', function() + command('set noet') + command('set ts=4') + command('set sw=2') + command('set sts=4') - local check_events = setup_eventcheck(verify, {'asdfasdf'}) + local check_events = setup_eventcheck(verify, { 'asdfasdf' }) - feed("gg0i<tab>") + feed('gg0i<tab>') check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 }, - { "test1", "bytes", 1, 4, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 4, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, } - feed("<tab>") + feed('<tab>') -- when spaces are merged into a tabstop check_events { - { "test1", "bytes", 1, 5, 0, 2, 2, 0, 0, 0, 0, 1, 1 }, - { "test1", "bytes", 1, 6, 0, 3, 3, 0, 0, 0, 0, 1, 1 }, - { "test1", "bytes", 1, 7, 0, 0, 0, 0, 4, 4, 0, 1, 1 }, + { 'test1', 'bytes', 1, 5, 0, 2, 2, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 6, 0, 3, 3, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 7, 0, 0, 0, 0, 4, 4, 0, 1, 1 }, } - - feed("<esc>u") + feed('<esc>u') check_events { - { "test1", "bytes", 1, 9, 0, 0, 0, 0, 1, 1, 0, 4, 4 }, - { "test1", "bytes", 1, 9, 0, 0, 0, 0, 4, 4, 0, 0, 0 } + { 'test1', 'bytes', 1, 9, 0, 0, 0, 0, 1, 1, 0, 4, 4 }, + { 'test1', 'bytes', 1, 9, 0, 0, 0, 0, 4, 4, 0, 0, 0 }, } -- in REPLACE mode - feed("R<tab><tab>") + feed('R<tab><tab>') check_events { - { "test1", "bytes", 1, 10, 0, 0, 0, 0, 1, 1, 0, 1, 1 }, - { "test1", "bytes", 1, 11, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, - { "test1", "bytes", 1, 12, 0, 2, 2, 0, 1, 1, 0, 1, 1 }, - { "test1", "bytes", 1, 13, 0, 3, 3, 0, 0, 0, 0, 1, 1 }, - { "test1", "bytes", 1, 14, 0, 0, 0, 0, 4, 4, 0, 1, 1 }, + { 'test1', 'bytes', 1, 10, 0, 0, 0, 0, 1, 1, 0, 1, 1 }, + { 'test1', 'bytes', 1, 11, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 12, 0, 2, 2, 0, 1, 1, 0, 1, 1 }, + { 'test1', 'bytes', 1, 13, 0, 3, 3, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 14, 0, 0, 0, 0, 4, 4, 0, 1, 1 }, } - feed("<esc>u") + feed('<esc>u') check_events { - { "test1", "bytes", 1, 16, 0, 0, 0, 0, 1, 1, 0, 4, 4 }, - { "test1", "bytes", 1, 16, 0, 2, 2, 0, 2, 2, 0, 1, 1 }, - { "test1", "bytes", 1, 16, 0, 0, 0, 0, 2, 2, 0, 1, 1 } + { 'test1', 'bytes', 1, 16, 0, 0, 0, 0, 1, 1, 0, 4, 4 }, + { 'test1', 'bytes', 1, 16, 0, 2, 2, 0, 2, 2, 0, 1, 1 }, + { 'test1', 'bytes', 1, 16, 0, 0, 0, 0, 2, 2, 0, 1, 1 }, } -- in VISUALREPLACE mode - feed("gR<tab><tab>") - check_events { - { "test1", "bytes", 1, 17, 0, 0, 0, 0, 1, 1, 0, 1, 1 }; - { "test1", "bytes", 1, 18, 0, 1, 1, 0, 1, 1, 0, 1, 1 }; - { "test1", "bytes", 1, 19, 0, 2, 2, 0, 1, 1, 0, 1, 1 }; - { "test1", "bytes", 1, 20, 0, 3, 3, 0, 1, 1, 0, 1, 1 }; - { "test1", "bytes", 1, 21, 0, 3, 3, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 22, 0, 3, 3, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 24, 0, 2, 2, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 25, 0, 2, 2, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 27, 0, 1, 1, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 28, 0, 1, 1, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 30, 0, 0, 0, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 31, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 33, 0, 0, 0, 0, 4, 4, 0, 1, 1 }; + feed('gR<tab><tab>') + check_events { + { 'test1', 'bytes', 1, 17, 0, 0, 0, 0, 1, 1, 0, 1, 1 }, + { 'test1', 'bytes', 1, 18, 0, 1, 1, 0, 1, 1, 0, 1, 1 }, + { 'test1', 'bytes', 1, 19, 0, 2, 2, 0, 1, 1, 0, 1, 1 }, + { 'test1', 'bytes', 1, 20, 0, 3, 3, 0, 1, 1, 0, 1, 1 }, + { 'test1', 'bytes', 1, 21, 0, 3, 3, 0, 1, 1, 0, 0, 0 }, + { 'test1', 'bytes', 1, 22, 0, 3, 3, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 24, 0, 2, 2, 0, 1, 1, 0, 0, 0 }, + { 'test1', 'bytes', 1, 25, 0, 2, 2, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 27, 0, 1, 1, 0, 1, 1, 0, 0, 0 }, + { 'test1', 'bytes', 1, 28, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 30, 0, 0, 0, 0, 1, 1, 0, 0, 0 }, + { 'test1', 'bytes', 1, 31, 0, 0, 0, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 33, 0, 0, 0, 0, 4, 4, 0, 1, 1 }, } -- inserting tab after other tabs - command("set sw=4") - feed("<esc>0a<tab>") + command('set sw=4') + feed('<esc>0a<tab>') check_events { - { "test1", "bytes", 1, 34, 0, 1, 1, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 35, 0, 2, 2, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 36, 0, 3, 3, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 37, 0, 4, 4, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 38, 0, 1, 1, 0, 4, 4, 0, 1, 1 }; + { 'test1', 'bytes', 1, 34, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 35, 0, 2, 2, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 36, 0, 3, 3, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 37, 0, 4, 4, 0, 0, 0, 0, 1, 1 }, + { 'test1', 'bytes', 1, 38, 0, 1, 1, 0, 4, 4, 0, 1, 1 }, } end) - it("retab", function() - command("set noet") - command("set ts=4") + it('retab', function() + command('set noet') + command('set ts=4') - local check_events = setup_eventcheck(verify, {" asdf"}) - command("retab 8") + local check_events = setup_eventcheck(verify, { ' asdf' }) + command('retab 8') check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 0, 7, 7, 0, 9, 9 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 7, 7, 0, 9, 9 }, } end) - it("sends events when undoing with undofile", function() - write_file("Xtest-undofile", dedent([[ + it('sends events when undoing with undofile', function() + write_file( + 'Xtest-undofile', + dedent([[ 12345 hello world - ]])) + ]]) + ) - command("e! Xtest-undofile") - command("set undodir=. | set undofile") + command('e! Xtest-undofile') + command('set undodir=. | set undofile') - local ns = helpers.request('nvim_create_namespace', "ns1") - meths.buf_set_extmark(0, ns, 0, 0, {}) + local ns = helpers.request('nvim_create_namespace', 'ns1') + api.nvim_buf_set_extmark(0, ns, 0, 0, {}) - eq({"12345", "hello world"}, meths.buf_get_lines(0, 0, -1, true)) + eq({ '12345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true)) -- splice - feed("gg0d2l") + feed('gg0d2l') - eq({"345", "hello world"}, meths.buf_get_lines(0, 0, -1, true)) + eq({ '345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true)) -- move - command(".m+1") + command('.m+1') - eq({"hello world", "345"}, meths.buf_get_lines(0, 0, -1, true)) + eq({ 'hello world', '345' }, api.nvim_buf_get_lines(0, 0, -1, true)) -- reload undofile and undo changes - command("w") - command("set noundofile") - command("bw!") - command("e! Xtest-undofile") + command('w') + command('set noundofile') + command('bw!') + command('e! Xtest-undofile') - command("set undofile") + command('set undofile') local check_events = setup_eventcheck(verify, nil) - feed("u") - eq({"345", "hello world"}, meths.buf_get_lines(0, 0, -1, true)) + feed('u') + eq({ '345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true)) check_events { - { "test1", "bytes", 2, 6, 1, 0, 12, 1, 0, 4, 0, 0, 0 }, - { "test1", "bytes", 2, 6, 0, 0, 0, 0, 0, 0, 1, 0, 4 } + { 'test1', 'bytes', 2, 6, 1, 0, 12, 1, 0, 4, 0, 0, 0 }, + { 'test1', 'bytes', 2, 6, 0, 0, 0, 0, 0, 0, 1, 0, 4 }, } - feed("u") - eq({"12345", "hello world"}, meths.buf_get_lines(0, 0, -1, true)) + feed('u') + eq({ '12345', 'hello world' }, api.nvim_buf_get_lines(0, 0, -1, true)) check_events { - { "test1", "bytes", 2, 8, 0, 0, 0, 0, 0, 0, 0, 2, 2 } + { 'test1', 'bytes', 2, 8, 0, 0, 0, 0, 0, 0, 0, 2, 2 }, } - command("bw!") + command('bw!') end) - it("blockwise paste with uneven line lengths", function() - local check_events = setup_eventcheck(verify, {'aaaa', 'aaa', 'aaa'}) + it('blockwise paste with uneven line lengths', function() + local check_events = setup_eventcheck(verify, { 'aaaa', 'aaa', 'aaa' }) - -- eq({}, meths.buf_get_lines(0, 0, -1, true)) - feed("gg0<c-v>jj$d") + -- eq({}, api.nvim_buf_get_lines(0, 0, -1, true)) + feed('gg0<c-v>jj$d') check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 0, 4, 4, 0, 0, 0 }, - { "test1", "bytes", 1, 3, 1, 0, 1, 0, 3, 3, 0, 0, 0 }, - { "test1", "bytes", 1, 3, 2, 0, 2, 0, 3, 3, 0, 0, 0 }, + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 4, 4, 0, 0, 0 }, + { 'test1', 'bytes', 1, 3, 1, 0, 1, 0, 3, 3, 0, 0, 0 }, + { 'test1', 'bytes', 1, 3, 2, 0, 2, 0, 3, 3, 0, 0, 0 }, } - feed("p") + feed('p') check_events { - { "test1", "bytes", 1, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4 }, - { "test1", "bytes", 1, 4, 1, 0, 5, 0, 0, 0, 0, 3, 3 }, - { "test1", "bytes", 1, 4, 2, 0, 9, 0, 0, 0, 0, 3, 3 }, + { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4 }, + { 'test1', 'bytes', 1, 4, 1, 0, 5, 0, 0, 0, 0, 3, 3 }, + { 'test1', 'bytes', 1, 4, 2, 0, 9, 0, 0, 0, 0, 3, 3 }, } - end) - it(":luado", function() - local check_events = setup_eventcheck(verify, {"abc", "12345"}) + it(':luado', function() + local check_events = setup_eventcheck(verify, { 'abc', '12345' }) command(".luado return 'a'") check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 0, 3, 3, 0, 1, 1 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 0, 1, 1 }, } - command("luado return 10") + command('luado return 10') check_events { - { "test1", "bytes", 1, 4, 0, 0, 0, 0, 1, 1, 0, 2, 2 }; - { "test1", "bytes", 1, 5, 1, 0, 3, 0, 5, 5, 0, 2, 2 }; + { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 1, 1, 0, 2, 2 }, + { 'test1', 'bytes', 1, 5, 1, 0, 3, 0, 5, 5, 0, 2, 2 }, } - end) - it("flushes deleted bytes on move", function() - local check_events = setup_eventcheck(verify, {"AAA", "BBB", "CCC", "DDD"}) + it('flushes deleted bytes on move', function() + local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC', 'DDD' }) - feed(":.move+1<cr>") + feed(':.move+1<cr>') check_events { - { "test1", "bytes", 1, 5, 0, 0, 0, 1, 0, 4, 0, 0, 0 }; - { "test1", "bytes", 1, 5, 1, 0, 4, 0, 0, 0, 1, 0, 4 }; + { 'test1', 'bytes', 1, 5, 0, 0, 0, 1, 0, 4, 0, 0, 0 }, + { 'test1', 'bytes', 1, 5, 1, 0, 4, 0, 0, 0, 1, 0, 4 }, } - feed("jd2j") + feed('jd2j') check_events { - { "test1", "bytes", 1, 6, 2, 0, 8, 2, 0, 8, 0, 0, 0 }; + { 'test1', 'bytes', 1, 6, 2, 0, 8, 2, 0, 8, 0, 0, 0 }, } end) - it("virtual edit", function () - local check_events = setup_eventcheck(verify, { "", " " }) + it('virtual edit', function() + local check_events = setup_eventcheck(verify, { '', ' ' }) - meths.set_option_value('virtualedit', "all", {}) + api.nvim_set_option_value('virtualedit', 'all', {}) feed [[<Right><Right>iab<ESC>]] check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2 }; - { "test1", "bytes", 1, 4, 0, 2, 2, 0, 0, 0, 0, 2, 2 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2 }, + { 'test1', 'bytes', 1, 4, 0, 2, 2, 0, 0, 0, 0, 2, 2 }, } feed [[j<Right><Right>iab<ESC>]] check_events { - { "test1", "bytes", 1, 5, 1, 0, 5, 0, 1, 1, 0, 8, 8 }; - { "test1", "bytes", 1, 6, 1, 5, 10, 0, 0, 0, 0, 2, 2 }; + { 'test1', 'bytes', 1, 5, 1, 0, 5, 0, 1, 1, 0, 8, 8 }, + { 'test1', 'bytes', 1, 6, 1, 5, 10, 0, 0, 0, 0, 2, 2 }, } end) - it("block visual paste", function() - local check_events = setup_eventcheck(verify, {"AAA", - "BBB", - "CCC", - "DDD", - "EEE", - "FFF"}) - funcs.setreg("a", "___") + it('block visual paste', function() + local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF' }) + fn.setreg('a', '___') feed([[gg0l<c-v>3jl"ap]]) check_events { - { "test1", "bytes", 1, 3, 0, 1, 1, 0, 2, 2, 0, 0, 0 }; - { "test1", "bytes", 1, 3, 1, 1, 3, 0, 2, 2, 0, 0, 0 }; - { "test1", "bytes", 1, 3, 2, 1, 5, 0, 2, 2, 0, 0, 0 }; - { "test1", "bytes", 1, 3, 3, 1, 7, 0, 2, 2, 0, 0, 0 }; - { "test1", "bytes", 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 }; - { "test1", "bytes", 1, 6, 1, 1, 6, 0, 0, 0, 0, 3, 3 }; - { "test1", "bytes", 1, 7, 2, 1, 11, 0, 0, 0, 0, 3, 3 }; - { "test1", "bytes", 1, 8, 3, 1, 16, 0, 0, 0, 0, 3, 3 }; + { 'test1', 'bytes', 1, 3, 0, 1, 1, 0, 2, 2, 0, 0, 0 }, + { 'test1', 'bytes', 1, 3, 1, 1, 3, 0, 2, 2, 0, 0, 0 }, + { 'test1', 'bytes', 1, 3, 2, 1, 5, 0, 2, 2, 0, 0, 0 }, + { 'test1', 'bytes', 1, 3, 3, 1, 7, 0, 2, 2, 0, 0, 0 }, + { 'test1', 'bytes', 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 }, + { 'test1', 'bytes', 1, 6, 1, 1, 6, 0, 0, 0, 0, 3, 3 }, + { 'test1', 'bytes', 1, 7, 2, 1, 11, 0, 0, 0, 0, 3, 3 }, + { 'test1', 'bytes', 1, 8, 3, 1, 16, 0, 0, 0, 0, 3, 3 }, } end) - it("visual paste", function() - local check_events= setup_eventcheck(verify, { "aaa {", "b", "}" }) + it('visual paste', function() + local check_events = setup_eventcheck(verify, { 'aaa {', 'b', '}' }) -- Setting up - feed[[jdd]] + feed [[jdd]] check_events { - { "test1", "bytes", 1, 3, 1, 0, 6, 1, 0, 2, 0, 0, 0 }; + { 'test1', 'bytes', 1, 3, 1, 0, 6, 1, 0, 2, 0, 0, 0 }, } -- Actually testing - feed[[v%p]] + feed [[v%p]] + check_events { + { 'test1', 'bytes', 1, 8, 0, 4, 4, 1, 1, 3, 0, 0, 0 }, + { 'test1', 'bytes', 1, 8, 0, 4, 4, 0, 0, 0, 2, 0, 3 }, + } + end) + + it('visual paste 2: splitting an empty line', function() + local check_events = setup_eventcheck(verify, { 'abc', '{', 'def', '}' }) + feed('ggyyjjvi{p') check_events { - { "test1", "bytes", 1, 8, 0, 4, 4, 1, 1, 3, 0, 0, 0 }; - { "test1", "bytes", 1, 8, 0, 4, 4, 0, 0, 0, 2, 0, 3 }; + { 'test1', 'bytes', 1, 6, 2, 0, 6, 1, 0, 4, 0, 0, 0 }, + { 'test1', 'bytes', 1, 6, 2, 0, 6, 0, 0, 0, 2, 0, 5 }, } end) - it("nvim_buf_set_lines", function() - local check_events = setup_eventcheck(verify, {"AAA", "BBB"}) + it('nvim_buf_set_lines', function() + local check_events = setup_eventcheck(verify, { 'AAA', 'BBB' }) -- delete - meths.buf_set_lines(0, 0, 1, true, {}) + api.nvim_buf_set_lines(0, 0, 1, true, {}) check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 1, 0, 4, 0, 0, 0 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 4, 0, 0, 0 }, } -- add - meths.buf_set_lines(0, 0, 0, true, {'asdf'}) + api.nvim_buf_set_lines(0, 0, 0, true, { 'asdf' }) check_events { - { "test1", "bytes", 1, 4, 0, 0, 0, 0, 0, 0, 1, 0, 5 }; + { 'test1', 'bytes', 1, 4, 0, 0, 0, 0, 0, 0, 1, 0, 5 }, } -- replace - meths.buf_set_lines(0, 0, 1, true, {'asdf', 'fdsa'}) + api.nvim_buf_set_lines(0, 0, 1, true, { 'asdf', 'fdsa' }) check_events { - { "test1", "bytes", 1, 5, 0, 0, 0, 1, 0, 5, 2, 0, 10 }; + { 'test1', 'bytes', 1, 5, 0, 0, 0, 1, 0, 5, 2, 0, 10 }, } end) - it("flushes delbytes on substitute", function() - local check_events = setup_eventcheck(verify, {"AAA", "BBB", "CCC"}) + it('flushes delbytes on substitute', function() + local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' }) - feed("gg0") - command("s/AAA/GGG/") + feed('gg0') + command('s/AAA/GGG/') check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 0, 3, 3, 0, 3, 3 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 3, 3, 0, 3, 3 }, } -- check that byte updates for :delete (which uses curbuf->deleted_bytes2) -- are correct - command("delete") + command('delete') check_events { - { "test1", "bytes", 1, 4, 0, 0, 0, 1, 0, 4, 0, 0, 0 }; + { 'test1', 'bytes', 1, 4, 0, 0, 0, 1, 0, 4, 0, 0, 0 }, } end) - it("flushes delbytes on join", function() - local check_events = setup_eventcheck(verify, {"AAA", "BBB", "CCC"}) + it('flushes delbytes on join', function() + local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' }) - feed("gg0J") + feed('gg0J') check_events { - { "test1", "bytes", 1, 3, 0, 3, 3, 1, 0, 1, 0, 1, 1 }; + { 'test1', 'bytes', 1, 3, 0, 3, 3, 1, 0, 1, 0, 1, 1 }, } - command("delete") + command('delete') check_events { - { "test1", "bytes", 1, 5, 0, 0, 0, 1, 0, 8, 0, 0, 0 }; + { 'test1', 'bytes', 1, 5, 0, 0, 0, 1, 0, 8, 0, 0, 0 }, } end) - it("sends updates on U", function() - feed("ggiAAA<cr>BBB") - feed("<esc>gg$a CCC") + it('sends updates on U', function() + feed('ggiAAA<cr>BBB') + feed('<esc>gg$a CCC') local check_events = setup_eventcheck(verify, nil) - feed("ggU") + feed('ggU') check_events { - { "test1", "bytes", 1, 6, 0, 7, 7, 0, 0, 0, 0, 3, 3 }; + { 'test1', 'bytes', 1, 6, 0, 7, 7, 0, 0, 0, 0, 3, 3 }, } end) - it("delete in completely empty buffer", function() + it('delete in completely empty buffer', function() local check_events = setup_eventcheck(verify, nil) - command "delete" - check_events { } + command 'delete' + check_events {} end) - it("delete the only line of a buffer", function() - local check_events = setup_eventcheck(verify, {"AAA"}) + it('delete the only line of a buffer', function() + local check_events = setup_eventcheck(verify, { 'AAA' }) - command "delete" + command 'delete' check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 1, 0, 4, 1, 0, 1 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 1, 0, 4, 1, 0, 1 }, } end) - it("delete the last line of a buffer with two lines", function() - local check_events = setup_eventcheck(verify, {"AAA", "BBB"}) + it('delete the last line of a buffer with two lines', function() + local check_events = setup_eventcheck(verify, { 'AAA', 'BBB' }) - command "2delete" + command '2delete' check_events { - { "test1", "bytes", 1, 3, 1, 0, 4, 1, 0, 4, 0, 0, 0 }; + { 'test1', 'bytes', 1, 3, 1, 0, 4, 1, 0, 4, 0, 0, 0 }, } end) - it(":sort lines", function() - local check_events = setup_eventcheck(verify, {"CCC", "BBB", "AAA"}) + it(':sort lines', function() + local check_events = setup_eventcheck(verify, { 'CCC', 'BBB', 'AAA' }) - command "%sort" + command '%sort' check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 3, 0, 12, 3, 0, 12 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 3, 0, 12, 3, 0, 12 }, } end) - it("handles already sorted lines", function() - local check_events = setup_eventcheck(verify, {"AAA", "BBB", "CCC"}) + it('handles already sorted lines', function() + local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' }) - command "%sort" - check_events { } + command '%sort' + check_events {} end) - it("works with accepting spell suggestions", function() - local check_events = setup_eventcheck(verify, {"hallo world", "hallo world"}) + it('works with accepting spell suggestions', function() + local check_events = setup_eventcheck(verify, { 'hallo world', 'hallo world' }) - feed("gg0z=4<cr><cr>") -- accepts 'Hello' + feed('gg0z=4<cr><cr>') -- accepts 'Hello' check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 0, 2, 2, 0, 2, 2 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 0, 2, 2, 0, 2, 2 }, } - command("spellrepall") -- replaces whole words + command('spellrepall') -- replaces whole words check_events { - { "test1", "bytes", 1, 4, 1, 0, 12, 0, 5, 5, 0, 5, 5 }; + { 'test1', 'bytes', 1, 4, 1, 0, 12, 0, 5, 5, 0, 5, 5 }, } end) it('works with :diffput and :diffget', function() - local check_events = setup_eventcheck(verify, {"AAA"}) + local check_events = setup_eventcheck(verify, { 'AAA' }) command('diffthis') command('new') command('diffthis') - meths.buf_set_lines(0, 0, -1, true, {"AAA", "BBB"}) + api.nvim_buf_set_lines(0, 0, -1, true, { 'AAA', 'BBB' }) feed('G') command('diffput') check_events { - { "test1", "bytes", 1, 3, 1, 0, 4, 0, 0, 0, 1, 0, 4 }; + { 'test1', 'bytes', 1, 3, 1, 0, 4, 0, 0, 0, 1, 0, 4 }, } - meths.buf_set_lines(0, 0, -1, true, {"AAA", "CCC"}) + api.nvim_buf_set_lines(0, 0, -1, true, { 'AAA', 'CCC' }) feed('<C-w>pG') command('diffget') check_events { - { "test1", "bytes", 1, 4, 1, 0, 4, 1, 0, 4, 1, 0, 4 }; + { 'test1', 'bytes', 1, 4, 1, 0, 4, 1, 0, 4, 1, 0, 4 }, } end) local function test_lockmarks(mode) - local description = (mode ~= "") and mode or "(baseline)" - it("test_lockmarks " .. description .. " %delete _", function() - local check_events = setup_eventcheck(verify, {"AAA", "BBB", "CCC"}) + local description = (mode ~= '') and mode or '(baseline)' + it('test_lockmarks ' .. description .. ' %delete _', function() + local check_events = setup_eventcheck(verify, { 'AAA', 'BBB', 'CCC' }) - command(mode .. " %delete _") + command(mode .. ' %delete _') check_events { - { "test1", "bytes", 1, 3, 0, 0, 0, 3, 0, 12, 1, 0, 1 }; + { 'test1', 'bytes', 1, 3, 0, 0, 0, 3, 0, 12, 1, 0, 1 }, } end) - it("test_lockmarks " .. description .. " append()", function() + it('test_lockmarks ' .. description .. ' append()', function() local check_events = setup_eventcheck(verify) command(mode .. " call append(0, 'CCC')") check_events { - { "test1", "bytes", 1, 2, 0, 0, 0, 0, 0, 0, 1, 0, 4 }; + { 'test1', 'bytes', 1, 2, 0, 0, 0, 0, 0, 0, 1, 0, 4 }, } command(mode .. " call append(1, 'BBBB')") check_events { - { "test1", "bytes", 1, 3, 1, 0, 4, 0, 0, 0, 1, 0, 5 }; + { 'test1', 'bytes', 1, 3, 1, 0, 4, 0, 0, 0, 1, 0, 5 }, } command(mode .. " call append(2, '')") check_events { - { "test1", "bytes", 1, 4, 2, 0, 9, 0, 0, 0, 1, 0, 1 }; + { 'test1', 'bytes', 1, 4, 2, 0, 9, 0, 0, 0, 1, 0, 1 }, } - command(mode .. " $delete _") + command(mode .. ' $delete _') check_events { - { "test1", "bytes", 1, 5, 3, 0, 10, 1, 0, 1, 0, 0, 0 }; + { 'test1', 'bytes', 1, 5, 3, 0, 10, 1, 0, 1, 0, 0, 0 }, } - eq("CCC|BBBB|", table.concat(meths.buf_get_lines(0, 0, -1, true), "|")) + eq('CCC|BBBB|', table.concat(api.nvim_buf_get_lines(0, 0, -1, true), '|')) end) end -- check that behavior is identical with and without "lockmarks" - test_lockmarks "" - test_lockmarks "lockmarks" + test_lockmarks '' + test_lockmarks 'lockmarks' teardown(function() - os.remove "Xtest-reload" - os.remove "Xtest-undofile" - os.remove ".Xtest-undofile.un~" + os.remove 'Xtest-reload' + os.remove 'Xtest-undofile' + os.remove '.Xtest-undofile.un~' end) end @@ -1253,4 +1282,3 @@ describe('lua: nvim_buf_attach on_bytes', function() do_both(false) end) end) - diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua index 177e077f4a..b88a38082f 100644 --- a/test/functional/lua/command_line_completion_spec.lua +++ b/test/functional/lua/command_line_completion_spec.lua @@ -5,34 +5,33 @@ local eq = helpers.eq local exec_lua = helpers.exec_lua local get_completions = function(input, env) - return exec_lua("return {vim._expand_pat(...)}", input, env) + return exec_lua('return {vim._expand_pat(...)}', input, env) end local get_compl_parts = function(parts) - return exec_lua("return {vim._expand_pat_get_parts(...)}", parts) + return exec_lua('return {vim._expand_pat_get_parts(...)}', parts) end before_each(clear) describe('nlua_expand_pat', function() it('should complete exact matches', function() - eq({{'exact'}, 0}, get_completions('exact', { exact = true })) + eq({ { 'exact' }, 0 }, get_completions('exact', { exact = true })) end) it('should return empty table when nothing matches', function() - eq({{}, 0}, get_completions('foo', { bar = true })) + eq({ {}, 0 }, get_completions('foo', { bar = true })) end) it('should return nice completions with function call prefix', function() - eq({{'FOO'}, 6}, get_completions('print(F', { FOO = true, bawr = true })) + eq({ { 'FOO' }, 6 }, get_completions('print(F', { FOO = true, bawr = true })) end) it('should return keys for nested dictionaries', function() eq( - {{ + { { 'nvim_buf_set_lines', - }, 8 - }, + }, 8 }, get_completions('vim.api.nvim_buf_', { vim = { api = { @@ -40,34 +39,32 @@ describe('nlua_expand_pat', function() nvim_win_doesnt_match = true, }, other_key = true, - } + }, }) ) end) it('it should work with colons', function() eq( - {{ + { { 'bawr', 'baz', - }, 8 - }, + }, 8 }, get_completions('MyClass:b', { MyClass = { baz = true, bawr = true, foo = false, - } + }, }) ) end) it('should return keys for string reffed dictionaries', function() eq( - {{ + { { 'nvim_buf_set_lines', - }, 11 - }, + }, 11 }, get_completions('vim["api"].nvim_buf_', { vim = { api = { @@ -75,17 +72,16 @@ describe('nlua_expand_pat', function() nvim_win_doesnt_match = true, }, other_key = true, - } + }, }) ) end) it('should return keys for string reffed dictionaries', function() eq( - {{ + { { 'nvim_buf_set_lines', - }, 21 - }, + }, 21 }, get_completions('vim["nested"]["api"].nvim_buf_', { vim = { nested = { @@ -95,80 +91,76 @@ describe('nlua_expand_pat', function() }, }, other_key = true, - } + }, }) ) end) it('should work with lazy submodules of "vim" global', function() - eq({{ 'inspect', 'inspect_pos' }, 4 }, - get_completions('vim.inspec')) + eq({ { 'inspect', 'inspect_pos' }, 4 }, get_completions('vim.inspec')) - eq({{ 'treesitter' }, 4 }, - get_completions('vim.treesi')) + eq({ { 'treesitter' }, 4 }, get_completions('vim.treesi')) - eq({{ 'set' }, 11 }, - get_completions('vim.keymap.se')) + eq({ { 'set' }, 11 }, get_completions('vim.keymap.se')) end) it('should be able to interpolate globals', function() eq( - {{ + { { 'nvim_buf_set_lines', - }, 12 - }, + }, 12 }, get_completions('vim[MY_VAR].nvim_buf_', { - MY_VAR = "api", + MY_VAR = 'api', vim = { api = { nvim_buf_set_lines = true, nvim_win_doesnt_match = true, }, other_key = true, - } + }, }) ) end) it('should return everything if the input is of length 0', function() - eq({{"other", "vim"}, 0}, get_completions('', { vim = true, other = true })) + eq({ { 'other', 'vim' }, 0 }, get_completions('', { vim = true, other = true })) end) describe('get_parts', function() it('should return an empty list for no separators', function() - eq({{}, 1}, get_compl_parts("vim")) + eq({ {}, 1 }, get_compl_parts('vim')) end) it('just the first item before a period', function() - eq({{"vim"}, 5}, get_compl_parts("vim.ap")) + eq({ { 'vim' }, 5 }, get_compl_parts('vim.ap')) end) it('should return multiple parts just for period', function() - eq({{"vim", "api"}, 9}, get_compl_parts("vim.api.nvim_buf")) + eq({ { 'vim', 'api' }, 9 }, get_compl_parts('vim.api.nvim_buf')) end) it('should be OK with colons', function() - eq({{"vim", "api"}, 9}, get_compl_parts("vim:api.nvim_buf")) + eq({ { 'vim', 'api' }, 9 }, get_compl_parts('vim:api.nvim_buf')) end) it('should work for just one string ref', function() - eq({{"vim", "api"}, 12}, get_compl_parts("vim['api'].nvim_buf")) + eq({ { 'vim', 'api' }, 12 }, get_compl_parts("vim['api'].nvim_buf")) end) it('should work for just one string ref, with double quote', function() - eq({{"vim", "api"}, 12}, get_compl_parts('vim["api"].nvim_buf')) + eq({ { 'vim', 'api' }, 12 }, get_compl_parts('vim["api"].nvim_buf')) end) it('should allows back-to-back string ref', function() - eq({{"vim", "nested", "api"}, 22}, get_compl_parts('vim["nested"]["api"].nvim_buf')) + eq({ { 'vim', 'nested', 'api' }, 22 }, get_compl_parts('vim["nested"]["api"].nvim_buf')) end) it('should allows back-to-back string ref with spaces before and after', function() - eq({{"vim", "nested", "api"}, 25}, get_compl_parts('vim[ "nested" ]["api"].nvim_buf')) + eq({ { 'vim', 'nested', 'api' }, 25 }, get_compl_parts('vim[ "nested" ]["api"].nvim_buf')) end) it('should allow VAR style loolup', function() - eq({{"vim", {"NESTED"}, "api"}, 20}, get_compl_parts('vim[NESTED]["api"].nvim_buf')) + eq({ { 'vim', { 'NESTED' }, 'api' }, 20 }, get_compl_parts('vim[NESTED]["api"].nvim_buf')) end) end) end) diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index fca619348d..b8d0638ce5 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -3,106 +3,124 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local eq = helpers.eq -local NIL = helpers.NIL +local NIL = vim.NIL local eval = helpers.eval local feed = helpers.feed local clear = helpers.clear local matches = helpers.matches -local meths = helpers.meths +local api = helpers.api local exec_lua = helpers.exec_lua local exec_capture = helpers.exec_capture -local funcs = helpers.funcs +local fn = helpers.fn local source = helpers.source local dedent = helpers.dedent local command = helpers.command local exc_exec = helpers.exc_exec local pcall_err = helpers.pcall_err local write_file = helpers.write_file -local curbufmeths = helpers.curbufmeths local remove_trace = helpers.remove_trace before_each(clear) -describe(':lua command', function() +describe(':lua', function() it('works', function() - eq('', exec_capture( - 'lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TEST"})')) - eq({'', 'TEST'}, curbufmeths.get_lines(0, 100, false)) + eq('', exec_capture('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TEST"})')) + eq({ '', 'TEST' }, api.nvim_buf_get_lines(0, 0, 100, false)) source([[ lua << EOF vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TSET"}) EOF]]) - eq({'', 'TSET'}, curbufmeths.get_lines(0, 100, false)) + eq({ '', 'TSET' }, api.nvim_buf_get_lines(0, 0, 100, false)) source([[ lua << EOF vim.api.nvim_buf_set_lines(1, 1, 2, false, {"SETT"})]]) - eq({'', 'SETT'}, curbufmeths.get_lines(0, 100, false)) + eq({ '', 'SETT' }, api.nvim_buf_get_lines(0, 0, 100, false)) source([[ lua << EOF vim.api.nvim_buf_set_lines(1, 1, 2, false, {"ETTS"}) vim.api.nvim_buf_set_lines(1, 2, 3, false, {"TTSE"}) vim.api.nvim_buf_set_lines(1, 3, 4, false, {"STTE"}) EOF]]) - eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false)) - matches('.*Vim%(lua%):E15: Invalid expression: .*', pcall_err(source, [[ + eq({ '', 'ETTS', 'TTSE', 'STTE' }, api.nvim_buf_get_lines(0, 0, 100, false)) + matches( + '.*Vim%(lua%):E15: Invalid expression: .*', + pcall_err( + source, + [[ lua << eval EOF {} EOF - ]])) + ]] + ) + ) end) + it('throws catchable errors', function() - eq([[Vim(lua):E5107: Error loading lua [string ":lua"]:0: unexpected symbol near ')']], - pcall_err(command, 'lua ()')) - eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: TEST]], - remove_trace(exc_exec('lua error("TEST")'))) - eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: Invalid buffer id: -10]], - remove_trace(exc_exec('lua vim.api.nvim_buf_set_lines(-10, 1, 1, false, {"TEST"})'))) - eq({''}, curbufmeths.get_lines(0, 100, false)) + eq('Vim(lua):E471: Argument required', pcall_err(command, 'lua')) + eq( + [[Vim(lua):E5107: Error loading lua [string ":lua"]:0: unexpected symbol near ')']], + pcall_err(command, 'lua ()') + ) + eq( + [[Vim(lua):E5108: Error executing lua [string ":lua"]:1: TEST]], + remove_trace(exc_exec('lua error("TEST")')) + ) + eq( + [[Vim(lua):E5108: Error executing lua [string ":lua"]:1: Invalid buffer id: -10]], + remove_trace(exc_exec('lua vim.api.nvim_buf_set_lines(-10, 1, 1, false, {"TEST"})')) + ) + eq({ '' }, api.nvim_buf_get_lines(0, 0, 100, false)) end) + it('works with NULL errors', function() - eq([=[Vim(lua):E5108: Error executing lua [NULL]]=], - exc_exec('lua error(nil)')) + eq([=[Vim(lua):E5108: Error executing lua [NULL]]=], exc_exec('lua error(nil)')) end) + it('accepts embedded NLs without heredoc', function() -- Such code is usually used for `:execute 'lua' {generated_string}`: -- heredocs do not work in this case. - meths.command([[ + command([[ lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"ETTS"}) vim.api.nvim_buf_set_lines(1, 2, 3, false, {"TTSE"}) vim.api.nvim_buf_set_lines(1, 3, 4, false, {"STTE"}) ]]) - eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false)) + eq({ '', 'ETTS', 'TTSE', 'STTE' }, api.nvim_buf_get_lines(0, 0, 100, false)) end) + it('preserves global and not preserves local variables', function() eq('', exec_capture('lua gvar = 42')) eq('', exec_capture('lua local lvar = 100500')) - eq(NIL, funcs.luaeval('lvar')) - eq(42, funcs.luaeval('gvar')) + eq(NIL, fn.luaeval('lvar')) + eq(42, fn.luaeval('gvar')) end) + it('works with long strings', function() local s = ('x'):rep(100500) - eq('Vim(lua):E5107: Error loading lua [string ":lua"]:0: unfinished string near \'<eof>\'', - pcall_err(command, ('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s))) - eq({''}, curbufmeths.get_lines(0, -1, false)) + eq( + 'Vim(lua):E5107: Error loading lua [string ":lua"]:0: unfinished string near \'<eof>\'', + pcall_err(command, ('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s)) + ) + eq({ '' }, api.nvim_buf_get_lines(0, 0, -1, false)) eq('', exec_capture(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s"})'):format(s))) - eq({'', s}, curbufmeths.get_lines(0, -1, false)) + eq({ '', s }, api.nvim_buf_get_lines(0, 0, -1, false)) end) it('can show multiline error messages', function() - local screen = Screen.new(40,10) + local screen = Screen.new(40, 10) screen:attach() screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { bold = true, reverse = true }, + [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, }) feed(':lua error("fail\\nmuch error\\nsuch details")<cr>') - screen:expect{grid=[[ + screen:expect { + grid = [[ {2: }| {3:E5108: Error executing lua [string ":lua}| {3:"]:1: fail} | @@ -113,29 +131,30 @@ describe(':lua command', function() {3: [string ":lua"]:1: in main chunk}| | {4:Press ENTER or type command to continue}^ | - ]]} + ]], + } feed('<cr>') - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*8 | - ]]} - eq('E5108: Error executing lua [string ":lua"]:1: fail\nmuch error\nsuch details', remove_trace(eval('v:errmsg'))) + ]], + } + eq( + 'E5108: Error executing lua [string ":lua"]:1: fail\nmuch error\nsuch details', + remove_trace(eval('v:errmsg')) + ) - local status, err = pcall(command,'lua error("some error\\nin a\\nAPI command")') - local expected = 'Vim(lua):E5108: Error executing lua [string ":lua"]:1: some error\nin a\nAPI command' + local status, err = pcall(command, 'lua error("some error\\nin a\\nAPI command")') + local expected = + 'Vim(lua):E5108: Error executing lua [string ":lua"]:1: some error\nin a\nAPI command' eq(false, status) eq(expected, string.sub(remove_trace(err), -string.len(expected))) feed(':messages<cr>') - screen:expect{grid=[[ + screen:expect { + grid = [[ {2: }| {3:E5108: Error executing lua [string ":lua}| {3:"]:1: fail} | @@ -146,17 +165,18 @@ describe(':lua command', function() {3: [string ":lua"]:1: in main chunk}| | {4:Press ENTER or type command to continue}^ | - ]]} + ]], + } end) it('prints result of =expr', function() - exec_lua("x = 5") - eq("5", exec_capture(':lua =x')) - eq("5", exec_capture('=x')) + exec_lua('x = 5') + eq('5', exec_capture(':lua =x')) + eq('5', exec_capture('=x')) exec_lua("function x() return 'hello' end") eq('hello', exec_capture(':lua = x()')) - exec_lua("x = {a = 1, b = 2}") - eq("{\n a = 1,\n b = 2\n}", exec_capture(':lua =x')) + exec_lua('x = {a = 1, b = 2}') + eq('{\n a = 1,\n b = 2\n}', exec_capture(':lua =x')) exec_lua([[function x(success) if success then return true, "Return value" @@ -164,69 +184,127 @@ describe(':lua command', function() return false, nil, "Error message" end end]]) - eq(dedent[[ + eq( + dedent [[ true Return value]], - exec_capture(':lua =x(true)')) - eq(dedent[[ + exec_capture(':lua =x(true)') + ) + eq( + dedent [[ false nil Error message]], - exec_capture('=x(false)')) + exec_capture('=x(false)') + ) + end) + + it('with range', function() + local screen = Screen.new(40, 10) + screen:attach() + api.nvim_buf_set_lines(0, 0, 0, 0, { 'nonsense', 'function x() print "hello" end', 'x()' }) + + -- ":{range}lua" fails on invalid Lua code. + eq( + [[:{range}lua: Vim(lua):E5107: Error loading lua [string ":{range}lua"]:0: '=' expected near '<eof>']], + pcall_err(command, '1lua') + ) + + -- ":{range}lua" executes valid Lua code. + feed(':2,3lua<CR>') + screen:expect { + grid = [[ + nonsense | + function x() print "hello" end | + x() | + ^ | + {1:~ }|*5 + hello | + ]], + attr_ids = { + [1] = { foreground = Screen.colors.Blue, bold = true }, + }, + } + + -- ":{range}lua {code}" executes {code}, ignoring {range} + eq('', exec_capture('1lua gvar = 42')) + eq(42, fn.luaeval('gvar')) end) end) describe(':luado command', function() it('works', function() - curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) + api.nvim_buf_set_lines(0, 0, 1, false, { 'ABC', 'def', 'gHi' }) eq('', exec_capture('luado lines = (lines or {}) lines[#lines + 1] = {linenr, line}')) - eq({'ABC', 'def', 'gHi'}, curbufmeths.get_lines(0, -1, false)) - eq({{1, 'ABC'}, {2, 'def'}, {3, 'gHi'}}, funcs.luaeval('lines')) + eq({ 'ABC', 'def', 'gHi' }, api.nvim_buf_get_lines(0, 0, -1, false)) + eq({ { 1, 'ABC' }, { 2, 'def' }, { 3, 'gHi' } }, fn.luaeval('lines')) -- Automatic transformation of numbers eq('', exec_capture('luado return linenr')) - eq({'1', '2', '3'}, curbufmeths.get_lines(0, -1, false)) + eq({ '1', '2', '3' }, api.nvim_buf_get_lines(0, 0, -1, false)) eq('', exec_capture('luado return ("<%02x>"):format(line:byte())')) - eq({'<31>', '<32>', '<33>'}, curbufmeths.get_lines(0, -1, false)) + eq({ '<31>', '<32>', '<33>' }, api.nvim_buf_get_lines(0, 0, -1, false)) end) + it('stops processing lines when suddenly out of lines', function() - curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) + api.nvim_buf_set_lines(0, 0, 1, false, { 'ABC', 'def', 'gHi' }) eq('', exec_capture('2,$luado runs = ((runs or 0) + 1) vim.api.nvim_command("%d")')) - eq({''}, curbufmeths.get_lines(0, -1, false)) - eq(1, funcs.luaeval('runs')) - end) - it('works correctly when changing lines out of range', function() - curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) - eq('Vim(luado):E322: Line number out of range: 1 past the end', - pcall_err(command, '2,$luado vim.api.nvim_command("%d") return linenr')) - eq({''}, curbufmeths.get_lines(0, -1, false)) + eq({ '' }, api.nvim_buf_get_lines(0, 0, -1, false)) + eq(1, fn.luaeval('runs')) + + api.nvim_buf_set_lines(0, 0, -1, false, { 'one', 'two', 'three' }) + eq('', exec_capture('luado vim.api.nvim_command("%d")')) + eq({ '' }, api.nvim_buf_get_lines(0, 0, -1, false)) + + api.nvim_buf_set_lines(0, 0, -1, false, { 'one', 'two', 'three' }) + eq('', exec_capture('luado vim.api.nvim_command("1,2d")')) + eq({ 'three' }, api.nvim_buf_get_lines(0, 0, -1, false)) + + api.nvim_buf_set_lines(0, 0, -1, false, { 'one', 'two', 'three' }) + eq('', exec_capture('luado vim.api.nvim_command("2,3d"); return "REPLACED"')) + eq({ 'REPLACED' }, api.nvim_buf_get_lines(0, 0, -1, false)) + + api.nvim_buf_set_lines(0, 0, -1, false, { 'one', 'two', 'three' }) + eq('', exec_capture('2,3luado vim.api.nvim_command("1,2d"); return "REPLACED"')) + eq({ 'three' }, api.nvim_buf_get_lines(0, 0, -1, false)) end) + it('fails on errors', function() - eq([[Vim(luado):E5109: Error loading lua: [string ":luado"]:0: unexpected symbol near ')']], - pcall_err(command, 'luado ()')) - eq([[Vim(luado):E5111: Error calling lua: [string ":luado"]:0: attempt to perform arithmetic on global 'liness' (a nil value)]], - pcall_err(command, 'luado return liness + 1')) + eq( + [[Vim(luado):E5109: Error loading lua: [string ":luado"]:0: unexpected symbol near ')']], + pcall_err(command, 'luado ()') + ) + eq( + [[Vim(luado):E5111: Error calling lua: [string ":luado"]:0: attempt to perform arithmetic on global 'liness' (a nil value)]], + pcall_err(command, 'luado return liness + 1') + ) end) + it('works with NULL errors', function() - eq([=[Vim(luado):E5111: Error calling lua: [NULL]]=], - exc_exec('luado error(nil)')) + eq([=[Vim(luado):E5111: Error calling lua: [NULL]]=], exc_exec('luado error(nil)')) end) + it('fails in sandbox when needed', function() - curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) - eq('Vim(luado):E48: Not allowed in sandbox: sandbox luado runs = (runs or 0) + 1', - pcall_err(command, 'sandbox luado runs = (runs or 0) + 1')) - eq(NIL, funcs.luaeval('runs')) + api.nvim_buf_set_lines(0, 0, 1, false, { 'ABC', 'def', 'gHi' }) + eq( + 'Vim(luado):E48: Not allowed in sandbox: sandbox luado runs = (runs or 0) + 1', + pcall_err(command, 'sandbox luado runs = (runs or 0) + 1') + ) + eq(NIL, fn.luaeval('runs')) end) + it('works with long strings', function() local s = ('x'):rep(100500) - eq('Vim(luado):E5109: Error loading lua: [string ":luado"]:0: unfinished string near \'<eof>\'', - pcall_err(command, ('luado return "%s'):format(s))) - eq({''}, curbufmeths.get_lines(0, -1, false)) + eq( + 'Vim(luado):E5109: Error loading lua: [string ":luado"]:0: unfinished string near \'<eof>\'', + pcall_err(command, ('luado return "%s'):format(s)) + ) + eq({ '' }, api.nvim_buf_get_lines(0, 0, -1, false)) eq('', exec_capture(('luado return "%s"'):format(s))) - eq({s}, curbufmeths.get_lines(0, -1, false)) + eq({ s }, api.nvim_buf_get_lines(0, 0, -1, false)) end) end) @@ -238,26 +316,40 @@ describe(':luafile', function() end) it('works', function() - write_file(fname, [[ + write_file( + fname, + [[ vim.api.nvim_buf_set_lines(1, 1, 2, false, {"ETTS"}) vim.api.nvim_buf_set_lines(1, 2, 3, false, {"TTSE"}) vim.api.nvim_buf_set_lines(1, 3, 4, false, {"STTE"}) - ]]) + ]] + ) eq('', exec_capture('luafile ' .. fname)) - eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false)) + eq({ '', 'ETTS', 'TTSE', 'STTE' }, api.nvim_buf_get_lines(0, 0, 100, false)) end) it('correctly errors out', function() write_file(fname, '()') - eq(("Vim(luafile):E5112: Error while creating lua chunk: %s:1: unexpected symbol near ')'"):format(fname), - exc_exec('luafile ' .. fname)) + eq( + ("Vim(luafile):E5112: Error while creating lua chunk: %s:1: unexpected symbol near ')'"):format( + fname + ), + exc_exec('luafile ' .. fname) + ) write_file(fname, 'vimm.api.nvim_buf_set_lines(1, 1, 2, false, {"ETTS"})') - eq(("Vim(luafile):E5113: Error while calling lua chunk: %s:1: attempt to index global 'vimm' (a nil value)"):format(fname), - remove_trace(exc_exec('luafile ' .. fname))) + eq( + ("Vim(luafile):E5113: Error while calling lua chunk: %s:1: attempt to index global 'vimm' (a nil value)"):format( + fname + ), + remove_trace(exc_exec('luafile ' .. fname)) + ) end) + it('works with NULL errors', function() write_file(fname, 'error(nil)') - eq([=[Vim(luafile):E5113: Error while calling lua chunk: [NULL]]=], - exc_exec('luafile ' .. fname)) + eq( + [=[Vim(luafile):E5113: Error while calling lua chunk: [NULL]]=], + exc_exec('luafile ' .. fname) + ) end) end) diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index f061fac50a..5802925339 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -1,12 +1,12 @@ local helpers = require('test.functional.helpers')(after_each) -local NIL = helpers.NIL +local NIL = vim.NIL local command = helpers.command local clear = helpers.clear local exec_lua = helpers.exec_lua local eq = helpers.eq -local nvim = helpers.nvim local matches = helpers.matches +local api = helpers.api local pcall_err = helpers.pcall_err describe('vim.diagnostic', function() @@ -128,12 +128,20 @@ describe('vim.diagnostic', function() return vim.diagnostic.get() ]] eq(3, #result) - eq(2, exec_lua([[return #vim.tbl_filter(function(d) return d.bufnr == diagnostic_bufnr end, ...)]], result)) + eq( + 2, + exec_lua( + [[return #vim.tbl_filter(function(d) return d.bufnr == diagnostic_bufnr end, ...)]], + result + ) + ) eq('Diagnostic #1', result[1].message) end) it('removes diagnostics from the cache when a buffer is removed', function() - eq(2, exec_lua [[ + eq( + 2, + exec_lua [[ vim.api.nvim_win_set_buf(0, diagnostic_bufnr) local other_bufnr = vim.fn.bufadd('test | test') local lines = vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, -1, true) @@ -151,16 +159,23 @@ describe('vim.diagnostic', function() vim.opt_local.buflisted = true vim.cmd('bwipeout!') return #vim.diagnostic.get() - ]]) - eq(2, exec_lua [[ + ]] + ) + eq( + 2, + exec_lua [[ vim.api.nvim_set_current_buf(diagnostic_bufnr) vim.opt_local.buflisted = false return #vim.diagnostic.get() - ]]) - eq(0, exec_lua [[ + ]] + ) + eq( + 0, + exec_lua [[ vim.cmd('bwipeout!') return #vim.diagnostic.get() - ]]) + ]] + ) end) it('removes diagnostic from stale cache on reset', function() @@ -194,37 +209,48 @@ describe('vim.diagnostic', function() end) it('resolves buffer number 0 to the current buffer', function() - eq(2, exec_lua [[ + eq( + 2, + exec_lua [[ vim.api.nvim_set_current_buf(diagnostic_bufnr) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), make_error('Diagnostic #2', 2, 1, 2, 1), }) return #vim.diagnostic.get(0) - ]]) + ]] + ) end) it('saves and count a single error', function() - eq(1, exec_lua [[ + eq( + 1, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), }) return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns) - ]]) + ]] + ) end) it('saves and count multiple errors', function() - eq(2, exec_lua [[ + eq( + 2, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), make_error('Diagnostic #2', 2, 1, 2, 1), }) return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns) - ]]) + ]] + ) end) it('saves and count from multiple namespaces', function() - eq({1, 1, 2}, exec_lua [[ + eq( + { 1, 1, 2 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic From Server 1', 1, 1, 1, 1), }) @@ -239,11 +265,14 @@ describe('vim.diagnostic', function() -- All namespaces count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR), } - ]]) + ]] + ) end) it('saves and count from multiple namespaces with respect to severity', function() - eq({3, 0, 3}, exec_lua [[ + eq( + { 3, 0, 3 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), make_error('Diagnostic From Server 1:2', 2, 2, 2, 2), @@ -260,7 +289,8 @@ describe('vim.diagnostic', function() -- All namespaces count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR), } - ]]) + ]] + ) end) it('handles one namespace clearing highlights while the other still has highlights', function() @@ -269,8 +299,10 @@ describe('vim.diagnostic', function() -- 1 Warning (2) + 1 Warning (1) -- 2 highlights and 2 underlines (since error) -- 1 highlight + 1 underline - local all_highlights = {1, 1, 2, 4, 2} - eq(all_highlights, exec_lua [[ + local all_highlights = { 1, 1, 2, 4, 2 } + eq( + all_highlights, + exec_lua [[ local ns_1_diags = { make_error("Error 1", 1, 1, 1, 5), make_warning("Warning on Server 1", 2, 1, 2, 3), @@ -289,10 +321,13 @@ describe('vim.diagnostic', function() count_extmarks(diagnostic_bufnr, diagnostic_ns), count_extmarks(diagnostic_bufnr, other_ns), } - ]]) + ]] + ) -- Clear diagnostics from namespace 1, and make sure we have the right amount of stuff for namespace 2 - eq({1, 1, 2, 0, 2}, exec_lua [[ + eq( + { 1, 1, 2, 0, 2 }, + exec_lua [[ vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns) return { count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), @@ -301,10 +336,13 @@ describe('vim.diagnostic', function() count_extmarks(diagnostic_bufnr, diagnostic_ns), count_extmarks(diagnostic_bufnr, other_ns), } - ]]) + ]] + ) -- Show diagnostics from namespace 1 again - eq(all_highlights, exec_lua([[ + eq( + all_highlights, + exec_lua([[ vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns) return { count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), @@ -313,11 +351,14 @@ describe('vim.diagnostic', function() count_extmarks(diagnostic_bufnr, diagnostic_ns), count_extmarks(diagnostic_bufnr, other_ns), } - ]])) + ]]) + ) end) it('does not display diagnostics when disabled', function() - eq({0, 2}, exec_lua [[ + eq( + { 0, 2 }, + exec_lua [[ local ns_1_diags = { make_error("Error 1", 1, 1, 1, 5), make_warning("Warning on Server 1", 2, 1, 2, 3), @@ -335,9 +376,12 @@ describe('vim.diagnostic', function() count_extmarks(diagnostic_bufnr, diagnostic_ns), count_extmarks(diagnostic_bufnr, other_ns), } - ]]) + ]] + ) - eq({4, 0}, exec_lua [[ + eq( + { 4, 0 }, + exec_lua [[ vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns) vim.diagnostic.disable(diagnostic_bufnr, other_ns) @@ -345,7 +389,8 @@ describe('vim.diagnostic', function() count_extmarks(diagnostic_bufnr, diagnostic_ns), count_extmarks(diagnostic_bufnr, other_ns), } - ]]) + ]] + ) end) describe('show() and hide()', function() @@ -660,8 +705,10 @@ describe('vim.diagnostic', function() -- 1 Warning (2) + 1 Warning (1) -- 2 highlights and 2 underlines (since error) -- 1 highlight + 1 underline - local all_highlights = {1, 1, 2, 4, 2} - eq(all_highlights, exec_lua [[ + local all_highlights = { 1, 1, 2, 4, 2 } + eq( + all_highlights, + exec_lua [[ local ns_1_diags = { make_error("Error 1", 1, 1, 1, 5), make_warning("Warning on Server 1", 2, 1, 2, 3), @@ -680,13 +727,16 @@ describe('vim.diagnostic', function() count_extmarks(diagnostic_bufnr, diagnostic_ns), count_extmarks(diagnostic_bufnr, other_ns), } - ]]) + ]] + ) -- Reset diagnostics from namespace 1 exec_lua([[ vim.diagnostic.reset(diagnostic_ns) ]]) -- Make sure we have the right diagnostic count - eq({0, 1, 1, 0, 2} , exec_lua [[ + eq( + { 0, 1, 1, 0, 2 }, + exec_lua [[ local diagnostic_count = {} vim.wait(100, function () diagnostic_count = { count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), @@ -696,13 +746,16 @@ describe('vim.diagnostic', function() count_extmarks(diagnostic_bufnr, other_ns), } end ) return diagnostic_count - ]]) + ]] + ) -- Reset diagnostics from namespace 2 exec_lua([[ vim.diagnostic.reset(other_ns) ]]) -- Make sure we have the right diagnostic count - eq({0, 0, 0, 0, 0}, exec_lua [[ + eq( + { 0, 0, 0, 0, 0 }, + exec_lua [[ local diagnostic_count = {} vim.wait(100, function () diagnostic_count = { count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns), @@ -712,8 +765,8 @@ describe('vim.diagnostic', function() count_extmarks(diagnostic_bufnr, other_ns), } end ) return diagnostic_count - ]]) - + ]] + ) end) it("doesn't error after bwipeout called on buffer", function() @@ -728,17 +781,22 @@ describe('vim.diagnostic', function() describe('get_next_pos()', function() it('can find the next pos with only one namespace', function() - eq({1, 1}, exec_lua [[ + eq( + { 1, 1 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) return vim.diagnostic.get_next_pos() - ]]) + ]] + ) end) it('can find next pos with two errors', function() - eq({4, 4}, exec_lua [[ + eq( + { 4, 4 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), make_error('Diagnostic #2', 4, 4, 4, 4), @@ -746,44 +804,56 @@ describe('vim.diagnostic', function() vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {3, 1}) return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]]) + ]] + ) end) it('can cycle when position is past error', function() - eq({1, 1}, exec_lua [[ + eq( + { 1, 1 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {3, 1}) return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]]) + ]] + ) end) it('will not cycle when wrap is off', function() - eq(false, exec_lua [[ + eq( + false, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {3, 1}) return vim.diagnostic.get_next_pos { namespace = diagnostic_ns, wrap = false } - ]]) + ]] + ) end) it('can cycle even from the last line', function() - eq({4, 4}, exec_lua [[ + eq( + { 4, 4 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #2', 4, 4, 4, 4), }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {vim.api.nvim_buf_line_count(0), 1}) return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]]) + ]] + ) end) it('works with diagnostics past the end of the line #16349', function() - eq({4, 0}, exec_lua [[ + eq( + { 4, 0 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 3, 9001, 3, 9001), make_error('Diagnostic #2', 4, 0, 4, 0), @@ -792,11 +862,14 @@ describe('vim.diagnostic', function() vim.api.nvim_win_set_cursor(0, {1, 1}) vim.diagnostic.goto_next { float = false } return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]]) + ]] + ) end) it('works with diagnostics before the start of the line', function() - eq({4, 0}, exec_lua [[ + eq( + { 4, 0 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 3, 9001, 3, 9001), make_error('Diagnostic #2', 4, -1, 4, -1), @@ -805,24 +878,30 @@ describe('vim.diagnostic', function() vim.api.nvim_win_set_cursor(0, {1, 1}) vim.diagnostic.goto_next { float = false } return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]]) -end) + ]] + ) + end) end) describe('get_prev_pos()', function() it('can find the prev pos with only one namespace', function() - eq({1, 1}, exec_lua [[ + eq( + { 1, 1 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {3, 1}) return vim.diagnostic.get_prev_pos() - ]]) + ]] + ) end) it('can find prev pos with two errors', function() - eq({1, 1}, exec_lua [[ + eq( + { 1, 1 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), make_error('Diagnostic #2', 4, 4, 4, 4), @@ -830,29 +909,36 @@ end) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {3, 1}) return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]]) + ]] + ) end) it('can cycle when position is past error', function() - eq({4, 4}, exec_lua [[ + eq( + { 4, 4 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #2', 4, 4, 4, 4), }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {3, 1}) return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]]) + ]] + ) end) it('respects wrap parameter', function() - eq(false, exec_lua [[ + eq( + false, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #2', 4, 4, 4, 4), }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {3, 1}) return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns, wrap = false} - ]]) + ]] + ) end) end) @@ -862,18 +948,23 @@ end) end) it('returns all diagnostics when no severity is supplied', function() - eq(2, exec_lua [[ + eq( + 2, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error("Error 1", 1, 1, 1, 5), make_warning("Warning on Server 1", 1, 1, 2, 3), }) return #vim.diagnostic.get(diagnostic_bufnr) - ]]) + ]] + ) end) it('returns only requested diagnostics when severity range is supplied', function() - eq({2, 3, 2}, exec_lua [[ + eq( + { 2, 3, 2 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error("Error 1", 1, 1, 1, 5), make_warning("Warning on Server 1", 1, 1, 2, 3), @@ -891,11 +982,14 @@ end) } }), } - ]]) + ]] + ) end) it('returns only requested diagnostics when severities are supplied', function() - eq({1, 1, 2}, exec_lua [[ + eq( + { 1, 1, 2 }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error("Error 1", 1, 1, 1, 5), make_warning("Warning on Server 1", 1, 1, 2, 3), @@ -913,11 +1007,14 @@ end) } }), } - ]]) + ]] + ) end) it('allows filtering by line', function() - eq(1, exec_lua [[ + eq( + 1, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error("Error 1", 1, 1, 1, 5), make_warning("Warning on Server 1", 1, 1, 2, 3), @@ -926,13 +1023,132 @@ end) }) return #vim.diagnostic.get(diagnostic_bufnr, {lnum = 2}) - ]]) + ]] + ) + end) + end) + + describe('count', function() + it('returns actually present severity counts', function() + eq( + exec_lua [[return { + [vim.diagnostic.severity.ERROR] = 4, + [vim.diagnostic.severity.WARN] = 3, + [vim.diagnostic.severity.INFO] = 2, + [vim.diagnostic.severity.HINT] = 1, + }]], + exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error("Error 1", 1, 1, 1, 2), + make_error("Error 2", 1, 3, 1, 4), + make_error("Error 3", 1, 5, 1, 6), + make_error("Error 4", 1, 7, 1, 8), + make_warning("Warning 1", 2, 1, 2, 2), + make_warning("Warning 2", 2, 3, 2, 4), + make_warning("Warning 3", 2, 5, 2, 6), + make_info("Info 1", 3, 1, 3, 2), + make_info("Info 2", 3, 3, 3, 4), + make_hint("Hint 1", 4, 1, 4, 2), + }) + return vim.diagnostic.count(diagnostic_bufnr) + ]] + ) + eq( + exec_lua [[return { + [vim.diagnostic.severity.ERROR] = 2, + [vim.diagnostic.severity.INFO] = 1, + }]], + exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error("Error 1", 1, 1, 1, 2), + make_error("Error 2", 1, 3, 1, 4), + make_info("Info 1", 3, 1, 3, 2), + }) + return vim.diagnostic.count(diagnostic_bufnr) + ]] + ) + end) + + it('returns only requested diagnostics count when severity range is supplied', function() + eq( + exec_lua [[return { + { [vim.diagnostic.severity.ERROR] = 1, [vim.diagnostic.severity.WARN] = 1 }, + { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1, [vim.diagnostic.severity.HINT] = 1 }, + { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, + }]], + exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error("Error 1", 1, 1, 1, 5), + make_warning("Warning on Server 1", 1, 1, 2, 3), + make_info("Ignored information", 1, 1, 2, 3), + make_hint("Here's a hint", 1, 1, 2, 3), + }) + + return { + vim.diagnostic.count(diagnostic_bufnr, { severity = {min=vim.diagnostic.severity.WARN} }), + vim.diagnostic.count(diagnostic_bufnr, { severity = {max=vim.diagnostic.severity.WARN} }), + vim.diagnostic.count(diagnostic_bufnr, { + severity = { + min=vim.diagnostic.severity.INFO, + max=vim.diagnostic.severity.WARN, + } + }), + } + ]] + ) + end) + + it('returns only requested diagnostics when severities are supplied', function() + eq( + exec_lua [[return { + { [vim.diagnostic.severity.WARN] = 1 }, + { [vim.diagnostic.severity.ERROR] = 1 }, + { [vim.diagnostic.severity.WARN] = 1, [vim.diagnostic.severity.INFO] = 1 }, + }]], + exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error("Error 1", 1, 1, 1, 5), + make_warning("Warning on Server 1", 1, 1, 2, 3), + make_info("Ignored information", 1, 1, 2, 3), + make_hint("Here's a hint", 1, 1, 2, 3), + }) + + return { + vim.diagnostic.count(diagnostic_bufnr, { severity = {vim.diagnostic.severity.WARN} }), + vim.diagnostic.count(diagnostic_bufnr, { severity = {vim.diagnostic.severity.ERROR} }), + vim.diagnostic.count(diagnostic_bufnr, { + severity = { + vim.diagnostic.severity.INFO, + vim.diagnostic.severity.WARN, + } + }), + } + ]] + ) + end) + + it('allows filtering by line', function() + eq( + exec_lua [[return { [vim.diagnostic.severity.ERROR] = 1 }]], + exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error("Error 1", 1, 1, 1, 5), + make_warning("Warning on Server 1", 1, 1, 2, 3), + make_info("Ignored information", 1, 1, 2, 3), + make_error("Error On Other Line", 2, 1, 1, 5), + }) + + return vim.diagnostic.count(diagnostic_bufnr, {lnum = 2}) + ]] + ) end) end) describe('config()', function() it('works with global, namespace, and ephemeral options', function() - eq(1, exec_lua [[ + eq( + 1, + exec_lua [[ vim.diagnostic.config({ virtual_text = false, }) @@ -947,9 +1163,12 @@ end) }) return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]]) + ]] + ) - eq(1, exec_lua [[ + eq( + 1, + exec_lua [[ vim.diagnostic.config({ virtual_text = false, }) @@ -964,9 +1183,12 @@ end) }, {virtual_text = true}) return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]]) + ]] + ) - eq(0, exec_lua [[ + eq( + 0, + exec_lua [[ vim.diagnostic.config({ virtual_text = false, }) @@ -981,9 +1203,12 @@ end) }, {virtual_text = true}) return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]]) + ]] + ) - eq(1, exec_lua [[ + eq( + 1, + exec_lua [[ vim.diagnostic.config({ virtual_text = false, }) @@ -1000,7 +1225,8 @@ end) }) return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]]) + ]] + ) end) it('can use functions for config values', function() @@ -1013,7 +1239,10 @@ end) }) ]] - eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) + eq( + 1, + exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + ) eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) -- Now, don't enable virtual text. @@ -1024,13 +1253,17 @@ end) }, diagnostic_ns) ]] - eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) + eq( + 1, + exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + ) eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) end) it('allows filtering by severity', function() local get_extmark_count_with_severity = function(min_severity) - return exec_lua([[ + return exec_lua( + [[ vim.diagnostic.config({ underline = false, virtual_text = { @@ -1043,15 +1276,17 @@ end) }) return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]], min_severity) + ]], + min_severity + ) end -- No messages with Error or higher - eq(0, get_extmark_count_with_severity("ERROR")) + eq(0, get_extmark_count_with_severity('ERROR')) -- But now we don't filter it - eq(1, get_extmark_count_with_severity("WARN")) - eq(1, get_extmark_count_with_severity("HINT")) + eq(1, get_extmark_count_with_severity('WARN')) + eq(1, get_extmark_count_with_severity('HINT')) end) it('allows sorting by severity', function() @@ -1080,9 +1315,19 @@ end) table.insert(virt_texts, (string.gsub(virt_text[i][2], "DiagnosticVirtualText", ""))) end + local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local sign_ns = ns.user_data.sign_ns local signs = {} - for _, v in ipairs(vim.fn.sign_getplaced(diagnostic_bufnr, {group = "*"})[1].signs) do - table.insert(signs, (string.gsub(v.name, "DiagnosticSign", ""))) + local all_signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type = 'sign', details = true}) + table.sort(all_signs, function(a, b) + return a[1] > b[1] + end) + + for _, v in ipairs(all_signs) do + local s = v[4].sign_hl_group:gsub('DiagnosticSign', "") + if not vim.tbl_contains(signs, s) then + signs[#signs + 1] = s + end end return {virt_texts, signs} @@ -1093,16 +1338,16 @@ end) -- Virt texts are defined lowest priority to highest, signs from -- highest to lowest - eq({'Warn', 'Error', 'Info'}, result[1]) - eq({'Info', 'Error', 'Warn'}, result[2]) + eq({ 'Warn', 'Error', 'Info' }, result[1]) + eq({ 'Info', 'Error', 'Warn' }, result[2]) result = exec_lua [[return get_virt_text_and_signs(true)]] - eq({'Info', 'Warn', 'Error'}, result[1]) - eq({'Error', 'Warn', 'Info'}, result[2]) + eq({ 'Info', 'Warn', 'Error' }, result[1]) + eq({ 'Error', 'Warn', 'Info' }, result[2]) result = exec_lua [[return get_virt_text_and_signs({ reverse = true })]] - eq({'Error', 'Warn', 'Info'}, result[1]) - eq({'Info', 'Warn', 'Error'}, result[2]) + eq({ 'Error', 'Warn', 'Info' }, result[1]) + eq({ 'Info', 'Warn', 'Error' }, result[2]) end) it('can show diagnostic sources in virtual text', function() @@ -1185,8 +1430,8 @@ end) local extmarks = get_virt_text_extmarks(diagnostic_ns) return {extmarks[1][4].virt_text, extmarks[2][4].virt_text} ]] - eq(" 👀 Warning", result[1][3][1]) - eq(" 🔥 Error", result[2][3][1]) + eq(' 👀 Warning', result[1][3][1]) + eq(' 🔥 Error', result[2][3][1]) end) it('includes source for formatted diagnostics', function() @@ -1213,12 +1458,14 @@ end) local extmarks = get_virt_text_extmarks(diagnostic_ns) return {extmarks[1][4].virt_text, extmarks[2][4].virt_text} ]] - eq(" some_linter: 👀 Warning", result[1][3][1]) - eq(" another_linter: 🔥 Error", result[2][3][1]) + eq(' some_linter: 👀 Warning', result[1][3][1]) + eq(' another_linter: 🔥 Error', result[2][3][1]) end) it('can add a prefix to virtual text', function() - eq('E Some error', exec_lua [[ + eq( + 'E Some error', + exec_lua [[ local diagnostics = { make_error('Some error', 0, 0, 0, 0), } @@ -1235,9 +1482,12 @@ end) local prefix = extmarks[1][4].virt_text[2][1] local message = extmarks[1][4].virt_text[3][1] return prefix .. message - ]]) + ]] + ) - eq('[(1/1) err-code] Some error', exec_lua [[ + eq( + '[(1/1) err-code] Some error', + exec_lua [[ local diagnostics = { make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), } @@ -1254,11 +1504,14 @@ end) local prefix = extmarks[1][4].virt_text[2][1] local message = extmarks[1][4].virt_text[3][1] return prefix .. message - ]]) + ]] + ) end) it('can add a suffix to virtual text', function() - eq(' Some error ✘', exec_lua [[ + eq( + ' Some error ✘', + exec_lua [[ local diagnostics = { make_error('Some error', 0, 0, 0, 0), } @@ -1274,9 +1527,12 @@ end) local extmarks = get_virt_text_extmarks(diagnostic_ns) local virt_text = extmarks[1][4].virt_text[3][1] return virt_text - ]]) + ]] + ) - eq(' Some error [err-code]', exec_lua [[ + eq( + ' Some error [err-code]', + exec_lua [[ local diagnostics = { make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), } @@ -1292,20 +1548,23 @@ end) local extmarks = get_virt_text_extmarks(diagnostic_ns) local virt_text = extmarks[1][4].virt_text[3][1] return virt_text - ]]) + ]] + ) end) end) describe('set()', function() it('validates its arguments', function() - matches("expected a list of diagnostics", - pcall_err(exec_lua, [[vim.diagnostic.set(1, 0, {lnum = 1, col = 2})]])) + matches( + 'expected a list of diagnostics', + pcall_err(exec_lua, [[vim.diagnostic.set(1, 0, {lnum = 1, col = 2})]]) + ) end) it('can perform updates after insert_leave', function() exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] - nvim("input", "o") - eq({mode='i', blocking=false}, nvim("get_mode")) + api.nvim_input('o') + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics exec_lua [[ @@ -1318,21 +1577,27 @@ end) ]] -- No diagnostics displayed yet. - eq({mode='i', blocking=false}, nvim("get_mode")) - eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) + eq( + 1, + exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + ) eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) - nvim("input", "<esc>") - eq({mode='n', blocking=false}, nvim("get_mode")) + api.nvim_input('<esc>') + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) - eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) + eq( + 1, + exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + ) eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) end) it('does not perform updates when not needed', function() exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] - nvim("input", "o") - eq({mode='i', blocking=false}, nvim("get_mode")) + api.nvim_input('o') + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics exec_lua [[ @@ -1354,24 +1619,30 @@ end) ]] -- No diagnostics displayed yet. - eq({mode='i', blocking=false}, nvim("get_mode")) - eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) + eq( + 1, + exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + ) eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) eq(0, exec_lua [[return DisplayCount]]) - nvim("input", "<esc>") - eq({mode='n', blocking=false}, nvim("get_mode")) + api.nvim_input('<esc>') + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) - eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) + eq( + 1, + exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + ) eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) eq(1, exec_lua [[return DisplayCount]]) -- Go in and out of insert mode one more time. - nvim("input", "o") - eq({mode='i', blocking=false}, nvim("get_mode")) + api.nvim_input('o') + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) - nvim("input", "<esc>") - eq({mode='n', blocking=false}, nvim("get_mode")) + api.nvim_input('<esc>') + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) -- Should not have set the virtual text again. eq(1, exec_lua [[return DisplayCount]]) @@ -1379,8 +1650,8 @@ end) it('never sets virtual text, in combination with insert leave', function() exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] - nvim("input", "o") - eq({mode='i', blocking=false}, nvim("get_mode")) + api.nvim_input('o') + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics exec_lua [[ @@ -1403,24 +1674,30 @@ end) ]] -- No diagnostics displayed yet. - eq({mode='i', blocking=false}, nvim("get_mode")) - eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) + eq( + 1, + exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + ) eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) eq(0, exec_lua [[return DisplayCount]]) - nvim("input", "<esc>") - eq({mode='n', blocking=false}, nvim("get_mode")) + api.nvim_input('<esc>') + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) - eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) + eq( + 1, + exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + ) eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) eq(0, exec_lua [[return DisplayCount]]) -- Go in and out of insert mode one more time. - nvim("input", "o") - eq({mode='i', blocking=false}, nvim("get_mode")) + api.nvim_input('o') + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) - nvim("input", "<esc>") - eq({mode='n', blocking=false}, nvim("get_mode")) + api.nvim_input('<esc>') + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) -- Should not have set the virtual text still. eq(0, exec_lua [[return DisplayCount]]) @@ -1428,8 +1705,8 @@ end) it('can perform updates while in insert mode, if desired', function() exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]] - nvim("input", "o") - eq({mode='i', blocking=false}, nvim("get_mode")) + api.nvim_input('o') + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) -- Save the diagnostics exec_lua [[ @@ -1443,49 +1720,126 @@ end) ]] -- Diagnostics are displayed, because the user wanted them that way! - eq({mode='i', blocking=false}, nvim("get_mode")) - eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) + eq( + 1, + exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + ) eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) - nvim("input", "<esc>") - eq({mode='n', blocking=false}, nvim("get_mode")) + api.nvim_input('<esc>') + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) - eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]]) + eq( + 1, + exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]] + ) eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]]) end) it('can set diagnostics without displaying them', function() - eq(0, exec_lua [[ + eq( + 0, + exec_lua [[ vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), }) return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]]) + ]] + ) - eq(2, exec_lua [[ + eq( + 2, + exec_lua [[ vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns) return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]]) + ]] + ) end) it('can set display options', function() - eq(0, exec_lua [[ + eq( + 0, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), }, { virtual_text = false, underline = false }) return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]]) + ]] + ) - eq(1, exec_lua [[ + eq( + 1, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic From Server 1:1', 1, 1, 1, 1), }, { virtual_text = true, underline = false }) return count_extmarks(diagnostic_bufnr, diagnostic_ns) - ]]) + ]] + ) end) - it('sets signs', function() + it('sets and clears signs #26193 #26555', function() + do + local result = exec_lua [[ + vim.diagnostic.config({ + signs = true, + }) + + local diagnostics = { + make_error('Error', 1, 1, 1, 2), + make_warning('Warning', 3, 3, 3, 3), + } + + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) + + local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local sign_ns = ns.user_data.sign_ns + + local signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true}) + local result = {} + for _, s in ipairs(signs) do + result[#result + 1] = { lnum = s[2] + 1, name = s[4].sign_hl_group } + end + return result + ]] + + eq({ 2, 'DiagnosticSignError' }, { result[1].lnum, result[1].name }) + eq({ 4, 'DiagnosticSignWarn' }, { result[2].lnum, result[2].name }) + end + + do + local result = exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {}) + + local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local sign_ns = ns.user_data.sign_ns + + return vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true}) + ]] + + eq({}, result) + end + end) + + it('respects legacy signs placed with :sign define or sign_define #26618', function() + -- Legacy signs for diagnostics were deprecated in 0.10 and will be removed in 0.12 + eq(0, helpers.fn.has('nvim-0.12')) + + helpers.command( + 'sign define DiagnosticSignError text= texthl= linehl=ErrorMsg numhl=ErrorMsg' + ) + helpers.command( + 'sign define DiagnosticSignWarn text= texthl= linehl=WarningMsg numhl=WarningMsg' + ) + helpers.command( + 'sign define DiagnosticSignInfo text= texthl= linehl=Underlined numhl=Underlined' + ) + helpers.command( + 'sign define DiagnosticSignHint text= texthl= linehl=Underlined numhl=Underlined' + ) + local result = exec_lua [[ vim.diagnostic.config({ signs = true, @@ -1498,17 +1852,46 @@ end) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics) - return vim.fn.sign_getplaced(diagnostic_bufnr, {group = '*'})[1].signs + local ns = vim.diagnostic.get_namespace(diagnostic_ns) + local sign_ns = ns.user_data.sign_ns + + local signs = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, sign_ns, 0, -1, {type ='sign', details = true}) + local result = {} + for _, s in ipairs(signs) do + result[#result + 1] = { + lnum = s[2] + 1, + name = s[4].sign_hl_group, + text = s[4].sign_text or '', + numhl = s[4].number_hl_group, + linehl = s[4].line_hl_group, + } + end + return result ]] - eq({2, 'DiagnosticSignError'}, {result[1].lnum, result[1].name}) - eq({4, 'DiagnosticSignWarn'}, {result[2].lnum, result[2].name}) + eq({ + lnum = 2, + name = 'DiagnosticSignError', + text = '', + numhl = 'ErrorMsg', + linehl = 'ErrorMsg', + }, result[1]) + + eq({ + lnum = 4, + name = 'DiagnosticSignWarn', + text = '', + numhl = 'WarningMsg', + linehl = 'WarningMsg', + }, result[2]) end) end) describe('open_float()', function() it('can display a header', function() - eq({'Diagnostics:', '1. Syntax error'}, exec_lua [[ + eq( + { 'Diagnostics:', '1. Syntax error' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), } @@ -1518,9 +1901,12 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq({"We're no strangers to love...", '1. Syntax error'}, exec_lua [[ + eq( + { "We're no strangers to love...", '1. Syntax error' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), } @@ -1530,9 +1916,12 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq({'You know the rules', '1. Syntax error'}, exec_lua [[ + eq( + { 'You know the rules', '1. Syntax error' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), } @@ -1542,11 +1931,14 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) end) it('can show diagnostics from the whole buffer', function() - eq({'1. Syntax error', '2. Some warning'}, exec_lua [[ + eq( + { '1. Syntax error', '2. Some warning' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), make_warning("Some warning", 1, 1, 1, 3), @@ -1557,12 +1949,15 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) end) it('can show diagnostics from a single line', function() -- Using cursor position - eq({'1. Some warning'}, exec_lua [[ + eq( + { '1. Some warning' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), make_warning("Some warning", 1, 1, 1, 3), @@ -1574,10 +1969,13 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) -- With specified position - eq({'1. Some warning'}, exec_lua [[ + eq( + { '1. Some warning' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), make_warning("Some warning", 1, 1, 1, 3), @@ -1589,12 +1987,15 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) end) it('can show diagnostics from a specific position', function() -- Using cursor position - eq({'Syntax error'}, exec_lua [[ + eq( + { 'Syntax error' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 1, 1, 1, 2), make_warning("Some warning", 1, 3, 1, 4), @@ -1606,10 +2007,13 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) -- With specified position - eq({'Some warning'}, exec_lua [[ + eq( + { 'Some warning' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 1, 1, 1, 2), make_warning("Some warning", 1, 3, 1, 4), @@ -1621,10 +2025,13 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) -- With column position past the end of the line. #16062 - eq({'Syntax error'}, exec_lua [[ + eq( + { 'Syntax error' }, + exec_lua [[ local first_line_len = #vim.api.nvim_buf_get_lines(diagnostic_bufnr, 0, 1, true)[1] local diagnostics = { make_error("Syntax error", 0, first_line_len + 1, 1, 0), @@ -1636,14 +2043,19 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) - end) - - it('creates floating window and returns float bufnr and winnr if current line contains diagnostics', function() - -- Two lines: - -- Diagnostic: - -- 1. <msg> - eq(2, exec_lua [[ + ]] + ) + end) + + it( + 'creates floating window and returns float bufnr and winnr if current line contains diagnostics', + function() + -- Two lines: + -- Diagnostic: + -- 1. <msg> + eq( + 2, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), } @@ -1653,11 +2065,15 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines - ]]) - end) + ]] + ) + end + ) it('only reports diagnostics from the current buffer when bufnr is omitted #15710', function() - eq(2, exec_lua [[ + eq( + 2, + exec_lua [[ local other_bufnr = vim.api.nvim_create_buf(true, false) local buf_1_diagnostics = { make_error("Syntax error", 0, 1, 0, 3), @@ -1672,11 +2088,14 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines - ]]) + ]] + ) end) it('allows filtering by namespace', function() - eq(2, exec_lua [[ + eq( + 2, + exec_lua [[ local ns_1_diagnostics = { make_error("Syntax error", 0, 1, 0, 3), } @@ -1690,13 +2109,18 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines - ]]) + ]] + ) end) - it('creates floating window and returns float bufnr and winnr without header, if requested', function() - -- One line (since no header): - -- 1. <msg> - eq(1, exec_lua [[ + it( + 'creates floating window and returns float bufnr and winnr without header, if requested', + function() + -- One line (since no header): + -- 1. <msg> + eq( + 1, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), } @@ -1706,11 +2130,15 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines - ]]) - end) + ]] + ) + end + ) it('clamps diagnostic line numbers within the valid range', function() - eq(1, exec_lua [[ + eq( + 1, + exec_lua [[ local diagnostics = { make_error("Syntax error", 6, 0, 6, 0), } @@ -1720,13 +2148,16 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines - ]]) + ]] + ) end) it('can show diagnostic source', function() exec_lua [[vim.api.nvim_win_set_buf(0, diagnostic_bufnr)]] - eq({"1. Syntax error"}, exec_lua [[ + eq( + { '1. Syntax error' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3, "source x"), } @@ -1738,9 +2169,12 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq({"1. source x: Syntax error"}, exec_lua [[ + eq( + { '1. source x: Syntax error' }, + exec_lua [[ local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false, source = "always", @@ -1748,9 +2182,12 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq({"1. source x: Syntax error", "2. source y: Another error"}, exec_lua [[ + eq( + { '1. source x: Syntax error', '2. source y: Another error' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3, "source x"), make_error("Another error", 0, 1, 0, 3, "source y"), @@ -1763,13 +2200,16 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) end) it('respects severity_sort', function() exec_lua [[vim.api.nvim_win_set_buf(0, diagnostic_bufnr)]] - eq({"1. Syntax error", "2. Info", "3. Error", "4. Warning"}, exec_lua [[ + eq( + { '1. Syntax error', '2. Info', '3. Error', '4. Warning' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), make_info('Info', 0, 3, 0, 4), @@ -1785,28 +2225,36 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq({"1. Syntax error", "2. Error", "3. Warning", "4. Info"}, exec_lua [[ + eq( + { '1. Syntax error', '2. Error', '3. Warning', '4. Info' }, + exec_lua [[ vim.diagnostic.config({severity_sort = true}) local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false }) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq({"1. Info", "2. Warning", "3. Error", "4. Syntax error"}, exec_lua [[ + eq( + { '1. Info', '2. Warning', '3. Error', '4. Syntax error' }, + exec_lua [[ vim.diagnostic.config({severity_sort = { reverse = true } }) local float_bufnr, winnr = vim.diagnostic.open_float(diagnostic_bufnr, { header = false }) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) end) it('can filter by severity', function() local count_diagnostics_with_severity = function(min_severity, max_severity) - return exec_lua([[ + return exec_lua( + [[ local min_severity, max_severity = ... vim.diagnostic.config({ float = { @@ -1829,19 +2277,24 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return #lines - ]], min_severity, max_severity) + ]], + min_severity, + max_severity + ) end - eq(2, count_diagnostics_with_severity("ERROR")) - eq(3, count_diagnostics_with_severity("WARN")) - eq(1, count_diagnostics_with_severity("WARN", "WARN")) - eq(4, count_diagnostics_with_severity("HINT")) - eq(0, count_diagnostics_with_severity("HINT", "HINT")) + eq(2, count_diagnostics_with_severity('ERROR')) + eq(3, count_diagnostics_with_severity('WARN')) + eq(1, count_diagnostics_with_severity('WARN', 'WARN')) + eq(4, count_diagnostics_with_severity('HINT')) + eq(0, count_diagnostics_with_severity('HINT', 'HINT')) end) it('can add a prefix to diagnostics', function() -- Default is to add a number - eq({'1. Syntax error', '2. Some warning'}, exec_lua [[ + eq( + { '1. Syntax error', '2. Some warning' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), make_warning("Some warning", 1, 1, 1, 3), @@ -1852,9 +2305,12 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq({'Syntax error', 'Some warning'}, exec_lua [[ + eq( + { 'Syntax error', 'Some warning' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), make_warning("Some warning", 1, 1, 1, 3), @@ -1865,9 +2321,12 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq({'1. Syntax error', '2. Some warning'}, exec_lua [[ + eq( + { '1. Syntax error', '2. Some warning' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), make_warning("Some warning", 0, 1, 0, 3), @@ -1887,9 +2346,12 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq({'Syntax error'}, exec_lua [[ + eq( + { 'Syntax error' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), } @@ -1908,15 +2370,20 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq(".../diagnostic.lua:0: prefix: expected string|table|function, got number", - pcall_err(exec_lua, [[ vim.diagnostic.open_float({ prefix = 42 }) ]])) + eq( + '.../diagnostic.lua:0: prefix: expected string|table|function, got number', + pcall_err(exec_lua, [[ vim.diagnostic.open_float({ prefix = 42 }) ]]) + ) end) it('can add a suffix to diagnostics', function() -- Default is to render the diagnostic error code - eq({'1. Syntax error [code-x]', '2. Some warning [code-y]'}, exec_lua [[ + eq( + { '1. Syntax error [code-x]', '2. Some warning [code-y]' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3, nil, "code-x"), make_warning("Some warning", 1, 1, 1, 3, nil, "code-y"), @@ -1927,9 +2394,12 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq({'1. Syntax error', '2. Some warning'}, exec_lua [[ + eq( + { '1. Syntax error', '2. Some warning' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3, nil, "code-x"), make_warning("Some warning", 1, 1, 1, 3, nil, "code-y"), @@ -1940,10 +2410,13 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) -- Suffix is rendered on the last line of a multiline diagnostic - eq({'1. Syntax error', ' More context [code-x]'}, exec_lua [[ + eq( + { '1. Syntax error', ' More context [code-x]' }, + exec_lua [[ local diagnostics = { make_error("Syntax error\nMore context", 0, 1, 0, 3, nil, "code-x"), } @@ -1953,14 +2426,19 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) - eq(".../diagnostic.lua:0: suffix: expected string|table|function, got number", - pcall_err(exec_lua, [[ vim.diagnostic.open_float({ suffix = 42 }) ]])) + eq( + '.../diagnostic.lua:0: suffix: expected string|table|function, got number', + pcall_err(exec_lua, [[ vim.diagnostic.open_float({ suffix = 42 }) ]]) + ) end) it('works with the old signature', function() - eq({'1. Syntax error'}, exec_lua [[ + eq( + { '1. Syntax error' }, + exec_lua [[ local diagnostics = { make_error("Syntax error", 0, 1, 0, 3), } @@ -1970,7 +2448,8 @@ end) local lines = vim.api.nvim_buf_get_lines(float_bufnr, 0, -1, false) vim.api.nvim_win_close(winnr, true) return lines - ]]) + ]] + ) end) end) @@ -2015,55 +2494,76 @@ end) describe('match()', function() it('matches a string', function() - local msg = "ERROR: george.txt:19:84:Two plus two equals five" + local msg = 'ERROR: george.txt:19:84:Two plus two equals five' local diagnostic = { severity = exec_lua [[return vim.diagnostic.severity.ERROR]], lnum = 18, col = 83, end_lnum = 18, end_col = 83, - message = "Two plus two equals five", + message = 'Two plus two equals five', } - eq(diagnostic, exec_lua([[ + eq( + diagnostic, + exec_lua( + [[ return vim.diagnostic.match(..., "^(%w+): [^:]+:(%d+):(%d+):(.+)$", {"severity", "lnum", "col", "message"}) - ]], msg)) + ]], + msg + ) + ) end) it('returns nil if the pattern fails to match', function() - eq(NIL, exec_lua [[ + eq( + NIL, + exec_lua [[ local msg = "The answer to life, the universe, and everything is" return vim.diagnostic.match(msg, "This definitely will not match", {}) - ]]) + ]] + ) end) it('respects default values', function() - local msg = "anna.txt:1:Happy families are all alike" + local msg = 'anna.txt:1:Happy families are all alike' local diagnostic = { severity = exec_lua [[return vim.diagnostic.severity.INFO]], lnum = 0, col = 0, end_lnum = 0, end_col = 0, - message = "Happy families are all alike", + message = 'Happy families are all alike', } - eq(diagnostic, exec_lua([[ + eq( + diagnostic, + exec_lua( + [[ return vim.diagnostic.match(..., "^[^:]+:(%d+):(.+)$", {"lnum", "message"}, nil, {severity = vim.diagnostic.severity.INFO}) - ]], msg)) + ]], + msg + ) + ) end) it('accepts a severity map', function() - local msg = "46:FATAL:Et tu, Brute?" + local msg = '46:FATAL:Et tu, Brute?' local diagnostic = { severity = exec_lua [[return vim.diagnostic.severity.ERROR]], lnum = 45, col = 0, end_lnum = 45, end_col = 0, - message = "Et tu, Brute?", + message = 'Et tu, Brute?', } - eq(diagnostic, exec_lua([[ + eq( + diagnostic, + exec_lua( + [[ return vim.diagnostic.match(..., "^(%d+):(%w+):(.+)$", {"lnum", "severity", "message"}, {FATAL = vim.diagnostic.severity.ERROR}) - ]], msg)) + ]], + msg + ) + ) end) end) @@ -2095,12 +2595,20 @@ end) describe('handlers', function() it('checks that a new handler is a table', function() - matches([[.*handler: expected table, got string.*]], pcall_err(exec_lua, [[ vim.diagnostic.handlers.foo = "bar" ]])) - matches([[.*handler: expected table, got function.*]], pcall_err(exec_lua, [[ vim.diagnostic.handlers.foo = function() end ]])) + matches( + [[.*handler: expected table, got string.*]], + pcall_err(exec_lua, [[ vim.diagnostic.handlers.foo = "bar" ]]) + ) + matches( + [[.*handler: expected table, got function.*]], + pcall_err(exec_lua, [[ vim.diagnostic.handlers.foo = function() end ]]) + ) end) it('can add new handlers', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ local handler_called = false vim.diagnostic.handlers.test = { show = function(namespace, bufnr, diagnostics, opts) @@ -2117,11 +2625,14 @@ end) make_warning("Warning", 0, 0, 0, 0), }) return handler_called - ]]) + ]] + ) end) it('can disable handlers by setting the corresponding option to false', function() - eq(false, exec_lua [[ + eq( + false, + exec_lua [[ local handler_called = false vim.diagnostic.handlers.test = { show = function(namespace, bufnr, diagnostics, opts) @@ -2134,11 +2645,14 @@ end) make_warning("Warning", 0, 0, 0, 0), }) return handler_called - ]]) + ]] + ) end) - it('always calls a handler\'s hide function if defined', function() - eq({false, true}, exec_lua [[ + it("always calls a handler's hide function if defined", function() + eq( + { false, true }, + exec_lua [[ local hide_called = false local show_called = false vim.diagnostic.handlers.test = { @@ -2158,11 +2672,14 @@ end) }) vim.diagnostic.hide(diagnostic_ns, diagnostic_bufnr) return {show_called, hide_called} - ]]) + ]] + ) end) it('triggers the autocommand when diagnostics are set', function() - eq({true, true}, exec_lua [[ + eq( + { true, true }, + exec_lua [[ -- Set a different buffer as current to test that <abuf> is being set properly in -- DiagnosticChanged callbacks local tmp = vim.api.nvim_create_buf(false, true) @@ -2182,11 +2699,14 @@ end) triggered[1] == diagnostic_bufnr, triggered[2] == 1, } - ]]) - end) + ]] + ) + end) it('triggers the autocommand when diagnostics are cleared', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ local tmp = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_current_buf(tmp) vim.g.diagnostic_autocmd_triggered = 0 @@ -2194,11 +2714,14 @@ end) vim.api.nvim_buf_set_name(diagnostic_bufnr, "test | test") vim.diagnostic.reset(diagnostic_ns, diagnostic_bufnr) return vim.g.diagnostic_autocmd_triggered == diagnostic_bufnr - ]]) - end) + ]] + ) + end) - it("checks if diagnostics are disabled in a buffer", function() - eq({true, true, true , true}, exec_lua [[ + it('checks if diagnostics are disabled in a buffer', function() + eq( + { true, true, true, true }, + exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic #1', 1, 1, 1, 1), }) @@ -2210,9 +2733,12 @@ end) vim.diagnostic.is_disabled(diagnostic_bufnr, diagnostic_ns), vim.diagnostic.is_disabled(_, diagnostic_ns), } - ]]) + ]] + ) - eq({false, false, false , false}, exec_lua [[ + eq( + { false, false, false, false }, + exec_lua [[ vim.diagnostic.enable() return { vim.diagnostic.is_disabled(), @@ -2220,7 +2746,8 @@ end) vim.diagnostic.is_disabled(diagnostic_bufnr, diagnostic_ns), vim.diagnostic.is_disabled(_, diagnostic_ns), } - ]]) + ]] + ) end) end) end) diff --git a/test/functional/lua/ffi_spec.lua b/test/functional/lua/ffi_spec.lua index 3a37b18cd1..c9e8e9d4ca 100644 --- a/test/functional/lua/ffi_spec.lua +++ b/test/functional/lua/ffi_spec.lua @@ -11,7 +11,9 @@ describe('ffi.cdef', function() pending('missing LuaJIT FFI') end - eq(12, exec_lua[[ + eq( + 12, + exec_lua [[ local ffi = require('ffi') ffi.cdef('int curwin_col_off(void);') @@ -19,9 +21,12 @@ describe('ffi.cdef', function() vim.cmd('set number numberwidth=4 signcolumn=yes:4') return ffi.C.curwin_col_off() - ]]) + ]] + ) - eq(20, exec_lua[=[ + eq( + 20, + exec_lua [=[ local ffi = require('ffi') ffi.cdef[[ @@ -38,7 +43,7 @@ describe('ffi.cdef', function() char *out, size_t outlen, char *fmt, - char *opt_name, + int opt_idx, int opt_scope, int fillchar, int maxwidth, @@ -53,7 +58,7 @@ describe('ffi.cdef', function() ffi.new('char[1024]'), 1024, ffi.cast('char*', 'StatusLineOfLength20'), - nil, + -1, 0, 0, 0, @@ -61,15 +66,19 @@ describe('ffi.cdef', function() nil, nil ) - ]=]) + ]=] + ) -- Check that extern symbols are exported and accessible - eq(true, exec_lua[[ + eq( + true, + exec_lua [[ local ffi = require('ffi') ffi.cdef('uint64_t display_tick;') return ffi.C.display_tick >= 0 - ]]) + ]] + ) end) end) diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index b3d95e1c7f..8b0e0a8beb 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -1,7 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local exec_lua = helpers.exec_lua local eq = helpers.eq -local meths = helpers.meths +local api = helpers.api local clear = helpers.clear local pathroot = helpers.pathroot local command = helpers.command @@ -19,18 +19,23 @@ describe('vim.filetype', function() end) it('works with extensions', function() - eq('radicalscript', exec_lua [[ + eq( + 'radicalscript', + exec_lua [[ vim.filetype.add({ extension = { rs = 'radicalscript', }, }) return vim.filetype.match({ filename = 'main.rs' }) - ]]) + ]] + ) end) it('prioritizes filenames over extensions', function() - eq('somethingelse', exec_lua [[ + eq( + 'somethingelse', + exec_lua [[ vim.filetype.add({ extension = { rs = 'radicalscript', @@ -40,20 +45,27 @@ describe('vim.filetype', function() }, }) return vim.filetype.match({ filename = 'main.rs' }) - ]]) + ]] + ) end) it('works with filenames', function() - eq('nim', exec_lua [[ + eq( + 'nim', + exec_lua [[ vim.filetype.add({ filename = { ['s_O_m_e_F_i_l_e'] = 'nim', }, }) return vim.filetype.match({ filename = 's_O_m_e_F_i_l_e' }) - ]]) + ]] + ) - eq('dosini', exec_lua([[ + eq( + 'dosini', + exec_lua( + [[ local root = ... vim.filetype.add({ filename = { @@ -62,11 +74,17 @@ describe('vim.filetype', function() }, }) return vim.filetype.match({ filename = root .. '/.config/fun/config' }) - ]], root)) + ]], + root + ) + ) end) it('works with patterns', function() - eq('markdown', exec_lua([[ + eq( + 'markdown', + exec_lua( + [[ local root = ... vim.env.HOME = '/a-funky+home%dir' vim.filetype.add({ @@ -75,13 +93,18 @@ describe('vim.filetype', function() } }) return vim.filetype.match({ filename = '~/blog/why_neovim_is_awesome.txt' }) - ]], root)) + ]], + root + ) + ) end) it('works with functions', function() command('new') command('file relevant_to_me') - eq('foss', exec_lua [[ + eq( + 'foss', + exec_lua [[ vim.filetype.add({ pattern = { ["relevant_to_(%a+)"] = function(path, bufnr, capture) @@ -92,26 +115,33 @@ describe('vim.filetype', function() } }) return vim.filetype.match({ buf = 0 }) - ]]) + ]] + ) end) it('works with contents #22180', function() - eq('sh', exec_lua [[ + eq( + 'sh', + exec_lua [[ -- Needs to be set so detect#sh doesn't fail vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$' return vim.filetype.match({ contents = { '#!/usr/bin/env bash' } }) - ]]) + ]] + ) end) it('considers extension mappings when matching from hashbang', function() - eq('fooscript', exec_lua [[ + eq( + 'fooscript', + exec_lua [[ vim.filetype.add({ extension = { foo = 'fooscript', } }) return vim.filetype.match({ contents = { '#!/usr/bin/env foo' } }) - ]]) + ]] + ) end) it('can get default option values for filetypes via vim.filetype.get_option()', function() @@ -120,20 +150,21 @@ describe('vim.filetype', 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, exec_lua([[ return vim.filetype.get_option(...) ]], ft, option)) end end - end) end) describe('filetype.lua', function() it('does not override user autocommands that set filetype #20333', function() - clear({args={'--clean', '--cmd', 'autocmd BufRead *.md set filetype=notmarkdown', 'README.md'}}) - eq('notmarkdown', meths.get_option_value('filetype', {})) + clear({ + args = { '--clean', '--cmd', 'autocmd BufRead *.md set filetype=notmarkdown', 'README.md' }, + }) + eq('notmarkdown', api.nvim_get_option_value('filetype', {})) end) end) diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 6bdb9ed79d..6821fe3c5e 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -1,5 +1,4 @@ local helpers = require('test.functional.helpers')(after_each) -local uv = require('luv') local clear = helpers.clear local exec_lua = helpers.exec_lua @@ -7,8 +6,8 @@ local eq = helpers.eq local mkdir_p = helpers.mkdir_p local rmdir = helpers.rmdir local nvim_dir = helpers.nvim_dir -local test_build_dir = helpers.test_build_dir -local test_source_path = helpers.test_source_path +local test_build_dir = helpers.paths.test_build_dir +local test_source_path = helpers.paths.test_source_path local nvim_prog = helpers.nvim_prog local is_os = helpers.is_os local mkdir = helpers.mkdir @@ -55,40 +54,33 @@ describe('vim.fs', function() it('works', function() local test_dir = nvim_dir .. '/test' mkdir_p(test_dir) - local dirs = exec_lua([[ - local test_dir, test_build_dir = ... - local dirs = {} - for dir in vim.fs.parents(test_dir .. "/foo.txt") do - dirs[#dirs + 1] = dir - if dir == test_build_dir then - break - end + local dirs = {} + for dir in vim.fs.parents(test_dir .. '/foo.txt') do + dirs[#dirs + 1] = dir + if dir == test_build_dir then + break end - return dirs - ]], test_dir, test_build_dir) - eq({test_dir, nvim_dir, test_build_dir}, dirs) + end + eq({ test_dir, nvim_dir, test_build_dir }, dirs) rmdir(test_dir) end) end) describe('dirname()', function() it('works', function() - eq(test_build_dir, exec_lua([[ - local nvim_dir = ... - return vim.fs.dirname(nvim_dir) - ]], nvim_dir)) + eq(test_build_dir, vim.fs.dirname(nvim_dir)) local function test_paths(paths) for _, path in ipairs(paths) do eq( - exec_lua([[ + exec_lua( + [[ local path = ... return vim.fn.fnamemodify(path,':h'):gsub('\\', '/') - ]], path), - exec_lua([[ - local path = ... - return vim.fs.dirname(path) - ]], path), + ]], + path + ), + vim.fs.dirname(path), path ) end @@ -103,23 +95,19 @@ describe('vim.fs', function() describe('basename()', function() it('works', function() - - eq(nvim_prog_basename, exec_lua([[ - local nvim_prog = ... - return vim.fs.basename(nvim_prog) - ]], nvim_prog)) + eq(nvim_prog_basename, vim.fs.basename(nvim_prog)) local function test_paths(paths) for _, path in ipairs(paths) do eq( - exec_lua([[ + exec_lua( + [[ local path = ... return vim.fn.fnamemodify(path,':t'):gsub('\\', '/') - ]], path), - exec_lua([[ - local path = ... - return vim.fs.basename(path) - ]], path), + ]], + path + ), + vim.fs.basename(path), path ) end @@ -145,7 +133,10 @@ describe('vim.fs', function() end) it('works', function() - eq(true, exec_lua([[ + eq( + true, + exec_lua( + [[ local dir, nvim = ... for name, type in vim.fs.dir(dir) do if name == nvim and type == 'file' then @@ -153,7 +144,11 @@ describe('vim.fs', function() end end return false - ]], nvim_dir, nvim_prog_basename)) + ]], + nvim_dir, + nvim_prog_basename + ) + ) end) it('works with opts.depth and opts.skip', function() @@ -171,7 +166,8 @@ describe('vim.fs', function() io.open('testd/a/b/c/c4', 'w'):close() local function run(dir, depth, skip) - local r = exec_lua([[ + local r = exec_lua( + [[ local dir, depth, skip = ... local r = {} local skip_f @@ -186,7 +182,11 @@ describe('vim.fs', function() r[name] = type_ end return r - ]], dir, depth, skip) + ]], + dir, + depth, + skip + ) return r end @@ -212,7 +212,7 @@ describe('vim.fs', function() exp['a/b/c'] = 'directory' eq(exp, run('testd', 3)) - eq(exp, run('testd', 999, {'a/b/c'})) + eq(exp, run('testd', 999, { 'a/b/c' })) exp['a/b/c/a4'] = 'file' exp['a/b/c/b4'] = 'file' @@ -224,88 +224,92 @@ describe('vim.fs', function() describe('find()', function() it('works', function() - eq({test_build_dir .. "/build"}, exec_lua([[ - local dir = ... - return vim.fs.find('build', { path = dir, upward = true, type = 'directory' }) - ]], nvim_dir)) - eq({nvim_prog}, exec_lua([[ - local dir, nvim = ... - return vim.fs.find(nvim, { path = dir, type = 'file' }) - ]], test_build_dir, nvim_prog_basename)) - eq({nvim_dir}, exec_lua([[ - local dir = ... - local parent, name = dir:match('^(.*/)([^/]+)$') - return vim.fs.find(name, { path = parent, upward = true, type = 'directory' }) - ]], nvim_dir)) + eq( + { test_build_dir .. '/build' }, + vim.fs.find('build', { path = nvim_dir, upward = true, type = 'directory' }) + ) + eq({ nvim_prog }, vim.fs.find(nvim_prog_basename, { path = test_build_dir, type = 'file' })) + + local parent, name = nvim_dir:match('^(.*/)([^/]+)$') + eq({ nvim_dir }, vim.fs.find(name, { path = parent, upward = true, type = 'directory' })) end) it('accepts predicate as names', function() - eq({test_build_dir .. "/build"}, exec_lua([[ - local dir = ... - local opts = { path = dir, upward = true, type = 'directory' } - return vim.fs.find(function(x) return x == 'build' end, opts) - ]], nvim_dir)) - eq({nvim_prog}, exec_lua([[ - local dir, nvim = ... - return vim.fs.find(function(x) return x == nvim end, { path = dir, type = 'file' }) - ]], test_build_dir, nvim_prog_basename)) - eq({}, exec_lua([[ - local dir = ... - local opts = { path = dir, upward = true, type = 'directory' } - return vim.fs.find(function(x) return x == 'no-match' end, opts) - ]], nvim_dir)) + local opts = { path = nvim_dir, upward = true, type = 'directory' } + eq( + { test_build_dir .. '/build' }, + vim.fs.find(function(x) + return x == 'build' + end, opts) + ) + eq( + { nvim_prog }, + vim.fs.find(function(x) + return x == nvim_prog_basename + end, { path = test_build_dir, type = 'file' }) + ) + eq( + {}, + vim.fs.find(function(x) + return x == 'no-match' + end, opts) + ) + + opts = { path = test_source_path .. '/contrib', limit = math.huge } eq( - exec_lua([[ + exec_lua( + [[ local dir = ... return vim.tbl_map(vim.fs.basename, vim.fn.glob(dir..'/contrib/*', false, true)) - ]], test_source_path), - exec_lua([[ - local dir = ... - local opts = { path = dir .. "/contrib", limit = math.huge } - return vim.tbl_map(vim.fs.basename, vim.fs.find(function(_, d) return d:match('[\\/]contrib$') end, opts)) - ]], test_source_path)) + ]], + test_source_path + ), + vim.tbl_map( + vim.fs.basename, + vim.fs.find(function(_, d) + return d:match('[\\/]contrib$') + end, opts) + ) + ) end) end) describe('joinpath()', function() it('works', function() - eq('foo/bar/baz', exec_lua([[ - return vim.fs.joinpath('foo', 'bar', 'baz') - ]], nvim_dir)) - eq('foo/bar/baz', exec_lua([[ - return vim.fs.joinpath('foo', '/bar/', '/baz') - ]], nvim_dir)) + eq('foo/bar/baz', vim.fs.joinpath('foo', 'bar', 'baz')) + eq('foo/bar/baz', vim.fs.joinpath('foo', '/bar/', '/baz')) end) end) describe('normalize()', function() it('works with backward slashes', function() - eq('C:/Users/jdoe', exec_lua [[ return vim.fs.normalize('C:\\Users\\jdoe') ]]) + eq('C:/Users/jdoe', vim.fs.normalize('C:\\Users\\jdoe')) end) it('removes trailing /', function() - eq('/home/user', exec_lua [[ return vim.fs.normalize('/home/user/') ]]) + eq('/home/user', vim.fs.normalize('/home/user/')) end) it('works with /', function() - eq('/', exec_lua [[ return vim.fs.normalize('/') ]]) + eq('/', vim.fs.normalize('/')) end) it('works with ~', function() - eq( - exec_lua([[ - local home = ... - return home .. '/src/foo' - ]], vim.fs.normalize(uv.os_homedir())), - exec_lua [[ return vim.fs.normalize('~/src/foo') ]]) + eq(vim.fs.normalize(vim.uv.os_homedir()) .. '/src/foo', vim.fs.normalize('~/src/foo')) end) it('works with environment variables', function() local xdg_config_home = test_build_dir .. '/.config' - eq(xdg_config_home .. '/nvim', exec_lua([[ + eq( + xdg_config_home .. '/nvim', + exec_lua( + [[ vim.env.XDG_CONFIG_HOME = ... return vim.fs.normalize('$XDG_CONFIG_HOME/nvim') - ]], xdg_config_home)) + ]], + xdg_config_home + ) + ) end) if is_os('win') then it('Last slash is not truncated from root drive', function() - eq('C:/', exec_lua [[ return vim.fs.normalize('C:/') ]]) + eq('C:/', vim.fs.normalize('C:/')) end) end end) diff --git a/test/functional/lua/glob_spec.lua b/test/functional/lua/glob_spec.lua new file mode 100644 index 0000000000..1eac037575 --- /dev/null +++ b/test/functional/lua/glob_spec.lua @@ -0,0 +1,226 @@ +local helpers = require('test.functional.helpers')(after_each) +local eq = helpers.eq +local exec_lua = helpers.exec_lua + +describe('glob', function() + before_each(helpers.clear) + after_each(helpers.clear) + + local match = function(...) + return exec_lua( + [[ + local pattern = select(1, ...) + local str = select(2, ...) + return require("vim.glob").to_lpeg(pattern):match(str) ~= nil + ]], + ... + ) + end + + describe('glob matching', function() + it('should match literal strings', function() + eq(true, match('', '')) + eq(false, match('', 'a')) + eq(true, match('a', 'a')) + eq(true, match('/', '/')) + eq(true, match('abc', 'abc')) + eq(false, match('abc', 'abcdef')) + eq(false, match('abc', 'a')) + eq(false, match('abc', 'bc')) + eq(false, match('a', 'b')) + eq(false, match('.', 'a')) + eq(true, match('$', '$')) + eq(true, match('/dir', '/dir')) + eq(true, match('dir/', 'dir/')) + eq(true, match('dir/subdir', 'dir/subdir')) + eq(false, match('dir/subdir', 'subdir')) + eq(false, match('dir/subdir', 'dir/subdir/file')) + eq(true, match('🤠', '🤠')) + end) + + it('should match * wildcards', function() + eq(false, match('*', '')) + eq(true, match('*', 'a')) + eq(false, match('*', '/')) + eq(false, match('*', '/a')) + eq(false, match('*', 'a/')) + eq(true, match('*', 'aaa')) + eq(true, match('*a', 'aa')) + eq(true, match('*a', 'abca')) + eq(true, match('*.txt', 'file.txt')) + eq(false, match('*.txt', 'file.txtxt')) + eq(false, match('*.txt', 'dir/file.txt')) + eq(false, match('*.txt', '/dir/file.txt')) + eq(false, match('*.txt', 'C:/dir/file.txt')) + eq(false, match('*.dir', 'test.dir/file')) + eq(true, match('file.*', 'file.txt')) + eq(false, match('file.*', 'not-file.txt')) + eq(true, match('*/file.txt', 'dir/file.txt')) + eq(false, match('*/file.txt', 'dir/subdir/file.txt')) + eq(false, match('*/file.txt', '/dir/file.txt')) + eq(true, match('dir/*', 'dir/file.txt')) + eq(false, match('dir/*', 'dir')) + eq(false, match('dir/*.txt', 'file.txt')) + eq(true, match('dir/*.txt', 'dir/file.txt')) + eq(false, match('dir/*.txt', 'dir/subdir/file.txt')) + eq(false, match('dir/*/file.txt', 'dir/file.txt')) + eq(true, match('dir/*/file.txt', 'dir/subdir/file.txt')) + eq(false, match('dir/*/file.txt', 'dir/subdir/subdir/file.txt')) + + -- The spec does not describe this, but VSCode only interprets ** when it's by + -- itself in a path segment, and otherwise interprets ** as consecutive * directives. + -- see: https://github.com/microsoft/vscode/blob/eef30e7165e19b33daa1e15e92fa34ff4a5df0d3/src/vs/base/common/glob.ts#L112 + eq(true, match('a**', 'abc')) -- '**' should parse as two '*'s when not by itself in a path segment + eq(true, match('**c', 'abc')) + eq(false, match('a**', 'ab')) -- each '*' should still represent at least one character + eq(false, match('**c', 'bc')) + eq(true, match('a**', 'abcd')) + eq(true, match('**d', 'abcd')) + eq(false, match('a**', 'abc/d')) + eq(false, match('**d', 'abc/d')) + end) + + it('should match ? wildcards', function() + eq(false, match('?', '')) + eq(true, match('?', 'a')) + eq(false, match('??', 'a')) + eq(false, match('?', 'ab')) + eq(true, match('??', 'ab')) + eq(true, match('a?c', 'abc')) + eq(false, match('a?c', 'a/c')) + end) + + it('should match ** wildcards', function() + eq(true, match('**', '')) + eq(true, match('**', 'a')) + eq(true, match('**', '/')) + eq(true, match('**', 'a/')) + eq(true, match('**', '/a')) + eq(true, match('**', 'C:/a')) + eq(true, match('**', 'a/a')) + eq(true, match('**', 'a/a/a')) + eq(false, match('/**', '')) -- /** matches leading / literally + eq(true, match('/**', '/')) + eq(true, match('/**', '/a/b/c')) + eq(true, match('**/', '')) -- **/ absorbs trailing / + eq(true, match('**/', '/a/b/c')) + eq(true, match('**/**', '')) + eq(true, match('**/**', 'a')) + eq(false, match('a/**', '')) + eq(false, match('a/**', 'a')) + eq(true, match('a/**', 'a/b')) + eq(true, match('a/**', 'a/b/c')) + eq(false, match('a/**', 'b/a')) + eq(false, match('a/**', '/a')) + eq(false, match('**/a', '')) + eq(true, match('**/a', 'a')) + eq(false, match('**/a', 'a/b')) + eq(true, match('**/a', '/a')) + eq(true, match('**/a', '/b/a')) + eq(true, match('**/a', '/c/b/a')) + eq(true, match('**/a', '/a/a')) + eq(true, match('**/a', '/abc/a')) + eq(false, match('a/**/c', 'a')) + eq(false, match('a/**/c', 'c')) + eq(true, match('a/**/c', 'a/c')) + eq(true, match('a/**/c', 'a/b/c')) + eq(true, match('a/**/c', 'a/b/b/c')) + eq(false, match('**/a/**', 'a')) + eq(true, match('**/a/**', 'a/')) + eq(false, match('**/a/**', '/dir/a')) + eq(false, match('**/a/**', 'dir/a')) + eq(true, match('**/a/**', 'dir/a/')) + eq(true, match('**/a/**', 'a/dir')) + eq(true, match('**/a/**', 'dir/a/dir')) + eq(true, match('**/a/**', '/a/dir')) + eq(true, match('**/a/**', 'C:/a/dir')) + eq(false, match('**/a/**', 'a.txt')) + end) + + it('should match {} groups', function() + eq(true, match('{}', '')) + eq(false, match('{}', 'a')) + eq(true, match('a{}', 'a')) + eq(true, match('{}a', 'a')) + eq(true, match('{,}', '')) + eq(true, match('{a,}', '')) + eq(true, match('{a,}', 'a')) + eq(true, match('{a}', 'a')) + eq(false, match('{a}', 'aa')) + eq(false, match('{a}', 'ab')) + eq(true, match('{a?c}', 'abc')) + eq(false, match('{ab}', 'a')) + eq(false, match('{ab}', 'b')) + eq(true, match('{ab}', 'ab')) + eq(true, match('{a,b}', 'a')) + eq(true, match('{a,b}', 'b')) + eq(false, match('{a,b}', 'ab')) + eq(true, match('{ab,cd}', 'ab')) + eq(false, match('{ab,cd}', 'a')) + eq(true, match('{ab,cd}', 'cd')) + eq(true, match('{a,b,c}', 'c')) + eq(true, match('{a,{b,c}}', 'c')) + end) + + it('should match [] groups', function() + eq(true, match('[]', '[]')) -- empty [] is a literal + eq(false, match('[a-z]', '')) + eq(true, match('[a-z]', 'a')) + eq(false, match('[a-z]', 'ab')) + eq(true, match('[a-z]', 'z')) + eq(true, match('[a-z]', 'j')) + eq(false, match('[a-f]', 'j')) + eq(false, match('[a-z]', '`')) -- 'a' - 1 + eq(false, match('[a-z]', '{')) -- 'z' + 1 + eq(false, match('[a-z]', 'A')) + eq(false, match('[a-z]', '5')) + eq(true, match('[A-Z]', 'A')) + eq(true, match('[A-Z]', 'Z')) + eq(true, match('[A-Z]', 'J')) + eq(false, match('[A-Z]', '@')) -- 'A' - 1 + eq(false, match('[A-Z]', '[')) -- 'Z' + 1 + eq(false, match('[A-Z]', 'a')) + eq(false, match('[A-Z]', '5')) + eq(true, match('[a-zA-Z0-9]', 'z')) + eq(true, match('[a-zA-Z0-9]', 'Z')) + eq(true, match('[a-zA-Z0-9]', '9')) + eq(false, match('[a-zA-Z0-9]', '&')) + end) + + it('should match [!...] groups', function() + eq(true, match('[!]', '[!]')) -- [!] is a literal + eq(false, match('[!a-z]', '')) + eq(false, match('[!a-z]', 'a')) + eq(false, match('[!a-z]', 'z')) + eq(false, match('[!a-z]', 'j')) + eq(true, match('[!a-f]', 'j')) + eq(false, match('[!a-f]', 'jj')) + eq(true, match('[!a-z]', '`')) -- 'a' - 1 + eq(true, match('[!a-z]', '{')) -- 'z' + 1 + eq(false, match('[!a-zA-Z0-9]', 'a')) + eq(false, match('[!a-zA-Z0-9]', 'A')) + eq(false, match('[!a-zA-Z0-9]', '0')) + eq(true, match('[!a-zA-Z0-9]', '!')) + end) + + it('should match complex patterns', function() + eq(false, match('**/*.{c,h}', '')) + eq(false, match('**/*.{c,h}', 'c')) + eq(false, match('**/*.{c,h}', 'file.m')) + eq(true, match('**/*.{c,h}', 'file.c')) + eq(true, match('**/*.{c,h}', 'file.h')) + eq(true, match('**/*.{c,h}', '/file.c')) + eq(true, match('**/*.{c,h}', 'dir/subdir/file.c')) + eq(true, match('**/*.{c,h}', 'dir/subdir/file.h')) + eq(true, match('**/*.{c,h}', '/dir/subdir/file.c')) + eq(true, match('**/*.{c,h}', 'C:/dir/subdir/file.c')) + eq(true, match('/dir/**/*.{c,h}', '/dir/file.c')) + eq(false, match('/dir/**/*.{c,h}', 'dir/file.c')) + eq(true, match('/dir/**/*.{c,h}', '/dir/subdir/subdir/file.c')) + + eq(true, match('{[0-9],[a-z]}', '0')) + eq(true, match('{[0-9],[a-z]}', 'a')) + eq(false, match('{[0-9],[a-z]}', 'A')) + end) + end) +end) diff --git a/test/functional/lua/help_spec.lua b/test/functional/lua/help_spec.lua deleted file mode 100644 index ef1b8ebf3f..0000000000 --- a/test/functional/lua/help_spec.lua +++ /dev/null @@ -1,53 +0,0 @@ --- Tests for gen_help_html.lua. Validates :help tags/links and HTML doc generation. --- --- TODO: extract parts of gen_help_html.lua into Nvim stdlib? - -local helpers = require('test.functional.helpers')(after_each) -local clear = helpers.clear -local exec_lua = helpers.exec_lua -local eq = helpers.eq -local ok = helpers.ok - -if helpers.skip(helpers.is_ci('cirrus'), 'No need to run this on Cirrus') then return end - -describe(':help docs', function() - before_each(clear) - it('validate', function() - -- If this test fails, try these steps (in order): - -- 1. Fix/cleanup the :help docs. - -- 2. Fix the parser: https://github.com/neovim/tree-sitter-vimdoc - -- 3. File a parser bug, and adjust the tolerance of this test in the meantime. - - local rv = exec_lua([[return require('scripts.gen_help_html').validate('./build/runtime/doc')]]) - -- Check that we actually found helpfiles. - ok(rv.helpfiles > 100, '>100 :help files', rv.helpfiles) - - eq({}, rv.parse_errors, 'no parse errors') - eq(0, rv.err_count, 'no parse errors') - eq({}, rv.invalid_links, 'invalid tags in :help docs') - eq({}, rv.invalid_urls, 'invalid URLs in :help docs') - eq({}, rv.invalid_spelling, 'invalid spelling in :help docs (see spell_dict in scripts/gen_help_html.lua)') - end) - - it('gen_help_html.lua generates HTML', function() - -- 1. Test that gen_help_html.lua actually works. - -- 2. Test that parse errors did not increase wildly. Because we explicitly test only a few - -- :help files, we can be precise about the tolerances here. - - local tmpdir = exec_lua('return vim.fs.dirname(vim.fn.tempname())') - -- Because gen() is slow (~30s), this test is limited to a few files. - local rv = exec_lua([[ - local to_dir = ... - return require('scripts.gen_help_html').gen( - './build/runtime/doc', - to_dir, - { 'pi_health.txt', 'help.txt', 'index.txt', 'nvim.txt', } - ) - ]], - tmpdir - ) - eq(4, #rv.helpfiles) - eq(0, rv.err_count, 'parse errors in :help docs') - eq({}, rv.invalid_links, 'invalid tags in :help docs') - end) -end) diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua index 8e499f1e79..197f3139f3 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/highlight_spec.lua @@ -1,9 +1,11 @@ local helpers = require('test.functional.helpers')(after_each) local exec_lua = helpers.exec_lua local eq = helpers.eq +local neq = helpers.neq local eval = helpers.eval local command = helpers.command local clear = helpers.clear +local api = helpers.api describe('vim.highlight.on_yank', function() before_each(function() @@ -16,7 +18,7 @@ describe('vim.highlight.on_yank', function() vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y", regtype = "v"}}) vim.cmd('bwipeout!') ]]) - helpers.sleep(10) + vim.uv.sleep(10) helpers.feed('<cr>') -- avoid hang if error message exists eq('', eval('v:errmsg')) end) @@ -31,4 +33,34 @@ describe('vim.highlight.on_yank', function() ]]) eq('', eval('v:errmsg')) end) + + it('does not show in another window', function() + command('vsplit') + exec_lua([[ + vim.api.nvim_buf_set_mark(0,"[",1,1,{}) + vim.api.nvim_buf_set_mark(0,"]",1,1,{}) + vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) + ]]) + neq({}, api.nvim_win_get_ns(0)) + command('wincmd w') + eq({}, api.nvim_win_get_ns(0)) + end) + + it('removes old highlight if new one is created before old one times out', function() + command('vnew') + exec_lua([[ + vim.api.nvim_buf_set_mark(0,"[",1,1,{}) + vim.api.nvim_buf_set_mark(0,"]",1,1,{}) + vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) + ]]) + neq({}, api.nvim_win_get_ns(0)) + command('wincmd w') + exec_lua([[ + vim.api.nvim_buf_set_mark(0,"[",1,1,{}) + vim.api.nvim_buf_set_mark(0,"]",1,1,{}) + vim.highlight.on_yank({timeout = math.huge, on_macro = true, event = {operator = "y"}}) + ]]) + command('wincmd w') + eq({}, api.nvim_win_get_ns(0)) + end) end) diff --git a/test/functional/lua/inspector_spec.lua b/test/functional/lua/inspector_spec.lua index c369956e56..ad8b5a45a8 100644 --- a/test/functional/lua/inspector_spec.lua +++ b/test/functional/lua/inspector_spec.lua @@ -46,9 +46,9 @@ describe('vim.inspect_pos', function() hl_group_link = 'Normal', ns_id = 1, priority = 4096, - right_gravity = true + right_gravity = true, }, - row = 0 + row = 0, }, { col = 10, @@ -63,10 +63,10 @@ describe('vim.inspect_pos', function() hl_group_link = 'Normal', ns_id = 2, priority = 4096, - right_gravity = true + right_gravity = true, }, - row = 0 - } + row = 0, + }, }, treesitter = {}, semantic_tokens = {}, diff --git a/test/functional/lua/iter_spec.lua b/test/functional/lua/iter_spec.lua index ffa28e7b11..8d6cf1264b 100644 --- a/test/functional/lua/iter_spec.lua +++ b/test/functional/lua/iter_spec.lua @@ -6,11 +6,11 @@ local pcall_err = helpers.pcall_err describe('vim.iter', function() it('new() on iterable class instance', function() local rb = vim.ringbuf(3) - rb:push("a") - rb:push("b") + rb:push('a') + rb:push('b') local it = vim.iter(rb) - eq({"a", "b"}, it:totable()) + eq({ 'a', 'b' }, it:totable()) end) it('filter()', function() @@ -20,18 +20,43 @@ describe('vim.iter', function() local t = { 1, 2, 3, 4, 5 } eq({ 1, 3, 5 }, vim.iter(t):filter(odd):totable()) - eq({ 2, 4 }, vim.iter(t):filter(function(v) return not odd(v) end):totable()) - eq({}, vim.iter(t):filter(function(v) return v > 5 end):totable()) + eq( + { 2, 4 }, + vim + .iter(t) + :filter(function(v) + return not odd(v) + end) + :totable() + ) + eq( + {}, + vim + .iter(t) + :filter(function(v) + return v > 5 + end) + :totable() + ) do local it = vim.iter(ipairs(t)) - it:filter(function(i, v) return i > 1 and v < 5 end) - it:map(function(_, v) return v * 2 end) + it:filter(function(i, v) + return i > 1 and v < 5 + end) + it:map(function(_, v) + return v * 2 + end) eq({ 4, 6, 8 }, it:totable()) end local it = vim.iter(string.gmatch('the quick brown fox', '%w+')) - eq({'the', 'fox'}, it:filter(function(s) return #s <= 3 end):totable()) + eq( + { 'the', 'fox' }, + it:filter(function(s) + return #s <= 3 + end):totable() + ) end) it('map()', function() @@ -39,11 +64,11 @@ describe('vim.iter', function() eq( { 2, 4, 6, 8, 10 }, vim - .iter(t) - :map(function(v) - return 2 * v - end) - :totable() + .iter(t) + :map(function(v) + return 2 * v + end) + :totable() ) local it = vim.gsplit( @@ -59,21 +84,25 @@ describe('vim.iter', function() eq( { 'Lion 2', 'Lion 4' }, vim - .iter(it) - :map(function(s) - local lnum = s:match('(%d+)') - if lnum and tonumber(lnum) % 2 == 0 then - return vim.trim(s:gsub('Line', 'Lion')) - end - end) - :totable() + .iter(it) + :map(function(s) + local lnum = s:match('(%d+)') + if lnum and tonumber(lnum) % 2 == 0 then + return vim.trim(s:gsub('Line', 'Lion')) + end + end) + :totable() ) end) it('for loops', function() - local t = {1, 2, 3, 4, 5} + local t = { 1, 2, 3, 4, 5 } local acc = 0 - for v in vim.iter(t):map(function(v) return v * 3 end) do + for v in + vim.iter(t):map(function(v) + return v * 3 + end) + do acc = acc + v end eq(45, acc) @@ -81,18 +110,27 @@ describe('vim.iter', function() it('totable()', function() do - local it = vim.iter({1, 2, 3}):map(function(v) return v, v*v end) - eq({{1, 1}, {2, 4}, {3, 9}}, it:totable()) + local it = vim.iter({ 1, 2, 3 }):map(function(v) + return v, v * v + end) + eq({ { 1, 1 }, { 2, 4 }, { 3, 9 } }, it:totable()) end do local it = vim.iter(string.gmatch('1,4,lol,17,blah,2,9,3', '%d+')):map(tonumber) - eq({1, 4, 17, 2, 9, 3}, it:totable()) + eq({ 1, 4, 17, 2, 9, 3 }, it:totable()) end end) + it('join()', function() + eq('1, 2, 3', vim.iter({ 1, 2, 3 }):join(', ')) + eq('a|b|c|d', vim.iter(vim.gsplit('a|b|c|d', '|')):join('|')) + end) + it('next()', function() - local it = vim.iter({1, 2, 3}):map(function(v) return 2 * v end) + local it = vim.iter({ 1, 2, 3 }):map(function(v) + return 2 * v + end) eq(2, it:next()) eq(4, it:next()) eq(6, it:next()) @@ -100,19 +138,19 @@ describe('vim.iter', function() end) it('rev()', function() - eq({3, 2, 1}, vim.iter({1, 2, 3}):rev():totable()) + eq({ 3, 2, 1 }, vim.iter({ 1, 2, 3 }):rev():totable()) - local it = vim.iter(string.gmatch("abc", "%w")) + local it = vim.iter(string.gmatch('abc', '%w')) matches('rev%(%) requires a list%-like table', pcall_err(it.rev, it)) end) it('skip()', function() do - local t = {4, 3, 2, 1} + local t = { 4, 3, 2, 1 } eq(t, vim.iter(t):skip(0):totable()) - eq({3, 2, 1}, vim.iter(t):skip(1):totable()) - eq({2, 1}, vim.iter(t):skip(2):totable()) - eq({1}, vim.iter(t):skip(#t - 1):totable()) + eq({ 3, 2, 1 }, vim.iter(t):skip(1):totable()) + eq({ 2, 1 }, vim.iter(t):skip(2):totable()) + eq({ 1 }, vim.iter(t):skip(#t - 1):totable()) eq({}, vim.iter(t):skip(#t):totable()) eq({}, vim.iter(t):skip(#t + 1):totable()) end @@ -121,10 +159,10 @@ describe('vim.iter', function() local function skip(n) return vim.iter(vim.gsplit('a|b|c|d', '|')):skip(n):totable() end - eq({'a', 'b', 'c', 'd'}, skip(0)) - eq({'b', 'c', 'd'}, skip(1)) - eq({'c', 'd'}, skip(2)) - eq({'d'}, skip(3)) + eq({ 'a', 'b', 'c', 'd' }, skip(0)) + eq({ 'b', 'c', 'd' }, skip(1)) + eq({ 'c', 'd' }, skip(2)) + eq({ 'd' }, skip(3)) eq({}, skip(4)) eq({}, skip(5)) end @@ -132,11 +170,11 @@ describe('vim.iter', function() it('skipback()', function() do - local t = {4, 3, 2, 1} + local t = { 4, 3, 2, 1 } eq(t, vim.iter(t):skipback(0):totable()) - eq({4, 3, 2}, vim.iter(t):skipback(1):totable()) - eq({4, 3}, vim.iter(t):skipback(2):totable()) - eq({4}, vim.iter(t):skipback(#t - 1):totable()) + eq({ 4, 3, 2 }, vim.iter(t):skipback(1):totable()) + eq({ 4, 3 }, vim.iter(t):skipback(2):totable()) + eq({ 4 }, vim.iter(t):skipback(#t - 1):totable()) eq({}, vim.iter(t):skipback(#t):totable()) eq({}, vim.iter(t):skipback(#t + 1):totable()) end @@ -146,14 +184,14 @@ describe('vim.iter', function() end) it('slice()', function() - local t = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} - eq({3, 4, 5, 6, 7}, vim.iter(t):slice(3, 7):totable()) + local t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } + eq({ 3, 4, 5, 6, 7 }, vim.iter(t):slice(3, 7):totable()) eq({}, vim.iter(t):slice(6, 5):totable()) eq({}, vim.iter(t):slice(0, 0):totable()) - eq({1}, vim.iter(t):slice(1, 1):totable()) - eq({1, 2}, vim.iter(t):slice(1, 2):totable()) - eq({10}, vim.iter(t):slice(10, 10):totable()) - eq({8, 9, 10}, vim.iter(t):slice(8, 11):totable()) + eq({ 1 }, vim.iter(t):slice(1, 1):totable()) + eq({ 1, 2 }, vim.iter(t):slice(1, 2):totable()) + eq({ 10 }, vim.iter(t):slice(10, 10):totable()) + eq({ 8, 9, 10 }, vim.iter(t):slice(8, 11):totable()) local it = vim.iter(vim.gsplit('a|b|c|d', '|')) matches('slice%(%) requires a list%-like table', pcall_err(it.slice, it, 1, 3)) @@ -161,7 +199,7 @@ describe('vim.iter', function() it('nth()', function() do - local t = {4, 3, 2, 1} + local t = { 4, 3, 2, 1 } eq(nil, vim.iter(t):nth(0)) eq(4, vim.iter(t):nth(1)) eq(3, vim.iter(t):nth(2)) @@ -185,7 +223,7 @@ describe('vim.iter', function() it('nthback()', function() do - local t = {4, 3, 2, 1} + local t = { 4, 3, 2, 1 } eq(nil, vim.iter(t):nthback(0)) eq(1, vim.iter(t):nthback(1)) eq(2, vim.iter(t):nthback(2)) @@ -198,6 +236,33 @@ describe('vim.iter', function() matches('skipback%(%) requires a list%-like table', pcall_err(it.nthback, it, 1)) end) + it('take()', function() + do + local t = { 4, 3, 2, 1 } + eq({}, vim.iter(t):take(0):totable()) + eq({ 4 }, vim.iter(t):take(1):totable()) + eq({ 4, 3 }, vim.iter(t):take(2):totable()) + eq({ 4, 3, 2 }, vim.iter(t):take(3):totable()) + eq({ 4, 3, 2, 1 }, vim.iter(t):take(4):totable()) + eq({ 4, 3, 2, 1 }, vim.iter(t):take(5):totable()) + end + + do + local t = { 4, 3, 2, 1 } + local it = vim.iter(t) + eq({ 4, 3 }, it:take(2):totable()) + -- tail is already set from the previous take() + eq({ 4, 3 }, it:take(3):totable()) + end + + do + local it = vim.iter(vim.gsplit('a|b|c|d', '|')) + eq({ 'a', 'b' }, it:take(2):totable()) + -- non-array iterators are consumed by take() + eq({}, it:take(2):totable()) + end + end) + it('any()', function() local function odd(v) return v % 2 ~= 0 @@ -214,8 +279,18 @@ describe('vim.iter', function() end do - eq(true, vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s) return s == 'd' end)) - eq(false, vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s) return s == 'e' end)) + eq( + true, + vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s) + return s == 'd' + end) + ) + eq( + false, + vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s) + return s == 'e' + end) + ) end end) @@ -235,8 +310,18 @@ describe('vim.iter', function() end do - eq(true, vim.iter(vim.gsplit('a|a|a|a', '|')):all(function(s) return s == 'a' end)) - eq(false, vim.iter(vim.gsplit('a|a|a|b', '|')):all(function(s) return s == 'a' end)) + eq( + true, + vim.iter(vim.gsplit('a|a|a|a', '|')):all(function(s) + return s == 'a' + end) + ) + eq( + false, + vim.iter(vim.gsplit('a|a|a|b', '|')):all(function(s) + return s == 'a' + end) + ) end end) @@ -248,10 +333,10 @@ describe('vim.iter', function() it('enumerate()', function() local it = vim.iter(vim.gsplit('abc', '')):enumerate() - eq({1, 'a'}, {it:next()}) - eq({2, 'b'}, {it:next()}) - eq({3, 'c'}, {it:next()}) - eq({}, {it:next()}) + eq({ 1, 'a' }, { it:next() }) + eq({ 2, 'b' }, { it:next() }) + eq({ 3, 'c' }, { it:next() }) + eq({}, { it:next() }) end) it('peek()', function() @@ -269,14 +354,21 @@ describe('vim.iter', function() end) it('find()', function() - local t = {3, 6, 9, 12} + local t = { 3, 6, 9, 12 } eq(12, vim.iter(t):find(12)) eq(nil, vim.iter(t):find(15)) - eq(12, vim.iter(t):find(function(v) return v % 4 == 0 end)) + eq( + 12, + vim.iter(t):find(function(v) + return v % 4 == 0 + end) + ) do local it = vim.iter(t) - local pred = function(v) return v % 3 == 0 end + local pred = function(v) + return v % 3 == 0 + end eq(3, it:find(pred)) eq(6, it:find(pred)) eq(9, it:find(pred)) @@ -286,7 +378,9 @@ describe('vim.iter', function() do local it = vim.iter(vim.gsplit('AbCdE', '')) - local pred = function(s) return s:match('[A-Z]') end + local pred = function(s) + return s:match('[A-Z]') + end eq('A', it:find(pred)) eq('C', it:find(pred)) eq('E', it:find(pred)) @@ -295,7 +389,7 @@ describe('vim.iter', function() end) it('rfind()', function() - local t = {1, 2, 3, 2, 1} + local t = { 1, 2, 3, 2, 1 } do local it = vim.iter(t) eq(1, it:rfind(1)) @@ -305,10 +399,12 @@ describe('vim.iter', function() do local it = vim.iter(t):enumerate() - local pred = function(i) return i % 2 ~= 0 end - eq({5, 1}, {it:rfind(pred)}) - eq({3, 3}, {it:rfind(pred)}) - eq({1, 1}, {it:rfind(pred)}) + local pred = function(i) + return i % 2 ~= 0 + end + eq({ 5, 1 }, { it:rfind(pred) }) + eq({ 3, 3 }, { it:rfind(pred) }) + eq({ 1, 1 }, { it:rfind(pred) }) eq(nil, it:rfind(pred)) end @@ -350,12 +446,52 @@ describe('vim.iter', function() end) it('fold()', function() - local t = {1, 2, 3, 4, 5} - eq(115, vim.iter(t):fold(100, function(acc, v) return acc + v end)) - eq({5, 4, 3, 2, 1}, vim.iter(t):fold({}, function(acc, v) - table.insert(acc, 1, v) - return acc - end)) + local t = { 1, 2, 3, 4, 5 } + eq( + 115, + vim.iter(t):fold(100, function(acc, v) + return acc + v + end) + ) + eq( + { 5, 4, 3, 2, 1 }, + vim.iter(t):fold({}, function(acc, v) + table.insert(acc, 1, v) + return acc + end) + ) + end) + + it('flatten()', function() + local t = { { 1, { 2 } }, { { { { 3 } } }, { 4 } }, { 5 } } + + eq(t, vim.iter(t):flatten(-1):totable()) + eq(t, vim.iter(t):flatten(0):totable()) + eq({ 1, { 2 }, { { { 3 } } }, { 4 }, 5 }, vim.iter(t):flatten():totable()) + eq({ 1, 2, { { 3 } }, 4, 5 }, vim.iter(t):flatten(2):totable()) + eq({ 1, 2, { 3 }, 4, 5 }, vim.iter(t):flatten(3):totable()) + eq({ 1, 2, 3, 4, 5 }, vim.iter(t):flatten(4):totable()) + + local m = { a = 1, b = { 2, 3 }, d = { 4 } } + local it = vim.iter(m) + + local flat_err = 'flatten%(%) requires a list%-like table' + matches(flat_err, pcall_err(it.flatten, it)) + + -- cases from the documentation + local simple_example = { 1, { 2 }, { { 3 } } } + eq({ 1, 2, { 3 } }, vim.iter(simple_example):flatten():totable()) + + local not_list_like = vim.iter({ [2] = 2 }) + matches(flat_err, pcall_err(not_list_like.flatten, not_list_like)) + + local also_not_list_like = vim.iter({ nil, 2 }) + matches(flat_err, pcall_err(not_list_like.flatten, also_not_list_like)) + + local nested_non_lists = vim.iter({ 1, { { a = 2 } }, { { nil } }, { 3 } }) + eq({ 1, { a = 2 }, { nil }, 3 }, nested_non_lists:flatten():totable()) + -- only error if we're going deep enough to flatten a dict-like table + matches(flat_err, pcall_err(nested_non_lists.flatten, nested_non_lists, math.huge)) end) it('handles map-like tables', function() @@ -385,9 +521,12 @@ describe('vim.iter', function() }, } - local output = vim.iter(map):map(function(key, value) - return { [key] = value.file } - end):totable() + local output = vim + .iter(map) + :map(function(key, value) + return { [key] = value.file } + end) + :totable() table.sort(output, function(a, b) return next(a) < next(b) diff --git a/test/functional/lua/json_spec.lua b/test/functional/lua/json_spec.lua index 25fdb48eea..d348e2de3c 100644 --- a/test/functional/lua/json_spec.lua +++ b/test/functional/lua/json_spec.lua @@ -16,40 +16,44 @@ describe('vim.json.decode()', function() end) it('validation', function() - eq('Expected object key string but found invalid token at character 2', - pcall_err(exec_lua, [[return vim.json.decode('{a:"b"}')]])) + eq( + 'Expected object key string but found invalid token at character 2', + pcall_err(exec_lua, [[return vim.json.decode('{a:"b"}')]]) + ) end) it('options', function() local jsonstr = '{"arr":[1,2,null],"bar":[3,7],"foo":{"a":"b"},"baz":null}' eq({ - arr = { 1, 2, vim.NIL }, - bar = { 3, 7 }, - baz = vim.NIL, - foo = { a = 'b' }, - }, - exec_lua([[return vim.json.decode(..., {})]], jsonstr)) - eq({ - arr = { 1, 2, vim.NIL }, - bar = { 3, 7 }, - -- baz = nil, - foo = { a = 'b' }, - }, - exec_lua([[return vim.json.decode(..., { luanil = { object = true } })]], jsonstr)) + arr = { 1, 2, vim.NIL }, + bar = { 3, 7 }, + baz = vim.NIL, + foo = { a = 'b' }, + }, exec_lua([[return vim.json.decode(..., {})]], jsonstr)) eq({ - arr = { 1, 2 }, - bar = { 3, 7 }, - baz = vim.NIL, - foo = { a = 'b' }, - }, - exec_lua([[return vim.json.decode(..., { luanil = { array = true } })]], jsonstr)) + arr = { 1, 2, vim.NIL }, + bar = { 3, 7 }, + -- baz = nil, + foo = { a = 'b' }, + }, exec_lua([[return vim.json.decode(..., { luanil = { object = true } })]], jsonstr)) eq({ + arr = { 1, 2 }, + bar = { 3, 7 }, + baz = vim.NIL, + foo = { a = 'b' }, + }, exec_lua([[return vim.json.decode(..., { luanil = { array = true } })]], jsonstr)) + eq( + { arr = { 1, 2 }, bar = { 3, 7 }, -- baz = nil, foo = { a = 'b' }, }, - exec_lua([[return vim.json.decode(..., { luanil = { array = true, object = true } })]], jsonstr)) + exec_lua( + [[return vim.json.decode(..., { luanil = { array = true, object = true } })]], + jsonstr + ) + ) end) it('parses integer numbers', function() @@ -96,11 +100,15 @@ describe('vim.json.decode()', function() end) it('parses containers', function() - eq({1}, exec_lua([[return vim.json.decode('[1]')]])) - eq({vim.NIL, 1}, exec_lua([[return vim.json.decode('[null, 1]')]])) - eq({['1']=2}, exec_lua([[return vim.json.decode('{"1": 2}')]])) - eq({['1']=2, ['3']={{['4']={['5']={{}, 1}}}}}, - exec_lua([[return vim.json.decode('{"1": 2, "3": [{"4": {"5": [ [], 1]}}]}')]])) + eq({ 1 }, exec_lua([[return vim.json.decode('[1]')]])) + eq({ vim.NIL, 1 }, exec_lua([[return vim.json.decode('[null, 1]')]])) + eq({ ['1'] = 2 }, exec_lua([[return vim.json.decode('{"1": 2}')]])) + eq( + { ['1'] = 2, ['3'] = { { ['4'] = { ['5'] = { {}, 1 } } } } }, + exec_lua([[return vim.json.decode('{"1": 2, "3": [{"4": {"5": [ [], 1]}}]}')]]) + ) + -- Empty string is a valid key. #20757 + eq({ [''] = 42 }, exec_lua([[return vim.json.decode('{"": 42}')]])) end) it('parses strings properly', function() @@ -109,8 +117,8 @@ describe('vim.json.decode()', function() eq('\\/"\t\b\n\r\f', exec_lua([=[return vim.json.decode([["\\\/\"\t\b\n\r\f"]])]=])) eq('/a', exec_lua([=[return vim.json.decode([["\/a"]])]=])) -- Unicode characters: 2-byte, 3-byte - eq('«',exec_lua([=[return vim.json.decode([["«"]])]=])) - eq('ફ',exec_lua([=[return vim.json.decode([["ફ"]])]=])) + eq('«', exec_lua([=[return vim.json.decode([["«"]])]=])) + eq('ફ', exec_lua([=[return vim.json.decode([["ફ"]])]=])) end) it('parses surrogate pairs properly', function() @@ -118,11 +126,11 @@ describe('vim.json.decode()', function() end) it('accepts all spaces in every position where space may be put', function() - local s = ' \t\n\r \t\r\n \n\t\r \n\r\t \r\t\n \r\n\t\t \n\r\t \r\n\t\n \r\t\n\r \t\r \n\t\r\n \n \t\r\n \r\t\n\t \r\n\t\r \n\r \t\n\r\t \r \t\n\r \n\t\r\t \n\r\t\n \r\n \t\r\n\t' + local s = + ' \t\n\r \t\r\n \n\t\r \n\r\t \r\t\n \r\n\t\t \n\r\t \r\n\t\n \r\t\n\r \t\r \n\t\r\n \n \t\r\n \r\t\n\t \r\n\t\r \n\r \t\n\r\t \r \t\n\r \n\t\r\t \n\r\t\n \r\n \t\r\n\t' local str = ('%s{%s"key"%s:%s[%s"val"%s,%s"val2"%s]%s,%s"key2"%s:%s1%s}%s'):gsub('%%s', s) - eq({key={'val', 'val2'}, key2=1}, exec_lua([[return vim.json.decode(...)]], str)) + eq({ key = { 'val', 'val2' }, key2 = 1 }, exec_lua([[return vim.json.decode(...)]], str)) end) - end) describe('vim.json.encode()', function() @@ -161,10 +169,11 @@ describe('vim.json.encode()', function() it('dumps dictionaries', function() eq('{}', exec_lua([[return vim.json.encode(vim.empty_dict())]])) eq('{"d":[]}', exec_lua([[return vim.json.encode({d={}})]])) + -- Empty string is a valid key. #20757 + eq('{"":42}', exec_lua([[return vim.json.encode({['']=42})]])) end) it('dumps vim.NIL', function() eq('null', exec_lua([[return vim.json.encode(vim.NIL)]])) end) - end) diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua index 34c36b04ef..4e42a18405 100644 --- a/test/functional/lua/loader_spec.lua +++ b/test/functional/lua/loader_spec.lua @@ -3,43 +3,77 @@ local helpers = require('test.functional.helpers')(after_each) local exec_lua = helpers.exec_lua local command = helpers.command +local clear = helpers.clear local eq = helpers.eq describe('vim.loader', function() - before_each(helpers.clear) + before_each(clear) + + it('can work in compatibility with --luamod-dev #27413', function() + clear({ args = { '--luamod-dev' } }) + exec_lua [[ + vim.loader.enable() + + require("vim.fs") + + -- try to load other vim submodules as well (Nvim Lua stdlib) + for key, _ in pairs(vim._submodules) do + local modname = 'vim.' .. key -- e.g. "vim.fs" + + local lhs = vim[key] + local rhs = require(modname) + assert( + lhs == rhs, + ('%s != require("%s"), %s != %s'):format(modname, modname, tostring(lhs), tostring(rhs)) + ) + end + ]] + end) it('handles changing files (#23027)', function() - exec_lua[[ + exec_lua [[ vim.loader.enable() ]] local tmp = helpers.tmpname() command('edit ' .. tmp) - eq(1, exec_lua([[ + eq( + 1, + exec_lua( + [[ vim.api.nvim_buf_set_lines(0, 0, -1, true, {'_G.TEST=1'}) vim.cmd.write() loadfile(...)() return _G.TEST - ]], tmp)) + ]], + tmp + ) + ) -- fs latency - helpers.sleep(10) + vim.uv.sleep(10) - eq(2, exec_lua([[ + eq( + 2, + exec_lua( + [[ vim.api.nvim_buf_set_lines(0, 0, -1, true, {'_G.TEST=2'}) vim.cmd.write() loadfile(...)() return _G.TEST - ]], tmp)) + ]], + tmp + ) + ) end) it('handles % signs in modpath (#24491)', function() - exec_lua[[ + exec_lua [[ vim.loader.enable() ]] - local tmp1, tmp2 = (function (t) + local tmp1, tmp2 = (function(t) assert(os.remove(t)) assert(helpers.mkdir(t)) assert(helpers.mkdir(t .. '/%')) diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua index c0924fa0c0..71eaf29009 100644 --- a/test/functional/lua/loop_spec.lua +++ b/test/functional/lua/loop_spec.lua @@ -1,10 +1,10 @@ -- Test suite for testing interactions with API bindings local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local funcs = helpers.funcs -local meths = helpers.meths +local fn = helpers.fn +local api = helpers.api local clear = helpers.clear -local sleep = helpers.sleep +local sleep = vim.uv.sleep local feed = helpers.feed local eq = helpers.eq local eval = helpers.eval @@ -15,23 +15,20 @@ local retry = helpers.retry before_each(clear) describe('vim.uv', function() - it('version', function() - assert(funcs.luaeval('vim.uv.version()')>=72961, "libuv version too old") - matches("(%d+)%.(%d+)%.(%d+)", funcs.luaeval('vim.uv.version_string()')) + assert(fn.luaeval('vim.uv.version()') >= 72961, 'libuv version too old') + matches('(%d+)%.(%d+)%.(%d+)', fn.luaeval('vim.uv.version_string()')) end) it('timer', function() exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {}) - local code=[[ - local uv = vim.uv - + local code = [[ local touch = 0 local function wait(ms) local this = coroutine.running() assert(this) - local timer = uv.new_timer() + local timer = vim.uv.new_timer() timer:start(ms, 0, vim.schedule_wrap(function () timer:close() touch = touch + 1 @@ -51,24 +48,24 @@ describe('vim.uv', function() end)() ]] - eq(0, meths.get_var('coroutine_cnt')) + eq(0, api.nvim_get_var('coroutine_cnt')) exec_lua(code) retry(2, nil, function() sleep(50) - eq(2, meths.get_var('coroutine_cnt')) + eq(2, api.nvim_get_var('coroutine_cnt')) end) - eq(3, meths.get_var('coroutine_cnt_1')) + eq(3, api.nvim_get_var('coroutine_cnt_1')) end) it('is API safe', function() - local screen = Screen.new(50,10) + local screen = Screen.new(50, 10) screen:attach() screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, - [5] = {bold = true}, + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { bold = true, reverse = true }, + [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, + [5] = { bold = true }, }) -- deferred API functions are disabled, as their safety can't be guaranteed @@ -96,7 +93,7 @@ describe('vim.uv', function() ]]) feed('<cr>') eq(false, eval("get(g:, 'valid', v:false)")) - eq(true, exec_lua("return _G.is_fast")) + eq(true, exec_lua('return _G.is_fast')) -- callbacks can be scheduled to be executed in the main event loop -- where the entire API is available @@ -112,18 +109,11 @@ describe('vim.uv', function() screen:expect([[ ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*8 howdy | ]]) eq(true, eval("get(g:, 'valid', v:false)")) - eq(false, exec_lua("return _G.is_fast")) + eq(false, exec_lua('return _G.is_fast')) -- fast (not deferred) API functions are allowed to be called directly exec_lua([[ @@ -137,17 +127,10 @@ describe('vim.uv', function() ]]) screen:expect([[ sneaky^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*8 {5:-- INSERT --} | ]]) - eq({blocking=false, mode='n'}, exec_lua("return _G.mode")) + eq({ blocking = false, mode = 'n' }, exec_lua('return _G.mode')) end) it("is equal to require('luv')", function() diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index dfbd2fb18b..b28cfa4dd2 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -7,12 +7,12 @@ local exc_exec = helpers.exc_exec local remove_trace = helpers.remove_trace local exec_lua = helpers.exec_lua local command = helpers.command -local meths = helpers.meths -local funcs = helpers.funcs +local api = helpers.api +local fn = helpers.fn local clear = helpers.clear local eval = helpers.eval local feed = helpers.feed -local NIL = helpers.NIL +local NIL = vim.NIL local eq = helpers.eq before_each(clear) @@ -39,7 +39,7 @@ describe('luaeval()', function() describe('second argument', function() it('is successfully received', function() local t = {t=true, f=false, --[[n=NIL,]] d={l={'string', 42, 0.42}}} - eq(t, funcs.luaeval("_A", t)) + eq(t, fn.luaeval("_A", t)) -- Not tested: nil, funcrefs, returned object identity: behaviour will -- most likely change. end) @@ -47,39 +47,37 @@ describe('luaeval()', function() describe('lua values', function() it('are successfully transformed', function() eq({n=1, f=1.5, s='string', l={4, 2}}, - funcs.luaeval('{n=1, f=1.5, s="string", l={4, 2}}')) + fn.luaeval('{n=1, f=1.5, s="string", l={4, 2}}')) -- Not tested: nil inside containers: behaviour will most likely change. - eq(NIL, funcs.luaeval('nil')) - eq({['']=1}, funcs.luaeval('{[""]=1}')) + eq(NIL, fn.luaeval('nil')) + eq({['']=1}, fn.luaeval('{[""]=1}')) end) end) describe('recursive lua values', function() it('are successfully transformed', function() command('lua rawset(_G, "d", {})') command('lua rawset(d, "d", d)') - eq('\n{\'d\': {...@0}}', funcs.execute('echo luaeval("d")')) + eq('\n{\'d\': {...@0}}', fn.execute('echo luaeval("d")')) command('lua rawset(_G, "l", {})') command('lua table.insert(l, l)') - eq('\n[[...@0]]', funcs.execute('echo luaeval("l")')) + eq('\n[[...@0]]', fn.execute('echo luaeval("l")')) end) end) describe('strings with NULs', function() it('are successfully converted to blobs', function() command([[let s = luaeval('"\0"')]]) - eq('\000', meths.get_var('s')) + eq('\000', api.nvim_get_var('s')) end) - it('are successfully converted to special dictionaries in table keys', - function() + it('are successfully converted to special dictionaries in table keys', function() command([[let d = luaeval('{["\0"]=1}')]]) - eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n'}}, 1}}}, meths.get_var('d')) - eq(1, funcs.eval('d._TYPE is v:msgpack_types.map')) - eq(1, funcs.eval('d._VAL[0][0]._TYPE is v:msgpack_types.string')) + 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')) end) - it('are successfully converted to blobs from a list', - function() + it('are successfully converted to blobs from a list', function() command([[let l = luaeval('{"abc", "a\0b", "c\0d", "def"}')]]) - eq({'abc', 'a\000b', 'c\000d', 'def'}, meths.get_var('l')) + eq({'abc', 'a\000b', 'c\000d', 'def'}, api.nvim_get_var('l')) end) end) @@ -88,62 +86,68 @@ describe('luaeval()', function() it('correctly evaluates scalars', function() -- Also test method call (->) syntax - eq(1, funcs.luaeval('1')) + eq(1, fn.luaeval('1')) eq(0, eval('"1"->luaeval()->type()')) - eq(1.5, funcs.luaeval('1.5')) + eq(1.5, fn.luaeval('1.5')) eq(5, eval('"1.5"->luaeval()->type()')) - eq("test", funcs.luaeval('"test"')) + eq("test", fn.luaeval('"test"')) eq(1, eval('"\'test\'"->luaeval()->type()')) - eq('', funcs.luaeval('""')) - eq('\000', funcs.luaeval([['\0']])) - eq('\000\n\000', funcs.luaeval([['\0\n\0']])) + eq('', fn.luaeval('""')) + eq('\000', fn.luaeval([['\0']])) + eq('\000\n\000', fn.luaeval([['\0\n\0']])) eq(10, eval([[type(luaeval("'\\0\\n\\0'"))]])) - eq(true, funcs.luaeval('true')) - eq(false, funcs.luaeval('false')) - eq(NIL, funcs.luaeval('nil')) + eq(true, fn.luaeval('true')) + eq(false, fn.luaeval('false')) + eq(NIL, fn.luaeval('nil')) end) it('correctly evaluates containers', function() - eq({}, funcs.luaeval('{}')) + eq({}, fn.luaeval('{}')) eq(3, eval('type(luaeval("{}"))')) - eq({test=1, foo=2}, funcs.luaeval('{test=1, foo=2}')) + eq({test=1, foo=2}, fn.luaeval('{test=1, foo=2}')) eq(4, eval('type(luaeval("{test=1, foo=2}"))')) - eq({4, 2}, funcs.luaeval('{4, 2}')) + eq({4, 2}, fn.luaeval('{4, 2}')) eq(3, eval('type(luaeval("{4, 2}"))')) + eq({NIL, 20}, fn.luaeval('{[2] = 20}')) + eq(3, eval('type(luaeval("{[2] = 20}"))')) + + eq({10, NIL, 30}, fn.luaeval('{[1] = 10, [3] = 30}')) + eq(3, eval('type(luaeval("{[1] = 10, [3] = 30}"))')) + local level = 30 - eq(nested_by_level[level].o, funcs.luaeval(nested_by_level[level].s)) + eq(nested_by_level[level].o, fn.luaeval(nested_by_level[level].s)) eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}}, - funcs.luaeval([[{['\0\n\0']='\0\n\0\0'}]])) + fn.luaeval([[{['\0\n\0']='\0\n\0\0'}]])) 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]])) eq({nested={{_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}}}}, - funcs.luaeval([[{nested={{['\0\n\0']='\0\n\0\0'}}}]])) + fn.luaeval([[{nested={{['\0\n\0']='\0\n\0\0'}}}]])) end) it('correctly passes scalars as argument', function() - eq(1, funcs.luaeval('_A', 1)) - eq(1.5, funcs.luaeval('_A', 1.5)) - eq('', funcs.luaeval('_A', '')) - eq('test', funcs.luaeval('_A', 'test')) - eq(NIL, funcs.luaeval('_A', NIL)) - eq(true, funcs.luaeval('_A', true)) - eq(false, funcs.luaeval('_A', false)) + 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)) end) it('correctly passes containers as argument', function() - eq({}, funcs.luaeval('_A', {})) - eq({test=1}, funcs.luaeval('_A', {test=1})) - eq({4, 2}, funcs.luaeval('_A', {4, 2})) + eq({}, fn.luaeval('_A', {})) + eq({test=1}, fn.luaeval('_A', {test=1})) + eq({4, 2}, fn.luaeval('_A', {4, 2})) local level = 28 - eq(nested_by_level[level].o, funcs.luaeval('_A', nested_by_level[level].o)) + eq(nested_by_level[level].o, fn.luaeval('_A', nested_by_level[level].o)) end) local function sp(typ, val) @@ -158,7 +162,7 @@ describe('luaeval()', function() return sp('map', '[' .. val .. ']') end local function luaevalarg(argexpr, expr) - return eval(([=[ + return eval((([=[ [ extend(g:, {'_ret': luaeval(%s, %s)})._ret, type(g:_ret)==type({})&&has_key(g:_ret, '_TYPE') @@ -168,7 +172,7 @@ describe('luaeval()', function() get(g:_ret, '_VAL', g:_ret) ] : [0, g:_ret]][1] - ]=]):format(expr or '"_A"', argexpr):gsub('\n', '')) + ]=]):format(expr or '"_A"', argexpr):gsub('\n', ''))) end it('correctly passes special dictionaries', function() @@ -182,7 +186,7 @@ describe('luaeval()', function() end) it('issues an error in some cases', function() - eq("Vim(call):E5100: Cannot convert given lua table: table should either have a sequence of positive integer keys or contain only string keys", + eq("Vim(call):E5100: Cannot convert given lua table: table should contain either only integer keys or only string keys", exc_exec('call luaeval("{1, foo=2}")')) startswith("Vim(call):E5107: Error loading lua [string \"luaeval()\"]:", @@ -395,26 +399,26 @@ describe('luaeval()', function() eq(4, eval([[type(luaeval('{[vim.type_idx]=vim.types.dictionary}'))]])) eq(3, eval([[type(luaeval('{[vim.type_idx]=vim.types.array}'))]])) - eq({}, funcs.luaeval('{[vim.type_idx]=vim.types.array}')) + eq({}, fn.luaeval('{[vim.type_idx]=vim.types.array}')) -- Presence of type_idx makes Vim ignore some keys - eq({42}, funcs.luaeval('{[vim.type_idx]=vim.types.array, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) - eq({foo=2}, funcs.luaeval('{[vim.type_idx]=vim.types.dictionary, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) - eq(10, funcs.luaeval('{[vim.type_idx]=vim.types.float, [vim.val_idx]=10, [5]=1, foo=2, [1]=42}')) + 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}')) -- The following should not crash - eq({}, funcs.luaeval('{[vim.type_idx]=vim.types.dictionary}')) + eq({}, fn.luaeval('{[vim.type_idx]=vim.types.dictionary}')) end) it('correctly converts self-containing containers', function() - meths.set_var('l', {}) + api.nvim_set_var('l', {}) 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])')) - meths.set_var('d', {foo=42}) + api.nvim_set_var('d', {foo=42}) eval('extend(d, {"d": d})') eq(true, eval('luaeval("_A == _A.d", d)')) eq(true, eval('luaeval("_A[1] == _A[1].d", [d])')) @@ -437,7 +441,7 @@ describe('luaeval()', function() local s = ('x'):rep(65536) eq('Vim(call):E5107: Error loading lua [string "luaeval()"]:1: unexpected symbol near \')\'', exc_exec([[call luaeval("(']] .. s ..[[' + )")]])) - eq(s, funcs.luaeval('"' .. s .. '"')) + eq(s, fn.luaeval('"' .. s .. '"')) end) end) @@ -474,7 +478,7 @@ describe('v:lua', 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")')) - eq("hey eval", meths.get_current_line()) + eq("hey eval", api.nvim_get_current_line()) eq("string: abc", eval('v:lua.mymod.whatis(0z616263)')) eq("string: ", eval('v:lua.mymod.whatis(v:_null_blob)')) @@ -490,7 +494,7 @@ describe('v:lua', function() eq("boop", exec_lua([[return _G.val]])) eq(NIL, eval('"there"->v:lua.mymod.noisy()')) - eq("hey there", meths.get_current_line()) + eq("hey there", api.nvim_get_current_line()) 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)", @@ -499,7 +503,7 @@ describe('v:lua', function() it('works in :call', function() command(":call v:lua.mymod.noisy('command')") - eq("hey command", meths.get_current_line()) + eq("hey command", api.nvim_get_current_line()) eq("Vim(call):E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)", pcall_err(command, 'call v:lua.mymod.crashy()')) end) @@ -514,21 +518,19 @@ describe('v:lua', function() [5] = {bold = true, foreground = Screen.colors.SeaGreen4}, }) screen:attach() - meths.set_option_value('omnifunc', 'v:lua.mymod.omni', {}) + api.nvim_set_option_value('omnifunc', 'v:lua.mymod.omni', {}) 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: }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*3 {4:-- Omni completion (^O^N^P) }{5:match 1 of 3} | ]]} - meths.set_option_value('operatorfunc', 'v:lua.mymod.noisy', {}) + api.nvim_set_option_value('operatorfunc', 'v:lua.mymod.noisy', {}) feed('<Esc>g@g@') - eq("hey line", meths.get_current_line()) + eq("hey line", api.nvim_get_current_line()) end) it('supports packages', function() @@ -536,6 +538,8 @@ describe('v:lua', function() eq('\tbadval', eval("v:lua.require'leftpad'('badval')")) eq(9003, eval("v:lua.require'bar'.doit()")) eq(9004, eval("v:lua.require'baz-quux'.doit()")) + 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()")) end) it('throw errors for invalid use', function() diff --git a/test/functional/lua/mpack_spec.lua b/test/functional/lua/mpack_spec.lua index cc788ed8bb..0b6a6d60bd 100644 --- a/test/functional/lua/mpack_spec.lua +++ b/test/functional/lua/mpack_spec.lua @@ -8,16 +8,22 @@ local exec_lua = helpers.exec_lua describe('lua vim.mpack', function() before_each(clear) it('encodes vim.NIL', function() - eq({true, true, true, true}, exec_lua [[ + eq( + { true, true, true, true }, + exec_lua [[ local var = vim.mpack.decode(vim.mpack.encode({33, vim.NIL, 77})) return {var[1]==33, var[2]==vim.NIL, var[3]==77, var[4]==nil} - ]]) + ]] + ) end) it('encodes vim.empty_dict()', function() - eq({{{}, "foo", {}}, true, false}, exec_lua [[ + eq( + { { {}, 'foo', {} }, true, false }, + exec_lua [[ local var = vim.mpack.decode(vim.mpack.encode({{}, "foo", vim.empty_dict()})) return {var, vim.tbl_islist(var[1]), vim.tbl_islist(var[3])} - ]]) + ]] + ) end) end) diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index c08f3d06a9..ecbdde3bfd 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -3,11 +3,11 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local eq = helpers.eq -local NIL = helpers.NIL +local NIL = vim.NIL local feed = helpers.feed local clear = helpers.clear -local funcs = helpers.funcs -local meths = helpers.meths +local fn = helpers.fn +local api = helpers.api local command = helpers.command local write_file = helpers.write_file local exec_capture = helpers.exec_capture @@ -25,15 +25,15 @@ end) describe('print', function() it('returns nothing', function() - eq(NIL, funcs.luaeval('print("abc")')) - eq(0, funcs.luaeval('select("#", print("abc"))')) + eq(NIL, fn.luaeval('print("abc")')) + eq(0, fn.luaeval('select("#", print("abc"))')) end) it('allows catching printed text with :execute', function() - eq('\nabc', funcs.execute('lua print("abc")')) - eq('\nabc', funcs.execute('luado print("abc")')) - eq('\nabc', funcs.execute('call luaeval("print(\'abc\')")')) + eq('\nabc', fn.execute('lua print("abc")')) + eq('\nabc', fn.execute('luado print("abc")')) + eq('\nabc', fn.execute('call luaeval("print(\'abc\')")')) write_file(fname, 'print("abc")') - eq('\nabc', funcs.execute('luafile ' .. fname)) + eq('\nabc', fn.execute('luafile ' .. fname)) eq('abc', exec_capture('lua print("abc")')) eq('abc', exec_capture('luado print("abc")')) @@ -42,25 +42,36 @@ describe('print', function() eq('abc', exec_capture('luafile ' .. fname)) end) it('handles errors in __tostring', function() - write_file(fname, [[ + write_file( + fname, + [[ local meta_nilerr = { __tostring = function() error(nil) end } local meta_abcerr = { __tostring = function() error("abc") end } local meta_tblout = { __tostring = function() return {"TEST"} end } v_nilerr = setmetatable({}, meta_nilerr) v_abcerr = setmetatable({}, meta_abcerr) v_tblout = setmetatable({}, meta_tblout) - ]]) + ]] + ) eq('', exec_capture('luafile ' .. fname)) -- TODO(bfredl): these look weird, print() should not use "E5114:" style errors.. - eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: [NULL]', - pcall_err(command, 'lua print("foo", v_nilerr, "bar")')) - eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc', - pcall_err(command, 'lua print("foo", v_abcerr, "bar")')) - eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>', - pcall_err(command, 'lua print("foo", v_tblout, "bar")')) + eq( + 'Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: [NULL]', + pcall_err(command, 'lua print("foo", v_nilerr, "bar")') + ) + eq( + 'Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc', + pcall_err(command, 'lua print("foo", v_abcerr, "bar")') + ) + eq( + 'Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>', + pcall_err(command, 'lua print("foo", v_tblout, "bar")') + ) end) it('coerces error values into strings', function() - write_file(fname, [[ + write_file( + fname, + [[ function string_error() error("my mistake") end function number_error() error(1234) end function nil_error() error(nil) end @@ -82,27 +93,35 @@ describe('print', function() }) error(err) end - ]]) + ]] + ) eq('', exec_capture('luafile ' .. fname)) - eq('Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:1: my mistake', - pcall_err(command, 'lua string_error()')) - eq('Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:2: 1234', - pcall_err(command, 'lua number_error()')) - eq('Vim(lua):E5108: Error executing lua [NULL]', - pcall_err(command, 'lua nil_error()')) - eq('Vim(lua):E5108: Error executing lua [NULL]', - pcall_err(command, 'lua table_error()')) - eq('Vim(lua):E5108: Error executing lua Internal Error [11234] my mistake', - pcall_err(command, 'lua custom_error()')) - eq('Vim(lua):E5108: Error executing lua [NULL]', - pcall_err(command, 'lua bad_custom_error()')) + eq( + 'Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:1: my mistake', + pcall_err(command, 'lua string_error()') + ) + eq( + 'Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:2: 1234', + pcall_err(command, 'lua number_error()') + ) + eq('Vim(lua):E5108: Error executing lua [NULL]', pcall_err(command, 'lua nil_error()')) + eq('Vim(lua):E5108: Error executing lua [NULL]', pcall_err(command, 'lua table_error()')) + eq( + 'Vim(lua):E5108: Error executing lua Internal Error [11234] my mistake', + pcall_err(command, 'lua custom_error()') + ) + eq('Vim(lua):E5108: Error executing lua [NULL]', pcall_err(command, 'lua bad_custom_error()')) end) it('prints strings with NULs and NLs correctly', function() - meths.set_option_value('more', true, {}) - eq('abc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT\n', - exec_capture([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\n")]])) - eq('abc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT^@', - exec_capture([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\0")]])) + api.nvim_set_option_value('more', true, {}) + eq( + 'abc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT\n', + exec_capture([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\n")]]) + ) + eq( + 'abc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT^@', + exec_capture([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\0")]]) + ) eq('T^@', exec_capture([[lua print("T\0")]])) eq('T\n', exec_capture([[lua print("T\n")]])) end) @@ -114,7 +133,8 @@ describe('print', function() eq('abc def', exec_capture('lua print("abc", "", "def")')) end) it('defers printing in luv event handlers', function() - exec_lua([[ + exec_lua( + [[ local cmd = ... function test() local timer = vim.uv.new_timer() @@ -133,7 +153,9 @@ describe('print', function() print("very slow") vim.api.nvim_command("sleep 1m") -- force deferred event processing end - ]], (is_os('win') and "timeout 1") or "sleep 0.1") + ]], + (is_os('win') and 'timeout 1') or 'sleep 0.1' + ) eq('very slow\nvery fast', exec_capture('lua test()')) end) @@ -141,33 +163,34 @@ describe('print', function() local 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}, + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { bold = true, foreground = Screen.colors.SeaGreen }, + [2] = { bold = true, reverse = true }, }) feed([[:lua print('\na')<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([[:lua print('b\n\nc')<CR>]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| + {0:~ }|*2 {2: }| b | | c | {1:Press ENTER or type command to continue}^ | - ]]} + ]], + } end) end) @@ -178,10 +201,10 @@ describe('debug.debug', function() screen = Screen.new() screen:attach() screen:set_default_attr_ids { - [0] = {bold=true, foreground=255}; - [1] = {bold = true, reverse = true}; - E = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}; - cr = {bold = true, foreground = Screen.colors.SeaGreen4}; + [0] = { bold = true, foreground = 255 }, + [1] = { bold = true, reverse = true }, + E = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + cr = { bold = true, foreground = Screen.colors.SeaGreen4 }, } end) @@ -194,33 +217,19 @@ describe('debug.debug', function() end ]]) feed(':lua Test()\n') - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*10 {1: }| nil | lua_debug> ^ | - ]]} + ]], + } feed('print("TEST")\n') screen:expect([[ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*8 {1: }| nil | lua_debug> print("TEST") | @@ -228,10 +237,10 @@ describe('debug.debug', function() lua_debug> ^ | ]]) feed('<C-c>') - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| + {0:~ }|*2 {1: }| nil | lua_debug> print("TEST") | @@ -243,31 +252,21 @@ describe('debug.debug', function() {E: [string ":lua"]:5: in function 'Test'} | {E: [string ":lua"]:1: in main chunk} | Interrupt: {cr:Press ENTER or type command to continue}^ | - ]]} + ]], + } feed('<C-l>:lua Test()\n') screen:expect([[ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*10 {1: }| nil | lua_debug> ^ | ]]) feed('\n') - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*4 {1: }| nil | lua_debug> | @@ -277,56 +276,39 @@ describe('debug.debug', function() {E: [string ":lua"]:5: in function 'Test'} | {E: [string ":lua"]:1: in main chunk} | {cr:Press ENTER or type command to continue}^ | - ]]} + ]], + } end) it("can be safely exited with 'cont'", function() feed('<cr>') feed(':lua debug.debug() print("x")<cr>') - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*12 lua_debug> ^ | - ]]} + ]], + } - feed("conttt<cr>") -- misspelled cont; invalid syntax - screen:expect{grid=[[ + feed('conttt<cr>') -- misspelled cont; invalid syntax + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*8 {1: }| lua_debug> conttt | {E:E5115: Error while loading debug string: (debug comma}| {E:nd):1: '=' expected near '<eof>'} | lua_debug> ^ | - ]]} + ]], + } - feed("cont<cr>") -- exactly "cont", exit now - screen:expect{grid=[[ + feed('cont<cr>') -- exactly "cont", exit now + screen:expect { + grid = [[ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*6 {1: }| lua_debug> conttt | {E:E5115: Error while loading debug string: (debug comma}| @@ -334,41 +316,33 @@ describe('debug.debug', function() lua_debug> cont | x | {cr:Press ENTER or type command to continue}^ | - ]]} + ]], + } feed('<cr>') - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*12 | - ]]} + ]], + } end) end) describe('os.getenv', function() it('returns nothing for undefined env var', function() - eq(NIL, funcs.luaeval('os.getenv("XTEST_1")')) + eq(NIL, fn.luaeval('os.getenv("XTEST_1")')) end) it('returns env var set by the parent process', function() local value = 'foo' - clear({env = {['XTEST_1']=value}}) - eq(value, funcs.luaeval('os.getenv("XTEST_1")')) + clear({ env = { ['XTEST_1'] = value } }) + eq(value, fn.luaeval('os.getenv("XTEST_1")')) end) it('returns env var set by let', function() local value = 'foo' - meths.command('let $XTEST_1 = "'..value..'"') - eq(value, funcs.luaeval('os.getenv("XTEST_1")')) + command('let $XTEST_1 = "' .. value .. '"') + eq(value, fn.luaeval('os.getenv("XTEST_1")')) end) end) @@ -376,6 +350,6 @@ end) -- luajit or PUC lua 5.1. describe('bit module', function() it('works', function() - eq (9, exec_lua [[ return require'bit'.band(11,13) ]]) + eq(9, exec_lua [[ return require'bit'.band(11,13) ]]) end) end) diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index 0b8b2234db..6f36ccfb9e 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -4,7 +4,7 @@ local clear = helpers.clear local eq = helpers.eq local eval = helpers.eval local exec = helpers.exec -local funcs = helpers.funcs +local fn = helpers.fn local mkdir_p = helpers.mkdir_p local rmdir = helpers.rmdir local write_file = helpers.write_file @@ -15,8 +15,8 @@ describe('runtime:', function() local init = 'dummy_init.lua' setup(function() - io.open(init, 'w'):close() -- touch init file - clear{args = {'-u', init}} + io.open(init, 'w'):close() -- touch init file + clear { args = { '-u', init } } exec('set rtp+=' .. plug_dir) exec([[ set shell=doesnotexist @@ -45,11 +45,11 @@ describe('runtime:', function() end) it('lua colorschemes work and are included in cmdline completion', function() - local colorscheme_file = table.concat({colorscheme_folder, 'new_colorscheme.lua'}, sep) + local colorscheme_file = table.concat({ colorscheme_folder, 'new_colorscheme.lua' }, sep) write_file(colorscheme_file, [[vim.g.lua_colorscheme = 1]]) - eq({'new_colorscheme'}, funcs.getcompletion('new_c', 'color')) - eq({'colors/new_colorscheme.lua'}, funcs.getcompletion('colors/new_c', 'runtime')) + eq({ 'new_colorscheme' }, fn.getcompletion('new_c', 'color')) + eq({ 'colors/new_colorscheme.lua' }, fn.getcompletion('colors/new_c', 'runtime')) exec('colorscheme new_colorscheme') @@ -64,48 +64,60 @@ describe('runtime:', function() end) exec('set pp+=' .. pack_dir) - local pack_opt_dir = table.concat({pack_dir, 'pack', 'some_name', 'opt'}, sep) - local colors_opt_dir = table.concat({pack_opt_dir, 'some_pack', 'colors'}, sep) + local pack_opt_dir = table.concat({ pack_dir, 'pack', 'some_name', 'opt' }, sep) + local colors_opt_dir = table.concat({ pack_opt_dir, 'some_pack', 'colors' }, sep) mkdir_p(colors_opt_dir) - local after_colorscheme_folder = table.concat({plug_dir, 'after', 'colors'}, sep) + local after_colorscheme_folder = table.concat({ plug_dir, 'after', 'colors' }, sep) mkdir_p(after_colorscheme_folder) exec('set rtp+=' .. plug_dir .. '/after') - write_file(table.concat({colors_opt_dir, 'new_colorscheme.lua'}, sep), - [[vim.g.colorscheme = 'lua_pp']]) + write_file( + table.concat({ colors_opt_dir, 'new_colorscheme.lua' }, sep), + [[vim.g.colorscheme = 'lua_pp']] + ) exec('colorscheme new_colorscheme') eq('lua_pp', eval('g:colorscheme')) - write_file(table.concat({colors_opt_dir, 'new_colorscheme.vim'}, sep), - [[let g:colorscheme = 'vim_pp']]) + write_file( + table.concat({ colors_opt_dir, 'new_colorscheme.vim' }, sep), + [[let g:colorscheme = 'vim_pp']] + ) exec('colorscheme new_colorscheme') eq('vim_pp', eval('g:colorscheme')) - write_file(table.concat({after_colorscheme_folder, 'new_colorscheme.lua'}, sep), - [[vim.g.colorscheme = 'lua_rtp_after']]) + write_file( + table.concat({ after_colorscheme_folder, 'new_colorscheme.lua' }, sep), + [[vim.g.colorscheme = 'lua_rtp_after']] + ) exec('colorscheme new_colorscheme') eq('lua_rtp_after', eval('g:colorscheme')) - write_file(table.concat({after_colorscheme_folder, 'new_colorscheme.vim'}, sep), - [[let g:colorscheme = 'vim_rtp_after']]) + write_file( + table.concat({ after_colorscheme_folder, 'new_colorscheme.vim' }, sep), + [[let g:colorscheme = 'vim_rtp_after']] + ) exec('colorscheme new_colorscheme') eq('vim_rtp_after', eval('g:colorscheme')) - write_file(table.concat({colorscheme_folder, 'new_colorscheme.lua'}, sep), - [[vim.g.colorscheme = 'lua_rtp']]) + write_file( + table.concat({ colorscheme_folder, 'new_colorscheme.lua' }, sep), + [[vim.g.colorscheme = 'lua_rtp']] + ) exec('colorscheme new_colorscheme') eq('lua_rtp', eval('g:colorscheme')) - write_file(table.concat({colorscheme_folder, 'new_colorscheme.vim'}, sep), - [[let g:colorscheme = 'vim_rtp']]) + write_file( + table.concat({ colorscheme_folder, 'new_colorscheme.vim' }, sep), + [[let g:colorscheme = 'vim_rtp']] + ) exec('colorscheme new_colorscheme') eq('vim_rtp', eval('g:colorscheme')) end) end) describe('compiler', function() - local compiler_folder = table.concat({plug_dir, 'compiler'}, sep) + local compiler_folder = table.concat({ plug_dir, 'compiler' }, sep) before_each(function() mkdir_p(compiler_folder) end) @@ -114,8 +126,8 @@ describe('runtime:', function() local compiler_file = compiler_folder .. sep .. 'new_compiler.lua' write_file(compiler_file, [[vim.b.lua_compiler = 1]]) - eq({'new_compiler'}, funcs.getcompletion('new_c', 'compiler')) - eq({'compiler/new_compiler.lua'}, funcs.getcompletion('compiler/new_c', 'runtime')) + eq({ 'new_compiler' }, fn.getcompletion('new_c', 'compiler')) + eq({ 'compiler/new_compiler.lua' }, fn.getcompletion('compiler/new_c', 'runtime')) exec('compiler new_compiler') @@ -123,126 +135,189 @@ describe('runtime:', function() end) it("'rtp' order is respected", function() - local after_compiler_folder = table.concat({plug_dir, 'after', 'compiler'}, sep) - mkdir_p(table.concat({compiler_folder, 'new_compiler'}, sep)) - mkdir_p(table.concat({after_compiler_folder, 'new_compiler'}, sep)) + local after_compiler_folder = table.concat({ plug_dir, 'after', 'compiler' }, sep) + mkdir_p(table.concat({ compiler_folder, 'new_compiler' }, sep)) + mkdir_p(table.concat({ after_compiler_folder, 'new_compiler' }, sep)) exec('set rtp+=' .. plug_dir .. '/after') exec('let g:seq = ""') -- A .lua file is loaded after a .vim file if they only differ in extension. -- All files in after/compiler/ are loaded after all files in compiler/. - write_file(table.concat({compiler_folder, 'new_compiler.vim'}, sep), [[let g:seq ..= 'A']]) - write_file(table.concat({compiler_folder, 'new_compiler.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) - write_file(table.concat({after_compiler_folder, 'new_compiler.vim'}, sep), [[let g:seq ..= 'a']]) - write_file(table.concat({after_compiler_folder, 'new_compiler.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) + write_file(table.concat({ compiler_folder, 'new_compiler.vim' }, sep), [[let g:seq ..= 'A']]) + write_file( + table.concat({ compiler_folder, 'new_compiler.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'B']] + ) + write_file( + table.concat({ after_compiler_folder, 'new_compiler.vim' }, sep), + [[let g:seq ..= 'a']] + ) + write_file( + table.concat({ after_compiler_folder, 'new_compiler.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'b']] + ) exec('compiler new_compiler') eq('ABab', eval('g:seq')) end) end) describe('ftplugin', function() - local ftplugin_folder = table.concat({plug_dir, 'ftplugin'}, sep) + local ftplugin_folder = table.concat({ plug_dir, 'ftplugin' }, sep) it('lua ftplugins work and are included in cmdline completion', function() mkdir_p(ftplugin_folder) - local ftplugin_file = table.concat({ftplugin_folder , 'new-ft.lua'}, sep) - write_file(ftplugin_file , [[vim.b.lua_ftplugin = 1]]) + local ftplugin_file = table.concat({ ftplugin_folder, 'new-ft.lua' }, sep) + write_file(ftplugin_file, [[vim.b.lua_ftplugin = 1]]) - eq({'new-ft'}, funcs.getcompletion('new-f', 'filetype')) - eq({'ftplugin/new-ft.lua'}, funcs.getcompletion('ftplugin/new-f', 'runtime')) + eq({ 'new-ft' }, fn.getcompletion('new-f', 'filetype')) + eq({ 'ftplugin/new-ft.lua' }, fn.getcompletion('ftplugin/new-f', 'runtime')) exec [[set filetype=new-ft]] eq(1, eval('b:lua_ftplugin')) end) it("'rtp' order is respected", function() - local after_ftplugin_folder = table.concat({plug_dir, 'after', 'ftplugin'}, sep) - mkdir_p(table.concat({ftplugin_folder, 'new-ft'}, sep)) - mkdir_p(table.concat({after_ftplugin_folder, 'new-ft'}, sep)) + local after_ftplugin_folder = table.concat({ plug_dir, 'after', 'ftplugin' }, sep) + mkdir_p(table.concat({ ftplugin_folder, 'new-ft' }, sep)) + mkdir_p(table.concat({ after_ftplugin_folder, 'new-ft' }, sep)) exec('set rtp+=' .. plug_dir .. '/after') exec('let g:seq = ""') -- A .lua file is loaded after a .vim file if they only differ in extension. -- All files in after/ftplugin/ are loaded after all files in ftplugin/. - write_file(table.concat({ftplugin_folder, 'new-ft.vim'}, sep), [[let g:seq ..= 'A']]) - write_file(table.concat({ftplugin_folder, 'new-ft.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) - write_file(table.concat({ftplugin_folder, 'new-ft_a.vim'}, sep), [[let g:seq ..= 'C']]) - write_file(table.concat({ftplugin_folder, 'new-ft_a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'D']]) - write_file(table.concat({ftplugin_folder, 'new-ft', 'a.vim'}, sep), [[let g:seq ..= 'E']]) - write_file(table.concat({ftplugin_folder, 'new-ft', 'a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'F']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft.vim'}, sep), [[let g:seq ..= 'a']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft_a.vim'}, sep), [[let g:seq ..= 'c']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft_a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'd']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft', 'a.vim'}, sep), [[let g:seq ..= 'e']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft', 'a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'f']]) + write_file(table.concat({ ftplugin_folder, 'new-ft.vim' }, sep), [[let g:seq ..= 'A']]) + write_file( + table.concat({ ftplugin_folder, 'new-ft.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'B']] + ) + write_file(table.concat({ ftplugin_folder, 'new-ft_a.vim' }, sep), [[let g:seq ..= 'C']]) + write_file( + table.concat({ ftplugin_folder, 'new-ft_a.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'D']] + ) + write_file(table.concat({ ftplugin_folder, 'new-ft', 'a.vim' }, sep), [[let g:seq ..= 'E']]) + write_file( + table.concat({ ftplugin_folder, 'new-ft', 'a.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'F']] + ) + write_file(table.concat({ after_ftplugin_folder, 'new-ft.vim' }, sep), [[let g:seq ..= 'a']]) + write_file( + table.concat({ after_ftplugin_folder, 'new-ft.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'b']] + ) + write_file( + table.concat({ after_ftplugin_folder, 'new-ft_a.vim' }, sep), + [[let g:seq ..= 'c']] + ) + write_file( + table.concat({ after_ftplugin_folder, 'new-ft_a.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'd']] + ) + write_file( + table.concat({ after_ftplugin_folder, 'new-ft', 'a.vim' }, sep), + [[let g:seq ..= 'e']] + ) + write_file( + table.concat({ after_ftplugin_folder, 'new-ft', 'a.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'f']] + ) exec('setfiletype new-ft') eq('ABCDEFabcdef', eval('g:seq')) end) it("'rtp' order is respected with 'fileignorecase'", function() exec('set fileignorecase') - local after_ftplugin_folder = table.concat({plug_dir, 'after', 'ftplugin'}, sep) - mkdir_p(table.concat({ftplugin_folder, 'new-ft'}, sep)) - mkdir_p(table.concat({after_ftplugin_folder, 'new-ft'}, sep)) + local after_ftplugin_folder = table.concat({ plug_dir, 'after', 'ftplugin' }, sep) + mkdir_p(table.concat({ ftplugin_folder, 'new-ft' }, sep)) + mkdir_p(table.concat({ after_ftplugin_folder, 'new-ft' }, sep)) exec('set rtp+=' .. plug_dir .. '/after') exec('let g:seq = ""') -- A .lua file is loaded after a .vim file if they only differ in extension. -- All files in after/ftplugin/ are loaded after all files in ftplugin/. - write_file(table.concat({ftplugin_folder, 'new-ft.VIM'}, sep), [[let g:seq ..= 'A']]) - write_file(table.concat({ftplugin_folder, 'new-ft.LUA'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) - write_file(table.concat({ftplugin_folder, 'new-ft_a.vim'}, sep), [[let g:seq ..= 'C']]) - write_file(table.concat({ftplugin_folder, 'new-ft_a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'D']]) - write_file(table.concat({ftplugin_folder, 'new-ft', 'a.VIM'}, sep), [[let g:seq ..= 'E']]) - write_file(table.concat({ftplugin_folder, 'new-ft', 'a.LUA'}, sep), [[vim.g.seq = vim.g.seq .. 'F']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft.vim'}, sep), [[let g:seq ..= 'a']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft_a.VIM'}, sep), [[let g:seq ..= 'c']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft_a.LUA'}, sep), [[vim.g.seq = vim.g.seq .. 'd']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft', 'a.vim'}, sep), [[let g:seq ..= 'e']]) - write_file(table.concat({after_ftplugin_folder, 'new-ft', 'a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'f']]) + write_file(table.concat({ ftplugin_folder, 'new-ft.VIM' }, sep), [[let g:seq ..= 'A']]) + write_file( + table.concat({ ftplugin_folder, 'new-ft.LUA' }, sep), + [[vim.g.seq = vim.g.seq .. 'B']] + ) + write_file(table.concat({ ftplugin_folder, 'new-ft_a.vim' }, sep), [[let g:seq ..= 'C']]) + write_file( + table.concat({ ftplugin_folder, 'new-ft_a.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'D']] + ) + write_file(table.concat({ ftplugin_folder, 'new-ft', 'a.VIM' }, sep), [[let g:seq ..= 'E']]) + write_file( + table.concat({ ftplugin_folder, 'new-ft', 'a.LUA' }, sep), + [[vim.g.seq = vim.g.seq .. 'F']] + ) + write_file(table.concat({ after_ftplugin_folder, 'new-ft.vim' }, sep), [[let g:seq ..= 'a']]) + write_file( + table.concat({ after_ftplugin_folder, 'new-ft.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'b']] + ) + write_file( + table.concat({ after_ftplugin_folder, 'new-ft_a.VIM' }, sep), + [[let g:seq ..= 'c']] + ) + write_file( + table.concat({ after_ftplugin_folder, 'new-ft_a.LUA' }, sep), + [[vim.g.seq = vim.g.seq .. 'd']] + ) + write_file( + table.concat({ after_ftplugin_folder, 'new-ft', 'a.vim' }, sep), + [[let g:seq ..= 'e']] + ) + write_file( + table.concat({ after_ftplugin_folder, 'new-ft', 'a.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'f']] + ) exec('setfiletype new-ft') eq('ABCDEFabcdef', eval('g:seq')) end) end) describe('indent', function() - local indent_folder = table.concat({plug_dir, 'indent'}, sep) + local indent_folder = table.concat({ plug_dir, 'indent' }, sep) it('lua indents work and are included in cmdline completion', function() mkdir_p(indent_folder) - local indent_file = table.concat({indent_folder , 'new-ft.lua'}, sep) - write_file(indent_file , [[vim.b.lua_indent = 1]]) + local indent_file = table.concat({ indent_folder, 'new-ft.lua' }, sep) + write_file(indent_file, [[vim.b.lua_indent = 1]]) - eq({'new-ft'}, funcs.getcompletion('new-f', 'filetype')) - eq({'indent/new-ft.lua'}, funcs.getcompletion('indent/new-f', 'runtime')) + eq({ 'new-ft' }, fn.getcompletion('new-f', 'filetype')) + eq({ 'indent/new-ft.lua' }, fn.getcompletion('indent/new-f', 'runtime')) exec [[set filetype=new-ft]] eq(1, eval('b:lua_indent')) end) it("'rtp' order is respected", function() - local after_indent_folder = table.concat({plug_dir, 'after', 'indent'}, sep) - mkdir_p(table.concat({indent_folder, 'new-ft'}, sep)) - mkdir_p(table.concat({after_indent_folder, 'new-ft'}, sep)) + local after_indent_folder = table.concat({ plug_dir, 'after', 'indent' }, sep) + mkdir_p(table.concat({ indent_folder, 'new-ft' }, sep)) + mkdir_p(table.concat({ after_indent_folder, 'new-ft' }, sep)) exec('set rtp+=' .. plug_dir .. '/after') exec('let g:seq = ""') -- A .lua file is loaded after a .vim file if they only differ in extension. -- All files in after/indent/ are loaded after all files in indent/. - write_file(table.concat({indent_folder, 'new-ft.vim'}, sep), [[let g:seq ..= 'A']]) - write_file(table.concat({indent_folder, 'new-ft.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) - write_file(table.concat({after_indent_folder, 'new-ft.vim'}, sep), [[let g:seq ..= 'a']]) - write_file(table.concat({after_indent_folder, 'new-ft.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) + write_file(table.concat({ indent_folder, 'new-ft.vim' }, sep), [[let g:seq ..= 'A']]) + write_file( + table.concat({ indent_folder, 'new-ft.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'B']] + ) + write_file(table.concat({ after_indent_folder, 'new-ft.vim' }, sep), [[let g:seq ..= 'a']]) + write_file( + table.concat({ after_indent_folder, 'new-ft.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'b']] + ) exec('setfiletype new-ft') eq('ABab', eval('g:seq')) end) end) describe('syntax', function() - local syntax_folder = table.concat({plug_dir, 'syntax'}, sep) + local syntax_folder = table.concat({ plug_dir, 'syntax' }, sep) before_each(function() mkdir_p(syntax_folder) - local syntax_file = table.concat({syntax_folder , 'my-lang.lua'}, sep) - write_file(syntax_file , [[vim.b.current_syntax = 'my-lang']]) + local syntax_file = table.concat({ syntax_folder, 'my-lang.lua' }, sep) + write_file(syntax_file, [[vim.b.current_syntax = 'my-lang']]) exec([[let b:current_syntax = '']]) end) @@ -263,27 +338,42 @@ describe('runtime:', function() end) it('lua syntaxes are included in cmdline completion', function() - eq({'my-lang'}, funcs.getcompletion('my-l', 'filetype')) - eq({'my-lang'}, funcs.getcompletion('my-l', 'syntax')) - eq({'syntax/my-lang.lua'}, funcs.getcompletion('syntax/my-l', 'runtime')) + eq({ 'my-lang' }, fn.getcompletion('my-l', 'filetype')) + eq({ 'my-lang' }, fn.getcompletion('my-l', 'syntax')) + eq({ 'syntax/my-lang.lua' }, fn.getcompletion('syntax/my-l', 'runtime')) end) it("'rtp' order is respected", function() - local after_syntax_folder = table.concat({plug_dir, 'after', 'syntax'}, sep) - mkdir_p(table.concat({syntax_folder, 'my-lang'}, sep)) - mkdir_p(table.concat({after_syntax_folder, 'my-lang'}, sep)) + local after_syntax_folder = table.concat({ plug_dir, 'after', 'syntax' }, sep) + mkdir_p(table.concat({ syntax_folder, 'my-lang' }, sep)) + mkdir_p(table.concat({ after_syntax_folder, 'my-lang' }, sep)) exec('set rtp+=' .. plug_dir .. '/after') exec('let g:seq = ""') -- A .lua file is loaded after a .vim file if they only differ in extension. -- All files in after/syntax/ are loaded after all files in syntax/. - write_file(table.concat({syntax_folder, 'my-lang.vim'}, sep), [[let g:seq ..= 'A']]) - write_file(table.concat({syntax_folder, 'my-lang.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) - write_file(table.concat({syntax_folder, 'my-lang', 'a.vim'}, sep), [[let g:seq ..= 'C']]) - write_file(table.concat({syntax_folder, 'my-lang', 'a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'D']]) - write_file(table.concat({after_syntax_folder, 'my-lang.vim'}, sep), [[let g:seq ..= 'a']]) - write_file(table.concat({after_syntax_folder, 'my-lang.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) - write_file(table.concat({after_syntax_folder, 'my-lang', 'a.vim'}, sep), [[let g:seq ..= 'c']]) - write_file(table.concat({after_syntax_folder, 'my-lang', 'a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'd']]) + write_file(table.concat({ syntax_folder, 'my-lang.vim' }, sep), [[let g:seq ..= 'A']]) + write_file( + table.concat({ syntax_folder, 'my-lang.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'B']] + ) + write_file(table.concat({ syntax_folder, 'my-lang', 'a.vim' }, sep), [[let g:seq ..= 'C']]) + write_file( + table.concat({ syntax_folder, 'my-lang', 'a.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'D']] + ) + write_file(table.concat({ after_syntax_folder, 'my-lang.vim' }, sep), [[let g:seq ..= 'a']]) + write_file( + table.concat({ after_syntax_folder, 'my-lang.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'b']] + ) + write_file( + table.concat({ after_syntax_folder, 'my-lang', 'a.vim' }, sep), + [[let g:seq ..= 'c']] + ) + write_file( + table.concat({ after_syntax_folder, 'my-lang', 'a.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'd']] + ) exec('setfiletype my-lang') eq('ABCDabcd', eval('g:seq')) end) @@ -291,21 +381,23 @@ describe('runtime:', function() describe('spell', function() it("loads spell/LANG.{vim,lua} respecting 'rtp' order", function() - local spell_folder = table.concat({plug_dir, 'spell'}, sep) - local after_spell_folder = table.concat({plug_dir, 'after', 'spell'}, sep) - mkdir_p(table.concat({spell_folder, 'Xtest'}, sep)) - mkdir_p(table.concat({after_spell_folder, 'Xtest'}, sep)) + local spell_folder = table.concat({ plug_dir, 'spell' }, sep) + local after_spell_folder = table.concat({ plug_dir, 'after', 'spell' }, sep) + mkdir_p(table.concat({ spell_folder, 'Xtest' }, sep)) + mkdir_p(table.concat({ after_spell_folder, 'Xtest' }, sep)) exec('set rtp+=' .. plug_dir .. '/after') exec('let g:seq = ""') -- A .lua file is loaded after a .vim file if they only differ in extension. -- All files in after/spell/ are loaded after all files in spell/. - write_file(table.concat({spell_folder, 'Xtest.vim'}, sep), [[let g:seq ..= 'A']]) - write_file(table.concat({spell_folder, 'Xtest.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) - write_file(table.concat({after_spell_folder, 'Xtest.vim'}, sep), [[let g:seq ..= 'a']]) - write_file(table.concat({after_spell_folder, 'Xtest.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) + write_file(table.concat({ spell_folder, 'Xtest.vim' }, sep), [[let g:seq ..= 'A']]) + write_file(table.concat({ spell_folder, 'Xtest.lua' }, sep), [[vim.g.seq = vim.g.seq .. 'B']]) + write_file(table.concat({ after_spell_folder, 'Xtest.vim' }, sep), [[let g:seq ..= 'a']]) + write_file( + table.concat({ after_spell_folder, 'Xtest.lua' }, sep), + [[vim.g.seq = vim.g.seq .. 'b']] + ) exec('set spelllang=Xtest') eq('ABab', eval('g:seq')) end) end) - end) diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua index fc20a06390..7aed711b23 100644 --- a/test/functional/lua/secure_spec.lua +++ b/test/functional/lua/secure_spec.lua @@ -6,11 +6,11 @@ local clear = helpers.clear local command = helpers.command local pathsep = helpers.get_pathsep() local is_os = helpers.is_os -local meths = helpers.meths +local api = helpers.api local exec_lua = helpers.exec_lua local feed_command = helpers.feed_command local feed = helpers.feed -local funcs = helpers.funcs +local fn = helpers.fn local pcall_err = helpers.pcall_err local matches = helpers.matches @@ -19,11 +19,14 @@ describe('vim.secure', function() local xstate = 'Xstate' setup(function() - clear{env={XDG_STATE_HOME=xstate}} + clear { env = { XDG_STATE_HOME = xstate } } helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim')) - helpers.write_file('Xfile', [[ + helpers.write_file( + 'Xfile', + [[ let g:foobar = 42 - ]]) + ]] + ) end) teardown(function() @@ -35,132 +38,139 @@ describe('vim.secure', function() local screen = Screen.new(80, 8) screen:attach() screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {bold = true, foreground = Screen.colors.SeaGreen}, - [4] = {reverse = true}, + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { bold = true, reverse = true }, + [3] = { bold = true, foreground = Screen.colors.SeaGreen }, + [4] = { reverse = true }, }) --- XXX: screen:expect() may fail if this path is too long. - local cwd = funcs.getcwd() + local cwd = fn.getcwd() -- Need to use feed_command instead of exec_lua because of the confirmation prompt feed_command([[lua vim.secure.read('Xfile')]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*3 {2: }| :lua vim.secure.read('Xfile') | - {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH:%s+}| + {3:]] + .. cwd + .. pathsep + .. [[Xfile is not trusted.}{MATCH:%s+}| {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | - ]]} + ]], + } feed('d') - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*6 | - ]]} + ]], + } - local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + local trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', cwd .. pathsep .. 'Xfile'), vim.trim(trust)) - eq(helpers.NIL, exec_lua([[return vim.secure.read('Xfile')]])) + eq(vim.NIL, exec_lua([[return vim.secure.read('Xfile')]])) - os.remove(funcs.stdpath('state') .. pathsep .. 'trust') + os.remove(fn.stdpath('state') .. pathsep .. 'trust') feed_command([[lua vim.secure.read('Xfile')]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*3 {2: }| :lua vim.secure.read('Xfile') | - {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH:%s+}| + {3:]] + .. cwd + .. pathsep + .. [[Xfile is not trusted.}{MATCH:%s+}| {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | - ]]} + ]], + } feed('a') - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*6 | - ]]} + ]], + } - local hash = funcs.sha256(helpers.read_file('Xfile')) - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + local hash = fn.sha256(helpers.read_file('Xfile')) + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, cwd .. pathsep .. 'Xfile'), vim.trim(trust)) - eq(helpers.NIL, exec_lua([[vim.secure.read('Xfile')]])) + eq(vim.NIL, exec_lua([[vim.secure.read('Xfile')]])) - os.remove(funcs.stdpath('state') .. pathsep .. 'trust') + os.remove(fn.stdpath('state') .. pathsep .. 'trust') feed_command([[lua vim.secure.read('Xfile')]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*3 {2: }| :lua vim.secure.read('Xfile') | - {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH:%s+}| + {3:]] + .. cwd + .. pathsep + .. [[Xfile is not trusted.}{MATCH:%s+}| {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | - ]]} + ]], + } feed('i') - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*6 | - ]]} + ]], + } -- Trust database is not updated - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(nil, trust) feed_command([[lua vim.secure.read('Xfile')]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ | - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*3 {2: }| :lua vim.secure.read('Xfile') | - {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH:%s+}| + {3:]] + .. cwd + .. pathsep + .. [[Xfile is not trusted.}{MATCH:%s+}| {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | - ]]} + ]], + } feed('v') - screen:expect{grid=[[ + screen:expect { + grid = [[ ^let g:foobar = 42 | - {1:~ }| - {1:~ }| - {2:]] .. funcs.fnamemodify(cwd, ':~') .. pathsep .. [[Xfile [RO]{MATCH:%s+}}| + {1:~ }|*2 + {2:]] + .. fn.fnamemodify(cwd, ':~') + .. pathsep + .. [[Xfile [RO]{MATCH:%s+}}| | {1:~ }| {4:[No Name] }| | - ]]} + ]], + } -- Trust database is not updated - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(nil, trust) -- Cannot write file pcall_err(command, 'write') - eq(true, meths.get_option_value('readonly', {})) + eq(true, api.nvim_get_option_value('readonly', {})) end) end) @@ -168,7 +178,7 @@ describe('vim.secure', function() local xstate = 'Xstate' setup(function() - clear{env={XDG_STATE_HOME=xstate}} + clear { env = { XDG_STATE_HOME = xstate } } helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim')) end) @@ -185,95 +195,113 @@ describe('vim.secure', function() end) it('returns error when passing both path and bufnr', function() - matches('"path" and "bufnr" are mutually exclusive', - pcall_err(exec_lua, [[vim.secure.trust({action='deny', bufnr=0, path='test_file'})]])) + matches( + '"path" and "bufnr" are mutually exclusive', + pcall_err(exec_lua, [[vim.secure.trust({action='deny', bufnr=0, path='test_file'})]]) + ) end) it('returns error when passing neither path or bufnr', function() - matches('one of "path" or "bufnr" is required', - pcall_err(exec_lua, [[vim.secure.trust({action='deny'})]])) + matches( + 'one of "path" or "bufnr" is required', + pcall_err(exec_lua, [[vim.secure.trust({action='deny'})]]) + ) end) it('trust then deny then remove a file using bufnr', function() - local cwd = funcs.getcwd() - local hash = funcs.sha256(helpers.read_file('test_file')) + local cwd = fn.getcwd() + local hash = fn.sha256(helpers.read_file('test_file')) local full_path = cwd .. pathsep .. 'test_file' command('edit test_file') - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) - local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) + local trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, full_path), vim.trim(trust)) - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', bufnr=0})}]])) - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='deny', bufnr=0})}]])) + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', full_path), vim.trim(trust)) - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', bufnr=0})}]])) - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='remove', bufnr=0})}]])) + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq('', vim.trim(trust)) end) it('deny then trust then remove a file using bufnr', function() - local cwd = funcs.getcwd() - local hash = funcs.sha256(helpers.read_file('test_file')) + local cwd = fn.getcwd() + local hash = fn.sha256(helpers.read_file('test_file')) local full_path = cwd .. pathsep .. 'test_file' command('edit test_file') - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', bufnr=0})}]])) - local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='deny', bufnr=0})}]])) + local trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', full_path), vim.trim(trust)) - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, full_path), vim.trim(trust)) - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', bufnr=0})}]])) - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='remove', bufnr=0})}]])) + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq('', vim.trim(trust)) end) it('trust using bufnr then deny then remove a file using path', function() - local cwd = funcs.getcwd() - local hash = funcs.sha256(helpers.read_file('test_file')) + local cwd = fn.getcwd() + local hash = fn.sha256(helpers.read_file('test_file')) local full_path = cwd .. pathsep .. 'test_file' command('edit test_file') - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) - local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) + local trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, full_path), vim.trim(trust)) - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', path='test_file'})}]])) - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq( + { true, full_path }, + exec_lua([[return {vim.secure.trust({action='deny', path='test_file'})}]]) + ) + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', full_path), vim.trim(trust)) - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', path='test_file'})}]])) - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq( + { true, full_path }, + exec_lua([[return {vim.secure.trust({action='remove', path='test_file'})}]]) + ) + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq('', vim.trim(trust)) end) it('deny then trust then remove a file using bufnr', function() - local cwd = funcs.getcwd() - local hash = funcs.sha256(helpers.read_file('test_file')) + local cwd = fn.getcwd() + local hash = fn.sha256(helpers.read_file('test_file')) local full_path = cwd .. pathsep .. 'test_file' command('edit test_file') - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', path='test_file'})}]])) - local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq( + { true, full_path }, + exec_lua([[return {vim.secure.trust({action='deny', path='test_file'})}]]) + ) + local trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', full_path), vim.trim(trust)) - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq({ true, full_path }, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, full_path), vim.trim(trust)) - eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', path='test_file'})}]])) - trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') + eq( + { true, full_path }, + exec_lua([[return {vim.secure.trust({action='remove', path='test_file'})}]]) + ) + trust = helpers.read_file(fn.stdpath('state') .. pathsep .. 'trust') eq('', vim.trim(trust)) end) it('trust returns error when buffer not associated to file', function() command('new') - eq({false, 'buffer is not associated with a file'}, - exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]])) + eq( + { false, 'buffer is not associated with a file' }, + exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]) + ) end) end) end) diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index f0b3b44139..e981bc6261 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -5,9 +5,11 @@ local clear = helpers.clear local eq = helpers.eq local exec_lua = helpers.exec_lua local feed = helpers.feed +local fn = helpers.fn local matches = helpers.matches local pcall_err = helpers.pcall_err -local sleep = helpers.sleep +local poke_eventloop = helpers.poke_eventloop +local retry = helpers.retry describe('vim.snippet', function() before_each(function() @@ -35,6 +37,12 @@ describe('vim.snippet', function() eq(expected, buf_lines(0)) end + local function wait_for_pum() + retry(nil, nil, function() + eq(1, fn.pumvisible()) + end) + end + --- @param snippet string --- @param err string local function test_expand_fail(snippet, err) @@ -154,7 +162,10 @@ describe('vim.snippet', function() end) it('errors with multiple placeholders for the same index', function() - test_expand_fail('class ${1:Foo} { void ${1:foo}() {} }', 'multiple placeholders for tabstop $1') + test_expand_fail( + 'class ${1:Foo} { void ${1:foo}() {} }', + 'multiple placeholders for tabstop $1' + ) end) it('errors with multiple $0 tabstops', function() @@ -162,30 +173,36 @@ describe('vim.snippet', function() end) it('cancels session when deleting the snippet', function() - test_expand_success({ 'local function $1()', ' $0', 'end' }, { 'local function ()', ' ', 'end' }) + test_expand_success( + { 'local function $1()', ' $0', 'end' }, + { 'local function ()', ' ', 'end' } + ) feed('<esc>Vjjd') eq(false, exec_lua('return vim.snippet.active()')) end) it('cancels session when inserting outside snippet region', function() feed('i<cr>') - test_expand_success({ 'local function $1()', ' $0', 'end' }, { '', 'local function ()', ' ', 'end' }) + test_expand_success( + { 'local function $1()', ' $0', 'end' }, + { '', 'local function ()', ' ', 'end' } + ) feed('<esc>O-- A comment') eq(false, exec_lua('return vim.snippet.active()')) end) - it('inserts choice', function () + it('inserts choice', function() test_expand_success({ 'console.${1|assert,log,error|}()' }, { 'console.()' }) - sleep(100) + wait_for_pum() feed('<Down><C-y>') eq({ 'console.log()' }, buf_lines(0)) end) - it('closes the choice completion menu when jumping', function () + it('closes the choice completion menu when jumping', function() test_expand_success({ 'console.${1|assert,log,error|}($2)' }, { 'console.()' }) - sleep(100) + wait_for_pum() exec_lua('vim.snippet.jump(1)') - eq(0, exec_lua('return vim.fn.pumvisible()')) + eq(0, fn.pumvisible()) end) it('jumps to next tabstop after inserting choice', function() @@ -193,10 +210,34 @@ describe('vim.snippet', function() { '${1|public,protected,private|} function ${2:name}() {', '\t$0', '}' }, { ' function name() {', '\t', '}' } ) - sleep(100) + wait_for_pum() feed('<C-y><Tab>') - sleep(10) + poke_eventloop() feed('foo') eq({ 'public function foo() {', '\t', '}' }, buf_lines(0)) end) + + it('jumps through adjacent tabstops', function() + test_expand_success( + { 'for i=1,${1:to}${2:,step} do\n\t$3\nend' }, + { 'for i=1,to,step do', '\t', 'end' } + ) + feed('10') + feed('<Tab>') + poke_eventloop() + feed(',2') + eq({ 'for i=1,10,2 do', '\t', 'end' }, buf_lines(0)) + end) + + it('updates snippet state when built-in completion menu is visible', function() + test_expand_success({ '$1 = function($2)\n$3\nend' }, { ' = function()', '', 'end' }) + -- Show the completion menu. + feed('<C-n>') + -- Make sure no item is selected. + feed('<C-p>') + -- Jump forward (the 2nd tabstop). + exec_lua('vim.snippet.jump(1)') + feed('foo') + eq({ ' = function(foo)', '', 'end' }, buf_lines(0)) + end) end) diff --git a/test/functional/lua/spell_spec.lua b/test/functional/lua/spell_spec.lua index b3de6a0912..e82dd7b4a0 100644 --- a/test/functional/lua/spell_spec.lua +++ b/test/functional/lua/spell_spec.lua @@ -11,43 +11,32 @@ describe('vim.spell', function() describe('.check', function() local check = function(x, exp) - return eq(exp, exec_lua("return vim.spell.check(...)", x)) + return eq(exp, exec_lua('return vim.spell.check(...)', x)) end it('can handle nil', function() - eq([[bad argument #1 to 'check' (expected string)]], - pcall_err(exec_lua, [[vim.spell.check(nil)]])) + eq( + [[bad argument #1 to 'check' (expected string)]], + pcall_err(exec_lua, [[vim.spell.check(nil)]]) + ) end) it('can check spellings', function() check('hello', {}) - check( - 'helloi', - {{"helloi", "bad", 1}} - ) + check('helloi', { { 'helloi', 'bad', 1 } }) - check( - 'hello therei', - {{"therei", "bad", 7}} - ) + check('hello therei', { { 'therei', 'bad', 7 } }) - check( - 'hello. there', - {{"there", "caps", 8}} - ) + check('hello. there', { { 'there', 'caps', 8 } }) - check( - 'neovim cna chkc spellins. okay?', - { - {"neovim" , "bad" , 1}, - {"cna" , "bad" , 8}, - {"chkc" , "bad" , 12}, - {"spellins", "bad" , 17}, - {"okay" , "caps", 27} - } - ) + check('neovim cna chkc spellins. okay?', { + { 'neovim', 'bad', 1 }, + { 'cna', 'bad', 8 }, + { 'chkc', 'bad', 12 }, + { 'spellins', 'bad', 17 }, + { 'okay', 'caps', 27 }, + }) end) - end) end) diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua index a988d3f0d7..cb561f0771 100644 --- a/test/functional/lua/system_spec.lua +++ b/test/functional/lua/system_spec.lua @@ -4,7 +4,8 @@ local exec_lua = helpers.exec_lua local eq = helpers.eq local function system_sync(cmd, opts) - return exec_lua([[ + return exec_lua( + [[ local cmd, opts = ... local obj = vim.system(...) @@ -21,11 +22,15 @@ local function system_sync(cmd, opts) assert(not proc, 'process still exists') return res - ]], cmd, opts) + ]], + cmd, + opts + ) end local function system_async(cmd, opts) - return exec_lua([[ + return exec_lua( + [[ local cmd, opts = ... _G.done = false local obj = vim.system(cmd, opts, function(obj) @@ -44,7 +49,10 @@ local function system_async(cmd, opts) assert(not proc, 'process still exists') return _G.ret - ]], cmd, opts) + ]], + cmd, + opts + ) end describe('vim.system', function() @@ -52,10 +60,10 @@ describe('vim.system', function() clear() end) - for name, system in pairs{ sync = system_sync, async = system_async, } do - describe('('..name..')', function() + for name, system in pairs { sync = system_sync, async = system_async } do + describe('(' .. name .. ')', function() it('can run simple commands', function() - eq('hello\n', system({'echo', 'hello' }, { text = true }).stdout) + eq('hello\n', system({ 'echo', 'hello' }, { text = true }).stdout) end) it('handle input', function() @@ -67,7 +75,7 @@ describe('vim.system', function() code = 124, signal = 15, stdout = '', - stderr = '' + stderr = '', }, system({ 'sleep', '10' }, { timeout = 1000 })) end) end) @@ -97,4 +105,17 @@ describe('vim.system', function() ]]) end) + it('SystemObj:wait() does not process non-fast events #27292', function() + eq( + false, + exec_lua([[ + _G.processed = false + local cmd = vim.system({ 'sleep', '1' }) + vim.schedule(function() _G.processed = true end) + cmd:wait() + return _G.processed + ]]) + ) + eq(true, exec_lua([[return _G.processed]])) + end) end) diff --git a/test/functional/lua/text_spec.lua b/test/functional/lua/text_spec.lua index 68206557c3..e31aa63768 100644 --- a/test/functional/lua/text_spec.lua +++ b/test/functional/lua/text_spec.lua @@ -20,4 +20,3 @@ describe('vim.text', function() end) end) end) - diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua index e79d26a641..c1981e19d4 100644 --- a/test/functional/lua/thread_spec.lua +++ b/test/functional/lua/thread_spec.lua @@ -6,7 +6,7 @@ local feed = helpers.feed local eq = helpers.eq local exec_lua = helpers.exec_lua local next_msg = helpers.next_msg -local NIL = helpers.NIL +local NIL = vim.NIL local pcall_err = helpers.pcall_err describe('thread', function() @@ -17,11 +17,11 @@ describe('thread', function() screen = Screen.new(50, 10) screen:attach() screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, - [5] = {bold = true}, + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { bold = true, reverse = true }, + [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, + [5] = { bold = true }, }) end) @@ -35,11 +35,7 @@ describe('thread', function() screen:expect([[ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*5 {2: }| {3:Error in luv thread:} | {3:[string "<nvim>"]:2: Error in thread entry func} | @@ -66,11 +62,7 @@ describe('thread', function() screen:expect([[ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*5 {2: }| {3:Error in luv callback, thread:} | {3:[string "<nvim>"]:6: Error in thread callback} | @@ -91,14 +83,7 @@ describe('thread', function() screen:expect([[ ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*8 print in thread | ]]) end) @@ -113,14 +98,7 @@ describe('thread', function() screen:expect([[ ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*8 { 1, 2 } | ]]) end) @@ -172,7 +150,7 @@ describe('thread', function() thread_test:do_test() ]] - eq({'notification', 'result', {true}}, next_msg()) + eq({ 'notification', 'result', { true } }, next_msg()) end) it('uv', function() @@ -204,7 +182,7 @@ describe('thread', function() thread_test:do_test() ]] - eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg()) + eq({ 'notification', 'result', { { 33, NIL, 'text' } } }, next_msg()) end) it('json', function() @@ -219,7 +197,7 @@ describe('thread', function() thread_test:do_test() ]] - eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg()) + eq({ 'notification', 'result', { { 33, NIL, 'text' } } }, next_msg()) end) it('diff', function() @@ -234,14 +212,18 @@ describe('thread', function() thread_test:do_test() ]] - eq({'notification', 'result', - {table.concat({ + eq({ + 'notification', + 'result', + { + table.concat({ '@@ -1 +1 @@', '-Hello', '+Helli', - '' - }, '\n')}}, - next_msg()) + '', + }, '\n'), + }, + }, next_msg()) end) end) end) @@ -263,28 +245,30 @@ describe('threadpool', function() work:queue() ]] - eq({'notification', 'result', {true}}, next_msg()) + eq({ 'notification', 'result', { true } }, next_msg()) end) it('with invalid argument', function() - local status = pcall_err(exec_lua, [[ + local status = pcall_err( + exec_lua, + [[ local work = vim.uv.new_thread(function() end, function() end) work:queue({}) - ]]) + ]] + ) - eq([[Error: thread arg not support type 'function' at 1]], - status) + eq([[Error: thread arg not support type 'function' at 1]], status) end) it('with invalid return value', function() local screen = Screen.new(50, 10) screen:attach() screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, - [5] = {bold = true}, + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { bold = true, reverse = true }, + [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, + [5] = { bold = true }, }) exec_lua [[ @@ -294,11 +278,7 @@ describe('threadpool', function() screen:expect([[ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*5 {2: }| {3:Error in luv thread:} | {3:Error: thread arg not support type 'table' at 1} | @@ -364,7 +344,7 @@ describe('threadpool', function() threadpool_test:do_test() ]] - eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg()) + eq({ 'notification', 'result', { { 33, NIL, 'text' } } }, next_msg()) end) it('json', function() @@ -380,7 +360,7 @@ describe('threadpool', function() threadpool_test:do_test() ]] - eq({'notification', 'result', {{33, NIL, 'text'}}}, next_msg()) + eq({ 'notification', 'result', { { 33, NIL, 'text' } } }, next_msg()) end) it('work', function() @@ -395,14 +375,18 @@ describe('threadpool', function() threadpool_test:do_test() ]] - eq({'notification', 'result', - {table.concat({ + eq({ + 'notification', + 'result', + { + table.concat({ '@@ -1 +1 @@', '-Hello', '+Helli', - '' - }, '\n')}}, - next_msg()) + '', + }, '\n'), + }, + }, next_msg()) end) end) end) diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 373d45da61..3e46018682 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -4,8 +4,7 @@ local eq = helpers.eq local exec_lua = helpers.exec_lua local clear = helpers.clear local feed = helpers.feed -local funcs = helpers.funcs -local inspect = require'vim.inspect' +local fn = helpers.fn describe('vim.ui_attach', function() local screen @@ -26,60 +25,67 @@ describe('vim.ui_attach', function() end ]] - screen = Screen.new(40,5) + screen = Screen.new(40, 5) screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}; - [2] = {bold = true}; - [3] = {background = Screen.colors.Grey}; - [4] = {background = Screen.colors.LightMagenta}; + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { bold = true }, + [3] = { background = Screen.colors.Grey }, + [4] = { background = Screen.colors.LightMagenta }, }) screen:attach() end) local function expect_events(expected) - local evs = exec_lua "return get_events(...)" - eq(expected, evs, inspect(evs)) + local evs = exec_lua 'return get_events(...)' + eq(expected, evs, vim.inspect(evs)) end it('can receive popupmenu events', function() exec_lua [[ vim.ui_attach(ns, {ext_popupmenu=true}, on_event) ]] feed('ifo') - screen:expect{grid=[[ + screen:expect { + grid = [[ fo^ | - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*3 {2:-- INSERT --} | - ]]} + ]], + } - funcs.complete(1, {'food', 'foobar', 'foo'}) - screen:expect{grid=[[ + fn.complete(1, { 'food', 'foobar', 'foo' }) + screen:expect { + grid = [[ food^ | - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*3 {2:-- INSERT --} | - ]]} + ]], + } expect_events { - { "popupmenu_show", { { "food", "", "", "" }, { "foobar", "", "", "" }, { "foo", "", "", "" } }, 0, 0, 0, 1 }; + { + 'popupmenu_show', + { { 'food', '', '', '' }, { 'foobar', '', '', '' }, { 'foo', '', '', '' } }, + 0, + 0, + 0, + 1, + }, } feed '<c-n>' - screen:expect{grid=[[ + screen:expect { + grid = [[ foobar^ | - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*3 {2:-- INSERT --} | - ]]} + ]], + } expect_events { - { "popupmenu_select", 1 }; + { 'popupmenu_select', 1 }, } feed '<c-y>' screen:expect_unchanged() expect_events { - { "popupmenu_hide" }; + { 'popupmenu_hide' }, } -- vim.ui_detach() stops events, and reenables builtin pum immediately @@ -88,26 +94,31 @@ describe('vim.ui_attach', function() vim.fn.complete(1, {'food', 'foobar', 'foo'}) ]] - screen:expect{grid=[[ + screen:expect { + grid = [[ food^ | {3:food }{1: }| {4:foobar }{1: }| {4:foo }{1: }| {2:-- INSERT --} | - ]]} - expect_events { + ]], } - + expect_events {} end) it('does not crash on exit', function() - helpers.funcs.system({ + fn.system({ helpers.nvim_prog, - '-u', 'NONE', - '-i', 'NONE', - '--cmd', [[ lua ns = vim.api.nvim_create_namespace 'testspace' ]], - '--cmd', [[ lua vim.ui_attach(ns, {ext_popupmenu=true}, function() end) ]], - '--cmd', 'quitall!', + '-u', + 'NONE', + '-i', + 'NONE', + '--cmd', + [[ lua ns = vim.api.nvim_create_namespace 'testspace' ]], + '--cmd', + [[ lua vim.ui_attach(ns, {ext_popupmenu=true}, function() end) ]], + '--cmd', + 'quitall!', }) eq(0, helpers.eval('v:shell_error')) end) @@ -136,6 +147,6 @@ describe('vim.ui_attach', function() { 'echomsg', { { 0, 'message3' } } }, }, }, - }, actual, inspect(actual)) + }, actual, vim.inspect(actual)) end) end) diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua index d4c150c5f2..e769843b19 100644 --- a/test/functional/lua/ui_spec.lua +++ b/test/functional/lua/ui_spec.lua @@ -16,7 +16,7 @@ describe('vim.ui', function() describe('select()', function() it('can select an item', function() - local result = exec_lua[[ + local result = exec_lua [[ local items = { { name = 'Item 1' }, { name = 'Item 2' }, @@ -51,7 +51,7 @@ describe('vim.ui', function() describe('input()', function() it('can input text', function() - local result = exec_lua[[ + local result = exec_lua [[ local opts = { prompt = 'Input: ', } @@ -117,38 +117,44 @@ describe('vim.ui', function() it('can return nil when interrupted with Ctrl-C #18144', function() feed(':lua result = "on_confirm not called"<cr>') feed(':lua vim.ui.input({}, function(input) result = input end)<cr>') - poke_eventloop() -- This is needed because Ctrl-C flushes input + poke_eventloop() -- This is needed because Ctrl-C flushes input feed('Inputted Text<c-c>') eq(true, exec_lua('return (nil == result)')) end) - it('can return the identical object when an arbitrary opts.cancelreturn object is given', function() - feed(':lua fn = function() return 42 end<CR>') - eq(42, exec_lua('return fn()')) - feed(':lua vim.ui.input({ cancelreturn = fn }, function(input) result = input end)<cr>') - feed('cancel<esc>') - eq(true, exec_lua('return (result == fn)')) - eq(42, exec_lua('return result()')) - end) - + it( + 'can return the identical object when an arbitrary opts.cancelreturn object is given', + function() + feed(':lua fn = function() return 42 end<CR>') + eq(42, exec_lua('return fn()')) + feed(':lua vim.ui.input({ cancelreturn = fn }, function(input) result = input end)<cr>') + feed('cancel<esc>') + eq(true, exec_lua('return (result == fn)')) + eq(42, exec_lua('return result()')) + end + ) end) describe('open()', function() it('validation', function() if is_os('win') or not is_ci('github') then - exec_lua[[vim.system = function() return { wait=function() return { code=3} end } end]] + exec_lua [[vim.system = function() return { wait=function() return { code=3} end } end]] end if not is_os('bsd') then - matches('vim.ui.open: command failed %(%d%): { "[^"]+", .*"non%-existent%-file" }', - exec_lua[[local _, err = vim.ui.open('non-existent-file') ; return err]]) + matches( + 'vim.ui.open: command failed %(%d%): { "[^"]+", .*"non%-existent%-file" }', + exec_lua [[local _, err = vim.ui.open('non-existent-file') ; return err]] + ) end - exec_lua[[ + exec_lua [[ vim.fn.has = function() return 0 end vim.fn.executable = function() return 0 end ]] - eq('vim.ui.open: no handler found (tried: wslview, xdg-open)', - exec_lua[[local _, err = vim.ui.open('foo') ; return err]]) + eq( + 'vim.ui.open: no handler found (tried: explorer.exe, xdg-open)', + exec_lua [[local _, err = vim.ui.open('foo') ; return err]] + ) end) end) end) diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua index 416e9e1f02..dacaf95867 100644 --- a/test/functional/lua/uri_spec.lua +++ b/test/functional/lua/uri_spec.lua @@ -16,20 +16,23 @@ describe('URI methods', function() it('file path includes only ascii characters', function() exec_lua("filepath = '/Foo/Bar/Baz.txt'") - eq('file:///Foo/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + eq('file:///Foo/Bar/Baz.txt', exec_lua('return vim.uri_from_fname(filepath)')) end) it('file path including white space', function() exec_lua("filepath = '/Foo /Bar/Baz.txt'") - eq('file:///Foo%20/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + eq('file:///Foo%20/Bar/Baz.txt', exec_lua('return vim.uri_from_fname(filepath)')) end) it('file path including Unicode characters', function() exec_lua("filepath = '/xy/åäö/ɧ/汉语/↥/🤦/🦄/å/بِيَّ.txt'") -- The URI encoding should be case-insensitive - eq('file:///xy/%c3%a5%c3%a4%c3%b6/%c9%a7/%e6%b1%89%e8%af%ad/%e2%86%a5/%f0%9f%a4%a6/%f0%9f%a6%84/a%cc%8a/%d8%a8%d9%90%d9%8a%d9%8e%d9%91.txt', exec_lua("return vim.uri_from_fname(filepath)")) + eq( + 'file:///xy/%c3%a5%c3%a4%c3%b6/%c9%a7/%e6%b1%89%e8%af%ad/%e2%86%a5/%f0%9f%a4%a6/%f0%9f%a6%84/a%cc%8a/%d8%a8%d9%90%d9%8a%d9%8e%d9%91.txt', + exec_lua('return vim.uri_from_fname(filepath)') + ) end) end) @@ -37,19 +40,22 @@ describe('URI methods', function() it('file path includes only ascii characters', function() exec_lua([[filepath = 'C:\\Foo\\Bar\\Baz.txt']]) - eq('file:///C:/Foo/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + eq('file:///C:/Foo/Bar/Baz.txt', exec_lua('return vim.uri_from_fname(filepath)')) end) it('file path including white space', function() exec_lua([[filepath = 'C:\\Foo \\Bar\\Baz.txt']]) - eq('file:///C:/Foo%20/Bar/Baz.txt', exec_lua("return vim.uri_from_fname(filepath)")) + eq('file:///C:/Foo%20/Bar/Baz.txt', exec_lua('return vim.uri_from_fname(filepath)')) end) it('file path including Unicode characters', function() exec_lua([[filepath = 'C:\\xy\\åäö\\ɧ\\汉语\\↥\\🤦\\🦄\\å\\بِيَّ.txt']]) - eq('file:///C:/xy/%c3%a5%c3%a4%c3%b6/%c9%a7/%e6%b1%89%e8%af%ad/%e2%86%a5/%f0%9f%a4%a6/%f0%9f%a6%84/a%cc%8a/%d8%a8%d9%90%d9%8a%d9%8e%d9%91.txt', exec_lua("return vim.uri_from_fname(filepath)")) + eq( + 'file:///C:/xy/%c3%a5%c3%a4%c3%b6/%c9%a7/%e6%b1%89%e8%af%ad/%e2%86%a5/%f0%9f%a4%a6/%f0%9f%a6%84/a%cc%8a/%d8%a8%d9%90%d9%8a%d9%8e%d9%91.txt', + exec_lua('return vim.uri_from_fname(filepath)') + ) end) end) end) @@ -59,19 +65,19 @@ describe('URI methods', function() it('file path includes only ascii characters', function() exec_lua("uri = 'file:///Foo/Bar/Baz.txt'") - eq('/Foo/Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)")) + eq('/Foo/Bar/Baz.txt', exec_lua('return vim.uri_to_fname(uri)')) end) it('local file path without hostname', function() exec_lua("uri = 'file:/Foo/Bar/Baz.txt'") - eq('/Foo/Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)")) + eq('/Foo/Bar/Baz.txt', exec_lua('return vim.uri_to_fname(uri)')) end) it('file path including white space', function() exec_lua("uri = 'file:///Foo%20/Bar/Baz.txt'") - eq('/Foo /Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)")) + eq('/Foo /Bar/Baz.txt', exec_lua('return vim.uri_to_fname(uri)')) end) it('file path including Unicode characters', function() @@ -82,6 +88,12 @@ describe('URI methods', function() eq('/xy/åäö/ɧ/汉语/↥/🤦/🦄/å/بِيَّ.txt', exec_lua(test_case)) end) + + it('file path with uri fragment', function() + exec_lua("uri = 'file:///Foo/Bar/Baz.txt#fragment'") + + eq('/Foo/Bar/Baz.txt', exec_lua('return vim.uri_to_fname(uri)')) + end) end) describe('decode Windows filepath', function() @@ -133,73 +145,109 @@ describe('URI methods', function() describe('decode non-file URI', function() it('uri_to_fname returns non-file URI unchanged', function() - eq('jdt1.23+x-z://content/%5C/', exec_lua [[ + eq( + 'jdt1.23+x-z://content/%5C/', + exec_lua [[ return vim.uri_to_fname('jdt1.23+x-z://content/%5C/') - ]]) + ]] + ) end) it('uri_to_fname returns non-file upper-case scheme URI unchanged', function() - eq('JDT://content/%5C/', exec_lua [[ + eq( + 'JDT://content/%5C/', + exec_lua [[ return vim.uri_to_fname('JDT://content/%5C/') - ]]) + ]] + ) end) it('uri_to_fname returns non-file scheme URI without authority unchanged', function() - eq('zipfile:///path/to/archive.zip%3A%3Afilename.txt', exec_lua [[ + eq( + 'zipfile:///path/to/archive.zip%3A%3Afilename.txt', + exec_lua [[ return vim.uri_to_fname('zipfile:///path/to/archive.zip%3A%3Afilename.txt') - ]]) + ]] + ) end) end) describe('decode URI without scheme', function() it('fails because URI must have a scheme', function() - eq(false, exec_lua [[ + eq( + false, + exec_lua [[ return pcall(vim.uri_to_fname, 'not_an_uri.txt') - ]]) + ]] + ) end) it('uri_to_fname should not treat comma as a scheme character', function() - eq(false, exec_lua [[ + eq( + false, + exec_lua [[ return pcall(vim.uri_to_fname, 'foo,://bar') - ]]) + ]] + ) end) - end) + it('uri_to_fname returns non-file schema URI with fragment unchanged', function() + eq( + 'scheme://path#fragment', + exec_lua [[ + return vim.uri_to_fname('scheme://path#fragment') + ]] + ) + end) + end) end) describe('uri from bufnr', function() it('Windows paths should not be treated as uris', function() - skip(not is_os('win'), "Not applicable on non-Windows") + skip(not is_os('win'), 'Not applicable on non-Windows') local file = helpers.tmpname() write_file(file, 'Test content') - local test_case = string.format([[ + local test_case = string.format( + [[ local file = '%s' return vim.uri_from_bufnr(vim.fn.bufadd(file)) - ]], file) - local expected_uri = 'file:///' .. file:gsub("\\", "/") - eq(expected_uri, exec_lua(test_case)) - os.remove(file) + ]], + file + ) + local expected_uri = 'file:///' .. file:gsub('\\', '/') + eq(expected_uri, exec_lua(test_case)) + os.remove(file) end) end) describe('uri to bufnr', function() it('uri_to_bufnr & uri_from_bufnr returns original uri for non-file uris', function() - local uri = 'jdt://contents/java.base/java.util/List.class?=sql/%5C/home%5C/user%5C/.jabba%5C/jdk%5C/openjdk%5C@1.14.0%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/14%5C/docs%5C/api%5C/=/%3Cjava.util(List.class' - local test_case = string.format([[ + local uri = + 'jdt://contents/java.base/java.util/List.class?=sql/%5C/home%5C/user%5C/.jabba%5C/jdk%5C/openjdk%5C@1.14.0%5C/lib%5C/jrt-fs.jar%60java.base=/javadoc_location=/https:%5C/%5C/docs.oracle.com%5C/en%5C/java%5C/javase%5C/14%5C/docs%5C/api%5C/=/%3Cjava.util(List.class' + local test_case = string.format( + [[ local uri = '%s' return vim.uri_from_bufnr(vim.uri_to_bufnr(uri)) - ]], uri) + ]], + uri + ) eq(uri, exec_lua(test_case)) end) - it('uri_to_bufnr & uri_from_bufnr returns original uri for non-file uris without authority', function() - local uri = 'zipfile:///path/to/archive.zip%3A%3Afilename.txt' - local test_case = string.format([[ + it( + 'uri_to_bufnr & uri_from_bufnr returns original uri for non-file uris without authority', + function() + local uri = 'zipfile:///path/to/archive.zip%3A%3Afilename.txt' + local test_case = string.format( + [[ local uri = '%s' return vim.uri_from_bufnr(vim.uri_to_bufnr(uri)) - ]], uri) - eq(uri, exec_lua(test_case)) - end) + ]], + uri + ) + eq(uri, exec_lua(test_case)) + end + ) end) end) diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index d1c981c388..3bc9e26d41 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -11,7 +11,6 @@ local function v(ver) end describe('version', function() - it('package', function() clear() eq({ major = 42, minor = 3, patch = 99 }, exec_lua("return vim.version.parse('v42.3.99')")) @@ -35,7 +34,13 @@ describe('version', function() ['v1.2'] = { major = 1, minor = 2, patch = 0 }, ['v1.2.3-prerelease'] = { major = 1, minor = 2, patch = 3, prerelease = 'prerelease' }, ['v1.2-prerelease'] = { major = 1, minor = 2, patch = 0, prerelease = 'prerelease' }, - ['v1.2.3-prerelease+build'] = { major = 1, minor = 2, patch = 3, prerelease = 'prerelease', build = 'build' }, + ['v1.2.3-prerelease+build'] = { + major = 1, + minor = 2, + patch = 3, + prerelease = 'prerelease', + build = 'build', + }, ['1.2.3+build'] = { major = 1, minor = 2, patch = 3, build = 'build' }, } for input, output in pairs(tests) do @@ -108,86 +113,114 @@ describe('version', function() describe('cmp()', function() local testcases = { - { v1 = 'v0.0.99', v2 = 'v9.0.0', want = -1, }, - { v1 = 'v0.4.0', v2 = 'v0.9.99', want = -1, }, - { v1 = 'v0.2.8', v2 = 'v1.0.9', want = -1, }, - { v1 = 'v0.0.0', v2 = 'v0.0.0', want = 0, }, - { v1 = 'v9.0.0', v2 = 'v0.9.0', want = 1, }, - { v1 = 'v0.9.0', v2 = 'v0.0.0', want = 1, }, - { v1 = 'v0.0.9', v2 = 'v0.0.0', want = 1, }, - { v1 = 'v0.0.9+aaa', v2 = 'v0.0.9+bbb', want = 0, }, + { v1 = 'v0.0.99', v2 = 'v9.0.0', want = -1 }, + { v1 = 'v0.4.0', v2 = 'v0.9.99', want = -1 }, + { v1 = 'v0.2.8', v2 = 'v1.0.9', want = -1 }, + { v1 = 'v0.0.0', v2 = 'v0.0.0', want = 0 }, + { v1 = 'v9.0.0', v2 = 'v0.9.0', want = 1 }, + { v1 = 'v0.9.0', v2 = 'v0.0.0', want = 1 }, + { v1 = 'v0.0.9', v2 = 'v0.0.0', want = 1 }, + { v1 = 'v0.0.9+aaa', v2 = 'v0.0.9+bbb', want = 0 }, -- prerelease 💩 https://semver.org/#spec-item-11 - { v1 = 'v1.0.0-alpha', v2 = 'v1.0.0', want = -1, }, - { v1 = '1.0.0', v2 = '1.0.0-alpha', want = 1, }, - { v1 = '1.0.0-2', v2 = '1.0.0-1', want = 1, }, - { v1 = '1.0.0-2', v2 = '1.0.0-9', want = -1, }, - { v1 = '1.0.0-2', v2 = '1.0.0-2.0', want = -1, }, - { v1 = '1.0.0-2.0', v2 = '1.0.0-2', want = 1, }, - { v1 = '1.0.0-2.0', v2 = '1.0.0-2.0', want = 0, }, - { v1 = '1.0.0-alpha', v2 = '1.0.0-alpha', want = 0, }, - { v1 = '1.0.0-alpha', v2 = '1.0.0-beta', want = -1, }, - { v1 = '1.0.0-beta', v2 = '1.0.0-alpha', want = 1, }, - { v1 = '1.0.0-alpha', v2 = '1.0.0-alpha.1', want = -1, }, - { v1 = '1.0.0-alpha.1', v2 = '1.0.0-alpha', want = 1, }, - { v1 = '1.0.0-alpha.beta', v2 = '1.0.0-alpha', want = 1, }, - { v1 = '1.0.0-alpha', v2 = '1.0.0-alpha.beta', want = -1, }, - { v1 = '1.0.0-alpha.beta', v2 = '1.0.0-beta', want = -1, }, - { v1 = '1.0.0-beta.2', v2 = '1.0.0-beta.11', want = -1, }, - { v1 = '1.0.0-beta.20', v2 = '1.0.0-beta.11', want = 1, }, - { v1 = '1.0.0-alpha.20', v2 = '1.0.0-beta.11', want = -1, }, - { v1 = '1.0.0-a.01.x.3', v2 = '1.0.0-a.1.x.003', want = 0, }, - { v1 = 'v0.9.0-dev-92+9', v2 = 'v0.9.0-dev-120+3', want = -1, }, + { v1 = 'v1.0.0-alpha', v2 = 'v1.0.0', want = -1 }, + { v1 = '1.0.0', v2 = '1.0.0-alpha', want = 1 }, + { v1 = '1.0.0-2', v2 = '1.0.0-1', want = 1 }, + { v1 = '1.0.0-2', v2 = '1.0.0-9', want = -1 }, + { v1 = '1.0.0-2', v2 = '1.0.0-2.0', want = -1 }, + { v1 = '1.0.0-2.0', v2 = '1.0.0-2', want = 1 }, + { v1 = '1.0.0-2.0', v2 = '1.0.0-2.0', want = 0 }, + { v1 = '1.0.0-alpha', v2 = '1.0.0-alpha', want = 0 }, + { v1 = '1.0.0-alpha', v2 = '1.0.0-beta', want = -1 }, + { v1 = '1.0.0-beta', v2 = '1.0.0-alpha', want = 1 }, + { v1 = '1.0.0-alpha', v2 = '1.0.0-alpha.1', want = -1 }, + { v1 = '1.0.0-alpha.1', v2 = '1.0.0-alpha', want = 1 }, + { v1 = '1.0.0-alpha.beta', v2 = '1.0.0-alpha', want = 1 }, + { v1 = '1.0.0-alpha', v2 = '1.0.0-alpha.beta', want = -1 }, + { v1 = '1.0.0-alpha.beta', v2 = '1.0.0-beta', want = -1 }, + { v1 = '1.0.0-beta.2', v2 = '1.0.0-beta.11', want = -1 }, + { v1 = '1.0.0-beta.20', v2 = '1.0.0-beta.11', want = 1 }, + { v1 = '1.0.0-alpha.20', v2 = '1.0.0-beta.11', want = -1 }, + { v1 = '1.0.0-a.01.x.3', v2 = '1.0.0-a.1.x.003', want = 0 }, + { v1 = 'v0.9.0-dev-92+9', v2 = 'v0.9.0-dev-120+3', want = -1 }, } for _, tc in ipairs(testcases) do - local msg = function(s) return ('v1 %s v2'):format(s == 0 and '==' or (s == 1 and '>' or '<')) end - it(string.format('(v1 = %s, v2 = %s)', tc.v1, tc.v2), - function() - local rv = vim.version.cmp(tc.v1, tc.v2, { strict = true }) - ok(tc.want == rv, msg(tc.want), msg(rv)) - end - ) + local msg = function(s) + return ('v1 %s v2'):format(s == 0 and '==' or (s == 1 and '>' or '<')) + end + it(string.format('(v1 = %s, v2 = %s)', tc.v1, tc.v2), function() + local rv = vim.version.cmp(tc.v1, tc.v2, { strict = true }) + ok(tc.want == rv, msg(tc.want), msg(rv)) + end) end end) describe('parse()', function() describe('strict=true', function() local testcases = { - { desc = 'Nvim version', version = 'v0.9.0-dev-1233+g210120dde81e', want = { major = 0, minor = 9, patch = 0, prerelease = 'dev-1233', build = 'g210120dde81e', }, }, - { desc = 'no v', version = '10.20.123', want = { major = 10, minor = 20, patch = 123, prerelease = nil, build = nil, }, }, - { desc = 'with v', version = 'v1.2.3', want = { major = 1, minor = 2, patch = 3 }, }, - { desc = 'prerelease', version = '1.2.3-alpha', want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha' }, }, - { desc = 'prerelease.x', version = '1.2.3-alpha.1', want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha.1' }, }, - { desc = 'build.x', version = '1.2.3+build.15', want = { major = 1, minor = 2, patch = 3, build = 'build.15' }, }, - { desc = 'prerelease and build', version = '1.2.3-rc1+build.15', want = { major = 1, minor = 2, patch = 3, prerelease = 'rc1', build = 'build.15', }, }, + { + desc = 'Nvim version', + version = 'v0.9.0-dev-1233+g210120dde81e', + want = { + major = 0, + minor = 9, + patch = 0, + prerelease = 'dev-1233', + build = 'g210120dde81e', + }, + }, + { + desc = 'no v', + version = '10.20.123', + want = { major = 10, minor = 20, patch = 123, prerelease = nil, build = nil }, + }, + { + desc = 'with v', + version = 'v1.2.3', + want = { major = 1, minor = 2, patch = 3 }, + }, + { + desc = 'prerelease', + version = '1.2.3-alpha', + want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha' }, + }, + { + desc = 'prerelease.x', + version = '1.2.3-alpha.1', + want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha.1' }, + }, + { + desc = 'build.x', + version = '1.2.3+build.15', + want = { major = 1, minor = 2, patch = 3, build = 'build.15' }, + }, + { + desc = 'prerelease and build', + version = '1.2.3-rc1+build.15', + want = { major = 1, minor = 2, patch = 3, prerelease = 'rc1', build = 'build.15' }, + }, } for _, tc in ipairs(testcases) do - it( - string.format('%q: version = %q', tc.desc, tc.version), - function() - eq(tc.want, vim.version.parse(tc.version)) - end - ) + it(string.format('%q: version = %q', tc.desc, tc.version), function() + eq(tc.want, vim.version.parse(tc.version)) + end) end end) describe('strict=false', function() local testcases = { - { version = '1.2', want = { major = 1, minor = 2, patch = 0 }, }, - { version = '1', want = { major = 1, minor = 0, patch = 0 }, }, - { version = '1.1-0', want = { major = 1, minor = 1, patch = 0, prerelease = '0' }, }, - { version = '1-1.0', want = { major = 1, minor = 0, patch = 0, prerelease = '1.0' }, }, - { version = 'v1.2.3 ', want = { major = 1, minor = 2, patch = 3 }, }, - { version = ' v1.2.3', want = { major = 1, minor = 2, patch = 3 }, }, - { version = 'tmux 3.2a', want = { major = 3, minor = 2, patch = 0, }, }, + { version = '1.2', want = { major = 1, minor = 2, patch = 0 } }, + { version = '1', want = { major = 1, minor = 0, patch = 0 } }, + { version = '1.1-0', want = { major = 1, minor = 1, patch = 0, prerelease = '0' } }, + { version = '1-1.0', want = { major = 1, minor = 0, patch = 0, prerelease = '1.0' } }, + { version = 'v1.2.3 ', want = { major = 1, minor = 2, patch = 3 } }, + { version = ' v1.2.3', want = { major = 1, minor = 2, patch = 3 } }, + { version = 'tmux 3.2a', want = { major = 3, minor = 2, patch = 0 } }, } for _, tc in ipairs(testcases) do - it( - string.format('version = %q', tc.version), - function() - eq(tc.want, vim.version.parse(tc.version, { strict = false })) - end - ) + it(string.format('version = %q', tc.version), function() + eq(tc.want, vim.version.parse(tc.version, { strict = false })) + end) end end) @@ -205,8 +238,8 @@ describe('version', function() { version = '1.2.3-%?' }, { version = '1.2.3+%?' }, { version = '1.2.3+build.0-rc1' }, - { version = '3.2a', }, - { version = 'tmux 3.2a', }, + { version = '3.2a' }, + { version = 'tmux 3.2a' }, } local function quote_empty(s) @@ -230,8 +263,10 @@ describe('version', function() } for _, tc in ipairs(testcases) do it(string.format('(%s): %s', tc.desc, tostring(tc.version)), function() - local expected = string.format(type(tc.version) == 'string' - and 'invalid version: "%s"' or 'invalid version: %s', tostring(tc.version)) + local expected = string.format( + type(tc.version) == 'string' and 'invalid version: "%s"' or 'invalid version: %s', + tostring(tc.version) + ) matches(expected, pcall_err(vim.version.parse, tc.version, { strict = true })) end) end @@ -253,21 +288,55 @@ describe('version', function() eq(vim.version.last({ v('2.0.0'), v('1.2.3') }), v('2.0.0')) end) + it('le()', function() + eq(true, vim.version.le('1', '1')) + eq(true, vim.version.le({ 3, 1, 4 }, '3.1.4')) + eq(true, vim.version.le('1', '2')) + eq(true, vim.version.le({ 0, 7, 4 }, { 3 })) + eq(false, vim.version.le({ 3 }, { 0, 7, 4 })) + eq(false, vim.version.le({ major = 3, minor = 3, patch = 0 }, { 3, 2, 0 })) + eq(false, vim.version.le('2', '1')) + end) + it('lt()', function() + eq(false, vim.version.lt('1', '1')) + eq(false, vim.version.lt({ 3, 1, 4 }, '3.1.4')) eq(true, vim.version.lt('1', '2')) - eq(false, vim.version.lt({3}, {0, 7, 4})) - eq(false, vim.version.lt({major=3, minor=3, patch=0}, {3, 2, 0})) + eq(true, vim.version.lt({ 0, 7, 4 }, { 3 })) + eq(false, vim.version.lt({ 3 }, { 0, 7, 4 })) + eq(false, vim.version.lt({ major = 3, minor = 3, patch = 0 }, { 3, 2, 0 })) + eq(false, vim.version.lt('2', '1')) + end) + + it('ge()', function() + eq(true, vim.version.ge('1', '1')) + eq(true, vim.version.ge({ 3, 1, 4 }, '3.1.4')) + eq(true, vim.version.ge('2', '1')) + eq(true, vim.version.ge({ 3 }, { 0, 7, 4 })) + eq(true, vim.version.ge({ major = 3, minor = 3, patch = 0 }, { 3, 2, 0 })) + eq(false, vim.version.ge('1', '2')) + eq(false, vim.version.ge({ 0, 7, 4 }, { 3 })) end) it('gt()', function() + eq(false, vim.version.gt('1', '1')) + eq(false, vim.version.gt({ 3, 1, 4 }, '3.1.4')) eq(true, vim.version.gt('2', '1')) - eq(true, vim.version.gt({3}, {0, 7, 4})) - eq(true, vim.version.gt({major=3, minor=3, patch=0}, {3, 2, 0})) + eq(true, vim.version.gt({ 3 }, { 0, 7, 4 })) + eq(true, vim.version.gt({ major = 3, minor = 3, patch = 0 }, { 3, 2, 0 })) + eq(false, vim.version.gt('1', '2')) + eq(false, vim.version.gt({ 0, 7, 4 }, { 3 })) end) it('eq()', function() eq(true, vim.version.eq('2', '2')) - eq(true, vim.version.eq({3, 1, 0}, '3.1.0')) - eq(true, vim.version.eq({major=3, minor=3, patch=0}, {3, 3, 0})) + eq(true, vim.version.eq({ 3, 1, 0 }, '3.1.0')) + eq(true, vim.version.eq({ major = 3, minor = 3, patch = 0 }, { 3, 3, 0 })) + eq(false, vim.version.eq('2', '3')) + + -- semver: v3 == v3.0 == v3.0.0 + eq(true, vim.version.eq('3', { 3, 0, 0 })) + eq(true, vim.version.eq({ 3, 0 }, { 3 })) + eq(true, vim.version.eq({ 3, 0, 0 }, { 3 })) end) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index ebe5fc254e..a262d239e8 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3,22 +3,22 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local nvim_prog = helpers.nvim_prog -local funcs = helpers.funcs -local meths = helpers.meths +local fn = helpers.fn +local api = helpers.api local command = helpers.command local dedent = helpers.dedent local insert = helpers.insert local clear = helpers.clear local eq = helpers.eq local ok = helpers.ok -local pesc = helpers.pesc +local pesc = vim.pesc local eval = helpers.eval local feed = helpers.feed local pcall_err = helpers.pcall_err local exec_lua = helpers.exec_lua local matches = helpers.matches local exec = helpers.exec -local NIL = helpers.NIL +local NIL = vim.NIL local retry = helpers.retry local next_msg = helpers.next_msg local remove_trace = helpers.remove_trace @@ -39,204 +39,479 @@ describe('lua stdlib', function() -- Note: Built-in Nvim comparison (on systems lacking `strcasecmp`) works -- only on ASCII characters. it('vim.stricmp', function() - eq(0, funcs.luaeval('vim.stricmp("a", "A")')) - eq(0, funcs.luaeval('vim.stricmp("A", "a")')) - eq(0, funcs.luaeval('vim.stricmp("a", "a")')) - eq(0, funcs.luaeval('vim.stricmp("A", "A")')) - - eq(0, funcs.luaeval('vim.stricmp("", "")')) - eq(0, funcs.luaeval('vim.stricmp("\\0", "\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0a")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0A")')) - eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0a")')) - - eq(0, funcs.luaeval('vim.stricmp("a\\0", "A\\0")')) - eq(0, funcs.luaeval('vim.stricmp("A\\0", "a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("a\\0", "a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("A\\0", "A\\0")')) - - eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0A")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0a")')) - eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0a")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0A")')) - - eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0A\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0a\\0")')) - eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0A\\0")')) - - eq(-1, funcs.luaeval('vim.stricmp("a", "B")')) - eq(-1, funcs.luaeval('vim.stricmp("A", "b")')) - eq(-1, funcs.luaeval('vim.stricmp("a", "b")')) - eq(-1, funcs.luaeval('vim.stricmp("A", "B")')) - - eq(-1, funcs.luaeval('vim.stricmp("", "\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0", "\\0\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0b")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0B")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0b")')) - - eq(-1, funcs.luaeval('vim.stricmp("a\\0", "B\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("A\\0", "b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("a\\0", "b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("A\\0", "B\\0")')) - - eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0B")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0b")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0b")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0B")')) - - eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0B\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0b\\0")')) - eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0B\\0")')) - - eq(1, funcs.luaeval('vim.stricmp("c", "B")')) - eq(1, funcs.luaeval('vim.stricmp("C", "b")')) - eq(1, funcs.luaeval('vim.stricmp("c", "b")')) - eq(1, funcs.luaeval('vim.stricmp("C", "B")')) - - eq(1, funcs.luaeval('vim.stricmp("\\0", "")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0\\0", "\\0\\0\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0C", "\\0\\0\\0b")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0B")')) - eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0b")')) - - eq(1, funcs.luaeval('vim.stricmp("c\\0", "B\\0")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("c\\0", "b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "B\\0")')) - - eq(1, funcs.luaeval('vim.stricmp("c\\0", "B")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "b")')) - eq(1, funcs.luaeval('vim.stricmp("c\\0", "b")')) - eq(1, funcs.luaeval('vim.stricmp("C\\0", "B")')) - - eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0B")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0b")')) - eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0b")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0B")')) - - eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0B\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")')) - eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")')) - end) - - it('vim.deprecate', function() - -- vim.deprecate(name, alternative, version, plugin, backtrace) - eq(dedent[[ - foo.bar() is deprecated, use zub.wooo{ok=yay} instead. :help deprecated - This feature will be removed in Nvim version 2.17]], - exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', '2.17')) - -- Same message, skipped. - eq(vim.NIL, - exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', '2.17')) - -- When `plugin` is specified, don't show ":help deprecated". #22235 - eq(dedent[[ - foo.bar() is deprecated, use zub.wooo{ok=yay} instead. - This feature will be removed in my-plugin.nvim version 0.3.0]], - exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', '0.3.0', 'my-plugin.nvim', false)) + eq(0, fn.luaeval('vim.stricmp("a", "A")')) + eq(0, fn.luaeval('vim.stricmp("A", "a")')) + eq(0, fn.luaeval('vim.stricmp("a", "a")')) + eq(0, fn.luaeval('vim.stricmp("A", "A")')) + + eq(0, fn.luaeval('vim.stricmp("", "")')) + eq(0, fn.luaeval('vim.stricmp("\\0", "\\0")')) + eq(0, fn.luaeval('vim.stricmp("\\0\\0", "\\0\\0")')) + eq(0, fn.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0\\0")')) + eq(0, fn.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0a")')) + eq(0, fn.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0A")')) + eq(0, fn.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0a")')) + + eq(0, fn.luaeval('vim.stricmp("a\\0", "A\\0")')) + eq(0, fn.luaeval('vim.stricmp("A\\0", "a\\0")')) + eq(0, fn.luaeval('vim.stricmp("a\\0", "a\\0")')) + eq(0, fn.luaeval('vim.stricmp("A\\0", "A\\0")')) + + eq(0, fn.luaeval('vim.stricmp("\\0a", "\\0A")')) + eq(0, fn.luaeval('vim.stricmp("\\0A", "\\0a")')) + eq(0, fn.luaeval('vim.stricmp("\\0a", "\\0a")')) + eq(0, fn.luaeval('vim.stricmp("\\0A", "\\0A")')) + + eq(0, fn.luaeval('vim.stricmp("\\0a\\0", "\\0A\\0")')) + eq(0, fn.luaeval('vim.stricmp("\\0A\\0", "\\0a\\0")')) + eq(0, fn.luaeval('vim.stricmp("\\0a\\0", "\\0a\\0")')) + eq(0, fn.luaeval('vim.stricmp("\\0A\\0", "\\0A\\0")')) + + eq(-1, fn.luaeval('vim.stricmp("a", "B")')) + eq(-1, fn.luaeval('vim.stricmp("A", "b")')) + eq(-1, fn.luaeval('vim.stricmp("a", "b")')) + eq(-1, fn.luaeval('vim.stricmp("A", "B")')) + + eq(-1, fn.luaeval('vim.stricmp("", "\\0")')) + eq(-1, fn.luaeval('vim.stricmp("\\0", "\\0\\0")')) + eq(-1, fn.luaeval('vim.stricmp("\\0\\0", "\\0\\0\\0")')) + eq(-1, fn.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0b")')) + eq(-1, fn.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0B")')) + eq(-1, fn.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0b")')) + + eq(-1, fn.luaeval('vim.stricmp("a\\0", "B\\0")')) + eq(-1, fn.luaeval('vim.stricmp("A\\0", "b\\0")')) + eq(-1, fn.luaeval('vim.stricmp("a\\0", "b\\0")')) + eq(-1, fn.luaeval('vim.stricmp("A\\0", "B\\0")')) + + eq(-1, fn.luaeval('vim.stricmp("\\0a", "\\0B")')) + eq(-1, fn.luaeval('vim.stricmp("\\0A", "\\0b")')) + eq(-1, fn.luaeval('vim.stricmp("\\0a", "\\0b")')) + eq(-1, fn.luaeval('vim.stricmp("\\0A", "\\0B")')) + + eq(-1, fn.luaeval('vim.stricmp("\\0a\\0", "\\0B\\0")')) + eq(-1, fn.luaeval('vim.stricmp("\\0A\\0", "\\0b\\0")')) + eq(-1, fn.luaeval('vim.stricmp("\\0a\\0", "\\0b\\0")')) + eq(-1, fn.luaeval('vim.stricmp("\\0A\\0", "\\0B\\0")')) + + eq(1, fn.luaeval('vim.stricmp("c", "B")')) + eq(1, fn.luaeval('vim.stricmp("C", "b")')) + eq(1, fn.luaeval('vim.stricmp("c", "b")')) + eq(1, fn.luaeval('vim.stricmp("C", "B")')) + + eq(1, fn.luaeval('vim.stricmp("\\0", "")')) + eq(1, fn.luaeval('vim.stricmp("\\0\\0", "\\0")')) + eq(1, fn.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0")')) + eq(1, fn.luaeval('vim.stricmp("\\0\\0\\0\\0", "\\0\\0\\0")')) + eq(1, fn.luaeval('vim.stricmp("\\0\\0\\0C", "\\0\\0\\0b")')) + eq(1, fn.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0B")')) + eq(1, fn.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0b")')) + + eq(1, fn.luaeval('vim.stricmp("c\\0", "B\\0")')) + eq(1, fn.luaeval('vim.stricmp("C\\0", "b\\0")')) + eq(1, fn.luaeval('vim.stricmp("c\\0", "b\\0")')) + eq(1, fn.luaeval('vim.stricmp("C\\0", "B\\0")')) + + eq(1, fn.luaeval('vim.stricmp("c\\0", "B")')) + eq(1, fn.luaeval('vim.stricmp("C\\0", "b")')) + eq(1, fn.luaeval('vim.stricmp("c\\0", "b")')) + eq(1, fn.luaeval('vim.stricmp("C\\0", "B")')) + + eq(1, fn.luaeval('vim.stricmp("\\0c", "\\0B")')) + eq(1, fn.luaeval('vim.stricmp("\\0C", "\\0b")')) + eq(1, fn.luaeval('vim.stricmp("\\0c", "\\0b")')) + eq(1, fn.luaeval('vim.stricmp("\\0C", "\\0B")')) + + eq(1, fn.luaeval('vim.stricmp("\\0c\\0", "\\0B\\0")')) + eq(1, fn.luaeval('vim.stricmp("\\0C\\0", "\\0b\\0")')) + eq(1, fn.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")')) + eq(1, fn.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")')) end) - it('vim.startswith', function() - eq(true, funcs.luaeval('vim.startswith("123", "1")')) - eq(true, funcs.luaeval('vim.startswith("123", "")')) - eq(true, funcs.luaeval('vim.startswith("123", "123")')) - eq(true, funcs.luaeval('vim.startswith("", "")')) + local function test_vim_deprecate(current_version) + -- vim.deprecate(name, alternative, version, plugin, backtrace) + -- See MAINTAIN.md for the soft/hard deprecation policy - eq(false, funcs.luaeval('vim.startswith("123", " ")')) - eq(false, funcs.luaeval('vim.startswith("123", "2")')) - eq(false, funcs.luaeval('vim.startswith("123", "1234")')) + describe(('vim.deprecate [current_version = %s]'):format(current_version), function() + before_each(function() + -- mock vim.version() behavior, should be pinned for consistent testing + exec_lua( + [[ + local current_version_mock = vim.version.parse(...) + getmetatable(vim.version).__call = function() + return current_version_mock + end + ]], + current_version + ) + end) - matches("prefix: expected string, got nil", - pcall_err(exec_lua, 'return vim.startswith("123", nil)')) - matches("s: expected string, got nil", - pcall_err(exec_lua, 'return vim.startswith(nil, "123")')) - end) + it('when plugin = nil', function() + eq( + dedent [[ + foo.bar() is deprecated, use zub.wooo{ok=yay} instead. :help deprecated + This feature will be removed in Nvim version 0.10]], + exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', '0.10') + ) + -- Same message, skipped. + eq(vim.NIL, exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', '0.10')) + + -- Don't show error if not hard-deprecated (only soft-deprecated) + eq( + vim.NIL, + exec_lua('return vim.deprecate(...)', 'foo.baz()', 'foo.better_baz()', '0.12.0') + ) + + -- Show error if hard-deprecated + eq( + dedent [[ + foo.hard_dep() is deprecated, use vim.new_api() instead. :help deprecated + This feature will be removed in Nvim version 0.11]], + exec_lua('return vim.deprecate(...)', 'foo.hard_dep()', 'vim.new_api()', '0.11') + ) + + -- To be deleted in the next major version (1.0) + eq( + dedent [[ + foo.baz() is deprecated. :help deprecated + This feature will be removed in Nvim version 1.0]], + exec_lua [[ return vim.deprecate('foo.baz()', nil, '1.0') ]] + ) + end) - it('vim.endswith', function() - eq(true, funcs.luaeval('vim.endswith("123", "3")')) - eq(true, funcs.luaeval('vim.endswith("123", "")')) - eq(true, funcs.luaeval('vim.endswith("123", "123")')) - eq(true, funcs.luaeval('vim.endswith("", "")')) + it('when plugin is specified', function() + -- When `plugin` is specified, don't show ":help deprecated". #22235 + eq( + dedent [[ + foo.bar() is deprecated, use zub.wooo{ok=yay} instead. + This feature will be removed in my-plugin.nvim version 0.3.0]], + exec_lua( + 'return vim.deprecate(...)', + 'foo.bar()', + 'zub.wooo{ok=yay}', + '0.3.0', + 'my-plugin.nvim', + false + ) + ) + + -- plugins: no soft deprecation period + eq( + dedent [[ + foo.bar() is deprecated, use zub.wooo{ok=yay} instead. + This feature will be removed in my-plugin.nvim version 0.11.0]], + exec_lua( + 'return vim.deprecate(...)', + 'foo.bar()', + 'zub.wooo{ok=yay}', + '0.11.0', + 'my-plugin.nvim', + false + ) + ) + end) + end) + end - eq(false, funcs.luaeval('vim.endswith("123", " ")')) - eq(false, funcs.luaeval('vim.endswith("123", "2")')) - eq(false, funcs.luaeval('vim.endswith("123", "1234")')) + test_vim_deprecate('0.10') + test_vim_deprecate('0.10-dev+g0000000') - matches("suffix: expected string, got nil", - pcall_err(exec_lua, 'return vim.endswith("123", nil)')) - matches("s: expected string, got nil", - pcall_err(exec_lua, 'return vim.endswith(nil, "123")')) + it('vim.startswith', function() + eq(true, fn.luaeval('vim.startswith("123", "1")')) + eq(true, fn.luaeval('vim.startswith("123", "")')) + eq(true, fn.luaeval('vim.startswith("123", "123")')) + eq(true, fn.luaeval('vim.startswith("", "")')) + + eq(false, fn.luaeval('vim.startswith("123", " ")')) + eq(false, fn.luaeval('vim.startswith("123", "2")')) + eq(false, fn.luaeval('vim.startswith("123", "1234")')) + + matches( + 'prefix: expected string, got nil', + pcall_err(exec_lua, 'return vim.startswith("123", nil)') + ) + matches('s: expected string, got nil', pcall_err(exec_lua, 'return vim.startswith(nil, "123")')) + end) + + it('vim.endswith', function() + eq(true, fn.luaeval('vim.endswith("123", "3")')) + eq(true, fn.luaeval('vim.endswith("123", "")')) + eq(true, fn.luaeval('vim.endswith("123", "123")')) + eq(true, fn.luaeval('vim.endswith("", "")')) + + eq(false, fn.luaeval('vim.endswith("123", " ")')) + eq(false, fn.luaeval('vim.endswith("123", "2")')) + eq(false, fn.luaeval('vim.endswith("123", "1234")')) + + matches( + 'suffix: expected string, got nil', + pcall_err(exec_lua, 'return vim.endswith("123", nil)') + ) + matches('s: expected string, got nil', pcall_err(exec_lua, 'return vim.endswith(nil, "123")')) end) - it("vim.str_utfindex/str_byteindex", function() + it('vim.str_utfindex/str_byteindex', function() exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ\000ъ"]]) - local indices32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48,49,51} - local indices16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48,49,51} - for i,k in pairs(indices32) do - eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i) + local indices32 = { + [0] = 0, + 1, + 2, + 3, + 5, + 7, + 9, + 10, + 12, + 13, + 16, + 19, + 20, + 23, + 24, + 28, + 29, + 33, + 34, + 35, + 37, + 38, + 40, + 42, + 44, + 46, + 48, + 49, + 51, + } + local indices16 = { + [0] = 0, + 1, + 2, + 3, + 5, + 7, + 9, + 10, + 12, + 13, + 16, + 19, + 20, + 23, + 24, + 28, + 28, + 29, + 33, + 33, + 34, + 35, + 37, + 38, + 40, + 42, + 44, + 46, + 48, + 49, + 51, + } + for i, k in pairs(indices32) do + eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ...)', i), i) end - for i,k in pairs(indices16) do - eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i) + for i, k in pairs(indices16) do + eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., true)', i), i) end - eq("index out of range", pcall_err(exec_lua, "return vim.str_byteindex(_G.test_text, ...)", #indices32 + 1)) - eq("index out of range", pcall_err(exec_lua, "return vim.str_byteindex(_G.test_text, ..., true)", #indices16 + 1)) + eq( + 'index out of range', + pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ...)', #indices32 + 1) + ) + eq( + 'index out of range', + pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ..., true)', #indices16 + 1) + ) local i32, i16 = 0, 0 local len = 51 - for k = 0,len do + for k = 0, len do if indices32[i32] < k then i32 = i32 + 1 end if indices16[i16] < k then i16 = i16 + 1 - if indices16[i16+1] == indices16[i16] then + if indices16[i16 + 1] == indices16[i16] then i16 = i16 + 1 end end - eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k) + eq({ i32, i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, ...)}', k), k) end - eq("index out of range", pcall_err(exec_lua, "return vim.str_utfindex(_G.test_text, ...)", len + 1)) + eq( + 'index out of range', + pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, ...)', len + 1) + ) end) - it("vim.str_utf_start", function() + it('vim.str_utf_start', function() exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]]) - local expected_positions = {0,0,0,0,-1,0,-1,0,-1,0,0,-1,0,0,-1,-2,0,-1,-2,0,0,-1,-2,0,0,-1,-2,-3,0,0,-1,-2,-3,0,0,0,-1,0,0,-1,0,-1,0,-1,0,-1,0,-1} - eq(expected_positions, exec_lua([[ + local expected_positions = { + 0, + 0, + 0, + 0, + -1, + 0, + -1, + 0, + -1, + 0, + 0, + -1, + 0, + 0, + -1, + -2, + 0, + -1, + -2, + 0, + 0, + -1, + -2, + 0, + 0, + -1, + -2, + -3, + 0, + 0, + -1, + -2, + -3, + 0, + 0, + 0, + -1, + 0, + 0, + -1, + 0, + -1, + 0, + -1, + 0, + -1, + 0, + -1, + } + eq( + expected_positions, + exec_lua([[ local start_codepoint_positions = {} for idx = 1, #_G.test_text do table.insert(start_codepoint_positions, vim.str_utf_start(_G.test_text, idx)) end return start_codepoint_positions - ]])) + ]]) + ) end) - it("vim.str_utf_end", function() + it('vim.str_utf_end', function() exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]]) - local expected_positions = {0,0,0,1,0,1,0,1,0,0,1,0,0,2,1,0,2,1,0,0,2,1,0,0,3,2,1,0,0,3,2,1,0,0,0,1,0,0,1,0,1,0,1,0,1,0,1,0 } - eq(expected_positions, exec_lua([[ + local expected_positions = { + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 2, + 1, + 0, + 2, + 1, + 0, + 0, + 2, + 1, + 0, + 0, + 3, + 2, + 1, + 0, + 0, + 3, + 2, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + } + eq( + expected_positions, + exec_lua([[ local end_codepoint_positions = {} for idx = 1, #_G.test_text do table.insert(end_codepoint_positions, vim.str_utf_end(_G.test_text, idx)) end return end_codepoint_positions - ]])) + ]]) + ) end) - - it("vim.str_utf_pos", function() + it('vim.str_utf_pos', function() exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]]) - local expected_positions = { 1,2,3,4,6,8,10,11,13,14,17,20,21,24,25,29,30,34,35,36,38,39,41,43,45,47 } - eq(expected_positions, exec_lua("return vim.str_utf_pos(_G.test_text)")) + local expected_positions = { + 1, + 2, + 3, + 4, + 6, + 8, + 10, + 11, + 13, + 14, + 17, + 20, + 21, + 24, + 25, + 29, + 30, + 34, + 35, + 36, + 38, + 39, + 41, + 43, + 45, + 47, + } + eq(expected_positions, exec_lua('return vim.str_utf_pos(_G.test_text)')) end) - it("vim.schedule", function() + it('vim.schedule', function() exec_lua([[ test_table = {} vim.schedule(function() @@ -244,13 +519,11 @@ describe('lua stdlib', function() end) table.insert(test_table, "yy") ]]) - eq({"yy","xx"}, exec_lua("return test_table")) + eq({ 'yy', 'xx' }, exec_lua('return test_table')) -- Validates args. - matches('vim.schedule: expected function', - pcall_err(exec_lua, "vim.schedule('stringly')")) - matches('vim.schedule: expected function', - pcall_err(exec_lua, "vim.schedule()")) + matches('vim.schedule: expected function', pcall_err(exec_lua, "vim.schedule('stringly')")) + matches('vim.schedule: expected function', pcall_err(exec_lua, 'vim.schedule()')) exec_lua([[ vim.schedule(function() @@ -258,24 +531,24 @@ describe('lua stdlib', function() end) ]]) - feed("<cr>") - matches('big failure\nvery async', remove_trace(eval("v:errmsg"))) + feed('<cr>') + matches('big failure\nvery async', remove_trace(eval('v:errmsg'))) - local screen = Screen.new(60,5) + local screen = Screen.new(60, 5) screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { bold = true, reverse = true }, + [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, }) screen:attach() - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {1:~ }| - {1:~ }| - {1:~ }| + {1:~ }|*3 | - ]]} + ]], + } -- nvim_command causes a Vimscript exception, check that it is properly caught -- and propagated as an error message in async contexts.. #10809 @@ -284,62 +557,61 @@ describe('lua stdlib', function() vim.api.nvim_command(":echo 'err") end) ]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ {3:stack traceback:} | {3: [C]: in function 'nvim_command'} | {3: [string "<nvim>"]:2: in function <[string "<nvim>"]:}| {3:1>} | {4:Press ENTER or type command to continue}^ | - ]]} + ]], + } end) it('vim.gsplit, vim.split', function() local tests = { -- plain trimempty - { 'a,b', ',', false, false, { 'a', 'b' } }, - { ':aa::::bb:', ':', false, false, { '', 'aa', '', '', '', 'bb', '' } }, - { ':aa::::bb:', ':', false, true, { 'aa', '', '', '', 'bb' } }, - { 'aa::::bb:', ':', false, true, { 'aa', '', '', '', 'bb' } }, - { ':aa::bb:', ':', false, true, { 'aa', '', 'bb' } }, - { '/a/b:/b/\n', '[:\n]', false, true, { '/a/b', '/b/' } }, - { '::ee::ff:', ':', false, false, { '', '', 'ee', '', 'ff', '' } }, - { '::ee::ff::', ':', false, true, { 'ee', '', 'ff' } }, - { 'ab', '.', false, false, { '', '', '' } }, - { 'a1b2c', '[0-9]', false, false, { 'a', 'b', 'c' } }, - { 'xy', '', false, false, { 'x', 'y' } }, - { 'here be dragons', ' ', false, false, { 'here', 'be', 'dragons'} }, - { 'axaby', 'ab?', false, false, { '', 'x', 'y' } }, - { 'f v2v v3v w2w ', '([vw])2%1', false, false, { 'f ', ' v3v ', ' ' } }, - { '', '', false, false, {} }, - { '', '', false, true, {} }, - { '\n', '[:\n]', false, true, {} }, - { '', 'a', false, false, { '' } }, - { 'x*yz*oo*l', '*', true, false, { 'x', 'yz', 'oo', 'l' } }, + { 'a,b', ',', false, false, { 'a', 'b' } }, + { ':aa::::bb:', ':', false, false, { '', 'aa', '', '', '', 'bb', '' } }, + { ':aa::::bb:', ':', false, true, { 'aa', '', '', '', 'bb' } }, + { 'aa::::bb:', ':', false, true, { 'aa', '', '', '', 'bb' } }, + { ':aa::bb:', ':', false, true, { 'aa', '', 'bb' } }, + { '/a/b:/b/\n', '[:\n]', false, true, { '/a/b', '/b/' } }, + { '::ee::ff:', ':', false, false, { '', '', 'ee', '', 'ff', '' } }, + { '::ee::ff::', ':', false, true, { 'ee', '', 'ff' } }, + { 'ab', '.', false, false, { '', '', '' } }, + { 'a1b2c', '[0-9]', false, false, { 'a', 'b', 'c' } }, + { 'xy', '', false, false, { 'x', 'y' } }, + { 'here be dragons', ' ', false, false, { 'here', 'be', 'dragons' } }, + { 'axaby', 'ab?', false, false, { '', 'x', 'y' } }, + { 'f v2v v3v w2w ', '([vw])2%1', false, false, { 'f ', ' v3v ', ' ' } }, + { '', '', false, false, {} }, + { '', '', false, true, {} }, + { '\n', '[:\n]', false, true, {} }, + { '', 'a', false, false, { '' } }, + { 'x*yz*oo*l', '*', true, false, { 'x', 'yz', 'oo', 'l' } }, } for _, t in ipairs(tests) do - eq(t[5], vim.split(t[1], t[2], {plain=t[3], trimempty=t[4]}), t[1]) + eq(t[5], vim.split(t[1], t[2], { plain = t[3], trimempty = t[4] }), t[1]) end -- Test old signature - eq({'x', 'yz', 'oo', 'l'}, vim.split("x*yz*oo*l", "*", true)) + eq({ 'x', 'yz', 'oo', 'l' }, vim.split('x*yz*oo*l', '*', true)) local loops = { - { "abc", ".-" }, + { 'abc', '.-' }, } for _, t in ipairs(loops) do - matches("Infinite loop detected", pcall_err(vim.split, t[1], t[2])) + matches('Infinite loop detected', pcall_err(vim.split, t[1], t[2])) end -- Validates args. eq(true, pcall(vim.split, 'string', 'string')) - matches('s: expected string, got number', - pcall_err(vim.split, 1, 'string')) - matches('sep: expected string, got number', - pcall_err(vim.split, 'string', 1)) - matches('opts: expected table, got number', - pcall_err(vim.split, 'string', 'string', 1)) + matches('s: expected string, got number', pcall_err(vim.split, 1, 'string')) + matches('sep: expected string, got number', pcall_err(vim.split, 'string', 1)) + matches('opts: expected table, got number', pcall_err(vim.split, 'string', 'string', 1)) end) it('vim.trim', function() @@ -348,10 +620,10 @@ describe('lua stdlib', function() end local trims = { - { " a", "a" }, - { " b ", "b" }, - { "\tc" , "c" }, - { "r\n", "r" }, + { ' a', 'a' }, + { ' b ', 'b' }, + { '\tc', 'c' }, + { 'r\n', 'r' }, } for _, t in ipairs(trims) do @@ -359,8 +631,7 @@ describe('lua stdlib', function() end -- Validates args. - matches('s: expected string, got number', - pcall_err(trim, 2)) + matches('s: expected string, got number', pcall_err(trim, 2)) end) it('vim.inspect', function() @@ -370,21 +641,23 @@ describe('lua stdlib', function() end eq('2', inspect(2)) - eq('{+a = {+b = 1+}+}', - inspect({ a = { b = 1 } }, { newline = '+', indent = '' })) + eq('{+a = {+b = 1+}+}', inspect({ a = { b = 1 } }, { newline = '+', indent = '' })) -- special value vim.inspect.KEY works - eq('{ KEY_a = "x", KEY_b = "y"}', exec_lua([[ + eq( + '{ KEY_a = "x", KEY_b = "y"}', + exec_lua([[ return vim.inspect({a="x", b="y"}, {newline = '', process = function(item, path) if path[#path] == vim.inspect.KEY then return 'KEY_'..item end return item end}) - ]])) + ]]) + ) end) - it("vim.deepcopy", function() + it('vim.deepcopy', function() ok(exec_lua([[ local a = { x = { 1, 2 }, y = 5} local b = vim.deepcopy(a) @@ -445,23 +718,27 @@ describe('lua stdlib', function() return t2.a == vim.NIL ]])) - matches('Cannot deepcopy object of type thread', - pcall_err(exec_lua, [[ + matches( + 'Cannot deepcopy object of type thread', + pcall_err( + exec_lua, + [[ local thread = coroutine.create(function () return 0 end) local t = {thr = thread} vim.deepcopy(t) - ]])) + ]] + ) + ) end) it('vim.pesc', function() eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]])) eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]])) -- pesc() returns one result. #20751 - eq({'x'}, exec_lua([[return {vim.pesc('x')}]])) + eq({ 'x' }, exec_lua([[return {vim.pesc('x')}]])) -- Validates args. - matches('s: expected string, got number', - pcall_err(exec_lua, [[return vim.pesc(2)]])) + matches('s: expected string, got number', pcall_err(exec_lua, [[return vim.pesc(2)]])) end) it('vim.list_contains', function() @@ -473,97 +750,131 @@ describe('lua stdlib', function() eq(true, exec_lua("return vim.tbl_contains({'a','b','c'}, 'c')")) eq(false, exec_lua("return vim.tbl_contains({'a','b','c'}, 'd')")) eq(true, exec_lua("return vim.tbl_contains({[2]='a',foo='b',[5] = 'c'}, 'c')")) - eq(true, exec_lua([[ + eq( + true, + exec_lua([[ return vim.tbl_contains({ 'a', { 'b', 'c' } }, function(v) return vim.deep_equal(v, { 'b', 'c' }) end, { predicate = true }) - ]])) + ]]) + ) end) it('vim.tbl_keys', function() - eq({}, exec_lua("return vim.tbl_keys({})")) + eq({}, exec_lua('return vim.tbl_keys({})')) for _, v in pairs(exec_lua("return vim.tbl_keys({'a', 'b', 'c'})")) do - eq(true, exec_lua("return vim.tbl_contains({ 1, 2, 3 }, ...)", v)) + eq(true, exec_lua('return vim.tbl_contains({ 1, 2, 3 }, ...)', v)) end - for _, v in pairs(exec_lua("return vim.tbl_keys({a=1, b=2, c=3})")) do + for _, v in pairs(exec_lua('return vim.tbl_keys({a=1, b=2, c=3})')) do eq(true, exec_lua("return vim.tbl_contains({ 'a', 'b', 'c' }, ...)", v)) end end) it('vim.tbl_values', function() - eq({}, exec_lua("return vim.tbl_values({})")) + eq({}, exec_lua('return vim.tbl_values({})')) for _, v in pairs(exec_lua("return vim.tbl_values({'a', 'b', 'c'})")) do eq(true, exec_lua("return vim.tbl_contains({ 'a', 'b', 'c' }, ...)", v)) end - for _, v in pairs(exec_lua("return vim.tbl_values({a=1, b=2, c=3})")) do - eq(true, exec_lua("return vim.tbl_contains({ 1, 2, 3 }, ...)", v)) + for _, v in pairs(exec_lua('return vim.tbl_values({a=1, b=2, c=3})')) do + eq(true, exec_lua('return vim.tbl_contains({ 1, 2, 3 }, ...)', v)) end end) it('vim.tbl_map', function() - eq({}, exec_lua([[ + eq( + {}, + exec_lua([[ return vim.tbl_map(function(v) return v * 2 end, {}) - ]])) - eq({2, 4, 6}, exec_lua([[ + ]]) + ) + eq( + { 2, 4, 6 }, + exec_lua([[ return vim.tbl_map(function(v) return v * 2 end, {1, 2, 3}) - ]])) - eq({{i=2}, {i=4}, {i=6}}, exec_lua([[ + ]]) + ) + eq( + { { i = 2 }, { i = 4 }, { i = 6 } }, + exec_lua([[ return vim.tbl_map(function(v) return { i = v.i * 2 } end, {{i=1}, {i=2}, {i=3}}) - ]])) + ]]) + ) end) it('vim.tbl_filter', function() - eq({}, exec_lua([[ + eq( + {}, + exec_lua([[ return vim.tbl_filter(function(v) return (v % 2) == 0 end, {}) - ]])) - eq({2}, exec_lua([[ + ]]) + ) + eq( + { 2 }, + exec_lua([[ return vim.tbl_filter(function(v) return (v % 2) == 0 end, {1, 2, 3}) - ]])) - eq({{i=2}}, exec_lua([[ + ]]) + ) + eq( + { { i = 2 } }, + exec_lua([[ return vim.tbl_filter(function(v) return (v.i % 2) == 0 end, {{i=1}, {i=2}, {i=3}}) - ]])) + ]]) + ) end) it('vim.tbl_isarray', function() - eq(true, exec_lua("return vim.tbl_isarray({})")) - eq(false, exec_lua("return vim.tbl_isarray(vim.empty_dict())")) + eq(true, exec_lua('return vim.tbl_isarray({})')) + eq(false, exec_lua('return vim.tbl_isarray(vim.empty_dict())')) eq(true, exec_lua("return vim.tbl_isarray({'a', 'b', 'c'})")) eq(false, exec_lua("return vim.tbl_isarray({'a', '32', a='hello', b='baz'})")) eq(false, exec_lua("return vim.tbl_isarray({1, a='hello', b='baz'})")) eq(false, exec_lua("return vim.tbl_isarray({a='hello', b='baz', 1})")) eq(false, exec_lua("return vim.tbl_isarray({1, 2, nil, a='hello'})")) - eq(true, exec_lua("return vim.tbl_isarray({1, 2, nil, 4})")) - eq(true, exec_lua("return vim.tbl_isarray({nil, 2, 3, 4})")) - eq(false, exec_lua("return vim.tbl_isarray({1, [1.5]=2, [3]=3})")) + eq(true, exec_lua('return vim.tbl_isarray({1, 2, nil, 4})')) + eq(true, exec_lua('return vim.tbl_isarray({nil, 2, 3, 4})')) + eq(false, exec_lua('return vim.tbl_isarray({1, [1.5]=2, [3]=3})')) end) it('vim.tbl_islist', function() - eq(true, exec_lua("return vim.tbl_islist({})")) - eq(false, exec_lua("return vim.tbl_islist(vim.empty_dict())")) + eq(true, exec_lua('return vim.tbl_islist({})')) + eq(false, exec_lua('return vim.tbl_islist(vim.empty_dict())')) eq(true, exec_lua("return vim.tbl_islist({'a', 'b', 'c'})")) eq(false, exec_lua("return vim.tbl_islist({'a', '32', a='hello', b='baz'})")) eq(false, exec_lua("return vim.tbl_islist({1, a='hello', b='baz'})")) eq(false, exec_lua("return vim.tbl_islist({a='hello', b='baz', 1})")) eq(false, exec_lua("return vim.tbl_islist({1, 2, nil, a='hello'})")) - eq(false, exec_lua("return vim.tbl_islist({1, 2, nil, 4})")) - eq(false, exec_lua("return vim.tbl_islist({nil, 2, 3, 4})")) - eq(false, exec_lua("return vim.tbl_islist({1, [1.5]=2, [3]=3})")) + eq(false, exec_lua('return vim.tbl_islist({1, 2, nil, 4})')) + eq(false, exec_lua('return vim.tbl_islist({nil, 2, 3, 4})')) + eq(false, exec_lua('return vim.tbl_islist({1, [1.5]=2, [3]=3})')) end) it('vim.tbl_isempty', function() - eq(true, exec_lua("return vim.tbl_isempty({})")) - eq(false, exec_lua("return vim.tbl_isempty({ 1, 2, 3 })")) - eq(false, exec_lua("return vim.tbl_isempty({a=1, b=2, c=3})")) + eq(true, exec_lua('return vim.tbl_isempty({})')) + eq(false, exec_lua('return vim.tbl_isempty({ 1, 2, 3 })')) + eq(false, exec_lua('return vim.tbl_isempty({a=1, b=2, c=3})')) end) it('vim.tbl_get', function() - eq(true, exec_lua("return vim.tbl_get({ test = { nested_test = true }}, 'test', 'nested_test')")) + eq( + true, + exec_lua("return vim.tbl_get({ test = { nested_test = true }}, 'test', 'nested_test')") + ) eq(NIL, exec_lua("return vim.tbl_get({ unindexable = true }, 'unindexable', 'missing_key')")) eq(NIL, exec_lua("return vim.tbl_get({ unindexable = 1 }, 'unindexable', 'missing_key')")) - eq(NIL, exec_lua("return vim.tbl_get({ unindexable = coroutine.create(function () end) }, 'unindexable', 'missing_key')")) - eq(NIL, exec_lua("return vim.tbl_get({ unindexable = function () end }, 'unindexable', 'missing_key')")) + eq( + NIL, + exec_lua( + "return vim.tbl_get({ unindexable = coroutine.create(function () end) }, 'unindexable', 'missing_key')" + ) + ) + eq( + NIL, + exec_lua( + "return vim.tbl_get({ unindexable = function () end }, 'unindexable', 'missing_key')" + ) + ) eq(NIL, exec_lua("return vim.tbl_get({}, 'missing_key')")) - eq(NIL, exec_lua("return vim.tbl_get({})")) + eq(NIL, exec_lua('return vim.tbl_get({})')) eq(1, exec_lua("return select('#', vim.tbl_get({}))")) eq(1, exec_lua("return select('#', vim.tbl_get({ nested = {} }, 'nested', 'missing_key'))")) end) @@ -629,22 +940,34 @@ describe('lua stdlib', function() return c.x.a == 1 and c.x.b == 2 and c.x.c == nil and count == 1 ]])) - matches('invalid "behavior": nil', - pcall_err(exec_lua, [[ + matches( + 'invalid "behavior": nil', + pcall_err( + exec_lua, + [[ return vim.tbl_extend() - ]]) + ]] + ) ) - matches('wrong number of arguments %(given 1, expected at least 3%)', - pcall_err(exec_lua, [[ + matches( + 'wrong number of arguments %(given 1, expected at least 3%)', + pcall_err( + exec_lua, + [[ return vim.tbl_extend("keep") - ]]) + ]] + ) ) - matches('wrong number of arguments %(given 2, expected at least 3%)', - pcall_err(exec_lua, [[ + matches( + 'wrong number of arguments %(given 2, expected at least 3%)', + pcall_err( + exec_lua, + [[ return vim.tbl_extend("keep", {}) - ]]) + ]] + ) ) end) @@ -717,17 +1040,23 @@ describe('lua stdlib', function() return vim.tbl_islist(c) and count == 0 ]])) - eq({a = {b = 1}}, exec_lua([[ + eq( + { a = { b = 1 } }, + exec_lua([[ local a = { a = { b = 1 } } local b = { a = {} } return vim.tbl_deep_extend("force", a, b) - ]])) + ]]) + ) - eq({a = {b = 1}}, exec_lua([[ + eq( + { a = { b = 1 } }, + exec_lua([[ local a = { a = 123 } local b = { a = { b = 1} } return vim.tbl_deep_extend("force", a, b) - ]])) + ]]) + ) ok(exec_lua([[ local a = { a = {[2] = 3} } @@ -736,28 +1065,43 @@ describe('lua stdlib', function() return vim.deep_equal(c, {a = {[3] = 3}}) ]])) - eq({a = 123}, exec_lua([[ + eq( + { a = 123 }, + exec_lua([[ local a = { a = { b = 1} } local b = { a = 123 } return vim.tbl_deep_extend("force", a, b) - ]])) + ]]) + ) - matches('invalid "behavior": nil', - pcall_err(exec_lua, [[ + matches( + 'invalid "behavior": nil', + pcall_err( + exec_lua, + [[ return vim.tbl_deep_extend() - ]]) + ]] + ) ) - matches('wrong number of arguments %(given 1, expected at least 3%)', - pcall_err(exec_lua, [[ + matches( + 'wrong number of arguments %(given 1, expected at least 3%)', + pcall_err( + exec_lua, + [[ return vim.tbl_deep_extend("keep") - ]]) + ]] + ) ) - matches('wrong number of arguments %(given 2, expected at least 3%)', - pcall_err(exec_lua, [[ + matches( + 'wrong number of arguments %(given 2, expected at least 3%)', + pcall_err( + exec_lua, + [[ return vim.tbl_deep_extend("keep", {}) - ]]) + ]] + ) ) end) @@ -786,23 +1130,28 @@ describe('lua stdlib', function() end) it('vim.list_extend', function() - eq({1,2,3}, exec_lua [[ return vim.list_extend({1}, {2,3}) ]]) - matches('src: expected table, got nil', - pcall_err(exec_lua, [[ return vim.list_extend({1}, nil) ]])) - eq({1,2}, exec_lua [[ return vim.list_extend({1}, {2;a=1}) ]]) + eq({ 1, 2, 3 }, exec_lua [[ return vim.list_extend({1}, {2,3}) ]]) + matches( + 'src: expected table, got nil', + pcall_err(exec_lua, [[ return vim.list_extend({1}, nil) ]]) + ) + eq({ 1, 2 }, exec_lua [[ return vim.list_extend({1}, {2;a=1}) ]]) eq(true, exec_lua [[ local a = {1} return vim.list_extend(a, {2;a=1}) == a ]]) - eq({2}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1) ]]) + eq({ 2 }, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1) ]]) eq({}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 2) ]]) eq({}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1, -1) ]]) - eq({2}, exec_lua [[ return vim.list_extend({}, {2;a=1}, -1, 2) ]]) + eq({ 2 }, exec_lua [[ return vim.list_extend({}, {2;a=1}, -1, 2) ]]) end) it('vim.tbl_add_reverse_lookup', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ local a = { A = 1 } vim.tbl_add_reverse_lookup(a) return vim.deep_equal(a, { A = 1; [1] = 'A'; }) - ]]) + ]] + ) -- Throw an error for trying to do it twice (run into an existing key) local code = [[ local res = {} @@ -811,17 +1160,19 @@ describe('lua stdlib', function() assert(vim.deep_equal(a, { A = 1; [1] = 'A'; })) vim.tbl_add_reverse_lookup(a) ]] - matches('The reverse lookup found an existing value for "[1A]" while processing key "[1A]"$', - pcall_err(exec_lua, code)) + matches( + 'The reverse lookup found an existing value for "[1A]" while processing key "[1A]"$', + pcall_err(exec_lua, code) + ) end) it('vim.spairs', function() local res = '' local table = { - ccc=1, - bbb=2, - ddd=3, - aaa=4 + ccc = 1, + bbb = 2, + ddd = 3, + aaa = 4, } for key, _ in vim.spairs(table) do res = res .. key @@ -848,37 +1199,51 @@ describe('lua stdlib', function() endfunc ]]) eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]])) - eq(3, eval("g:test")) + eq(3, eval('g:test')) -- compat: nvim_call_function uses "special" value for empty dict eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]])) - eq(5, eval("g:test")) + eq(5, eval('g:test')) - eq({2, "foo", true}, exec_lua([[return vim.fn.VarArg(2, "foo", true)]])) + eq({ 2, 'foo', true }, exec_lua([[return vim.fn.VarArg(2, "foo", true)]])) - eq(true, exec_lua([[ + eq( + true, + exec_lua([[ local x = vim.fn.Nilly() return #x == 2 and x[1] == vim.NIL and x[2] == vim.NIL - ]])) - eq({NIL, NIL}, exec_lua([[return vim.fn.Nilly()]])) + ]]) + ) + eq({ NIL, NIL }, exec_lua([[return vim.fn.Nilly()]])) -- error handling - eq({false, 'Vim:E897: List or Blob required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]])) + eq( + { false, 'Vim:E897: List or Blob required' }, + exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]]) + ) -- conversion between LuaRef and Vim Funcref - eq(true, exec_lua([[ + eq( + true, + exec_lua([[ local x = vim.fn.VarArg(function() return 'foo' end, function() return 'bar' end) return #x == 2 and x[1]() == 'foo' and x[2]() == 'bar' - ]])) + ]]) + ) -- Test for #20211 - eq('a (b) c', exec_lua([[ + eq( + 'a (b) c', + exec_lua([[ return vim.fn.substitute('a b c', 'b', function(m) return '(' .. m[1] .. ')' end, 'g') - ]])) + ]]) + ) end) it('vim.fn should error when calling API function', function() - matches('Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead', - pcall_err(exec_lua, "vim.fn.nvim_get_current_line()")) + matches( + 'Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead', + pcall_err(exec_lua, 'vim.fn.nvim_get_current_line()') + ) end) it('vim.fn is allowed in "fast" context by some functions #18306', function() @@ -891,8 +1256,8 @@ describe('lua stdlib', function() end) ]]) - helpers.poke_eventloop() - eq('hello', exec_lua[[return vim.g.fnres]]) + poke_eventloop() + eq('hello', exec_lua [[return vim.g.fnres]]) end) it('vim.rpcrequest and vim.rpcnotify', function() @@ -900,52 +1265,60 @@ describe('lua stdlib', function() chan = vim.fn.jobstart({'cat'}, {rpc=true}) vim.rpcrequest(chan, 'nvim_set_current_line', 'meow') ]]) - eq('meow', meths.get_current_line()) + eq('meow', api.nvim_get_current_line()) command("let x = [3, 'aa', v:true, v:null]") - eq(true, exec_lua([[ + eq( + true, + exec_lua([[ ret = vim.rpcrequest(chan, 'nvim_get_var', 'x') return #ret == 4 and ret[1] == 3 and ret[2] == 'aa' and ret[3] == true and ret[4] == vim.NIL - ]])) - eq({3, 'aa', true, NIL}, exec_lua([[return ret]])) + ]]) + ) + eq({ 3, 'aa', true, NIL }, exec_lua([[return ret]])) - eq({{}, {}, false, true}, exec_lua([[ + eq( + { {}, {}, false, true }, + exec_lua([[ vim.rpcrequest(chan, 'nvim_exec', 'let xx = {}\nlet yy = []', false) local dict = vim.rpcrequest(chan, 'nvim_eval', 'xx') local list = vim.rpcrequest(chan, 'nvim_eval', 'yy') return {dict, list, vim.tbl_islist(dict), vim.tbl_islist(list)} - ]])) + ]]) + ) - exec_lua([[ + exec_lua([[ vim.rpcrequest(chan, 'nvim_set_var', 'aa', {}) vim.rpcrequest(chan, 'nvim_set_var', 'bb', vim.empty_dict()) ]]) - eq({1, 1}, eval('[type(g:aa) == type([]), type(g:bb) == type({})]')) + eq({ 1, 1 }, eval('[type(g:aa) == type([]), type(g:bb) == type({})]')) -- error handling - eq({false, 'Invalid channel: 23'}, - exec_lua([[return {pcall(vim.rpcrequest, 23, 'foo')}]])) - eq({false, 'Invalid channel: 23'}, - exec_lua([[return {pcall(vim.rpcnotify, 23, 'foo')}]])) - - eq({false, 'Vim:E121: Undefined variable: foobar'}, - exec_lua([[return {pcall(vim.rpcrequest, chan, 'nvim_eval', "foobar")}]])) + eq({ false, 'Invalid channel: 23' }, exec_lua([[return {pcall(vim.rpcrequest, 23, 'foo')}]])) + eq({ false, 'Invalid channel: 23' }, exec_lua([[return {pcall(vim.rpcnotify, 23, 'foo')}]])) + eq( + { false, 'Vim:E121: Undefined variable: foobar' }, + exec_lua([[return {pcall(vim.rpcrequest, chan, 'nvim_eval', "foobar")}]]) + ) -- rpcnotify doesn't wait on request - eq('meow', exec_lua([[ + eq( + 'meow', + exec_lua([[ vim.rpcnotify(chan, 'nvim_set_current_line', 'foo') return vim.api.nvim_get_current_line() - ]])) + ]]) + ) retry(10, nil, function() - eq('foo', meths.get_current_line()) + eq('foo', api.nvim_get_current_line()) end) - local screen = Screen.new(50,7) + local screen = Screen.new(50, 7) screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - [2] = {bold = true, reverse = true}, - [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [1] = { bold = true, foreground = Screen.colors.Blue1 }, + [2] = { bold = true, reverse = true }, + [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, }) screen:attach() exec_lua([[ @@ -957,7 +1330,8 @@ describe('lua stdlib', function() vim.rpcrequest(chan, 'nvim_set_current_line', 'bork') end) ]]) - screen:expect{grid=[[ + screen:expect { + grid = [[ {3:[string "<nvim>"]:6: E5560: rpcrequest must not be}| {3: called in a lua loop callback} | {3:stack traceback:} | @@ -965,35 +1339,42 @@ describe('lua stdlib', function() {3: [string "<nvim>"]:6: in function <[string }| {3:"<nvim>"]:2>} | {4:Press ENTER or type command to continue}^ | - ]]} + ]], + } feed('<cr>') - eq({3, NIL}, meths.get_var('yy')) + eq({ 3, NIL }, api.nvim_get_var('yy')) exec_lua([[timer:close()]]) end) it('vim.empty_dict()', function() - eq({true, false, true, true}, exec_lua([[ + eq( + { true, false, true, true }, + exec_lua([[ vim.api.nvim_set_var('listy', {}) vim.api.nvim_set_var('dicty', vim.empty_dict()) local listy = vim.fn.eval("listy") local dicty = vim.fn.eval("dicty") return {vim.tbl_islist(listy), vim.tbl_islist(dicty), next(listy) == nil, next(dicty) == nil} - ]])) + ]]) + ) -- vim.empty_dict() gives new value each time -- equality is not overridden (still by ref) -- non-empty table uses the usual heuristics (ignores the tag) - eq({false, {"foo"}, {namey="bar"}}, exec_lua([[ + eq( + { false, { 'foo' }, { namey = 'bar' } }, + exec_lua([[ local aa = vim.empty_dict() local bb = vim.empty_dict() local equally = (aa == bb) aa[1] = "foo" bb["namey"] = "bar" return {equally, aa, bb} - ]])) + ]]) + ) - eq("{ {}, vim.empty_dict() }", exec_lua("return vim.inspect({{}, vim.empty_dict()})")) + eq('{ {}, vim.empty_dict() }', exec_lua('return vim.inspect({{}, vim.empty_dict()})')) eq('{}', exec_lua([[ return vim.fn.json_encode(vim.empty_dict()) ]])) eq('{"a": {}, "b": []}', exec_lua([[ return vim.fn.json_encode({a=vim.empty_dict(), b={}}) ]])) end) @@ -1028,56 +1409,72 @@ describe('lua stdlib', function() 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'} }}") - 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('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 }}')) -- Validated parameters are required by default. - matches('arg1: expected string, got nil', - pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's' }}")) + matches( + 'arg1: expected string, got nil', + pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's' }}") + ) -- Explicitly required. - matches('arg1: expected string, got nil', - pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's', false }}")) - - matches('arg1: expected table, got number', - pcall_err(exec_lua, "vim.validate{arg1={1, 't'}}")) - matches('arg2: expected string, got number', - pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}")) - matches('arg2: expected string, got nil', - pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")) - matches('arg2: expected string, got nil', - pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")) - 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, {'n', 's'} }}")) + matches( + 'arg1: expected string, got nil', + pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's', false }}") + ) + + matches('arg1: expected table, got number', pcall_err(exec_lua, "vim.validate{arg1={1, 't'}}")) + matches( + 'arg2: expected string, got number', + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}") + ) + matches( + 'arg2: expected string, got nil', + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}") + ) + matches( + 'arg2: expected string, got nil', + pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}") + ) + 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, {'n', 's'} }}") + ) -- 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}}")) + 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.is_callable', function() - eq(true, exec_lua("return vim.is_callable(function()end)")) - eq(true, exec_lua([[ + eq(true, exec_lua('return vim.is_callable(function()end)')) + eq( + true, + exec_lua([[ local meta = { __call = function()end } local function new_callable() return setmetatable({}, meta) end local callable = new_callable() return vim.is_callable(callable) - ]])) + ]]) + ) - eq(false, exec_lua("return vim.is_callable(1)")) + eq(false, exec_lua('return vim.is_callable(1)')) eq(false, exec_lua("return vim.is_callable('foo')")) - eq(false, exec_lua("return vim.is_callable({})")) + eq(false, exec_lua('return vim.is_callable({})')) end) it('vim.g', function() @@ -1089,24 +1486,26 @@ describe('lua stdlib', function() vim.api.nvim_set_var("to_delete", {hello="world"}) ]] - eq('hi', funcs.luaeval "vim.g.testing") - eq(123, funcs.luaeval "vim.g.other") - eq(5120.1, funcs.luaeval "vim.g.floaty") - eq(NIL, funcs.luaeval "vim.g.nonexistent") - eq(NIL, funcs.luaeval "vim.g.nullvar") + eq('hi', fn.luaeval 'vim.g.testing') + eq(123, fn.luaeval 'vim.g.other') + eq(5120.1, fn.luaeval 'vim.g.floaty') + eq(NIL, fn.luaeval 'vim.g.nonexistent') + eq(NIL, fn.luaeval 'vim.g.nullvar') -- lost over RPC, so test locally: - eq({false, true}, exec_lua [[ + eq( + { false, true }, + exec_lua [[ return {vim.g.nonexistent == vim.NIL, vim.g.nullvar == vim.NIL} - ]]) + ]] + ) - eq({hello="world"}, funcs.luaeval "vim.g.to_delete") + eq({ hello = 'world' }, fn.luaeval 'vim.g.to_delete') exec_lua [[ vim.g.to_delete = nil ]] - eq(NIL, funcs.luaeval "vim.g.to_delete") + eq(NIL, fn.luaeval 'vim.g.to_delete') - matches([[attempt to index .* nil value]], - pcall_err(exec_lua, 'return vim.g[0].testing')) + matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.g[0].testing')) exec_lua [[ local counter = 0 @@ -1114,7 +1513,7 @@ describe('lua stdlib', function() local function get_counter() return counter end vim.g.AddCounter = add_counter vim.g.GetCounter = get_counter - vim.g.funcs = {add = add_counter, get = get_counter} + vim.g.fn = {add = add_counter, get = get_counter} vim.g.AddParens = function(s) return '(' .. s .. ')' end ]] @@ -1127,10 +1526,10 @@ describe('lua stdlib', function() eq(3, exec_lua([[return vim.g.GetCounter()]])) exec_lua([[vim.api.nvim_get_var('AddCounter')()]]) eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]])) - exec_lua([[vim.g.funcs.add()]]) - eq(5, exec_lua([[return vim.g.funcs.get()]])) - exec_lua([[vim.api.nvim_get_var('funcs').add()]]) - eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]])) + exec_lua([[vim.g.fn.add()]]) + eq(5, exec_lua([[return vim.g.fn.get()]])) + exec_lua([[vim.api.nvim_get_var('fn').add()]]) + eq(6, exec_lua([[return vim.api.nvim_get_var('fn').get()]])) eq('((foo))', eval([['foo'->AddParens()->AddParens()]])) exec_lua [[ @@ -1139,7 +1538,7 @@ describe('lua stdlib', function() local function get_counter() return counter end vim.api.nvim_set_var('AddCounter', add_counter) vim.api.nvim_set_var('GetCounter', get_counter) - vim.api.nvim_set_var('funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_set_var('fn', {add = add_counter, get = get_counter}) vim.api.nvim_set_var('AddParens', function(s) return '(' .. s .. ')' end) ]] @@ -1152,10 +1551,10 @@ describe('lua stdlib', function() eq(3, exec_lua([[return vim.g.GetCounter()]])) exec_lua([[vim.api.nvim_get_var('AddCounter')()]]) eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]])) - exec_lua([[vim.g.funcs.add()]]) - eq(5, exec_lua([[return vim.g.funcs.get()]])) - exec_lua([[vim.api.nvim_get_var('funcs').add()]]) - eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]])) + exec_lua([[vim.g.fn.add()]]) + eq(5, exec_lua([[return vim.g.fn.get()]])) + exec_lua([[vim.api.nvim_get_var('fn').add()]]) + eq(6, exec_lua([[return vim.api.nvim_get_var('fn').get()]])) eq('((foo))', eval([['foo'->AddParens()->AddParens()]])) exec([[ @@ -1173,12 +1572,12 @@ describe('lua stdlib', function() 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 } } + clear { args_rm = { '-u' }, env = { XDG_CONFIG_HOME = xconfig, XDG_DATA_HOME = xdata } } eq(2, exec_lua("return vim.g['testload#value']")) rmdir('Xhome') @@ -1195,26 +1594,28 @@ describe('lua stdlib', function() vim.api.nvim_buf_set_var(BUF, "testing", "bye") ]] - eq('hi', funcs.luaeval "vim.b.testing") - eq('bye', funcs.luaeval "vim.b[BUF].testing") - eq(123, funcs.luaeval "vim.b.other") - eq(5120.1, funcs.luaeval "vim.b.floaty") - eq(NIL, funcs.luaeval "vim.b.nonexistent") - eq(NIL, funcs.luaeval "vim.b[BUF].nonexistent") - eq(NIL, funcs.luaeval "vim.b.nullvar") + eq('hi', fn.luaeval 'vim.b.testing') + eq('bye', fn.luaeval 'vim.b[BUF].testing') + eq(123, fn.luaeval 'vim.b.other') + eq(5120.1, fn.luaeval 'vim.b.floaty') + eq(NIL, fn.luaeval 'vim.b.nonexistent') + eq(NIL, fn.luaeval 'vim.b[BUF].nonexistent') + eq(NIL, fn.luaeval 'vim.b.nullvar') -- lost over RPC, so test locally: - eq({false, true}, exec_lua [[ + eq( + { false, true }, + exec_lua [[ return {vim.b.nonexistent == vim.NIL, vim.b.nullvar == vim.NIL} - ]]) + ]] + ) - matches([[attempt to index .* nil value]], - pcall_err(exec_lua, 'return vim.b[BUF][0].testing')) + matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.b[BUF][0].testing')) - eq({hello="world"}, funcs.luaeval "vim.b.to_delete") + eq({ hello = 'world' }, fn.luaeval 'vim.b.to_delete') exec_lua [[ vim.b.to_delete = nil ]] - eq(NIL, funcs.luaeval "vim.b.to_delete") + eq(NIL, fn.luaeval 'vim.b.to_delete') exec_lua [[ local counter = 0 @@ -1222,7 +1623,7 @@ describe('lua stdlib', function() local function get_counter() return counter end vim.b.AddCounter = add_counter vim.b.GetCounter = get_counter - vim.b.funcs = {add = add_counter, get = get_counter} + vim.b.fn = {add = add_counter, get = get_counter} vim.b.AddParens = function(s) return '(' .. s .. ')' end ]] @@ -1235,10 +1636,10 @@ describe('lua stdlib', function() eq(3, exec_lua([[return vim.b.GetCounter()]])) exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]]) eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]])) - exec_lua([[vim.b.funcs.add()]]) - eq(5, exec_lua([[return vim.b.funcs.get()]])) - exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]]) - eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]])) + exec_lua([[vim.b.fn.add()]]) + eq(5, exec_lua([[return vim.b.fn.get()]])) + exec_lua([[vim.api.nvim_buf_get_var(0, 'fn').add()]]) + eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'fn').get()]])) eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]])) exec_lua [[ @@ -1247,7 +1648,7 @@ describe('lua stdlib', function() local function get_counter() return counter end vim.api.nvim_buf_set_var(0, 'AddCounter', add_counter) vim.api.nvim_buf_set_var(0, 'GetCounter', get_counter) - vim.api.nvim_buf_set_var(0, 'funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_buf_set_var(0, 'fn', {add = add_counter, get = get_counter}) vim.api.nvim_buf_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) ]] @@ -1260,10 +1661,10 @@ describe('lua stdlib', function() eq(3, exec_lua([[return vim.b.GetCounter()]])) exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]]) eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]])) - exec_lua([[vim.b.funcs.add()]]) - eq(5, exec_lua([[return vim.b.funcs.get()]])) - exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]]) - eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]])) + exec_lua([[vim.b.fn.add()]]) + eq(5, exec_lua([[return vim.b.fn.get()]])) + exec_lua([[vim.api.nvim_buf_get_var(0, 'fn').add()]]) + eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'fn').get()]])) eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]])) exec([[ @@ -1281,9 +1682,9 @@ describe('lua stdlib', function() vim.cmd "vnew" ]] - eq(NIL, funcs.luaeval "vim.b.testing") - eq(NIL, funcs.luaeval "vim.b.other") - eq(NIL, funcs.luaeval "vim.b.nonexistent") + eq(NIL, fn.luaeval 'vim.b.testing') + eq(NIL, fn.luaeval 'vim.b.other') + eq(NIL, fn.luaeval 'vim.b.nonexistent') end) it('vim.w', function() @@ -1299,20 +1700,19 @@ describe('lua stdlib', function() vim.api.nvim_win_set_var(WIN, "testing", "bye") ]] - eq('hi', funcs.luaeval "vim.w.testing") - eq('bye', funcs.luaeval "vim.w[WIN].testing") - eq(123, funcs.luaeval "vim.w.other") - eq(NIL, funcs.luaeval "vim.w.nonexistent") - eq(NIL, funcs.luaeval "vim.w[WIN].nonexistent") + eq('hi', fn.luaeval 'vim.w.testing') + eq('bye', fn.luaeval 'vim.w[WIN].testing') + eq(123, fn.luaeval 'vim.w.other') + eq(NIL, fn.luaeval 'vim.w.nonexistent') + eq(NIL, fn.luaeval 'vim.w[WIN].nonexistent') - matches([[attempt to index .* nil value]], - pcall_err(exec_lua, 'return vim.w[WIN][0].testing')) + matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.w[WIN][0].testing')) - eq({hello="world"}, funcs.luaeval "vim.w.to_delete") + eq({ hello = 'world' }, fn.luaeval 'vim.w.to_delete') exec_lua [[ vim.w.to_delete = nil ]] - eq(NIL, funcs.luaeval "vim.w.to_delete") + eq(NIL, fn.luaeval 'vim.w.to_delete') exec_lua [[ local counter = 0 @@ -1320,7 +1720,7 @@ describe('lua stdlib', function() local function get_counter() return counter end vim.w.AddCounter = add_counter vim.w.GetCounter = get_counter - vim.w.funcs = {add = add_counter, get = get_counter} + vim.w.fn = {add = add_counter, get = get_counter} vim.w.AddParens = function(s) return '(' .. s .. ')' end ]] @@ -1333,10 +1733,10 @@ describe('lua stdlib', function() eq(3, exec_lua([[return vim.w.GetCounter()]])) exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]]) eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]])) - exec_lua([[vim.w.funcs.add()]]) - eq(5, exec_lua([[return vim.w.funcs.get()]])) - exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]]) - eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]])) + exec_lua([[vim.w.fn.add()]]) + eq(5, exec_lua([[return vim.w.fn.get()]])) + exec_lua([[vim.api.nvim_win_get_var(0, 'fn').add()]]) + eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'fn').get()]])) eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]])) exec_lua [[ @@ -1345,7 +1745,7 @@ describe('lua stdlib', function() local function get_counter() return counter end vim.api.nvim_win_set_var(0, 'AddCounter', add_counter) vim.api.nvim_win_set_var(0, 'GetCounter', get_counter) - vim.api.nvim_win_set_var(0, 'funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_win_set_var(0, 'fn', {add = add_counter, get = get_counter}) vim.api.nvim_win_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) ]] @@ -1358,10 +1758,10 @@ describe('lua stdlib', function() eq(3, exec_lua([[return vim.w.GetCounter()]])) exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]]) eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]])) - exec_lua([[vim.w.funcs.add()]]) - eq(5, exec_lua([[return vim.w.funcs.get()]])) - exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]]) - eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]])) + exec_lua([[vim.w.fn.add()]]) + eq(5, exec_lua([[return vim.w.fn.get()]])) + exec_lua([[vim.api.nvim_win_get_var(0, 'fn').add()]]) + eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'fn').get()]])) eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]])) exec([[ @@ -1379,9 +1779,9 @@ describe('lua stdlib', function() vim.cmd "vnew" ]] - eq(NIL, funcs.luaeval "vim.w.testing") - eq(NIL, funcs.luaeval "vim.w.other") - eq(NIL, funcs.luaeval "vim.w.nonexistent") + eq(NIL, fn.luaeval 'vim.w.testing') + eq(NIL, fn.luaeval 'vim.w.other') + eq(NIL, fn.luaeval 'vim.w.nonexistent') end) it('vim.t', function() @@ -1391,21 +1791,20 @@ describe('lua stdlib', function() vim.api.nvim_tabpage_set_var(0, "to_delete", {hello="world"}) ]] - eq('hi', funcs.luaeval "vim.t.testing") - eq(123, funcs.luaeval "vim.t.other") - eq(NIL, funcs.luaeval "vim.t.nonexistent") - eq('hi', funcs.luaeval "vim.t[0].testing") - eq(123, funcs.luaeval "vim.t[0].other") - eq(NIL, funcs.luaeval "vim.t[0].nonexistent") + eq('hi', fn.luaeval 'vim.t.testing') + eq(123, fn.luaeval 'vim.t.other') + eq(NIL, fn.luaeval 'vim.t.nonexistent') + eq('hi', fn.luaeval 'vim.t[0].testing') + eq(123, fn.luaeval 'vim.t[0].other') + eq(NIL, fn.luaeval 'vim.t[0].nonexistent') - matches([[attempt to index .* nil value]], - pcall_err(exec_lua, 'return vim.t[0][0].testing')) + matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.t[0][0].testing')) - eq({hello="world"}, funcs.luaeval "vim.t.to_delete") + eq({ hello = 'world' }, fn.luaeval 'vim.t.to_delete') exec_lua [[ vim.t.to_delete = nil ]] - eq(NIL, funcs.luaeval "vim.t.to_delete") + eq(NIL, fn.luaeval 'vim.t.to_delete') exec_lua [[ local counter = 0 @@ -1413,7 +1812,7 @@ describe('lua stdlib', function() local function get_counter() return counter end vim.t.AddCounter = add_counter vim.t.GetCounter = get_counter - vim.t.funcs = {add = add_counter, get = get_counter} + vim.t.fn = {add = add_counter, get = get_counter} vim.t.AddParens = function(s) return '(' .. s .. ')' end ]] @@ -1426,10 +1825,10 @@ describe('lua stdlib', function() eq(3, exec_lua([[return vim.t.GetCounter()]])) exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]]) eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]])) - exec_lua([[vim.t.funcs.add()]]) - eq(5, exec_lua([[return vim.t.funcs.get()]])) - exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]]) - eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]])) + exec_lua([[vim.t.fn.add()]]) + eq(5, exec_lua([[return vim.t.fn.get()]])) + exec_lua([[vim.api.nvim_tabpage_get_var(0, 'fn').add()]]) + eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'fn').get()]])) eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]])) exec_lua [[ @@ -1438,7 +1837,7 @@ describe('lua stdlib', function() local function get_counter() return counter end vim.api.nvim_tabpage_set_var(0, 'AddCounter', add_counter) vim.api.nvim_tabpage_set_var(0, 'GetCounter', get_counter) - vim.api.nvim_tabpage_set_var(0, 'funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_tabpage_set_var(0, 'fn', {add = add_counter, get = get_counter}) vim.api.nvim_tabpage_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) ]] @@ -1451,47 +1850,46 @@ describe('lua stdlib', function() eq(3, exec_lua([[return vim.t.GetCounter()]])) exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]]) eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]])) - exec_lua([[vim.t.funcs.add()]]) - eq(5, exec_lua([[return vim.t.funcs.get()]])) - exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]]) - eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]])) + exec_lua([[vim.t.fn.add()]]) + eq(5, exec_lua([[return vim.t.fn.get()]])) + exec_lua([[vim.api.nvim_tabpage_get_var(0, 'fn').add()]]) + eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'fn').get()]])) eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]])) exec_lua [[ vim.cmd "tabnew" ]] - eq(NIL, funcs.luaeval "vim.t.testing") - eq(NIL, funcs.luaeval "vim.t.other") - eq(NIL, funcs.luaeval "vim.t.nonexistent") + eq(NIL, fn.luaeval 'vim.t.testing') + eq(NIL, fn.luaeval 'vim.t.other') + eq(NIL, fn.luaeval 'vim.t.nonexistent') end) it('vim.env', function() exec_lua([[vim.fn.setenv('A', 123)]]) - eq('123', funcs.luaeval('vim.env.A')) + eq('123', fn.luaeval('vim.env.A')) exec_lua([[vim.env.A = 456]]) - eq('456', funcs.luaeval('vim.env.A')) + eq('456', fn.luaeval('vim.env.A')) exec_lua([[vim.env.A = nil]]) - eq(NIL, funcs.luaeval('vim.env.A')) + eq(NIL, fn.luaeval('vim.env.A')) - eq(true, funcs.luaeval('vim.env.B == nil')) + eq(true, fn.luaeval('vim.env.B == nil')) command([[let $HOME = 'foo']]) - eq('foo', funcs.expand('~')) - eq('foo', funcs.luaeval('vim.env.HOME')) + eq('foo', fn.expand('~')) + eq('foo', fn.luaeval('vim.env.HOME')) exec_lua([[vim.env.HOME = nil]]) - eq('foo', funcs.expand('~')) + eq('foo', fn.expand('~')) exec_lua([[vim.env.HOME = 'bar']]) - eq('bar', funcs.expand('~')) - eq('bar', funcs.luaeval('vim.env.HOME')) + eq('bar', fn.expand('~')) + eq('bar', fn.luaeval('vim.env.HOME')) end) it('vim.v', function() - eq(funcs.luaeval "vim.api.nvim_get_vvar('progpath')", funcs.luaeval "vim.v.progpath") - eq(false, funcs.luaeval "vim.v['false']") - eq(NIL, funcs.luaeval "vim.v.null") - matches([[attempt to index .* nil value]], - pcall_err(exec_lua, 'return vim.v[0].progpath')) + eq(fn.luaeval "vim.api.nvim_get_vvar('progpath')", fn.luaeval 'vim.v.progpath') + eq(false, fn.luaeval "vim.v['false']") + eq(NIL, fn.luaeval 'vim.v.null') + matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.v[0].progpath')) eq('Key is read-only: count', pcall_err(exec_lua, [[vim.v.count = 42]])) eq('Dictionary is locked', pcall_err(exec_lua, [[vim.v.nosuchvar = 42]])) eq('Key is fixed: errmsg', pcall_err(exec_lua, [[vim.v.errmsg = nil]])) @@ -1507,69 +1905,72 @@ describe('lua stdlib', function() 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)) + eq({ 1, 5 }, api.nvim_win_get_cursor(0)) exec_lua([[vim.v.searchforward = 0]]) eq(0, eval('v:searchforward')) feed('n') - eq({1, 1}, meths.win_get_cursor(0)) + eq({ 1, 1 }, api.nvim_win_get_cursor(0)) exec_lua([[vim.v.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:~ }| | - ]]} + ]], + } exec_lua([[vim.v.hlsearch = 0]]) eq(0, eval('v:hlsearch')) - screen:expect{grid=[[ + screen:expect { + grid = [[ foo ^foo foo | {0:~ }| | - ]]} + ]], + } exec_lua([[vim.v.hlsearch = 1]]) eq(1, eval('v:hlsearch')) - screen:expect{grid=[[ + screen:expect { + grid = [[ {1:foo} {1:^foo} {1:foo} | {0:~ }| | - ]]} + ]], + } end) it('vim.bo', function() - eq('', funcs.luaeval "vim.bo.filetype") + eq('', fn.luaeval 'vim.bo.filetype') exec_lua [[ vim.api.nvim_set_option_value("filetype", "markdown", {}) BUF = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_option_value("modifiable", false, {buf = BUF}) ]] - eq(false, funcs.luaeval "vim.bo.modified") - eq('markdown', funcs.luaeval "vim.bo.filetype") - eq(false, funcs.luaeval "vim.bo[BUF].modifiable") + eq(false, fn.luaeval 'vim.bo.modified') + eq('markdown', fn.luaeval 'vim.bo.filetype') + eq(false, fn.luaeval 'vim.bo[BUF].modifiable') exec_lua [[ vim.bo.filetype = '' vim.bo[BUF].modifiable = true ]] - eq('', funcs.luaeval "vim.bo.filetype") - eq(true, funcs.luaeval "vim.bo[BUF].modifiable") - matches("Unknown option 'nosuchopt'$", - pcall_err(exec_lua, 'return vim.bo.nosuchopt')) - matches("Expected Lua string$", - pcall_err(exec_lua, 'return vim.bo[0][0].autoread')) - matches("Invalid buffer id: %-1$", - pcall_err(exec_lua, 'return vim.bo[-1].filetype')) + eq('', fn.luaeval 'vim.bo.filetype') + eq(true, fn.luaeval 'vim.bo[BUF].modifiable') + matches("Unknown option 'nosuchopt'$", pcall_err(exec_lua, 'return vim.bo.nosuchopt')) + matches('Expected Lua string$', pcall_err(exec_lua, 'return vim.bo[0][0].autoread')) + matches('Invalid buffer id: %-1$', pcall_err(exec_lua, 'return vim.bo[-1].filetype')) end) it('vim.wo', function() @@ -1578,34 +1979,32 @@ describe('lua stdlib', function() vim.cmd "split" vim.api.nvim_set_option_value("cole", 2, {}) ]] - eq(2, funcs.luaeval "vim.wo.cole") + eq(2, fn.luaeval 'vim.wo.cole') exec_lua [[ vim.wo.conceallevel = 0 ]] - eq(0, funcs.luaeval "vim.wo.cole") - eq(0, funcs.luaeval "vim.wo[0].cole") - eq(0, funcs.luaeval "vim.wo[1001].cole") - matches("Unknown option 'notanopt'$", - pcall_err(exec_lua, 'return vim.wo.notanopt')) - matches("Invalid window id: %-1$", - pcall_err(exec_lua, 'return vim.wo[-1].list')) - eq(2, funcs.luaeval "vim.wo[1000].cole") + eq(0, fn.luaeval 'vim.wo.cole') + eq(0, fn.luaeval 'vim.wo[0].cole') + eq(0, fn.luaeval 'vim.wo[1001].cole') + matches("Unknown option 'notanopt'$", pcall_err(exec_lua, 'return vim.wo.notanopt')) + matches('Invalid window id: %-1$', pcall_err(exec_lua, 'return vim.wo[-1].list')) + eq(2, fn.luaeval 'vim.wo[1000].cole') exec_lua [[ vim.wo[1000].cole = 0 ]] - eq(0, funcs.luaeval "vim.wo[1000].cole") + eq(0, fn.luaeval 'vim.wo[1000].cole') -- Can handle global-local values exec_lua [[vim.o.scrolloff = 100]] exec_lua [[vim.wo.scrolloff = 200]] - eq(200, funcs.luaeval "vim.wo.scrolloff") + eq(200, fn.luaeval 'vim.wo.scrolloff') exec_lua [[vim.wo.scrolloff = -1]] - eq(100, funcs.luaeval "vim.wo.scrolloff") + eq(100, fn.luaeval 'vim.wo.scrolloff') exec_lua [[ vim.wo[0][0].scrolloff = 200 vim.cmd "enew" ]] - eq(100, funcs.luaeval "vim.wo.scrolloff") + eq(100, fn.luaeval 'vim.wo.scrolloff') end) describe('vim.opt', function() @@ -1638,7 +2037,7 @@ describe('lua stdlib', function() vim.opt.wildignore = { 'hello', 'world' } return vim.o.wildignore ]] - eq(wildignore, "hello,world") + eq(wildignore, 'hello,world') end) it('should allow setting tables with shortnames', function() @@ -1646,7 +2045,7 @@ describe('lua stdlib', function() vim.opt.wig = { 'hello', 'world' } return vim.o.wildignore ]] - eq(wildignore, "hello,world") + eq(wildignore, 'hello,world') end) it('should error when you attempt to set string values to numeric options', function() @@ -1668,7 +2067,9 @@ describe('lua stdlib', function() end) it('should allow you to set boolean values', function() - eq({true, false, true}, exec_lua [[ + eq( + { true, false, true }, + exec_lua [[ local results = {} vim.opt.autoindent = true @@ -1681,7 +2082,8 @@ describe('lua stdlib', function() table.insert(results, vim.bo.autoindent) return results - ]]) + ]] + ) end) it('should change current buffer values and defaults for global local values', function() @@ -1707,20 +2109,20 @@ describe('lua stdlib', function() ]] -- Set -> global & local - eq("global-local", result[1]) - eq("", result[2]) + eq('global-local', result[1]) + eq('', result[2]) -- Setlocal -> only local - eq("global-local", result[3]) - eq("only-local", result[4]) + eq('global-local', result[3]) + eq('only-local', result[4]) -- Setglobal -> only global - eq("only-global", result[5]) - eq("only-local", result[6]) + eq('only-global', result[5]) + eq('only-local', result[6]) -- Set -> sets global value and resets local value - eq("global-local", result[7]) - eq("", result[8]) + eq('global-local', result[7]) + eq('', result[8]) end) it('should allow you to retrieve window opts even if they have not been set', function() @@ -1735,11 +2137,13 @@ describe('lua stdlib', function() return result ]] - eq({false, false, true, true}, result) + eq({ false, false, true, true }, result) end) it('should allow all sorts of string manipulation', function() - eq({'hello', 'hello world', 'start hello world'}, exec_lua [[ + eq( + { 'hello', 'hello world', 'start hello world' }, + exec_lua [[ local results = {} vim.opt.makeprg = "hello" @@ -1752,19 +2156,23 @@ describe('lua stdlib', function() table.insert(results, vim.o.makeprg) return results - ]]) + ]] + ) end) describe('option:get()', function() it('should work for boolean values', function() - eq(false, exec_lua [[ + eq( + false, + exec_lua [[ vim.opt.number = false return vim.opt.number:get() - ]]) + ]] + ) end) it('should work for number values', function() - local tabstop = exec_lua[[ + local tabstop = exec_lua [[ vim.opt.tabstop = 10 return vim.opt.tabstop:get() ]] @@ -1773,10 +2181,13 @@ describe('lua stdlib', function() end) it('should work for string values', function() - eq("hello world", exec_lua [[ + eq( + 'hello world', + exec_lua [[ vim.opt.makeprg = "hello world" return vim.opt.makeprg:get() - ]]) + ]] + ) end) it('should work for set type flaglists', function() @@ -1806,7 +2217,7 @@ describe('lua stdlib', function() ]] eq(3, #wildignore) - eq("*.c", wildignore[1]) + eq('*.c', wildignore[1]) end) it('should work for options that are both commalist and flaglist', function() @@ -1815,14 +2226,14 @@ describe('lua stdlib', function() return vim.opt.whichwrap:get() ]] - eq({b = true, s = true}, result) + eq({ b = true, s = true }, result) result = exec_lua [[ vim.opt.whichwrap = { b = true, s = false, h = true } return vim.opt.whichwrap:get() ]] - eq({b = true, h = true}, result) + eq({ b = true, h = true }, result) end) it('should work for key-value pair options', function() @@ -1832,25 +2243,31 @@ describe('lua stdlib', function() ]] eq({ - tab = "> ", - space = "_", + tab = '> ', + space = '_', }, listchars) end) it('should allow you to add numeric options', function() - eq(16, exec_lua [[ + eq( + 16, + exec_lua [[ vim.opt.tabstop = 12 vim.opt.tabstop = vim.opt.tabstop + 4 return vim.bo.tabstop - ]]) + ]] + ) end) it('should allow you to subtract numeric options', function() - eq(2, exec_lua [[ + eq( + 2, + exec_lua [[ vim.opt.tabstop = 4 vim.opt.tabstop = vim.opt.tabstop - 2 return vim.bo.tabstop - ]]) + ]] + ) end) end) @@ -1864,7 +2281,7 @@ describe('lua stdlib', function() return vim.o.listchars ]] - eq("eol:~,space:.", listchars) + eq('eol:~,space:.', listchars) end) it('should allow adding dictionary style', function() @@ -1879,7 +2296,7 @@ describe('lua stdlib', function() return vim.o.listchars ]] - eq("eol:~,space:-", listchars) + eq('eol:~,space:-', listchars) end) it('should allow adding dictionary style', function() @@ -1893,7 +2310,7 @@ describe('lua stdlib', function() return vim.o.listchars ]] - eq("eol:~,space:_", listchars) + eq('eol:~,space:_', listchars) end) it('should allow completely new keys', function() @@ -1907,7 +2324,7 @@ describe('lua stdlib', function() return vim.o.listchars ]] - eq("eol:~,space:.,tab:>>>", listchars) + eq('eol:~,space:.,tab:>>>', listchars) end) it('should allow subtracting dictionary style', function() @@ -1921,7 +2338,7 @@ describe('lua stdlib', function() return vim.o.listchars ]] - eq("eol:~", listchars) + eq('eol:~', listchars) end) it('should allow subtracting dictionary style', function() @@ -1935,7 +2352,7 @@ describe('lua stdlib', function() return vim.o.listchars ]] - eq("", listchars) + eq('', listchars) end) it('should allow subtracting dictionary style multiple times', function() @@ -1949,7 +2366,7 @@ describe('lua stdlib', function() return vim.o.listchars ]] - eq("eol:~", listchars) + eq('eol:~', listchars) end) it('should allow adding a key:value string to a listchars', function() @@ -1963,7 +2380,7 @@ describe('lua stdlib', function() return vim.o.listchars ]] - eq("eol:~,space:.,tab:>~", listchars) + eq('eol:~,space:.,tab:>~', listchars) end) it('should allow prepending a key:value string to a listchars', function() @@ -1977,44 +2394,56 @@ describe('lua stdlib', function() return vim.o.listchars ]] - eq("eol:~,space:.,tab:>~", listchars) + eq('eol:~,space:.,tab:>~', listchars) end) end) it('should automatically set when calling remove', function() - eq("foo,baz", exec_lua [[ + eq( + 'foo,baz', + exec_lua [[ vim.opt.wildignore = "foo,bar,baz" vim.opt.wildignore:remove("bar") return vim.o.wildignore - ]]) + ]] + ) end) it('should automatically set when calling remove with a table', function() - eq("foo", exec_lua [[ + eq( + 'foo', + exec_lua [[ vim.opt.wildignore = "foo,bar,baz" vim.opt.wildignore:remove { "bar", "baz" } return vim.o.wildignore - ]]) + ]] + ) end) it('should automatically set when calling append', function() - eq("foo,bar,baz,bing", exec_lua [[ + eq( + 'foo,bar,baz,bing', + exec_lua [[ vim.opt.wildignore = "foo,bar,baz" vim.opt.wildignore:append("bing") return vim.o.wildignore - ]]) + ]] + ) end) it('should automatically set when calling append with a table', function() - eq("foo,bar,baz,bing,zap", exec_lua [[ + eq( + 'foo,bar,baz,bing,zap', + exec_lua [[ vim.opt.wildignore = "foo,bar,baz" vim.opt.wildignore:append { "bing", "zap" } return vim.o.wildignore - ]]) + ]] + ) end) it('should allow adding tables', function() @@ -2106,96 +2535,198 @@ describe('lua stdlib', function() describe('option types', function() it('should allow to set option with numeric value', function() - eq(4, exec_lua [[ + eq( + 4, + exec_lua [[ vim.opt.tabstop = 4 return vim.bo.tabstop - ]]) + ]] + ) - matches("Invalid option type 'string' for 'tabstop'", pcall_err(exec_lua, [[ + matches( + "Invalid option type 'string' for 'tabstop'", + pcall_err( + exec_lua, + [[ vim.opt.tabstop = '4' - ]])) - matches("Invalid option type 'boolean' for 'tabstop'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'boolean' for 'tabstop'", + pcall_err( + exec_lua, + [[ vim.opt.tabstop = true - ]])) - matches("Invalid option type 'table' for 'tabstop'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'table' for 'tabstop'", + pcall_err( + exec_lua, + [[ vim.opt.tabstop = {4, 2} - ]])) - matches("Invalid option type 'function' for 'tabstop'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'function' for 'tabstop'", + pcall_err( + exec_lua, + [[ vim.opt.tabstop = function() return 4 end - ]])) + ]] + ) + ) end) it('should allow to set option with boolean value', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ vim.opt.undofile = true return vim.bo.undofile - ]]) + ]] + ) - matches("Invalid option type 'number' for 'undofile'", pcall_err(exec_lua, [[ + matches( + "Invalid option type 'number' for 'undofile'", + pcall_err( + exec_lua, + [[ vim.opt.undofile = 0 - ]])) - matches("Invalid option type 'table' for 'undofile'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'table' for 'undofile'", + pcall_err( + exec_lua, + [[ vim.opt.undofile = {true} - ]])) - matches("Invalid option type 'string' for 'undofile'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'string' for 'undofile'", + pcall_err( + exec_lua, + [[ vim.opt.undofile = 'true' - ]])) - matches("Invalid option type 'function' for 'undofile'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'function' for 'undofile'", + pcall_err( + exec_lua, + [[ vim.opt.undofile = function() return true end - ]])) + ]] + ) + ) end) it('should allow to set option with array or string value', function() - eq('indent,eol,start', exec_lua [[ + eq( + 'indent,eol,start', + exec_lua [[ vim.opt.backspace = {'indent','eol','start'} return vim.go.backspace - ]]) - eq('indent,eol,start', exec_lua [[ + ]] + ) + eq( + 'indent,eol,start', + exec_lua [[ vim.opt.backspace = 'indent,eol,start' return vim.go.backspace - ]]) + ]] + ) - matches("Invalid option type 'boolean' for 'backspace'", pcall_err(exec_lua, [[ + matches( + "Invalid option type 'boolean' for 'backspace'", + pcall_err( + exec_lua, + [[ vim.opt.backspace = true - ]])) - matches("Invalid option type 'number' for 'backspace'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'number' for 'backspace'", + pcall_err( + exec_lua, + [[ vim.opt.backspace = 2 - ]])) - matches("Invalid option type 'function' for 'backspace'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'function' for 'backspace'", + pcall_err( + exec_lua, + [[ vim.opt.backspace = function() return 'indent,eol,start' end - ]])) + ]] + ) + ) end) it('should allow set option with map or string value', function() - eq("eol:~,space:.", exec_lua [[ + eq( + 'eol:~,space:.', + exec_lua [[ vim.opt.listchars = { eol = "~", space = ".", } return vim.o.listchars - ]]) - eq("eol:~,space:.,tab:>~", exec_lua [[ + ]] + ) + eq( + 'eol:~,space:.,tab:>~', + exec_lua [[ vim.opt.listchars = "eol:~,space:.,tab:>~" return vim.o.listchars - ]]) + ]] + ) - matches("Invalid option type 'boolean' for 'listchars'", pcall_err(exec_lua, [[ + matches( + "Invalid option type 'boolean' for 'listchars'", + pcall_err( + exec_lua, + [[ vim.opt.listchars = true - ]])) - matches("Invalid option type 'number' for 'listchars'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'number' for 'listchars'", + pcall_err( + exec_lua, + [[ vim.opt.listchars = 2 - ]])) - matches("Invalid option type 'function' for 'listchars'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'function' for 'listchars'", + pcall_err( + exec_lua, + [[ vim.opt.listchars = function() return "eol:~,space:.,tab:>~" end - ]])) + ]] + ) + ) end) it('should allow set option with set or string value', function() @@ -2207,23 +2738,44 @@ describe('lua stdlib', function() return vim.go.whichwrap ]] - eq(ww, "b,s") - eq("b,s,<,>,[,]", exec_lua [[ + eq(ww, 'b,s') + eq( + 'b,s,<,>,[,]', + exec_lua [[ vim.opt.whichwrap = "b,s,<,>,[,]" return vim.go.whichwrap - ]]) + ]] + ) - matches("Invalid option type 'boolean' for 'whichwrap'", pcall_err(exec_lua, [[ + matches( + "Invalid option type 'boolean' for 'whichwrap'", + pcall_err( + exec_lua, + [[ vim.opt.whichwrap = true - ]])) - matches("Invalid option type 'number' for 'whichwrap'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'number' for 'whichwrap'", + pcall_err( + exec_lua, + [[ vim.opt.whichwrap = 2 - ]])) - matches("Invalid option type 'function' for 'whichwrap'", pcall_err(exec_lua, [[ + ]] + ) + ) + matches( + "Invalid option type 'function' for 'whichwrap'", + pcall_err( + exec_lua, + [[ vim.opt.whichwrap = function() return "b,s,<,>,[,]" end - ]])) + ]] + ) + ) end) end) @@ -2234,7 +2786,7 @@ describe('lua stdlib', function() return { vim.opt.isfname:get(), vim.go.isfname } ]] - eq({{",", "a", "b", "c"}, "a,b,,,c"}, result) + eq({ { ',', 'a', 'b', 'c' }, 'a,b,,,c' }, result) end) -- isfname=a,b,c,^,,def @@ -2244,77 +2796,101 @@ describe('lua stdlib', function() return { vim.opt.isfname:get(), vim.go.isfname } ]] - eq({{"^,", "a", "b", "c"}, "a,b,^,,c"}, result) + eq({ { '^,', 'a', 'b', 'c' }, 'a,b,^,,c' }, result) end) - - describe('https://github.com/neovim/neovim/issues/14828', function() it('gives empty list when item is empty:array', function() - eq({}, exec_lua [[ + eq( + {}, + exec_lua [[ vim.cmd("set wildignore=") return vim.opt.wildignore:get() - ]]) + ]] + ) - eq({}, exec_lua [[ + eq( + {}, + exec_lua [[ vim.opt.wildignore = {} return vim.opt.wildignore:get() - ]]) + ]] + ) end) it('gives empty list when item is empty:set', function() - eq({}, exec_lua [[ + eq( + {}, + exec_lua [[ vim.cmd("set formatoptions=") return vim.opt.formatoptions:get() - ]]) + ]] + ) - eq({}, exec_lua [[ + eq( + {}, + exec_lua [[ vim.opt.formatoptions = {} return vim.opt.formatoptions:get() - ]]) + ]] + ) end) it('does not append to empty item', function() - eq({"*.foo", "*.bar"}, exec_lua [[ + eq( + { '*.foo', '*.bar' }, + exec_lua [[ vim.opt.wildignore = {} vim.opt.wildignore:append { "*.foo", "*.bar" } return vim.opt.wildignore:get() - ]]) + ]] + ) end) it('does not prepend to empty item', function() - eq({"*.foo", "*.bar"}, exec_lua [[ + eq( + { '*.foo', '*.bar' }, + exec_lua [[ vim.opt.wildignore = {} vim.opt.wildignore:prepend { "*.foo", "*.bar" } return vim.opt.wildignore:get() - ]]) + ]] + ) end) it('append to empty set', function() - eq({ t = true }, exec_lua [[ + eq( + { t = true }, + exec_lua [[ vim.opt.formatoptions = {} vim.opt.formatoptions:append("t") return vim.opt.formatoptions:get() - ]]) + ]] + ) end) it('prepend to empty set', function() - eq({ t = true }, exec_lua [[ + eq( + { t = true }, + exec_lua [[ vim.opt.formatoptions = {} vim.opt.formatoptions:prepend("t") return vim.opt.formatoptions:get() - ]]) + ]] + ) end) end) end) -- vim.opt describe('vim.opt_local', function() it('appends into global value when changing local option value', function() - eq({ "foo,bar,baz,qux" }, exec_lua [[ + eq( + { 'foo,bar,baz,qux' }, + exec_lua [[ local result = {} vim.opt.tags = "foo,bar" @@ -2324,20 +2900,24 @@ describe('lua stdlib', function() table.insert(result, vim.bo.tags) return result - ]]) + ]] + ) end) end) describe('vim.opt_global', function() it('gets current global option value', function() - eq({ "yes" }, exec_lua [[ + eq( + { 'yes' }, + exec_lua [[ local result = {} vim.cmd "setglobal signcolumn=yes" table.insert(result, vim.opt_global.signcolumn:get()) return result - ]]) + ]] + ) end) end) @@ -2346,15 +2926,15 @@ describe('lua stdlib', function() vim.cmd "autocmd BufNew * ++once lua BUF = vim.fn.expand('<abuf>')" vim.cmd "new" ]] - eq('2', funcs.luaeval "BUF") - eq(2, funcs.luaeval "#vim.api.nvim_list_bufs()") + eq('2', fn.luaeval 'BUF') + eq(2, fn.luaeval '#vim.api.nvim_list_bufs()') -- vim.cmd can be indexed with a command name exec_lua [[ vim.cmd.let 'g:var = 2' ]] - eq(2, funcs.luaeval "vim.g.var") + eq(2, fn.luaeval 'vim.g.var') end) it('vim.regex', function() @@ -2363,16 +2943,16 @@ describe('lua stdlib', function() vim.cmd "set nomagic ignorecase" re2 = vim.regex"xYz" ]] - eq({}, exec_lua[[return {re1:match_str("x ac")}]]) - eq({3,7}, exec_lua[[return {re1:match_str("ac abbc")}]]) + eq({}, exec_lua [[return {re1:match_str("x ac")}]]) + eq({ 3, 7 }, exec_lua [[return {re1:match_str("ac abbc")}]]) - meths.buf_set_lines(0, 0, -1, true, {"yy", "abc abbc"}) - eq({}, exec_lua[[return {re1:match_line(0, 0)}]]) - eq({0,3}, exec_lua[[return {re1:match_line(0, 1)}]]) - eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1)}]]) - eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1, 8)}]]) - eq({}, exec_lua[[return {re1:match_line(0, 1, 1, 7)}]]) - eq({0,3}, exec_lua[[return {re1:match_line(0, 1, 0, 7)}]]) + api.nvim_buf_set_lines(0, 0, -1, true, { 'yy', 'abc abbc' }) + eq({}, exec_lua [[return {re1:match_line(0, 0)}]]) + eq({ 0, 3 }, exec_lua [[return {re1:match_line(0, 1)}]]) + eq({ 3, 7 }, exec_lua [[return {re1:match_line(0, 1, 1)}]]) + eq({ 3, 7 }, exec_lua [[return {re1:match_line(0, 1, 1, 8)}]]) + eq({}, exec_lua [[return {re1:match_line(0, 1, 1, 7)}]]) + eq({ 0, 3 }, exec_lua [[return {re1:match_line(0, 1, 0, 7)}]]) -- vim.regex() error inside :silent! should not crash. #20546 command([[silent! lua vim.regex('\\z')]]) @@ -2380,46 +2960,49 @@ describe('lua stdlib', function() end) it('vim.defer_fn', function() - eq(false, exec_lua [[ + eq( + false, + exec_lua [[ vim.g.test = false vim.defer_fn(function() vim.g.test = true end, 150) return vim.g.test - ]]) + ]] + ) exec_lua [[vim.wait(1000, function() return vim.g.test end)]] - eq(true, exec_lua[[return vim.g.test]]) + eq(true, exec_lua [[return vim.g.test]]) end) describe('vim.region', function() it('charwise', function() - insert(dedent( [[ + insert(dedent([[ text tααt tααt text text tαxt txtα tex text tαxt tαxt ]])) - eq({5,13}, exec_lua[[ return vim.region(0,{0,5},{0,13},'v',false)[0] ]]) - eq({5,15}, exec_lua[[ return vim.region(0,{0,5},{0,13},'v',true)[0] ]]) - eq({5,15}, exec_lua[[ return vim.region(0,{0,5},{0,14},'v',true)[0] ]]) - eq({5,15}, exec_lua[[ return vim.region(0,{0,5},{0,15},'v',false)[0] ]]) - eq({5,17}, exec_lua[[ return vim.region(0,{0,5},{0,15},'v',true)[0] ]]) - eq({5,17}, exec_lua[[ return vim.region(0,{0,5},{0,16},'v',true)[0] ]]) - eq({5,17}, exec_lua[[ return vim.region(0,{0,5},{0,17},'v',false)[0] ]]) - eq({5,18}, exec_lua[[ return vim.region(0,{0,5},{0,17},'v',true)[0] ]]) + eq({ 5, 13 }, exec_lua [[ return vim.region(0,{0,5},{0,13},'v',false)[0] ]]) + eq({ 5, 15 }, exec_lua [[ return vim.region(0,{0,5},{0,13},'v',true)[0] ]]) + eq({ 5, 15 }, exec_lua [[ return vim.region(0,{0,5},{0,14},'v',true)[0] ]]) + eq({ 5, 15 }, exec_lua [[ return vim.region(0,{0,5},{0,15},'v',false)[0] ]]) + eq({ 5, 17 }, exec_lua [[ return vim.region(0,{0,5},{0,15},'v',true)[0] ]]) + eq({ 5, 17 }, exec_lua [[ return vim.region(0,{0,5},{0,16},'v',true)[0] ]]) + eq({ 5, 17 }, exec_lua [[ return vim.region(0,{0,5},{0,17},'v',false)[0] ]]) + eq({ 5, 18 }, exec_lua [[ return vim.region(0,{0,5},{0,17},'v',true)[0] ]]) end) it('blockwise', function() insert([[αα]]) - eq({0,5}, exec_lua[[ return vim.region(0,{0,0},{0,4},'3',true)[0] ]]) + eq({ 0, 5 }, exec_lua [[ return vim.region(0,{0,0},{0,4},'3',true)[0] ]]) end) it('linewise', function() - insert(dedent( [[ + insert(dedent([[ text tααt tααt text text tαxt txtα tex text tαxt tαxt ]])) - eq({0,-1}, exec_lua[[ return vim.region(0,{1,5},{1,14},'V',true)[1] ]]) + eq({ 0, -1 }, exec_lua [[ return vim.region(0,{1,5},{1,14},'V',true)[1] ]]) end) it('getpos() input', function() insert('getpos') - eq({0,6}, exec_lua[[ return vim.region(0,{0,0},'.','v',true)[0] ]]) + eq({ 0, 6 }, exec_lua [[ return vim.region(0,{0,0},'.','v',true)[0] ]]) end) end) @@ -2447,10 +3030,10 @@ describe('lua stdlib', function() it('allows removing on_key listeners', function() -- Create some unused namespaces - meths.create_namespace('unused1') - meths.create_namespace('unused2') - meths.create_namespace('unused3') - meths.create_namespace('unused4') + api.nvim_create_namespace('unused1') + api.nvim_create_namespace('unused2') + api.nvim_create_namespace('unused3') + api.nvim_create_namespace('unused4') insert([[hello world]]) @@ -2518,9 +3101,9 @@ describe('lua stdlib', function() table.insert(keys, buf) end) ]] - insert("hello") + insert('hello') - eq('iworld<ESC>', exec_lua[[return table.concat(keys, '')]]) + eq('iworld<ESC>', exec_lua [[return table.concat(keys, '')]]) end) it('can call vim.fn functions on Ctrl-C #17273', function() @@ -2534,7 +3117,7 @@ describe('lua stdlib', function() end) ]]) feed('/') - poke_eventloop() -- This is needed because Ctrl-C flushes input + poke_eventloop() -- This is needed because Ctrl-C flushes input feed('<C-C>') eq('/', exec_lua([[return _G.ctrl_c_cmdtype]])) end) @@ -2542,7 +3125,7 @@ describe('lua stdlib', function() describe('vim.wait', function() before_each(function() - exec_lua[[ + exec_lua [[ -- high precision timer get_time = function() return vim.fn.reltimefloat(vim.fn.reltime()) @@ -2551,11 +3134,13 @@ describe('lua stdlib', function() end) it('should run from lua', function() - exec_lua[[vim.wait(100, function() return true end)]] + exec_lua [[vim.wait(100, function() return true end)]] end) it('should wait the expected time if false', function() - eq({time = true, wait_result = {false, -1}}, exec_lua[[ + eq( + { time = true, wait_result = { false, -1 } }, + exec_lua [[ start_time = get_time() wait_succeed, wait_fail_val = vim.wait(200, function() return false end) @@ -2564,11 +3149,14 @@ describe('lua stdlib', function() time = (start_time + 0.15) < get_time(), wait_result = {wait_succeed, wait_fail_val} } - ]]) + ]] + ) end) it('should not block other events', function() - eq({time = true, wait_result = true}, exec_lua[[ + eq( + { time = true, wait_result = true }, + exec_lua [[ start_time = get_time() vim.g.timer_result = false @@ -2586,11 +3174,14 @@ describe('lua stdlib', function() time = (start_time + 5) > get_time(), wait_result = wait_result, } - ]]) + ]] + ) end) it('should not process non-fast events when commanded', function() - eq({wait_result = false}, exec_lua[[ + eq( + { wait_result = false }, + exec_lua [[ start_time = get_time() vim.g.timer_result = false @@ -2606,11 +3197,14 @@ describe('lua stdlib', function() return { wait_result = wait_result, } - ]]) + ]] + ) end) it('should work with vim.defer_fn', function() - eq({time = true, wait_result = true}, exec_lua[[ + eq( + { time = true, wait_result = true }, + exec_lua [[ start_time = get_time() vim.defer_fn(function() vim.g.timer_result = true end, 100) @@ -2620,94 +3214,124 @@ describe('lua stdlib', function() time = (start_time + 5) > get_time(), wait_result = wait_result, } - ]]) + ]] + ) end) it('should not crash when callback errors', function() local result = exec_lua [[ return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)} ]] - eq({false, '[string "<nvim>"]:1: As Expected'}, {result[1], remove_trace(result[2])}) + eq({ false, '[string "<nvim>"]:1: As Expected' }, { result[1], remove_trace(result[2]) }) end) it('if callback is passed, it must be a function', function() - eq({false, 'vim.wait: if passed, condition must be a function'}, exec_lua [[ + eq( + { false, 'vim.wait: if passed, condition must be a function' }, + exec_lua [[ return {pcall(function() vim.wait(1000, 13) end)} - ]]) + ]] + ) end) it('should allow waiting with no callback, explicit', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ local start_time = vim.uv.hrtime() vim.wait(50, nil) return vim.uv.hrtime() - start_time > 25000 - ]]) + ]] + ) end) it('should allow waiting with no callback, implicit', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ local start_time = vim.uv.hrtime() vim.wait(50) return vim.uv.hrtime() - start_time > 25000 - ]]) + ]] + ) end) it('should call callbacks exactly once if they return true immediately', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ vim.g.wait_count = 0 vim.wait(1000, function() vim.g.wait_count = vim.g.wait_count + 1 return true end, 20) return vim.g.wait_count == 1 - ]]) + ]] + ) end) it('should call callbacks few times with large `interval`', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ vim.g.wait_count = 0 vim.wait(50, function() vim.g.wait_count = vim.g.wait_count + 1 end, 200) return vim.g.wait_count < 5 - ]]) + ]] + ) end) it('should play nice with `not` when fails', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ if not vim.wait(50, function() end) then return true end return false - ]]) + ]] + ) end) it('should play nice with `if` when success', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ if vim.wait(50, function() return true end) then return true end return false - ]]) + ]] + ) end) it('should return immediately with false if timeout is 0', function() - eq({false, -1}, exec_lua [[ + eq( + { false, -1 }, + exec_lua [[ return { vim.wait(0, function() return false end) } - ]]) + ]] + ) end) it('should work with tables with __call', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ local t = setmetatable({}, {__call = function(...) return true end}) return vim.wait(100, t, 10) - ]]) + ]] + ) end) it('should work with tables with __call that change', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ local t = {count = 0} setmetatable(t, { __call = function() @@ -2717,7 +3341,8 @@ describe('lua stdlib', function() }) return vim.wait(1000, t, 10) - ]]) + ]] + ) end) it('should not work with negative intervals', function() @@ -2738,8 +3363,8 @@ describe('lua stdlib', function() describe('returns -2 when interrupted', function() before_each(function() - local channel = meths.get_api_info()[1] - meths.set_var('channel', channel) + local channel = api.nvim_get_chan_info(0).id + api.nvim_set_var('channel', channel) end) it('without callback', function() @@ -2751,9 +3376,9 @@ describe('lua stdlib', function() end ]]) feed(':lua _G.Wait()<CR>') - eq({'notification', 'ready', {}}, next_msg(500)) + eq({ 'notification', 'ready', {} }, next_msg(500)) feed('<C-C>') - eq({'notification', 'wait', {-2}}, next_msg(500)) + eq({ 'notification', 'wait', { -2 } }, next_msg(500)) end) it('with callback', function() @@ -2765,9 +3390,9 @@ describe('lua stdlib', function() end ]]) feed(':lua _G.Wait()<CR>') - eq({'notification', 'ready', {}}, next_msg(500)) + eq({ 'notification', 'ready', {} }, next_msg(500)) feed('<C-C>') - eq({'notification', 'wait', {-2}}, next_msg(500)) + eq({ 'notification', 'wait', { -2 } }, next_msg(500)) end) end) @@ -2790,35 +3415,35 @@ describe('lua stdlib', function() end) it('vim.notify_once', function() - local screen = Screen.new(60,5) + local screen = Screen.new(60, 5) screen:set_default_attr_ids({ - [0] = {bold=true, foreground=Screen.colors.Blue}, - [1] = {foreground=Screen.colors.Red}, + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { foreground = Screen.colors.Red }, }) screen:attach() - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*3 | - ]]} + ]], + } exec_lua [[vim.notify_once("I'll only tell you this once...", vim.log.levels.WARN)]] - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*3 {1:I'll only tell you this once...} | - ]]} + ]], + } feed('<C-l>') - screen:expect{grid=[[ + screen:expect { + grid = [[ ^ | - {0:~ }| - {0:~ }| - {0:~ }| + {0:~ }|*3 | - ]]} + ]], + } exec_lua [[vim.notify_once("I'll only tell you this once...")]] screen:expect_unchanged() end) @@ -2831,26 +3456,26 @@ describe('lua stdlib', function() end) fun("BOB", nil, "MIKE") ]] - eq({'notification', 'mayday_mayday', {{a='BOB', c='MIKE'}}}, next_msg()) + eq({ 'notification', 'mayday_mayday', { { a = 'BOB', c = 'MIKE' } } }, next_msg()) -- let's gooooo exec_lua [[ vim.schedule_wrap(function(...) vim.rpcnotify(1, 'boogalo', select('#', ...)) end)(nil,nil,nil,nil) ]] - eq({'notification', 'boogalo', {4}}, next_msg()) + eq({ 'notification', 'boogalo', { 4 } }, next_msg()) end) end) describe('vim.api.nvim_buf_call', function() it('can access buf options', function() - local buf1 = meths.get_current_buf().id + local buf1 = api.nvim_get_current_buf() local buf2 = exec_lua [[ buf2 = vim.api.nvim_create_buf(false, true) return buf2 ]] - eq(false, meths.get_option_value('autoindent', {buf=buf1})) - eq(false, meths.get_option_value('autoindent', {buf=buf2})) + eq(false, api.nvim_get_option_value('autoindent', { buf = buf1 })) + eq(false, api.nvim_get_option_value('autoindent', { buf = buf2 })) local val = exec_lua [[ return vim.api.nvim_buf_call(buf2, function() @@ -2859,9 +3484,9 @@ describe('lua stdlib', function() end) ]] - eq(false, meths.get_option_value('autoindent', {buf=buf1})) - eq(true, meths.get_option_value('autoindent', {buf=buf2})) - eq(buf1, meths.get_current_buf().id) + eq(false, api.nvim_get_option_value('autoindent', { buf = buf1 })) + eq(true, api.nvim_get_option_value('autoindent', { buf = buf2 })) + eq(buf1, api.nvim_get_current_buf()) eq(buf2, val) end) @@ -2877,7 +3502,9 @@ describe('lua stdlib', function() end) it('can be nested crazily with hidden buffers', function() - eq(true, exec_lua([[ + eq( + true, + exec_lua([[ local function scratch_buf_call(fn) local buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_option_value('cindent', true, {buf = buf}) @@ -2913,14 +3540,27 @@ describe('lua stdlib', function() end) end) end) - ]])) + ]]) + ) + end) + + it('can return values by reference', function() + eq( + { 4, 7 }, + exec_lua [[ + local val = {4, 10} + local ref = vim.api.nvim_buf_call(0, function() return val end) + ref[2] = 7 + return val + ]] + ) end) end) describe('vim.api.nvim_win_call', function() it('can access window options', function() command('vsplit') - local win1 = meths.get_current_win().id + local win1 = api.nvim_get_current_win() command('wincmd w') local win2 = exec_lua [[ win2 = vim.api.nvim_get_current_win() @@ -2928,8 +3568,8 @@ describe('lua stdlib', function() ]] command('wincmd p') - eq('', meths.get_option_value('winhighlight', {win=win1})) - eq('', meths.get_option_value('winhighlight', {win=win2})) + eq('', api.nvim_get_option_value('winhighlight', { win = win1 })) + eq('', api.nvim_get_option_value('winhighlight', { win = win2 })) local val = exec_lua [[ return vim.api.nvim_win_call(win2, function() @@ -2938,9 +3578,9 @@ describe('lua stdlib', function() end) ]] - eq('', meths.get_option_value('winhighlight', {win=win1})) - eq('Normal:Normal', meths.get_option_value('winhighlight', {win=win2})) - eq(win1, meths.get_current_win().id) + eq('', api.nvim_get_option_value('winhighlight', { win = win1 })) + eq('Normal:Normal', api.nvim_get_option_value('winhighlight', { win = win2 })) + eq(win1, api.nvim_get_current_win()) eq(win2, val) end) @@ -2978,8 +3618,8 @@ describe('lua stdlib', 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:set_default_attr_ids { - [1] = {reverse = true}, - [2] = {bold = true, reverse = true}, + [1] = { reverse = true }, + [2] = { bold = true, reverse = true }, } screen:attach() exec_lua [[ @@ -3012,75 +3652,110 @@ describe('lua stdlib', function() | ]] end) + + it('can return values by reference', function() + eq( + { 7, 10 }, + exec_lua [[ + local val = {4, 10} + local ref = vim.api.nvim_win_call(0, function() return val end) + ref[1] = 7 + return val + ]] + ) + end) end) describe('vim.iconv', function() it('can convert strings', function() - eq('hello', exec_lua[[ + eq( + 'hello', + exec_lua [[ return vim.iconv('hello', 'latin1', 'utf-8') - ]]) + ]] + ) end) it('can validate arguments', function() - eq({false, 'Expected at least 3 arguments'}, exec_lua[[ + eq( + { false, 'Expected at least 3 arguments' }, + exec_lua [[ return {pcall(vim.iconv, 'hello')} - ]]) + ]] + ) - eq({false, 'bad argument #3 to \'?\' (expected string)'}, exec_lua[[ + eq( + { false, "bad argument #3 to '?' (expected string)" }, + exec_lua [[ return {pcall(vim.iconv, 'hello', 'utf-8', true)} - ]]) + ]] + ) end) it('can handle bad encodings', function() - eq(NIL, exec_lua[[ + eq( + NIL, + exec_lua [[ return vim.iconv('hello', 'foo', 'bar') - ]]) + ]] + ) end) it('can handle strings with NUL bytes', function() - eq(7, exec_lua[[ + eq( + 7, + exec_lua [[ local a = string.char(97, 98, 99, 0, 100, 101, 102) -- abc\0def return string.len(vim.iconv(a, 'latin1', 'utf-8')) - ]]) + ]] + ) end) - end) - describe("vim.defaulttable", function() - it("creates nested table by default", function() - eq({ b = {c = 1 } }, exec_lua[[ + describe('vim.defaulttable', function() + it('creates nested table by default', function() + eq( + { b = { c = 1 } }, + exec_lua [[ local a = vim.defaulttable() a.b.c = 1 return a - ]]) + ]] + ) end) - it("allows to create default objects", function() - eq({ b = 1 }, exec_lua[[ + it('allows to create default objects', function() + eq( + { b = 1 }, + exec_lua [[ local a = vim.defaulttable(function() return 0 end) a.b = a.b + 1 return a - ]]) + ]] + ) end) it('accepts the key name', function() - eq({ b = 'b', c = 'c' }, exec_lua [[ + eq( + { b = 'b', c = 'c' }, + exec_lua [[ local a = vim.defaulttable(function(k) return k end) local _ = a.b local _ = a.c return a - ]]) + ]] + ) end) end) it('vim.lua_omnifunc', function() - local screen = Screen.new(60,5) + local screen = Screen.new(60, 5) screen:set_default_attr_ids { - [1] = {foreground = Screen.colors.Blue1, bold = true}; - [2] = {background = Screen.colors.WebGray}; - [3] = {background = Screen.colors.LightMagenta}; - [4] = {bold = true}; - [5] = {foreground = Screen.colors.SeaGreen, bold = true}; + [1] = { foreground = Screen.colors.Blue1, bold = true }, + [2] = { background = Screen.colors.WebGray }, + [3] = { background = Screen.colors.LightMagenta }, + [4] = { bold = true }, + [5] = { foreground = Screen.colors.SeaGreen, bold = true }, } screen:attach() command [[ set omnifunc=v:lua.vim.lua_omnifunc ]] @@ -3088,22 +3763,27 @@ describe('lua stdlib', function() -- Note: the implementation is shared with lua command line completion. -- More tests for completion in lua/command_line_completion_spec.lua feed [[ivim.insp<c-x><c-o>]] - screen:expect{grid=[[ + screen:expect { + grid = [[ vim.inspect^ | {1:~ }{2: inspect }{1: }| {1:~ }{3: inspect_pos }{1: }| {1:~ }| {4:-- Omni completion (^O^N^P) }{5:match 1 of 2} | - ]]} + ]], + } end) it('vim.print', function() -- vim.print() returns its args. - eq({42, 'abc', { a = { b = 77 }}}, - exec_lua[[return {vim.print(42, 'abc', { a = { b = 77 }})}]]) + eq( + { 42, 'abc', { a = { b = 77 } } }, + exec_lua [[return {vim.print(42, 'abc', { a = { b = 77 }})}]] + ) -- vim.print() pretty-prints the args. - eq(dedent[[ + eq( + dedent [[ 42 abc @@ -3112,12 +3792,14 @@ describe('lua stdlib', function() b = 77 } }]], - eval[[execute('lua vim.print(42, "abc", { a = { b = 77 }})')]]) + eval [[execute('lua vim.print(42, "abc", { a = { b = 77 }})')]] + ) end) it('vim.F.if_nil', function() local function if_nil(...) - return exec_lua([[ + return exec_lua( + [[ local args = {...} local nargs = select('#', ...) for i = 1, nargs do @@ -3126,7 +3808,9 @@ describe('lua stdlib', function() end end return vim.F.if_nil(unpack(args, 1, nargs)) - ]], ...) + ]], + ... + ) end local a = NIL @@ -3142,15 +3826,18 @@ describe('lua stdlib', function() end) it('lpeg', function() - eq(5, exec_lua [[ + eq( + 5, + exec_lua [[ local m = vim.lpeg return m.match(m.R'09'^1, '4504ab') - ]]) + ]] + ) eq(4, exec_lua [[ return vim.re.match("abcde", '[a-c]+') ]]) end) - it("vim.ringbuf", function() + it('vim.ringbuf', function() local results = exec_lua([[ local ringbuf = vim.ringbuf(3) ringbuf:push("a") -- idx: 0 @@ -3178,14 +3865,14 @@ describe('lua stdlib', function() } ]]) local expected = { - peeka1 = "a", - peeka2 = "a", - pop1 = "a", + peeka1 = 'a', + peeka2 = 'a', + pop1 = 'a', pop2 = nil, - pop3 = "b", - pop4 = "c", - pop5 = "d", - pop_after_add_b = "a", + pop3 = 'b', + pop4 = 'c', + pop5 = 'd', + pop_after_add_b = 'a', } eq(expected, results) end) @@ -3193,8 +3880,8 @@ end) describe('lua: builtin modules', function() local function do_tests() - eq(2, exec_lua[[return vim.tbl_count {x=1,y=2}]]) - eq('{ 10, "spam" }', exec_lua[[return vim.inspect {10, 'spam'}]]) + eq(2, exec_lua [[return vim.tbl_count {x=1,y=2}]]) + eq('{ 10, "spam" }', exec_lua [[return vim.inspect {10, 'spam'}]]) end it('works', function() @@ -3208,17 +3895,21 @@ describe('lua: builtin modules', function() end) it('works without runtime', function() - clear{env={VIMRUNTIME='fixtures/a'}} + clear { env = { VIMRUNTIME = 'fixtures/a' } } do_tests() end) - it('fails when disabled without runtime', function() clear() command("let $VIMRUNTIME='fixtures/a'") -- Use system([nvim,…]) instead of clear() to avoid stderr noise. #21844 - local out = funcs.system({nvim_prog, '--clean', '--luamod-dev', - [[+call nvim_exec_lua('return vim.tbl_count {x=1,y=2}')]], '+qa!'}):gsub('\r\n', '\n') + local out = fn.system({ + nvim_prog, + '--clean', + '--luamod-dev', + [[+call nvim_exec_lua('return vim.tbl_count {x=1,y=2}')]], + '+qa!', + }):gsub('\r\n', '\n') eq(1, eval('v:shell_error')) matches("'vim%.shared' not found", out) end) @@ -3235,7 +3926,7 @@ describe('lua: require("mod") from packages', function() return err ]] - matches("unexpected symbol", syntax_error_msg) + matches('unexpected symbol', syntax_error_msg) end) it('uses the right order of mod.lua vs mod/init.lua', function() @@ -3252,15 +3943,18 @@ describe('vim.keymap', function() before_each(clear) it('can make a mapping', function() - eq(0, exec_lua [[ + eq( + 0, + exec_lua [[ GlobalCount = 0 vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end) return GlobalCount - ]]) + ]] + ) feed('asdf\n') - eq(1, exec_lua[[return GlobalCount]]) + eq(1, exec_lua [[return GlobalCount]]) end) it('can make an expr mapping', function() @@ -3270,19 +3964,22 @@ describe('vim.keymap', function() feed('aa') - eq({'π<M-π>foo<'}, meths.buf_get_lines(0, 0, -1, false)) + eq({ 'π<M-π>foo<' }, api.nvim_buf_get_lines(0, 0, -1, false)) end) it('can overwrite a mapping', function() - eq(0, exec_lua [[ + eq( + 0, + exec_lua [[ GlobalCount = 0 vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end) return GlobalCount - ]]) + ]] + ) feed('asdf\n') - eq(1, exec_lua[[return GlobalCount]]) + eq(1, exec_lua [[return GlobalCount]]) exec_lua [[ vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount - 1 end) @@ -3290,19 +3987,22 @@ describe('vim.keymap', function() feed('asdf\n') - eq(0, exec_lua[[return GlobalCount]]) + eq(0, exec_lua [[return GlobalCount]]) end) it('can unmap a mapping', function() - eq(0, exec_lua [[ + eq( + 0, + exec_lua [[ GlobalCount = 0 vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end) return GlobalCount - ]]) + ]] + ) feed('asdf\n') - eq(1, exec_lua[[return GlobalCount]]) + eq(1, exec_lua [[return GlobalCount]]) exec_lua [[ vim.keymap.del('n', 'asdf') @@ -3310,20 +4010,23 @@ describe('vim.keymap', function() feed('asdf\n') - eq(1, exec_lua[[return GlobalCount]]) + eq(1, exec_lua [[return GlobalCount]]) eq('\nNo mapping found', helpers.exec_capture('nmap asdf')) end) it('works with buffer-local mappings', function() - eq(0, exec_lua [[ + eq( + 0, + exec_lua [[ GlobalCount = 0 vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end, {buffer=true}) return GlobalCount - ]]) + ]] + ) feed('asdf\n') - eq(1, exec_lua[[return GlobalCount]]) + eq(1, exec_lua [[return GlobalCount]]) exec_lua [[ vim.keymap.del('n', 'asdf', {buffer=true}) @@ -3331,33 +4034,63 @@ describe('vim.keymap', function() feed('asdf\n') - eq(1, exec_lua[[return GlobalCount]]) + eq(1, exec_lua [[return GlobalCount]]) eq('\nNo mapping found', helpers.exec_capture('nmap asdf')) end) it('does not mutate the opts parameter', function() - eq(true, exec_lua [[ + eq( + true, + exec_lua [[ opts = {buffer=true} vim.keymap.set('n', 'asdf', function() end, opts) return opts.buffer - ]]) - eq(true, exec_lua [[ + ]] + ) + eq( + true, + exec_lua [[ vim.keymap.del('n', 'asdf', opts) return opts.buffer - ]]) + ]] + ) end) it('can do <Plug> mappings', function() - eq(0, exec_lua [[ + eq( + 0, + exec_lua [[ GlobalCount = 0 vim.keymap.set('n', '<plug>(asdf)', function() GlobalCount = GlobalCount + 1 end) vim.keymap.set('n', 'ww', '<plug>(asdf)') return GlobalCount - ]]) + ]] + ) feed('ww\n') - eq(1, exec_lua[[return GlobalCount]]) + eq(1, exec_lua [[return GlobalCount]]) end) +end) +describe('Vimscript function exists()', function() + it('can check a lua function', function() + eq( + 1, + exec_lua [[ + _G.test = function() print("hello") end + return vim.fn.exists('*v:lua.test') + ]] + ) + + eq(1, fn.exists('*v:lua.require("mpack").decode')) + eq(1, fn.exists("*v:lua.require('mpack').decode")) + eq(1, fn.exists('*v:lua.require"mpack".decode')) + eq(1, fn.exists("*v:lua.require'mpack'.decode")) + eq(1, fn.exists("*v:lua.require('vim.lsp').start")) + eq(1, fn.exists('*v:lua.require"vim.lsp".start')) + eq(1, fn.exists("*v:lua.require'vim.lsp'.start")) + eq(0, fn.exists("*v:lua.require'vim.lsp'.unknown")) + eq(0, fn.exists('*v:lua.?')) + end) end) diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index cdcef08a1a..115fee8091 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -2,72 +2,113 @@ local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq local exec_lua = helpers.exec_lua local clear = helpers.clear +local is_ci = helpers.is_ci local is_os = helpers.is_os local skip = helpers.skip +-- Create a file via a rename to avoid multiple +-- events which can happen with some backends on some platforms +local function touch(path) + local tmp = helpers.tmpname() + io.open(tmp, 'w'):close() + assert(vim.uv.fs_rename(tmp, path)) +end + describe('vim._watch', function() before_each(function() clear() end) - describe('watch', function() - it('detects file changes', function() - skip(is_os('bsd'), "Stopped working on bsd after 3ca967387c49c754561c3b11a574797504d40f38") - local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') + local function run(watchfunc) + it('detects file changes (watchfunc=' .. watchfunc .. '())', function() + if watchfunc == 'fswatch' then + skip(is_os('mac'), 'flaky test on mac') + skip( + not is_ci() and helpers.fn.executable('fswatch') == 0, + 'fswatch not installed and not on CI' + ) + skip(is_os('win'), 'not supported on windows') + end - local result = exec_lua( - [[ - local root_dir = ... + if watchfunc == 'watch' then + skip(is_os('bsd'), 'Stopped working on bsd after 3ca967387c49c754561c3b11a574797504d40f38') + else + skip( + is_os('bsd'), + 'kqueue only reports events on watched folder itself, not contained files #26110' + ) + end + + local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') - local events = {} + local expected_events = 0 - local expected_events = 0 - local function wait_for_events() - assert(vim.wait(100, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) - end + local function wait_for_event() + expected_events = expected_events + 1 + exec_lua( + [[ + local expected_events = ... + assert( + vim.wait(3000, function() + return #_G.events == expected_events + end), + string.format( + 'Timed out waiting for expected event no. %d. Current events seen so far: %s', + expected_events, + vim.inspect(events) + ) + ) + ]], + expected_events + ) + end - local stop = vim._watch.watch(root_dir, {}, function(path, change_type) - table.insert(events, { path = path, change_type = change_type }) - end) + local unwatched_path = root_dir .. '/file.unwatched' + local watched_path = root_dir .. '/file' - -- Only BSD seems to need some extra time for the watch to be ready to respond to events - if vim.fn.has('bsd') then - vim.wait(50) - end + exec_lua( + [[ + local root_dir, watchfunc = ... - local watched_path = root_dir .. '/file' - local watched, err = io.open(watched_path, 'w') - assert(not err, err) + _G.events = {} - expected_events = expected_events + 1 - wait_for_events() + _G.stop_watch = vim._watch[watchfunc](root_dir, { + debounce = 100, + include_pattern = vim.lpeg.P(root_dir) * vim.lpeg.P("/file") ^ -1, + exclude_pattern = vim.lpeg.P(root_dir .. '/file.unwatched'), + }, function(path, change_type) + table.insert(_G.events, { path = path, change_type = change_type }) + end) + ]], + root_dir, + watchfunc + ) - watched:close() - os.remove(watched_path) + if watchfunc ~= 'watch' then + vim.uv.sleep(200) + end - expected_events = expected_events + 1 - wait_for_events() + touch(watched_path) + touch(unwatched_path) - stop() - -- No events should come through anymore + wait_for_event() - local watched_path = root_dir .. '/file' - local watched, err = io.open(watched_path, 'w') - assert(not err, err) + os.remove(watched_path) + os.remove(unwatched_path) - vim.wait(50) + wait_for_event() - watched:close() - os.remove(watched_path) + exec_lua [[_G.stop_watch()]] - vim.wait(50) + -- No events should come through anymore - return events - ]], - root_dir - ) + vim.uv.sleep(100) + touch(watched_path) + vim.uv.sleep(100) + os.remove(watched_path) + vim.uv.sleep(100) - local expected = { + eq({ { change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), path = root_dir .. '/file', @@ -76,103 +117,11 @@ describe('vim._watch', function() change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), path = root_dir .. '/file', }, - } - - -- kqueue only reports events on the watched path itself, so creating a file within a - -- watched directory results in a "rename" libuv event on the directory. - if is_os('bsd') then - expected = { - { - change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), - path = root_dir, - }, - { - change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), - path = root_dir, - }, - } - end - - eq(expected, result) + }, exec_lua [[return _G.events]]) end) - end) + end - describe('poll', function() - it('detects file changes', function() - skip(is_os('bsd'), "bsd only reports rename on folders if file inside change") - local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') - - local result = exec_lua( - [[ - local root_dir = ... - local lpeg = vim.lpeg - - local events = {} - - local debounce = 100 - local wait_ms = debounce + 200 - - local expected_events = 0 - local function wait_for_events() - assert(vim.wait(wait_ms, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) - end - - local incl = lpeg.P(root_dir) * lpeg.P("/file")^-1 - local excl = lpeg.P(root_dir..'/file.unwatched') - local stop = vim._watch.poll(root_dir, { - debounce = debounce, - include_pattern = incl, - exclude_pattern = excl, - }, function(path, change_type) - table.insert(events, { path = path, change_type = change_type }) - end) - - local watched_path = root_dir .. '/file' - local watched, err = io.open(watched_path, 'w') - assert(not err, err) - local unwatched_path = root_dir .. '/file.unwatched' - local unwatched, err = io.open(unwatched_path, 'w') - assert(not err, err) - - expected_events = expected_events + 1 - wait_for_events() - - watched:close() - os.remove(watched_path) - unwatched:close() - os.remove(unwatched_path) - - expected_events = expected_events + 1 - wait_for_events() - - stop() - -- No events should come through anymore - - local watched_path = root_dir .. '/file' - local watched, err = io.open(watched_path, 'w') - assert(not err, err) - - watched:close() - os.remove(watched_path) - - return events - ]], - root_dir - ) - - local created = exec_lua([[return vim._watch.FileChangeType.Created]]) - local deleted = exec_lua([[return vim._watch.FileChangeType.Deleted]]) - local expected = { - { - change_type = created, - path = root_dir .. "/file", - }, - { - change_type = deleted, - path = root_dir .. "/file", - } - } - eq(expected, result) - end) - end) + run('watch') + run('watchdirs') + run('fswatch') end) diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua index 3121ac051f..c21309c2e4 100644 --- a/test/functional/lua/xdiff_spec.lua +++ b/test/functional/lua/xdiff_spec.lua @@ -11,7 +11,7 @@ describe('xdiff bindings', function() describe('can diff text', function() before_each(function() - exec_lua[[ + exec_lua [[ a1 = 'Hello\n' b1 = 'Helli\n' @@ -21,15 +21,14 @@ describe('xdiff bindings', function() end) it('with no callback', function() - eq( table.concat({ '@@ -1 +1 @@', '-Hello', '+Helli', - '' + '', }, '\n'), - exec_lua("return vim.diff(a1, b1)") + exec_lua('return vim.diff(a1, b1)') ) eq( @@ -41,11 +40,10 @@ describe('xdiff bindings', function() '-foo', '+bar', '+baz', - '' + '', }, '\n'), - exec_lua("return vim.diff(a2, b2)") + exec_lua('return vim.diff(a2, b2)') ) - end) it('with callback', function() @@ -53,43 +51,55 @@ describe('xdiff bindings', function() exp[#exp+1] = {sa, ca, sb, cb} end]]) - eq({{1, 1, 1, 1}}, exec_lua[[ + eq( + { { 1, 1, 1, 1 } }, + exec_lua [[ exp = {} assert(vim.diff(a1, b1, {on_hunk = on_hunk}) == nil) return exp - ]]) + ]] + ) - eq({{1, 1, 1, 1}, {3, 1, 3, 2}}, exec_lua[[ + eq( + { { 1, 1, 1, 1 }, { 3, 1, 3, 2 } }, + exec_lua [[ exp = {} assert(vim.diff(a2, b2, {on_hunk = on_hunk}) == nil) return exp - ]]) + ]] + ) -- gives higher precedence to on_hunk over result_type - eq({{1, 1, 1, 1}, {3, 1, 3, 2}}, exec_lua[[ + eq( + { { 1, 1, 1, 1 }, { 3, 1, 3, 2 } }, + exec_lua [[ exp = {} assert(vim.diff(a2, b2, {on_hunk = on_hunk, result_type='indices'}) == nil) return exp - ]]) + ]] + ) end) it('with error callback', function() - exec_lua[[ + exec_lua [[ on_hunk = function(sa, ca, sb, cb) error('ERROR1') end ]] - eq([[error running function on_hunk: [string "<nvim>"]:0: ERROR1]], - pcall_err(exec_lua, [[vim.diff(a1, b1, {on_hunk = on_hunk})]])) + eq( + [[error running function on_hunk: [string "<nvim>"]:0: ERROR1]], + pcall_err(exec_lua, [[vim.diff(a1, b1, {on_hunk = on_hunk})]]) + ) end) it('with hunk_lines', function() - eq({{1, 1, 1, 1}}, - exec_lua([[return vim.diff(a1, b1, {result_type = 'indices'})]])) + eq({ { 1, 1, 1, 1 } }, exec_lua([[return vim.diff(a1, b1, {result_type = 'indices'})]])) - eq({{1, 1, 1, 1}, {3, 1, 3, 2}}, - exec_lua([[return vim.diff(a2, b2, {result_type = 'indices'})]])) + eq( + { { 1, 1, 1, 1 }, { 3, 1, 3, 2 } }, + exec_lua([[return vim.diff(a2, b2, {result_type = 'indices'})]]) + ) end) it('can run different algorithms', function() @@ -101,7 +111,8 @@ describe('xdiff bindings', function() '.bar {', ' margin: 0;', '}', - ''}, '\n') + '', + }, '\n') local b = table.concat({ '.bar {', @@ -112,10 +123,12 @@ describe('xdiff bindings', function() ' margin: 0;', ' color: green;', '}', - ''}, '\n') + '', + }, '\n') eq( - table.concat({'@@ -1,4 +0,0 @@', + table.concat({ + '@@ -1,4 +0,0 @@', '-.foo1 {', '- margin: 0;', '-}', @@ -126,31 +139,37 @@ describe('xdiff bindings', function() '+ margin: 0;', '+ color: green;', '+}', - ''}, '\n'), - exec_lua([[ + '', + }, '\n'), + exec_lua( + [[ local args = {...} return vim.diff(args[1], args[2], { algorithm = 'patience' }) - ]], a, b)) + ]], + a, + b + ) + ) end) end) it('can handle bad args', function() - eq([[Expected at least 2 arguments]], - pcall_err(exec_lua, [[vim.diff('a')]])) - - eq([[bad argument #1 to 'diff' (expected string)]], - pcall_err(exec_lua, [[vim.diff(1, 2)]])) + eq([[Expected at least 2 arguments]], pcall_err(exec_lua, [[vim.diff('a')]])) - eq([[bad argument #3 to 'diff' (expected table)]], - pcall_err(exec_lua, [[vim.diff('a', 'b', true)]])) + eq([[bad argument #1 to 'diff' (expected string)]], pcall_err(exec_lua, [[vim.diff(1, 2)]])) - eq([[unexpected key: bad_key]], - pcall_err(exec_lua, [[vim.diff('a', 'b', { bad_key = true })]])) + eq( + [[bad argument #3 to 'diff' (expected table)]], + pcall_err(exec_lua, [[vim.diff('a', 'b', true)]]) + ) - eq([[on_hunk is not a function]], - pcall_err(exec_lua, [[vim.diff('a', 'b', { on_hunk = true })]])) + eq([[invalid key: bad_key]], pcall_err(exec_lua, [[vim.diff('a', 'b', { bad_key = true })]])) + eq( + [[on_hunk is not a function]], + pcall_err(exec_lua, [[vim.diff('a', 'b', { on_hunk = true })]]) + ) end) end) |