From d6279f9392073cb1422d76c57baf3fd283ed954e Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 31 Jan 2023 23:35:04 +0100 Subject: refactor(tests): move lua-client into core and use it for functionaltests Eliminates lua-client and non-static libluv as test time dependencies Note: the API for a public lua-client is not yet finished. The interface needs to be adjusted to work in the embedded loop of a nvim instance (to use it to talk between instances) --- test/functional/helpers.lua | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 6400db9f87..cd6b535477 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -1,14 +1,11 @@ -require('coxpcall') local luv = require('luv') local lfs = require('lfs') -local mpack = require('mpack') local global_helpers = require('test.helpers') --- nvim client: Found in .deps/usr/share/lua//nvim/ if "bundled". -local Session = require('nvim.session') -local TcpStream = require('nvim.tcp_stream') -local SocketStream = require('nvim.socket_stream') -local ChildProcessStream = require('nvim.child_process_stream') +local Session = require('test.client.session') +local uv_stream = require('test.client.uv_stream') +local SocketStream = uv_stream.SocketStream +local ChildProcessStream = uv_stream.ChildProcessStream local check_cores = global_helpers.check_cores local check_logs = global_helpers.check_logs @@ -23,7 +20,6 @@ local tbl_contains = global_helpers.tbl_contains local fail = global_helpers.fail local module = { - NIL = mpack.NIL, mkdir = lfs.mkdir, } @@ -202,7 +198,7 @@ function module.expect_msg_seq(...) end local function call_and_stop_on_error(lsession, ...) - local status, result = copcall(...) -- luacheck: ignore + local status, result = Session.safe_pcall(...) -- luacheck: ignore if not status then lsession:stop() last_error = result @@ -428,7 +424,7 @@ end -- Creates a new Session connected by domain socket (named pipe) or TCP. function module.connect(file_or_address) local addr, port = string.match(file_or_address, "(.*):(%d+)") - local stream = (addr and port) and TcpStream.open(addr, port) or + local stream = (addr and port) and SocketStream.connect(addr, port) or SocketStream.open(file_or_address) return Session.new(stream) end -- cgit From af23d173883f47fd02a9a380c719e4428370b484 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 7 Mar 2023 04:13:04 +0100 Subject: test: move oldtests to test directory (#22536) The new oldtest directory is in test/old/testdir. The reason for this is that many tests have hardcoded the parent directory name to be 'testdir'. --- test/functional/helpers.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index cd6b535477..43e5b73608 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -898,7 +898,7 @@ local load_factor = 1 if global_helpers.is_ci() then -- Compute load factor only once (but outside of any tests). module.clear() - module.request('nvim_command', 'source src/nvim/testdir/load.vim') + module.request('nvim_command', 'source test/old/testdir/load.vim') load_factor = module.request('nvim_eval', 'g:test_load_factor') end function module.load_adjust(num) -- cgit From ecc4d0e435d618828b938d78fbded7fbe1314760 Mon Sep 17 00:00:00 2001 From: Enan Ajmain <3nan.ajmain@gmail.com> Date: Mon, 20 Mar 2023 03:25:12 +0600 Subject: fix(shell): on Windows :make does not echo #22728 Problem: On Windows, :make does not display the output of the program it runs. The cause is the default 'shellpipe'. On Linux, nvim uses `tee` to redirect the output to both stdout and the error file. In Windows, for both cmd.exe and powershell, the output is only redirected to the error file. Solution: - On Windows, change the 'shellpipe' default to "2>&1| tee". - Nvim includes `tee` in its Windows package. - Document recommended defaults for powershell. Fixes #12910 --- test/functional/helpers.lua | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 43e5b73608..b485352c94 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -553,16 +553,18 @@ function module.set_shell_powershell(fake) assert(found) end local shell = found and (is_os('win') and 'powershell' or 'pwsh') or module.testprg('pwsh-test') - local set_encoding = '[Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();' - local cmd = set_encoding..'Remove-Item -Force '..table.concat(is_os('win') + local cmd = 'Remove-Item -Force '..table.concat(is_os('win') and {'alias:cat', 'alias:echo', 'alias:sleep', 'alias:sort'} or {'alias:echo'}, ',')..';' module.exec([[ let &shell = ']]..shell..[[' set shellquote= shellxquote= - let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ]]..cmd..[[' - let &shellpipe = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode' - let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode' + let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ' + let &shellcmdflag .= '[Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();' + let &shellcmdflag .= '$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';' + let &shellcmdflag .= ']]..cmd..[[' + let &shellredir = '2>&1 | %%{ "$_" } | Out-File %s; exit $LastExitCode' + let &shellpipe = '2>&1 | %%{ "$_" } | Tee-Object %s; exit $LastExitCode' ]]) return found end -- cgit From fe9cbcb3a5c82932ecfb8f49d07e98a1fc2b31e5 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 25 Mar 2023 18:58:48 +0200 Subject: feat(api): nvim_exec2(), deprecate nvim_exec() #19032 Problem: The signature of nvim_exec() is not extensible per ":help api-contract". Solution: Introduce nvim_exec2() and deprecate nvim_exec(). --- test/functional/helpers.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index b485352c94..de5fe96934 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -533,7 +533,7 @@ function module.feed_command(...) end end --- @deprecated use nvim_exec() +-- @deprecated use nvim_exec2() function module.source(code) module.exec(dedent(code)) end @@ -826,11 +826,11 @@ function module.skip_fragile(pending_fn, cond) end function module.exec(code) - return module.meths.exec(code, false) + module.meths.exec2(code, { output = false }) end function module.exec_capture(code) - return module.meths.exec(code, true) + return module.meths.exec2(code, { output = true }).output end function module.exec_lua(code, ...) -- cgit From 4863ca6b8902c5b0aab95f2af640118cd417d379 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 Mar 2023 10:49:32 +0800 Subject: test: use exec_capture() in more places (#22787) Problem: Using `meths.exec2("code", { output = true })` is too verbose. Solution: Use exec_capture() in more places. --- test/functional/helpers.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index de5fe96934..188c196eb3 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -826,7 +826,7 @@ function module.skip_fragile(pending_fn, cond) end function module.exec(code) - module.meths.exec2(code, { output = false }) + module.meths.exec2(code, {}) end function module.exec_capture(code) -- cgit From 743860de40502227b3f0ed64317eb937d24d4a36 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 4 Apr 2023 21:59:06 +0200 Subject: test: replace lfs with luv and vim.fs test: replace lfs with luv luv already pretty much does everything lfs does, so this duplication of dependencies isn't needed. --- test/functional/helpers.lua | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 188c196eb3..2e373467d0 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -1,5 +1,4 @@ local luv = require('luv') -local lfs = require('lfs') local global_helpers = require('test.helpers') local Session = require('test.client.session') @@ -20,10 +19,9 @@ local tbl_contains = global_helpers.tbl_contains local fail = global_helpers.fail local module = { - mkdir = lfs.mkdir, } -local start_dir = lfs.currentdir() +local start_dir = luv.cwd() local runtime_set = 'set runtimepath^=./build/lib/nvim/' module.nvim_prog = ( os.getenv('NVIM_PRG') @@ -730,21 +728,17 @@ function module.assert_visible(bufnr, visible) end local function do_rmdir(path) - local mode, errmsg, errcode = lfs.attributes(path, 'mode') - if mode == nil then - if errcode == 2 then - -- "No such file or directory", don't complain. - return - end - error(string.format('rmdir: %s (%d)', errmsg, errcode)) + local stat = luv.fs_stat(path) + if stat == nil then + return end - if mode ~= 'directory' then + if stat.type ~= 'directory' then error(string.format('rmdir: not a directory: %s', path)) end - for file in lfs.dir(path) do + for file in vim.fs.dir(path) do if file ~= '.' and file ~= '..' then local abspath = path..'/'..file - if lfs.attributes(abspath, 'mode') == 'directory' then + if global_helpers.isdir(abspath) then do_rmdir(abspath) -- recurse else local ret, err = os.remove(abspath) @@ -764,9 +758,9 @@ local function do_rmdir(path) end end end - local ret, err = lfs.rmdir(path) + local ret, err = luv.fs_rmdir(path) if not ret then - error('lfs.rmdir('..path..'): '..err) + error('luv.fs_rmdir('..path..'): '..err) end end -- cgit From d9f78b63361e00a7f623ebb5b869606ac653b180 Mon Sep 17 00:00:00 2001 From: T727 <74924917+T-727@users.noreply.github.com> Date: Sat, 22 Apr 2023 13:04:05 +0300 Subject: docs(powershell): use tee.exe instead of Tee-Object Problem: Tee-Object does not create a file if it does not receive input for example when :grep does not find matches. and so nvim tries to open a nonexistent errorfile causing an error. Solution: use tee.exe instead of Tee-Object --- test/functional/helpers.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 2e373467d0..6e668b22b0 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -552,7 +552,7 @@ function module.set_shell_powershell(fake) end local shell = found and (is_os('win') and 'powershell' or 'pwsh') or module.testprg('pwsh-test') local cmd = 'Remove-Item -Force '..table.concat(is_os('win') - and {'alias:cat', 'alias:echo', 'alias:sleep', 'alias:sort'} + and {'alias:cat', 'alias:echo', 'alias:sleep', 'alias:sort', 'alias:tee'} or {'alias:echo'}, ',')..';' module.exec([[ let &shell = ']]..shell..[[' @@ -562,7 +562,7 @@ function module.set_shell_powershell(fake) let &shellcmdflag .= '$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';' let &shellcmdflag .= ']]..cmd..[[' let &shellredir = '2>&1 | %%{ "$_" } | Out-File %s; exit $LastExitCode' - let &shellpipe = '2>&1 | %%{ "$_" } | Tee-Object %s; exit $LastExitCode' + let &shellpipe = '2>&1 | %%{ "$_" } | tee %s; exit $LastExitCode' ]]) return found end -- cgit From 2f17ef1fc4b96cf1106fd95ba090d34a2e4b977b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 22 Jun 2023 04:09:14 -0700 Subject: fix(messages): use "Vimscript" instead of "VimL" #24111 followup to #24109 fix #16150 --- test/functional/helpers.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 6e668b22b0..67275b12a4 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -265,7 +265,7 @@ function module.nvim_prog_abs() end end --- Executes an ex-command. VimL errors manifest as client (lua) errors, but +-- Executes an ex-command. Vimscript errors manifest as client (lua) errors, but -- v:errmsg will not be updated. function module.command(cmd) module.request('nvim_command', cmd) @@ -289,26 +289,26 @@ function module.expect_exit(fn_or_timeout, ...) end end --- Evaluates a VimL expression. --- Fails on VimL error, but does not update v:errmsg. +-- Evaluates a Vimscript expression. +-- Fails on Vimscript error, but does not update v:errmsg. function module.eval(expr) return module.request('nvim_eval', expr) end --- Executes a VimL function via RPC. --- Fails on VimL error, but does not update v:errmsg. +-- Executes a Vimscript function via RPC. +-- Fails on Vimscript error, but does not update v:errmsg. function module.call(name, ...) return module.request('nvim_call_function', name, {...}) end --- Executes a VimL function via Lua. --- Fails on VimL error, but does not update v:errmsg. +-- Executes a Vimscript function via Lua. +-- Fails on Vimscript error, but does not update v:errmsg. function module.call_lua(name, ...) return module.exec_lua([[return vim.call(...)]], name, ...) end -- Sends user input to Nvim. --- Does not fail on VimL error, but v:errmsg will be updated. +-- Does not fail on Vimscript error, but v:errmsg will be updated. local function nvim_feed(input) while #input > 0 do local written = module.request('nvim_input', input) @@ -518,7 +518,7 @@ function module.insert(...) nvim_feed('') end --- Executes an ex-command by user input. Because nvim_input() is used, VimL +-- Executes an ex-command by user input. Because nvim_input() is used, Vimscript -- errors will not manifest as client (lua) errors. Use command() for that. function module.feed_command(...) for _, v in ipairs({...}) do -- cgit From 5970157e1d22fd5e05ae5d3bd949f807fb7a744c Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 17 May 2023 16:08:06 +0200 Subject: refactor(map): enhanced implementation, Clean Codeā„¢, etc etc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This involves two redesigns of the map.c implementations: 1. Change of macro style and code organization The old khash.h and map.c implementation used huge #define blocks with a lot of backslash line continuations. This instead uses the "implementation file" .c.h pattern. Such a file is meant to be included multiple times, with different macros set prior to inclusion as parameters. we already use this pattern e.g. for eval/typval_encode.c.h to implement different typval encoders reusing a similar structure. We can structure this code into two parts. one that only depends on key type and is enough to implement sets, and one which depends on both key and value to implement maps (as a wrapper around sets, with an added value[] array) 2. Separate the main hash buckets from the key / value arrays Change the hack buckets to only contain an index into separate key / value arrays This is a common pattern in modern, state of the art hashmap implementations. Even though this leads to one more allocated array, it is this often is a net reduction of memory consumption. Consider key+value consuming at least 12 bytes per pair. On average, we will have twice as many buckets per item. Thus old implementation: 2*12 = 24 bytes per item New implementation 1*12 + 2*4 = 20 bytes per item And the difference gets bigger with larger items. One might think we have pulled a fast one here, as wouldn't the average size of the new key/value arrays be 1.5 slots per items due to amortized grows? But remember, these arrays are fully dense, and thus the accessed memory, measured in _cache lines_, the unit which actually matters, will be the fully used memory but just rounded up to the nearest cache line boundary. This has some other interesting properties, such as an insert-only set/map will be fully ordered by insert only. Preserving this ordering in face of deletions is more tricky tho. As we currently don't use ordered maps, the "delete" operation maintains compactness of the item arrays in the simplest way by breaking the ordering. It would be possible to implement an order-preserving delete although at some cost, like allowing the items array to become non-dense until the next rehash. Finally, in face of these two major changes, all code used in khash.h has been integrated into map.c and friends. Given the heavy edits it makes no sense to "layer" the code into a vendored and a wrapper part. Rather, the layered cake follows the specialization depth: code shared for all maps, code specialized to a key type (and its equivalence relation), and finally code specialized to value+key type. --- test/functional/helpers.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 67275b12a4..b98cf97e7e 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -83,6 +83,13 @@ end local session, loop_running, last_error, method_error +if not is_os('win') then + local sigpipe_handler = luv.new_signal() + luv.signal_start(sigpipe_handler, "sigpipe", function() + print("warning: got SIGPIPE signal. Likely related to a crash in nvim") + end) +end + function module.get_session() return session end -- cgit From b04286a187d57c50f01cd36cd4668b7a69026579 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 22 Nov 2020 10:10:37 +0100 Subject: feat(extmark): support proper multiline ranges The removes the previous restriction that nvim_buf_set_extmark() could not be used to highlight arbitrary multi-line regions The problem can be summarized as follows: let's assume an extmark with a hl_group is placed covering the region (5,0) to (50,0) Now, consider what happens if nvim needs to redraw a window covering the lines 20-30. It needs to be able to ask the marktree what extmarks cover this region, even if they don't begin or end here. Therefore the marktree needs to be augmented with the information covers a point, not just what marks begin or end there. To do this, we augment each node with a field "intersect" which is a set the ids of the marks which overlap this node, but only if it is not part of the set of any parent. This ensures the number of nodes that need to be explicitly marked grows only logarithmically with the total number of explicitly nodes (and thus the number of of overlapping marks). Thus we can quickly iterate all marks which overlaps any query position by looking up what leaf node contains that position. Then we only need to consider all "start" marks within that leaf node, and the "intersect" set of that node and all its parents. Now, and the major source of complexity is that the tree restructuring operations (to ensure that each node has T-1 <= size <= 2*T-1) also need to update these sets. If a full inner node is split in two, one of the new parents might start to completely overlap some ranges and its ids will need to be moved from its children's sets to its own set. Similarly, if two undersized nodes gets joined into one, it might no longer completely overlap some ranges, and now the children which do needs to have the have the ids in its set instead. And then there are the pivots! Yes the pivot operations when a child gets moved from one parent to another. --- test/functional/helpers.lua | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index b98cf97e7e..6f5397a089 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -857,6 +857,11 @@ function module.testprg(name) return ('%s/%s%s'):format(module.nvim_dir, name, ext) end +function module.is_asan() + local version = module.eval('execute("verbose version")') + return version:match('-fsanitize=[a-z,]*address') +end + -- Returns a valid, platform-independent Nvim listen address. -- Useful for communicating with child instances. function module.new_pipename() -- cgit From 448907f65d6709fa234d8366053e33311a01bdb9 Mon Sep 17 00:00:00 2001 From: LW Date: Sun, 12 Nov 2023 04:54:27 -0800 Subject: feat(lsp)!: vim.lsp.inlay_hint.get(), enable(), is_enabled() #25512 refactor!: `vim.lsp.inlay_hint()` -> `vim.lsp.inlay_hint.enable()` Problem: The LSP specification allows inlay hints to include tooltips, clickable label parts, and code actions; but Neovim provides no API to query for these. Solution: Add minimal viable extension point from which plugins can query for inlay hints in a range, in order to build functionality on top of. Possible Next Steps --- - Add `virt_text_idx` field to `vim.fn.getmousepos()` return value, for usage in mappings of ``, ``, etc --- test/functional/helpers.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 6f5397a089..761e7dc522 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -18,8 +18,7 @@ local sleep = global_helpers.sleep local tbl_contains = global_helpers.tbl_contains local fail = global_helpers.fail -local module = { -} +local module = {} local start_dir = luv.cwd() local runtime_set = 'set runtimepath^=./build/lib/nvim/' @@ -834,6 +833,8 @@ function module.exec_capture(code) return module.meths.exec2(code, { output = true }).output end +--- @param code string +--- @return any function module.exec_lua(code, ...) return module.meths.exec_lua(code, {...}) end @@ -948,8 +949,10 @@ function module.mkdir_p(path) or 'mkdir -p '..path)) end +--- @class test.functional.helpers: test.helpers module = global_helpers.tbl_extend('error', module, global_helpers) +--- @return test.functional.helpers return function(after_each) if after_each then after_each(function() -- cgit From b514edcdf4747b2ebf00a97f89f310d6d4f090f5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 23 Nov 2023 23:05:52 +0800 Subject: test: remove the pipe created by new_pipename() (#26173) --- test/functional/helpers.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'test/functional/helpers.lua') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 761e7dc522..dcaaa664b9 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -869,6 +869,9 @@ function module.new_pipename() -- HACK: Start a server temporarily, get the name, then stop it. local pipename = module.eval('serverstart()') module.funcs.serverstop(pipename) + -- Remove the pipe so that trying to connect to it without a server listening + -- will be an error instead of a hang. + os.remove(pipename) return pipename end -- cgit