From d24f3d055ae7b3e9e47e9eb53a1dafb3ad44760c Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Thu, 30 May 2024 19:57:47 -0500 Subject: test: do not set termguicolors in test runner It's not clear why this is needed and it has adverse side effects on other tests. --- test/functional/testnvim.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/testnvim.lua') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 6b858e4d69..5f24ef3fe6 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -22,7 +22,7 @@ local runtime_set = 'set runtimepath^=./build/lib/nvim/' M.nvim_prog = (os.getenv('NVIM_PRG') or t.paths.test_build_dir .. '/bin/nvim') -- Default settings for the test session. M.nvim_set = ( - 'set shortmess+=IS background=light termguicolors noswapfile noautoindent startofline' + 'set shortmess+=IS background=light noswapfile noautoindent startofline' .. ' laststatus=1 undodir=. directory=. viewdir=. backupdir=.' .. ' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid' ) -- cgit From 8cbb1f20e557461c8417583a7f69d53aaaef920b Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Tue, 4 Jun 2024 09:06:02 -0400 Subject: refactor(lua): use tuple syntax everywhere #29111 --- test/functional/testnvim.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/testnvim.lua') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 6b858e4d69..746c7290ef 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -256,7 +256,7 @@ end --- @param notification_cb function? --- @param setup_cb function? --- @param timeout integer ---- @return {[1]: integer, [2]: string} +--- @return [integer, string] function M.run_session(lsession, request_cb, notification_cb, setup_cb, timeout) local on_request --- @type function? local on_notification --- @type function? -- cgit From 573a71469d37cc35f72bfc929f4ce1156833df9f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 17 Jul 2024 12:23:15 +0100 Subject: fix(scrollbind): properly take filler/virtual lines into account Problem: `'scrollbind'` does not work properly if the window being scrolled automatically contains any filler/virtual lines (except for diff filler lines). This is because when the scrollbind check is done, the logic only considers changes to topline which are represented as line numbers. Solution: Write the logic for determine the scroll amount to take into account filler/virtual lines. Fixes #29751 --- test/functional/testnvim.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'test/functional/testnvim.lua') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 5a9e7f8c29..66ce6daacb 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -835,9 +835,18 @@ function M.exec_capture(code) return M.api.nvim_exec2(code, { output = true }).output end ---- @param code string +--- @param code string|function --- @return any function M.exec_lua(code, ...) + if type(code) == 'function' then + return M.api.nvim_exec_lua( + [[ + local code = ... + return loadstring(code)(select(2, ...)) + ]], + { string.dump(code), ... } + ) + end return M.api.nvim_exec_lua(code, { ... }) end -- cgit From 8a2aec99748229ad9d1e12c1cbc0768d063e8eed Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 8 Sep 2024 12:48:32 -0700 Subject: fix(startup): server fails if $NVIM_APPNAME is relative dir #30310 Problem: If $NVIM_APPNAME is a relative dir path, Nvim fails to start its primary/default server, and `v:servername` is empty. Root cause is d34c64e342dfba9248d1055e702d02620a1b31a8, but this wasn't noticed until 96128a5076b7 started reporting the error more loudly. Solution: - `server_address_new`: replace slashes "/" in the appname before using it as a servername. - `vim_mktempdir`: always prefer the system-wide top-level "nvim.user/" directory. That isn't intended to be specific to NVIM_APPNAME; rather, each *subdirectory* ("nvim.user/xxx") is owned by each Nvim instance. Nvim "apps" can be identified by the server socket(s) stored in those per-Nvim subdirs. fix #30256 --- test/functional/testnvim.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'test/functional/testnvim.lua') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 66ce6daacb..d74e8055ef 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -14,8 +14,7 @@ local is_os = t.is_os local ok = t.ok local sleep = uv.sleep ---- This module uses functions from the context of the test session, i.e. in the context of the ---- nvim being tests. +--- Functions executing in the current nvim session/process being tested. local M = {} local runtime_set = 'set runtimepath^=./build/lib/nvim/' -- cgit From ed832b9ddf45705abe9d7f4a50cedc27072c8e16 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 8 Sep 2024 21:29:20 +0200 Subject: refactor(test): rename alter_slashes, invert its behavior - `alter_slashes` belongs in `testutil.lua`, not `testnvim.lua`. - `alter_slashes` is an unusual name. Rename it to `fix_slashes`. - invert its behavior, to emphasize that `/` slashes are the preferred, pervasive convention, not `\` slashes. --- test/functional/testnvim.lua | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'test/functional/testnvim.lua') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index d74e8055ef..8c8b239cd8 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -902,26 +902,6 @@ function M.missing_provider(provider) assert(false, 'Unknown provider: ' .. provider) end ---- @param obj string|table ---- @return any -function M.alter_slashes(obj) - if not is_os('win') then - return obj - end - if type(obj) == 'string' then - local ret = obj:gsub('/', '\\') - return ret - elseif type(obj) == 'table' then - --- @cast obj table - local ret = {} --- @type table - for k, v in pairs(obj) do - ret[k] = M.alter_slashes(v) - end - return ret - end - assert(false, 'expected string or table of strings, got ' .. type(obj)) -end - local load_factor = 1 if t.is_ci() then -- Compute load factor only once (but outside of any tests). -- cgit From 5792546777332361a9ac49107e46149c703de90e Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 15 Sep 2024 03:28:14 -0700 Subject: refactor(tests): rename terminal/testutil.lua => testterm.lua #30372 This module is generally used by any tests that need the full Nvim TUI instead of `screen.lua`. Thus it should live in `functional/` instead of in `functional/terminal/`. --- test/functional/testnvim.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test/functional/testnvim.lua') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 8c8b239cd8..a66f0cd52c 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -250,6 +250,8 @@ function M.set_method_error(err) method_error = err end +--- Runs the event loop of the given session. +--- --- @param lsession test.Session --- @param request_cb function? --- @param notification_cb function? @@ -296,6 +298,7 @@ function M.run_session(lsession, request_cb, notification_cb, setup_cb, timeout) return lsession.eof_err end +--- Runs the event loop of the current global session. function M.run(request_cb, notification_cb, setup_cb, timeout) assert(session) return M.run_session(session, request_cb, notification_cb, setup_cb, timeout) -- cgit From ff85e54939b0aca34a779a2b6381d09db1858b29 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 18 Sep 2024 04:14:06 -0700 Subject: feat(tui): builtin UI (TUI) sets client info #30397 Problem: The default builtin UI client does not declare its client info. This reduces discoverability and makes it difficult for plugins to identify the UI. Solution: - Call nvim_set_client_info after attaching, as recommended by `:help dev-ui`. - Also set the "pid" field. - Also change `ui_active()` to return a count. Not directly relevant to this commit, but will be useful later. --- test/functional/testnvim.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/testnvim.lua') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index a66f0cd52c..ac2ec89271 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -458,7 +458,7 @@ end --- @param argv string[] --- @param merge boolean? --- @param env string[]? ---- @param keep boolean +--- @param keep boolean? --- @param io_extra uv.uv_pipe_t? used for stdin_fd, see :help ui-option --- @return test.Session function M.spawn(argv, merge, env, keep, io_extra) -- cgit From e5c174421df3872df0dd3a676609d1e74dfef6a9 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 11 Aug 2024 09:27:48 +0100 Subject: test: support upvalues in exec_lua --- test/functional/testnvim.lua | 164 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 158 insertions(+), 6 deletions(-) (limited to 'test/functional/testnvim.lua') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index ac2ec89271..36e6b4d7bd 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -837,19 +837,171 @@ function M.exec_capture(code) return M.api.nvim_exec2(code, { output = true }).output end +--- @param f function +--- @return table +local function get_upvalues(f) + local i = 1 + local upvalues = {} --- @type table + while true do + local n, v = debug.getupvalue(f, i) + if not n then + break + end + upvalues[n] = v + i = i + 1 + end + return upvalues +end + +--- @param f function +--- @param upvalues table +local function set_upvalues(f, upvalues) + local i = 1 + while true do + local n = debug.getupvalue(f, i) + if not n then + break + end + if upvalues[n] then + debug.setupvalue(f, i, upvalues[n]) + end + i = i + 1 + end +end + +--- @type fun(f: function): table +_G.__get_upvalues = nil + +--- @type fun(f: function, upvalues: table) +_G.__set_upvalues = nil + +--- @param self table +--- @param bytecode string +--- @param upvalues table +--- @param ... any[] +--- @return any[] result +--- @return table upvalues +local function exec_lua_handler(self, bytecode, upvalues, ...) + local f = assert(loadstring(bytecode)) + self.set_upvalues(f, upvalues) + local ret = { f(...) } --- @type any[] + --- @type table + local new_upvalues = self.get_upvalues(f) + + do -- Check return value types for better error messages + local invalid_types = { + ['thread'] = true, + ['function'] = true, + ['userdata'] = true, + } + + for k, v in pairs(ret) do + if invalid_types[type(v)] then + error( + string.format( + "Return index %d with value '%s' of type '%s' cannot be serialized over RPC", + k, + tostring(v), + type(v) + ) + ) + end + end + end + + return ret, new_upvalues +end + +--- Execute Lua code in the wrapped Nvim session. +--- +--- When `code` is passed as a function, it is converted into Lua byte code. +--- +--- Direct upvalues are copied over, however upvalues contained +--- within nested functions are not. Upvalues are also copied back when `code` +--- finishes executing. See `:help lua-upvalue`. +--- +--- Only types which can be serialized can be transferred over, e.g: +--- `table`, `number`, `boolean`, `string`. +--- +--- `code` runs with a different environment and thus will have a different global +--- environment. See `:help lua-environments`. +--- +--- Example: +--- ```lua +--- local upvalue1 = 'upvalue1' +--- exec_lua(function(a, b, c) +--- print(upvalue1, a, b, c) +--- (function() +--- print(upvalue2) +--- end)() +--- end, 'a', 'b', 'c' +--- ``` +--- Prints: +--- ``` +--- upvalue1 a b c +--- nil +--- ``` +--- +--- Not supported: +--- ```lua +--- local a = vim.uv.new_timer() +--- exec_lua(function() +--- print(a) -- Error: a is of type 'userdata' which cannot be serialized. +--- end) +--- ``` --- @param code string|function +--- @param ... any --- @return any function M.exec_lua(code, ...) - if type(code) == 'function' then - return M.api.nvim_exec_lua( + if type(code) == 'string' then + return M.api.nvim_exec_lua(code, { ... }) + end + + assert(session) + + if not session.exec_lua_setup then + M.api.nvim_exec_lua( [[ - local code = ... - return loadstring(code)(select(2, ...)) + _G.__test_exec_lua = { + get_upvalues = loadstring((select(1,...))), + set_upvalues = loadstring((select(2,...))), + handler = loadstring((select(3,...))) + } + setmetatable(_G.__test_exec_lua, { __index = _G.__test_exec_lua }) ]], - { string.dump(code), ... } + { string.dump(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) } ) + session.exec_lua_setup = true end - return M.api.nvim_exec_lua(code, { ... }) + + --- @type any[], table + local ret, upvalues = unpack(M.api.nvim_exec_lua( + [[ + return { + _G.__test_exec_lua:handler(...) + } + ]], + { + string.dump(code), + get_upvalues(code), + ..., + } + )) + + -- Update upvalues + if next(upvalues) then + local caller = debug.getinfo(2) + local f = caller.func + -- On PUC-Lua, if the function is a tail call, then func will be nil. + -- In this case we need to use the current function. + if not f then + assert(caller.source == '=(tail call)') + f = debug.getinfo(1).func + end + set_upvalues(f, upvalues) + end + + return unpack(ret, 1, table.maxn(ret)) end function M.get_pathsep() -- cgit From 511b991e66892b4bb8176ce64c0e8fefb300f638 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 21 Sep 2024 16:23:00 +0100 Subject: feat(fs.lua): add vim.fs.rm() Analogous to the shell `rm` command. --- test/functional/testnvim.lua | 43 +++---------------------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) (limited to 'test/functional/testnvim.lua') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 36e6b4d7bd..8a2281e2a1 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -759,58 +759,21 @@ function M.assert_visible(bufnr, visible) end end ---- @param path string -local function do_rmdir(path) - local stat = uv.fs_stat(path) - if stat == nil then - return - end - if stat.type ~= 'directory' then - error(string.format('rmdir: not a directory: %s', path)) - end - for file in vim.fs.dir(path) do - if file ~= '.' and file ~= '..' then - local abspath = path .. '/' .. file - if t.isdir(abspath) then - do_rmdir(abspath) -- recurse - else - local ret, err = os.remove(abspath) - if not ret then - if not session then - error('os.remove: ' .. err) - else - -- Try Nvim delete(): it handles `readonly` attribute on Windows, - -- and avoids Lua cross-version/platform incompatibilities. - if -1 == M.call('delete', abspath) then - local hint = (is_os('win') and ' (hint: try :%bwipeout! before rmdir())' or '') - error('delete() failed' .. hint .. ': ' .. abspath) - end - end - end - end - end - end - local ret, err = uv.fs_rmdir(path) - if not ret then - error('luv.fs_rmdir(' .. path .. '): ' .. err) - end -end - local start_dir = uv.cwd() function M.rmdir(path) - local ret, _ = pcall(do_rmdir, path) + local ret, _ = pcall(vim.fs.rm, path, { recursive = true, force = true }) if not ret and is_os('win') then -- Maybe "Permission denied"; try again after changing the nvim -- process to the top-level directory. M.command([[exe 'cd '.fnameescape(']] .. start_dir .. "')") - ret, _ = pcall(do_rmdir, path) + ret, _ = pcall(vim.fs.rm, path, { recursive = true, force = true }) end -- During teardown, the nvim process may not exit quickly enough, then rmdir() -- will fail (on Windows). if not ret then -- Try again. sleep(1000) - do_rmdir(path) + vim.fs.rm(path, { recursive = true, force = true }) end end -- cgit