diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-25 19:15:05 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-25 19:27:38 +0000 |
commit | c5d770d311841ea5230426cc4c868e8db27300a8 (patch) | |
tree | dd21f70127b4b8b5f109baefc8ecc5016f507c91 /test/functional/lua | |
parent | 9be89f131f87608f224f0ee06d199fcd09d32176 (diff) | |
parent | 081beb3659bd6d8efc3e977a160b1e72becbd8a2 (diff) | |
download | rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.tar.gz rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.tar.bz2 rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.zip |
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'test/functional/lua')
-rw-r--r-- | test/functional/lua/buffer_updates_spec.lua | 1 | ||||
-rw-r--r-- | test/functional/lua/commands_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/lua/diagnostic_spec.lua | 34 | ||||
-rw-r--r-- | test/functional/lua/filetype_spec.lua | 12 | ||||
-rw-r--r-- | test/functional/lua/hl_spec.lua (renamed from test/functional/lua/highlight_spec.lua) | 29 | ||||
-rw-r--r-- | test/functional/lua/loop_spec.lua | 5 | ||||
-rw-r--r-- | test/functional/lua/luaeval_spec.lua | 1 | ||||
-rw-r--r-- | test/functional/lua/overrides_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/lua/runtime_spec.lua | 4 | ||||
-rw-r--r-- | test/functional/lua/secure_spec.lua | 1 | ||||
-rw-r--r-- | test/functional/lua/system_spec.lua | 12 | ||||
-rw-r--r-- | test/functional/lua/thread_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/lua/ui_event_spec.lua | 189 | ||||
-rw-r--r-- | test/functional/lua/ui_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 376 | ||||
-rw-r--r-- | test/functional/lua/with_spec.lua | 2 |
16 files changed, 560 insertions, 114 deletions
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index f277868b1c..7d034222c8 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -344,7 +344,6 @@ describe('lua buffer event callbacks: on_lines', function() it('setting extmark in on_lines callback works', function() local screen = Screen.new(40, 6) - screen:attach() api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'bbb', 'ccc' }) exec_lua(function() diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 456ee13da2..1fd01cfd5a 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -111,7 +111,6 @@ describe(':lua', function() it('can show multiline error messages', function() 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 }, @@ -204,7 +203,6 @@ describe(':lua', function() 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. diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 4ae1146703..eb1ac3e6a1 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -111,6 +111,19 @@ describe('vim.diagnostic', function() { details = true } ) end + + ---@param ns integer + function _G.get_underline_extmarks(ns) + ---@type integer + local underline_ns = vim.diagnostic.get_namespace(ns).user_data.underline_ns + return vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + underline_ns, + 0, + -1, + { details = true } + ) + end end) exec_lua(function() @@ -1813,6 +1826,21 @@ describe('vim.diagnostic', function() _G.make_info('Info', 4, 4, 4, 4), }) + function _G.get_highest_underline_hl(severity_sort) + vim.diagnostic.config({ + underline = true, + severity_sort = severity_sort, + }) + + local extmarks = _G.get_underline_extmarks(_G.diagnostic_ns) + + table.sort(extmarks, function(a, b) + return a[4].priority > b[4].priority + end) + + return extmarks[1][4].hl_group + end + function _G.get_virt_text_and_signs(severity_sort) vim.diagnostic.config({ severity_sort = severity_sort, @@ -1864,6 +1892,12 @@ describe('vim.diagnostic', function() result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]] eq({ 'Error', 'Warn', 'Info' }, result[1]) eq({ 'Info', 'Warn', 'Error' }, result[2]) + + local underline_hl = exec_lua [[return _G.get_highest_underline_hl(true)]] + eq('DiagnosticUnderlineError', underline_hl) + + underline_hl = exec_lua [[return _G.get_highest_underline_hl({ reverse = true })]] + eq('DiagnosticUnderlineInfo', underline_hl) end) it('can show diagnostic sources in virtual text', function() diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 574c837f92..b6011d5268 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -161,6 +161,18 @@ describe('vim.filetype', function() end end end) + + it('.get_option() cleans up buffer on error', function() + api.nvim_create_autocmd('FileType', { pattern = 'foo', command = 'lua error()' }) + + local buf = api.nvim_get_current_buf() + + exec_lua(function() + pcall(vim.filetype.get_option, 'foo', 'lisp') + end) + + eq(buf, api.nvim_get_current_buf()) + end) end) describe('filetype.lua', function() diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/hl_spec.lua index c048949df8..89881973bf 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/hl_spec.lua @@ -9,7 +9,7 @@ local command = n.command local clear = n.clear local api = n.api -describe('vim.highlight.range', function() +describe('vim.hl.range', function() local screen before_each(function() @@ -18,7 +18,6 @@ describe('vim.highlight.range', function() screen:add_extra_attr_ids({ [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true }, }) - screen:attach() api.nvim_set_option_value('list', true, {}) api.nvim_set_option_value('listchars', 'eol:$', {}) api.nvim_buf_set_lines(0, 0, -1, true, { @@ -33,7 +32,7 @@ describe('vim.highlight.range', function() it('works with charwise selection', function() exec_lua(function() local ns = vim.api.nvim_create_namespace('') - vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 }) + vim.hl.range(0, ns, 'Search', { 1, 5 }, { 3, 10 }) end) screen:expect([[ ^asdfghjkl{1:$} | @@ -48,7 +47,7 @@ describe('vim.highlight.range', function() it('works with linewise selection', function() exec_lua(function() local ns = vim.api.nvim_create_namespace('') - vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' }) + vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' }) end) screen:expect([[ {10:^asdfghjkl}{100:$} | @@ -63,7 +62,7 @@ describe('vim.highlight.range', function() it('works with blockwise selection', function() exec_lua(function() local ns = vim.api.nvim_create_namespace('') - vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' }) + vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' }) end) screen:expect([[ {10:^asdf}ghjkl{1:$} | @@ -78,7 +77,7 @@ describe('vim.highlight.range', function() it('works with blockwise selection with width', function() exec_lua(function() local ns = vim.api.nvim_create_namespace('') - vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' }) + vim.hl.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' }) end) screen:expect([[ ^asdf{10:ghjkl}{1:$} | @@ -93,8 +92,8 @@ describe('vim.highlight.range', function() it('can use -1 or v:maxcol to indicate end of line', function() exec_lua(function() local ns = vim.api.nvim_create_namespace('') - vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {}) - vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {}) + vim.hl.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {}) + vim.hl.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {}) end) screen:expect([[ ^asdf{10:ghjkl}{100:$} | @@ -107,7 +106,7 @@ describe('vim.highlight.range', function() end) end) -describe('vim.highlight.on_yank', function() +describe('vim.hl.on_yank', function() before_each(function() clear() end) @@ -115,7 +114,7 @@ describe('vim.highlight.on_yank', function() it('does not show errors even if buffer is wiped before timeout', function() command('new') exec_lua(function() - vim.highlight.on_yank({ + vim.hl.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y', regtype = 'v' }, @@ -129,10 +128,10 @@ describe('vim.highlight.on_yank', function() it('does not close timer twice', function() exec_lua(function() - vim.highlight.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } }) + vim.hl.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } }) vim.uv.sleep(10) vim.schedule(function() - vim.highlight.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) + vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) end) end) eq('', eval('v:errmsg')) @@ -143,7 +142,7 @@ describe('vim.highlight.on_yank', function() exec_lua(function() 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' } }) + vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) end) local ns = api.nvim_create_namespace('hlyank') local win = api.nvim_get_current_win() @@ -157,7 +156,7 @@ describe('vim.highlight.on_yank', function() exec_lua(function() 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' } }) + vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) end) local ns = api.nvim_create_namespace('hlyank') eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1]) @@ -165,7 +164,7 @@ describe('vim.highlight.on_yank', function() exec_lua(function() 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' } }) + vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) end) local win = api.nvim_get_current_win() eq({ win }, api.nvim__ns_get(ns).wins) diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua index de8200a5f1..52a8fec0bf 100644 --- a/test/functional/lua/loop_spec.lua +++ b/test/functional/lua/loop_spec.lua @@ -65,7 +65,6 @@ describe('vim.uv', function() it('is API safe', 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 }, @@ -88,9 +87,9 @@ describe('vim.uv', function() screen:expect([[ | {2: }| - {3:Error executing luv callback:} | + {3:Error executing callback:} | {3:[string "<nvim>"]:5: E5560: nvim_set_var must not }| - {3:be called in a lua loop callback} | + {3:be called in a fast event context} | {3:stack traceback:} | {3: [C]: in function 'nvim_set_var'} | {3: [string "<nvim>"]:5: in function <[string }| diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 2b23f72c7d..5fea79141c 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -510,7 +510,6 @@ describe('v:lua', function() it('works in func options', function() local screen = Screen.new(60, 8) - screen:attach() api.nvim_set_option_value('omnifunc', 'v:lua.mymod.omni', {}) feed('isome st<c-x><c-o>') screen:expect{grid=[[ diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 33a2813200..2f332d2c10 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -158,7 +158,6 @@ describe('print', function() it('blank line in message works', 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 }, @@ -196,7 +195,6 @@ describe('debug.debug', function() before_each(function() screen = Screen.new() - screen:attach() screen:set_default_attr_ids { [0] = { bold = true, foreground = 255 }, [1] = { bold = true, reverse = true }, diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index f63363d6d9..6705dff847 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -21,7 +21,9 @@ describe('runtime:', function() exec('set rtp+=' .. plug_dir) exec([[ set shell=doesnotexist - set completeslash=slash + if exists('+completeslash') + set completeslash=slash + endif set isfname+=(,) ]]) end) diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua index c58fd689b7..b40b084ef9 100644 --- a/test/functional/lua/secure_spec.lua +++ b/test/functional/lua/secure_spec.lua @@ -39,7 +39,6 @@ describe('vim.secure', function() it('works', 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 }, diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua index 482bfcf1a9..afbada007d 100644 --- a/test/functional/lua/system_spec.lua +++ b/test/functional/lua/system_spec.lua @@ -9,7 +9,7 @@ local function system_sync(cmd, opts) return exec_lua(function() local obj = vim.system(cmd, opts) - if opts.timeout then + if opts and opts.timeout then -- Minor delay before calling wait() so the timeout uv timer can have a headstart over the -- internal call to vim.wait() in wait(). vim.wait(10) @@ -75,7 +75,7 @@ describe('vim.system', function() it('kill processes', function() exec_lua(function() - local signal + local signal --- @type integer? local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r) signal = r.signal end) -- run forever @@ -112,4 +112,12 @@ describe('vim.system', function() ) eq(true, exec_lua([[return _G.processed]])) end) + + if t.is_os('win') then + it('can resolve windows command extentions.', function() + t.write_file('test.bat', 'echo hello world') + system_sync({ 'chmod', '+x', 'test.bat' }) + system_sync({ './test' }) + end) + end end) diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua index cbf23517dc..310705fd97 100644 --- a/test/functional/lua/thread_spec.lua +++ b/test/functional/lua/thread_spec.lua @@ -17,7 +17,6 @@ describe('thread', function() before_each(function() clear() screen = Screen.new(50, 10) - screen:attach() end) it('entry func is executed in protected mode', function() @@ -257,7 +256,6 @@ describe('threadpool', function() it('with invalid return value', function() local screen = Screen.new(50, 10) - screen:attach() exec_lua [[ local work = vim.uv.new_work(function() return {} end, function() end) diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 0a6deaa41c..c8616e3e11 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -32,16 +32,6 @@ describe('vim.ui_attach', function() ]] 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 }, - [5] = { reverse = true }, - [6] = { reverse = true, bold = true }, - [7] = { background = Screen.colors.Yellow1 }, - }) - screen:attach() end) local function expect_events(expected) @@ -56,7 +46,7 @@ describe('vim.ui_attach', function() grid = [[ fo^ | {1:~ }|*3 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], } @@ -65,7 +55,7 @@ describe('vim.ui_attach', function() grid = [[ food^ | {1:~ }|*3 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], } expect_events { @@ -84,7 +74,7 @@ describe('vim.ui_attach', function() grid = [[ foobar^ | {1:~ }|*3 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], } expect_events { @@ -106,10 +96,10 @@ describe('vim.ui_attach', function() screen:expect { grid = [[ food^ | - {3:food }{1: }| + {12:food }{1: }| {4:foobar }{1: }| {4:foo }{1: }| - {2:-- INSERT --} | + {5:-- INSERT --} | ]], } expect_events {} @@ -151,9 +141,9 @@ describe('vim.ui_attach', function() { 'msg_history_show', { - { 'echomsg', { { 0, 'message1' } } }, - { '', { { 0, 'message2' } } }, - { 'echomsg', { { 0, 'message3' } } }, + { 'echomsg', { { 0, 'message1', 0 } } }, + { 'lua_print', { { 0, 'message2', 0 } } }, + { 'echomsg', { { 0, 'message3', 0 } } }, }, }, }, actual, vim.inspect(actual)) @@ -181,12 +171,17 @@ describe('vim.ui_attach', function() exec_lua([[ _G.cmdline = 0 vim.ui_attach(ns, { ext_messages = true }, function(ev) - vim.cmd.redraw() + if ev == 'msg_show' then + vim.schedule(function() vim.cmd.redraw() end) + else + vim.cmd.redraw() + end _G.cmdline = _G.cmdline + (ev == 'cmdline_show' and 1 or 0) end )]]) feed(':') - eq(1, exec_lua('return _G.cmdline')) + n.assert_alive() + eq(2, exec_lua('return _G.cmdline')) n.assert_alive() feed('version<CR><CR>v<Esc>') n.assert_alive() @@ -212,9 +207,9 @@ describe('vim.ui_attach', function() screen:expect({ grid = [[ cmdline | - {5:cmdline [+] }| + {2:cmdline [+] }| fooba^r | - {6:[No Name] [+] }| + {3:[No Name] [+] }| | ]], }) @@ -223,9 +218,9 @@ describe('vim.ui_attach', function() screen:expect({ grid = [[ foo | - {5:cmdline [+] }| - {5:foo}ba^r | - {6:[No Name] [+] }| + {2:cmdline [+] }| + {2:foo}ba^r | + {3:[No Name] [+] }| | ]], }) @@ -234,25 +229,78 @@ describe('vim.ui_attach', function() screen:expect({ grid = [[ %s/bar/baz | - {5:cmdline [+] }| - foo{7:ba^z} | - {6:[No Name] [+] }| + {2:cmdline [+] }| + foo{10:ba^z} | + {3:[No Name] [+] }| | ]], }) end) + + it('msg_show in fast context', function() + exec_lua([[ + vim.ui_attach(ns, { ext_messages = true }, function(event, _, content) + if event == "msg_show" then + vim.api.nvim_get_runtime_file("foo", false) + -- non-"fast-api" is not allowed in msg_show callback and should be scheduled + local _, err = pcall(vim.api.nvim_buf_set_lines, 0, -2, -1, false, { content[1][2] }) + pcall(vim.api.nvim__redraw, { flush = true }) + vim.schedule(function() + vim.api.nvim_buf_set_lines(0, -2, -1, false, { content[1][2], err }) + end) + end + end) + ]]) + -- "fast-api" does not prevent aborting :function + feed(':func Foo()<cr>bar<cr>endf<cr>:func Foo()<cr>') + screen:expect({ + grid = [[ + ^E122: Function Foo already exists, add !| + to replace it | + E5560: nvim_buf_set_lines must not be ca| + lled in a fast event context | + {1:~ }| + ]], + messages = { + { + content = { { 'E122: Function Foo already exists, add ! to replace it', 9, 7 } }, + kind = 'emsg', + }, + }, + }) + -- No fast context for prompt message kinds + feed(':%s/Function/Replacement/c<cr>') + screen:expect({ + grid = [[ + ^E122: {10:Function} Foo already exists, add !| + to replace it | + replace with Replacement (y/n/a/q/l/^E/^| + Y)? | + {1:~ }| + ]], + messages = { + { + content = { { 'replace with Replacement (y/n/a/q/l/^E/^Y)?', 6, 19 } }, + kind = 'confirm_sub', + }, + }, + }) + end) end) describe('vim.ui_attach', function() + local screen + before_each(function() + clear({ env = { NVIM_LOG_FILE = testlog } }) + screen = Screen.new(40, 5) + end) + after_each(function() check_close() os.remove(testlog) end) it('error in callback is logged', function() - clear({ env = { NVIM_LOG_FILE = testlog } }) - local screen = Screen.new() - screen:attach() exec_lua([[ local ns = vim.api.nvim_create_namespace('testspace') vim.ui_attach(ns, { ext_popupmenu = true }, function() error(42) end) @@ -260,4 +308,83 @@ describe('vim.ui_attach', function() feed('ifoo<CR>foobar<CR>fo<C-X><C-N>') assert_log('Error executing UI event callback: Error executing lua: .*: 42', testlog, 100) end) + + it('detaches after excessive errors', function() + screen:add_extra_attr_ids({ [100] = { bold = true, foreground = Screen.colors.SeaGreen } }) + exec_lua([[ + vim.ui_attach(vim.api.nvim_create_namespace(''), { ext_messages = true }, function() + vim.api.nvim_buf_set_lines(0, -2, -1, false, { err[1] }) + end) + ]]) + screen:expect({ + grid = [[ + ^ | + {1:~ }|*4 + ]], + }) + feed('ifoo') + screen:expect({ + grid = [[ + foo^ | + {1:~ }|*4 + ]], + showmode = { { '-- INSERT --', 5, 12 } }, + }) + feed('<esc>:1mes clear<cr>:mes<cr>') + screen:expect({ + grid = [[ + foo | + {3: }| + {9:Excessive errors in vim.ui_attach() call}| + {9:back from ns: 1.} | + {100:Press ENTER or type command to continue}^ | + ]], + }) + feed('<cr>') + -- Also when scheduled + exec_lua([[ + vim.ui_attach(vim.api.nvim_create_namespace(''), { ext_messages = true }, function() + vim.schedule(function() vim.api.nvim_buf_set_lines(0, -2, -1, false, { err[1] }) end) + end) + ]]) + screen:expect({ + any = 'fo^o', + messages = { + { + content = { + { + 'Error executing vim.schedule lua callback: [string "<nvim>"]:2: attempt to index global \'err\' (a nil value)\nstack traceback:\n\t[string "<nvim>"]:2: in function <[string "<nvim>"]:2>', + 9, + 7, + }, + }, + kind = 'lua_error', + }, + { + content = { + { + 'Error executing vim.schedule lua callback: [string "<nvim>"]:2: attempt to index global \'err\' (a nil value)\nstack traceback:\n\t[string "<nvim>"]:2: in function <[string "<nvim>"]:2>', + 9, + 7, + }, + }, + kind = 'lua_error', + }, + { + content = { { 'Press ENTER or type command to continue', 100, 19 } }, + kind = 'return_prompt', + }, + }, + }) + feed('<esc>:1mes clear<cr>:mes<cr>') + screen:expect({ + grid = [[ + foo | + {3: }| + {9:Excessive errors in vim.ui_attach() call}| + {9:back from ns: 2.} | + {100:Press ENTER or type command to continue}^ | + ]], + }) + end) end) diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua index d5eede2885..5c727b3347 100644 --- a/test/functional/lua/ui_spec.lua +++ b/test/functional/lua/ui_spec.lua @@ -153,7 +153,7 @@ describe('vim.ui', function() vim.fn.executable = function() return 0 end ]] eq( - 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)', + 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open, lemonade)', exec_lua [[local _, err = vim.ui.open('foo') ; return err]] ) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 3c65ec664e..3cfbfe167a 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -28,6 +28,7 @@ local rmdir = n.rmdir local write_file = t.write_file local poke_eventloop = n.poke_eventloop local assert_alive = n.assert_alive +local expect = n.expect describe('lua stdlib', function() before_each(clear) @@ -155,10 +156,10 @@ describe('lua stdlib', function() end) it('plugin=nil, no error if soft-deprecated', function() - eq( - vim.NIL, - exec_lua('return vim.deprecate(...)', 'foo.baz()', 'foo.better_baz()', '0.99.0') - ) + eq(vim.NIL, exec_lua [[return vim.deprecate('old1', 'new1', '0.99.0')]]) + -- Major version > current Nvim major is always "soft-deprecated". + -- XXX: This is also a reminder to update the hardcoded `nvim_major`, when Nvim reaches 1.0. + eq(vim.NIL, exec_lua [[return vim.deprecate('old2', 'new2', '1.0.0')]]) end) it('plugin=nil, show error if hard-deprecated', function() @@ -175,13 +176,6 @@ describe('lua stdlib', function() ) end) - it('plugin=nil, to be deleted in the next major version (1.0)', function() - eq( - [[foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]], - exec_lua [[ return vim.deprecate('foo.baz()', nil, '1.0') ]] - ) - end) - it('plugin specified', function() -- When `plugin` is specified, don't show ":help deprecated". #22235 eq( @@ -319,21 +313,106 @@ describe('lua stdlib', function() 49, 51, } + local indices8 = { + [0] = 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + } for i, k in pairs(indices32) do eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ...)', i), i) + eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., false)', i), i) + eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-32", ...)', i), i) end for i, k in pairs(indices16) do eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., true)', i), i) + eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-16", ...)', i), i) end - eq( + for i, k in pairs(indices8) do + eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-8", ...)', i), i) + end + matches( 'index out of range', pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ...)', #indices32 + 1) ) - eq( + matches( 'index out of range', pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ..., true)', #indices16 + 1) ) - local i32, i16 = 0, 0 + matches( + 'index out of range', + pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, "utf-16", ...)', #indices16 + 1) + ) + matches( + 'index out of range', + pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, "utf-32", ...)', #indices32 + 1) + ) + matches( + 'invalid encoding', + pcall_err(exec_lua, 'return vim.str_byteindex("hello", "madeupencoding", 1)') + ) + eq( + indices32[#indices32], + exec_lua('return vim.str_byteindex(_G.test_text, "utf-32", 99999, false)') + ) + eq( + indices16[#indices16], + exec_lua('return vim.str_byteindex(_G.test_text, "utf-16", 99999, false)') + ) + eq( + indices8[#indices8], + exec_lua('return vim.str_byteindex(_G.test_text, "utf-8", 99999, false)') + ) + eq(2, exec_lua('return vim.str_byteindex("é", "utf-16", 2, false)')) + local i32, i16, i8 = 0, 0, 0 local len = 51 for k = 0, len do if indices32[i32] < k then @@ -345,9 +424,29 @@ describe('lua stdlib', function() i16 = i16 + 1 end end + if indices8[i8] < k then + i8 = i8 + 1 + end eq({ i32, i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, ...)}', k), k) + eq({ i32 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-32", ...)}', k), k) + eq({ i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-16", ...)}', k), k) + eq({ i8 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-8", ...)}', k), k) end - eq( + + eq({ #indices32, #indices16 }, exec_lua('return {vim.str_utfindex(_G.test_text)}')) + + eq(#indices32, exec_lua('return vim.str_utfindex(_G.test_text, "utf-32", math.huge, false)')) + eq(#indices16, exec_lua('return vim.str_utfindex(_G.test_text, "utf-16", math.huge, false)')) + eq(#indices8, exec_lua('return vim.str_utfindex(_G.test_text, "utf-8", math.huge, false)')) + + eq(#indices32, exec_lua('return vim.str_utfindex(_G.test_text, "utf-32")')) + eq(#indices16, exec_lua('return vim.str_utfindex(_G.test_text, "utf-16")')) + eq(#indices8, exec_lua('return vim.str_utfindex(_G.test_text, "utf-8")')) + matches( + 'invalid encoding', + pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, "madeupencoding", ...)', 1) + ) + matches( 'index out of range', pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, ...)', len + 1) ) @@ -538,7 +637,6 @@ describe('lua stdlib', function() matches('big failure\nvery async', remove_trace(eval('v:errmsg'))) local screen = Screen.new(60, 5) - screen:attach() screen:expect { grid = [[ ^ | @@ -1304,7 +1402,6 @@ describe('lua stdlib', function() end) local screen = Screen.new(50, 7) - screen:attach() exec_lua([[ timer = vim.uv.new_timer() timer:start(20, 0, function () @@ -1317,7 +1414,7 @@ describe('lua stdlib', function() screen:expect { grid = [[ {9:[string "<nvim>"]:6: E5560: rpcrequest must not be}| - {9: called in a lua loop callback} | + {9: called in a fast event context} | {9:stack traceback:} | {9: [C]: in function 'rpcrequest'} | {9: [string "<nvim>"]:6: in function <[string }| @@ -1326,7 +1423,9 @@ describe('lua stdlib', function() ]], } feed('<cr>') - eq({ 3, NIL }, api.nvim_get_var('yy')) + retry(10, nil, function() + eq({ 3, NIL }, api.nvim_get_var('yy')) + end) exec_lua([[timer:close()]]) end) @@ -1363,7 +1462,79 @@ describe('lua stdlib', function() eq('{"a": {}, "b": []}', exec_lua([[ return vim.fn.json_encode({a=vim.empty_dict(), b={}}) ]])) end) - it('vim.validate', function() + it('vim.validate (fast form)', function() + exec_lua("vim.validate('arg1', {}, 'table')") + exec_lua("vim.validate('arg1', nil, 'table', true)") + exec_lua("vim.validate('arg1', { foo='foo' }, 'table')") + exec_lua("vim.validate('arg1', { 'foo' }, 'table')") + exec_lua("vim.validate('arg1', 'foo', 'string')") + exec_lua("vim.validate('arg1', nil, 'string', true)") + exec_lua("vim.validate('arg1', 1, 'number')") + exec_lua("vim.validate('arg1', 0, 'number')") + exec_lua("vim.validate('arg1', 0.1, 'number')") + exec_lua("vim.validate('arg1', nil, 'number', true)") + exec_lua("vim.validate('arg1', true, 'boolean')") + exec_lua("vim.validate('arg1', false, 'boolean')") + exec_lua("vim.validate('arg1', nil, 'boolean', true)") + exec_lua("vim.validate('arg1', function()end, 'function')") + exec_lua("vim.validate('arg1', nil, 'function', true)") + exec_lua("vim.validate('arg1', nil, 'nil')") + exec_lua("vim.validate('arg1', nil, 'nil', true)") + exec_lua("vim.validate('arg1', coroutine.create(function()end), 'thread')") + exec_lua("vim.validate('arg1', nil, 'thread', true)") + exec_lua("vim.validate('arg1', 2, function(a) return (a % 2) == 0 end, 'even number')") + exec_lua("vim.validate('arg1', 5, {'number', 'string'})") + exec_lua("vim.validate('arg2', 'foo', {'number', 'string'})") + + matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number')) + matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string')) + matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table')) + matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function')) + matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string')) + matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table')) + matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function')) + matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number')) + matches('arg1: expected x, got number', pcall_err(exec_lua, "vim.validate('arg1', 1, 'x')")) + matches('invalid validator: 1', pcall_err(exec_lua, "vim.validate('arg1', 1, 1)")) + matches('invalid arguments', pcall_err(exec_lua, "vim.validate('arg1', { 1 })")) + + -- Validated parameters are required by default. + matches( + 'arg1: expected string, got nil', + pcall_err(exec_lua, "vim.validate('arg1', nil, 'string')") + ) + -- Explicitly required. + matches( + 'arg1: expected string, got nil', + pcall_err(exec_lua, "vim.validate('arg1', nil, 'string', false)") + ) + + matches( + 'arg1: expected table, got number', + pcall_err(exec_lua, "vim.validate('arg1', 1, 'table')") + ) + + matches( + 'arg1: expected even number, got 3', + pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1 end, 'even number')") + ) + matches( + 'arg1: expected %?, got 3', + pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1 end)") + ) + matches( + 'arg1: expected number|string, got nil', + pcall_err(exec_lua, "vim.validate('arg1', nil, {'number', 'string'})") + ) + + -- Pass an additional message back. + matches( + 'arg1: expected %?, got 3. Info: TEST_MSG', + pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1, 'TEST_MSG' end)") + ) + end) + + it('vim.validate (spec form)', function() exec_lua("vim.validate{arg1={{}, 'table' }}") exec_lua("vim.validate{arg1={{}, 't' }}") exec_lua("vim.validate{arg1={nil, 't', true }}") @@ -1392,29 +1563,11 @@ describe('lua stdlib', function() exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}") exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}") exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}") - vim.validate('arg1', 5, 'number') - vim.validate('arg1', '5', 'string') - vim.validate('arg1', { 5 }, 'table') - vim.validate('arg1', function() - return 5 - end, 'function') - vim.validate('arg1', nil, 'number', true) - vim.validate('arg1', nil, 'string', true) - vim.validate('arg1', nil, 'table', true) - vim.validate('arg1', nil, 'function', true) - matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number')) - matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string')) - matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table')) - matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function')) - matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string')) - matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table')) - matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function')) - matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number')) matches('expected table, got number', pcall_err(exec_lua, "vim.validate{ 1, 'x' }")) - matches('invalid type name: x', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}")) - matches('invalid type name: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}')) - matches('invalid type name: nil', pcall_err(exec_lua, 'vim.validate{ arg1={ 1 }}')) + matches('arg1: expected x, got number', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}")) + matches('invalid validator: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}')) + matches('invalid validator: nil', pcall_err(exec_lua, 'vim.validate{ arg1={ 1 }}')) -- Validated parameters are required by default. matches( @@ -1975,7 +2128,6 @@ describe('lua stdlib', function() eq({ 1, 5 }, api.nvim_win_get_cursor(0)) local screen = Screen.new(60, 3) - screen:attach() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ @@ -3157,10 +3309,17 @@ describe('lua stdlib', function() eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]]) end) - it('skips any function that caused an error', function() + it('skips any function that caused an error and shows stacktrace', function() insert([[hello world]]) exec_lua [[ + local function ErrF2() + error("Dumb Error") + end + local function ErrF1() + ErrF2() + end + keys = {} return vim.on_key(function(buf) @@ -3171,7 +3330,7 @@ describe('lua stdlib', function() table.insert(keys, buf) if buf == 'l' then - error("Dumb Error") + ErrF1() end end) ]] @@ -3181,6 +3340,19 @@ describe('lua stdlib', function() -- Only the first letter gets added. After that we remove the callback eq('inext l', exec_lua [[ return table.concat(keys, '') ]]) + + local errmsg = api.nvim_get_vvar('errmsg') + matches( + [[ +^Error executing vim%.on%_key%(%) callbacks:.* +With ns%_id %d+: .*: Dumb Error +stack traceback: +.*: in function 'error' +.*: in function 'ErrF2' +.*: in function 'ErrF1' +.*]], + errmsg + ) end) it('argument 1 is keys after mapping, argument 2 is typed keys', function() @@ -3223,6 +3395,109 @@ describe('lua stdlib', function() feed('<C-C>') eq('/', exec_lua([[return _G.ctrl_c_cmdtype]])) end) + + it('callback is not invoked recursively #30752', function() + local screen = Screen.new(60, 10) + exec_lua([[ + vim.on_key(function(key, typed) + vim.api.nvim_echo({ + { 'key_cb\n' }, + { ("KEYCB: key '%s', typed '%s'\n"):format(key, typed) }, + }, false, {}) + end) + ]]) + feed('^') + screen:expect([[ + | + {1:~ }|*5 + {3: }| + key_cb | + KEYCB: key '^', typed '^' | + {6:Press ENTER or type command to continue}^ | + ]]) + feed('<C-C>') + screen:expect([[ + | + {1:~ }|*3 + {3: }| + key_cb | + KEYCB: key '^', typed '^' | + key_cb | + KEYCB: key '{18:^C}', typed '{18:^C}' | + {6:Press ENTER or type command to continue}^ | + ]]) + feed('<C-C>') + screen:expect([[ + ^ | + {1:~ }|*8 + | + ]]) + end) + + it('can discard input', function() + clear() + -- discard every other normal 'x' command + exec_lua [[ + n_key = 0 + + vim.on_key(function(buf, typed_buf) + if typed_buf == 'x' then + n_key = n_key + 1 + end + return (n_key % 2 == 0) and "" or nil + end) + ]] + + api.nvim_buf_set_lines(0, 0, -1, true, { '54321' }) + + feed('x') + expect('4321') + feed('x') + expect('4321') + feed('x') + expect('321') + feed('x') + expect('321') + end) + + it('callback invalid return', function() + clear() + -- second key produces an error which removes the callback + exec_lua [[ + n_call = 0 + + vim.on_key(function(buf, typed_buf) + if typed_buf == 'x' then + n_call = n_call + 1 + end + return n_call >= 2 and '!' or nil + end) + ]] + + api.nvim_buf_set_lines(0, 0, -1, true, { '54321' }) + + local function cleanup_msg(msg) + return msg:gsub('^Error .*\nWith ns%_id %d+: ', '') + end + + feed('x') + eq(1, exec_lua [[ return n_call ]]) + + eq(1, exec_lua [[ return vim.on_key(nil, nil) ]]) + + eq('', cleanup_msg(eval('v:errmsg'))) + feed('x') + eq(2, exec_lua [[ return n_call ]]) + eq('return string must be empty', cleanup_msg(eval('v:errmsg'))) + command('let v:errmsg = ""') + + eq(0, exec_lua [[ return vim.on_key(nil, nil) ]]) + + feed('x') + eq(2, exec_lua [[ return n_call ]]) + expect('21') + eq('', cleanup_msg(eval('v:errmsg'))) + end) end) describe('vim.wait', function() @@ -3500,7 +3775,6 @@ describe('lua stdlib', function() it('fails in fast callbacks #26122', function() local screen = Screen.new(80, 10) - screen:attach() exec_lua([[ local timer = vim.uv.new_timer() timer:start(0, 0, function() @@ -3509,7 +3783,7 @@ describe('lua stdlib', function() end) ]]) screen:expect({ - any = pesc('E5560: vim.wait must not be called in a lua loop callback'), + any = pesc('E5560: vim.wait must not be called in a fast event context'), }) feed('<CR>') assert_alive() @@ -3518,7 +3792,6 @@ describe('lua stdlib', function() it('vim.notify_once', function() local screen = Screen.new(60, 5) - screen:attach() screen:expect { grid = [[ ^ | @@ -3715,7 +3988,6 @@ describe('lua stdlib', function() it('updates ruler if cursor moved', function() -- Fixed for win_execute in vim-patch:8.1.2124, but should've applied to nvim_win_call too! local screen = Screen.new(30, 5) - screen:attach() exec_lua [[ _G.api = vim.api vim.opt.ruler = true @@ -3858,7 +4130,6 @@ describe('lua stdlib', function() it('vim.lua_omnifunc', function() local screen = Screen.new(60, 5) - screen:attach() command [[ set omnifunc=v:lua.vim.lua_omnifunc ]] -- Note: the implementation is shared with lua command line completion. @@ -4060,11 +4331,16 @@ describe('vim.keymap', function() ) matches( - 'opts: expected table, got function', + 'rhs: expected string|function, got number', pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 42, function() end)]]) ) matches( + 'opts: expected table, got function', + pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 'x', function() end)]]) + ) + + matches( 'rhs: expected string|function, got number', pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 42)]]) ) diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua index 99b80ef749..6127e83619 100644 --- a/test/functional/lua/with_spec.lua +++ b/test/functional/lua/with_spec.lua @@ -1029,7 +1029,6 @@ describe('vim._with', function() [1] = { bold = true, reverse = true }, [2] = { bold = true, foreground = Screen.colors.Blue }, } - screen:attach() exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echo('"ccc"') end) ]] screen:expect [[ ^ | @@ -1178,7 +1177,6 @@ describe('vim._with', function() [1] = { reverse = true }, [2] = { bold = true, reverse = true }, } - screen:attach() exec_lua [[ vim.opt.ruler = true local lines = {} |