diff options
Diffstat (limited to 'test')
31 files changed, 1161 insertions, 164 deletions
diff --git a/test/compat.lua b/test/compat.lua new file mode 100644 index 0000000000..2c9786d491 --- /dev/null +++ b/test/compat.lua @@ -0,0 +1,12 @@ +-- Lua 5.1 forward-compatibility layer. +-- For background see https://github.com/neovim/neovim/pull/9280 +-- +-- Reference the lua-compat-5.2 project for hints: +-- https://github.com/keplerproject/lua-compat-5.2/blob/c164c8f339b95451b572d6b4b4d11e944dc7169d/compat52/mstrict.lua +-- https://github.com/keplerproject/lua-compat-5.2/blob/c164c8f339b95451b572d6b4b4d11e944dc7169d/tests/test.lua + +local lua_version = _VERSION:sub(-3) + +if lua_version >= '5.2' then + unpack = table.unpack -- luacheck: ignore 121 143 +end diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index 1c00f001ff..1c554b05a3 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -7,6 +7,7 @@ local exec_lua = helpers.exec_lua local retry = helpers.retry local isCI = helpers.isCI local assert_alive = helpers.assert_alive +local uname = helpers.uname describe('notify', function() local channel @@ -78,6 +79,9 @@ describe('notify', function() end) it('cancels stale events on channel close', function() + if uname() == 'freebsd' then + pending('Failing FreeBSD test') + end if isCI() then pending('hangs on CI #14083 #15251') return diff --git a/test/functional/autocmd/cursorhold_spec.lua b/test/functional/autocmd/cursorhold_spec.lua index 506b688853..b04bd5233a 100644 --- a/test/functional/autocmd/cursorhold_spec.lua +++ b/test/functional/autocmd/cursorhold_spec.lua @@ -2,30 +2,82 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq -local eval = helpers.eval local feed = helpers.feed local retry = helpers.retry -local source = helpers.source +local exec = helpers.source local sleep = helpers.sleep +local meths = helpers.meths -describe('CursorHoldI', function() - before_each(clear) +before_each(clear) + +describe('CursorHold', function() + before_each(function() + exec([[ + let g:cursorhold = 0 + augroup test + au CursorHold * let g:cursorhold += 1 + augroup END + ]]) + end) + + it('is triggered correctly #12587', function() + local function test_cursorhold(fn, early) + local ut = 2 + -- if testing with small 'updatetime' fails, double its value and test again + retry(10, nil, function() + ut = ut * 2 + meths.set_option('updatetime', ut) + feed('0') -- reset did_cursorhold + meths.set_var('cursorhold', 0) + sleep(ut / 4) + fn() + eq(0, meths.get_var('cursorhold')) + sleep(ut / 2) + fn() + eq(0, meths.get_var('cursorhold')) + sleep(ut / 2) + eq(early, meths.get_var('cursorhold')) + sleep(ut / 4 * 3) + eq(1, meths.get_var('cursorhold')) + end) + end + local ignore_key = meths.replace_termcodes('<Ignore>', true, true, true) + test_cursorhold(function() end, 1) + test_cursorhold(function() feed('') end, 1) + test_cursorhold(function() meths.feedkeys('', 'n', true) end, 1) + test_cursorhold(function() feed('<Ignore>') end, 0) + test_cursorhold(function() meths.feedkeys(ignore_key, 'n', true) end, 0) + end) + + it("reducing 'updatetime' while waiting for CursorHold #20241", function() + meths.set_option('updatetime', 10000) + feed('0') -- reset did_cursorhold + meths.set_var('cursorhold', 0) + sleep(50) + eq(0, meths.get_var('cursorhold')) + meths.set_option('updatetime', 20) + sleep(10) + eq(1, meths.get_var('cursorhold')) + end) +end) + +describe('CursorHoldI', function() -- NOTE: since this test uses RPC it is not necessary to trigger the initial -- issue (#3757) via timer's or RPC callbacks in the first place. it('is triggered after input', function() - source([[ - set updatetime=1 + exec([[ + set updatetime=1 - let g:cursorhold = 0 - augroup test - au CursorHoldI * let g:cursorhold += 1 - augroup END + let g:cursorhold = 0 + augroup test + au CursorHoldI * let g:cursorhold += 1 + augroup END ]]) feed('ifoo') retry(5, nil, function() sleep(1) - eq(1, eval('g:cursorhold')) + eq(1, meths.get_var('cursorhold')) end) end) end) diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index a4d22685e8..e71131dcf8 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -23,6 +23,7 @@ local iswin = helpers.iswin local assert_alive = helpers.assert_alive local expect_exit = helpers.expect_exit local write_file = helpers.write_file +local uname = helpers.uname describe('fileio', function() before_each(function() @@ -83,6 +84,9 @@ describe('fileio', function() end) it('backup #9709', function() + if uname() == 'freebsd' then + pending('Failing FreeBSD test') + end clear({ args={ '-i', 'Xtest_startup_shada', '--cmd', 'set directory=Xtest_startup_swapdir' } }) @@ -102,6 +106,9 @@ describe('fileio', function() end) it('backup with full path #11214', function() + if uname() == 'freebsd' then + pending('Failing FreeBSD test') + end clear() mkdir('Xtest_backupdir') command('set backup') diff --git a/test/functional/core/remote_spec.lua b/test/functional/core/remote_spec.lua index d7bd075eb2..846d79abf3 100644 --- a/test/functional/core/remote_spec.lua +++ b/test/functional/core/remote_spec.lua @@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local command = helpers.command local eq = helpers.eq +local exec_lua = helpers.exec_lua local expect = helpers.expect local funcs = helpers.funcs local insert = helpers.insert @@ -48,8 +49,8 @@ describe('Remote', function() -- our incoming --remote calls. local client_starter = spawn(new_argv(), false, nil, true) set_session(client_starter) - local client_job_id = funcs.jobstart(client_argv) - eq({ 0 }, funcs.jobwait({client_job_id})) + -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness. + eq({ 0 }, exec_lua([[return vim.fn.jobwait({ vim.fn.jobstart(...) })]], client_argv)) client_starter:close() set_session(server) end @@ -121,8 +122,8 @@ describe('Remote', function() -- the event loop. If the server event loop is blocked, it can't process -- our incoming --remote calls. clear() - local bogus_job_id = funcs.jobstart(bogus_argv) - eq({2}, funcs.jobwait({bogus_job_id})) + -- Call jobstart() and jobwait() in the same RPC request to reduce flakiness. + eq({ 2 }, exec_lua([[return vim.fn.jobwait({ vim.fn.jobstart(...) })]], bogus_argv)) end it('bogus subcommand', function() run_and_check_exit_code('--remote-bogus') diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua index 32fe397c03..14035a4341 100644 --- a/test/functional/ex_cmds/write_spec.lua +++ b/test/functional/ex_cmds/write_spec.lua @@ -9,6 +9,7 @@ local feed_command = helpers.feed_command local funcs = helpers.funcs local meths = helpers.meths local iswin = helpers.iswin +local uname = helpers.uname local fname = 'Xtest-functional-ex_cmds-write' local fname_bak = fname .. '~' @@ -52,6 +53,9 @@ describe(':write', function() end) it('&backupcopy=no replaces symlink with new file', function() + if uname() == 'freebsd' then + pending('Failing FreeBSD test') + end command('set backupcopy=no') write_file('test_bkc_file.txt', 'content0') if iswin() then @@ -91,6 +95,9 @@ describe(':write', function() end) it('errors out correctly', function() + if uname() == 'freebsd' then + pending('Failing FreeBSD test') + end command('let $HOME=""') eq(funcs.fnamemodify('.', ':p:h'), funcs.fnamemodify('.', ':p:h:~')) -- Message from check_overwrite diff --git a/test/functional/fixtures/printenv-test.c b/test/functional/fixtures/printenv-test.c index 0e68129543..295b4f04c3 100644 --- a/test/functional/fixtures/printenv-test.c +++ b/test/functional/fixtures/printenv-test.c @@ -3,13 +3,13 @@ #include <stdio.h> -#ifdef WIN32 +#ifdef MSWIN # include <windows.h> #else # include <stdlib.h> #endif -#ifdef WIN32 +#ifdef MSWIN int wmain(int argc, wchar_t **argv) #else int main(int argc, char **argv) @@ -19,7 +19,7 @@ int main(int argc, char **argv) return 1; } -#ifdef WIN32 +#ifdef MSWIN wchar_t *value = _wgetenv(argv[1]); if (value == NULL) { return 1; diff --git a/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua b/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua index a312572c5b..45226ce24b 100644 --- a/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua +++ b/test/functional/fixtures/start/nvim-leftpad/lua/async_leftpad.lua @@ -1,3 +1,5 @@ return function (val, res) - vim.loop.new_async(function() _G[res] = require'leftpad'(val) end):send() + local handle + handle = vim.loop.new_async(function() _G[res] = require'leftpad'(val) handle:close() end) + handle:send() end diff --git a/test/functional/fixtures/tty-test.c b/test/functional/fixtures/tty-test.c index 4438b73a22..6ee7715021 100644 --- a/test/functional/fixtures/tty-test.c +++ b/test/functional/fixtures/tty-test.c @@ -5,7 +5,7 @@ #include <stdio.h> #include <stdlib.h> #include <uv.h> -#ifdef _WIN32 +#ifdef MSWIN # include <windows.h> #else # include <unistd.h> @@ -23,7 +23,7 @@ uv_tty_t tty_out; bool owns_tty(void); // silence -Wmissing-prototypes bool owns_tty(void) { -#ifdef _WIN32 +#ifdef MSWIN // XXX: We need to make proper detect owns tty // HWND consoleWnd = GetConsoleWindow(); // DWORD dwProcessId; @@ -38,14 +38,14 @@ bool owns_tty(void) static void walk_cb(uv_handle_t *handle, void *arg) { if (!uv_is_closing(handle)) { -#ifdef WIN32 +#ifdef MSWIN uv_tty_set_mode(&tty, UV_TTY_MODE_NORMAL); #endif uv_close(handle, NULL); } } -#ifndef WIN32 +#ifndef MSWIN static void sig_handler(int signum) { switch (signum) { @@ -64,7 +64,7 @@ static void sig_handler(int signum) } #endif -#ifdef WIN32 +#ifdef MSWIN static void sigwinch_cb(uv_signal_t *handle, int signum) { int width, height; @@ -102,7 +102,7 @@ static void read_cb(uv_stream_t *stream, ssize_t cnt, const uv_buf_t *buf) uv_write_t req; uv_buf_t b = { .base = buf->base, -#ifdef WIN32 +#ifdef MSWIN .len = (ULONG)cnt #else .len = (size_t)cnt @@ -171,7 +171,7 @@ int main(int argc, char **argv) uv_prepare_t prepare; uv_prepare_init(uv_default_loop(), &prepare); uv_prepare_start(&prepare, prepare_cb); -#ifndef WIN32 +#ifndef MSWIN uv_tty_init(uv_default_loop(), &tty, fileno(stderr), 1); #else uv_tty_init(uv_default_loop(), &tty, fileno(stdin), 1); @@ -182,7 +182,7 @@ int main(int argc, char **argv) uv_tty_set_mode(&tty, UV_TTY_MODE_RAW); tty.data = &interrupted; uv_read_start(STRUCT_CAST(uv_stream_t, &tty), alloc_cb, read_cb); -#ifndef WIN32 +#ifndef MSWIN struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; @@ -196,7 +196,7 @@ int main(int argc, char **argv) #endif uv_run(uv_default_loop(), UV_RUN_DEFAULT); -#ifndef WIN32 +#ifndef MSWIN // XXX: Without this the SIGHUP handler is skipped on some systems. sleep(100); #endif diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index d672037a1e..eff54b6d4a 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -380,10 +380,23 @@ local function remove_args(args, args_rm) return new_args end +function module.check_close(old_session) + local start_time = luv.now() + old_session:close() + luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()). + local end_time = luv.now() + local delta = end_time - start_time + if delta > 500 then + print("nvim took " .. delta .. " milliseconds to exit after last test\n".. + "This indicates a likely problem with the test even if it passed!\n") + io.stdout:flush() + end +end + --- @param io_extra used for stdin_fd, see :help ui-option function module.spawn(argv, merge, env, keep, io_extra) if session and not keep then - session:close() + module.check_close(session) end local child_stream = ChildProcessStream.spawn( diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua index 99d2d0f30e..49e3825693 100644 --- a/test/functional/legacy/cmdline_spec.lua +++ b/test/functional/legacy/cmdline_spec.lua @@ -140,6 +140,115 @@ describe('cmdline', function() :^ | ]]) end) + + -- oldtest: Test_redraw_in_autocmd() + it('cmdline cursor position is correct after :redraw with cmdheight=2', function() + local screen = Screen.new(30, 6) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + }) + screen:attach() + exec([[ + set cmdheight=2 + autocmd CmdlineChanged * redraw + ]]) + feed(':for i in range(3)<CR>') + screen:expect([[ + | + {0:~ }| + {0:~ }| + {0:~ }| + :for i in range(3) | + : ^ | + ]]) + feed(':let i =') + -- Note: this may still be considered broken, ref #18140 + screen:expect([[ + | + {0:~ }| + {0:~ }| + {0:~ }| + : :let i =^ | + | + ]]) + end) + + -- oldtest: Test_redrawstatus_in_autocmd() + it(':redrawstatus in cmdline mode', function() + local screen = Screen.new(60, 8) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {bold = true, reverse = true}, -- MsgSeparator, StatusLine + }) + screen:attach() + exec([[ + set laststatus=2 + set statusline=%=:%{getcmdline()} + autocmd CmdlineChanged * redrawstatus + set display-=msgsep + ]]) + -- :redrawstatus is postponed if messages have scrolled + feed([[:echo "one\ntwo\nthree\nfour"<CR>]]) + feed(':foobar') + screen:expect([[ + {0:~ }| + {0:~ }| + {1: :echo "one\ntwo\nthree\nfour"}| + one | + two | + three | + four | + :foobar^ | + ]]) + -- it is not postponed if messages have not scrolled + feed('<Esc>:for in in range(3)') + screen:expect([[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {1: :for in in range(3)}| + :for in in range(3)^ | + ]]) + -- with cmdheight=1 messages have scrolled when typing :endfor + feed('<CR>:endfor') + screen:expect([[ + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {1: :for in in range(3)}| + :for in in range(3) | + : :endfor^ | + ]]) + feed('<CR>:set cmdheight=2<CR>') + -- with cmdheight=2 messages haven't scrolled when typing :for or :endfor + feed(':for in in range(3)') + screen:expect([[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {1: :for in in range(3)}| + :for in in range(3)^ | + | + ]]) + feed('<CR>:endfor') + screen:expect([[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {1: ::endfor}| + :for in in range(3) | + : :endfor^ | + ]]) + end) end) describe('cmdwin', function() diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua index 159cf7a551..c76ce62ef0 100644 --- a/test/functional/legacy/messages_spec.lua +++ b/test/functional/legacy/messages_spec.lua @@ -10,6 +10,43 @@ before_each(clear) describe('messages', function() local screen + -- oldtest: Test_warning_scroll() + it('a warning causes scrolling if and only if it has a stacktrace', function() + screen = Screen.new(75, 6) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg + [2] = {bold = true, reverse = true}, -- MsgSeparator + [3] = {foreground = Screen.colors.Red}, -- WarningMsg + }) + screen:attach() + + -- When the warning comes from a script, messages are scrolled so that the + -- stacktrace is visible. + -- It is a bit hard to assert the screen when sourcing a script, so skip this part. + + -- When the warning does not come from a script, messages are not scrolled. + command('enew') + command('set readonly') + feed('u') + screen:expect({grid = [[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:W10: Warning: Changing a readonly file}^ | + ]], timeout = 500}) + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + Already at oldest change | + ]]) + end) + describe('more prompt', function() before_each(function() screen = Screen.new(75, 6) diff --git a/test/functional/legacy/080_substitute_spec.lua b/test/functional/legacy/substitute_spec.lua index faeb61e3af..f3ce343680 100644 --- a/test/functional/legacy/080_substitute_spec.lua +++ b/test/functional/legacy/substitute_spec.lua @@ -3,11 +3,13 @@ -- Test for *:s%* on :substitute. local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local feed, insert = helpers.feed, helpers.insert +local exec = helpers.exec local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers.expect local eq, eval = helpers.eq, helpers.eval -describe('substitue()', function() +describe('substitute()', function() before_each(clear) -- The original test contained several TEST_X lines to delimit different @@ -132,7 +134,7 @@ describe('substitue()', function() end) end) -describe(':substitue', function() +describe(':substitute', function() before_each(clear) it('with \\ze and \\zs and confirmation dialog (TEST_8)', function() @@ -159,4 +161,29 @@ describe(':substitue', function() feed('yyq') -- For the dialog of the previous :s command. expect('XXx') end) + + it('first char is highlighted with confirmation dialog and empty match', function() + local screen = Screen.new(60, 8) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {reverse = true}, -- IncSearch + [2] = {bold = true, foreground = Screen.colors.SeaGreen}, -- MoreMsg + }) + screen:attach() + exec([[ + set nohlsearch noincsearch + call setline(1, ['one', 'two', 'three']) + ]]) + feed(':%s/^/ /c<CR>') + screen:expect([[ + {1:o}ne | + two | + three | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {2:replace with (y/n/a/q/l/^E/^Y)?}^ | + ]]) + end) end) diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 1514dadca8..28a8679205 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -1983,19 +1983,26 @@ end) end) it('triggers the autocommand when diagnostics are set', function() - eq(true, exec_lua [[ + eq({true, true}, exec_lua [[ -- Set a different buffer as current to test that <abuf> is being set properly in -- DiagnosticChanged callbacks local tmp = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_current_buf(tmp) - vim.g.diagnostic_autocmd_triggered = 0 - vim.cmd('autocmd DiagnosticChanged * let g:diagnostic_autocmd_triggered = +expand("<abuf>")') + local triggered = {} + vim.api.nvim_create_autocmd('DiagnosticChanged', { + callback = function(args) + triggered = {args.buf, #args.data.diagnostics} + end, + }) vim.api.nvim_buf_set_name(diagnostic_bufnr, "test | test") vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error('Diagnostic', 0, 0, 0, 0) }) - return vim.g.diagnostic_autocmd_triggered == diagnostic_bufnr + return { + triggered[1] == diagnostic_bufnr, + triggered[2] == 1, + } ]]) end) diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 2bcc84db0f..3123ec324c 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -78,6 +78,23 @@ describe('vim.fs', function() return vim.fs.find(nvim, { path = dir, type = 'file' }) ]], test_build_dir, nvim_prog_basename)) end) + + it('accepts predicate as names', function() + eq({test_build_dir}, exec_lua([[ + local dir = ... + local opts = { path = dir, upward = true, type = 'directory' } + return vim.fs.find(function(x) return x == 'build' end, opts) + ]], nvim_dir)) + eq({nvim_prog}, exec_lua([[ + local dir, nvim = ... + return vim.fs.find(function(x) return x == nvim end, { path = dir, type = 'file' }) + ]], test_build_dir, nvim_prog_basename)) + eq({}, exec_lua([[ + local dir = ... + local opts = { path = dir, upward = true, type = 'directory' } + return vim.fs.find(function(x) return x == 'no-match' end, opts) + ]], nvim_dir)) + end) end) describe('normalize()', function() diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 294222ad13..57ffcf7b4e 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -105,4 +105,16 @@ describe('vim.ui_attach', function() } end) + + it('does not crash on exit', function() + helpers.funcs.system({ + helpers.nvim_prog, + '-u', 'NONE', + '-i', 'NONE', + '--cmd', [[ lua ns = vim.api.nvim_create_namespace 'testspace' ]], + '--cmd', [[ lua vim.ui_attach(ns, {ext_popupmenu=true}, function() end) ]], + '--cmd', 'quitall!', + }) + eq(0, helpers.eval('v:shell_error')) + end) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 2466e9cc31..3184f01ef4 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -158,17 +158,20 @@ describe('lua stdlib', function() end) it("vim.str_utfindex/str_byteindex", function() - exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]]) - local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48} - local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48} + exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ\000ъ"]]) + local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48,49,51} + local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48,49,51} for i,k in pairs(indicies32) do eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i) end for i,k in pairs(indicies16) do eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i) end + matches(": index out of range$", pcall_err(exec_lua, "return vim.str_byteindex(_G.test_text, ...)", #indicies32 + 1)) + matches(": index out of range$", pcall_err(exec_lua, "return vim.str_byteindex(_G.test_text, ..., true)", #indicies16 + 1)) local i32, i16 = 0, 0 - for k = 0,48 do + local len = 51 + for k = 0,len do if indicies32[i32] < k then i32 = i32 + 1 end @@ -180,6 +183,7 @@ describe('lua stdlib', function() end eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k) end + matches(": index out of range$", pcall_err(exec_lua, "return vim.str_utfindex(_G.test_text, ...)", len + 1)) end) it("vim.str_utf_start", function() @@ -788,6 +792,11 @@ describe('lua stdlib', function() local x = vim.fn.VarArg(function() return 'foo' end, function() return 'bar' end) return #x == 2 and x[1]() == 'foo' and x[2]() == 'bar' ]])) + + -- Test for #20211 + eq('a (b) c', exec_lua([[ + return vim.fn.substitute('a b c', 'b', function(m) return '(' .. m[1] .. ')' end, 'g') + ]])) end) it('vim.fn should error when calling API function', function() @@ -1029,6 +1038,7 @@ describe('lua stdlib', function() vim.g.AddCounter = add_counter vim.g.GetCounter = get_counter vim.g.funcs = {add = add_counter, get = get_counter} + vim.g.AddParens = function(s) return '(' .. s .. ')' end ]] eq(0, eval('g:GetCounter()')) @@ -1044,6 +1054,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.g.funcs.get()]])) exec_lua([[vim.api.nvim_get_var('funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]])) + eq('((foo))', eval([['foo'->AddParens()->AddParens()]])) exec_lua [[ local counter = 0 @@ -1052,6 +1063,7 @@ describe('lua stdlib', function() vim.api.nvim_set_var('AddCounter', add_counter) vim.api.nvim_set_var('GetCounter', get_counter) vim.api.nvim_set_var('funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_set_var('AddParens', function(s) return '(' .. s .. ')' end) ]] eq(0, eval('g:GetCounter()')) @@ -1067,6 +1079,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.g.funcs.get()]])) exec_lua([[vim.api.nvim_get_var('funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]])) + eq('((foo))', eval([['foo'->AddParens()->AddParens()]])) exec([[ function Test() @@ -1133,6 +1146,7 @@ describe('lua stdlib', function() vim.b.AddCounter = add_counter vim.b.GetCounter = get_counter vim.b.funcs = {add = add_counter, get = get_counter} + vim.b.AddParens = function(s) return '(' .. s .. ')' end ]] eq(0, eval('b:GetCounter()')) @@ -1148,6 +1162,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.b.funcs.get()]])) exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]])) exec_lua [[ local counter = 0 @@ -1156,6 +1171,7 @@ describe('lua stdlib', function() vim.api.nvim_buf_set_var(0, 'AddCounter', add_counter) vim.api.nvim_buf_set_var(0, 'GetCounter', get_counter) vim.api.nvim_buf_set_var(0, 'funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_buf_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) ]] eq(0, eval('b:GetCounter()')) @@ -1171,6 +1187,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.b.funcs.get()]])) exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]])) exec([[ function Test() @@ -1227,6 +1244,7 @@ describe('lua stdlib', function() vim.w.AddCounter = add_counter vim.w.GetCounter = get_counter vim.w.funcs = {add = add_counter, get = get_counter} + vim.w.AddParens = function(s) return '(' .. s .. ')' end ]] eq(0, eval('w:GetCounter()')) @@ -1242,6 +1260,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.w.funcs.get()]])) exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]])) exec_lua [[ local counter = 0 @@ -1250,6 +1269,7 @@ describe('lua stdlib', function() vim.api.nvim_win_set_var(0, 'AddCounter', add_counter) vim.api.nvim_win_set_var(0, 'GetCounter', get_counter) vim.api.nvim_win_set_var(0, 'funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_win_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) ]] eq(0, eval('w:GetCounter()')) @@ -1265,6 +1285,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.w.funcs.get()]])) exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]])) exec([[ function Test() @@ -1316,6 +1337,7 @@ describe('lua stdlib', function() vim.t.AddCounter = add_counter vim.t.GetCounter = get_counter vim.t.funcs = {add = add_counter, get = get_counter} + vim.t.AddParens = function(s) return '(' .. s .. ')' end ]] eq(0, eval('t:GetCounter()')) @@ -1331,6 +1353,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.t.funcs.get()]])) exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]])) exec_lua [[ local counter = 0 @@ -1339,6 +1362,7 @@ describe('lua stdlib', function() vim.api.nvim_tabpage_set_var(0, 'AddCounter', add_counter) vim.api.nvim_tabpage_set_var(0, 'GetCounter', get_counter) vim.api.nvim_tabpage_set_var(0, 'funcs', {add = add_counter, get = get_counter}) + vim.api.nvim_tabpage_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end) ]] eq(0, eval('t:GetCounter()')) @@ -1354,6 +1378,7 @@ describe('lua stdlib', function() eq(5, exec_lua([[return vim.t.funcs.get()]])) exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]]) eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]])) + eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]])) exec_lua [[ vim.cmd "tabnew" diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 9da2c4aa61..e032f3bc2b 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -418,6 +418,43 @@ describe('LSP', function() } end) + it('should detach buffer on bufwipe', function() + clear() + local result = exec_lua([[ + local server = function(dispatchers) + local closing = false + return { + request = function(method, params, callback) + if method == 'initialize' then + callback(nil, { capabilities = {} }) + end + end, + notify = function(...) + end, + is_closing = function() return closing end, + terminate = function() closing = true end + } + end + local bufnr = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(bufnr) + local client_id = vim.lsp.start({ name = 'detach-dummy', cmd = server }) + assert(client_id, "lsp.start must return client_id") + local client = vim.lsp.get_client_by_id(client_id) + local num_attached_before = vim.tbl_count(client.attached_buffers) + vim.api.nvim_buf_delete(bufnr, { force = true }) + local num_attached_after = vim.tbl_count(client.attached_buffers) + return { + bufnr = bufnr, + client_id = client_id, + num_attached_before = num_attached_before, + num_attached_after = num_attached_after, + } + ]]) + eq(true, result ~= nil, "exec_lua must return result") + eq(1, result.num_attached_before) + eq(0, result.num_attached_after) + end) + it('client should return settings via workspace/configuration handler', function() local expected_handlers = { {NIL, {}, {method="shutdown", client_id=1}}; @@ -1682,6 +1719,46 @@ describe('LSP', function() end) end) + describe('apply_text_edits regression tests for #20116', function() + before_each(function() + insert(dedent([[ + Test line one + Test line two 21 char]])) + end) + describe('with LSP end column out of bounds and start column at 0', function() + it('applies edits at the end of the buffer', function() + local edits = { + make_edit(0, 0, 1, 22, {'#include "whatever.h"\r\n#include <algorithm>\r'}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-8") + eq({'#include "whatever.h"', '#include <algorithm>'}, buf_lines(1)) + end) + it('applies edits in the middle of the buffer', function() + local edits = { + make_edit(0, 0, 0, 22, {'#include "whatever.h"\r\n#include <algorithm>\r'}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-8") + eq({'#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char'}, buf_lines(1)) + end) + end) + describe('with LSP end column out of bounds and start column NOT at 0', function() + it('applies edits at the end of the buffer', function() + local edits = { + make_edit(0, 2, 1, 22, {'#include "whatever.h"\r\n#include <algorithm>\r'}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-8") + eq({'Te#include "whatever.h"', '#include <algorithm>'}, buf_lines(1)) + end) + it('applies edits in the middle of the buffer', function() + local edits = { + make_edit(0, 2, 0, 22, {'#include "whatever.h"\r\n#include <algorithm>\r'}); + } + exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1, "utf-8") + eq({'Te#include "whatever.h"', '#include <algorithm>', 'Test line two 21 char'}, buf_lines(1)) + end) + end) + end) + describe('apply_text_document_edit', function() local target_bufnr local text_document_edit = function(editVersion) @@ -3255,4 +3332,75 @@ describe('LSP', function() eq(result.method, "initialize") end) end) + + describe('handlers', function() + it('handler can return false as response', function() + local result = exec_lua [[ + local uv = vim.loop + local server = uv.new_tcp() + local messages = {} + local responses = {} + 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) + local payload = vim.json.decode(body) + if payload.method then + table.insert(messages, payload.method) + if payload.method == 'initialize' then + local msg = vim.json.encode({ + id = payload.id, + jsonrpc = '2.0', + result = { + capabilities = {} + }, + }) + socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg})) + elseif payload.method == 'initialized' then + local msg = vim.json.encode({ + id = 10, + jsonrpc = '2.0', + method = 'dummy', + params = {}, + }) + socket:write(table.concat({'Content-Length: ', tostring(#msg), '\r\n\r\n', msg})) + end + else + table.insert(responses, payload) + socket:close() + end + end)) + end) + local port = server:getsockname().port + local handler_called = false + vim.lsp.handlers['dummy'] = function(err, result) + handler_called = true + return false + end + local client_id = vim.lsp.start({ name = 'dummy', cmd = vim.lsp.rpc.connect('127.0.0.1', port) }) + local client = vim.lsp.get_client_by_id(client_id) + vim.wait(1000, function() return #messages == 2 and handler_called and #responses == 1 end) + server:close() + server:shutdown() + return { + messages = messages, + handler_called = handler_called, + responses = responses } + ]] + local expected = { + messages = { 'initialize', 'initialized' }, + handler_called = true, + responses = { + { + id = 10, + jsonrpc = '2.0', + result = false + } + } + } + eq(expected, result) + end) + end) end) diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua index d10a2facbb..f5a81eb2ef 100644 --- a/test/functional/shada/shada_spec.lua +++ b/test/functional/shada/shada_spec.lua @@ -238,6 +238,15 @@ describe('ShaDa support code', function() eq('', meths.get_option('shada')) end) + it('setting &shada gives proper error message on missing number', function() + eq([[Vim(set):E526: Missing number after <">: shada="]], + exc_exec([[set shada=\"]])) + for _, c in ipairs({"'", "/", ":", "<", "@", "s"}) do + eq(([[Vim(set):E526: Missing number after <%s>: shada=%s]]):format(c, c), + exc_exec(([[set shada=%s]]):format(c))) + end + end) + it('does not crash when ShaDa file directory is not writable', function() if helpers.pending_win32(pending) then return end diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index 23b69319f0..36f9f90143 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -10,6 +10,7 @@ local retry = helpers.retry local ok = helpers.ok local iswin = helpers.iswin local command = helpers.command +local uname = helpers.uname describe(':terminal', function() local screen @@ -45,6 +46,9 @@ describe(':terminal', function() end) it("reads output buffer on terminal reporting #4151", function() + if uname() == 'freebsd' then + pending('Failing FreeBSD test') + end if helpers.pending_win32(pending) then return end if iswin() then feed_command([[terminal powershell -NoProfile -NoLogo -Command Write-Host -NoNewline "\"$([char]27)[6n\""; Start-Sleep -Milliseconds 500 ]]) diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index d557b2c012..1684337c3c 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -605,8 +605,8 @@ describe('treesitter highlighting', function() }} eq({ - {capture='Error', priority='101'}; - {capture='type'}; + {capture='Error', metadata = { priority='101' }}; + {capture='type', metadata = { } }; }, exec_lua [[ return vim.treesitter.get_captures_at_position(0, 0, 2) ]]) end) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index db13647cc6..92eb853686 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -934,6 +934,15 @@ describe('cmdheight=0', function() before_each(function() clear() screen = Screen.new(25, 5) + screen:set_default_attr_ids { + [1] = {bold = true, foreground = Screen.colors.Blue}; + [2] = {bold = true, reverse = true}; + [3] = {bold = true}; + [4] = {foreground = Screen.colors.White, background = Screen.colors.Red}; + [5] = {foreground = Screen.colors.SeaGreen4, bold = true}; + [6] = {reverse = true}; + [7] = {background = Screen.colors.Yellow}; + } screen:attach() end) @@ -941,9 +950,9 @@ describe('cmdheight=0', function() command("set cmdheight=1 noruler laststatus=2") screen:expect{grid=[[ ^ | - ~ | - ~ | - [No Name] | + {1:~ }| + {1:~ }| + {2:[No Name] }| | ]]} end) @@ -952,10 +961,10 @@ describe('cmdheight=0', function() command("set cmdheight=0 noruler laststatus=2") screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - [No Name] | + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] }| ]]} end) @@ -963,10 +972,10 @@ describe('cmdheight=0', function() command("set cmdheight=0 ruler laststatus=0") screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]]} end) @@ -975,10 +984,10 @@ describe('cmdheight=0', function() feed('i') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]], showmode={}} feed('<Esc>') eq(0, eval('&cmdheight')) @@ -989,10 +998,10 @@ describe('cmdheight=0', function() feed('i') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]], showmode={}} feed('<Esc>') eq(0, eval('&cmdheight')) @@ -1003,10 +1012,10 @@ describe('cmdheight=0', function() feed('i') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - -- INSERT -- | + {1:~ }| + {1:~ }| + {1:~ }| + {3:-- INSERT --} | ]]} feed('<Esc>') eq(1, eval('&cmdheight')) @@ -1017,19 +1026,19 @@ describe('cmdheight=0', function() feed(':') screen:expect{grid=[[ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| :^ | ]]} - eq(1, eval('&cmdheight')) + eq(0, eval('&cmdheight')) feed('<cr>') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]], showmode={}} eq(0, eval('&cmdheight')) end) @@ -1039,19 +1048,19 @@ describe('cmdheight=0', function() feed(':call input("foo >")<cr>') screen:expect{grid=[[ | - ~ | - ~ | - ~ | + {1:~ }| + {2: }| + :call input("foo >") | foo >^ | ]]} - eq(1, eval('&cmdheight')) + eq(0, eval('&cmdheight')) feed('<cr>') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]], showmode={}} eq(0, eval('&cmdheight')) end) @@ -1060,35 +1069,35 @@ describe('cmdheight=0', function() command("set cmdheight=0 noruler laststatus=3 winbar=foo") feed(':split<CR>') screen:expect{grid=[[ - foo | - | - E36: Not enough room | - Press ENTER or type comma| - nd to continue^ | + {2: }| + :split | + {4:E36: Not enough room} | + {5:Press ENTER or type comma}| + {5:nd to continue}^ | ]]} feed('<CR>') screen:expect{grid=[[ - foo | + {3:foo }| ^ | - ~ | - ~ | - [No Name] | + {1:~ }| + {1:~ }| + {2:[No Name] }| ]]} feed(':') screen:expect{grid=[[ - foo | + {3:foo }| | - ~ | - [No Name] | + {1:~ }| + {1:~ }| :^ | ]]} feed('<Esc>') screen:expect{grid=[[ - foo | + {3:foo }| ^ | - ~ | - ~ | - [No Name] | + {1:~ }| + {1:~ }| + {2:[No Name] }| ]], showmode={}} eq(0, eval('&cmdheight')) @@ -1100,19 +1109,19 @@ describe('cmdheight=0', function() feed('qq') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - recording @q | - ]], showmode={}} + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} feed('q') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | - ]], showmode={}} + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], unchanged=true} end) it("when substitute text", function() @@ -1120,28 +1129,28 @@ describe('cmdheight=0', function() feed('ifoo<ESC>') screen:expect{grid=[[ fo^o | - ~ | - ~ | - ~ | - [No Name] [+] | + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] [+] }| ]]} feed(':%s/foo/bar/gc<CR>') screen:expect{grid=[[ - foo | - ~ | - ~ | - [No Name] [+] | - replace wi...q/l/^E/^Y)?^ | + {6:foo} | + {1:~ }| + {1:~ }| + {1:~ }| + {5:replace wi...q/l/^E/^Y)?}^ | ]]} feed('y') screen:expect{grid=[[ ^bar | - ~ | - ~ | - ~ | - [No Name] [+] | + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] [+] }| ]]} assert_alive() @@ -1152,4 +1161,26 @@ describe('cmdheight=0', function() feed('<C-w>+') eq(0, eval('&cmdheight')) end) + + it("with non-silent mappings with cmdline", function() + command("set cmdheight=0") + command("map <f3> :nohlsearch<cr>") + feed('iaabbaa<esc>/aa<cr>') + screen:expect{grid=[[ + {7:^aa}bb{7:aa} | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + + feed('<f3>') + screen:expect{grid=[[ + ^aabbaa | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + end) end) diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index db5a775632..eff6fe6d23 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -686,15 +686,15 @@ end]] screen:expect{grid=[[ {5:^for} _,item {5:in} {6:ipairs}(items) {5:do} | - {5:local} text, hl_id_cell, count = unpack(item) | - {5:if} hl_id_cell ~= {13:nil} {5:then} | - hl_id = hl_id_cell | + {5:local} text, hl_id_cell, count {5:=} unpack(item) | + {5:if} hl_id_cell {5:~=} {13:nil} {5:then} | + hl_id {5:=} hl_id_cell | {5:end} | - {5:for} _ = {13:1}, (count {5:or} {13:1}) {5:do} | - {5:local} cell = line[colpos] | - cell.text = text | - cell.hl_id = hl_id | - colpos = colpos+{13:1} | + {5:for} _ {5:=} {13:1}, (count {5:or} {13:1}) {5:do} | + {5:local} cell {5:=} line[colpos] | + cell.text {5:=} text | + cell.hl_id {5:=} hl_id | + colpos {5:=} colpos{5:+}{13:1} | {5:end} | {5:end} | {1:~ }| @@ -713,15 +713,15 @@ end]] screen:expect{grid=[[ {5:^for} _,item {5:in} {6:ipairs}(items) {5:do} | - {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count = unpack(item) | - {5:i}{12:c}{11:ombining color} {13:nil} {5:then} | + {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count {5:=} unpack(item) | + {5:i}{12:c}{11:ombining col}{12:or} {13:nil} {5:then} | {11:replacing color}d_cell | {5:e}{8:bl}{7:endy}{10: }{7:text}{10: }{7:-}{10: }{7:here} | - {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | + {5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | {11:replacing color} line[colpos] | - cell.text = text | - cell.hl_id = hl_id | - colpos = colpos+{13:1} | + cell.text {5:=} text | + cell.hl_id {5:=} hl_id | + colpos {5:=} colpos{5:+}{13:1} | {5:end} | {5:end} | {1:~ }| @@ -732,15 +732,15 @@ end]] feed 'V5G' screen:expect{grid=[[ {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} | - {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} | - {18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} | + {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)} | + {18: }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then} | {18: }{11:replacing color}{18:d_cell} | {18: }{5:^e}{17:nd} | - {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | + {5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | {11:replacing color} line[colpos] | - cell.text = text | - cell.hl_id = hl_id | - colpos = colpos+{13:1} | + cell.text {5:=} text | + cell.hl_id {5:=} hl_id | + colpos {5:=} colpos{5:+}{13:1} | {5:end} | {5:end} | {1:~ }| @@ -751,15 +751,15 @@ end]] feed 'jj' screen:expect{grid=[[ {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} | - {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} | - {18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} | + {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)} | + {18: }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then} | {18: }{11:replacing color}{18:d_cell} | {18: }{17:end} | - {18: }{17:for}{18: _ = }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} | - {18: }^ {18: }{17:local}{18: cell = line[colpos]} | - cell.text = text | - cell.hl_id = hl_id | - colpos = colpos+{13:1} | + {18: }{17:for}{18: _ }{17:=}{18: }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} | + {18: }^ {18: }{17:local}{18: cell }{17:=}{18: line[colpos]} | + cell.text {5:=} text | + cell.hl_id {5:=} hl_id | + colpos {5:=} colpos{5:+}{13:1} | {5:end} | {5:end} | {1:~ }| diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 5967b630f6..5e819f14a3 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -596,6 +596,11 @@ describe('float window', function() meths.buf_delete(old_buf, {force = true}) eq(old_win, curwin().id) end) + it('if called from non-floating window in another tabpage', function() + command('tab split') + eq(3, #meths.list_tabpages()) + meths.buf_delete(old_buf, {force = true}) + end) it('if called from floating window with the same buffer', function() meths.set_current_win(same_buf_float) command('autocmd WinLeave * let g:win_leave = nvim_get_current_win()') @@ -8147,6 +8152,366 @@ describe('float window', function() ]]} end end) + + it('it can be resized with messages and cmdheight=0 #20106', function() + screen:try_resize(40,9) + command 'set cmdheight=0' + local buf = meths.create_buf(false,true) + local win = meths.open_win(buf, false, {relative='editor', width=40, height=4, anchor='SW', row=9, col=0, style='minimal', border="single", noautocmd=true}) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + ## grid 5 + {5:┌────────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────────────────────────┘}| + ]], float_pos={ + [5] = {{id = 1002}, "SW", 1, 9, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {5:┌──────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└──────────────────────────────────────┘}| + ]]} + end + + exec_lua([[ + local win = ... + vim.api.nvim_win_set_height(win, 2) + vim.api.nvim_echo({ { "" } }, false, {}) + ]], win) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + ## grid 5 + {5:┌────────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────────────────────────┘}| + ]], float_pos={ + [5] = {{id = 1002}, "SW", 1, 9, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {5:┌──────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└──────────────────────────────────────┘}| + ]]} + + end + + meths.win_close(win, true) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ]]} + end + end) + + it('it can be resized with messages and cmdheight=1', function() + screen:try_resize(40,9) + local buf = meths.create_buf(false,true) + local win = meths.open_win(buf, false, {relative='editor', width=40, height=4, anchor='SW', row=8, col=0, style='minimal', border="single", noautocmd=true}) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + {5:┌────────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────────────────────────┘}| + ]], float_pos={ + [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {5:┌──────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└──────────────────────────────────────┘}| + | + ]]} + end + + exec_lua([[ + -- echo prompt is blocking, so schedule + local win = ... + vim.schedule(function() + vim.api.nvim_win_set_height(win, 2) + vim.api.nvim_echo({ { "\n" } }, false, {}) + end) + ]], win) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + {8:Press ENTER or type command to continue}^ | + ## grid 5 + {5:┌────────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────────────────────────┘}| + ]], float_pos={ + [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + | + {0:~ }| + {5:┌──────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {4: }| + | + {8:Press ENTER or type command to continue}^ | + ]]} + end + + feed('<cr>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + {5:┌────────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────────────────────────┘}| + ]], float_pos={ + [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {5:┌──────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└──────────────────────────────────────┘}| + | + ]]} + end + + meths.win_close(win, true) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + end + end) end describe('with ext_multigrid', function() diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index 9ca4673efe..49b3c7a655 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -1190,6 +1190,8 @@ describe(":substitute, inccommand=split", function() end) it("deactivates if 'redrawtime' is exceeded #5602", function() + -- prevent redraws from 'incsearch' + meths.set_option('incsearch', false) -- Assert that 'inccommand' is ENABLED initially. eq("split", eval("&inccommand")) -- Set 'redrawtime' to minimal value, to ensure timeout is triggered. @@ -2972,6 +2974,59 @@ it(':substitute with inccommand, does not crash if range contains invalid marks' ]]) end) +it(':substitute with inccommand, no unnecessary redraw if preview is not shown', function() + local screen = Screen.new(60, 6) + clear() + common_setup(screen, 'split', 'test') + feed(':ls<CR>') + screen:expect([[ + test | + {15:~ }| + {11: }| + :ls | + 1 %a + "[No Name]" line 1 | + {13:Press ENTER or type command to continue}^ | + ]]) + feed(':s') + -- no unnecessary redraw, so messages are still shown + screen:expect([[ + test | + {15:~ }| + {11: }| + :ls | + 1 %a + "[No Name]" line 1 | + :s^ | + ]]) + feed('o') + screen:expect([[ + test | + {15:~ }| + {11: }| + :ls | + 1 %a + "[No Name]" line 1 | + :so^ | + ]]) + feed('<BS>') + screen:expect([[ + test | + {15:~ }| + {11: }| + :ls | + 1 %a + "[No Name]" line 1 | + :s^ | + ]]) + feed('/test') + -- now inccommand is shown, so screen is redrawn + screen:expect([[ + {12:test} | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + :s/test^ | + ]]) +end) + it(":substitute doesn't crash with inccommand, if undo is empty #12932", function() local screen = Screen.new(10,5) clear() diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 522c9ccba2..6b8fa99b38 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -2020,4 +2020,55 @@ aliquip ex ea commodo consequat.]]) | ]]} end) + + it('with cmdheight=0 does not crash with g<', function() + command('set cmdheight=0') + feed(':ls<cr>') + screen:expect{grid=[[ + | + {1:~ }| + {12: }| + :ls | + 1 %a "[No Name]" | + line 1 | + {4:Press ENTER or type command to cont}| + {4:inue}^ | + ]]} + + feed('<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + + feed('g<lt>') + screen:expect{grid=[[ + | + {1:~ }| + {12: }| + :ls | + 1 %a "[No Name]" | + line 1 | + {4:Press ENTER or type command to cont}| + {4:inue}^ | + ]]} + + feed('<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + end) end) diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua index f790597140..e8798ddd93 100644 --- a/test/functional/ui/syntax_conceal_spec.lua +++ b/test/functional/ui/syntax_conceal_spec.lua @@ -947,7 +947,7 @@ describe('Screen', function() {0:~ }| | ]]} - eq({{2, 0, {{'c', 0, 3}}}}, grid_lines) + eq({{2, 0, {{'c', 0, 3}, {' ', 0, 50}}}, {3, 0, {{' ', 0, 53}}}}, grid_lines) end) it('K_EVENT should not cause extra redraws with concealcursor #13196', function() @@ -994,10 +994,11 @@ describe('Screen', function() {0:~ }| | ]]} - eq({{2, 0, {{'c', 0, 3}}}}, grid_lines) + eq({{2, 0, {{'c', 0, 3}, {' ', 0, 50}}}}, grid_lines) + grid_lines = {} poke_eventloop() -- causes K_EVENT key screen:expect_unchanged() - eq({{2, 0, {{'c', 0, 3}}}}, grid_lines) + eq({}, grid_lines) -- no redraw was done end) -- Copy of Test_cursor_column_in_concealed_line_after_window_scroll in diff --git a/test/functional/vimscript/executable_spec.lua b/test/functional/vimscript/executable_spec.lua index b4162b2336..b49eb09512 100644 --- a/test/functional/vimscript/executable_spec.lua +++ b/test/functional/vimscript/executable_spec.lua @@ -34,11 +34,13 @@ describe('executable()', function() it('fails for invalid values', function() for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do - eq('Vim(call):E928: String required', exc_exec('call executable('..input..')')) + eq('Vim(call):E1174: String required for argument 1', + exc_exec('call executable('..input..')')) end command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do - eq('Vim(call):E928: String required', exc_exec('call executable('..input..')')) + eq('Vim(call):E1174: String required for argument 1', + exc_exec('call executable('..input..')')) end end) diff --git a/test/functional/vimscript/exepath_spec.lua b/test/functional/vimscript/exepath_spec.lua index bbca954511..439dd96fcd 100644 --- a/test/functional/vimscript/exepath_spec.lua +++ b/test/functional/vimscript/exepath_spec.lua @@ -21,12 +21,12 @@ describe('exepath()', function() it('fails for invalid values', function() for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do - eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')')) + eq('Vim(call):E1174: String required for argument 1', exc_exec('call exepath('..input..')')) end - eq('Vim(call):E1142: Non-empty string required', exc_exec('call exepath("")')) + eq('Vim(call):E1142: Non-empty string required for argument 1', exc_exec('call exepath("")')) command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') for _, input in ipairs({'v:null', 'v:true', 'v:false'}) do - eq('Vim(call):E928: String required', exc_exec('call exepath('..input..')')) + eq('Vim(call):E1174: String required for argument 1', exc_exec('call exepath('..input..')')) end end) diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua index 5463cfb234..1818a71ea2 100644 --- a/test/functional/vimscript/timer_spec.lua +++ b/test/functional/vimscript/timer_spec.lua @@ -131,34 +131,34 @@ describe('timers', function() nvim_async("command", "call timer_start("..load_adjust(100)..", 'AddItem', {'repeat': -1})") screen:expect([[ - ITEM 1 | + ^ITEM 1 | ITEM 2 | {1:~ }| {1:~ }| {1:~ }| - ^ | + | ]]) nvim_async("command", "let g:cont = 1") screen:expect([[ - ITEM 1 | + ^ITEM 1 | ITEM 2 | ITEM 3 | {1:~ }| {1:~ }| - ^ | + | ]]) feed("3") eq(51, eval("g:c2")) - screen:expect([[ + screen:expect{grid=[[ ^ITEM 1 | ITEM 2 | ITEM 3 | {1:~ }| {1:~ }| | - ]]) + ]], unchanged=true} end) it('can be stopped', function() diff --git a/test/helpers.lua b/test/helpers.lua index 7ec9beea92..a7eda60f87 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -1,4 +1,4 @@ -require('vim.compat') +require('test.compat') local shared = require('vim.shared') local assert = require('luassert') local luv = require('luv') @@ -790,10 +790,9 @@ end function module.isCI(name) local any = (name == nil) - assert(any or name == 'sourcehut' or name == 'github') - local sh = ((any or name == 'sourcehut') and nil ~= os.getenv('SOURCEHUT')) + assert(any or name == 'github') local gh = ((any or name == 'github') and nil ~= os.getenv('GITHUB_ACTIONS')) - return sh or gh + return gh end |