diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2022-08-30 23:23:09 -0600 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2022-08-30 23:23:09 -0600 |
commit | 968aa6e3ed0497ea99f123c74c5fd0f3880ccc63 (patch) | |
tree | 32ac91852b82d040012d40a3f54f772723509968 /test/functional | |
parent | 242f75745009b3a0a2108d98ce6c02b6e13aac3f (diff) | |
parent | f4274d0f62625683486d3912dcd6e8e45877c6a4 (diff) | |
download | rneovim-968aa6e3ed0497ea99f123c74c5fd0f3880ccc63.tar.gz rneovim-968aa6e3ed0497ea99f123c74c5fd0f3880ccc63.tar.bz2 rneovim-968aa6e3ed0497ea99f123c74c5fd0f3880ccc63.zip |
Merge remote-tracking branch 'upstream/master' into userreg
Diffstat (limited to 'test/functional')
28 files changed, 1127 insertions, 76 deletions
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index 890710b6e6..440e93da0e 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -114,8 +114,8 @@ describe('nvim_create_user_command', function() ]] eq({ - args = [[this is a\ test]], - fargs = {"this", "is", "a test"}, + args = [[this\ is a\ test]], + fargs = {"this ", "is", "a test"}, bang = false, line1 = 1, line2 = 1, @@ -144,7 +144,7 @@ describe('nvim_create_user_command', function() count = 2, reg = "", }, exec_lua [=[ - vim.api.nvim_command([[CommandWithLuaCallback this is a\ test]]) + vim.api.nvim_command([[CommandWithLuaCallback this\ is a\ test]]) return result ]=]) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 72a03c409a..24d0b6da45 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3668,6 +3668,55 @@ describe('API', function() :^ | ]]) end) + it('does not move cursor or change search history/pattern #19878 #19890', function() + meths.buf_set_lines(0, 0, -1, true, {'foo', 'bar', 'foo', 'bar'}) + eq({1, 0}, meths.win_get_cursor(0)) + eq('', funcs.getreg('/')) + eq('', funcs.histget('search')) + feed(':') -- call the API in cmdline mode to test whether it changes search history + eq({ + cmd = 'normal', + args = {'x'}, + bang = true, + range = {3, 4}, + count = -1, + reg = '', + addr = 'line', + magic = { + file = false, + bar = false, + }, + nargs = '+', + nextcmd = '', + mods = { + browse = false, + confirm = false, + emsg_silent = false, + filter = { + pattern = "", + force = false, + }, + hide = false, + keepalt = false, + keepjumps = false, + keepmarks = false, + keeppatterns = false, + lockmarks = false, + noautocmd = false, + noswapfile = false, + sandbox = false, + silent = false, + split = "", + tab = 0, + unsilent = false, + verbose = -1, + vertical = false, + } + }, meths.parse_cmd('+2;/bar/normal! x', {})) + eq({1, 0}, meths.win_get_cursor(0)) + eq('', funcs.getreg('/')) + eq('', funcs.histget('search')) + end) end) describe('nvim_cmd', function() it('works', function () diff --git a/test/functional/autocmd/winscrolled_spec.lua b/test/functional/autocmd/winscrolled_spec.lua index 5c1b758961..12b8e7c42d 100644 --- a/test/functional/autocmd/winscrolled_spec.lua +++ b/test/functional/autocmd/winscrolled_spec.lua @@ -61,6 +61,20 @@ describe('WinScrolled', function() eq(3, eval('g:scrolled')) end) + it('is triggered by scrolling on a long wrapped line #19968', function() + local height = meths.win_get_height(0) + local width = meths.win_get_width(0) + meths.buf_set_lines(0, 0, -1, true, {('foo'):rep(height * width)}) + meths.win_set_cursor(0, {1, height * width - 1}) + eq(0, eval('g:scrolled')) + feed('gj') + eq(1, eval('g:scrolled')) + feed('0') + eq(2, eval('g:scrolled')) + feed('$') + eq(3, eval('g:scrolled')) + end) + it('is triggered when the window scrolls in Insert mode', function() local height = meths.win_get_height(0) local lines = {} diff --git a/test/functional/editor/K_spec.lua b/test/functional/editor/K_spec.lua index 8ad81ac3d6..3b5580540f 100644 --- a/test/functional/editor/K_spec.lua +++ b/test/functional/editor/K_spec.lua @@ -1,6 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) -local eq, clear, eval, feed, retry = - helpers.eq, helpers.clear, helpers.eval, helpers.feed, helpers.retry +local eq, clear, eval, feed, meths, retry = + helpers.eq, helpers.clear, helpers.eval, helpers.feed, helpers.meths, helpers.retry describe('K', function() local test_file = 'K_spec_out' @@ -58,4 +58,11 @@ describe('K', function() helpers.neq(bufnr, eval('bufnr()')) end) + it('empty string falls back to :help #19298', function() + meths.set_option('keywordprg', '') + meths.buf_set_lines(0, 0, -1, true, {'doesnotexist'}) + feed('K') + eq('E149: Sorry, no help for doesnotexist', meths.get_vvar('errmsg')) + end) + end) diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua index e3d3cdbd85..cd51a65be3 100644 --- a/test/functional/editor/mode_insert_spec.lua +++ b/test/functional/editor/mode_insert_spec.lua @@ -6,12 +6,20 @@ local expect = helpers.expect local command = helpers.command local eq = helpers.eq local eval = helpers.eval +local curbuf_contents = helpers.curbuf_contents describe('insert-mode', function() before_each(function() clear() end) + it('indents only once after "!" keys #12894', function() + command('let counter = []') + command('set indentexpr=len(add(counter,0))') + feed('i<C-F>x') + eq(' x', curbuf_contents()) + end) + it('CTRL-@', function() -- Inserts last-inserted text, leaves insert-mode. insert('hello') diff --git a/test/functional/ex_cmds/normal_spec.lua b/test/functional/ex_cmds/normal_spec.lua index f6e7dd2b3a..009f1d6516 100644 --- a/test/functional/ex_cmds/normal_spec.lua +++ b/test/functional/ex_cmds/normal_spec.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local command = helpers.command +local funcs = helpers.funcs local feed = helpers.feed local expect = helpers.expect local eq = helpers.eq @@ -8,20 +9,30 @@ local eval = helpers.eval before_each(clear) -describe(':normal', function() +describe(':normal!', function() it('can get out of Insert mode if called from Ex mode #17924', function() feed('gQnormal! Ifoo<CR>') expect('foo') end) - it('normal! does not execute command in Ex mode when running out of characters', function() + it('does not execute command in Ex mode when running out of characters', function() command('let g:var = 0') command('normal! gQlet g:var = 1') eq(0, eval('g:var')) end) - it('normal! gQinsert does not hang #17980', function() + it('gQinsert does not hang #17980', function() command('normal! gQinsert') expect('') end) + + it('can stop Visual mode without closing cmdwin vim-patch:9.0.0234', function() + feed('q:') + feed('v') + eq('v', funcs.mode(1)) + eq(':', funcs.getcmdwintype()) + command('normal! \027') + eq('n', funcs.mode(1)) + eq(':', funcs.getcmdwintype()) + end) end) diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua index 163ded43f9..cd1f43f9fd 100644 --- a/test/functional/ex_cmds/source_spec.lua +++ b/test/functional/ex_cmds/source_spec.lua @@ -166,6 +166,7 @@ describe(':source', function() vim.g.sourced_lua = 1 vim.g.sfile_value = vim.fn.expand('<sfile>') vim.g.stack_value = vim.fn.expand('<stack>') + vim.g.script_value = vim.fn.expand('<script>') ]]) command('set shellslash') @@ -173,6 +174,7 @@ describe(':source', function() eq(1, eval('g:sourced_lua')) matches([[/test%.lua$]], meths.get_var('sfile_value')) matches([[/test%.lua$]], meths.get_var('stack_value')) + matches([[/test%.lua$]], meths.get_var('script_value')) os.remove(test_file) end) @@ -214,6 +216,7 @@ describe(':source', function() "\ 2]=] vim.g.sfile_value = vim.fn.expand('<sfile>') vim.g.stack_value = vim.fn.expand('<stack>') + vim.g.script_value = vim.fn.expand('<script>') ]]) command('edit '..test_file) @@ -223,6 +226,7 @@ describe(':source', function() eq(' \\ 1\n "\\ 2', exec_lua('return _G.a')) eq(':source (no file)', meths.get_var('sfile_value')) eq(':source (no file)', meths.get_var('stack_value')) + eq(':source (no file)', meths.get_var('script_value')) os.remove(test_file) end) diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua index 4d984af41e..69404039ff 100644 --- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua +++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua @@ -1,8 +1,8 @@ local Screen = require('test.functional.ui.screen') local helpers = require('test.functional.helpers')(after_each) local lfs = require('lfs') -local eq, eval, expect, source = - helpers.eq, helpers.eval, helpers.expect, helpers.source +local eq, eval, expect, exec = + helpers.eq, helpers.eval, helpers.expect, helpers.exec local assert_alive = helpers.assert_alive local clear = helpers.clear local command = helpers.command @@ -10,6 +10,8 @@ local feed = helpers.feed local nvim_prog = helpers.nvim_prog local ok = helpers.ok local rmdir = helpers.rmdir +local new_argv = helpers.new_argv +local pesc = helpers.pesc local os_kill = helpers.os_kill local set_session = helpers.set_session local spawn = helpers.spawn @@ -55,11 +57,11 @@ describe(':preserve', function() set swapfile fileformat=unix undolevels=-1 ]] - source(init) + exec(init) command('edit! '..testfile) feed('isometext<esc>') command('preserve') - source('redir => g:swapname | silent swapname | redir END') + exec('redir => g:swapname | silent swapname | redir END') local swappath1 = eval('g:swapname') @@ -69,12 +71,12 @@ describe(':preserve', function() true) set_session(nvim2) - source(init) + exec(init) -- Use the "SwapExists" event to choose the (R)ecover choice at the dialog. command('autocmd SwapExists * let v:swapchoice = "r"') command('silent edit! '..testfile) - source('redir => g:swapname | silent swapname | redir END') + exec('redir => g:swapname | silent swapname | redir END') local swappath2 = eval('g:swapname') @@ -92,25 +94,28 @@ end) describe('swapfile detection', function() local swapdir = lfs.currentdir()..'/Xtest_swapdialog_dir' + local nvim0 + -- Put swapdir at the start of the 'directory' list. #1836 + -- Note: `set swapfile` *must* go after `set directory`: otherwise it may + -- attempt to create a swapfile in different directory. + local init = [[ + set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[// + set swapfile fileformat=unix undolevels=-1 hidden + ]] before_each(function() - clear() + nvim0 = spawn(new_argv()) + set_session(nvim0) rmdir(swapdir) lfs.mkdir(swapdir) end) after_each(function() + set_session(nvim0) command('%bwipeout!') rmdir(swapdir) end) it('always show swapfile dialog #8840 #9027', function() local testfile = 'Xtest_swapdialog_file1' - -- Put swapdir at the start of the 'directory' list. #1836 - -- Note: `set swapfile` *must* go after `set directory`: otherwise it may - -- attempt to create a swapfile in different directory. - local init = [[ - set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[// - set swapfile fileformat=unix undolevels=-1 hidden - ]] local expected_no_dialog = '^'..(' '):rep(256)..'|\n' for _=1,37 do @@ -119,19 +124,17 @@ describe('swapfile detection', function() expected_no_dialog = expected_no_dialog..testfile..(' '):rep(216)..'0,0-1 All|\n' expected_no_dialog = expected_no_dialog..(' '):rep(256)..'|\n' - source(init) + exec(init) command('edit! '..testfile) feed('isometext<esc>') command('preserve') - os_kill(eval('getpid()')) -- Start another Nvim instance. - local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'}, - true) + local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'}, true, nil, true) set_session(nvim2) local screen2 = Screen.new(256, 40) screen2:attach() - source(init) + exec(init) -- With shortmess+=F command('set shortmess+=F') @@ -176,5 +179,88 @@ describe('swapfile detection', function() } }) feed('<cr>') + + nvim2:close() + end) + + -- oldtest: Test_swap_prompt_splitwin() + it('selecting "q" in the attention prompt', function() + exec(init) + command('edit Xfile1') + command('preserve') -- should help to make sure the swap file exists + + local screen = Screen.new(75, 18) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg + }) + + local nvim1 = spawn(new_argv(), true, nil, true) + set_session(nvim1) + screen:attach() + exec(init) + feed(':split Xfile1\n') + screen:expect({ + any = pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^') + }) + feed('q') + feed(':<CR>') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + : | + ]]) + nvim1:close() + + local nvim2 = spawn(new_argv(), true, nil, true) + set_session(nvim2) + screen:attach() + exec(init) + command('set more') + command('au bufadd * let foo_w = wincol()') + feed(':e Xfile1<CR>') + screen:expect({any = pesc('{1:-- More --}^')}) + feed('<Space>') + screen:expect({ + any = pesc('{1:[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: }^') + }) + feed('q') + command([[echo 'hello']]) + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + hello | + ]]) + nvim2:close() end) end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 981cfc306e..93fb0f245e 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -761,6 +761,7 @@ function module.pending_c_parser(pending_fn) pending_fn 'no C parser, skipping' return true end + module.exec_lua [[vim._ts_remove_language 'c']] return false end diff --git a/test/functional/legacy/buffer_spec.lua b/test/functional/legacy/buffer_spec.lua new file mode 100644 index 0000000000..acaa9a51f1 --- /dev/null +++ b/test/functional/legacy/buffer_spec.lua @@ -0,0 +1,59 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear, source = helpers.clear, helpers.source +local call, eq, meths = helpers.call, helpers.eq, helpers.meths + +local function expected_empty() + eq({}, meths.get_vvar('errors')) +end + +describe('buffer', function() + before_each(function() + clear() + meths.ui_attach(80, 24, {}) + meths.set_option('hidden', false) + end) + + it('deleting a modified buffer with :confirm', function() + source([[ + func Test_bdel_with_confirm() + new + call setline(1, 'test') + call assert_fails('bdel', 'E89:') + call nvim_input('c') + confirm bdel + call assert_equal(2, winnr('$')) + call assert_equal(1, &modified) + call nvim_input('n') + confirm bdel + call assert_equal(1, winnr('$')) + endfunc + ]]) + call('Test_bdel_with_confirm') + expected_empty() + end) + + it('editing another buffer from a modified buffer with :confirm', function() + source([[ + func Test_goto_buf_with_confirm() + new Xfile + enew + call setline(1, 'test') + call assert_fails('b Xfile', 'E37:') + call nvim_input('c') + call assert_fails('confirm b Xfile', 'E37:') + call assert_equal(1, &modified) + call assert_equal('', @%) + call nvim_input('y') + call assert_fails('confirm b Xfile', 'E37:') + call assert_equal(1, &modified) + call assert_equal('', @%) + call nvim_input('n') + confirm b Xfile + call assert_equal('Xfile', @%) + close! + endfunc + ]]) + call('Test_goto_buf_with_confirm') + expected_empty() + end) +end) diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua index cf02636890..99d2d0f30e 100644 --- a/test/functional/legacy/cmdline_spec.lua +++ b/test/functional/legacy/cmdline_spec.lua @@ -1,9 +1,11 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear = helpers.clear +local command = helpers.command local feed = helpers.feed local feed_command = helpers.feed_command local exec = helpers.exec +local pesc = helpers.pesc describe('cmdline', function() before_each(clear) @@ -18,8 +20,6 @@ describe('cmdline', function() [3] = {reverse = true}; [4] = {bold = true, foreground = Screen.colors.Blue1}; } - -- TODO(bfredl): redraw with tabs is severly broken. fix it - feed_command [[ set display-=msgsep ]] feed_command([[call setline(1, range(30))]]) screen:expect([[ @@ -60,7 +60,7 @@ describe('cmdline', function() {4:~ }| | | - :tabnew | + | ]]} feed [[gt]] @@ -141,3 +141,81 @@ describe('cmdline', function() ]]) end) end) + +describe('cmdwin', function() + before_each(clear) + + -- oldtest: Test_cmdwin_interrupted() + it('still uses a new buffer when interrupting more prompt on open', function() + local screen = Screen.new(30, 16) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {bold = true, reverse = true}, -- StatusLine + [2] = {reverse = true}, -- StatusLineNC + [3] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg + [4] = {bold = true}, -- ModeMsg + }) + screen:attach() + command('set more') + command('autocmd WinNew * highlight') + feed('q:') + screen:expect({any = pesc('{3:-- More --}^')}) + feed('q') + screen:expect([[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {2:[No Name] }| + {0::}^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {1:[Command Line] }| + | + ]]) + feed([[aecho 'done']]) + screen:expect([[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {2:[No Name] }| + {0::}echo 'done'^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {1:[Command Line] }| + {4:-- INSERT --} | + ]]) + feed('<CR>') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + done | + ]]) + end) +end) diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index f9647f5b6a..4226bcebac 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -128,6 +128,28 @@ describe('vim.diagnostic', function() eq('Diagnostic #1', result[1].message) end) + it('removes diagnostics from the cache when a buffer is removed', function() + 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) + vim.api.nvim_buf_set_lines(other_bufnr, 0, 1, false, lines) + vim.cmd('bunload! ' .. other_bufnr) + + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + make_error('Diagnostic #2', 2, 1, 2, 1), + }) + vim.diagnostic.set(diagnostic_ns, other_bufnr, { + make_error('Diagnostic #3', 3, 1, 3, 1), + }) + vim.api.nvim_set_current_buf(other_bufnr) + vim.opt_local.buflisted = true + vim.cmd('bwipeout!') + return #vim.diagnostic.get() + ]]) + end) + it('resolves buffer number 0 to the current buffer', function() eq(2, exec_lua [[ vim.api.nvim_set_current_buf(diagnostic_bufnr) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 2b249b7a69..f2fb661b70 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2721,6 +2721,39 @@ describe('lua stdlib', function() ]] end) end) + + describe('vim.iconv', function() + it('can convert strings', function() + 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[[ + return {pcall(vim.iconv, 'hello')} + ]]) + + 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[[ + return vim.iconv('hello', 'foo', 'bar') + ]]) + end) + + it('can handle strings with NUL bytes', function() + 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) + end) describe('lua: builtin modules', function() diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index cd7415de90..fa731f6faf 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -3181,4 +3181,32 @@ describe('LSP', function() } end) end) + + describe('cmd', function() + it('can connect to lsp server via rpc.connect', function() + local result = exec_lua [[ + local uv = vim.loop + local server = uv.new_tcp() + local init = nil + server:bind('127.0.0.1', 0) + server:listen(127, function(err) + assert(not err, err) + local socket = uv.new_tcp() + server:accept(socket) + socket:read_start(require('vim.lsp.rpc').create_read_loop(function(body) + init = body + socket:close() + end)) + end) + local port = server:getsockname().port + vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }) + vim.wait(1000, function() return init ~= nil end) + assert(init, "server must receive `initialize` request") + server:close() + server:shutdown() + return vim.json.decode(init) + ]] + eq(result.method, "initialize") + end) + end) end) diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index c8da5a711f..9304aa6da9 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -6,6 +6,12 @@ local funcs = helpers.funcs local nvim_prog = helpers.nvim_prog local matches = helpers.matches +clear() +if funcs.executable('man') == 0 then + pending('missing "man" command', function() end) + return +end + describe(':Man', function() before_each(function() clear() diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 99f69ef556..4f444316c3 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -297,6 +297,199 @@ describe('TUI', function() ]], attrs) end) + it('accepts mouse wheel events #19992', function() + child_session:request('nvim_command', [[ + set number nostartofline nowrap mousescroll=hor:1,ver:1 + call setline(1, repeat([join(range(10), '----')], 10)) + vsplit + ]]) + screen:expect([[ + {11: 1 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----| + {11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----| + {11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----| + {11: 4 }0----1----2----3----4│{11: 4 }0----1----2----3----| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <ScrollWheelDown> in active window + feed_data('\027[<65;8;1M') + screen:expect([[ + {11: 2 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----| + {11: 3 }0----1----2----3----4│{11: 2 }0----1----2----3----| + {11: 4 }0----1----2----3----4│{11: 3 }0----1----2----3----| + {11: 5 }0----1----2----3----4│{11: 4 }0----1----2----3----| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <ScrollWheelDown> in inactive window + feed_data('\027[<65;48;1M') + screen:expect([[ + {11: 2 }{1:0}----1----2----3----4│{11: 2 }0----1----2----3----| + {11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----| + {11: 4 }0----1----2----3----4│{11: 4 }0----1----2----3----| + {11: 5 }0----1----2----3----4│{11: 5 }0----1----2----3----| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <ScrollWheelRight> in active window + feed_data('\027[<67;8;1M') + screen:expect([[ + {11: 2 }{1:-}---1----2----3----4-│{11: 2 }0----1----2----3----| + {11: 3 }----1----2----3----4-│{11: 3 }0----1----2----3----| + {11: 4 }----1----2----3----4-│{11: 4 }0----1----2----3----| + {11: 5 }----1----2----3----4-│{11: 5 }0----1----2----3----| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <ScrollWheelRight> in inactive window + feed_data('\027[<67;48;1M') + screen:expect([[ + {11: 2 }{1:-}---1----2----3----4-│{11: 2 }----1----2----3----4| + {11: 3 }----1----2----3----4-│{11: 3 }----1----2----3----4| + {11: 4 }----1----2----3----4-│{11: 4 }----1----2----3----4| + {11: 5 }----1----2----3----4-│{11: 5 }----1----2----3----4| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <S-ScrollWheelDown> in active window + feed_data('\027[<69;8;1M') + screen:expect([[ + {11: 5 }{1:-}---1----2----3----4-│{11: 2 }----1----2----3----4| + {11: 6 }----1----2----3----4-│{11: 3 }----1----2----3----4| + {11: 7 }----1----2----3----4-│{11: 4 }----1----2----3----4| + {11: 8 }----1----2----3----4-│{11: 5 }----1----2----3----4| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <S-ScrollWheelDown> in inactive window + feed_data('\027[<69;48;1M') + screen:expect([[ + {11: 5 }{1:-}---1----2----3----4-│{11: 5 }----1----2----3----4| + {11: 6 }----1----2----3----4-│{11: 6 }----1----2----3----4| + {11: 7 }----1----2----3----4-│{11: 7 }----1----2----3----4| + {11: 8 }----1----2----3----4-│{11: 8 }----1----2----3----4| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <S-ScrollWheelRight> in active window + feed_data('\027[<71;8;1M') + screen:expect([[ + {11: 5 }{1:-}---6----7----8----9 │{11: 5 }----1----2----3----4| + {11: 6 }----6----7----8----9 │{11: 6 }----1----2----3----4| + {11: 7 }----6----7----8----9 │{11: 7 }----1----2----3----4| + {11: 8 }----6----7----8----9 │{11: 8 }----1----2----3----4| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <S-ScrollWheelRight> in inactive window + feed_data('\027[<71;48;1M') + screen:expect([[ + {11: 5 }{1:-}---6----7----8----9 │{11: 5 }5----6----7----8----| + {11: 6 }----6----7----8----9 │{11: 6 }5----6----7----8----| + {11: 7 }----6----7----8----9 │{11: 7 }5----6----7----8----| + {11: 8 }----6----7----8----9 │{11: 8 }5----6----7----8----| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <ScrollWheelUp> in active window + feed_data('\027[<64;8;1M') + screen:expect([[ + {11: 4 }----6----7----8----9 │{11: 5 }5----6----7----8----| + {11: 5 }{1:-}---6----7----8----9 │{11: 6 }5----6----7----8----| + {11: 6 }----6----7----8----9 │{11: 7 }5----6----7----8----| + {11: 7 }----6----7----8----9 │{11: 8 }5----6----7----8----| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <ScrollWheelUp> in inactive window + feed_data('\027[<64;48;1M') + screen:expect([[ + {11: 4 }----6----7----8----9 │{11: 4 }5----6----7----8----| + {11: 5 }{1:-}---6----7----8----9 │{11: 5 }5----6----7----8----| + {11: 6 }----6----7----8----9 │{11: 6 }5----6----7----8----| + {11: 7 }----6----7----8----9 │{11: 7 }5----6----7----8----| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <ScrollWheelLeft> in active window + feed_data('\027[<66;8;1M') + screen:expect([[ + {11: 4 }5----6----7----8----9│{11: 4 }5----6----7----8----| + {11: 5 }5{1:-}---6----7----8----9│{11: 5 }5----6----7----8----| + {11: 6 }5----6----7----8----9│{11: 6 }5----6----7----8----| + {11: 7 }5----6----7----8----9│{11: 7 }5----6----7----8----| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <ScrollWheelLeft> in inactive window + feed_data('\027[<66;48;1M') + screen:expect([[ + {11: 4 }5----6----7----8----9│{11: 4 }-5----6----7----8---| + {11: 5 }5{1:-}---6----7----8----9│{11: 5 }-5----6----7----8---| + {11: 6 }5----6----7----8----9│{11: 6 }-5----6----7----8---| + {11: 7 }5----6----7----8----9│{11: 7 }-5----6----7----8---| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <S-ScrollWheelUp> in active window + feed_data('\027[<68;8;1M') + screen:expect([[ + {11: 1 }5----6----7----8----9│{11: 4 }-5----6----7----8---| + {11: 2 }5----6----7----8----9│{11: 5 }-5----6----7----8---| + {11: 3 }5----6----7----8----9│{11: 6 }-5----6----7----8---| + {11: 4 }5{1:-}---6----7----8----9│{11: 7 }-5----6----7----8---| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <S-ScrollWheelUp> in inactive window + feed_data('\027[<68;48;1M') + screen:expect([[ + {11: 1 }5----6----7----8----9│{11: 1 }-5----6----7----8---| + {11: 2 }5----6----7----8----9│{11: 2 }-5----6----7----8---| + {11: 3 }5----6----7----8----9│{11: 3 }-5----6----7----8---| + {11: 4 }5{1:-}---6----7----8----9│{11: 4 }-5----6----7----8---| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <S-ScrollWheelLeft> in active window + feed_data('\027[<70;8;1M') + screen:expect([[ + {11: 1 }0----1----2----3----4│{11: 1 }-5----6----7----8---| + {11: 2 }0----1----2----3----4│{11: 2 }-5----6----7----8---| + {11: 3 }0----1----2----3----4│{11: 3 }-5----6----7----8---| + {11: 4 }0----1----2----3----{1:4}│{11: 4 }-5----6----7----8---| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + -- <S-ScrollWheelLeft> in inactive window + feed_data('\027[<70;48;1M') + screen:expect([[ + {11: 1 }0----1----2----3----4│{11: 1 }0----1----2----3----| + {11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----| + {11: 3 }0----1----2----3----4│{11: 3 }0----1----2----3----| + {11: 4 }0----1----2----3----{1:4}│{11: 4 }0----1----2----3----| + {5:[No Name] [+] }{1:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + end) + it('accepts keypad keys from kitty keyboard protocol #19180', function() feed_data('i') feed_data(funcs.nr2char(57399)) -- KP_0 diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 5ec0a8a060..4b0bd1eb50 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -6,11 +6,14 @@ local insert = helpers.insert local exec_lua = helpers.exec_lua local feed = helpers.feed local pending_c_parser = helpers.pending_c_parser +local command = helpers.command +local meths = helpers.meths +local eq = helpers.eq before_each(clear) local hl_query = [[ - (ERROR) @ErrorMsg + (ERROR) @error "if" @keyword "else" @keyword @@ -23,23 +26,24 @@ local hl_query = [[ "enum" @type "extern" @type - (string_literal) @string.nonexistent-specializer-for-string.should-fallback-to-string + ; nonexistent specializer for string should fallback to string + (string_literal) @string.nonexistent_specializer (number_literal) @number (char_literal) @string (type_identifier) @type - ((type_identifier) @Special (#eq? @Special "LuaRef")) + ((type_identifier) @constant.builtin (#eq? @constant.builtin "LuaRef")) (primitive_type) @type (sized_type_specifier) @type ; Use lua regexes - ((identifier) @Identifier (#contains? @Identifier "lua_")) + ((identifier) @function (#contains? @function "lua_")) ((identifier) @Constant (#lua-match? @Constant "^[A-Z_]+$")) - ((identifier) @Normal (#vim-match? @Constant "^lstate$")) + ((identifier) @Normal (#vim-match? @Normal "^lstate$")) - ((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right) (#eq? @WarningMsg.left @WarningMsg.right)) + ((binary_expression left: (identifier) @warning.left right: (identifier) @warning.right) (#eq? @warning.left @warning.right)) (comment) @comment ]] @@ -103,6 +107,7 @@ describe('treesitter highlighting', function() } exec_lua([[ hl_query = ... ]], hl_query) + command [[ hi link @warning WarningMsg ]] end) it('is updated with edits', function() @@ -547,7 +552,7 @@ describe('treesitter highlighting', function() -- This will change ONLY the literal strings to look like comments -- The only literal string is the "vim.schedule: expected function" in this test. - exec_lua [[vim.cmd("highlight link cString comment")]] + exec_lua [[vim.cmd("highlight link @string.nonexistent_specializer comment")]] screen:expect{grid=[[ {2:/// Schedule Lua callback on main loop's event queue} | {3:static} {3:int} {11:nlua_schedule}({3:lua_State} *{3:const} lstate) | @@ -612,6 +617,11 @@ describe('treesitter highlighting', function() -- bold will not be overwritten at the moment [12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Grey100}; }} + + eq({ + {capture='Error', priority='101'}; + {capture='type'}; + }, exec_lua [[ return vim.treesitter.get_captures_at_position(0, 0, 2) ]]) end) it("allows to use captures with dots (don't use fallback when specialization of foo exists)", function() @@ -642,11 +652,13 @@ describe('treesitter highlighting', function() | ]]} + command [[ + hi link @foo.bar Type + hi link @foo String + ]] exec_lua [[ local parser = vim.treesitter.get_parser(0, "c", {}) local highlighter = vim.treesitter.highlighter - highlighter.hl_map['foo.bar'] = 'Type' - highlighter.hl_map['foo'] = 'String' test_hl = highlighter.new(parser, {queries = {c = "(primitive_type) @foo.bar (string_literal) @foo"}}) ]] @@ -670,6 +682,29 @@ describe('treesitter highlighting', function() {1:~ }| | ]]} + + -- clearing specialization reactivates fallback + command [[ hi clear @foo.bar ]] + screen:expect{grid=[[ + {5:char}* x = {5:"Will somebody ever read this?"}; | + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} end) it("supports conceal attribute", function() @@ -712,32 +747,26 @@ describe('treesitter highlighting', function() ]]} end) - it("hl_map has the correct fallback behavior", function() - exec_lua [[ - local hl_map = vim.treesitter.highlighter.hl_map - hl_map["foo"] = 1 - hl_map["foo.bar"] = 2 - hl_map["foo.bar.baz"] = 3 - - assert(hl_map["foo"] == 1) - assert(hl_map["foo.a.b.c.d"] == 1) - assert(hl_map["foo.bar"] == 2) - assert(hl_map["foo.bar.a.b.c.d"] == 2) - assert(hl_map["foo.bar.baz"] == 3) - assert(hl_map["foo.bar.baz.d"] == 3) - - hl_map["FOO"] = 1 - hl_map["FOO.BAR"] = 2 - assert(hl_map["FOO.BAR.BAZ"] == 2) - - hl_map["foo.missing.exists"] = 3 - assert(hl_map["foo.missing"] == 1) - assert(hl_map["foo.missing.exists"] == 3) - assert(hl_map["foo.missing.exists.bar"] == 3) - assert(hl_map["total.nonsense.but.a.lot.of.dots"] == nil) - -- It will not perform a second look up of this variable but return a sentinel value - assert(hl_map["total.nonsense.but.a.lot.of.dots"] == "__notfound") - ]] - + it("@foo.bar groups has the correct fallback behavior", function() + local get_hl = function(name) return meths.get_hl_by_name(name,1).foreground end + meths.set_hl(0, "@foo", {fg = 1}) + meths.set_hl(0, "@foo.bar", {fg = 2}) + meths.set_hl(0, "@foo.bar.baz", {fg = 3}) + + eq(1, get_hl"@foo") + eq(1, get_hl"@foo.a.b.c.d") + eq(2, get_hl"@foo.bar") + eq(2, get_hl"@foo.bar.a.b.c.d") + eq(3, get_hl"@foo.bar.baz") + eq(3, get_hl"@foo.bar.baz.d") + + -- lookup is case insensitive + eq(2, get_hl"@FOO.BAR.SPAM") + + meths.set_hl(0, "@foo.missing.exists", {fg = 3}) + eq(1, get_hl"@foo.missing") + eq(3, get_hl"@foo.missing.exists") + eq(3, get_hl"@foo.missing.exists.bar") + eq(nil, get_hl"@total.nonsense.but.a.lot.of.dots") end) end) diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 30585be328..8e9941d797 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -7,10 +7,11 @@ local exec_lua = helpers.exec_lua local pcall_err = helpers.pcall_err local matches = helpers.matches local pending_c_parser = helpers.pending_c_parser +local insert = helpers.insert before_each(clear) -describe('treesitter API', function() +describe('treesitter language API', function() -- error tests not requiring a parser library it('handles missing language', function() eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", @@ -26,6 +27,11 @@ describe('treesitter API', function() eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) + + if not pending_c_parser(pending) then + matches("Error executing lua: Failed to load parser: uv_dlsym: .+", + pcall_err(exec_lua, 'vim.treesitter.require_language("c", nil, false, "borklang")')) + end end) it('inspects language', function() @@ -79,5 +85,35 @@ describe('treesitter API', function() eq("Error executing lua: .../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0)")) end) + + it('retrieve the tree given a range', function () + if pending_c_parser(pending) then return end + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + langtree = vim.treesitter.get_parser(0, "c") + tree = langtree:tree_for_range({1, 3, 1, 3}) + ]]) + + eq('<node translation_unit>', exec_lua('return tostring(tree:root())')) + end) + + it('retrieve the node given a range', function () + if pending_c_parser(pending) then return end + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + langtree = vim.treesitter.get_parser(0, "c") + node = langtree:named_node_for_range({1, 3, 1, 3}) + ]]) + + eq('<node primitive_type>', exec_lua('return tostring(node)')) + end) end) diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua index 21c287644e..87ce1b973c 100644 --- a/test/functional/treesitter/node_spec.lua +++ b/test/functional/treesitter/node_spec.lua @@ -59,4 +59,53 @@ describe('treesitter node API', function() exec_lua 'node = node:prev_named_sibling()' eq('int x', lua_eval('node_text(node)')) end) + + it('can retrieve the children of a node', function() + insert([[ + int main() { + int x = 3; + }]]) + + local len = exec_lua([[ + tree = vim.treesitter.get_parser(0, "c"):parse()[1] + node = tree:root():child(0) + children = node:named_children() + + return #children + ]]) + + eq(3, len) + eq('<node compound_statement>', lua_eval('tostring(children[3])')) + end) + + it('can retrieve the tree root given a node', function() + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + tree = vim.treesitter.get_parser(0, "c"):parse()[1] + root = tree:root() + node = root:child(0):child(2) + ]]) + + eq(lua_eval('tostring(root)'), lua_eval('tostring(node:root())')) + end) + + it('can compute the byte length of a node', function() + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + tree = vim.treesitter.get_parser(0, "c"):parse()[1] + root = tree:root() + child = root:child(0):child(0) + ]]) + + eq(28, lua_eval('root:byte_length()')) + eq(3, lua_eval('child:byte_length()')) + end) end) diff --git a/test/functional/treesitter/utils_spec.lua b/test/functional/treesitter/utils_spec.lua new file mode 100644 index 0000000000..4f4c18a748 --- /dev/null +++ b/test/functional/treesitter/utils_spec.lua @@ -0,0 +1,33 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local insert = helpers.insert +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local pending_c_parser = helpers.pending_c_parser + +before_each(clear) + +describe('treesitter utils', function() + before_each(clear) + + it('can find an ancestor', function() + if pending_c_parser(pending) then return end + + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua([[ + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse()[1] + root = tree:root() + ancestor = root:child(0) + child = ancestor:child(0) + ]]) + + eq(true, exec_lua('return vim.treesitter.is_ancestor(ancestor, child)')) + eq(false, exec_lua('return vim.treesitter.is_ancestor(child, ancestor)')) + end) +end) diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 4e3d62509c..5ffe9ddaad 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -2333,6 +2333,51 @@ describe("'winhighlight' highlight", function() helpers.assert_alive() end) + + it('can redraw statusline on cursor movement', function() + screen:try_resize(40, 8) + exec [[ + set statusline=%f%=%#Background1#%l,%c%V\ %P + split + ]] + insert [[ + some text + more text]] + screen:expect{grid=[[ + some text | + more tex^t | + {0:~ }| + {3:[No Name] }{1:2,9 All}| + some text | + more text | + {4:[No Name] }{1:1,1 All}| + | + ]]} + + command 'set winhl=Background1:Background2' + screen:expect{grid=[[ + some text | + more tex^t | + {0:~ }| + {3:[No Name] }{5:2,9 All}| + some text | + more text | + {4:[No Name] }{1:1,1 All}| + | + ]]} + + feed 'k' + screen:expect{grid=[[ + some tex^t | + more text | + {0:~ }| + {3:[No Name] }{5:1,9 All}| + some text | + more text | + {4:[No Name] }{1:1,1 All}| + | + ]]} + end) end) describe('highlight namespaces', function() diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 2cff7c1cf4..522c9ccba2 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1077,10 +1077,10 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim ]]} end) - it('redraws NOT_VALID correctly after message', function() - -- edge case: only one window was set NOT_VALID. Original report + it('redraws UPD_NOT_VALID correctly after message', function() + -- edge case: only one window was set UPD_NOT_VALID. Original report -- used :make, but fake it using one command to set the current - -- window NOT_VALID and another to show a long message. + -- window UPD_NOT_VALID and another to show a long message. command("set more") feed(':new<cr><c-w><c-w>') screen:expect{grid=[[ diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index b30aa67fd3..78a1e8c677 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -3,7 +3,9 @@ local Screen = require('test.functional.ui.screen') local clear = helpers.clear local feed, command, insert = helpers.feed, helpers.command, helpers.insert local eq = helpers.eq +local funcs = helpers.funcs local meths = helpers.meths +local curwin = helpers.curwin local poke_eventloop = helpers.poke_eventloop @@ -871,6 +873,15 @@ describe('ext_multigrid', function() before_each(function() screen:try_resize_grid(2, 60, 20) end) + + it('winwidth() winheight() getwininfo() return inner width and height #19743', function() + eq(60, funcs.winwidth(0)) + eq(20, funcs.winheight(0)) + local win_info = funcs.getwininfo(curwin().id)[1] + eq(60, win_info.width) + eq(20, win_info.height) + end) + it('gets written till grid width', function() insert(('a'):rep(60).."\n") diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index e11cd1e859..dcd4ad3d9a 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1990,6 +1990,22 @@ describe('builtin popupmenu', function() efine unplace^ | ]]) + -- Pressing <Left> after that should move the cursor + feed('<Left>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {4: }| + :sign define jump list place und| + efine unplac^e | + ]]) + feed('<End>') + -- Pressing <C-D> when the popup menu is displayed should remove the popup -- menu feed('<C-U>sign <Tab><C-D>') diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 98398bc7a1..58ffa3bda8 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -461,20 +461,20 @@ end) describe('command line completion', function() local screen before_each(function() + clear() screen = Screen.new(40, 5) screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, [2] = {foreground = Screen.colors.Grey0, background = Screen.colors.Yellow}, [3] = {bold = true, reverse = true}, }) + screen:attach() end) after_each(function() os.remove('Xtest-functional-viml-compl-dir') end) it('lists directories with empty PATH', function() - clear() - screen:attach() local tmp = funcs.tempname() command('e '.. tmp) command('cd %:h') @@ -491,8 +491,6 @@ describe('command line completion', function() end) it('completes env var names #9681', function() - clear() - screen:attach() command('let $XTEST_1 = "foo" | let $XTEST_2 = "bar"') command('set wildmenu wildmode=full') feed(':!echo $XTEST_<tab>') @@ -521,6 +519,58 @@ describe('command line completion', function() :!echo $XTEST_1AaあB^ | ]]) end) + + it('does not leak memory with <S-Tab> with wildmenu and only one match #19874', function() + meths.set_option('wildmenu', true) + meths.set_option('wildmode', 'full') + meths.set_option('wildoptions', 'pum') + + feed(':sign unpla<S-Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplace^ | + ]]) + + feed('<Space>buff<Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplace buffer=^ | + ]]) + end) + + it('does not show matches with <S-Tab> without wildmenu with wildmode=full', function() + meths.set_option('wildmenu', false) + meths.set_option('wildmode', 'full') + + feed(':sign <S-Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplace^ | + ]]) + end) + + it('shows matches with <S-Tab> without wildmenu with wildmode=list', function() + meths.set_option('wildmenu', false) + meths.set_option('wildmode', 'list') + + feed(':sign <S-Tab>') + screen:expect([[ + {3: }| + :sign define | + define list undefine | + jump place unplace | + :sign unplace^ | + ]]) + end) end) describe('ui/ext_wildmenu', function() diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua index 8976c4371f..ece27ec3ff 100644 --- a/test/functional/ui/winbar_spec.lua +++ b/test/functional/ui/winbar_spec.lua @@ -7,6 +7,8 @@ local meths = helpers.meths local eq = helpers.eq local poke_eventloop = helpers.poke_eventloop local feed = helpers.feed +local funcs = helpers.funcs +local curwin = helpers.curwin local pcall_err = helpers.pcall_err describe('winbar', function() @@ -48,6 +50,11 @@ describe('winbar', function() {3:~ }| | ]]) + -- winbar is excluded from the heights returned by winheight() and getwininfo() + eq(11, funcs.winheight(0)) + local win_info = funcs.getwininfo(curwin().id)[1] + eq(11, win_info.height) + eq(1, win_info.winbar) end) it('works with custom \'fillchars\' value', function() diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua index 0c2ca8de78..d4fa7afe89 100644 --- a/test/functional/vimscript/eval_spec.lua +++ b/test/functional/vimscript/eval_spec.lua @@ -10,11 +10,13 @@ -- test/functional/vimscript/functions_spec.lua local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local lfs = require('lfs') local clear = helpers.clear local eq = helpers.eq local exc_exec = helpers.exc_exec +local exec = helpers.exec local eval = helpers.eval local command = helpers.command local write_file = helpers.write_file @@ -144,3 +146,104 @@ describe('List support code', function() end end) end) + +-- oldtest: Test_deep_nest() +it('Error when if/for/while/try/function is nested too deep',function() + clear() + local screen = Screen.new(80, 24) + screen:attach() + meths.set_option('laststatus', 2) + exec([[ + " Deep nesting of if ... endif + func Test1() + let @a = join(repeat(['if v:true'], 51), "\n") + let @a ..= "\n" + let @a ..= join(repeat(['endif'], 51), "\n") + @a + let @a = '' + endfunc + + " Deep nesting of for ... endfor + func Test2() + let @a = join(repeat(['for i in [1]'], 51), "\n") + let @a ..= "\n" + let @a ..= join(repeat(['endfor'], 51), "\n") + @a + let @a = '' + endfunc + + " Deep nesting of while ... endwhile + func Test3() + let @a = join(repeat(['while v:true'], 51), "\n") + let @a ..= "\n" + let @a ..= join(repeat(['endwhile'], 51), "\n") + @a + let @a = '' + endfunc + + " Deep nesting of try ... endtry + func Test4() + let @a = join(repeat(['try'], 51), "\n") + let @a ..= "\necho v:true\n" + let @a ..= join(repeat(['endtry'], 51), "\n") + @a + let @a = '' + endfunc + + " Deep nesting of function ... endfunction + func Test5() + let @a = join(repeat(['function X()'], 51), "\n") + let @a ..= "\necho v:true\n" + let @a ..= join(repeat(['endfunction'], 51), "\n") + @a + let @a = '' + endfunc + ]]) + screen:expect({any = '%[No Name%]'}) + feed(':call Test1()<CR>') + screen:expect({any = 'E579: '}) + feed('<C-C>') + screen:expect({any = '%[No Name%]'}) + feed(':call Test2()<CR>') + screen:expect({any = 'E585: '}) + feed('<C-C>') + screen:expect({any = '%[No Name%]'}) + feed(':call Test3()<CR>') + screen:expect({any = 'E585: '}) + feed('<C-C>') + screen:expect({any = '%[No Name%]'}) + feed(':call Test4()<CR>') + screen:expect({any = 'E601: '}) + feed('<C-C>') + screen:expect({any = '%[No Name%]'}) + feed(':call Test5()<CR>') + screen:expect({any = 'E1058: '}) +end) + +describe("uncaught exception", function() + before_each(clear) + after_each(function() + os.remove('throw1.vim') + os.remove('throw2.vim') + os.remove('throw3.vim') + end) + + it('is not forgotten #13490', function() + command('autocmd BufWinEnter * throw "i am error"') + eq('i am error', exc_exec('try | new | endtry')) + + -- Like Vim, throwing here aborts the processing of the script, but does not stop :runtime! + -- from processing the others. + -- Only the first thrown exception should be rethrown from the :try below, though. + for i = 1, 3 do + write_file('throw' .. i .. '.vim', ([[ + let result ..= '%d' + throw 'throw%d' + let result ..= 'X' + ]]):format(i, i)) + end + command('set runtimepath+=. | let result = ""') + eq('throw1', exc_exec('try | runtime! throw*.vim | endtry')) + eq('123', eval('result')) + end) +end) diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua index 554d15e550..f50b39c2c5 100644 --- a/test/functional/vimscript/input_spec.lua +++ b/test/functional/vimscript/input_spec.lua @@ -8,7 +8,8 @@ local clear = helpers.clear local source = helpers.source local command = helpers.command local exc_exec = helpers.exc_exec -local nvim_async = helpers.nvim_async +local pcall_err = helpers.pcall_err +local async_meths = helpers.async_meths local NIL = helpers.NIL local screen @@ -449,6 +450,78 @@ describe('inputdialog()', function() end) describe('confirm()', function() + -- oldtest: Test_confirm() + it('works', function() + meths.set_option('more', false) -- Avoid hit-enter prompt + meths.set_option('laststatus', 2) + -- screen:expect() calls are needed to avoid feeding input too early + screen:expect({any = '%[No Name%]'}) + + async_meths.command([[let a = confirm('Press O to proceed')]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('o') + screen:expect({any = '%[No Name%]'}) + eq(1, meths.get_var('a')) + + async_meths.command([[let a = 'Are you sure?'->confirm("&Yes\n&No")]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('y') + screen:expect({any = '%[No Name%]'}) + eq(1, meths.get_var('a')) + + async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('n') + screen:expect({any = '%[No Name%]'}) + eq(2, meths.get_var('a')) + + -- Not possible to match Vim's CTRL-C test here as CTRL-C always sets got_int in Nvim. + + -- confirm() should return 0 when pressing ESC. + async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('<Esc>') + screen:expect({any = '%[No Name%]'}) + eq(0, meths.get_var('a')) + + -- Default choice is returned when pressing <CR>. + async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No")]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('<CR>') + screen:expect({any = '%[No Name%]'}) + eq(1, meths.get_var('a')) + + async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No", 2)]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('<CR>') + screen:expect({any = '%[No Name%]'}) + eq(2, meths.get_var('a')) + + async_meths.command([[let a = confirm('Are you sure?', "&Yes\n&No", 0)]]) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('<CR>') + screen:expect({any = '%[No Name%]'}) + eq(0, meths.get_var('a')) + + -- Test with the {type} 4th argument + for _, type in ipairs({'Error', 'Question', 'Info', 'Warning', 'Generic'}) do + async_meths.command(([[let a = confirm('Are you sure?', "&Yes\n&No", 1, '%s')]]):format(type)) + screen:expect({any = '{CONFIRM:.+: }'}) + feed('y') + screen:expect({any = '%[No Name%]'}) + eq(1, meths.get_var('a')) + end + + eq('Vim(call):E730: using List as a String', + pcall_err(command, 'call confirm([])')) + eq('Vim(call):E730: using List as a String', + pcall_err(command, 'call confirm("Are you sure?", [])')) + eq('Vim(call):E745: Using a List as a Number', + pcall_err(command, 'call confirm("Are you sure?", "&Yes\n&No\n", [])')) + eq('Vim(call):E730: using List as a String', + pcall_err(command, 'call confirm("Are you sure?", "&Yes\n&No\n", 0, [])')) + end) + it("shows dialog even if :silent #8788", function() command("autocmd BufNewFile * call confirm('test')") @@ -483,7 +556,7 @@ describe('confirm()', function() feed(':call nvim_command("edit x")<cr>') check_and_clear(':call nvim_command("edit |\n') - nvim_async('command', 'edit x') + async_meths.command('edit x') check_and_clear(' |\n') end) end) |