From 9668c166e88cd71e517cacfb8d266b75047604f7 Mon Sep 17 00:00:00 2001 From: Jonas Strittmatter <40792180+smjonas@users.noreply.github.com> Date: Sat, 11 Feb 2023 16:08:33 +0100 Subject: fix(filetype): make vim.filetype.match() work with contents only (#22181) Co-authored-by: Gregory Anders --- test/functional/lua/filetype_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 2a7be53164..034665f717 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -94,6 +94,14 @@ describe('vim.filetype', function() return vim.filetype.match({ buf = 0 }) ]]) end) + + it('works with contents #22180', function() + eq('sh', exec_lua [[ + -- Needs to be set so detect#sh doesn't fail + vim.g.ft_ignore_pat = "\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$" + return vim.filetype.match({ contents = { '#!/usr/bin/env bash' } }) + ]]) + end) end) describe('filetype.lua', function() -- cgit From b518aceaa8f738e581e58aacae93514699b5ff8e Mon Sep 17 00:00:00 2001 From: Jonas Strittmatter <40792180+smjonas@users.noreply.github.com> Date: Tue, 14 Feb 2023 00:04:16 +0100 Subject: feat(filetype): fall back to file extension when matching from hashbang (#22140) If nothing matched in match_from_hashbang, also check the file extension table. For a hashbang like '#!/bin/env foo', this will set the filetype to 'fooscript' assuming the filetype for the 'foo' extension is 'fooscript' in the extension table. --- test/functional/lua/filetype_spec.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 034665f717..add69235b6 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -98,10 +98,22 @@ describe('vim.filetype', function() it('works with contents #22180', function() eq('sh', exec_lua [[ -- Needs to be set so detect#sh doesn't fail - vim.g.ft_ignore_pat = "\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$" + vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$' return vim.filetype.match({ contents = { '#!/usr/bin/env bash' } }) ]]) end) + + it('considers extension mappings when matching from hashbang', function() + eq('fooscript', exec_lua [[ + vim.filetype.add({ + extension = { + foo = 'fooscript', + } + }) + return vim.filetype.match({ contents = { '#!/usr/bin/env foo' } }) + ]]) + end) + end) describe('filetype.lua', function() -- cgit From 46a87a5d2bac598fed0870f0d3c926087f95d30f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 05:19:04 -0500 Subject: refactor(api): VALIDATE macros #22187 Problem: - API validation involves too much boilerplate. - API validation errors are not consistently worded. Solution: Introduce some macros. Currently these are clumsy, but they at least help with consistency and avoid some nesting. --- test/functional/lua/vim_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 867f366d06..b43e5b28db 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1458,7 +1458,7 @@ describe('lua stdlib', function() ]] eq('', funcs.luaeval "vim.bo.filetype") eq(true, funcs.luaeval "vim.bo[BUF].modifiable") - matches("no such option: 'nosuchopt'$", + matches("Invalid option %(not found%): 'nosuchopt'$", pcall_err(exec_lua, 'return vim.bo.nosuchopt')) matches("Expected lua string$", pcall_err(exec_lua, 'return vim.bo[0][0].autoread')) @@ -1479,7 +1479,7 @@ describe('lua stdlib', function() eq(0, funcs.luaeval "vim.wo.cole") eq(0, funcs.luaeval "vim.wo[0].cole") eq(0, funcs.luaeval "vim.wo[1001].cole") - matches("no such option: 'notanopt'$", + matches("Invalid option %(not found%): 'notanopt'$", pcall_err(exec_lua, 'return vim.wo.notanopt')) matches("Expected lua string$", pcall_err(exec_lua, 'return vim.wo[0][0].list')) -- cgit From ff3d04b75b4a9314815c37d53ebc4d035a043335 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 08:07:38 -0500 Subject: refactor(api): VALIDATE macros #22256 - VALIDATE() takes a format string - deduplicate check_string_array - VALIDATE_RANGE - validate UI args --- test/functional/lua/api_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 03832978a4..dc6452dd62 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -33,7 +33,7 @@ describe('luaeval(vim.api.…)', function() describe('with errors', function() it('transforms API error from nvim_buf_set_lines into lua error', function() funcs.setline(1, {"abc", "def", "a\nb", "ttt"}) - eq({false, 'String cannot contain newlines'}, + eq({false, "'replacement string' item contains newlines"}, funcs.luaeval('{pcall(vim.api.nvim_buf_set_lines, 1, 1, 2, false, {"b\\na"})}')) end) -- cgit From 05faa8f30ad770d4e4ead41cec601ccced8fb97f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 15 Feb 2023 07:26:55 +0800 Subject: test: make expect_unchanged() less confusing (#22255) Problem: The sleep before collecting the initial screen state is confusing and may lead to unexpected success if it comes after a blocking RPC call. Solution: Remove that sleep and add an "intermediate" argument. --- test/functional/lua/ui_event_spec.lua | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 6481da900e..de436771f9 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -77,13 +77,8 @@ describe('vim.ui_attach', function() } feed '' - screen:expect{grid=[[ - foobar^ | - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]], intermediate=true} + -- There is an intermediate state where the 'showmode' message disappears. + screen:expect_unchanged(true) expect_events { { "popupmenu_hide" }; } -- cgit From 9b9f8dfcc41ceb80d3970eb58af8ee350b57dc7f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 18 Feb 2023 09:27:10 +0800 Subject: test: make {MATCH:} behave less unexpectedly in screen:expect() Include the rest of the line and allow multiple {MATCH:} patterns. --- test/functional/lua/secure_spec.lua | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua index 2647b2be46..c4abf70f64 100644 --- a/test/functional/lua/secure_spec.lua +++ b/test/functional/lua/secure_spec.lua @@ -48,6 +48,7 @@ describe('vim.secure', function() [4] = {reverse = true}, }) + --- XXX: screen:expect() may fail if this path is too long. local cwd = funcs.getcwd() -- Need to use feed_command instead of exec_lua because of the confirmation prompt @@ -59,7 +60,7 @@ describe('vim.secure', function() {1:~ }| {2: }| :lua vim.secure.read('Xfile') | - {3:]] .. cwd .. pathsep .. [[Xfile is untrusted}{MATCH:%s+}| + {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH:%s+}| {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | ]]} feed('d') @@ -88,7 +89,7 @@ describe('vim.secure', function() {1:~ }| {2: }| :lua vim.secure.read('Xfile') | - {3:]] .. cwd .. pathsep .. [[Xfile is untrusted}{MATCH:%s+}| + {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH:%s+}| {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | ]]} feed('a') @@ -118,7 +119,7 @@ describe('vim.secure', function() {1:~ }| {2: }| :lua vim.secure.read('Xfile') | - {3:]] .. cwd .. pathsep .. [[Xfile is untrusted}{MATCH:%s+}| + {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH:%s+}| {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | ]]} feed('i') @@ -145,7 +146,7 @@ describe('vim.secure', function() {1:~ }| {2: }| :lua vim.secure.read('Xfile') | - {3:]] .. cwd .. pathsep .. [[Xfile is untrusted}{MATCH:%s+}| + {3:]] .. cwd .. pathsep .. [[Xfile is not trusted.}{MATCH:%s+}| {3:[i]gnore, (v)iew, (d)eny, (a)llow: }^ | ]]} feed('v') @@ -153,7 +154,7 @@ describe('vim.secure', function() ^let g:foobar = 42 | {1:~ }| {1:~ }| - {2:]] .. funcs.fnamemodify(cwd, ':~') .. pathsep .. [[Xfile [RO]{MATCH:%s+}| + {2:]] .. funcs.fnamemodify(cwd, ':~') .. pathsep .. [[Xfile [RO]{MATCH:%s+}}| | {1:~ }| {4:[No Name] }| -- cgit From 799edca18a4ddcf8edcb63dd391219e01e187f0d Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 28 Nov 2022 22:43:10 +0100 Subject: feat(lua): make sure require'bit' always works, even with PUC lua 5.1 --- test/functional/lua/overrides_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 3f107811ae..f88698f83d 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -338,3 +338,11 @@ describe('os.getenv', function() eq(value, funcs.luaeval('os.getenv("XTEST_1")')) end) end) + +-- "bit" module is always available, regardless if nvim is built with +-- luajit or PUC lua 5.1. +describe('bit module', function() + it('works', function() + eq (9, exec_lua [[ return require'bit'.band(11,13) ]]) + end) +end) -- cgit From 1c37553476f268d08d290dfee1fa3da4135b54b4 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 21 Feb 2023 17:00:48 +0100 Subject: test(help): drop treesitter parse error to 0 All parser errors have been fixed; make sure we don't introduce new ones. --- test/functional/lua/help_spec.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/help_spec.lua b/test/functional/lua/help_spec.lua index b396e2ba30..d66d9f7fbe 100644 --- a/test/functional/lua/help_spec.lua +++ b/test/functional/lua/help_spec.lua @@ -21,9 +21,8 @@ describe(':help docs', function() ok(rv.helpfiles > 100, '>100 :help files', rv.helpfiles) eq({}, rv.invalid_links, 'invalid tags in :help docs') eq({}, rv.invalid_urls, 'invalid URLs in :help docs') - -- Check that parse errors did not increase wildly. - -- TODO: Fix all parse errors in :help files. - ok(rv.err_count < 250, '<250 parse errors', rv.err_count) + -- Check that parse errors did not increase. + ok(rv.err_count == 0, 'no parse errors', rv.err_count) end) it('gen_help_html.lua generates HTML', function() -- cgit From 5732aa706c639b3d775573d91d1139f24624629c Mon Sep 17 00:00:00 2001 From: Jon Huhn Date: Sat, 25 Feb 2023 03:07:18 -0600 Subject: feat(lsp): implement workspace/didChangeWatchedFiles (#21293) --- test/functional/lua/watch_spec.lua | 195 +++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 test/functional/lua/watch_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua new file mode 100644 index 0000000000..19bb411ce6 --- /dev/null +++ b/test/functional/lua/watch_spec.lua @@ -0,0 +1,195 @@ +local helpers = require('test.functional.helpers')(after_each) +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local clear = helpers.clear +local is_os = helpers.is_os +local lfs = require('lfs') + +describe('vim._watch', function() + before_each(function() + clear() + end) + + describe('watch', function() + it('detects file changes', function() + local root_dir = helpers.tmpname() + os.remove(root_dir) + lfs.mkdir(root_dir) + + local result = exec_lua( + [[ + local root_dir = ... + + local events = {} + + local expected_events = 0 + local function wait_for_events() + assert(vim.wait(100, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) + end + + local stop = vim._watch.watch(root_dir, {}, function(path, change_type) + table.insert(events, { path = path, change_type = change_type }) + end) + + -- Only BSD seems to need some extra time for the watch to be ready to respond to events + if vim.fn.has('bsd') then + vim.wait(50) + end + + local watched_path = root_dir .. '/file' + local watched, err = io.open(watched_path, 'w') + assert(not err, err) + + expected_events = expected_events + 1 + wait_for_events() + + watched:close() + os.remove(watched_path) + + expected_events = expected_events + 1 + wait_for_events() + + stop() + -- No events should come through anymore + + local watched_path = root_dir .. '/file' + local watched, err = io.open(watched_path, 'w') + assert(not err, err) + + vim.wait(50) + + watched:close() + os.remove(watched_path) + + vim.wait(50) + + return events + ]], + root_dir + ) + + local expected = { + { + change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), + path = root_dir .. '/file', + }, + { + change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), + path = root_dir .. '/file', + }, + } + + -- kqueue only reports events on the watched path itself, so creating a file within a + -- watched directory results in a "rename" libuv event on the directory. + if is_os('bsd') then + expected = { + { + change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), + path = root_dir, + }, + { + change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), + path = root_dir, + }, + } + end + + eq(expected, result) + end) + end) + + describe('poll', function() + it('detects file changes', function() + local root_dir = helpers.tmpname() + os.remove(root_dir) + lfs.mkdir(root_dir) + + local result = exec_lua( + [[ + local root_dir = ... + + local events = {} + + local poll_interval_ms = 1000 + local poll_wait_ms = poll_interval_ms+200 + + local expected_events = 0 + local function wait_for_events() + assert(vim.wait(poll_wait_ms, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) + end + + local stop = vim._watch.poll(root_dir, { interval = poll_interval_ms }, function(path, change_type) + table.insert(events, { path = path, change_type = change_type }) + end) + + -- polling generates Created events for the existing entries when it starts. + expected_events = expected_events + 1 + wait_for_events() + + local watched_path = root_dir .. '/file' + local watched, err = io.open(watched_path, 'w') + assert(not err, err) + + expected_events = expected_events + 2 + wait_for_events() + + watched:close() + os.remove(watched_path) + + expected_events = expected_events + 2 + wait_for_events() + + stop() + -- No events should come through anymore + + local watched_path = root_dir .. '/file' + local watched, err = io.open(watched_path, 'w') + assert(not err, err) + + vim.wait(poll_wait_ms) + + watched:close() + os.remove(watched_path) + + return events + ]], + root_dir + ) + + eq(5, #result) + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), + path = root_dir, + }, result[1]) + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), + path = root_dir .. '/file', + }, result[2]) + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), + path = root_dir, + }, result[3]) + -- The file delete and corresponding directory change events do not happen in any + -- particular order, so allow either + if result[4].path == root_dir then + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), + path = root_dir, + }, result[4]) + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), + path = root_dir .. '/file', + }, result[5]) + else + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), + path = root_dir .. '/file', + }, result[4]) + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), + path = root_dir, + }, result[5]) + end + end) + end) +end) -- cgit From f0f27e9aef7c237dd55fbb5c2cd47c2f42d01742 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Sat, 25 Feb 2023 11:17:28 +0100 Subject: Revert "feat(lsp): implement workspace/didChangeWatchedFiles (#21293)" This reverts commit 5732aa706c639b3d775573d91d1139f24624629c. Causes editor to freeze in projects with many watcher registrations --- test/functional/lua/watch_spec.lua | 195 ------------------------------------- 1 file changed, 195 deletions(-) delete mode 100644 test/functional/lua/watch_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua deleted file mode 100644 index 19bb411ce6..0000000000 --- a/test/functional/lua/watch_spec.lua +++ /dev/null @@ -1,195 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq -local exec_lua = helpers.exec_lua -local clear = helpers.clear -local is_os = helpers.is_os -local lfs = require('lfs') - -describe('vim._watch', function() - before_each(function() - clear() - end) - - describe('watch', function() - it('detects file changes', function() - local root_dir = helpers.tmpname() - os.remove(root_dir) - lfs.mkdir(root_dir) - - local result = exec_lua( - [[ - local root_dir = ... - - local events = {} - - local expected_events = 0 - local function wait_for_events() - assert(vim.wait(100, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) - end - - local stop = vim._watch.watch(root_dir, {}, function(path, change_type) - table.insert(events, { path = path, change_type = change_type }) - end) - - -- Only BSD seems to need some extra time for the watch to be ready to respond to events - if vim.fn.has('bsd') then - vim.wait(50) - end - - local watched_path = root_dir .. '/file' - local watched, err = io.open(watched_path, 'w') - assert(not err, err) - - expected_events = expected_events + 1 - wait_for_events() - - watched:close() - os.remove(watched_path) - - expected_events = expected_events + 1 - wait_for_events() - - stop() - -- No events should come through anymore - - local watched_path = root_dir .. '/file' - local watched, err = io.open(watched_path, 'w') - assert(not err, err) - - vim.wait(50) - - watched:close() - os.remove(watched_path) - - vim.wait(50) - - return events - ]], - root_dir - ) - - local expected = { - { - change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), - path = root_dir .. '/file', - }, - { - change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), - path = root_dir .. '/file', - }, - } - - -- kqueue only reports events on the watched path itself, so creating a file within a - -- watched directory results in a "rename" libuv event on the directory. - if is_os('bsd') then - expected = { - { - change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), - path = root_dir, - }, - { - change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), - path = root_dir, - }, - } - end - - eq(expected, result) - end) - end) - - describe('poll', function() - it('detects file changes', function() - local root_dir = helpers.tmpname() - os.remove(root_dir) - lfs.mkdir(root_dir) - - local result = exec_lua( - [[ - local root_dir = ... - - local events = {} - - local poll_interval_ms = 1000 - local poll_wait_ms = poll_interval_ms+200 - - local expected_events = 0 - local function wait_for_events() - assert(vim.wait(poll_wait_ms, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) - end - - local stop = vim._watch.poll(root_dir, { interval = poll_interval_ms }, function(path, change_type) - table.insert(events, { path = path, change_type = change_type }) - end) - - -- polling generates Created events for the existing entries when it starts. - expected_events = expected_events + 1 - wait_for_events() - - local watched_path = root_dir .. '/file' - local watched, err = io.open(watched_path, 'w') - assert(not err, err) - - expected_events = expected_events + 2 - wait_for_events() - - watched:close() - os.remove(watched_path) - - expected_events = expected_events + 2 - wait_for_events() - - stop() - -- No events should come through anymore - - local watched_path = root_dir .. '/file' - local watched, err = io.open(watched_path, 'w') - assert(not err, err) - - vim.wait(poll_wait_ms) - - watched:close() - os.remove(watched_path) - - return events - ]], - root_dir - ) - - eq(5, #result) - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), - path = root_dir, - }, result[1]) - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), - path = root_dir .. '/file', - }, result[2]) - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), - path = root_dir, - }, result[3]) - -- The file delete and corresponding directory change events do not happen in any - -- particular order, so allow either - if result[4].path == root_dir then - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), - path = root_dir, - }, result[4]) - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), - path = root_dir .. '/file', - }, result[5]) - else - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), - path = root_dir .. '/file', - }, result[4]) - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), - path = root_dir, - }, result[5]) - end - end) - end) -end) -- cgit From bc15b075d14c85098d674a2466d2386e08b0005f Mon Sep 17 00:00:00 2001 From: Mike Date: Wed, 1 Mar 2023 10:51:22 -0600 Subject: feat(vim.fs): pass path to find() predicate, lazy evaluate #22378 Problem: No easy way to find files under certain directories (ex: grab all files under `test/`) or exclude the content of certain paths (ex. `build/`, `.git/`) Solution: Pass the full `path` as an arg to the predicate. --- test/functional/lua/fs_spec.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 642d36f63a..03de16c079 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -8,6 +8,7 @@ local mkdir_p = helpers.mkdir_p local rmdir = helpers.rmdir local nvim_dir = helpers.nvim_dir local test_build_dir = helpers.test_build_dir +local test_source_path = helpers.test_source_path local nvim_prog = helpers.nvim_prog local is_os = helpers.is_os @@ -252,6 +253,16 @@ describe('vim.fs', function() local opts = { path = dir, upward = true, type = 'directory' } return vim.fs.find(function(x) return x == 'no-match' end, opts) ]], nvim_dir)) + eq( + exec_lua([[ + local dir = ... + return vim.tbl_map(vim.fs.basename, vim.fn.glob(dir..'/contrib/*', false, true)) + ]], test_source_path), + exec_lua([[ + local dir = ... + local opts = { path = dir, limit = math.huge } + return vim.tbl_map(vim.fs.basename, vim.fs.find(function(_, d) return d:match('[\\/]contrib$') end, opts)) + ]], test_source_path)) end) end) -- cgit From ac69ba5fa0081026f2c5e6e29d5788802479b7b9 Mon Sep 17 00:00:00 2001 From: Jon Huhn Date: Sun, 5 Mar 2023 00:52:27 -0600 Subject: feat(lsp): implement workspace/didChangeWatchedFiles (#22405) --- test/functional/lua/watch_spec.lua | 195 +++++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 test/functional/lua/watch_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua new file mode 100644 index 0000000000..19bb411ce6 --- /dev/null +++ b/test/functional/lua/watch_spec.lua @@ -0,0 +1,195 @@ +local helpers = require('test.functional.helpers')(after_each) +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local clear = helpers.clear +local is_os = helpers.is_os +local lfs = require('lfs') + +describe('vim._watch', function() + before_each(function() + clear() + end) + + describe('watch', function() + it('detects file changes', function() + local root_dir = helpers.tmpname() + os.remove(root_dir) + lfs.mkdir(root_dir) + + local result = exec_lua( + [[ + local root_dir = ... + + local events = {} + + local expected_events = 0 + local function wait_for_events() + assert(vim.wait(100, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) + end + + local stop = vim._watch.watch(root_dir, {}, function(path, change_type) + table.insert(events, { path = path, change_type = change_type }) + end) + + -- Only BSD seems to need some extra time for the watch to be ready to respond to events + if vim.fn.has('bsd') then + vim.wait(50) + end + + local watched_path = root_dir .. '/file' + local watched, err = io.open(watched_path, 'w') + assert(not err, err) + + expected_events = expected_events + 1 + wait_for_events() + + watched:close() + os.remove(watched_path) + + expected_events = expected_events + 1 + wait_for_events() + + stop() + -- No events should come through anymore + + local watched_path = root_dir .. '/file' + local watched, err = io.open(watched_path, 'w') + assert(not err, err) + + vim.wait(50) + + watched:close() + os.remove(watched_path) + + vim.wait(50) + + return events + ]], + root_dir + ) + + local expected = { + { + change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), + path = root_dir .. '/file', + }, + { + change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), + path = root_dir .. '/file', + }, + } + + -- kqueue only reports events on the watched path itself, so creating a file within a + -- watched directory results in a "rename" libuv event on the directory. + if is_os('bsd') then + expected = { + { + change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), + path = root_dir, + }, + { + change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), + path = root_dir, + }, + } + end + + eq(expected, result) + end) + end) + + describe('poll', function() + it('detects file changes', function() + local root_dir = helpers.tmpname() + os.remove(root_dir) + lfs.mkdir(root_dir) + + local result = exec_lua( + [[ + local root_dir = ... + + local events = {} + + local poll_interval_ms = 1000 + local poll_wait_ms = poll_interval_ms+200 + + local expected_events = 0 + local function wait_for_events() + assert(vim.wait(poll_wait_ms, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) + end + + local stop = vim._watch.poll(root_dir, { interval = poll_interval_ms }, function(path, change_type) + table.insert(events, { path = path, change_type = change_type }) + end) + + -- polling generates Created events for the existing entries when it starts. + expected_events = expected_events + 1 + wait_for_events() + + local watched_path = root_dir .. '/file' + local watched, err = io.open(watched_path, 'w') + assert(not err, err) + + expected_events = expected_events + 2 + wait_for_events() + + watched:close() + os.remove(watched_path) + + expected_events = expected_events + 2 + wait_for_events() + + stop() + -- No events should come through anymore + + local watched_path = root_dir .. '/file' + local watched, err = io.open(watched_path, 'w') + assert(not err, err) + + vim.wait(poll_wait_ms) + + watched:close() + os.remove(watched_path) + + return events + ]], + root_dir + ) + + eq(5, #result) + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), + path = root_dir, + }, result[1]) + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), + path = root_dir .. '/file', + }, result[2]) + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), + path = root_dir, + }, result[3]) + -- The file delete and corresponding directory change events do not happen in any + -- particular order, so allow either + if result[4].path == root_dir then + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), + path = root_dir, + }, result[4]) + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), + path = root_dir .. '/file', + }, result[5]) + else + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), + path = root_dir .. '/file', + }, result[4]) + eq({ + change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), + path = root_dir, + }, result[5]) + end + end) + end) +end) -- cgit From ba38f35d3e2f37c2289543e6e0c4451c679c5834 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 5 Mar 2023 11:21:37 +0100 Subject: test: don't search entire repo for files Searching the entire repo for a directory named "contrib" causes failure if there happens to be another subdirectory with the name "contrib". Instead, point directly to the correct contrib directory. --- test/functional/lua/fs_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 03de16c079..da60b5c13b 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -260,7 +260,7 @@ describe('vim.fs', function() ]], test_source_path), exec_lua([[ local dir = ... - local opts = { path = dir, limit = math.huge } + local opts = { path = dir .. "/contrib", limit = math.huge } return vim.tbl_map(vim.fs.basename, vim.fs.find(function(_, d) return d:match('[\\/]contrib$') end, opts)) ]], test_source_path)) end) -- cgit From 0e7196438d8f856eecd7c90e160b79cbc8fb08dc Mon Sep 17 00:00:00 2001 From: Kelly Lin Date: Sun, 19 Feb 2023 22:33:57 +1100 Subject: feat(lua): add semver api --- test/functional/lua/version_spec.lua | 587 +++++++++++++++++++++++++++++++++++ 1 file changed, 587 insertions(+) create mode 100644 test/functional/lua/version_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua new file mode 100644 index 0000000000..23f3cec948 --- /dev/null +++ b/test/functional/lua/version_spec.lua @@ -0,0 +1,587 @@ +local helpers = require('test.functional.helpers')(after_each) +local eq = helpers.eq +local pcall_err = helpers.pcall_err +local matches = helpers.matches + +local version = require('vim.version') + +describe('version', function() + describe('cmp()', function() + local testcases = { + { + desc = 'v1 < v2', + v1 = 'v0.0.0', + v2 = 'v9.0.0', + want = -1, + }, + { + desc = 'v1 < v2', + v1 = 'v0.0.0', + v2 = 'v0.9.0', + want = -1, + }, + { + desc = 'v1 < v2', + v1 = 'v0.0.0', + v2 = 'v0.0.9', + want = -1, + }, + { + desc = 'v1 == v2', + v1 = 'v0.0.0', + v2 = 'v0.0.0', + want = 0, + }, + { + desc = 'v1 > v2', + v1 = 'v9.0.0', + v2 = 'v0.0.0', + want = 1, + }, + { + desc = 'v1 > v2', + v1 = 'v0.9.0', + v2 = 'v0.0.0', + want = 1, + }, + { + desc = 'v1 > v2', + v1 = 'v0.0.9', + v2 = 'v0.0.0', + want = 1, + }, + { + desc = 'v1 < v2 when v1 has prerelease', + v1 = 'v1.0.0-alpha', + v2 = 'v1.0.0', + want = -1, + }, + { + desc = 'v1 > v2 when v2 has prerelease', + v1 = '1.0.0', + v2 = '1.0.0-alpha', + want = 1, + }, + { + desc = 'v1 > v2 when v1 has a higher number identifier', + v1 = '1.0.0-2', + v2 = '1.0.0-1', + want = 1, + }, + { + desc = 'v1 < v2 when v2 has a higher number identifier', + v1 = '1.0.0-2', + v2 = '1.0.0-9', + want = -1, + }, + { + desc = 'v1 < v2 when v2 has more identifiers', + v1 = '1.0.0-2', + v2 = '1.0.0-2.0', + want = -1, + }, + { + desc = 'v1 > v2 when v1 has more identifiers', + v1 = '1.0.0-2.0', + v2 = '1.0.0-2', + want = 1, + }, + { + desc = 'v1 == v2 when v2 has same numeric identifiers', + v1 = '1.0.0-2.0', + v2 = '1.0.0-2.0', + want = 0, + }, + { + desc = 'v1 == v2 when v2 has same alphabet identifiers', + v1 = '1.0.0-alpha', + v2 = '1.0.0-alpha', + want = 0, + }, + { + desc = 'v1 < v2 when v2 has an alphabet identifier with a higher ASCII sort order', + v1 = '1.0.0-alpha', + v2 = '1.0.0-beta', + want = -1, + }, + { + desc = 'v1 > v2 when v1 has an alphabet identifier with a higher ASCII sort order', + v1 = '1.0.0-beta', + v2 = '1.0.0-alpha', + want = 1, + }, + { + desc = 'v1 < v2 when v2 has prerelease and number identifer', + v1 = '1.0.0-alpha', + v2 = '1.0.0-alpha.1', + want = -1, + }, + { + desc = 'v1 > v2 when v1 has prerelease and number identifer', + v1 = '1.0.0-alpha.1', + v2 = '1.0.0-alpha', + want = 1, + }, + { + desc = 'v1 > v2 when v1 has an additional alphabet identifier', + v1 = '1.0.0-alpha.beta', + v2 = '1.0.0-alpha', + want = 1, + }, + { + desc = 'v1 < v2 when v2 has an additional alphabet identifier', + v1 = '1.0.0-alpha', + v2 = '1.0.0-alpha.beta', + want = -1, + }, + { + desc = 'v1 < v2 when v2 has an a first alphabet identifier with higher precedence', + v1 = '1.0.0-alpha.beta', + v2 = '1.0.0-beta', + want = -1, + }, + { + desc = 'v1 > v2 when v1 has an a first alphabet identifier with higher precedence', + v1 = '1.0.0-beta', + v2 = '1.0.0-alpha.beta', + want = 1, + }, + { + desc = 'v1 < v2 when v2 has an additional number identifer', + v1 = '1.0.0-beta', + v2 = '1.0.0-beta.2', + want = -1, + }, + { + desc = 'v1 < v2 when v2 has same first alphabet identifier but has a higher number identifer', + v1 = '1.0.0-beta.2', + v2 = '1.0.0-beta.11', + want = -1, + }, + { + desc = 'v1 < v2 when v2 has higher alphabet precedence', + v1 = '1.0.0-beta.11', + v2 = '1.0.0-rc.1', + want = -1, + }, + } + for _, tc in ipairs(testcases) do + it( + string.format('returns %d if %s (v1 = %s, v2 = %s)', tc.want, tc.desc, tc.v1, tc.v2), + function() + eq(tc.want, version.cmp(tc.v1, tc.v2, { strict = true })) + end + ) + end + end) + + describe('parse()', function() + describe('parsing', function() + describe('strict = true', function() + local testcases = { + { + desc = 'a version without leading "v"', + version = '10.20.123', + want = { + major = 10, + minor = 20, + patch = 123, + prerelease = nil, + build = nil, + }, + }, + { + desc = 'a valid version with a leading "v"', + version = 'v1.2.3', + want = { major = 1, minor = 2, patch = 3 }, + }, + { + desc = 'a valid version with leading "v" and whitespace', + version = ' v1.2.3', + want = { major = 1, minor = 2, patch = 3 }, + }, + { + desc = 'a valid version with leading "v" and trailing whitespace', + version = 'v1.2.3 ', + want = { major = 1, minor = 2, patch = 3 }, + }, + { + desc = 'a version with a prerelease', + version = '1.2.3-alpha', + want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha' }, + }, + { + desc = 'a version with a prerelease with additional identifiers', + version = '1.2.3-alpha.1', + want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha.1' }, + }, + { + desc = 'a version with a build', + version = '1.2.3+build.15', + want = { major = 1, minor = 2, patch = 3, build = 'build.15' }, + }, + { + desc = 'a version with a prerelease and build', + version = '1.2.3-rc1+build.15', + want = { + major = 1, + minor = 2, + patch = 3, + prerelease = 'rc1', + build = 'build.15', + }, + }, + } + for _, tc in ipairs(testcases) do + it( + string.format('returns correct table for %q: version = %q', tc.desc, tc.version), + function() + eq(tc.want, version.parse(tc.version, { strict = true })) + end + ) + end + end) + + describe('strict = false', function() + local testcases = { + { + desc = 'a version missing patch version', + version = '1.2', + want = { major = 1, minor = 2, patch = 0 }, + }, + { + desc = 'a version missing minor and patch version', + version = '1', + want = { major = 1, minor = 0, patch = 0 }, + }, + { + desc = 'a version missing patch version with prerelease', + version = '1.1-0', + want = { major = 1, minor = 1, patch = 0, prerelease = '0' }, + }, + { + desc = 'a version missing minor and patch version with prerelease', + version = '1-1.0', + want = { major = 1, minor = 0, patch = 0, prerelease = '1.0' }, + }, + } + for _, tc in ipairs(testcases) do + it( + string.format('returns correct table for %q: version = %q', tc.desc, tc.version), + function() + eq(tc.want, version.parse(tc.version, { strict = false })) + end + ) + end + end) + end) + + describe('errors', function() + describe('returns nil', function() + local testcases = { + { desc = 'a word', version = 'foo' }, + { desc = 'an empty string', version = '' }, + { desc = 'trailing period character', version = '0.0.0.' }, + { desc = 'leading period character', version = '.0.0.0' }, + { desc = 'negative major version', version = '-1.0.0' }, + { desc = 'negative minor version', version = '0.-1.0' }, + { desc = 'negative patch version', version = '0.0.-1' }, + { desc = 'leading invalid string', version = 'foobar1.2.3' }, + { desc = 'trailing invalid string', version = '1.2.3foobar' }, + { desc = 'an invalid prerelease', version = '1.2.3-%?' }, + { desc = 'an invalid build', version = '1.2.3+%?' }, + { desc = 'build metadata before prerelease', version = '1.2.3+build.0-rc1' }, + } + for _, tc in ipairs(testcases) do + it(string.format('for %s: version = %s', tc.desc, tostring(tc.version)), function() + eq(nil, version.parse(tc.version, { strict = true })) + end) + end + end) + + describe('raises error', function() + local testcases = { + { desc = 'no parameters' }, + { desc = 'nil', version = nil }, + { desc = 'a number', version = 0 }, + { desc = 'a float', version = 0.01 }, + { desc = 'a table', version = {} }, + } + for _, tc in ipairs(testcases) do + it(string.format('for %s: version = %s', tc.desc, tostring(tc.version)), function() + matches( + string.format('invalid version: "%s"', tostring(tc.version)), + pcall_err(function() + version.parse(tc.version, { strict = true }) + end) + ) + end) + end + end) + end) + end) + + describe('eq', function() + describe('valid versions', function() + local testcases = { + { + version_1 = '1.0.0', + version_2 = '1.0.0', + want = true, + }, + { + version_1 = '1.0.0', + version_2 = 'v1.0.0', + want = true, + }, + { + version_1 = '1.0.0', + version_2 = '1.0', + want = true, + }, + { + version_1 = '1.0.0', + version_2 = '1', + want = true, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.0-alpha', + want = true, + }, + { + version_1 = '1.0.0-alpha', + version_2 = 'v1.0.0-alpha', + want = true, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.0-alpha+build.5', + want = true, + }, + { + version_1 = '1.0.0-alpha.1', + version_2 = '1.0.0-alpha.1+build.5', + want = true, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.0-alpha.1', + want = false, + }, + { + version_1 = '1.0.0', + version_2 = '2.0.0', + want = false, + }, + } + for _, tc in ipairs(testcases) do + it(string.format('returns %s for %s = %s', tc.want, tc.version_1, tc.version_2), function() + eq(tc.want, version.eq(tc.version_1, tc.version_2)) + end) + end + end) + + describe('errors', function() + local testcases = { + { + version_1 = '', + version_2 = '1.0.0', + err_version = '', + }, + { + version_1 = '1.0.0', + version_2 = '', + err_version = '', + }, + { + version_1 = '', + version_2 = '', + err_version = '', + }, + { + version_1 = '1.0.0', + version_2 = 'foo', + err_version = 'foo', + }, + } + for _, tc in ipairs(testcases) do + it(string.format('for %s = %s', tc.version_1, tc.version_2), function() + matches( + string.format('invalid version: "%s"', tc.err_version), + pcall_err(function() + version.eq(tc.version_1, tc.version_2) + end) + ) + end) + end + end) + end) + + describe('lt', function() + describe('valid versions', function() + local testcases = { + { + version_1 = '1.0.0', + version_2 = '1.0.1', + want = true, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.1', + want = true, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.1-beta', + want = true, + }, + { + version_1 = '1.0.1', + version_2 = '1.0.0', + want = false, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.0-alpha', + want = false, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.0-alpha+build.5', + want = false, + }, + { + version_1 = '1.0.0-alpha+build.4', + version_2 = '1.0.0-alpha+build.5', + want = false, + }, + } + for _, tc in ipairs(testcases) do + it( + string.format('returns %s for %s < %s', tostring(tc.want), tc.version_1, tc.version_2), + function() + eq(tc.want, version.lt(tc.version_1, tc.version_2)) + end + ) + end + end) + + describe('errors', function() + local testcases = { + { + version_1 = '', + version_2 = '1.0.0', + err_version = '', + }, + { + version_1 = '1.0.0', + version_2 = '', + err_version = '', + }, + { + version_1 = '', + version_2 = '', + err_version = '', + }, + } + for _, tc in ipairs(testcases) do + it(string.format('for %s < %s', tc.version_1, tc.version_2), function() + matches( + string.format('invalid version: "%s"', tc.err_version), + pcall_err(function() + version.lt(tc.version_1, tc.version_2) + end) + ) + end) + end + end) + end) + + describe('gt', function() + describe('valid versions', function() + local testcases = { + { + version_1 = '1.0.1', + version_2 = '1.0.0', + want = true, + }, + { + version_1 = '1.0.1', + version_2 = '1.0.1-alpha', + want = true, + }, + { + version_1 = '1.0.0', + version_2 = '1.0.1', + want = false, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.1', + want = false, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.1-beta', + want = false, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.0-alpha', + want = false, + }, + { + version_1 = '1.0.0-beta', + version_2 = '1.0.0-alpha', + want = true, + }, + { + version_1 = '1.0.0-alpha', + version_2 = '1.0.0-alpha+build.5', + want = false, + }, + { + version_1 = '1.0.0-alpha+build.4', + version_2 = '1.0.0-alpha+build.5', + want = false, + }, + } + for _, tc in ipairs(testcases) do + it(string.format('returns %s for %s > %s', tc.want, tc.version_1, tc.version_2), function() + eq(tc.want, version.gt(tc.version_1, tc.version_2)) + end) + end + end) + + describe('errors', function() + local testcases = { + { + version_1 = '', + version_2 = '1.0.0', + err_version = '', + }, + { + version_1 = '1.0.0', + version_2 = '', + err_version = '', + }, + { + version_1 = '', + version_2 = '', + err_version = '', + }, + } + for _, tc in ipairs(testcases) do + it(string.format('for %s < %s', tc.version_1, tc.version_2), function() + matches( + string.format('invalid version: "%s"', tc.err_version), + pcall_err(function() + version.gt(tc.version_1, tc.version_2) + end) + ) + end) + end + end) + end) +end) -- cgit From e31e49a8e3aac25e923dce15cc76dca4a447947f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 6 Mar 2023 13:23:03 +0100 Subject: refactor(vim.version): cleanup - version.cmp(): assert valid version - add test for loading vim.version (the other tests use shared.lua in the test runner) - reduce test scopes, reword test descriptions --- test/functional/lua/version_spec.lua | 690 +++++++++++++++++------------------ 1 file changed, 337 insertions(+), 353 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index 23f3cec948..9e41330915 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -1,165 +1,176 @@ local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear local eq = helpers.eq -local pcall_err = helpers.pcall_err +local exec_lua = helpers.exec_lua local matches = helpers.matches +local pcall_err = helpers.pcall_err local version = require('vim.version') +local function quote_empty(s) + return tostring(s) == '' and '""' or tostring(s) +end + describe('version', function() + it('package', function() + clear() + eq({ major = 42, minor = 3, patch = 99 }, exec_lua("return vim.version.parse('v42.3.99')")) + end) + describe('cmp()', function() local testcases = { { - desc = 'v1 < v2', + desc = '(v1 < v2)', v1 = 'v0.0.0', v2 = 'v9.0.0', want = -1, }, { - desc = 'v1 < v2', + desc = '(v1 < v2)', v1 = 'v0.0.0', v2 = 'v0.9.0', want = -1, }, { - desc = 'v1 < v2', + desc = '(v1 < v2)', v1 = 'v0.0.0', v2 = 'v0.0.9', want = -1, }, { - desc = 'v1 == v2', + desc = '(v1 == v2)', v1 = 'v0.0.0', v2 = 'v0.0.0', want = 0, }, { - desc = 'v1 > v2', + desc = '(v1 > v2)', v1 = 'v9.0.0', v2 = 'v0.0.0', want = 1, }, { - desc = 'v1 > v2', + desc = '(v1 > v2)', v1 = 'v0.9.0', v2 = 'v0.0.0', want = 1, }, { - desc = 'v1 > v2', + desc = '(v1 > v2)', v1 = 'v0.0.9', v2 = 'v0.0.0', want = 1, }, { - desc = 'v1 < v2 when v1 has prerelease', + desc = '(v1 < v2) when v1 has prerelease', v1 = 'v1.0.0-alpha', v2 = 'v1.0.0', want = -1, }, { - desc = 'v1 > v2 when v2 has prerelease', + desc = '(v1 > v2) when v2 has prerelease', v1 = '1.0.0', v2 = '1.0.0-alpha', want = 1, }, { - desc = 'v1 > v2 when v1 has a higher number identifier', + desc = '(v1 > v2) when v1 has a higher number identifier', v1 = '1.0.0-2', v2 = '1.0.0-1', want = 1, }, { - desc = 'v1 < v2 when v2 has a higher number identifier', + desc = '(v1 < v2) when v2 has a higher number identifier', v1 = '1.0.0-2', v2 = '1.0.0-9', want = -1, }, { - desc = 'v1 < v2 when v2 has more identifiers', + desc = '(v1 < v2) when v2 has more identifiers', v1 = '1.0.0-2', v2 = '1.0.0-2.0', want = -1, }, { - desc = 'v1 > v2 when v1 has more identifiers', + desc = '(v1 > v2) when v1 has more identifiers', v1 = '1.0.0-2.0', v2 = '1.0.0-2', want = 1, }, { - desc = 'v1 == v2 when v2 has same numeric identifiers', + desc = '(v1 == v2) when v2 has same numeric identifiers', v1 = '1.0.0-2.0', v2 = '1.0.0-2.0', want = 0, }, { - desc = 'v1 == v2 when v2 has same alphabet identifiers', + desc = '(v1 == v2) when v2 has same alphabet identifiers', v1 = '1.0.0-alpha', v2 = '1.0.0-alpha', want = 0, }, { - desc = 'v1 < v2 when v2 has an alphabet identifier with a higher ASCII sort order', + desc = '(v1 < v2) when v2 has an alphabet identifier with higher ASCII sort order', v1 = '1.0.0-alpha', v2 = '1.0.0-beta', want = -1, }, { - desc = 'v1 > v2 when v1 has an alphabet identifier with a higher ASCII sort order', + desc = '(v1 > v2) when v1 has an alphabet identifier with higher ASCII sort order', v1 = '1.0.0-beta', v2 = '1.0.0-alpha', want = 1, }, { - desc = 'v1 < v2 when v2 has prerelease and number identifer', + desc = '(v1 < v2) when v2 has prerelease and number identifer', v1 = '1.0.0-alpha', v2 = '1.0.0-alpha.1', want = -1, }, { - desc = 'v1 > v2 when v1 has prerelease and number identifer', + desc = '(v1 > v2) when v1 has prerelease and number identifer', v1 = '1.0.0-alpha.1', v2 = '1.0.0-alpha', want = 1, }, { - desc = 'v1 > v2 when v1 has an additional alphabet identifier', + desc = '(v1 > v2) when v1 has an additional alphabet identifier', v1 = '1.0.0-alpha.beta', v2 = '1.0.0-alpha', want = 1, }, { - desc = 'v1 < v2 when v2 has an additional alphabet identifier', + desc = '(v1 < v2) when v2 has an additional alphabet identifier', v1 = '1.0.0-alpha', v2 = '1.0.0-alpha.beta', want = -1, }, { - desc = 'v1 < v2 when v2 has an a first alphabet identifier with higher precedence', + desc = '(v1 < v2) when v2 has an a first alphabet identifier with higher precedence', v1 = '1.0.0-alpha.beta', v2 = '1.0.0-beta', want = -1, }, { - desc = 'v1 > v2 when v1 has an a first alphabet identifier with higher precedence', + desc = '(v1 > v2) when v1 has an a first alphabet identifier with higher precedence', v1 = '1.0.0-beta', v2 = '1.0.0-alpha.beta', want = 1, }, { - desc = 'v1 < v2 when v2 has an additional number identifer', + desc = '(v1 < v2) when v2 has an additional number identifer', v1 = '1.0.0-beta', v2 = '1.0.0-beta.2', want = -1, }, { - desc = 'v1 < v2 when v2 has same first alphabet identifier but has a higher number identifer', + desc = '(v1 < v2) when v2 has same first alphabet identifier but has a higher number identifer', v1 = '1.0.0-beta.2', v2 = '1.0.0-beta.11', want = -1, }, { - desc = 'v1 < v2 when v2 has higher alphabet precedence', + desc = '(v1 < v2) when v2 has higher alphabet precedence', v1 = '1.0.0-beta.11', v2 = '1.0.0-rc.1', want = -1, @@ -167,7 +178,7 @@ describe('version', function() } for _, tc in ipairs(testcases) do it( - string.format('returns %d if %s (v1 = %s, v2 = %s)', tc.want, tc.desc, tc.v1, tc.v2), + string.format('%d %s (v1 = %s, v2 = %s)', tc.want, tc.desc, tc.v1, tc.v2), function() eq(tc.want, version.cmp(tc.v1, tc.v2, { strict = true })) end @@ -176,410 +187,383 @@ describe('version', function() end) describe('parse()', function() - describe('parsing', function() - describe('strict = true', function() - local testcases = { - { - desc = 'a version without leading "v"', - version = '10.20.123', - want = { - major = 10, - minor = 20, - patch = 123, - prerelease = nil, - build = nil, - }, - }, - { - desc = 'a valid version with a leading "v"', - version = 'v1.2.3', - want = { major = 1, minor = 2, patch = 3 }, - }, - { - desc = 'a valid version with leading "v" and whitespace', - version = ' v1.2.3', - want = { major = 1, minor = 2, patch = 3 }, - }, - { - desc = 'a valid version with leading "v" and trailing whitespace', - version = 'v1.2.3 ', - want = { major = 1, minor = 2, patch = 3 }, - }, - { - desc = 'a version with a prerelease', - version = '1.2.3-alpha', - want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha' }, - }, - { - desc = 'a version with a prerelease with additional identifiers', - version = '1.2.3-alpha.1', - want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha.1' }, - }, - { - desc = 'a version with a build', - version = '1.2.3+build.15', - want = { major = 1, minor = 2, patch = 3, build = 'build.15' }, - }, - { - desc = 'a version with a prerelease and build', - version = '1.2.3-rc1+build.15', - want = { - major = 1, - minor = 2, - patch = 3, - prerelease = 'rc1', - build = 'build.15', - }, - }, - } - for _, tc in ipairs(testcases) do - it( - string.format('returns correct table for %q: version = %q', tc.desc, tc.version), - function() - eq(tc.want, version.parse(tc.version, { strict = true })) - end - ) - end - end) - - describe('strict = false', function() - local testcases = { - { - desc = 'a version missing patch version', - version = '1.2', - want = { major = 1, minor = 2, patch = 0 }, - }, - { - desc = 'a version missing minor and patch version', - version = '1', - want = { major = 1, minor = 0, patch = 0 }, - }, - { - desc = 'a version missing patch version with prerelease', - version = '1.1-0', - want = { major = 1, minor = 1, patch = 0, prerelease = '0' }, - }, - { - desc = 'a version missing minor and patch version with prerelease', - version = '1-1.0', - want = { major = 1, minor = 0, patch = 0, prerelease = '1.0' }, - }, - } - for _, tc in ipairs(testcases) do - it( - string.format('returns correct table for %q: version = %q', tc.desc, tc.version), - function() - eq(tc.want, version.parse(tc.version, { strict = false })) - end - ) - end - end) - end) - - describe('errors', function() - describe('returns nil', function() - local testcases = { - { desc = 'a word', version = 'foo' }, - { desc = 'an empty string', version = '' }, - { desc = 'trailing period character', version = '0.0.0.' }, - { desc = 'leading period character', version = '.0.0.0' }, - { desc = 'negative major version', version = '-1.0.0' }, - { desc = 'negative minor version', version = '0.-1.0' }, - { desc = 'negative patch version', version = '0.0.-1' }, - { desc = 'leading invalid string', version = 'foobar1.2.3' }, - { desc = 'trailing invalid string', version = '1.2.3foobar' }, - { desc = 'an invalid prerelease', version = '1.2.3-%?' }, - { desc = 'an invalid build', version = '1.2.3+%?' }, - { desc = 'build metadata before prerelease', version = '1.2.3+build.0-rc1' }, - } - for _, tc in ipairs(testcases) do - it(string.format('for %s: version = %s', tc.desc, tostring(tc.version)), function() - eq(nil, version.parse(tc.version, { strict = true })) - end) - end - end) - - describe('raises error', function() - local testcases = { - { desc = 'no parameters' }, - { desc = 'nil', version = nil }, - { desc = 'a number', version = 0 }, - { desc = 'a float', version = 0.01 }, - { desc = 'a table', version = {} }, - } - for _, tc in ipairs(testcases) do - it(string.format('for %s: version = %s', tc.desc, tostring(tc.version)), function() - matches( - string.format('invalid version: "%s"', tostring(tc.version)), - pcall_err(function() - version.parse(tc.version, { strict = true }) - end) - ) - end) - end - end) - end) - end) - - describe('eq', function() - describe('valid versions', function() + describe('strict=true', function() local testcases = { { - version_1 = '1.0.0', - version_2 = '1.0.0', - want = true, - }, - { - version_1 = '1.0.0', - version_2 = 'v1.0.0', - want = true, - }, - { - version_1 = '1.0.0', - version_2 = '1.0', - want = true, + desc = 'version without leading "v"', + version = '10.20.123', + want = { + major = 10, + minor = 20, + patch = 123, + prerelease = nil, + build = nil, + }, }, { - version_1 = '1.0.0', - version_2 = '1', - want = true, + desc = 'valid version with leading "v"', + version = 'v1.2.3', + want = { major = 1, minor = 2, patch = 3 }, }, { - version_1 = '1.0.0-alpha', - version_2 = '1.0.0-alpha', - want = true, + desc = 'valid version with leading "v" and whitespace', + version = ' v1.2.3', + want = { major = 1, minor = 2, patch = 3 }, }, { - version_1 = '1.0.0-alpha', - version_2 = 'v1.0.0-alpha', - want = true, + desc = 'valid version with leading "v" and trailing whitespace', + version = 'v1.2.3 ', + want = { major = 1, minor = 2, patch = 3 }, }, { - version_1 = '1.0.0-alpha', - version_2 = '1.0.0-alpha+build.5', - want = true, + desc = 'version with prerelease', + version = '1.2.3-alpha', + want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha' }, }, { - version_1 = '1.0.0-alpha.1', - version_2 = '1.0.0-alpha.1+build.5', - want = true, + desc = 'version with prerelease with additional identifiers', + version = '1.2.3-alpha.1', + want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha.1' }, }, { - version_1 = '1.0.0-alpha', - version_2 = '1.0.0-alpha.1', - want = false, + desc = 'version with build', + version = '1.2.3+build.15', + want = { major = 1, minor = 2, patch = 3, build = 'build.15' }, }, { - version_1 = '1.0.0', - version_2 = '2.0.0', - want = false, + desc = 'version with prerelease and build', + version = '1.2.3-rc1+build.15', + want = { + major = 1, + minor = 2, + patch = 3, + prerelease = 'rc1', + build = 'build.15', + }, }, } for _, tc in ipairs(testcases) do - it(string.format('returns %s for %s = %s', tc.want, tc.version_1, tc.version_2), function() - eq(tc.want, version.eq(tc.version_1, tc.version_2)) - end) + it( + string.format('for %q: version = %q', tc.desc, tc.version), + function() + eq(tc.want, version.parse(tc.version, { strict = true })) + end + ) end end) - describe('errors', function() + describe('strict=false', function() local testcases = { { - version_1 = '', - version_2 = '1.0.0', - err_version = '', + desc = 'version missing patch version', + version = '1.2', + want = { major = 1, minor = 2, patch = 0 }, }, { - version_1 = '1.0.0', - version_2 = '', - err_version = '', + desc = 'version missing minor and patch version', + version = '1', + want = { major = 1, minor = 0, patch = 0 }, }, { - version_1 = '', - version_2 = '', - err_version = '', + desc = 'version missing patch version with prerelease', + version = '1.1-0', + want = { major = 1, minor = 1, patch = 0, prerelease = '0' }, }, { - version_1 = '1.0.0', - version_2 = 'foo', - err_version = 'foo', + desc = 'version missing minor and patch version with prerelease', + version = '1-1.0', + want = { major = 1, minor = 0, patch = 0, prerelease = '1.0' }, }, } for _, tc in ipairs(testcases) do - it(string.format('for %s = %s', tc.version_1, tc.version_2), function() - matches( - string.format('invalid version: "%s"', tc.err_version), - pcall_err(function() - version.eq(tc.version_1, tc.version_2) - end) - ) - end) + it( + string.format('for %q: version = %q', tc.desc, tc.version), + function() + eq(tc.want, version.parse(tc.version, { strict = false })) + end + ) end end) - end) - describe('lt', function() - describe('valid versions', function() + describe('invalid semver', function() local testcases = { - { - version_1 = '1.0.0', - version_2 = '1.0.1', - want = true, - }, - { - version_1 = '1.0.0-alpha', - version_2 = '1.0.1', - want = true, - }, - { - version_1 = '1.0.0-alpha', - version_2 = '1.0.1-beta', - want = true, - }, - { - version_1 = '1.0.1', - version_2 = '1.0.0', - want = false, - }, - { - version_1 = '1.0.0-alpha', - version_2 = '1.0.0-alpha', - want = false, - }, - { - version_1 = '1.0.0-alpha', - version_2 = '1.0.0-alpha+build.5', - want = false, - }, - { - version_1 = '1.0.0-alpha+build.4', - version_2 = '1.0.0-alpha+build.5', - want = false, - }, + { desc = 'a word', version = 'foo' }, + { desc = 'empty string', version = '' }, + { desc = 'trailing period character', version = '0.0.0.' }, + { desc = 'leading period character', version = '.0.0.0' }, + { desc = 'negative major version', version = '-1.0.0' }, + { desc = 'negative minor version', version = '0.-1.0' }, + { desc = 'negative patch version', version = '0.0.-1' }, + { desc = 'leading invalid string', version = 'foobar1.2.3' }, + { desc = 'trailing invalid string', version = '1.2.3foobar' }, + { desc = 'an invalid prerelease', version = '1.2.3-%?' }, + { desc = 'an invalid build', version = '1.2.3+%?' }, + { desc = 'build metadata before prerelease', version = '1.2.3+build.0-rc1' }, } for _, tc in ipairs(testcases) do - it( - string.format('returns %s for %s < %s', tostring(tc.want), tc.version_1, tc.version_2), - function() - eq(tc.want, version.lt(tc.version_1, tc.version_2)) - end - ) + it(string.format('(%s): %s', tc.desc, quote_empty(tc.version)), function() + eq(nil, version.parse(tc.version, { strict = true })) + end) end end) - describe('errors', function() + describe('invalid shape', function() local testcases = { - { - version_1 = '', - version_2 = '1.0.0', - err_version = '', - }, - { - version_1 = '1.0.0', - version_2 = '', - err_version = '', - }, - { - version_1 = '', - version_2 = '', - err_version = '', - }, + { desc = 'no parameters' }, + { desc = 'nil', version = nil }, + { desc = 'number', version = 0 }, + { desc = 'float', version = 0.01 }, + { desc = 'table', version = {} }, } for _, tc in ipairs(testcases) do - it(string.format('for %s < %s', tc.version_1, tc.version_2), function() - matches( - string.format('invalid version: "%s"', tc.err_version), - pcall_err(function() - version.lt(tc.version_1, tc.version_2) - end) - ) + it(string.format('(%s): %s', tc.desc, tostring(tc.version)), function() + matches(string.format('invalid version: "%s"', tostring(tc.version)), + pcall_err(version.parse, tc.version, { strict = true })) end) end end) end) - describe('gt', function() - describe('valid versions', function() - local testcases = { - { - version_1 = '1.0.1', - version_2 = '1.0.0', - want = true, - }, - { - version_1 = '1.0.1', - version_2 = '1.0.1-alpha', - want = true, - }, + describe('eq()', function() + local testcases = { + { + v1 = '1.0.0', + v2 = '1.0.0', + want = true, + }, + { + v1 = '1.0.0', + v2 = 'v1.0.0', + want = true, + }, + { + v1 = '1.0.0', + v2 = '1.0', + want = true, + }, + { + v1 = '1.0.0', + v2 = '1', + want = true, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.0-alpha', + want = true, + }, + { + v1 = '1.0.0-alpha', + v2 = 'v1.0.0-alpha', + want = true, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.0-alpha+build.5', + want = true, + }, + { + v1 = '1.0.0-alpha.1', + v2 = '1.0.0-alpha.1+build.5', + want = true, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.0-alpha.1', + want = false, + }, + { + v1 = '1.0.0', + v2 = '2.0.0', + want = false, + }, + } + + for _, tc in ipairs(testcases) do + it(string.format('returns %s for %s = %s', tostring(tc.want), tc.v1, tc.v2), function() + eq(tc.want, version.eq(tc.v1, tc.v2)) + end) + end + + describe('fails', function() + local failtests = { { - version_1 = '1.0.0', - version_2 = '1.0.1', - want = false, + v1 = '', + v2 = '1.0.0', + err_version = '', }, { - version_1 = '1.0.0-alpha', - version_2 = '1.0.1', - want = false, + v1 = '1.0.0', + v2 = '', + err_version = '', }, { - version_1 = '1.0.0-alpha', - version_2 = '1.0.1-beta', - want = false, + v1 = '', + v2 = '', + err_version = '', }, { - version_1 = '1.0.0-alpha', - version_2 = '1.0.0-alpha', - want = false, + v1 = '1.0.0', + v2 = 'foo', + err_version = 'foo', }, + } + for _, tc in ipairs(failtests) do + it(string.format('for %s = %s', quote_empty(tc.v1), quote_empty(tc.v2)), function() + matches(string.format('invalid version: "%s"', tc.err_version), + pcall_err(version.eq, tc.v1, tc.v2)) + end) + end + end) + end) + + describe('lt()', function() + local testcases = { + { + v1 = '1.0.0', + v2 = '1.0.1', + want = true, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.1', + want = true, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.1-beta', + want = true, + }, + { + v1 = '1.0.1', + v2 = '1.0.0', + want = false, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.0-alpha', + want = false, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.0-alpha+build.5', + want = false, + }, + { + v1 = '1.0.0-alpha+build.4', + v2 = '1.0.0-alpha+build.5', + want = false, + }, + } + for _, tc in ipairs(testcases) do + it(string.format('returns %s for %s < %s', tostring(tc.want), tc.v1, tc.v2), function() + eq(tc.want, version.lt(tc.v1, tc.v2)) + end) + end + + describe('fails', function() + local failtests = { { - version_1 = '1.0.0-beta', - version_2 = '1.0.0-alpha', - want = true, + v1 = '', + v2 = '1.0.0', + err_version = '', }, { - version_1 = '1.0.0-alpha', - version_2 = '1.0.0-alpha+build.5', - want = false, + v1 = '1.0.0', + v2 = '', + err_version = '', }, { - version_1 = '1.0.0-alpha+build.4', - version_2 = '1.0.0-alpha+build.5', - want = false, + v1 = '', + v2 = '', + err_version = '', }, } - for _, tc in ipairs(testcases) do - it(string.format('returns %s for %s > %s', tc.want, tc.version_1, tc.version_2), function() - eq(tc.want, version.gt(tc.version_1, tc.version_2)) + for _, tc in ipairs(failtests) do + it(string.format('for %s < %s', quote_empty(tc.v1), quote_empty(tc.v2)), function() + matches(string.format('invalid version: "%s"', tc.err_version), + pcall_err(version.lt, tc.v1, tc.v2)) end) end end) + end) - describe('errors', function() - local testcases = { + describe('gt()', function() + local testcases = { + { + v1 = '1.0.1', + v2 = '1.0.0', + want = true, + }, + { + v1 = '1.0.1', + v2 = '1.0.1-alpha', + want = true, + }, + { + v1 = '1.0.0', + v2 = '1.0.1', + want = false, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.1', + want = false, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.1-beta', + want = false, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.0-alpha', + want = false, + }, + { + v1 = '1.0.0-beta', + v2 = '1.0.0-alpha', + want = true, + }, + { + v1 = '1.0.0-alpha', + v2 = '1.0.0-alpha+build.5', + want = false, + }, + { + v1 = '1.0.0-alpha+build.4', + v2 = '1.0.0-alpha+build.5', + want = false, + }, + } + + for _, tc in ipairs(testcases) do + it(string.format('returns %s for %s > %s', tostring(tc.want), tc.v1, tc.v2), function() + eq(tc.want, version.gt(tc.v1, tc.v2)) + end) + end + + describe('fails', function() + local failtests = { { - version_1 = '', - version_2 = '1.0.0', + v1 = '', + v2 = '1.0.0', err_version = '', }, { - version_1 = '1.0.0', - version_2 = '', + v1 = '1.0.0', + v2 = '', err_version = '', }, { - version_1 = '', - version_2 = '', + v1 = '', + v2 = '', err_version = '', }, } - for _, tc in ipairs(testcases) do - it(string.format('for %s < %s', tc.version_1, tc.version_2), function() - matches( - string.format('invalid version: "%s"', tc.err_version), - pcall_err(function() - version.gt(tc.version_1, tc.version_2) - end) - ) + for _, tc in ipairs(failtests) do + it(string.format('for %s < %s', quote_empty(tc.v1), quote_empty(tc.v2)), function() + matches(string.format('invalid version: "%s"', tc.err_version), + pcall_err(version.gt, tc.v1, tc.v2)) end) end end) -- cgit From 74ffebf8ec725a25c2ae1dde81cf26b83fc7ae61 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 6 Mar 2023 15:08:22 +0100 Subject: fix(vim.version): incorrect version.cmp() Problem: If majorminor, cmp_version_core returns 1 Solution: - Fix logic in cmp_version_core - Delete most eq()/gt()/lt() tests, they are redundant. --- test/functional/lua/version_spec.lua | 262 ++--------------------------------- 1 file changed, 15 insertions(+), 247 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index 9e41330915..b68727ca77 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -21,20 +21,20 @@ describe('version', function() local testcases = { { desc = '(v1 < v2)', - v1 = 'v0.0.0', + v1 = 'v0.0.99', v2 = 'v9.0.0', want = -1, }, { desc = '(v1 < v2)', - v1 = 'v0.0.0', - v2 = 'v0.9.0', + v1 = 'v0.4.0', + v2 = 'v0.9.99', want = -1, }, { desc = '(v1 < v2)', - v1 = 'v0.0.0', - v2 = 'v0.0.9', + v1 = 'v0.2.8', + v2 = 'v1.0.9', want = -1, }, { @@ -46,7 +46,7 @@ describe('version', function() { desc = '(v1 > v2)', v1 = 'v9.0.0', - v2 = 'v0.0.0', + v2 = 'v0.9.0', want = 1, }, { @@ -317,255 +317,23 @@ describe('version', function() } for _, tc in ipairs(testcases) do it(string.format('(%s): %s', tc.desc, tostring(tc.version)), function() - matches(string.format('invalid version: "%s"', tostring(tc.version)), - pcall_err(version.parse, tc.version, { strict = true })) + local expected = string.format(type(tc.version) == 'string' + and 'invalid version: "%s"' or 'invalid version: %s', tostring(tc.version)) + matches(expected, pcall_err(version.parse, tc.version, { strict = true })) end) end end) end) - describe('eq()', function() - local testcases = { - { - v1 = '1.0.0', - v2 = '1.0.0', - want = true, - }, - { - v1 = '1.0.0', - v2 = 'v1.0.0', - want = true, - }, - { - v1 = '1.0.0', - v2 = '1.0', - want = true, - }, - { - v1 = '1.0.0', - v2 = '1', - want = true, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.0-alpha', - want = true, - }, - { - v1 = '1.0.0-alpha', - v2 = 'v1.0.0-alpha', - want = true, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.0-alpha+build.5', - want = true, - }, - { - v1 = '1.0.0-alpha.1', - v2 = '1.0.0-alpha.1+build.5', - want = true, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.0-alpha.1', - want = false, - }, - { - v1 = '1.0.0', - v2 = '2.0.0', - want = false, - }, - } - - for _, tc in ipairs(testcases) do - it(string.format('returns %s for %s = %s', tostring(tc.want), tc.v1, tc.v2), function() - eq(tc.want, version.eq(tc.v1, tc.v2)) - end) - end - - describe('fails', function() - local failtests = { - { - v1 = '', - v2 = '1.0.0', - err_version = '', - }, - { - v1 = '1.0.0', - v2 = '', - err_version = '', - }, - { - v1 = '', - v2 = '', - err_version = '', - }, - { - v1 = '1.0.0', - v2 = 'foo', - err_version = 'foo', - }, - } - for _, tc in ipairs(failtests) do - it(string.format('for %s = %s', quote_empty(tc.v1), quote_empty(tc.v2)), function() - matches(string.format('invalid version: "%s"', tc.err_version), - pcall_err(version.eq, tc.v1, tc.v2)) - end) - end - end) + it('lt()', function() + eq(true, version.lt('1', '2')) end) - describe('lt()', function() - local testcases = { - { - v1 = '1.0.0', - v2 = '1.0.1', - want = true, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.1', - want = true, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.1-beta', - want = true, - }, - { - v1 = '1.0.1', - v2 = '1.0.0', - want = false, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.0-alpha', - want = false, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.0-alpha+build.5', - want = false, - }, - { - v1 = '1.0.0-alpha+build.4', - v2 = '1.0.0-alpha+build.5', - want = false, - }, - } - for _, tc in ipairs(testcases) do - it(string.format('returns %s for %s < %s', tostring(tc.want), tc.v1, tc.v2), function() - eq(tc.want, version.lt(tc.v1, tc.v2)) - end) - end - - describe('fails', function() - local failtests = { - { - v1 = '', - v2 = '1.0.0', - err_version = '', - }, - { - v1 = '1.0.0', - v2 = '', - err_version = '', - }, - { - v1 = '', - v2 = '', - err_version = '', - }, - } - for _, tc in ipairs(failtests) do - it(string.format('for %s < %s', quote_empty(tc.v1), quote_empty(tc.v2)), function() - matches(string.format('invalid version: "%s"', tc.err_version), - pcall_err(version.lt, tc.v1, tc.v2)) - end) - end - end) + it('gt()', function() + eq(true, version.gt('2', '1')) end) - describe('gt()', function() - local testcases = { - { - v1 = '1.0.1', - v2 = '1.0.0', - want = true, - }, - { - v1 = '1.0.1', - v2 = '1.0.1-alpha', - want = true, - }, - { - v1 = '1.0.0', - v2 = '1.0.1', - want = false, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.1', - want = false, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.1-beta', - want = false, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.0-alpha', - want = false, - }, - { - v1 = '1.0.0-beta', - v2 = '1.0.0-alpha', - want = true, - }, - { - v1 = '1.0.0-alpha', - v2 = '1.0.0-alpha+build.5', - want = false, - }, - { - v1 = '1.0.0-alpha+build.4', - v2 = '1.0.0-alpha+build.5', - want = false, - }, - } - - for _, tc in ipairs(testcases) do - it(string.format('returns %s for %s > %s', tostring(tc.want), tc.v1, tc.v2), function() - eq(tc.want, version.gt(tc.v1, tc.v2)) - end) - end - - describe('fails', function() - local failtests = { - { - v1 = '', - v2 = '1.0.0', - err_version = '', - }, - { - v1 = '1.0.0', - v2 = '', - err_version = '', - }, - { - v1 = '', - v2 = '', - err_version = '', - }, - } - for _, tc in ipairs(failtests) do - it(string.format('for %s < %s', quote_empty(tc.v1), quote_empty(tc.v2)), function() - matches(string.format('invalid version: "%s"', tc.err_version), - pcall_err(version.gt, tc.v1, tc.v2)) - end) - end - end) + it('eq()', function() + eq(true, version.eq('2', '2')) end) end) -- cgit From 79571b92ced968ad27bee2a7515a4a04e84dbad2 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 27 Jan 2021 09:00:28 +0100 Subject: feat(lua): omnifunc for builting lua interpreter also make implicit submodules "uri" and "_inspector" work with completion this is needed for `:lua=vim.uri_` wildmenu completion to work even before uri or _inspector functions are used. --- .../lua/command_line_completion_spec.lua | 7 +++++-- test/functional/lua/vim_spec.lua | 23 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua index 3a5966755e..9a0d534358 100644 --- a/test/functional/lua/command_line_completion_spec.lua +++ b/test/functional/lua/command_line_completion_spec.lua @@ -5,7 +5,7 @@ local eq = helpers.eq local exec_lua = helpers.exec_lua local get_completions = function(input, env) - return exec_lua("return {vim._expand_pat(...)}", '^' .. input, env) + return exec_lua("return {vim._expand_pat(...)}", input, env) end local get_compl_parts = function(parts) @@ -107,9 +107,12 @@ describe('nlua_expand_pat', function() end) it('should work with lazy submodules of "vim" global', function() - eq({{ 'inspect' }, 4 }, + eq({{ 'inspect', 'inspect_pos' }, 4 }, get_completions('vim.inspec')) + eq({{ 'treesitter' }, 4 }, + get_completions('vim.treesi')) + eq({{ 'set' }, 11 }, get_completions('vim.keymap.se')) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index b43e5b28db..77628487ca 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2900,6 +2900,29 @@ describe('lua stdlib', function() end) end) + it('vim.lua_omnifunc', function() + local screen = Screen.new(60,5) + screen:set_default_attr_ids { + [1] = {foreground = Screen.colors.Blue1, bold = true}; + [2] = {background = Screen.colors.WebGray}; + [3] = {background = Screen.colors.LightMagenta}; + [4] = {bold = true}; + [5] = {foreground = Screen.colors.SeaGreen, bold = true}; + } + screen:attach() + command [[ set omnifunc=v:lua.vim.lua_omnifunc ]] + + -- Note: the implementation is shared with lua command line completion. + -- More tests for completion in lua/command_line_completion_spec.lua + feed [[ivim.insp]] + screen:expect{grid=[[ + vim.inspect^ | + {1:~ }{2: inspect }{1: }| + {1:~ }{3: inspect_pos }{1: }| + {1:~ }| + {4:-- Omni completion (^O^N^P) }{5:match 1 of 2} | + ]]} + end) end) describe('lua: builtin modules', function() -- cgit From 89a525de9f2551e460cc91d40fd7afbb7e07622f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 9 Mar 2023 10:19:00 +0800 Subject: fix(buffer_updates): save and restore current window cursor (#16732) When a buffer update callback is called, textlock is active so buffer text cannot be changed, but cursor can still be moved. This can cause problems when the buffer update is in the middle of an operator, like the one mentioned in #16729. The solution is to save cursor position and restore it afterwards, like how cursor is saved and restored when evaluating an mapping. --- test/functional/lua/buffer_updates_spec.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 2fd44b8b5f..b1b39501f7 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -317,7 +317,18 @@ describe('lua buffer event callbacks: on_lines', function() feed('1G0') feed('P') eq(meths.get_var('linesev'), { "lines", 1, 6, 0, 3, 3, 9 }) + end) + it('calling nvim_buf_call() from callback does not cause Normal mode CTRL-A to misbehave #16729', function() + exec_lua([[ + vim.api.nvim_buf_attach(0, false, { + on_lines = function(...) + vim.api.nvim_buf_call(0, function() end) + end, + }) + ]]) + feed('itest123') + eq('test124', meths.get_current_line()) end) end) -- cgit From 2748202e0eb28574cdc65dcb758adea89023271d Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 11 Mar 2023 16:52:46 +0900 Subject: fix(diff): trigger on_bytes only once after diffget/diffput Problem: The fix from b50ee4a8dc4306e4be78ac33fb74b21dc6be5538 may adjust extmark twice, triggering on_bytes callback twice. Solution: Don't let mark_adjust adjust extmark. --- test/functional/lua/buffer_updates_spec.lua | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index b1b39501f7..2cd3123dcd 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -1171,6 +1171,25 @@ describe('lua: nvim_buf_attach on_bytes', function() } end) + it('works with :diffput and :diffget', function() + local check_events = setup_eventcheck(verify, {"AAA"}) + command('diffthis') + command('new') + command('diffthis') + meths.buf_set_lines(0, 0, -1, true, {"AAA", "BBB"}) + feed('G') + command('diffput') + check_events { + { "test1", "bytes", 1, 3, 1, 0, 4, 0, 0, 0, 1, 0, 4 }; + } + meths.buf_set_lines(0, 0, -1, true, {"AAA", "CCC"}) + feed('pG') + command('diffget') + check_events { + { "test1", "bytes", 1, 4, 1, 0, 4, 1, 0, 4, 1, 0, 4 }; + } + end) + local function test_lockmarks(mode) local description = (mode ~= "") and mode or "(baseline)" it("test_lockmarks " .. description .. " %delete _", function() -- cgit From 673d2b52fa4335aa083c52e6686f0728e25b8ebd Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 7 Mar 2023 16:04:57 +0100 Subject: refactor!: rename vim.pretty_print => vim.print Problem: The function name `vim.pretty_print`: 1. is verbose, which partially defeats its purpose as sugar 2. does not draw from existing precedent or any sort of convention (except external projects like penlight or python?), which reduces discoverability, and degrades signaling about best practices. Solution: - Rename to `vim.print`. - Change the behavior so that 1. strings are printed without quotes 2. each arg is printed on its own line 3. tables are indented with 2 instead of 4 spaces - Example: :lua ='a', 'b', 42, {a=3} a b 42 { a = 3 } Comparison of alternatives: - `vim.print`: - pro: consistent with Lua's `print()` - pro: aligns with potential `nvim_print` API function which will replace nvim_echo, nvim_notify, etc. - con: behaves differently than Lua's `print()`, slightly misleading? - `vim.echo`: - pro: `:echo` has similar "pretty print" behavior. - con: inconsistent with Lua idioms. - `vim.p`: - pro: very short, fits with `vim.o`, etc. - con: not as discoverable as "echo" - con: less opportunity for `local p = vim.p` because of potential shadowing. --- test/functional/lua/commands_spec.lua | 30 +++++++++++++++++++----------- test/functional/lua/vim_spec.lua | 21 ++++++++++++++++++++- 2 files changed, 39 insertions(+), 12 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index b8346df290..943095c51e 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -8,6 +8,8 @@ local eval = helpers.eval local feed = helpers.feed local clear = helpers.clear local meths = helpers.meths +local exec_lua = helpers.exec_lua +local exec_capture = helpers.exec_capture local funcs = helpers.funcs local source = helpers.source local dedent = helpers.dedent @@ -15,7 +17,6 @@ local command = helpers.command local exc_exec = helpers.exc_exec local pcall_err = helpers.pcall_err local write_file = helpers.write_file -local exec_capture = helpers.exec_capture local curbufmeths = helpers.curbufmeths local remove_trace = helpers.remove_trace @@ -142,22 +143,29 @@ describe(':lua command', function() ]]} end) - it('Can print results of =expr', function() - helpers.exec_lua("x = 5") - eq("5", helpers.exec_capture(':lua =x')) - helpers.exec_lua("function x() return 'hello' end") - eq([["hello"]], helpers.exec_capture(':lua = x()')) - helpers.exec_lua("x = {a = 1, b = 2}") - eq("{\n a = 1,\n b = 2\n}", helpers.exec_capture(':lua =x')) - helpers.exec_lua([[function x(success) + it('prints result of =expr', function() + exec_lua("x = 5") + eq("5", exec_capture(':lua =x')) + exec_lua("function x() return 'hello' end") + eq('hello', exec_capture(':lua = x()')) + exec_lua("x = {a = 1, b = 2}") + eq("{\n a = 1,\n b = 2\n}", exec_capture(':lua =x')) + exec_lua([[function x(success) if success then return true, "Return value" else return false, nil, "Error message" end end]]) - eq([[true "Return value"]], helpers.exec_capture(':lua =x(true)')) - eq([[false nil "Error message"]], helpers.exec_capture(':lua =x(false)')) + eq(dedent[[ + true + Return value]], + exec_capture(':lua =x(true)')) + eq(dedent[[ + false + nil + Error message]], + exec_capture(':lua =x(false)')) end) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 77628487ca..470102df5e 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -6,6 +6,7 @@ local nvim_prog = helpers.nvim_prog local funcs = helpers.funcs local meths = helpers.meths local command = helpers.command +local dedent = helpers.dedent local insert = helpers.insert local clear = helpers.clear local eq = helpers.eq @@ -2269,7 +2270,7 @@ describe('lua stdlib', function() describe('vim.region', function() it('charwise', function() - insert(helpers.dedent( [[ + insert(dedent( [[ text tααt tααt text text tαxt txtα tex text tαxt tαxt @@ -2923,6 +2924,24 @@ describe('lua stdlib', function() {4:-- Omni completion (^O^N^P) }{5:match 1 of 2} | ]]} end) + + it('vim.print', function() + -- vim.print() returns its args. + eq({42, 'abc', { a = { b = 77 }}}, + exec_lua[[return {vim.print(42, 'abc', { a = { b = 77 }})}]]) + + -- vim.print() pretty-prints the args. + eq(dedent[[ + + 42 + abc + { + a = { + b = 77 + } + }]], + eval[[execute('lua vim.print(42, "abc", { a = { b = 77 }})')]]) + end) end) describe('lua: builtin modules', function() -- cgit From 210120dde81ec289ae01e1d247df08f0b147c08a Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 15 Mar 2023 08:56:13 -0400 Subject: fix(lua): vim.deprecate() shows ":help deprecated" #22677 Problem: vim.deprecate() shows ":help deprecated" for third-party plugins. ":help deprecated" only describes deprecations in Nvim, and is unrelated to any 3rd party deprecations. Solution: If `plugin` is specified, don't show ":help deprecated". fix #22235 --- test/functional/lua/vim_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 470102df5e..0483ec46f0 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -127,6 +127,22 @@ describe('lua stdlib', function() eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")')) end) + it('vim.deprecate', function() + -- vim.deprecate(name, alternative, version, plugin, backtrace) + eq(dedent[[ + foo.bar() is deprecated, use zub.wooo{ok=yay} instead. :help deprecated + This feature will be removed in Nvim version 2.17]], + exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', '2.17')) + -- Same message, skipped. + eq(vim.NIL, + exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', '2.17')) + -- When `plugin` is specified, don't show ":help deprecated". #22235 + eq(dedent[[ + foo.bar() is deprecated, use zub.wooo{ok=yay} instead. + This feature will be removed in my-plugin.nvim version 0.3.0]], + exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', '0.3.0', 'my-plugin.nvim', false)) + end) + it('vim.startswith', function() eq(true, funcs.luaeval('vim.startswith("123", "1")')) eq(true, funcs.luaeval('vim.startswith("123", "")')) -- cgit From c6f8af36e134a67b489d59e078425cada5eafd7b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 18 Mar 2023 09:55:08 +0800 Subject: fix(spell): properly source spell/LANG.{vim,lua} (#22716) Using regexp doesn't work here because there are no wildcards. --- test/functional/lua/runtime_spec.lua | 37 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index 884ef3ef8e..72c99ac1f3 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -36,10 +36,12 @@ describe('runtime:', function() describe('colors', function() local colorscheme_folder = plug_dir .. sep .. 'colors' + before_each(function() + mkdir_p(colorscheme_folder) + end) it('loads lua colorscheme', function() local colorscheme_file = colorscheme_folder .. sep .. 'new_colorscheme.lua' - mkdir_p(colorscheme_folder) write_file(colorscheme_file, [[vim.g.lua_colorscheme = 1]]) eq({'new_colorscheme'}, funcs.getcompletion('new_c', 'color')) @@ -48,28 +50,27 @@ describe('runtime:', function() exec('colorscheme new_colorscheme') eq(1, eval('g:lua_colorscheme')) - rmdir(colorscheme_folder) end) it('loads vim colorscheme when both lua and vim version exist', function() local colorscheme_file = colorscheme_folder .. sep .. 'new_colorscheme' - mkdir_p(colorscheme_folder) write_file(colorscheme_file..'.vim', [[let g:colorscheme = 'vim']]) write_file(colorscheme_file..'.lua', [[vim.g.colorscheme = 'lua']]) exec('colorscheme new_colorscheme') eq('vim', eval('g:colorscheme')) - rmdir(colorscheme_folder) end) end) describe('compiler', function() local compiler_folder = plug_dir .. sep .. 'compiler' + before_each(function() + mkdir_p(compiler_folder) + end) it('loads lua compilers', function() local compiler_file = compiler_folder .. sep .. 'new_compiler.lua' - mkdir_p(compiler_folder) write_file(compiler_file, [[vim.b.lua_compiler = 1]]) eq({'new_compiler'}, funcs.getcompletion('new_c', 'compiler')) @@ -78,19 +79,16 @@ describe('runtime:', function() exec('compiler new_compiler') eq(1, eval('b:lua_compiler')) - rmdir(compiler_folder) end) it('loads vim compilers when both lua and vim version exist', function() local compiler_file = compiler_folder .. sep .. 'new_compiler' - mkdir_p(compiler_folder) write_file(compiler_file..'.vim', [[let b:compiler = 'vim']]) write_file(compiler_file..'.lua', [[vim.b.compiler = 'lua']]) exec('compiler new_compiler') eq('vim', eval('b:compiler')) - rmdir(compiler_folder) end) end) @@ -98,8 +96,8 @@ describe('runtime:', function() local ftplugin_folder = table.concat({plug_dir, 'ftplugin'}, sep) it('loads lua ftplugins', function() - local ftplugin_file = table.concat({ftplugin_folder , 'new-ft.lua'}, sep) mkdir_p(ftplugin_folder) + local ftplugin_file = table.concat({ftplugin_folder , 'new-ft.lua'}, sep) write_file(ftplugin_file , [[vim.b.lua_ftplugin = 1]]) eq({'new-ft'}, funcs.getcompletion('new-f', 'filetype')) @@ -107,7 +105,6 @@ describe('runtime:', function() exec [[set filetype=new-ft]] eq(1, eval('b:lua_ftplugin')) - rmdir(ftplugin_folder) end) end) @@ -115,8 +112,8 @@ describe('runtime:', function() local indent_folder = table.concat({plug_dir, 'indent'}, sep) it('loads lua indents', function() - local indent_file = table.concat({indent_folder , 'new-ft.lua'}, sep) mkdir_p(indent_folder) + local indent_file = table.concat({indent_folder , 'new-ft.lua'}, sep) write_file(indent_file , [[vim.b.lua_indent = 1]]) eq({'new-ft'}, funcs.getcompletion('new-f', 'filetype')) @@ -124,7 +121,6 @@ describe('runtime:', function() exec [[set filetype=new-ft]] eq(1, eval('b:lua_indent')) - rmdir(indent_folder) end) end) @@ -132,8 +128,8 @@ describe('runtime:', function() local syntax_folder = table.concat({plug_dir, 'syntax'}, sep) before_each(function() - local syntax_file = table.concat({syntax_folder , 'my-lang.lua'}, sep) mkdir_p(syntax_folder) + local syntax_file = table.concat({syntax_folder , 'my-lang.lua'}, sep) write_file(syntax_file , [[vim.b.current_syntax = 'my-lang']]) exec([[let b:current_syntax = '']]) end) @@ -161,5 +157,20 @@ describe('runtime:', function() end) end) + describe('spell', function() + local spell_folder = table.concat({plug_dir, 'spell'}, sep) + + it('loads spell/LANG.{vim,lua}', function() + mkdir_p(spell_folder) + local spell_vim = table.concat({spell_folder , 'Xtest.vim'}, sep) + write_file(spell_vim , [[let b:spell_vim = 1]]) + local spell_lua = table.concat({spell_folder , 'Xtest.lua'}, sep) + write_file(spell_lua , [[vim.b.spell_lua = 1]]) + exec('set spelllang=Xtest') + eq(1, eval('b:spell_vim')) + eq(1, eval('b:spell_lua')) + end) + end) + end) -- cgit From e5641df6d3fc3bb6c3c55593b6152082bfc561b6 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 11 Mar 2023 17:11:02 +0000 Subject: feat: add `vim.filetype.get_option()` --- test/functional/lua/filetype_spec.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index add69235b6..540eae1c9b 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -114,6 +114,21 @@ describe('vim.filetype', function() ]]) end) + it('can get default option values for filetypes via vim.filetype.get_option()', function() + command('filetype plugin on') + + for ft, opts in pairs { + lua = { commentstring = '-- %s' }, + vim = { commentstring = '"%s' }, + man = { tagfunc = 'v:lua.require\'man\'.goto_tag' }, + xml = { formatexpr = 'xmlformat#Format()' } + } do + for option, value in pairs(opts) do + eq(value, exec_lua([[ return vim.filetype.get_option(...) ]], ft, option)) + end + end + + end) end) describe('filetype.lua', function() -- cgit From 990c481551af2b346f315d75aa0815e9b65051f3 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 16 Mar 2023 14:50:20 +0100 Subject: refactor(vim.version): use lazy.nvim semver module Use semver code from https://github.com/folke/lazy.nvim License: Apache License 2.0 Co-authored-by: Folke Lemaitre --- test/functional/lua/version_spec.lua | 120 +++++++++++++++++++++++++++++++---- 1 file changed, 109 insertions(+), 11 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index b68727ca77..2901646e66 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -6,17 +6,115 @@ local matches = helpers.matches local pcall_err = helpers.pcall_err local version = require('vim.version') +local Semver = version.LazyM local function quote_empty(s) return tostring(s) == '' and '""' or tostring(s) end +local function v(ver) + return Semver.parse(ver) +end + describe('version', function() + it('package', function() clear() eq({ major = 42, minor = 3, patch = 99 }, exec_lua("return vim.version.parse('v42.3.99')")) end) + describe('semver version', function() + local tests = { + ['v1.2.3'] = { major = 1, minor = 2, patch = 3 }, + ['v1.2'] = { major = 1, minor = 2, patch = 0 }, + ['v1.2.3-prerelease'] = { major = 1, minor = 2, patch = 3, prerelease = 'prerelease' }, + ['v1.2-prerelease'] = { major = 1, minor = 2, patch = 0, prerelease = 'prerelease' }, + ['v1.2.3-prerelease+build'] = { major = 1, minor = 2, patch = 3, prerelease = 'prerelease', build = "build" }, + ['1.2.3+build'] = { major = 1, minor = 2, patch = 3, build = 'build' }, + } + for input, output in pairs(tests) do + it('parses ' .. input, function() + assert.same(output, v(input)) + end) + end + end) + + describe('semver range', function() + local tests = { + ['1.2.3'] = { from = { 1, 2, 3 }, to = { 1, 2, 4 } }, + ['1.2'] = { from = { 1, 2, 0 }, to = { 1, 3, 0 } }, + ['=1.2.3'] = { from = { 1, 2, 3 }, to = { 1, 2, 4 } }, + ['>1.2.3'] = { from = { 1, 2, 4 } }, + ['>=1.2.3'] = { from = { 1, 2, 3 } }, + ['~1.2.3'] = { from = { 1, 2, 3 }, to = { 1, 3, 0 } }, + ['^1.2.3'] = { from = { 1, 2, 3 }, to = { 2, 0, 0 } }, + ['^0.2.3'] = { from = { 0, 2, 3 }, to = { 0, 3, 0 } }, + ['^0.0.1'] = { from = { 0, 0, 1 }, to = { 0, 0, 2 } }, + ['^1.2'] = { from = { 1, 2, 0 }, to = { 2, 0, 0 } }, + ['~1.2'] = { from = { 1, 2, 0 }, to = { 1, 3, 0 } }, + ['~1'] = { from = { 1, 0, 0 }, to = { 2, 0, 0 } }, + ['^1'] = { from = { 1, 0, 0 }, to = { 2, 0, 0 } }, + ['1.*'] = { from = { 1, 0, 0 }, to = { 2, 0, 0 } }, + ['1'] = { from = { 1, 0, 0 }, to = { 2, 0, 0 } }, + ['1.x'] = { from = { 1, 0, 0 }, to = { 2, 0, 0 } }, + ['1.2.x'] = { from = { 1, 2, 0 }, to = { 1, 3, 0 } }, + ['1.2.*'] = { from = { 1, 2, 0 }, to = { 1, 3, 0 } }, + ['*'] = { from = { 0, 0, 0 } }, + ['1.2 - 2.3.0'] = { from = { 1, 2, 0 }, to = { 2, 3, 0 } }, + ['1.2.3 - 2.3.4'] = { from = { 1, 2, 3 }, to = { 2, 3, 4 } }, + ['1.2.3 - 2'] = { from = { 1, 2, 3 }, to = { 3, 0, 0 } }, + } + for input, output in pairs(tests) do + output.from = v(output.from) + output.to = output.to and v(output.to) + + local range = Semver.range(input) + it('parses ' .. input, function() + assert.same(output, range) + end) + + it('[from] in range ' .. input, function() + assert(range:matches(output.from)) + end) + + it('[from-1] not in range ' .. input, function() + local lower = vim.deepcopy(range.from) + lower.major = lower.major - 1 + assert(not range:matches(lower)) + end) + + it('[to] not in range ' .. input .. ' to:' .. tostring(range.to), function() + if range.to then + assert(not (range.to < range.to)) + assert(not range:matches(range.to)) + end + end) + end + + it("handles prerelease", function() + assert(not Semver.range('1.2.3'):matches('1.2.3-alpha')) + assert(Semver.range('1.2.3-alpha'):matches('1.2.3-alpha')) + assert(not Semver.range('1.2.3-alpha'):matches('1.2.3-beta')) + end) + end) + + describe('semver order', function() + it('is correct', function() + assert(v('v1.2.3') == v('1.2.3')) + assert(not (v('v1.2.3') < v('1.2.3'))) + assert(v('v1.2.3') > v('1.2.3-prerelease')) + assert(v('v1.2.3-alpha') < v('1.2.3-beta')) + assert(v('v1.2.3-prerelease') < v('1.2.3')) + assert(v('v1.2.3') >= v('1.2.3')) + assert(v('v1.2.3') >= v('1.0.3')) + assert(v('v1.2.3') >= v('1.2.2')) + assert(v('v1.2.3') > v('1.2.2')) + assert(v('v1.2.3') > v('1.0.3')) + assert.same(Semver.last({ v('1.2.3'), v('2.0.0') }), v('2.0.0')) + assert.same(Semver.last({ v('2.0.0'), v('1.2.3') }), v('2.0.0')) + end) + end) + describe('cmp()', function() local testcases = { { @@ -205,16 +303,6 @@ describe('version', function() version = 'v1.2.3', want = { major = 1, minor = 2, patch = 3 }, }, - { - desc = 'valid version with leading "v" and whitespace', - version = ' v1.2.3', - want = { major = 1, minor = 2, patch = 3 }, - }, - { - desc = 'valid version with leading "v" and trailing whitespace', - version = 'v1.2.3 ', - want = { major = 1, minor = 2, patch = 3 }, - }, { desc = 'version with prerelease', version = '1.2.3-alpha', @@ -246,7 +334,7 @@ describe('version', function() it( string.format('for %q: version = %q', tc.desc, tc.version), function() - eq(tc.want, version.parse(tc.version, { strict = true })) + eq(tc.want, Semver.parse(tc.version)) end ) end @@ -274,6 +362,16 @@ describe('version', function() version = '1-1.0', want = { major = 1, minor = 0, patch = 0, prerelease = '1.0' }, }, + { + desc = 'valid version with leading "v" and trailing whitespace', + version = 'v1.2.3 ', + want = { major = 1, minor = 2, patch = 3 }, + }, + { + desc = 'valid version with leading "v" and whitespace', + version = ' v1.2.3', + want = { major = 1, minor = 2, patch = 3 }, + }, } for _, tc in ipairs(testcases) do it( -- cgit From a715e6f87eede36775d0921b3537c7c57a82890a Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 16 Mar 2023 22:49:12 +0100 Subject: refactor(vim.version): use lazy.nvim semver module Now the Nvim version string "v0.9.0-dev-1233+g210120dde81e" parses correctly. --- test/functional/lua/version_spec.lua | 320 +++++++++-------------------------- 1 file changed, 82 insertions(+), 238 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index 2901646e66..2fb02795b2 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq +local ok = helpers.ok local exec_lua = helpers.exec_lua local matches = helpers.matches local pcall_err = helpers.pcall_err @@ -8,12 +9,8 @@ local pcall_err = helpers.pcall_err local version = require('vim.version') local Semver = version.LazyM -local function quote_empty(s) - return tostring(s) == '' and '""' or tostring(s) -end - local function v(ver) - return Semver.parse(ver) + return Semver.version(ver) end describe('version', function() @@ -23,7 +20,7 @@ describe('version', function() eq({ major = 42, minor = 3, patch = 99 }, exec_lua("return vim.version.parse('v42.3.99')")) end) - describe('semver version', function() + describe('lazy semver version', function() local tests = { ['v1.2.3'] = { major = 1, minor = 2, patch = 3 }, ['v1.2'] = { major = 1, minor = 2, patch = 0 }, @@ -34,12 +31,12 @@ describe('version', function() } for input, output in pairs(tests) do it('parses ' .. input, function() - assert.same(output, v(input)) + eq(output, v(input)) end) end end) - describe('semver range', function() + describe('lazy semver range', function() local tests = { ['1.2.3'] = { from = { 1, 2, 3 }, to = { 1, 2, 4 } }, ['1.2'] = { from = { 1, 2, 0 }, to = { 1, 3, 0 } }, @@ -70,7 +67,7 @@ describe('version', function() local range = Semver.range(input) it('parses ' .. input, function() - assert.same(output, range) + eq(output, range) end) it('[from] in range ' .. input, function() @@ -83,7 +80,7 @@ describe('version', function() assert(not range:matches(lower)) end) - it('[to] not in range ' .. input .. ' to:' .. tostring(range.to), function() + it('[to] not in range ' .. input .. ' to:' .. tostring(range and range.to), function() if range.to then assert(not (range.to < range.to)) assert(not range:matches(range.to)) @@ -98,7 +95,7 @@ describe('version', function() end) end) - describe('semver order', function() + describe('lazy semver order', function() it('is correct', function() assert(v('v1.2.3') == v('1.2.3')) assert(not (v('v1.2.3') < v('1.2.3'))) @@ -110,175 +107,48 @@ describe('version', function() assert(v('v1.2.3') >= v('1.2.2')) assert(v('v1.2.3') > v('1.2.2')) assert(v('v1.2.3') > v('1.0.3')) - assert.same(Semver.last({ v('1.2.3'), v('2.0.0') }), v('2.0.0')) - assert.same(Semver.last({ v('2.0.0'), v('1.2.3') }), v('2.0.0')) + eq(version.last({ v('1.2.3'), v('2.0.0') }), v('2.0.0')) + eq(version.last({ v('2.0.0'), v('1.2.3') }), v('2.0.0')) end) end) describe('cmp()', function() local testcases = { - { - desc = '(v1 < v2)', - v1 = 'v0.0.99', - v2 = 'v9.0.0', - want = -1, - }, - { - desc = '(v1 < v2)', - v1 = 'v0.4.0', - v2 = 'v0.9.99', - want = -1, - }, - { - desc = '(v1 < v2)', - v1 = 'v0.2.8', - v2 = 'v1.0.9', - want = -1, - }, - { - desc = '(v1 == v2)', - v1 = 'v0.0.0', - v2 = 'v0.0.0', - want = 0, - }, - { - desc = '(v1 > v2)', - v1 = 'v9.0.0', - v2 = 'v0.9.0', - want = 1, - }, - { - desc = '(v1 > v2)', - v1 = 'v0.9.0', - v2 = 'v0.0.0', - want = 1, - }, - { - desc = '(v1 > v2)', - v1 = 'v0.0.9', - v2 = 'v0.0.0', - want = 1, - }, - { - desc = '(v1 < v2) when v1 has prerelease', - v1 = 'v1.0.0-alpha', - v2 = 'v1.0.0', - want = -1, - }, - { - desc = '(v1 > v2) when v2 has prerelease', - v1 = '1.0.0', - v2 = '1.0.0-alpha', - want = 1, - }, - { - desc = '(v1 > v2) when v1 has a higher number identifier', - v1 = '1.0.0-2', - v2 = '1.0.0-1', - want = 1, - }, - { - desc = '(v1 < v2) when v2 has a higher number identifier', - v1 = '1.0.0-2', - v2 = '1.0.0-9', - want = -1, - }, - { - desc = '(v1 < v2) when v2 has more identifiers', - v1 = '1.0.0-2', - v2 = '1.0.0-2.0', - want = -1, - }, - { - desc = '(v1 > v2) when v1 has more identifiers', - v1 = '1.0.0-2.0', - v2 = '1.0.0-2', - want = 1, - }, - { - desc = '(v1 == v2) when v2 has same numeric identifiers', - v1 = '1.0.0-2.0', - v2 = '1.0.0-2.0', - want = 0, - }, - { - desc = '(v1 == v2) when v2 has same alphabet identifiers', - v1 = '1.0.0-alpha', - v2 = '1.0.0-alpha', - want = 0, - }, - { - desc = '(v1 < v2) when v2 has an alphabet identifier with higher ASCII sort order', - v1 = '1.0.0-alpha', - v2 = '1.0.0-beta', - want = -1, - }, - { - desc = '(v1 > v2) when v1 has an alphabet identifier with higher ASCII sort order', - v1 = '1.0.0-beta', - v2 = '1.0.0-alpha', - want = 1, - }, - { - desc = '(v1 < v2) when v2 has prerelease and number identifer', - v1 = '1.0.0-alpha', - v2 = '1.0.0-alpha.1', - want = -1, - }, - { - desc = '(v1 > v2) when v1 has prerelease and number identifer', - v1 = '1.0.0-alpha.1', - v2 = '1.0.0-alpha', - want = 1, - }, - { - desc = '(v1 > v2) when v1 has an additional alphabet identifier', - v1 = '1.0.0-alpha.beta', - v2 = '1.0.0-alpha', - want = 1, - }, - { - desc = '(v1 < v2) when v2 has an additional alphabet identifier', - v1 = '1.0.0-alpha', - v2 = '1.0.0-alpha.beta', - want = -1, - }, - { - desc = '(v1 < v2) when v2 has an a first alphabet identifier with higher precedence', - v1 = '1.0.0-alpha.beta', - v2 = '1.0.0-beta', - want = -1, - }, - { - desc = '(v1 > v2) when v1 has an a first alphabet identifier with higher precedence', - v1 = '1.0.0-beta', - v2 = '1.0.0-alpha.beta', - want = 1, - }, - { - desc = '(v1 < v2) when v2 has an additional number identifer', - v1 = '1.0.0-beta', - v2 = '1.0.0-beta.2', - want = -1, - }, - { - desc = '(v1 < v2) when v2 has same first alphabet identifier but has a higher number identifer', - v1 = '1.0.0-beta.2', - v2 = '1.0.0-beta.11', - want = -1, - }, - { - desc = '(v1 < v2) when v2 has higher alphabet precedence', - v1 = '1.0.0-beta.11', - v2 = '1.0.0-rc.1', - want = -1, - }, + { v1 = 'v0.0.99', v2 = 'v9.0.0', want = -1, }, + { v1 = 'v0.4.0', v2 = 'v0.9.99', want = -1, }, + { v1 = 'v0.2.8', v2 = 'v1.0.9', want = -1, }, + { v1 = 'v0.0.0', v2 = 'v0.0.0', want = 0, }, + { v1 = 'v9.0.0', v2 = 'v0.9.0', want = 1, }, + { v1 = 'v0.9.0', v2 = 'v0.0.0', want = 1, }, + { v1 = 'v0.0.9', v2 = 'v0.0.0', want = 1, }, + { v1 = 'v1.0.0-alpha', v2 = 'v1.0.0', want = -1, }, + { v1 = '1.0.0', v2 = '1.0.0-alpha', want = 1, }, + { v1 = '1.0.0-2', v2 = '1.0.0-1', want = 1, }, + { v1 = '1.0.0-2', v2 = '1.0.0-9', want = -1, }, + { v1 = '1.0.0-2', v2 = '1.0.0-2.0', want = -1, }, + { v1 = '1.0.0-2.0', v2 = '1.0.0-2', want = 1, }, + { v1 = '1.0.0-2.0', v2 = '1.0.0-2.0', want = 0, }, + { v1 = '1.0.0-alpha', v2 = '1.0.0-alpha', want = 0, }, + { v1 = '1.0.0-alpha', v2 = '1.0.0-beta', want = -1, }, + { v1 = '1.0.0-beta', v2 = '1.0.0-alpha', want = 1, }, + { v1 = '1.0.0-alpha', v2 = '1.0.0-alpha.1', want = -1, }, + { v1 = '1.0.0-alpha.1', v2 = '1.0.0-alpha', want = 1, }, + { v1 = '1.0.0-alpha.beta', v2 = '1.0.0-alpha', want = 1, }, + { v1 = '1.0.0-alpha', v2 = '1.0.0-alpha.beta', want = -1, }, + { v1 = '1.0.0-alpha.beta', v2 = '1.0.0-beta', want = -1, }, + { v1 = '1.0.0-beta', v2 = '1.0.0-alpha.beta', want = 1, }, + { v1 = '1.0.0-beta', v2 = '1.0.0-beta.2', want = -1, }, + -- TODO + -- { v1 = '1.0.0-beta.2', v2 = '1.0.0-beta.11', want = -1, }, + { v1 = '1.0.0-beta.11', v2 = '1.0.0-rc.1', want = -1, }, } for _, tc in ipairs(testcases) do - it( - string.format('%d %s (v1 = %s, v2 = %s)', tc.want, tc.desc, tc.v1, tc.v2), + local want = ('v1 %s v2'):format(tc.want == 0 and '==' or (tc.want == 1 and '>' or '<')) + it(string.format('(v1 = %s, v2 = %s)', tc.v1, tc.v2), function() - eq(tc.want, version.cmp(tc.v1, tc.v2, { strict = true })) + local rv = version.cmp(tc.v1, tc.v2, { strict = true }) + local got = ('v1 %s v2'):format(rv == 0 and '==' or (rv == 1 and '>' or '<')) + ok(tc.want == rv, want, got) end ) end @@ -288,53 +158,46 @@ describe('version', function() describe('strict=true', function() local testcases = { { - desc = 'version without leading "v"', + desc = 'Nvim version', + version = 'v0.9.0-dev-1233+g210120dde81e', + want = { major = 0, minor = 9, patch = 0, prerelease = 'dev-1233', build = 'g210120dde81e', }, + }, + { + desc = 'no leading v', version = '10.20.123', - want = { - major = 10, - minor = 20, - patch = 123, - prerelease = nil, - build = nil, - }, + want = { major = 10, minor = 20, patch = 123, prerelease = nil, build = nil, }, }, { - desc = 'valid version with leading "v"', + desc = 'leading v', version = 'v1.2.3', want = { major = 1, minor = 2, patch = 3 }, }, { - desc = 'version with prerelease', + desc = 'prerelease', version = '1.2.3-alpha', want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha' }, }, { - desc = 'version with prerelease with additional identifiers', + desc = 'prerelease and other identifiers', version = '1.2.3-alpha.1', want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha.1' }, }, { - desc = 'version with build', + desc = 'build', version = '1.2.3+build.15', want = { major = 1, minor = 2, patch = 3, build = 'build.15' }, }, { - desc = 'version with prerelease and build', + desc = 'prerelease and build', version = '1.2.3-rc1+build.15', - want = { - major = 1, - minor = 2, - patch = 3, - prerelease = 'rc1', - build = 'build.15', - }, + want = { major = 1, minor = 2, patch = 3, prerelease = 'rc1', build = 'build.15', }, }, } for _, tc in ipairs(testcases) do it( - string.format('for %q: version = %q', tc.desc, tc.version), + string.format('%q: version = %q', tc.desc, tc.version), function() - eq(tc.want, Semver.parse(tc.version)) + eq(tc.want, version.parse(tc.version)) end ) end @@ -342,40 +205,16 @@ describe('version', function() describe('strict=false', function() local testcases = { - { - desc = 'version missing patch version', - version = '1.2', - want = { major = 1, minor = 2, patch = 0 }, - }, - { - desc = 'version missing minor and patch version', - version = '1', - want = { major = 1, minor = 0, patch = 0 }, - }, - { - desc = 'version missing patch version with prerelease', - version = '1.1-0', - want = { major = 1, minor = 1, patch = 0, prerelease = '0' }, - }, - { - desc = 'version missing minor and patch version with prerelease', - version = '1-1.0', - want = { major = 1, minor = 0, patch = 0, prerelease = '1.0' }, - }, - { - desc = 'valid version with leading "v" and trailing whitespace', - version = 'v1.2.3 ', - want = { major = 1, minor = 2, patch = 3 }, - }, - { - desc = 'valid version with leading "v" and whitespace', - version = ' v1.2.3', - want = { major = 1, minor = 2, patch = 3 }, - }, + { version = '1.2', want = { major = 1, minor = 2, patch = 0 }, }, + { version = '1', want = { major = 1, minor = 0, patch = 0 }, }, + { version = '1.1-0', want = { major = 1, minor = 1, patch = 0, prerelease = '0' }, }, + { version = '1-1.0', want = { major = 1, minor = 0, patch = 0, prerelease = '1.0' }, }, + { version = 'v1.2.3 ', want = { major = 1, minor = 2, patch = 3 }, }, + { version = ' v1.2.3', want = { major = 1, minor = 2, patch = 3 }, }, } for _, tc in ipairs(testcases) do it( - string.format('for %q: version = %q', tc.desc, tc.version), + string.format('version = %q', tc.version), function() eq(tc.want, version.parse(tc.version, { strict = false })) end @@ -385,21 +224,26 @@ describe('version', function() describe('invalid semver', function() local testcases = { - { desc = 'a word', version = 'foo' }, - { desc = 'empty string', version = '' }, - { desc = 'trailing period character', version = '0.0.0.' }, - { desc = 'leading period character', version = '.0.0.0' }, - { desc = 'negative major version', version = '-1.0.0' }, - { desc = 'negative minor version', version = '0.-1.0' }, - { desc = 'negative patch version', version = '0.0.-1' }, - { desc = 'leading invalid string', version = 'foobar1.2.3' }, - { desc = 'trailing invalid string', version = '1.2.3foobar' }, - { desc = 'an invalid prerelease', version = '1.2.3-%?' }, - { desc = 'an invalid build', version = '1.2.3+%?' }, - { desc = 'build metadata before prerelease', version = '1.2.3+build.0-rc1' }, + { version = 'foo' }, + { version = '' }, + { version = '0.0.0.' }, + { version = '.0.0.0' }, + { version = '-1.0.0' }, + { version = '0.-1.0' }, + { version = '0.0.-1' }, + { version = 'foobar1.2.3' }, + { version = '1.2.3foobar' }, + { version = '1.2.3-%?' }, + { version = '1.2.3+%?' }, + { version = '1.2.3+build.0-rc1' }, } + + local function quote_empty(s) + return tostring(s) == '' and '""' or tostring(s) + end + for _, tc in ipairs(testcases) do - it(string.format('(%s): %s', tc.desc, quote_empty(tc.version)), function() + it(quote_empty(tc.version), function() eq(nil, version.parse(tc.version, { strict = true })) end) end -- cgit From a40eb7cc991eb4f8b89f467e8e42563868efa76b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 17 Mar 2023 01:12:33 +0100 Subject: feat(vim.version): more coercion with strict=false Problem: "tmux 3.2a" (output from "tmux -V") is not parsed easily. Solution: With `strict=false`, discard everything before the first digit. - rename Semver => Version - rename vim.version.version() => vim.version._version() - rename matches() => has() - remove `opts` from cmp() --- test/functional/lua/version_spec.lua | 133 ++++++++++++++--------------------- 1 file changed, 54 insertions(+), 79 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index 2fb02795b2..014fea5272 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -6,11 +6,8 @@ local exec_lua = helpers.exec_lua local matches = helpers.matches local pcall_err = helpers.pcall_err -local version = require('vim.version') -local Semver = version.LazyM - local function v(ver) - return Semver.version(ver) + return vim.version._version(ver) end describe('version', function() @@ -20,13 +17,13 @@ describe('version', function() eq({ major = 42, minor = 3, patch = 99 }, exec_lua("return vim.version.parse('v42.3.99')")) end) - describe('lazy semver version', function() + describe('_version()', function() local tests = { ['v1.2.3'] = { major = 1, minor = 2, patch = 3 }, ['v1.2'] = { major = 1, minor = 2, patch = 0 }, ['v1.2.3-prerelease'] = { major = 1, minor = 2, patch = 3, prerelease = 'prerelease' }, ['v1.2-prerelease'] = { major = 1, minor = 2, patch = 0, prerelease = 'prerelease' }, - ['v1.2.3-prerelease+build'] = { major = 1, minor = 2, patch = 3, prerelease = 'prerelease', build = "build" }, + ['v1.2.3-prerelease+build'] = { major = 1, minor = 2, patch = 3, prerelease = 'prerelease', build = 'build' }, ['1.2.3+build'] = { major = 1, minor = 2, patch = 3, build = 'build' }, } for input, output in pairs(tests) do @@ -36,7 +33,7 @@ describe('version', function() end end) - describe('lazy semver range', function() + describe('range', function() local tests = { ['1.2.3'] = { from = { 1, 2, 3 }, to = { 1, 2, 4 } }, ['1.2'] = { from = { 1, 2, 0 }, to = { 1, 3, 0 } }, @@ -64,51 +61,34 @@ describe('version', function() for input, output in pairs(tests) do output.from = v(output.from) output.to = output.to and v(output.to) + local range = vim.version.range(input) - local range = Semver.range(input) it('parses ' .. input, function() eq(output, range) end) it('[from] in range ' .. input, function() - assert(range:matches(output.from)) + assert(range:has(output.from)) end) it('[from-1] not in range ' .. input, function() local lower = vim.deepcopy(range.from) lower.major = lower.major - 1 - assert(not range:matches(lower)) + assert(not range:has(lower)) end) - it('[to] not in range ' .. input .. ' to:' .. tostring(range and range.to), function() + it('[to] not in range ' .. input .. ' to:' .. tostring(range.to), function() if range.to then assert(not (range.to < range.to)) - assert(not range:matches(range.to)) + assert(not range:has(range.to)) end end) end - it("handles prerelease", function() - assert(not Semver.range('1.2.3'):matches('1.2.3-alpha')) - assert(Semver.range('1.2.3-alpha'):matches('1.2.3-alpha')) - assert(not Semver.range('1.2.3-alpha'):matches('1.2.3-beta')) - end) - end) - - describe('lazy semver order', function() - it('is correct', function() - assert(v('v1.2.3') == v('1.2.3')) - assert(not (v('v1.2.3') < v('1.2.3'))) - assert(v('v1.2.3') > v('1.2.3-prerelease')) - assert(v('v1.2.3-alpha') < v('1.2.3-beta')) - assert(v('v1.2.3-prerelease') < v('1.2.3')) - assert(v('v1.2.3') >= v('1.2.3')) - assert(v('v1.2.3') >= v('1.0.3')) - assert(v('v1.2.3') >= v('1.2.2')) - assert(v('v1.2.3') > v('1.2.2')) - assert(v('v1.2.3') > v('1.0.3')) - eq(version.last({ v('1.2.3'), v('2.0.0') }), v('2.0.0')) - eq(version.last({ v('2.0.0'), v('1.2.3') }), v('2.0.0')) + it('handles prerelease', function() + assert(not vim.version.range('1.2.3'):has('1.2.3-alpha')) + assert(vim.version.range('1.2.3-alpha'):has('1.2.3-alpha')) + assert(not vim.version.range('1.2.3-alpha'):has('1.2.3-beta')) end) end) @@ -143,12 +123,11 @@ describe('version', function() { v1 = '1.0.0-beta.11', v2 = '1.0.0-rc.1', want = -1, }, } for _, tc in ipairs(testcases) do - local want = ('v1 %s v2'):format(tc.want == 0 and '==' or (tc.want == 1 and '>' or '<')) + local msg = function(s) return ('v1 %s v2'):format(s == 0 and '==' or (s == 1 and '>' or '<')) end it(string.format('(v1 = %s, v2 = %s)', tc.v1, tc.v2), function() - local rv = version.cmp(tc.v1, tc.v2, { strict = true }) - local got = ('v1 %s v2'):format(rv == 0 and '==' or (rv == 1 and '>' or '<')) - ok(tc.want == rv, want, got) + local rv = vim.version.cmp(tc.v1, tc.v2, { strict = true }) + ok(tc.want == rv, msg(tc.want), msg(rv)) end ) end @@ -157,47 +136,19 @@ describe('version', function() describe('parse()', function() describe('strict=true', function() local testcases = { - { - desc = 'Nvim version', - version = 'v0.9.0-dev-1233+g210120dde81e', - want = { major = 0, minor = 9, patch = 0, prerelease = 'dev-1233', build = 'g210120dde81e', }, - }, - { - desc = 'no leading v', - version = '10.20.123', - want = { major = 10, minor = 20, patch = 123, prerelease = nil, build = nil, }, - }, - { - desc = 'leading v', - version = 'v1.2.3', - want = { major = 1, minor = 2, patch = 3 }, - }, - { - desc = 'prerelease', - version = '1.2.3-alpha', - want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha' }, - }, - { - desc = 'prerelease and other identifiers', - version = '1.2.3-alpha.1', - want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha.1' }, - }, - { - desc = 'build', - version = '1.2.3+build.15', - want = { major = 1, minor = 2, patch = 3, build = 'build.15' }, - }, - { - desc = 'prerelease and build', - version = '1.2.3-rc1+build.15', - want = { major = 1, minor = 2, patch = 3, prerelease = 'rc1', build = 'build.15', }, - }, + { desc = 'Nvim version', version = 'v0.9.0-dev-1233+g210120dde81e', want = { major = 0, minor = 9, patch = 0, prerelease = 'dev-1233', build = 'g210120dde81e', }, }, + { desc = 'no v', version = '10.20.123', want = { major = 10, minor = 20, patch = 123, prerelease = nil, build = nil, }, }, + { desc = 'with v', version = 'v1.2.3', want = { major = 1, minor = 2, patch = 3 }, }, + { desc = 'prerelease', version = '1.2.3-alpha', want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha' }, }, + { desc = 'prerelease.x', version = '1.2.3-alpha.1', want = { major = 1, minor = 2, patch = 3, prerelease = 'alpha.1' }, }, + { desc = 'build.x', version = '1.2.3+build.15', want = { major = 1, minor = 2, patch = 3, build = 'build.15' }, }, + { desc = 'prerelease and build', version = '1.2.3-rc1+build.15', want = { major = 1, minor = 2, patch = 3, prerelease = 'rc1', build = 'build.15', }, }, } for _, tc in ipairs(testcases) do it( string.format('%q: version = %q', tc.desc, tc.version), function() - eq(tc.want, version.parse(tc.version)) + eq(tc.want, vim.version.parse(tc.version)) end ) end @@ -211,12 +162,13 @@ describe('version', function() { version = '1-1.0', want = { major = 1, minor = 0, patch = 0, prerelease = '1.0' }, }, { version = 'v1.2.3 ', want = { major = 1, minor = 2, patch = 3 }, }, { version = ' v1.2.3', want = { major = 1, minor = 2, patch = 3 }, }, + { version = 'tmux 3.2a', want = { major = 3, minor = 2, patch = 0, }, }, } for _, tc in ipairs(testcases) do it( string.format('version = %q', tc.version), function() - eq(tc.want, version.parse(tc.version, { strict = false })) + eq(tc.want, vim.version.parse(tc.version, { strict = false })) end ) end @@ -236,6 +188,8 @@ describe('version', function() { version = '1.2.3-%?' }, { version = '1.2.3+%?' }, { version = '1.2.3+build.0-rc1' }, + { version = '3.2a', }, + { version = 'tmux 3.2a', }, } local function quote_empty(s) @@ -244,7 +198,7 @@ describe('version', function() for _, tc in ipairs(testcases) do it(quote_empty(tc.version), function() - eq(nil, version.parse(tc.version, { strict = true })) + eq(nil, vim.version.parse(tc.version, { strict = true })) end) end end) @@ -261,21 +215,42 @@ describe('version', function() it(string.format('(%s): %s', tc.desc, tostring(tc.version)), function() local expected = string.format(type(tc.version) == 'string' and 'invalid version: "%s"' or 'invalid version: %s', tostring(tc.version)) - matches(expected, pcall_err(version.parse, tc.version, { strict = true })) + matches(expected, pcall_err(vim.version.parse, tc.version, { strict = true })) end) end end) end) + it('relational metamethods (== < >)', function() + assert(v('v1.2.3') == v('1.2.3')) + assert(not (v('v1.2.3') < v('1.2.3'))) + assert(v('v1.2.3') > v('1.2.3-prerelease')) + assert(v('v1.2.3-alpha') < v('1.2.3-beta')) + assert(v('v1.2.3-prerelease') < v('1.2.3')) + assert(v('v1.2.3') >= v('1.2.3')) + assert(v('v1.2.3') >= v('1.0.3')) + assert(v('v1.2.3') >= v('1.2.2')) + assert(v('v1.2.3') > v('1.2.2')) + assert(v('v1.2.3') > v('1.0.3')) + eq(vim.version.last({ v('1.2.3'), v('2.0.0') }), v('2.0.0')) + eq(vim.version.last({ v('2.0.0'), v('1.2.3') }), v('2.0.0')) + end) + it('lt()', function() - eq(true, version.lt('1', '2')) + eq(true, vim.version.lt('1', '2')) + eq(false, vim.version.lt({3}, {0, 7, 4})) + eq(false, vim.version.lt({major=3, minor=3, patch=0}, {3, 2, 0})) end) it('gt()', function() - eq(true, version.gt('2', '1')) + eq(true, vim.version.gt('2', '1')) + eq(true, vim.version.gt({3}, {0, 7, 4})) + eq(true, vim.version.gt({major=3, minor=3, patch=0}, {3, 2, 0})) end) it('eq()', function() - eq(true, version.eq('2', '2')) + eq(true, vim.version.eq('2', '2')) + eq(true, vim.version.eq({3, 1, 0}, '3.1.0')) + eq(true, vim.version.eq({major=3, minor=3, patch=0}, {3, 3, 0})) end) end) -- cgit From a92b38934a2d00c13ee4d1969d994da15e0857ab Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 20 Mar 2023 21:11:10 +0100 Subject: feat(lua): allow `:=expr` as a shorter version of `:lua =expr` existing behavior of := and :[range]= are unchanged. `|` is still allowed with this usage. However, :=p and similar are changed in a way which could be construed as a breaking change. Allowing |ex-flags| for := in the first place was a mistake as any form of := DOES NOT MOVE THE CURSOR. So it would print one line number and then print a completely different line contents after that. --- test/functional/lua/commands_spec.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 943095c51e..5bb9e0281b 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -146,6 +146,7 @@ describe(':lua command', function() it('prints result of =expr', function() exec_lua("x = 5") eq("5", exec_capture(':lua =x')) + eq("5", exec_capture('=x')) exec_lua("function x() return 'hello' end") eq('hello', exec_capture(':lua = x()')) exec_lua("x = {a = 1, b = 2}") @@ -165,7 +166,7 @@ describe(':lua command', function() false nil Error message]], - exec_capture(':lua =x(false)')) + exec_capture('=x(false)')) end) end) -- cgit From 9c49c1047079427ff0a2356cb37302934845108e Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 20 Mar 2023 08:12:33 +0100 Subject: feat(vim.gsplit): gain features of vim.split Problem: - vim.split has more features than vim.gsplit. - Cannot inspect the "separator" segments of vim.split or vim.gsplit. Solution: - Move common implementation from vim.split into vim.gsplit. - TODO: deprecate vim.split in favor of vim.totable(vim.gsplit())? - Introduce `keepsep` parameter. Related: 84f66909e4008a57da947f1640bfc24da5e41a72 --- test/functional/lua/vim_spec.lua | 65 +++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 27 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 0483ec46f0..4cf38a1567 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -292,51 +292,62 @@ describe('lua stdlib', function() ]]} end) - it("vim.split", function() - local split = function(str, sep, kwargs) - return exec_lua('return vim.split(...)', str, sep, kwargs) - end - + it('vim.gsplit, vim.split', function() local tests = { - { "a,b", ",", false, false, { 'a', 'b' } }, - { ":aa::bb:", ":", false, false, { '', 'aa', '', 'bb', '' } }, - { ":aa::bb:", ":", false, true, { 'aa', '', 'bb' } }, - { "::ee::ff:", ":", false, false, { '', '', 'ee', '', 'ff', '' } }, - { "::ee::ff:", ":", false, true, { 'ee', '', 'ff' } }, - { "ab", ".", false, false, { '', '', '' } }, - { "a1b2c", "[0-9]", false, false, { 'a', 'b', 'c' } }, - { "xy", "", false, false, { 'x', 'y' } }, - { "here be dragons", " ", false, false, { "here", "be", "dragons"} }, - { "axaby", "ab?", false, false, { '', 'x', 'y' } }, - { "f v2v v3v w2w ", "([vw])2%1", false, false, { 'f ', ' v3v ', ' ' } }, - { "", "", false, false, {} }, - { "", "a", false, false, { '' } }, - { "x*yz*oo*l", "*", true, false, { 'x', 'yz', 'oo', 'l' } }, + { 'a,b', ',', false, false, { 'a', 'b' } }, + { ':aa::::bb:', ':', false, false, { '', 'aa', '', '', '', 'bb', '' } }, + { ':aa::::bb:', ':', false, true, { 'aa', '', '', '', 'bb' } }, + { ':aa::bb:', ':', false, true, { 'aa', '', 'bb' } }, + { '/a/b:/b/\n', '[:\n]', false, true, { '/a/b', '/b/' } }, + { '::ee::ff:', ':', false, false, { '', '', 'ee', '', 'ff', '' } }, + { '::ee::ff::', ':', false, true, { 'ee', '', 'ff' } }, + { 'ab', '.', false, false, { '', '', '' } }, + { 'a1b2c', '[0-9]', false, false, { 'a', 'b', 'c' } }, + { 'xy', '', false, false, { 'x', 'y' } }, + { 'here be dragons', ' ', false, false, { 'here', 'be', 'dragons'} }, + { 'axaby', 'ab?', false, false, { '', 'x', 'y' } }, + { 'f v2v v3v w2w ', '([vw])2%1', false, false, { 'f ', ' v3v ', ' ' } }, + { '', '', false, false, {} }, + { '', '', false, true, {} }, + { '\n', '[:\n]', false, true, {} }, + { '', 'a', false, false, { '' } }, + { 'x*yz*oo*l', '*', true, false, { 'x', 'yz', 'oo', 'l' } }, } for _, t in ipairs(tests) do - eq(t[5], split(t[1], t[2], {plain=t[3], trimempty=t[4]})) + eq(t[5], vim.split(t[1], t[2], {plain=t[3], trimempty=t[4]})) end -- Test old signature - eq({'x', 'yz', 'oo', 'l'}, split("x*yz*oo*l", "*", true)) + eq({'x', 'yz', 'oo', 'l'}, vim.split("x*yz*oo*l", "*", true)) local loops = { { "abc", ".-" }, } for _, t in ipairs(loops) do - matches("Infinite loop detected", pcall_err(split, t[1], t[2])) + matches("Infinite loop detected", pcall_err(vim.split, t[1], t[2])) end + -- `keepsep` + eq({ '', '.', '', '.', 'aa', '.', 'bb', '.', 'cc', '.', 'dd', '.', 'ee', '.', '', }, + vim.split('..aa.bb.cc.dd.ee.', '%.', {keepsep=true})) + eq({ '..aa', '1', '.bb', '2', '', '2', '.cc.', '9', '', }, + vim.split('..aa1.bb22.cc.9', '%d', {keepsep=true})) + eq({ '..aa', '1', '.bb', '22', '.cc.', '9', '', }, + vim.split('..aa1.bb22.cc.9', '%d+', {keepsep=true})) + -- Validates args. - eq(true, pcall(split, 'string', 'string')) + eq(true, pcall(vim.split, 'string', 'string')) matches('s: expected string, got number', - pcall_err(split, 1, 'string')) + pcall_err(vim.split, 1, 'string')) matches('sep: expected string, got number', - pcall_err(split, 'string', 1)) - matches('kwargs: expected table, got number', - pcall_err(split, 'string', 'string', 1)) + pcall_err(vim.split, 'string', 1)) + matches('opts: expected table, got number', + pcall_err(vim.split, 'string', 'string', 1)) + -- Not supported (yet). + matches('keepsep%+trimempty not supported', + pcall_err(vim.split, 'foo bar', ' ', {keepsep=true, trimempty=true})) end) it('vim.trim', function() -- cgit From 8a70adbde03ee9931dc4e1b6f31bd8635eb3633b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 20 Mar 2023 13:36:06 +0100 Subject: fix(vim.version): prerelease compare Problem: semver specifies that digit sequences in a prerelease string should be compared as numbers, not lexically: https://semver.org/#spec-item-11 > Precedence for two pre-release versions with the same major, minor, > and patch version MUST be determined by comparing each dot separated > identifier from left to right until a difference is found as follows: > 1. Identifiers consisting of only digits are compared numerically. > 2. Identifiers with letters or hyphens are compared lexically in ASCII sort order. > 3. Numeric identifiers always have lower precedence than non-numeric identifiers. > 4. A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal. Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0. Solution: cmp_prerel() treats all digit sequences in a prerelease string as numbers. This doesn't _exactly_ match the spec, which specifies that only dot-delimited digit sequences should be treated as numbers... --- test/functional/lua/version_spec.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index 014fea5272..75b62e8318 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -101,6 +101,9 @@ describe('version', function() { v1 = 'v9.0.0', v2 = 'v0.9.0', want = 1, }, { v1 = 'v0.9.0', v2 = 'v0.0.0', want = 1, }, { v1 = 'v0.0.9', v2 = 'v0.0.0', want = 1, }, + { v1 = 'v0.0.9+aaa', v2 = 'v0.0.9+bbb', want = 0, }, + + -- prerelease 💩 https://semver.org/#spec-item-11 { v1 = 'v1.0.0-alpha', v2 = 'v1.0.0', want = -1, }, { v1 = '1.0.0', v2 = '1.0.0-alpha', want = 1, }, { v1 = '1.0.0-2', v2 = '1.0.0-1', want = 1, }, @@ -116,11 +119,11 @@ describe('version', function() { v1 = '1.0.0-alpha.beta', v2 = '1.0.0-alpha', want = 1, }, { v1 = '1.0.0-alpha', v2 = '1.0.0-alpha.beta', want = -1, }, { v1 = '1.0.0-alpha.beta', v2 = '1.0.0-beta', want = -1, }, - { v1 = '1.0.0-beta', v2 = '1.0.0-alpha.beta', want = 1, }, - { v1 = '1.0.0-beta', v2 = '1.0.0-beta.2', want = -1, }, - -- TODO - -- { v1 = '1.0.0-beta.2', v2 = '1.0.0-beta.11', want = -1, }, - { v1 = '1.0.0-beta.11', v2 = '1.0.0-rc.1', want = -1, }, + { v1 = '1.0.0-beta.2', v2 = '1.0.0-beta.11', want = -1, }, + { v1 = '1.0.0-beta.20', v2 = '1.0.0-beta.11', want = 1, }, + { v1 = '1.0.0-alpha.20', v2 = '1.0.0-beta.11', want = -1, }, + { v1 = '1.0.0-a.01.x.3', v2 = '1.0.0-a.1.x.003', want = 0, }, + { v1 = 'v0.9.0-dev-92+9', v2 = 'v0.9.0-dev-120+3', want = -1, }, } for _, tc in ipairs(testcases) do local msg = function(s) return ('v1 %s v2'):format(s == 0 and '==' or (s == 1 and '>' or '<')) end -- cgit From e51139f5c1d70bef1424f29e63eb527514e42865 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 22 Mar 2023 15:14:51 +0100 Subject: refactor(vim.gsplit): remove "keepsep" string.gmatch() is superior, use that instead. --- test/functional/lua/vim_spec.lua | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 4cf38a1567..a0428ed933 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -329,14 +329,6 @@ describe('lua stdlib', function() matches("Infinite loop detected", pcall_err(vim.split, t[1], t[2])) end - -- `keepsep` - eq({ '', '.', '', '.', 'aa', '.', 'bb', '.', 'cc', '.', 'dd', '.', 'ee', '.', '', }, - vim.split('..aa.bb.cc.dd.ee.', '%.', {keepsep=true})) - eq({ '..aa', '1', '.bb', '2', '', '2', '.cc.', '9', '', }, - vim.split('..aa1.bb22.cc.9', '%d', {keepsep=true})) - eq({ '..aa', '1', '.bb', '22', '.cc.', '9', '', }, - vim.split('..aa1.bb22.cc.9', '%d+', {keepsep=true})) - -- Validates args. eq(true, pcall(vim.split, 'string', 'string')) matches('s: expected string, got number', @@ -345,9 +337,6 @@ describe('lua stdlib', function() pcall_err(vim.split, 'string', 1)) matches('opts: expected table, got number', pcall_err(vim.split, 'string', 'string', 1)) - -- Not supported (yet). - matches('keepsep%+trimempty not supported', - pcall_err(vim.split, 'foo bar', ' ', {keepsep=true, trimempty=true})) end) it('vim.trim', function() -- cgit From b02880593e281ce44661ce22e9391edfe921e47e Mon Sep 17 00:00:00 2001 From: luukvbaal <31730729+luukvbaal@users.noreply.github.com> Date: Thu, 23 Mar 2023 12:58:50 +0100 Subject: build(win): export extern symbols for use in FFI #22756 Makes `extern` variables accessible through ffi on Windows. Follow-up to https://github.com/neovim/neovim/pull/15999 --- test/functional/lua/ffi_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/ffi_spec.lua b/test/functional/lua/ffi_spec.lua index 18b13a8959..c492c1e765 100644 --- a/test/functional/lua/ffi_spec.lua +++ b/test/functional/lua/ffi_spec.lua @@ -63,5 +63,14 @@ describe('ffi.cdef', function() nil ) ]=]) + + -- Check that extern symbols are exported and accessible + eq(true, exec_lua[[ + local ffi = require('ffi') + + ffi.cdef('uint64_t display_tick;') + + return ffi.C.display_tick >= 0 + ]]) end) end) -- cgit From 6a6191174afd7604b82fcc04b9a27b8d51133c9f Mon Sep 17 00:00:00 2001 From: Jon Huhn Date: Sun, 26 Mar 2023 04:41:27 -0500 Subject: test: fix flaky watchfiles tests (#22637) --- test/functional/lua/watch_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index 19bb411ce6..554480c2b3 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -126,6 +126,8 @@ describe('vim._watch', function() expected_events = expected_events + 1 wait_for_events() + vim.wait(100) + local watched_path = root_dir .. '/file' local watched, err = io.open(watched_path, 'w') assert(not err, err) -- cgit From 226a6c3eaef2a7220841d3d5e69e1baf543b3d6f Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 30 Mar 2023 14:49:58 +0100 Subject: feat(diagnostic): add support for tags The LSP spec supports two tags that can be added to diagnostics: unnecessary and deprecated. Extend vim.diagnostic to be able to handle these. --- test/functional/lua/diagnostic_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index d364986ad7..7b4d68c9cd 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -86,6 +86,7 @@ describe('vim.diagnostic', function() it('creates highlight groups', function() command('runtime plugin/diagnostic.vim') eq({ + 'DiagnosticDeprecated', 'DiagnosticError', 'DiagnosticFloatingError', 'DiagnosticFloatingHint', @@ -105,6 +106,7 @@ describe('vim.diagnostic', function() 'DiagnosticUnderlineInfo', 'DiagnosticUnderlineOk', 'DiagnosticUnderlineWarn', + 'DiagnosticUnnecessary', 'DiagnosticVirtualTextError', 'DiagnosticVirtualTextHint', 'DiagnosticVirtualTextInfo', -- cgit From 643c0ed571f1ac6e83f73ab2593132901278b4da Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sat, 1 Apr 2023 08:02:58 -0600 Subject: feat: allow function passed to defaulttable to take an argument (#22839) Pass the value of the key being accessed to the create function, to allow users to dynamically generate default values. --- test/functional/lua/vim_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index a0428ed933..4f401eed8f 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2915,6 +2915,15 @@ describe('lua stdlib', function() return a ]]) end) + + it('accepts the key name', function() + eq({ b = 'b', c = 'c' }, exec_lua [[ + local a = vim.defaulttable(function(k) return k end) + local _ = a.b + local _ = a.c + return a + ]]) + end) end) it('vim.lua_omnifunc', function() -- cgit From d510bfbc8e447b1a60d5ec7faaa8f440eb4ef56f Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 2 Apr 2023 10:11:42 +0200 Subject: refactor: remove char_u (#22829) Closes https://github.com/neovim/neovim/issues/459 --- test/functional/lua/ffi_spec.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/ffi_spec.lua b/test/functional/lua/ffi_spec.lua index c492c1e765..3a37b18cd1 100644 --- a/test/functional/lua/ffi_spec.lua +++ b/test/functional/lua/ffi_spec.lua @@ -25,7 +25,6 @@ describe('ffi.cdef', function() local ffi = require('ffi') ffi.cdef[[ - typedef unsigned char char_u; typedef struct window_S win_T; typedef struct {} stl_hlrec_t; typedef struct {} StlClickRecord; -- cgit From a93024555720325ecede9d2d15e4bd0f1fd82739 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 25 Mar 2023 15:19:22 +0100 Subject: refactor(lua): get all marks instead of iterating over namespaces Inspector now also includes highlights set in anonymous namespaces. Close #22732 --- test/functional/lua/inspector_spec.lua | 41 +++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/inspector_spec.lua b/test/functional/lua/inspector_spec.lua index 5e488bb082..edc0519471 100644 --- a/test/functional/lua/inspector_spec.lua +++ b/test/functional/lua/inspector_spec.lua @@ -12,9 +12,13 @@ describe('vim.inspect_pos', function() it('it returns items', function() local ret = exec_lua([[ local buf = vim.api.nvim_create_buf(true, false) + local ns1 = vim.api.nvim_create_namespace("ns1") + local ns2 = vim.api.nvim_create_namespace("") vim.api.nvim_set_current_buf(buf) vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"}) vim.api.nvim_buf_set_option(buf, "filetype", "lua") + vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = "Normal" }) + vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = "Normal" }) vim.cmd("syntax on") return {buf, vim.inspect_pos(0, 0, 10)} ]]) @@ -24,7 +28,42 @@ describe('vim.inspect_pos', function() buffer = buf, col = 10, row = 0, - extmarks = {}, + extmarks = { + { + col = 10, + end_col = 11, + end_row = 0, + id = 1, + ns = 'ns1', + ns_id = 1, + opts = { + hl_eol = false, + hl_group = 'Normal', + hl_group_link = 'Normal', + ns_id = 1, + priority = 4096, + right_gravity = true + }, + row = 0 + }, + { + col = 10, + end_col = 11, + end_row = 0, + id = 1, + ns = '', + ns_id = 2, + opts = { + hl_eol = false, + hl_group = 'Normal', + hl_group_link = 'Normal', + ns_id = 2, + priority = 4096, + right_gravity = true + }, + row = 0 + } + }, treesitter = {}, semantic_tokens = {}, syntax = { -- 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/lua/buffer_updates_spec.lua | 5 +++-- test/functional/lua/fs_spec.lua | 10 +++++----- test/functional/lua/watch_spec.lua | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 2cd3123dcd..04f4f89472 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -1,6 +1,6 @@ -- Test suite for testing interactions with API bindings local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') +local luv = require('luv') local command = helpers.command local meths = helpers.meths @@ -754,7 +754,8 @@ describe('lua: nvim_buf_attach on_bytes', function() write_file("Xtest-reload", dedent [[ old line 1 old line 2]]) - lfs.touch("Xtest-reload", os.time() - 10) + local atime = os.time() - 10 + luv.fs_utime("Xtest-reload", atime, atime) command "e Xtest-reload" command "set autoread" diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index da60b5c13b..aeb2e5d9a6 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -1,5 +1,4 @@ local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') local clear = helpers.clear local exec_lua = helpers.exec_lua @@ -11,6 +10,7 @@ local test_build_dir = helpers.test_build_dir local test_source_path = helpers.test_source_path local nvim_prog = helpers.nvim_prog local is_os = helpers.is_os +local mkdir = helpers.mkdir local nvim_prog_basename = is_os('win') and 'nvim.exe' or 'nvim' @@ -133,10 +133,10 @@ describe('vim.fs', function() describe('dir()', function() before_each(function() - lfs.mkdir('testd') - lfs.mkdir('testd/a') - lfs.mkdir('testd/a/b') - lfs.mkdir('testd/a/b/c') + mkdir('testd') + mkdir('testd/a') + mkdir('testd/a/b') + mkdir('testd/a/b/c') end) after_each(function() diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index 554480c2b3..bbcfd27cde 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -3,7 +3,7 @@ local eq = helpers.eq local exec_lua = helpers.exec_lua local clear = helpers.clear local is_os = helpers.is_os -local lfs = require('lfs') +local mkdir = helpers.mkdir describe('vim._watch', function() before_each(function() @@ -14,7 +14,7 @@ describe('vim._watch', function() it('detects file changes', function() local root_dir = helpers.tmpname() os.remove(root_dir) - lfs.mkdir(root_dir) + mkdir(root_dir) local result = exec_lua( [[ @@ -102,7 +102,7 @@ describe('vim._watch', function() it('detects file changes', function() local root_dir = helpers.tmpname() os.remove(root_dir) - lfs.mkdir(root_dir) + mkdir(root_dir) local result = exec_lua( [[ -- cgit From 34ac75b32927328a0c691c5bda987c0fdb5ce9eb Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 5 Apr 2023 17:19:53 +0100 Subject: refactor: rename local API alias from a to api Problem: Codebase inconsistently binds vim.api onto a or api. Solution: Use api everywhere. a as an identifier is too short to have at the module level. --- test/functional/lua/vim_spec.lua | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 4f401eed8f..9508469a61 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2721,11 +2721,11 @@ describe('lua stdlib', function() it('does not cause ml_get errors with invalid visual selection', function() -- Should be fixed by vim-patch:8.2.4028. exec_lua [[ - local a = vim.api - local t = function(s) return a.nvim_replace_termcodes(s, true, true, true) end - a.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"}) - a.nvim_feedkeys(t "G", "txn", false) - a.nvim_buf_call(a.nvim_create_buf(false, true), function() vim.cmd "redraw" end) + local api = vim.api + local t = function(s) return api.nvim_replace_termcodes(s, true, true, true) end + api.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"}) + api.nvim_feedkeys(t "G", "txn", false) + api.nvim_buf_call(api.nvim_create_buf(false, true), function() vim.cmd "redraw" end) ]] end) @@ -2800,29 +2800,29 @@ describe('lua stdlib', function() it('does not cause ml_get errors with invalid visual selection', function() -- Add lines to the current buffer and make another window looking into an empty buffer. exec_lua [[ - _G.a = vim.api - _G.t = function(s) return a.nvim_replace_termcodes(s, true, true, true) end - _G.win_lines = a.nvim_get_current_win() + _G.api = vim.api + _G.t = function(s) return api.nvim_replace_termcodes(s, true, true, true) end + _G.win_lines = api.nvim_get_current_win() vim.cmd "new" - _G.win_empty = a.nvim_get_current_win() - a.nvim_set_current_win(win_lines) - a.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"}) + _G.win_empty = api.nvim_get_current_win() + api.nvim_set_current_win(win_lines) + api.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"}) ]] -- Start Visual in current window, redraw in other window with fewer lines. -- Should be fixed by vim-patch:8.2.4018. exec_lua [[ - a.nvim_feedkeys(t "G", "txn", false) - a.nvim_win_call(win_empty, function() vim.cmd "redraw" end) + api.nvim_feedkeys(t "G", "txn", false) + api.nvim_win_call(win_empty, function() vim.cmd "redraw" end) ]] -- Start Visual in current window, extend it in other window with more lines. -- Fixed for win_execute by vim-patch:8.2.4026, but nvim_win_call should also not be affected. exec_lua [[ - a.nvim_feedkeys(t "gg", "txn", false) - a.nvim_set_current_win(win_empty) - a.nvim_feedkeys(t "gg", "txn", false) - a.nvim_win_call(win_lines, function() a.nvim_feedkeys(t "G", "txn", false) end) + api.nvim_feedkeys(t "gg", "txn", false) + api.nvim_set_current_win(win_empty) + api.nvim_feedkeys(t "gg", "txn", false) + api.nvim_win_call(win_lines, function() api.nvim_feedkeys(t "G", "txn", false) end) vim.cmd "redraw" ]] end) @@ -2836,14 +2836,14 @@ describe('lua stdlib', function() } screen:attach() exec_lua [[ - _G.a = vim.api + _G.api = vim.api vim.opt.ruler = true local lines = {} for i = 0, 499 do lines[#lines + 1] = tostring(i) end - a.nvim_buf_set_lines(0, 0, -1, true, lines) - a.nvim_win_set_cursor(0, {20, 0}) + api.nvim_buf_set_lines(0, 0, -1, true, lines) + api.nvim_win_set_cursor(0, {20, 0}) vim.cmd "split" - _G.win = a.nvim_get_current_win() + _G.win = api.nvim_get_current_win() vim.cmd "wincmd w | redraw" ]] screen:expect [[ @@ -2854,7 +2854,7 @@ describe('lua stdlib', function() | ]] exec_lua [[ - a.nvim_win_call(win, function() a.nvim_win_set_cursor(0, {100, 0}) end) + api.nvim_win_call(win, function() api.nvim_win_set_cursor(0, {100, 0}) end) vim.cmd "redraw" ]] screen:expect [[ -- cgit From fd32a987520cb132455d61301467182cb58cddf2 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Wed, 5 Apr 2023 23:56:33 +0200 Subject: test(vim.fs.normalize): enable test on Windows --- test/functional/lua/fs_spec.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index aeb2e5d9a6..2fcbc9450f 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -271,10 +271,11 @@ describe('vim.fs', function() eq('C:/Users/jdoe', exec_lua [[ return vim.fs.normalize('C:\\Users\\jdoe') ]]) end) it('works with ~', function() - if is_os('win') then - pending([[$HOME does not exist on Windows ¯\_(ツ)_/¯]]) - end - eq(os.getenv('HOME') .. '/src/foo', exec_lua [[ return vim.fs.normalize('~/src/foo') ]]) + eq( exec_lua([[ + local home = ... + return home .. '/src/foo' + ]], is_os('win') and vim.fs.normalize(os.getenv('USERPROFILE')) or os.getenv('HOME') + ) , exec_lua [[ return vim.fs.normalize('~/src/foo') ]]) end) it('works with environment variables', function() local xdg_config_home = test_build_dir .. '/.config' -- cgit From b2d10aa01da4cf9341f68969b22875afb4afabd9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 7 Apr 2023 09:38:52 +0800 Subject: test(lua/diagnostic_spec): remove unnecessary after_each() There is already a call to clear() in before_each(), so after_each() isn't necessary. --- test/functional/lua/diagnostic_spec.lua | 4 ---- 1 file changed, 4 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 7b4d68c9cd..6b4ca5ac73 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -79,10 +79,6 @@ describe('vim.diagnostic', function() ]]) end) - after_each(function() - clear() - end) - it('creates highlight groups', function() command('runtime plugin/diagnostic.vim') eq({ -- cgit From d675bd01b1e78b93e559320b262bdae40b3b54b2 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Fri, 7 Apr 2023 08:22:47 -0600 Subject: feat(lua): allow vim.F.if_nil to take multiple arguments (#22903) The first argument which is non-nil is returned. This is useful when using nested default values (e.g. in the EditorConfig plugin). Before: local enable = vim.F.if_nil(vim.b.editorconfig, vim.F.if_nil(vim.g.editorconfig, true)) After: local enable = vim.F.if_nil(vim.b.editorconfig, vim.g.editorconfig, true) --- test/functional/lua/vim_spec.lua | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 9508469a61..45d9263c0c 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2967,6 +2967,32 @@ describe('lua stdlib', function() }]], eval[[execute('lua vim.print(42, "abc", { a = { b = 77 }})')]]) end) + + it('vim.F.if_nil', function() + local function if_nil(...) + return exec_lua([[ + local args = {...} + local nargs = select('#', ...) + for i = 1, nargs do + if args[i] == vim.NIL then + args[i] = nil + end + end + return vim.F.if_nil(unpack(args, 1, nargs)) + ]], ...) + end + + local a = NIL + local b = NIL + local c = 42 + local d = false + eq(42, if_nil(a, c)) + eq(false, if_nil(d, b)) + eq(42, if_nil(a, b, c, d)) + eq(false, if_nil(d)) + eq(false, if_nil(d, c)) + eq(NIL, if_nil(a)) + end) end) describe('lua: builtin modules', function() -- cgit From 9e86f473e0f4e21c5f40bf990c53194d593a0f9f Mon Sep 17 00:00:00 2001 From: NAKAI Tsuyoshi <82267684+uga-rosa@users.noreply.github.com> Date: Tue, 11 Apr 2023 23:28:46 +0900 Subject: feat(lua): vim.region accepts getpos() arg (#22635) --- test/functional/lua/vim_spec.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 45d9263c0c..85e45788e8 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2297,6 +2297,10 @@ describe('lua stdlib', function() insert([[αα]]) eq({0,5}, exec_lua[[ return vim.region(0,{0,0},{0,4},'3',true)[0] ]]) end) + it('getpos() input', function() + insert('getpos') + eq({0,6}, exec_lua[[ return vim.region(0,{0,0},'.','v',true)[0] ]]) + end) end) describe('vim.on_key', function() -- cgit From 66c66d8db8ab5cb6d0c6d85d64556d7cf20b04fa Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 13 Apr 2023 17:34:47 +0100 Subject: fix(loader): reset hashes when running the loader --- test/functional/lua/loader_spec.lua | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 test/functional/lua/loader_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua new file mode 100644 index 0000000000..e2958d1592 --- /dev/null +++ b/test/functional/lua/loader_spec.lua @@ -0,0 +1,36 @@ +-- Test suite for testing interactions with API bindings +local helpers = require('test.functional.helpers')(after_each) + +local exec_lua = helpers.exec_lua +local command = helpers.command +local eq = helpers.eq + +describe('vim.loader', function() + before_each(helpers.clear) + + it('handles changing files (#23027)', function() + exec_lua[[ + vim.loader.enable() + ]] + + local tmp = helpers.tmpname() + command('edit ' .. tmp) + + eq(1, exec_lua([[ + vim.api.nvim_buf_set_lines(0, 0, -1, true, {'_G.TEST=1'}) + vim.cmd.write() + loadfile(...)() + return _G.TEST + ]], tmp)) + + -- fs latency + helpers.sleep(10) + + eq(2, exec_lua([[ + vim.api.nvim_buf_set_lines(0, 0, -1, true, {'_G.TEST=2'}) + vim.cmd.write() + loadfile(...)() + return _G.TEST + ]], tmp)) + end) +end) -- cgit From 4d04feb6629cb049cb2a13ba35f0c8d3c6b67ff4 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 14 Apr 2023 10:39:57 +0200 Subject: feat(lua): vim.tbl_contains supports general tables and predicates (#23040) * feat(lua): vim.tbl_contains supports general tables and predicates Problem: `vim.tbl_contains` only works for list-like tables (integer keys without gaps) and primitive values (in particular, not for nested tables). Solution: Rename `vim.tbl_contains` to `vim.list_contains` and add new `vim.tbl_contains` that works for general tables and optionally allows `value` to be a predicate function that is checked for every key. --- test/functional/lua/vim_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 85e45788e8..6b69018bc0 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -461,6 +461,22 @@ describe('lua stdlib', function() pcall_err(exec_lua, [[return vim.pesc(2)]])) end) + it('vim.list_contains', function() + eq(true, exec_lua("return vim.list_contains({'a','b','c'}, 'c')")) + eq(false, exec_lua("return vim.list_contains({'a','b','c'}, 'd')")) + end) + + it('vim.tbl_contains', function() + eq(true, exec_lua("return vim.tbl_contains({'a','b','c'}, 'c')")) + eq(false, exec_lua("return vim.tbl_contains({'a','b','c'}, 'd')")) + eq(true, exec_lua("return vim.tbl_contains({[2]='a',foo='b',[5] = 'c'}, 'c')")) + eq(true, exec_lua([[ + return vim.tbl_contains({ 'a', { 'b', 'c' } }, function(v) + return vim.deep_equal(v, { 'b', 'c' }) + end, { predicate = true }) + ]])) + end) + it('vim.tbl_keys', function() eq({}, exec_lua("return vim.tbl_keys({})")) for _, v in pairs(exec_lua("return vim.tbl_keys({'a', 'b', 'c'})")) do -- cgit From 7caf0eafd83b5a92f2ff219b3a64ffae4174b9af Mon Sep 17 00:00:00 2001 From: NAKAI Tsuyoshi <82267684+uga-rosa@users.noreply.github.com> Date: Fri, 14 Apr 2023 19:01:08 +0900 Subject: feat(lua)!: add stricter vim.tbl_islist() and rename old one to vim.tbl_isarray() (#16440) feat(lua)!: add stricter vim.tbl_islist(), rename vim.tbl_isarray() Problem: `vim.tbl_islist` allows gaps in tables with integer keys ("arrays"). Solution: Rename `vim.tbl_islist` to `vim.tbl_isarray`, add new `vim.tbl.islist` that checks for consecutive integer keys that start from 1. --- test/functional/lua/vim_spec.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 6b69018bc0..1ee1a13fd5 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -521,6 +521,19 @@ describe('lua stdlib', function() ]])) end) + it('vim.tbl_isarray', function() + eq(true, exec_lua("return vim.tbl_isarray({})")) + eq(false, exec_lua("return vim.tbl_isarray(vim.empty_dict())")) + eq(true, exec_lua("return vim.tbl_isarray({'a', 'b', 'c'})")) + eq(false, exec_lua("return vim.tbl_isarray({'a', '32', a='hello', b='baz'})")) + eq(false, exec_lua("return vim.tbl_isarray({1, a='hello', b='baz'})")) + eq(false, exec_lua("return vim.tbl_isarray({a='hello', b='baz', 1})")) + eq(false, exec_lua("return vim.tbl_isarray({1, 2, nil, a='hello'})")) + eq(true, exec_lua("return vim.tbl_isarray({1, 2, nil, 4})")) + eq(true, exec_lua("return vim.tbl_isarray({nil, 2, 3, 4})")) + eq(false, exec_lua("return vim.tbl_isarray({1, [1.5]=2, [3]=3})")) + end) + it('vim.tbl_islist', function() eq(true, exec_lua("return vim.tbl_islist({})")) eq(false, exec_lua("return vim.tbl_islist(vim.empty_dict())")) @@ -529,6 +542,9 @@ describe('lua stdlib', function() eq(false, exec_lua("return vim.tbl_islist({1, a='hello', b='baz'})")) eq(false, exec_lua("return vim.tbl_islist({a='hello', b='baz', 1})")) eq(false, exec_lua("return vim.tbl_islist({1, 2, nil, a='hello'})")) + eq(false, exec_lua("return vim.tbl_islist({1, 2, nil, 4})")) + eq(false, exec_lua("return vim.tbl_islist({nil, 2, 3, 4})")) + eq(false, exec_lua("return vim.tbl_islist({1, [1.5]=2, [3]=3})")) end) it('vim.tbl_isempty', function() -- cgit From 68ca16c376bd8786ffc0c7ce7619b9a0ce5657e8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 08:54:07 +0800 Subject: vim-patch:8.2.3783: confusing error for using a variable as a function Problem: Confusing error for using a variable as a function. Solution: If a function is not found but there is a variable, give a more useful error. (issue vim/vim#9310) https://github.com/vim/vim/commit/2ef9156b4284e4a52613c36e3d4667245273a28d Co-authored-by: Bram Moolenaar --- test/functional/lua/luaeval_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 9f313eab9e..32bb894be1 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -545,7 +545,7 @@ describe('v:lua', function() eq("Vim:E15: Invalid expression: v:['lua'].foo()", pcall_err(eval, "v:['lua'].foo()")) eq("Vim(call):E461: Illegal variable name: v:['lua']", pcall_err(command, "call v:['lua'].baar()")) - eq("Vim:E117: Unknown function: v:lua", pcall_err(eval, "v:lua()")) + eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "v:lua()")) eq("Vim(let):E46: Cannot change read-only variable \"v:['lua']\"", pcall_err(command, "let v:['lua'] = 'xx'")) eq("Vim(let):E46: Cannot change read-only variable \"v:lua\"", pcall_err(command, "let v:lua = 'xx'")) @@ -553,7 +553,7 @@ describe('v:lua', function() eq("Vim:E107: Missing parentheses: v:lua.func", pcall_err(eval, "'bad'->v:lua.func")) eq("Vim:E274: No white space allowed before parenthesis", pcall_err(eval, "'bad'->v:lua.func ()")) eq("Vim:E107: Missing parentheses: v:lua", pcall_err(eval, "'bad'->v:lua")) - eq("Vim:E117: Unknown function: v:lua", pcall_err(eval, "'bad'->v:lua()")) + eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "'bad'->v:lua()")) eq("Vim:E15: Invalid expression: v:lua.()", pcall_err(eval, "'bad'->v:lua.()")) end) end) -- cgit From 2f779b94e7fe0fb2fba00dd8e644c60605e83179 Mon Sep 17 00:00:00 2001 From: Raphael Date: Sun, 16 Apr 2023 17:50:32 +0800 Subject: fix(lua): inspect_pos respect bufnr when get syntax info (#23098) --- test/functional/lua/inspector_spec.lua | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/inspector_spec.lua b/test/functional/lua/inspector_spec.lua index edc0519471..f9ec274290 100644 --- a/test/functional/lua/inspector_spec.lua +++ b/test/functional/lua/inspector_spec.lua @@ -12,17 +12,21 @@ describe('vim.inspect_pos', function() it('it returns items', function() local ret = exec_lua([[ local buf = vim.api.nvim_create_buf(true, false) + local buf1 = vim.api.nvim_create_buf(true, false) local ns1 = vim.api.nvim_create_namespace("ns1") local ns2 = vim.api.nvim_create_namespace("") vim.api.nvim_set_current_buf(buf) vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"}) + vim.api.nvim_buf_set_lines(buf1, 0, -1, false, {"--commentline"}) vim.api.nvim_buf_set_option(buf, "filetype", "lua") + vim.api.nvim_buf_set_option(buf1, "filetype", "lua") vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = "Normal" }) vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = "Normal" }) vim.cmd("syntax on") - return {buf, vim.inspect_pos(0, 0, 10)} + return {buf, vim.inspect_pos(0, 0, 10), vim.inspect_pos(buf1, 0, 10).syntax } ]]) - local buf, items = unpack(ret) + local buf, items, other_buf_syntax = unpack(ret) + eq('', eval('v:errmsg')) eq({ buffer = buf, @@ -73,6 +77,13 @@ describe('vim.inspect_pos', function() }, }, }, items) + + eq({ + { + hl_group = 'luaComment', + hl_group_link = 'Comment', + }, + }, other_buf_syntax) end) end) -- cgit From fd68cd1c0aa7b3074ed8b316a354bf17111cf0b3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 16 Apr 2023 18:27:33 +0800 Subject: vim-patch:8.2.2857: Vim9: exception in ISN_INSTR caught at wrong level (#23131) Problem: Vim9: exception in ISN_INSTR caught at wrong level. Solution: Set the starting trylevel in exec_instructions(). (closes vim/vim#8214) https://github.com/vim/vim/commit/ff65288aa89dcd50760ad942d58baff70c6e93e6 Co-authored-by: Bram Moolenaar --- test/functional/lua/api_spec.lua | 4 ++-- test/functional/lua/luaeval_spec.lua | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index dc6452dd62..ffa2f40e91 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -103,9 +103,9 @@ describe('luaeval(vim.api.…)', function() eq(NIL, funcs.luaeval('vim.api.nvim__id(nil)')) -- API strings from Blobs can work as NUL-terminated C strings - eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ', + eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ""', exc_exec('call nvim_eval(v:_null_blob)')) - eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ', + eq('Vim(call):E5555: API call: Vim:E15: Invalid expression: ""', exc_exec('call nvim_eval(0z)')) eq(1, eval('nvim_eval(0z31)')) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 32bb894be1..613008b5e1 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -539,11 +539,11 @@ describe('v:lua', function() end) it('throw errors for invalid use', function() - eq('Vim(let):E15: Invalid expression: v:lua.func', pcall_err(command, "let g:Func = v:lua.func")) - eq('Vim(let):E15: Invalid expression: v:lua', pcall_err(command, "let g:Func = v:lua")) - eq("Vim(let):E15: Invalid expression: v:['lua']", pcall_err(command, "let g:Func = v:['lua']")) + eq([[Vim(let):E15: Invalid expression: "v:lua.func"]], pcall_err(command, "let g:Func = v:lua.func")) + eq([[Vim(let):E15: Invalid expression: "v:lua"]], pcall_err(command, "let g:Func = v:lua")) + eq([[Vim(let):E15: Invalid expression: "v:['lua']"]], pcall_err(command, "let g:Func = v:['lua']")) - eq("Vim:E15: Invalid expression: v:['lua'].foo()", pcall_err(eval, "v:['lua'].foo()")) + eq([[Vim:E15: Invalid expression: "v:['lua'].foo()"]], pcall_err(eval, "v:['lua'].foo()")) eq("Vim(call):E461: Illegal variable name: v:['lua']", pcall_err(command, "call v:['lua'].baar()")) eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "v:lua()")) @@ -554,6 +554,6 @@ describe('v:lua', function() eq("Vim:E274: No white space allowed before parenthesis", pcall_err(eval, "'bad'->v:lua.func ()")) eq("Vim:E107: Missing parentheses: v:lua", pcall_err(eval, "'bad'->v:lua")) eq("Vim:E1085: Not a callable type: v:lua", pcall_err(eval, "'bad'->v:lua()")) - eq("Vim:E15: Invalid expression: v:lua.()", pcall_err(eval, "'bad'->v:lua.()")) + eq([[Vim:E15: Invalid expression: "v:lua.()"]], pcall_err(eval, "'bad'->v:lua.()")) end) end) -- cgit From 07b60efd8058bb515998f50048b511d50f9671f8 Mon Sep 17 00:00:00 2001 From: Isak Samsten Date: Mon, 17 Apr 2023 13:53:34 +0200 Subject: feat(diagnostic): specify diagnostic virtual text prefix as a function - vim.diagnostic.config() now accepts a function for the virtual_text.prefix option, which allows for rendering e.g., diagnostic severities differently. --- test/functional/lua/diagnostic_spec.lua | 60 +++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 10 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 6b4ca5ac73..17b2d7da4f 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -1042,7 +1042,7 @@ end) local virt_text = get_virt_text_extmarks(diagnostic_ns)[1][4].virt_text local virt_texts = {} - for i = 2, #virt_text do + for i = 2, #virt_text - 1 do table.insert(virt_texts, (string.gsub(virt_text[i][2], "DiagnosticVirtualText", ""))) end @@ -1086,7 +1086,7 @@ end) }) local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = extmarks[1][4].virt_text[2][1] + local virt_text = extmarks[1][4].virt_text[3][1] return virt_text ]] eq(' source x: Some error', result) @@ -1101,7 +1101,7 @@ end) }, diagnostic_ns) local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = extmarks[1][4].virt_text[2][1] + local virt_text = extmarks[1][4].virt_text[3][1] return virt_text ]] eq(' Some error', result) @@ -1121,7 +1121,7 @@ end) }) local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = {extmarks[1][4].virt_text[2][1], extmarks[2][4].virt_text[2][1]} + local virt_text = {extmarks[1][4].virt_text[3][1], extmarks[2][4].virt_text[3][1]} return virt_text ]] eq(' source x: Some error', result[1]) @@ -1151,8 +1151,8 @@ end) local extmarks = get_virt_text_extmarks(diagnostic_ns) return {extmarks[1][4].virt_text, extmarks[2][4].virt_text} ]] - eq(" 👀 Warning", result[1][2][1]) - eq(" 🔥 Error", result[2][2][1]) + eq(" 👀 Warning", result[1][3][1]) + eq(" 🔥 Error", result[2][3][1]) end) it('includes source for formatted diagnostics', function() @@ -1179,8 +1179,48 @@ end) local extmarks = get_virt_text_extmarks(diagnostic_ns) return {extmarks[1][4].virt_text, extmarks[2][4].virt_text} ]] - eq(" some_linter: 👀 Warning", result[1][2][1]) - eq(" another_linter: 🔥 Error", result[2][2][1]) + eq(" some_linter: 👀 Warning", result[1][3][1]) + eq(" another_linter: 🔥 Error", result[2][3][1]) + end) + + it('can add a prefix to virtual text', function() + eq('E Some error', exec_lua [[ + local diagnostics = { + make_error('Some error', 0, 0, 0, 0), + } + + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { + underline = false, + virtual_text = { + prefix = 'E', + suffix = '', + } + }) + + local extmarks = get_virt_text_extmarks(diagnostic_ns) + local prefix = extmarks[1][4].virt_text[2][1] + local message = extmarks[1][4].virt_text[3][1] + return prefix .. message + ]]) + + eq('[err-code] Some error', exec_lua [[ + local diagnostics = { + make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), + } + + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { + underline = false, + virtual_text = { + prefix = function(diag) return string.format('[%s]', diag.code) end, + suffix = '', + } + }) + + local extmarks = get_virt_text_extmarks(diagnostic_ns) + local prefix = extmarks[1][4].virt_text[2][1] + local message = extmarks[1][4].virt_text[3][1] + return prefix .. message + ]]) end) it('can add a suffix to virtual text', function() @@ -1198,7 +1238,7 @@ end) }) local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = extmarks[1][4].virt_text[2][1] + local virt_text = extmarks[1][4].virt_text[3][1] return virt_text ]]) @@ -1216,7 +1256,7 @@ end) }) local extmarks = get_virt_text_extmarks(diagnostic_ns) - local virt_text = extmarks[1][4].virt_text[2][1] + local virt_text = extmarks[1][4].virt_text[3][1] return virt_text ]]) end) -- cgit From 6cc76011ca28ff61f1c2f8de6d895d4c6d0a1ad8 Mon Sep 17 00:00:00 2001 From: Jon Huhn Date: Mon, 17 Apr 2023 11:50:05 -0500 Subject: fix(watchfiles): skip Created events when poll starts (#23139) --- test/functional/lua/watch_spec.lua | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index bbcfd27cde..ad8678c17a 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -122,10 +122,6 @@ describe('vim._watch', function() table.insert(events, { path = path, change_type = change_type }) end) - -- polling generates Created events for the existing entries when it starts. - expected_events = expected_events + 1 - wait_for_events() - vim.wait(100) local watched_path = root_dir .. '/file' @@ -158,39 +154,35 @@ describe('vim._watch', function() root_dir ) - eq(5, #result) - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), - path = root_dir, - }, result[1]) + eq(4, #result) eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), path = root_dir .. '/file', - }, result[2]) + }, result[1]) eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), path = root_dir, - }, result[3]) + }, result[2]) -- The file delete and corresponding directory change events do not happen in any -- particular order, so allow either - if result[4].path == root_dir then + if result[3].path == root_dir then eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), path = root_dir, - }, result[4]) + }, result[3]) eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), path = root_dir .. '/file', - }, result[5]) + }, result[4]) else eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), path = root_dir .. '/file', - }, result[4]) + }, result[3]) eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), path = root_dir, - }, result[5]) + }, result[4]) end end) end) -- cgit From ab1edecfb7c73c82c2d5886cb8e270b44aca7d01 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 17 Apr 2023 12:54:19 -0600 Subject: feat(lua): add vim.iter (#23029) vim.iter wraps a table or iterator function into an `Iter` object with methods such as `filter`, `map`, and `fold` which can be chained to produce iterator pipelines that do not create new tables at each step. --- test/functional/lua/vim_spec.lua | 354 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 354 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 1ee1a13fd5..e5caf6f6f7 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3029,6 +3029,360 @@ describe('lua stdlib', function() eq(false, if_nil(d, c)) eq(NIL, if_nil(a)) end) + + describe('vim.iter', function() + it('filter()', function() + local function odd(v) + return v % 2 ~= 0 + end + + local t = { 1, 2, 3, 4, 5 } + eq({ 1, 3, 5 }, vim.iter(t):filter(odd):totable()) + eq({ 2, 4 }, vim.iter(t):filter(function(v) return not odd(v) end):totable()) + eq({}, vim.iter(t):filter(function(v) if v > 5 then return v end end):totable()) + + do + local it = vim.iter(ipairs(t)) + it:filter(function(i, v) return i > 1 and v < 5 end) + it:map(function(_, v) return v * 2 end) + eq({ 4, 6, 8 }, it:totable()) + end + + local it = vim.iter(string.gmatch('the quick brown fox', '%w+')) + eq({'the', 'fox'}, it:filter(function(s) return #s <= 3 end):totable()) + end) + + it('map()', function() + local t = { 1, 2, 3, 4, 5 } + eq( + { 2, 4, 6, 8, 10 }, + vim + .iter(t) + :map(function(v) + return 2 * v + end) + :totable() + ) + + local it = vim.gsplit( + [[ + Line 1 + Line 2 + Line 3 + Line 4 + ]], + '\n' + ) + + eq( + { 'Lion 2', 'Lion 4' }, + vim + .iter(it) + :map(function(s) + local lnum = s:match('(%d+)') + if lnum and tonumber(lnum) % 2 == 0 then + return vim.trim(s:gsub('Line', 'Lion')) + end + end) + :totable() + ) + end) + + it('for loops', function() + local t = {1, 2, 3, 4, 5} + local acc = 0 + for v in vim.iter(t):map(function(v) return v * 3 end) do + acc = acc + v + end + eq(45, acc) + end) + + it('totable()', function() + do + local it = vim.iter({1, 2, 3}):map(function(v) return v, v*v end) + eq({{1, 1}, {2, 4}, {3, 9}}, it:totable()) + end + + do + local it = vim.iter(string.gmatch('1,4,lol,17,blah,2,9,3', '%d+')):map(tonumber) + eq({1, 4, 17, 2, 9, 3}, it:totable()) + end + end) + + it('next()', function() + local it = vim.iter({1, 2, 3}):map(function(v) return 2 * v end) + eq(2, it:next()) + eq(4, it:next()) + eq(6, it:next()) + eq(nil, it:next()) + end) + + it('rev()', function() + eq({3, 2, 1}, vim.iter({1, 2, 3}):rev():totable()) + + local it = vim.iter(string.gmatch("abc", "%w")) + matches('rev%(%) requires a list%-like table', pcall_err(it.rev, it)) + end) + + it('skip()', function() + do + local t = {4, 3, 2, 1} + eq(t, vim.iter(t):skip(0):totable()) + eq({3, 2, 1}, vim.iter(t):skip(1):totable()) + eq({2, 1}, vim.iter(t):skip(2):totable()) + eq({1}, vim.iter(t):skip(#t - 1):totable()) + eq({}, vim.iter(t):skip(#t):totable()) + eq({}, vim.iter(t):skip(#t + 1):totable()) + end + + do + local function skip(n) + return vim.iter(vim.gsplit('a|b|c|d', '|')):skip(n):totable() + end + eq({'a', 'b', 'c', 'd'}, skip(0)) + eq({'b', 'c', 'd'}, skip(1)) + eq({'c', 'd'}, skip(2)) + eq({'d'}, skip(3)) + eq({}, skip(4)) + eq({}, skip(5)) + end + end) + + it('skipback()', function() + do + local t = {4, 3, 2, 1} + eq(t, vim.iter(t):skipback(0):totable()) + eq({4, 3, 2}, vim.iter(t):skipback(1):totable()) + eq({4, 3}, vim.iter(t):skipback(2):totable()) + eq({4}, vim.iter(t):skipback(#t - 1):totable()) + eq({}, vim.iter(t):skipback(#t):totable()) + eq({}, vim.iter(t):skipback(#t + 1):totable()) + end + + local it = vim.iter(vim.gsplit('a|b|c|d', '|')) + matches('skipback%(%) requires a list%-like table', pcall_err(it.skipback, it, 0)) + end) + + it('slice()', function() + local t = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + eq({3, 4, 5, 6, 7}, vim.iter(t):slice(3, 7):totable()) + eq({}, vim.iter(t):slice(6, 5):totable()) + eq({}, vim.iter(t):slice(0, 0):totable()) + eq({1}, vim.iter(t):slice(1, 1):totable()) + eq({1, 2}, vim.iter(t):slice(1, 2):totable()) + eq({10}, vim.iter(t):slice(10, 10):totable()) + eq({8, 9, 10}, vim.iter(t):slice(8, 11):totable()) + end) + + it('nth()', function() + do + local t = {4, 3, 2, 1} + eq(nil, vim.iter(t):nth(0)) + eq(4, vim.iter(t):nth(1)) + eq(3, vim.iter(t):nth(2)) + eq(2, vim.iter(t):nth(3)) + eq(1, vim.iter(t):nth(4)) + eq(nil, vim.iter(t):nth(5)) + end + + do + local function nth(n) + return vim.iter(vim.gsplit('a|b|c|d', '|')):nth(n) + end + eq(nil, nth(0)) + eq('a', nth(1)) + eq('b', nth(2)) + eq('c', nth(3)) + eq('d', nth(4)) + eq(nil, nth(5)) + end + end) + + it('nthback()', function() + do + local t = {4, 3, 2, 1} + eq(nil, vim.iter(t):nthback(0)) + eq(1, vim.iter(t):nthback(1)) + eq(2, vim.iter(t):nthback(2)) + eq(3, vim.iter(t):nthback(3)) + eq(4, vim.iter(t):nthback(4)) + eq(nil, vim.iter(t):nthback(5)) + end + + local it = vim.iter(vim.gsplit('a|b|c|d', '|')) + matches('skipback%(%) requires a list%-like table', pcall_err(it.nthback, it, 1)) + end) + + it('any()', function() + local function odd(v) + return v % 2 ~= 0 + end + + do + local t = { 4, 8, 9, 10 } + eq(true, vim.iter(t):any(odd)) + end + + do + local t = { 4, 8, 10 } + eq(false, vim.iter(t):any(odd)) + end + + do + eq(true, vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s) return s == 'd' end)) + eq(false, vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s) return s == 'e' end)) + end + end) + + it('all()', function() + local function odd(v) + return v % 2 ~= 0 + end + + do + local t = { 3, 5, 7, 9 } + eq(true, vim.iter(t):all(odd)) + end + + do + local t = { 3, 5, 7, 10 } + eq(false, vim.iter(t):all(odd)) + end + + do + eq(true, vim.iter(vim.gsplit('a|a|a|a', '|')):all(function(s) return s == 'a' end)) + eq(false, vim.iter(vim.gsplit('a|a|a|b', '|')):all(function(s) return s == 'a' end)) + end + end) + + it('last()', function() + local s = 'abcdefghijklmnopqrstuvwxyz' + eq('z', vim.iter(vim.split(s, '')):last()) + eq('z', vim.iter(vim.gsplit(s, '')):last()) + end) + + it('enumerate()', function() + local it = vim.iter(vim.gsplit('abc', '')):enumerate() + eq({1, 'a'}, {it:next()}) + eq({2, 'b'}, {it:next()}) + eq({3, 'c'}, {it:next()}) + eq({}, {it:next()}) + end) + + it('peek()', function() + do + local it = vim.iter({ 3, 6, 9, 12 }) + eq(3, it:peek()) + eq(3, it:peek()) + eq(3, it:next()) + end + + do + local it = vim.iter(vim.gsplit('hi', '')) + matches('peek%(%) requires a list%-like table', pcall_err(it.peek, it)) + end + end) + + it('find()', function() + local t = {3, 6, 9, 12} + eq(12, vim.iter(t):find(12)) + eq(nil, vim.iter(t):find(15)) + eq(12, vim.iter(t):find(function(v) return v % 4 == 0 end)) + + do + local it = vim.iter(t) + local pred = function(v) return v % 3 == 0 end + eq(3, it:find(pred)) + eq(6, it:find(pred)) + eq(9, it:find(pred)) + eq(12, it:find(pred)) + eq(nil, it:find(pred)) + end + + do + local it = vim.iter(vim.gsplit('AbCdE', '')) + local pred = function(s) return s:match('[A-Z]') end + eq('A', it:find(pred)) + eq('C', it:find(pred)) + eq('E', it:find(pred)) + eq(nil, it:find(pred)) + end + end) + + it('rfind()', function() + local t = {1, 2, 3, 2, 1} + do + local it = vim.iter(t) + eq(1, it:rfind(1)) + eq(1, it:rfind(1)) + eq(nil, it:rfind(1)) + end + + do + local it = vim.iter(t):enumerate() + local pred = function(i) return i % 2 ~= 0 end + eq({5, 1}, {it:rfind(pred)}) + eq({3, 3}, {it:rfind(pred)}) + eq({1, 1}, {it:rfind(pred)}) + eq(nil, it:rfind(pred)) + end + + do + local it = vim.iter(vim.gsplit('AbCdE', '')) + matches('rfind%(%) requires a list%-like table', pcall_err(it.rfind, it, 'E')) + end + end) + + it('nextback()', function() + do + local it = vim.iter({ 1, 2, 3, 4 }) + eq(4, it:nextback()) + eq(3, it:nextback()) + eq(2, it:nextback()) + eq(1, it:nextback()) + eq(nil, it:nextback()) + eq(nil, it:nextback()) + end + + do + local it = vim.iter(vim.gsplit('hi', '')) + matches('nextback%(%) requires a list%-like table', pcall_err(it.nextback, it)) + end + end) + + it('peekback()', function() + do + local it = vim.iter({ 1, 2, 3, 4 }) + eq(4, it:peekback()) + eq(4, it:peekback()) + eq(4, it:peekback()) + end + + do + local it = vim.iter(vim.gsplit('hi', '')) + matches('peekback%(%) requires a list%-like table', pcall_err(it.peekback, it)) + end + end) + + it('fold()', function() + local t = {1, 2, 3, 4, 5} + eq(115, vim.iter(t):fold(100, function(acc, v) return acc + v end)) + eq({5, 4, 3, 2, 1}, vim.iter(t):fold({}, function(acc, v) + table.insert(acc, 1, v) + return acc + end)) + end) + + it('handles map-like tables', function() + local t = { a = 1, b = 2, c = 3 } + local it = vim.iter(t):map(function(k, v) + if v % 2 ~= 0 then + return k:upper(), v * 2 + end + end) + eq({ A = 2, C = 6 }, it:totable()) + end) + end) end) describe('lua: builtin modules', function() -- cgit From 6b96122453fda22dc44a581af1d536988c1adf41 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Wed, 19 Apr 2023 06:45:56 -0600 Subject: fix(iter): add tag to packed table If pack() is called with a single value, it does not create a table; it simply returns the value it is passed. When unpack is called with a table argument, it interprets that table as a list of values that were packed together into a table. This causes a problem when the single value being packed is _itself_ a table. pack() will not place it into another table, but unpack() sees the table argument and tries to unpack it. To fix this, we add a simple "tag" to packed table values so that unpack() only attempts to unpack tables that have this tag. Other tables are left alone. The tag is simply the length of the table. --- test/functional/lua/vim_spec.lua | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index e5caf6f6f7..07b0f0340a 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3381,6 +3381,33 @@ describe('lua stdlib', function() end end) eq({ A = 2, C = 6 }, it:totable()) + + it('handles table values mid-pipeline', function() + local map = { + item = { + file = 'test', + }, + item_2 = { + file = 'test', + }, + item_3 = { + file = 'test', + }, + } + + local output = vim.iter(map):map(function(key, value) + return { [key] = value.file } + end):totable() + + table.sort(output, function(a, b) + return next(a) < next(b) + end) + + eq({ + { item = 'test' }, + { item_2 = 'test' }, + { item_3 = 'test' }, + }, output) end) end) end) -- cgit From 94894068794dbb99804cda689b6c37e70376c8ca Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Wed, 19 Apr 2023 07:05:04 -0600 Subject: fix(iter): remove special case totable for map-like tables This was originally meant as a convenience but prevents possible functionality. For example: -- Get the keys of the table with even values local t = { a = 1, b = 2, c = 3, d = 4 } vim.iter(t):map(function(k, v) if v % 2 == 0 then return k end end):totable() The example above would not work, because the map() function returns only a single value, and cannot be converted back into a table (there are many such examples like this). Instead, to convert an iterator into a map-like table, users can use fold(): vim.iter(t):fold({}, function(t, k, v) t[k] = v return t end) --- test/functional/lua/vim_spec.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 07b0f0340a..e37d477376 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3374,13 +3374,18 @@ describe('lua stdlib', function() end) it('handles map-like tables', function() - local t = { a = 1, b = 2, c = 3 } - local it = vim.iter(t):map(function(k, v) + local it = vim.iter({ a = 1, b = 2, c = 3 }):map(function(k, v) if v % 2 ~= 0 then return k:upper(), v * 2 end end) - eq({ A = 2, C = 6 }, it:totable()) + + local t = it:fold({}, function(t, k, v) + t[k] = v + return t + end) + eq({ A = 2, C = 6 }, t) + end) it('handles table values mid-pipeline', function() local map = { -- cgit From 622b1ae38a36c3d26fad19faa788d622f7835921 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 21 Apr 2023 06:46:18 +0200 Subject: fix(lua): vim.split may trim inner empty items Problem: `vim.split('a:::', ':', {trimempty=true})` trims inner empty items. Regression from 9c49c1047079427ff0a2356cb37302934845108e Solution: Set `empty_start=false` when first non-empty item is found. close #23212 --- test/functional/lua/vim_spec.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index e37d477376..b8cc15b2ca 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -294,9 +294,11 @@ describe('lua stdlib', function() it('vim.gsplit, vim.split', function() local tests = { + -- plain trimempty { 'a,b', ',', false, false, { 'a', 'b' } }, { ':aa::::bb:', ':', false, false, { '', 'aa', '', '', '', 'bb', '' } }, { ':aa::::bb:', ':', false, true, { 'aa', '', '', '', 'bb' } }, + { 'aa::::bb:', ':', false, true, { 'aa', '', '', '', 'bb' } }, { ':aa::bb:', ':', false, true, { 'aa', '', 'bb' } }, { '/a/b:/b/\n', '[:\n]', false, true, { '/a/b', '/b/' } }, { '::ee::ff:', ':', false, false, { '', '', 'ee', '', 'ff', '' } }, @@ -315,7 +317,7 @@ describe('lua stdlib', function() } for _, t in ipairs(tests) do - eq(t[5], vim.split(t[1], t[2], {plain=t[3], trimempty=t[4]})) + eq(t[5], vim.split(t[1], t[2], {plain=t[3], trimempty=t[4]}), t[1]) end -- Test old signature -- cgit From f68af3c3bc92c12f7dbbd32f44df8ab57a58ac98 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Fri, 21 Apr 2023 16:13:39 -0600 Subject: refactor(iter): use metatable as packed table tag (#23254) This is a more robust method for tagging a packed table as it completely eliminates the possibility of mistaking an actual table key as the packed table tag. --- test/functional/lua/vim_spec.lua | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index b8cc15b2ca..42927f7e1b 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3416,6 +3416,41 @@ describe('lua stdlib', function() { item_3 = 'test' }, }, output) end) + + it('handles nil values', function() + local t = {1, 2, 3, 4, 5} + do + local it = vim.iter(t):enumerate():map(function(i, v) + if i % 2 == 0 then + return nil, v*v + end + return v, nil + end) + eq({ + { [1] = 1 }, + { [2] = 4 }, + { [1] = 3 }, + { [2] = 16 }, + { [1] = 5 }, + }, it:totable()) + end + + do + local it = vim.iter(ipairs(t)):map(function(i, v) + if i % 2 == 0 then + return nil, v*v + end + return v, nil + end) + eq({ + { [1] = 1 }, + { [2] = 4 }, + { [1] = 3 }, + { [2] = 16 }, + { [1] = 5 }, + }, it:totable()) + end + end) end) end) -- cgit From 147bb87245cdb348e67c659415d0661d48aa5f1e Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Fri, 21 Apr 2023 07:04:35 -0600 Subject: test: move vim.iter tests to separate file --- test/functional/lua/iter_spec.lua | 425 ++++++++++++++++++++++++++++++++++++++ test/functional/lua/vim_spec.lua | 421 ------------------------------------- 2 files changed, 425 insertions(+), 421 deletions(-) create mode 100644 test/functional/lua/iter_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/iter_spec.lua b/test/functional/lua/iter_spec.lua new file mode 100644 index 0000000000..6e1ecc2f7e --- /dev/null +++ b/test/functional/lua/iter_spec.lua @@ -0,0 +1,425 @@ +local helpers = require('test.functional.helpers')(after_each) +local eq = helpers.eq +local matches = helpers.matches +local pcall_err = helpers.pcall_err + +describe('vim.iter', function() + it('filter()', function() + local function odd(v) + return v % 2 ~= 0 + end + + local t = { 1, 2, 3, 4, 5 } + eq({ 1, 3, 5 }, vim.iter(t):filter(odd):totable()) + eq({ 2, 4 }, vim.iter(t):filter(function(v) return not odd(v) end):totable()) + eq({}, vim.iter(t):filter(function(v) return v > 5 end):totable()) + + do + local it = vim.iter(ipairs(t)) + it:filter(function(i, v) return i > 1 and v < 5 end) + it:map(function(_, v) return v * 2 end) + eq({ 4, 6, 8 }, it:totable()) + end + + local it = vim.iter(string.gmatch('the quick brown fox', '%w+')) + eq({'the', 'fox'}, it:filter(function(s) return #s <= 3 end):totable()) + end) + + it('map()', function() + local t = { 1, 2, 3, 4, 5 } + eq( + { 2, 4, 6, 8, 10 }, + vim + .iter(t) + :map(function(v) + return 2 * v + end) + :totable() + ) + + local it = vim.gsplit( + [[ + Line 1 + Line 2 + Line 3 + Line 4 + ]], + '\n' + ) + + eq( + { 'Lion 2', 'Lion 4' }, + vim + .iter(it) + :map(function(s) + local lnum = s:match('(%d+)') + if lnum and tonumber(lnum) % 2 == 0 then + return vim.trim(s:gsub('Line', 'Lion')) + end + end) + :totable() + ) + end) + + it('for loops', function() + local t = {1, 2, 3, 4, 5} + local acc = 0 + for v in vim.iter(t):map(function(v) return v * 3 end) do + acc = acc + v + end + eq(45, acc) + end) + + it('totable()', function() + do + local it = vim.iter({1, 2, 3}):map(function(v) return v, v*v end) + eq({{1, 1}, {2, 4}, {3, 9}}, it:totable()) + end + + do + local it = vim.iter(string.gmatch('1,4,lol,17,blah,2,9,3', '%d+')):map(tonumber) + eq({1, 4, 17, 2, 9, 3}, it:totable()) + end + end) + + it('next()', function() + local it = vim.iter({1, 2, 3}):map(function(v) return 2 * v end) + eq(2, it:next()) + eq(4, it:next()) + eq(6, it:next()) + eq(nil, it:next()) + end) + + it('rev()', function() + eq({3, 2, 1}, vim.iter({1, 2, 3}):rev():totable()) + + local it = vim.iter(string.gmatch("abc", "%w")) + matches('rev%(%) requires a list%-like table', pcall_err(it.rev, it)) + end) + + it('skip()', function() + do + local t = {4, 3, 2, 1} + eq(t, vim.iter(t):skip(0):totable()) + eq({3, 2, 1}, vim.iter(t):skip(1):totable()) + eq({2, 1}, vim.iter(t):skip(2):totable()) + eq({1}, vim.iter(t):skip(#t - 1):totable()) + eq({}, vim.iter(t):skip(#t):totable()) + eq({}, vim.iter(t):skip(#t + 1):totable()) + end + + do + local function skip(n) + return vim.iter(vim.gsplit('a|b|c|d', '|')):skip(n):totable() + end + eq({'a', 'b', 'c', 'd'}, skip(0)) + eq({'b', 'c', 'd'}, skip(1)) + eq({'c', 'd'}, skip(2)) + eq({'d'}, skip(3)) + eq({}, skip(4)) + eq({}, skip(5)) + end + end) + + it('skipback()', function() + do + local t = {4, 3, 2, 1} + eq(t, vim.iter(t):skipback(0):totable()) + eq({4, 3, 2}, vim.iter(t):skipback(1):totable()) + eq({4, 3}, vim.iter(t):skipback(2):totable()) + eq({4}, vim.iter(t):skipback(#t - 1):totable()) + eq({}, vim.iter(t):skipback(#t):totable()) + eq({}, vim.iter(t):skipback(#t + 1):totable()) + end + + local it = vim.iter(vim.gsplit('a|b|c|d', '|')) + matches('skipback%(%) requires a list%-like table', pcall_err(it.skipback, it, 0)) + end) + + it('slice()', function() + local t = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + eq({3, 4, 5, 6, 7}, vim.iter(t):slice(3, 7):totable()) + eq({}, vim.iter(t):slice(6, 5):totable()) + eq({}, vim.iter(t):slice(0, 0):totable()) + eq({1}, vim.iter(t):slice(1, 1):totable()) + eq({1, 2}, vim.iter(t):slice(1, 2):totable()) + eq({10}, vim.iter(t):slice(10, 10):totable()) + eq({8, 9, 10}, vim.iter(t):slice(8, 11):totable()) + end) + + it('nth()', function() + do + local t = {4, 3, 2, 1} + eq(nil, vim.iter(t):nth(0)) + eq(4, vim.iter(t):nth(1)) + eq(3, vim.iter(t):nth(2)) + eq(2, vim.iter(t):nth(3)) + eq(1, vim.iter(t):nth(4)) + eq(nil, vim.iter(t):nth(5)) + end + + do + local function nth(n) + return vim.iter(vim.gsplit('a|b|c|d', '|')):nth(n) + end + eq(nil, nth(0)) + eq('a', nth(1)) + eq('b', nth(2)) + eq('c', nth(3)) + eq('d', nth(4)) + eq(nil, nth(5)) + end + end) + + it('nthback()', function() + do + local t = {4, 3, 2, 1} + eq(nil, vim.iter(t):nthback(0)) + eq(1, vim.iter(t):nthback(1)) + eq(2, vim.iter(t):nthback(2)) + eq(3, vim.iter(t):nthback(3)) + eq(4, vim.iter(t):nthback(4)) + eq(nil, vim.iter(t):nthback(5)) + end + + local it = vim.iter(vim.gsplit('a|b|c|d', '|')) + matches('skipback%(%) requires a list%-like table', pcall_err(it.nthback, it, 1)) + end) + + it('any()', function() + local function odd(v) + return v % 2 ~= 0 + end + + do + local t = { 4, 8, 9, 10 } + eq(true, vim.iter(t):any(odd)) + end + + do + local t = { 4, 8, 10 } + eq(false, vim.iter(t):any(odd)) + end + + do + eq(true, vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s) return s == 'd' end)) + eq(false, vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s) return s == 'e' end)) + end + end) + + it('all()', function() + local function odd(v) + return v % 2 ~= 0 + end + + do + local t = { 3, 5, 7, 9 } + eq(true, vim.iter(t):all(odd)) + end + + do + local t = { 3, 5, 7, 10 } + eq(false, vim.iter(t):all(odd)) + end + + do + eq(true, vim.iter(vim.gsplit('a|a|a|a', '|')):all(function(s) return s == 'a' end)) + eq(false, vim.iter(vim.gsplit('a|a|a|b', '|')):all(function(s) return s == 'a' end)) + end + end) + + it('last()', function() + local s = 'abcdefghijklmnopqrstuvwxyz' + eq('z', vim.iter(vim.split(s, '')):last()) + eq('z', vim.iter(vim.gsplit(s, '')):last()) + end) + + it('enumerate()', function() + local it = vim.iter(vim.gsplit('abc', '')):enumerate() + eq({1, 'a'}, {it:next()}) + eq({2, 'b'}, {it:next()}) + eq({3, 'c'}, {it:next()}) + eq({}, {it:next()}) + end) + + it('peek()', function() + do + local it = vim.iter({ 3, 6, 9, 12 }) + eq(3, it:peek()) + eq(3, it:peek()) + eq(3, it:next()) + end + + do + local it = vim.iter(vim.gsplit('hi', '')) + matches('peek%(%) requires a list%-like table', pcall_err(it.peek, it)) + end + end) + + it('find()', function() + local t = {3, 6, 9, 12} + eq(12, vim.iter(t):find(12)) + eq(nil, vim.iter(t):find(15)) + eq(12, vim.iter(t):find(function(v) return v % 4 == 0 end)) + + do + local it = vim.iter(t) + local pred = function(v) return v % 3 == 0 end + eq(3, it:find(pred)) + eq(6, it:find(pred)) + eq(9, it:find(pred)) + eq(12, it:find(pred)) + eq(nil, it:find(pred)) + end + + do + local it = vim.iter(vim.gsplit('AbCdE', '')) + local pred = function(s) return s:match('[A-Z]') end + eq('A', it:find(pred)) + eq('C', it:find(pred)) + eq('E', it:find(pred)) + eq(nil, it:find(pred)) + end + end) + + it('rfind()', function() + local t = {1, 2, 3, 2, 1} + do + local it = vim.iter(t) + eq(1, it:rfind(1)) + eq(1, it:rfind(1)) + eq(nil, it:rfind(1)) + end + + do + local it = vim.iter(t):enumerate() + local pred = function(i) return i % 2 ~= 0 end + eq({5, 1}, {it:rfind(pred)}) + eq({3, 3}, {it:rfind(pred)}) + eq({1, 1}, {it:rfind(pred)}) + eq(nil, it:rfind(pred)) + end + + do + local it = vim.iter(vim.gsplit('AbCdE', '')) + matches('rfind%(%) requires a list%-like table', pcall_err(it.rfind, it, 'E')) + end + end) + + it('nextback()', function() + do + local it = vim.iter({ 1, 2, 3, 4 }) + eq(4, it:nextback()) + eq(3, it:nextback()) + eq(2, it:nextback()) + eq(1, it:nextback()) + eq(nil, it:nextback()) + eq(nil, it:nextback()) + end + + do + local it = vim.iter(vim.gsplit('hi', '')) + matches('nextback%(%) requires a list%-like table', pcall_err(it.nextback, it)) + end + end) + + it('peekback()', function() + do + local it = vim.iter({ 1, 2, 3, 4 }) + eq(4, it:peekback()) + eq(4, it:peekback()) + eq(4, it:nextback()) + end + + do + local it = vim.iter(vim.gsplit('hi', '')) + matches('peekback%(%) requires a list%-like table', pcall_err(it.peekback, it)) + end + end) + + it('fold()', function() + local t = {1, 2, 3, 4, 5} + eq(115, vim.iter(t):fold(100, function(acc, v) return acc + v end)) + eq({5, 4, 3, 2, 1}, vim.iter(t):fold({}, function(acc, v) + table.insert(acc, 1, v) + return acc + end)) + end) + + it('handles map-like tables', function() + local it = vim.iter({ a = 1, b = 2, c = 3 }):map(function(k, v) + if v % 2 ~= 0 then + return k:upper(), v * 2 + end + end) + + local t = it:fold({}, function(t, k, v) + t[k] = v + return t + end) + eq({ A = 2, C = 6 }, t) + end) + + it('handles table values mid-pipeline', function() + local map = { + item = { + file = 'test', + }, + item_2 = { + file = 'test', + }, + item_3 = { + file = 'test', + }, + } + + local output = vim.iter(map):map(function(key, value) + return { [key] = value.file } + end):totable() + + table.sort(output, function(a, b) + return next(a) < next(b) + end) + + eq({ + { item = 'test' }, + { item_2 = 'test' }, + { item_3 = 'test' }, + }, output) + end) + + it('handles nil values', function() + local t = {1, 2, 3, 4, 5} + do + local it = vim.iter(t):enumerate():map(function(i, v) + if i % 2 == 0 then + return nil, v*v + end + return v, nil + end) + eq({ + { [1] = 1 }, + { [2] = 4 }, + { [1] = 3 }, + { [2] = 16 }, + { [1] = 5 }, + }, it:totable()) + end + + do + local it = vim.iter(ipairs(t)):map(function(i, v) + if i % 2 == 0 then + return nil, v*v + end + return v, nil + end) + eq({ + { [1] = 1 }, + { [2] = 4 }, + { [1] = 3 }, + { [2] = 16 }, + { [1] = 5 }, + }, it:totable()) + end + end) +end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 42927f7e1b..53c21fd668 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3031,427 +3031,6 @@ describe('lua stdlib', function() eq(false, if_nil(d, c)) eq(NIL, if_nil(a)) end) - - describe('vim.iter', function() - it('filter()', function() - local function odd(v) - return v % 2 ~= 0 - end - - local t = { 1, 2, 3, 4, 5 } - eq({ 1, 3, 5 }, vim.iter(t):filter(odd):totable()) - eq({ 2, 4 }, vim.iter(t):filter(function(v) return not odd(v) end):totable()) - eq({}, vim.iter(t):filter(function(v) if v > 5 then return v end end):totable()) - - do - local it = vim.iter(ipairs(t)) - it:filter(function(i, v) return i > 1 and v < 5 end) - it:map(function(_, v) return v * 2 end) - eq({ 4, 6, 8 }, it:totable()) - end - - local it = vim.iter(string.gmatch('the quick brown fox', '%w+')) - eq({'the', 'fox'}, it:filter(function(s) return #s <= 3 end):totable()) - end) - - it('map()', function() - local t = { 1, 2, 3, 4, 5 } - eq( - { 2, 4, 6, 8, 10 }, - vim - .iter(t) - :map(function(v) - return 2 * v - end) - :totable() - ) - - local it = vim.gsplit( - [[ - Line 1 - Line 2 - Line 3 - Line 4 - ]], - '\n' - ) - - eq( - { 'Lion 2', 'Lion 4' }, - vim - .iter(it) - :map(function(s) - local lnum = s:match('(%d+)') - if lnum and tonumber(lnum) % 2 == 0 then - return vim.trim(s:gsub('Line', 'Lion')) - end - end) - :totable() - ) - end) - - it('for loops', function() - local t = {1, 2, 3, 4, 5} - local acc = 0 - for v in vim.iter(t):map(function(v) return v * 3 end) do - acc = acc + v - end - eq(45, acc) - end) - - it('totable()', function() - do - local it = vim.iter({1, 2, 3}):map(function(v) return v, v*v end) - eq({{1, 1}, {2, 4}, {3, 9}}, it:totable()) - end - - do - local it = vim.iter(string.gmatch('1,4,lol,17,blah,2,9,3', '%d+')):map(tonumber) - eq({1, 4, 17, 2, 9, 3}, it:totable()) - end - end) - - it('next()', function() - local it = vim.iter({1, 2, 3}):map(function(v) return 2 * v end) - eq(2, it:next()) - eq(4, it:next()) - eq(6, it:next()) - eq(nil, it:next()) - end) - - it('rev()', function() - eq({3, 2, 1}, vim.iter({1, 2, 3}):rev():totable()) - - local it = vim.iter(string.gmatch("abc", "%w")) - matches('rev%(%) requires a list%-like table', pcall_err(it.rev, it)) - end) - - it('skip()', function() - do - local t = {4, 3, 2, 1} - eq(t, vim.iter(t):skip(0):totable()) - eq({3, 2, 1}, vim.iter(t):skip(1):totable()) - eq({2, 1}, vim.iter(t):skip(2):totable()) - eq({1}, vim.iter(t):skip(#t - 1):totable()) - eq({}, vim.iter(t):skip(#t):totable()) - eq({}, vim.iter(t):skip(#t + 1):totable()) - end - - do - local function skip(n) - return vim.iter(vim.gsplit('a|b|c|d', '|')):skip(n):totable() - end - eq({'a', 'b', 'c', 'd'}, skip(0)) - eq({'b', 'c', 'd'}, skip(1)) - eq({'c', 'd'}, skip(2)) - eq({'d'}, skip(3)) - eq({}, skip(4)) - eq({}, skip(5)) - end - end) - - it('skipback()', function() - do - local t = {4, 3, 2, 1} - eq(t, vim.iter(t):skipback(0):totable()) - eq({4, 3, 2}, vim.iter(t):skipback(1):totable()) - eq({4, 3}, vim.iter(t):skipback(2):totable()) - eq({4}, vim.iter(t):skipback(#t - 1):totable()) - eq({}, vim.iter(t):skipback(#t):totable()) - eq({}, vim.iter(t):skipback(#t + 1):totable()) - end - - local it = vim.iter(vim.gsplit('a|b|c|d', '|')) - matches('skipback%(%) requires a list%-like table', pcall_err(it.skipback, it, 0)) - end) - - it('slice()', function() - local t = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} - eq({3, 4, 5, 6, 7}, vim.iter(t):slice(3, 7):totable()) - eq({}, vim.iter(t):slice(6, 5):totable()) - eq({}, vim.iter(t):slice(0, 0):totable()) - eq({1}, vim.iter(t):slice(1, 1):totable()) - eq({1, 2}, vim.iter(t):slice(1, 2):totable()) - eq({10}, vim.iter(t):slice(10, 10):totable()) - eq({8, 9, 10}, vim.iter(t):slice(8, 11):totable()) - end) - - it('nth()', function() - do - local t = {4, 3, 2, 1} - eq(nil, vim.iter(t):nth(0)) - eq(4, vim.iter(t):nth(1)) - eq(3, vim.iter(t):nth(2)) - eq(2, vim.iter(t):nth(3)) - eq(1, vim.iter(t):nth(4)) - eq(nil, vim.iter(t):nth(5)) - end - - do - local function nth(n) - return vim.iter(vim.gsplit('a|b|c|d', '|')):nth(n) - end - eq(nil, nth(0)) - eq('a', nth(1)) - eq('b', nth(2)) - eq('c', nth(3)) - eq('d', nth(4)) - eq(nil, nth(5)) - end - end) - - it('nthback()', function() - do - local t = {4, 3, 2, 1} - eq(nil, vim.iter(t):nthback(0)) - eq(1, vim.iter(t):nthback(1)) - eq(2, vim.iter(t):nthback(2)) - eq(3, vim.iter(t):nthback(3)) - eq(4, vim.iter(t):nthback(4)) - eq(nil, vim.iter(t):nthback(5)) - end - - local it = vim.iter(vim.gsplit('a|b|c|d', '|')) - matches('skipback%(%) requires a list%-like table', pcall_err(it.nthback, it, 1)) - end) - - it('any()', function() - local function odd(v) - return v % 2 ~= 0 - end - - do - local t = { 4, 8, 9, 10 } - eq(true, vim.iter(t):any(odd)) - end - - do - local t = { 4, 8, 10 } - eq(false, vim.iter(t):any(odd)) - end - - do - eq(true, vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s) return s == 'd' end)) - eq(false, vim.iter(vim.gsplit('a|b|c|d', '|')):any(function(s) return s == 'e' end)) - end - end) - - it('all()', function() - local function odd(v) - return v % 2 ~= 0 - end - - do - local t = { 3, 5, 7, 9 } - eq(true, vim.iter(t):all(odd)) - end - - do - local t = { 3, 5, 7, 10 } - eq(false, vim.iter(t):all(odd)) - end - - do - eq(true, vim.iter(vim.gsplit('a|a|a|a', '|')):all(function(s) return s == 'a' end)) - eq(false, vim.iter(vim.gsplit('a|a|a|b', '|')):all(function(s) return s == 'a' end)) - end - end) - - it('last()', function() - local s = 'abcdefghijklmnopqrstuvwxyz' - eq('z', vim.iter(vim.split(s, '')):last()) - eq('z', vim.iter(vim.gsplit(s, '')):last()) - end) - - it('enumerate()', function() - local it = vim.iter(vim.gsplit('abc', '')):enumerate() - eq({1, 'a'}, {it:next()}) - eq({2, 'b'}, {it:next()}) - eq({3, 'c'}, {it:next()}) - eq({}, {it:next()}) - end) - - it('peek()', function() - do - local it = vim.iter({ 3, 6, 9, 12 }) - eq(3, it:peek()) - eq(3, it:peek()) - eq(3, it:next()) - end - - do - local it = vim.iter(vim.gsplit('hi', '')) - matches('peek%(%) requires a list%-like table', pcall_err(it.peek, it)) - end - end) - - it('find()', function() - local t = {3, 6, 9, 12} - eq(12, vim.iter(t):find(12)) - eq(nil, vim.iter(t):find(15)) - eq(12, vim.iter(t):find(function(v) return v % 4 == 0 end)) - - do - local it = vim.iter(t) - local pred = function(v) return v % 3 == 0 end - eq(3, it:find(pred)) - eq(6, it:find(pred)) - eq(9, it:find(pred)) - eq(12, it:find(pred)) - eq(nil, it:find(pred)) - end - - do - local it = vim.iter(vim.gsplit('AbCdE', '')) - local pred = function(s) return s:match('[A-Z]') end - eq('A', it:find(pred)) - eq('C', it:find(pred)) - eq('E', it:find(pred)) - eq(nil, it:find(pred)) - end - end) - - it('rfind()', function() - local t = {1, 2, 3, 2, 1} - do - local it = vim.iter(t) - eq(1, it:rfind(1)) - eq(1, it:rfind(1)) - eq(nil, it:rfind(1)) - end - - do - local it = vim.iter(t):enumerate() - local pred = function(i) return i % 2 ~= 0 end - eq({5, 1}, {it:rfind(pred)}) - eq({3, 3}, {it:rfind(pred)}) - eq({1, 1}, {it:rfind(pred)}) - eq(nil, it:rfind(pred)) - end - - do - local it = vim.iter(vim.gsplit('AbCdE', '')) - matches('rfind%(%) requires a list%-like table', pcall_err(it.rfind, it, 'E')) - end - end) - - it('nextback()', function() - do - local it = vim.iter({ 1, 2, 3, 4 }) - eq(4, it:nextback()) - eq(3, it:nextback()) - eq(2, it:nextback()) - eq(1, it:nextback()) - eq(nil, it:nextback()) - eq(nil, it:nextback()) - end - - do - local it = vim.iter(vim.gsplit('hi', '')) - matches('nextback%(%) requires a list%-like table', pcall_err(it.nextback, it)) - end - end) - - it('peekback()', function() - do - local it = vim.iter({ 1, 2, 3, 4 }) - eq(4, it:peekback()) - eq(4, it:peekback()) - eq(4, it:peekback()) - end - - do - local it = vim.iter(vim.gsplit('hi', '')) - matches('peekback%(%) requires a list%-like table', pcall_err(it.peekback, it)) - end - end) - - it('fold()', function() - local t = {1, 2, 3, 4, 5} - eq(115, vim.iter(t):fold(100, function(acc, v) return acc + v end)) - eq({5, 4, 3, 2, 1}, vim.iter(t):fold({}, function(acc, v) - table.insert(acc, 1, v) - return acc - end)) - end) - - it('handles map-like tables', function() - local it = vim.iter({ a = 1, b = 2, c = 3 }):map(function(k, v) - if v % 2 ~= 0 then - return k:upper(), v * 2 - end - end) - - local t = it:fold({}, function(t, k, v) - t[k] = v - return t - end) - eq({ A = 2, C = 6 }, t) - end) - - it('handles table values mid-pipeline', function() - local map = { - item = { - file = 'test', - }, - item_2 = { - file = 'test', - }, - item_3 = { - file = 'test', - }, - } - - local output = vim.iter(map):map(function(key, value) - return { [key] = value.file } - end):totable() - - table.sort(output, function(a, b) - return next(a) < next(b) - end) - - eq({ - { item = 'test' }, - { item_2 = 'test' }, - { item_3 = 'test' }, - }, output) - end) - - it('handles nil values', function() - local t = {1, 2, 3, 4, 5} - do - local it = vim.iter(t):enumerate():map(function(i, v) - if i % 2 == 0 then - return nil, v*v - end - return v, nil - end) - eq({ - { [1] = 1 }, - { [2] = 4 }, - { [1] = 3 }, - { [2] = 16 }, - { [1] = 5 }, - }, it:totable()) - end - - do - local it = vim.iter(ipairs(t)):map(function(i, v) - if i % 2 == 0 then - return nil, v*v - end - return v, nil - end) - eq({ - { [1] = 1 }, - { [2] = 4 }, - { [1] = 3 }, - { [2] = 16 }, - { [1] = 5 }, - }, it:totable()) - end - end) - end) end) describe('lua: builtin modules', function() -- cgit From d321deb4a9b05e9d81b79ac166274f4a6e7981bf Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 27 Apr 2023 15:51:44 +0800 Subject: test: fix dependencies between test cases (#23343) Discovered using --shuffle argument of busted. --- test/functional/lua/secure_spec.lua | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua index c4abf70f64..2348a193de 100644 --- a/test/functional/lua/secure_spec.lua +++ b/test/functional/lua/secure_spec.lua @@ -19,21 +19,14 @@ describe('vim.secure', function() local xstate = 'Xstate' setup(function() + clear{env={XDG_STATE_HOME=xstate}} helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim')) - end) - - teardown(function() - helpers.rmdir(xstate) - end) - - before_each(function() helpers.write_file('Xfile', [[ let g:foobar = 42 ]]) - clear{env={XDG_STATE_HOME=xstate}} end) - after_each(function() + teardown(function() os.remove('Xfile') helpers.rmdir(xstate) end) @@ -175,6 +168,7 @@ describe('vim.secure', function() local xstate = 'Xstate' setup(function() + clear{env={XDG_STATE_HOME=xstate}} helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim')) end) -- cgit From 45bcf8386918bbb475fbe20c48b508aa89ed0624 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 20 Apr 2023 13:19:38 +0200 Subject: refactor(build): include lpeg as a library --- test/functional/lua/vim_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 53c21fd668..86eb600bd9 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3031,6 +3031,15 @@ describe('lua stdlib', function() eq(false, if_nil(d, c)) eq(NIL, if_nil(a)) end) + + it('lpeg', function() + eq(5, exec_lua [[ + local m = vim.lpeg + return m.match(m.R'09'^1, '4504ab') + ]]) + + eq(4, exec_lua [[ return vim.re.match("abcde", '[a-c]+') ]]) + end) end) describe('lua: builtin modules', function() -- cgit From 7b6d041baed712b071acfa8bb71727a5f5e27561 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 29 Apr 2023 09:23:31 +0800 Subject: fix(heredoc): allow missing end marker for scripts Also do not crash when getting heredoc fails. --- test/functional/lua/commands_spec.lua | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 5bb9e0281b..0dc6c19fa1 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -7,6 +7,7 @@ local NIL = helpers.NIL local eval = helpers.eval local feed = helpers.feed local clear = helpers.clear +local matches = helpers.matches local meths = helpers.meths local exec_lua = helpers.exec_lua local exec_capture = helpers.exec_capture @@ -27,22 +28,27 @@ describe(':lua command', function() eq('', exec_capture( 'lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TEST"})')) eq({'', 'TEST'}, curbufmeths.get_lines(0, 100, false)) - source(dedent([[ + source([[ lua << EOF vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TSET"}) - EOF]])) + EOF]]) eq({'', 'TSET'}, curbufmeths.get_lines(0, 100, false)) - source(dedent([[ + source([[ lua << EOF - vim.api.nvim_buf_set_lines(1, 1, 2, false, {"SETT"})]])) + vim.api.nvim_buf_set_lines(1, 1, 2, false, {"SETT"})]]) eq({'', 'SETT'}, curbufmeths.get_lines(0, 100, false)) - source(dedent([[ + source([[ lua << EOF vim.api.nvim_buf_set_lines(1, 1, 2, false, {"ETTS"}) vim.api.nvim_buf_set_lines(1, 2, 3, false, {"TTSE"}) vim.api.nvim_buf_set_lines(1, 3, 4, false, {"STTE"}) - EOF]])) + EOF]]) eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false)) + matches('.*Vim%(lua%):E15: Invalid expression: .*', pcall_err(source, [[ + lua << eval EOF + {} + EOF + ]])) end) it('throws catchable errors', function() eq([[Vim(lua):E5107: Error loading lua [string ":lua"]:0: unexpected symbol near ')']], -- cgit From 88cfb49bee3c9102082c7010acb92244e4ad1348 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 5 May 2023 07:14:39 +0800 Subject: vim-patch:8.2.4890: inconsistent capitalization in error messages Problem: Inconsistent capitalization in error messages. Solution: Make capitalization consistent. (Doug Kearns) https://github.com/vim/vim/commit/cf030578b26460643dca4a40e7f2e3bc19c749aa Co-authored-by: Bram Moolenaar --- test/functional/lua/commands_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 0dc6c19fa1..9a8d5efa5d 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -198,7 +198,7 @@ describe(':luado command', function() end) it('works correctly when changing lines out of range', function() curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) - eq('Vim(luado):E322: line number out of range: 1 past the end', + eq('Vim(luado):E322: Line number out of range: 1 past the end', pcall_err(command, '2,$luado vim.api.nvim_command("%d") return linenr')) eq({''}, curbufmeths.get_lines(0, -1, false)) end) -- cgit From 4a098b97e53551a3383e669f4730be542c61e012 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 5 May 2023 06:32:17 +0800 Subject: fix(excmd): append original command to error message Revert the change to do_cmdline_cmd() from #5226. This function is used in many places, so making it different from Vim leads to small differences from Vim in the behavior of some functions like execute() and assert_fails(). If DOCMD_VERBOSE really needs to be removed somewhere, a do_cmdline() call without DOCMD_VERBOSE is also shorter than a do_cmdline() call with DOCMD_VERBOSE. --- test/functional/lua/commands_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 9a8d5efa5d..fca619348d 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -214,7 +214,7 @@ describe(':luado command', function() end) it('fails in sandbox when needed', function() curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"}) - eq('Vim(luado):E48: Not allowed in sandbox', + eq('Vim(luado):E48: Not allowed in sandbox: sandbox luado runs = (runs or 0) + 1', pcall_err(command, 'sandbox luado runs = (runs or 0) + 1')) eq(NIL, funcs.luaeval('runs')) end) -- cgit From 826b95203ac9c8decf02e332fbb55cf4ebf73aef Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Thu, 18 May 2023 16:27:47 +0200 Subject: build: bundle uncrustify Uncrustify is sensitive to version changes, which causes friction for contributors that doesn't have that exact version. It's also simpler to download and install the correct version than to have bespoke version checking. --- test/functional/lua/fs_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 2fcbc9450f..f646e676c6 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -223,7 +223,7 @@ describe('vim.fs', function() describe('find()', function() it('works', function() - eq({test_build_dir}, exec_lua([[ + eq({test_build_dir .. "/build"}, exec_lua([[ local dir = ... return vim.fs.find('build', { path = dir, upward = true, type = 'directory' }) ]], nvim_dir)) @@ -239,7 +239,7 @@ describe('vim.fs', function() end) it('accepts predicate as names', function() - eq({test_build_dir}, exec_lua([[ + eq({test_build_dir .. "/build"}, exec_lua([[ local dir = ... local opts = { path = dir, upward = true, type = 'directory' } return vim.fs.find(function(x) return x == 'build' end, opts) -- cgit From e3e6fadfd82861471c32fdcabe00bbef3de84563 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 20 May 2023 17:30:48 +0200 Subject: feat(fs): expose join_paths as `vim.fs.joinpath` (#23685) This is a small function but used a lot in some plugins. --- test/functional/lua/fs_spec.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index f646e676c6..aae0ed91a7 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -266,6 +266,17 @@ describe('vim.fs', function() end) end) + describe('joinpath()', function() + it('works', function() + eq('foo/bar/baz', exec_lua([[ + return vim.fs.joinpath('foo', 'bar', 'baz') + ]], nvim_dir)) + eq('foo/bar/baz', exec_lua([[ + return vim.fs.joinpath('foo', '/bar/', '/baz') + ]], nvim_dir)) + end) + end) + describe('normalize()', function() it('works with backward slashes', function() eq('C:/Users/jdoe', exec_lua [[ return vim.fs.normalize('C:\\Users\\jdoe') ]]) -- cgit From 1fe1bb084d0099fc4f9bfdc11189485d0f74b75a Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 19 Dec 2022 16:37:45 +0000 Subject: refactor(options): deprecate nvim[_buf|_win]_[gs]et_option Co-authored-by: zeertzjq Co-authored-by: famiu --- test/functional/lua/buffer_updates_spec.lua | 12 ++--- .../lua/command_line_completion_spec.lua | 8 --- test/functional/lua/filetype_spec.lua | 2 +- test/functional/lua/inspector_spec.lua | 6 +-- test/functional/lua/luaeval_spec.lua | 4 +- test/functional/lua/overrides_spec.lua | 2 +- test/functional/lua/secure_spec.lua | 4 +- test/functional/lua/vim_spec.lua | 60 +++++++++++----------- 8 files changed, 45 insertions(+), 53 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 04f4f89472..64cb524e99 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -415,7 +415,7 @@ describe('lua: nvim_buf_attach on_bytes', function() it('opening lines', function() local check_events = setup_eventcheck(verify, origlines) - -- meths.buf_set_option(0, 'autoindent', true) + -- meths.set_option_value('autoindent', true, { buf = 0 }) feed 'Go' check_events { { "test1", "bytes", 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 1 }; @@ -428,7 +428,7 @@ describe('lua: nvim_buf_attach on_bytes', function() it('opening lines with autoindent', function() local check_events = setup_eventcheck(verify, origlines) - meths.buf_set_option(0, 'autoindent', true) + meths.set_option_value('autoindent', true, { buf = 0 }) feed 'Go' check_events { { "test1", "bytes", 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 5 }; @@ -462,8 +462,8 @@ describe('lua: nvim_buf_attach on_bytes', function() it('continuing comments with fo=or', function() local check_events = setup_eventcheck(verify, {'// Comment'}) - meths.buf_set_option(0, 'formatoptions', 'ro') - meths.buf_set_option(0, 'filetype', 'c') + meths.set_option_value('formatoptions', 'ro', { buf = 0 }) + meths.set_option_value('filetype', 'c', { buf = 0 }) feed 'A' check_events { { "test1", "bytes", 1, 4, 0, 10, 10, 0, 0, 0, 1, 3, 4 }; @@ -603,7 +603,7 @@ describe('lua: nvim_buf_attach on_bytes', function() it('inccomand=nosplit and substitute', function() local check_events = setup_eventcheck(verify, {"abcde", "12345"}) - meths.set_option('inccommand', 'nosplit') + meths.set_option_value('inccommand', 'nosplit', {}) -- linewise substitute feed(':%s/bcd/') @@ -998,7 +998,7 @@ describe('lua: nvim_buf_attach on_bytes', function() it("virtual edit", function () local check_events = setup_eventcheck(verify, { "", " " }) - meths.set_option("virtualedit", "all") + meths.set_option_value('virtualedit', "all", {}) feed [[iab]] diff --git a/test/functional/lua/command_line_completion_spec.lua b/test/functional/lua/command_line_completion_spec.lua index 9a0d534358..177e077f4a 100644 --- a/test/functional/lua/command_line_completion_spec.lua +++ b/test/functional/lua/command_line_completion_spec.lua @@ -31,14 +31,12 @@ describe('nlua_expand_pat', function() eq( {{ 'nvim_buf_set_lines', - 'nvim_buf_set_option' }, 8 }, get_completions('vim.api.nvim_buf_', { vim = { api = { nvim_buf_set_lines = true, - nvim_buf_set_option = true, nvim_win_doesnt_match = true, }, other_key = true, @@ -68,14 +66,12 @@ describe('nlua_expand_pat', function() eq( {{ 'nvim_buf_set_lines', - 'nvim_buf_set_option' }, 11 }, get_completions('vim["api"].nvim_buf_', { vim = { api = { nvim_buf_set_lines = true, - nvim_buf_set_option = true, nvim_win_doesnt_match = true, }, other_key = true, @@ -88,7 +84,6 @@ describe('nlua_expand_pat', function() eq( {{ 'nvim_buf_set_lines', - 'nvim_buf_set_option' }, 21 }, get_completions('vim["nested"]["api"].nvim_buf_', { @@ -96,7 +91,6 @@ describe('nlua_expand_pat', function() nested = { api = { nvim_buf_set_lines = true, - nvim_buf_set_option = true, nvim_win_doesnt_match = true, }, }, @@ -121,7 +115,6 @@ describe('nlua_expand_pat', function() eq( {{ 'nvim_buf_set_lines', - 'nvim_buf_set_option' }, 12 }, get_completions('vim[MY_VAR].nvim_buf_', { @@ -129,7 +122,6 @@ describe('nlua_expand_pat', function() vim = { api = { nvim_buf_set_lines = true, - nvim_buf_set_option = true, nvim_win_doesnt_match = true, }, other_key = true, diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 540eae1c9b..4ea94796bc 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -134,6 +134,6 @@ end) describe('filetype.lua', function() it('does not override user autocommands that set filetype #20333', function() clear({args={'--clean', '--cmd', 'autocmd BufRead *.md set filetype=notmarkdown', 'README.md'}}) - eq('notmarkdown', meths.buf_get_option(0, 'filetype')) + eq('notmarkdown', meths.get_option_value('filetype', { buf = 0 })) end) end) diff --git a/test/functional/lua/inspector_spec.lua b/test/functional/lua/inspector_spec.lua index f9ec274290..c369956e56 100644 --- a/test/functional/lua/inspector_spec.lua +++ b/test/functional/lua/inspector_spec.lua @@ -18,8 +18,8 @@ describe('vim.inspect_pos', function() vim.api.nvim_set_current_buf(buf) vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"}) vim.api.nvim_buf_set_lines(buf1, 0, -1, false, {"--commentline"}) - vim.api.nvim_buf_set_option(buf, "filetype", "lua") - vim.api.nvim_buf_set_option(buf1, "filetype", "lua") + vim.bo[buf].filetype = 'lua' + vim.bo[buf1].filetype = 'lua' vim.api.nvim_buf_set_extmark(buf, ns1, 0, 10, { hl_group = "Normal" }) vim.api.nvim_buf_set_extmark(buf, ns2, 0, 10, { hl_group = "Normal" }) vim.cmd("syntax on") @@ -97,7 +97,7 @@ describe('vim.show_pos', function() local buf = vim.api.nvim_create_buf(true, false) vim.api.nvim_set_current_buf(buf) vim.api.nvim_buf_set_lines(0, 0, -1, false, {"local a = 123"}) - vim.api.nvim_buf_set_option(buf, "filetype", "lua") + vim.bo[buf].filetype = 'lua' vim.cmd("syntax on") return {buf, vim.show_pos(0, 0, 10)} ]]) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 613008b5e1..31da5db1df 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -514,7 +514,7 @@ describe('v:lua', function() [5] = {bold = true, foreground = Screen.colors.SeaGreen4}, }) screen:attach() - meths.buf_set_option(0, 'omnifunc', 'v:lua.mymod.omni') + meths.set_option_value('omnifunc', 'v:lua.mymod.omni', { buf = 0 }) feed('isome st') screen:expect{grid=[[ some stuff^ | @@ -526,7 +526,7 @@ describe('v:lua', function() {1:~ }| {4:-- Omni completion (^O^N^P) }{5:match 1 of 3} | ]]} - meths.set_option('operatorfunc', 'v:lua.mymod.noisy') + meths.set_option_value('operatorfunc', 'v:lua.mymod.noisy', {}) feed('g@g@') eq("hey line", meths.get_current_line()) end) diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index f88698f83d..68e2525151 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -100,7 +100,7 @@ describe('print', function() pcall_err(command, 'lua bad_custom_error()')) end) it('prints strings with NULs and NLs correctly', function() - meths.set_option('more', true) + meths.set_option_value('more', true, {}) eq('abc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT\n', exec_capture([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\n")]])) eq('abc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT^@', diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua index 2348a193de..9a6292a6c6 100644 --- a/test/functional/lua/secure_spec.lua +++ b/test/functional/lua/secure_spec.lua @@ -6,7 +6,7 @@ local clear = helpers.clear local command = helpers.command local pathsep = helpers.get_pathsep() local is_os = helpers.is_os -local curbufmeths = helpers.curbufmeths +local meths = helpers.meths local exec_lua = helpers.exec_lua local feed_command = helpers.feed_command local feed = helpers.feed @@ -160,7 +160,7 @@ describe('vim.secure', function() -- Cannot write file pcall_err(command, 'write') - eq(true, curbufmeths.get_option('readonly')) + eq(true, meths.get_option_value('readonly', {buf=0})) end) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 86eb600bd9..9a7654d610 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1496,9 +1496,9 @@ describe('lua stdlib', function() it('vim.bo', function() eq('', funcs.luaeval "vim.bo.filetype") exec_lua [[ - vim.api.nvim_buf_set_option(0, "filetype", "markdown") + vim.api.nvim_set_option_value("filetype", "markdown", {buf = 0}) BUF = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_option(BUF, "modifiable", false) + vim.api.nvim_set_option_value("modifiable", false, {buf = BUF}) ]] eq(false, funcs.luaeval "vim.bo.modified") eq('markdown', funcs.luaeval "vim.bo.filetype") @@ -1519,9 +1519,9 @@ describe('lua stdlib', function() it('vim.wo', function() exec_lua [[ - vim.api.nvim_win_set_option(0, "cole", 2) + vim.api.nvim_set_option_value("cole", 2, {win=0}) vim.cmd "split" - vim.api.nvim_win_set_option(0, "cole", 2) + vim.api.nvim_set_option_value("cole", 2, {win=0}) ]] eq(2, funcs.luaeval "vim.wo.cole") exec_lua [[ @@ -1566,8 +1566,8 @@ describe('lua stdlib', function() local result = exec_lua [[ local result = {} - table.insert(result, vim.api.nvim_get_option('scrolloff')) - table.insert(result, vim.api.nvim_win_get_option(0, 'scrolloff')) + table.insert(result, vim.api.nvim_get_option_value('scrolloff', {scope='global'})) + table.insert(result, vim.api.nvim_get_option_value('scrolloff', {win=0})) return result ]] @@ -1631,20 +1631,20 @@ describe('lua stdlib', function() local result = {} vim.opt.makeprg = "global-local" - table.insert(result, vim.api.nvim_get_option('makeprg')) - table.insert(result, vim.api.nvim_buf_get_option(0, 'makeprg')) + table.insert(result, vim.go.makeprg) + table.insert(result, vim.api.nvim_get_option_value('makeprg', {buf=0})) vim.opt_local.mp = "only-local" - table.insert(result, vim.api.nvim_get_option('makeprg')) - table.insert(result, vim.api.nvim_buf_get_option(0, 'makeprg')) + table.insert(result, vim.go.makeprg) + table.insert(result, vim.api.nvim_get_option_value('makeprg', {buf=0})) vim.opt_global.makeprg = "only-global" - table.insert(result, vim.api.nvim_get_option('makeprg')) - table.insert(result, vim.api.nvim_buf_get_option(0, 'makeprg')) + table.insert(result, vim.go.makeprg) + table.insert(result, vim.api.nvim_get_option_value('makeprg', {buf=0})) vim.opt.makeprg = "global-local" - table.insert(result, vim.api.nvim_get_option('makeprg')) - table.insert(result, vim.api.nvim_buf_get_option(0, 'makeprg')) + table.insert(result, vim.go.makeprg) + table.insert(result, vim.api.nvim_get_option_value('makeprg', {buf=0})) return result ]] @@ -2173,7 +2173,7 @@ describe('lua stdlib', function() it('can handle isfname ,,,', function() local result = exec_lua [[ vim.opt.isfname = "a,b,,,c" - return { vim.opt.isfname:get(), vim.api.nvim_get_option('isfname') } + return { vim.opt.isfname:get(), vim.go.isfname } ]] eq({{",", "a", "b", "c"}, "a,b,,,c"}, result) @@ -2183,7 +2183,7 @@ describe('lua stdlib', function() it('can handle isfname ,^,,', function() local result = exec_lua [[ vim.opt.isfname = "a,b,^,,c" - return { vim.opt.isfname:get(), vim.api.nvim_get_option('isfname') } + return { vim.opt.isfname:get(), vim.go.isfname } ]] eq({{"^,", "a", "b", "c"}, "a,b,^,,c"}, result) @@ -2734,14 +2734,14 @@ describe('lua stdlib', function() describe('vim.api.nvim_buf_call', function() it('can access buf options', function() - local buf1 = meths.get_current_buf() + local buf1 = meths.get_current_buf().id local buf2 = exec_lua [[ buf2 = vim.api.nvim_create_buf(false, true) return buf2 ]] - eq(false, meths.buf_get_option(buf1, 'autoindent')) - eq(false, meths.buf_get_option(buf2, 'autoindent')) + eq(false, meths.get_option_value('autoindent', {buf=buf1})) + eq(false, meths.get_option_value('autoindent', {buf=buf2})) local val = exec_lua [[ return vim.api.nvim_buf_call(buf2, function() @@ -2750,9 +2750,9 @@ describe('lua stdlib', function() end) ]] - eq(false, meths.buf_get_option(buf1, 'autoindent')) - eq(true, meths.buf_get_option(buf2, 'autoindent')) - eq(buf1, meths.get_current_buf()) + eq(false, meths.get_option_value('autoindent', {buf=buf1})) + eq(true, meths.get_option_value('autoindent', {buf=buf2})) + eq(buf1, meths.get_current_buf().id) eq(buf2, val) end) @@ -2771,10 +2771,10 @@ describe('lua stdlib', function() eq(true, exec_lua([[ local function scratch_buf_call(fn) local buf = vim.api.nvim_create_buf(false, true) - vim.api.nvim_buf_set_option(buf, 'cindent', true) + vim.api.nvim_set_option_value('cindent', true, {buf = buf}) return vim.api.nvim_buf_call(buf, function() return vim.api.nvim_get_current_buf() == buf - and vim.api.nvim_buf_get_option(buf, 'cindent') + and vim.api.nvim_get_option_value('cindent', {buf = buf}) and fn() end) and vim.api.nvim_buf_delete(buf, {}) == nil end @@ -2811,7 +2811,7 @@ describe('lua stdlib', function() describe('vim.api.nvim_win_call', function() it('can access window options', function() command('vsplit') - local win1 = meths.get_current_win() + local win1 = meths.get_current_win().id command('wincmd w') local win2 = exec_lua [[ win2 = vim.api.nvim_get_current_win() @@ -2819,8 +2819,8 @@ describe('lua stdlib', function() ]] command('wincmd p') - eq('', meths.win_get_option(win1, 'winhighlight')) - eq('', meths.win_get_option(win2, 'winhighlight')) + eq('', meths.get_option_value('winhighlight', {win=win1})) + eq('', meths.get_option_value('winhighlight', {win=win2})) local val = exec_lua [[ return vim.api.nvim_win_call(win2, function() @@ -2829,9 +2829,9 @@ describe('lua stdlib', function() end) ]] - eq('', meths.win_get_option(win1, 'winhighlight')) - eq('Normal:Normal', meths.win_get_option(win2, 'winhighlight')) - eq(win1, meths.get_current_win()) + eq('', meths.get_option_value('winhighlight', {win=win1})) + eq('Normal:Normal', meths.get_option_value('winhighlight', {win=win2})) + eq(win1, meths.get_current_win().id) eq(win2, val) end) -- cgit From 576dddb46168e81aa0f78c28816082c662dedea1 Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Mon, 22 May 2023 12:47:10 +0600 Subject: test: don't unnecessarily specify win/buf for `nvim_(get|set)_option_value` `nvim_(get|set)_option_value` pick the current buffer / window by default for buffer-local/window-local (but not global-local) options. So specifying `buf = 0` or `win = 0` in opts is unnecessary for those options. This PR removes those to reduce code clutter. --- test/functional/lua/buffer_updates_spec.lua | 8 ++++---- test/functional/lua/filetype_spec.lua | 2 +- test/functional/lua/luaeval_spec.lua | 2 +- test/functional/lua/secure_spec.lua | 2 +- test/functional/lua/vim_spec.lua | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 64cb524e99..d415b708be 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -415,7 +415,7 @@ describe('lua: nvim_buf_attach on_bytes', function() it('opening lines', function() local check_events = setup_eventcheck(verify, origlines) - -- meths.set_option_value('autoindent', true, { buf = 0 }) + -- meths.set_option_value('autoindent', true, {}) feed 'Go' check_events { { "test1", "bytes", 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 1 }; @@ -428,7 +428,7 @@ describe('lua: nvim_buf_attach on_bytes', function() it('opening lines with autoindent', function() local check_events = setup_eventcheck(verify, origlines) - meths.set_option_value('autoindent', true, { buf = 0 }) + meths.set_option_value('autoindent', true, {}) feed 'Go' check_events { { "test1", "bytes", 1, 4, 7, 0, 114, 0, 0, 0, 1, 0, 5 }; @@ -462,8 +462,8 @@ describe('lua: nvim_buf_attach on_bytes', function() it('continuing comments with fo=or', function() local check_events = setup_eventcheck(verify, {'// Comment'}) - meths.set_option_value('formatoptions', 'ro', { buf = 0 }) - meths.set_option_value('filetype', 'c', { buf = 0 }) + meths.set_option_value('formatoptions', 'ro', {}) + meths.set_option_value('filetype', 'c', {}) feed 'A' check_events { { "test1", "bytes", 1, 4, 0, 10, 10, 0, 0, 0, 1, 3, 4 }; diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 4ea94796bc..b3d95e1c7f 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -134,6 +134,6 @@ end) describe('filetype.lua', function() it('does not override user autocommands that set filetype #20333', function() clear({args={'--clean', '--cmd', 'autocmd BufRead *.md set filetype=notmarkdown', 'README.md'}}) - eq('notmarkdown', meths.get_option_value('filetype', { buf = 0 })) + eq('notmarkdown', meths.get_option_value('filetype', {})) end) end) diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 31da5db1df..dfbd2fb18b 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -514,7 +514,7 @@ describe('v:lua', function() [5] = {bold = true, foreground = Screen.colors.SeaGreen4}, }) screen:attach() - meths.set_option_value('omnifunc', 'v:lua.mymod.omni', { buf = 0 }) + meths.set_option_value('omnifunc', 'v:lua.mymod.omni', {}) feed('isome st') screen:expect{grid=[[ some stuff^ | diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua index 9a6292a6c6..fc20a06390 100644 --- a/test/functional/lua/secure_spec.lua +++ b/test/functional/lua/secure_spec.lua @@ -160,7 +160,7 @@ describe('vim.secure', function() -- Cannot write file pcall_err(command, 'write') - eq(true, meths.get_option_value('readonly', {buf=0})) + eq(true, meths.get_option_value('readonly', {})) end) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 9a7654d610..978a4fe0b6 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1496,7 +1496,7 @@ describe('lua stdlib', function() it('vim.bo', function() eq('', funcs.luaeval "vim.bo.filetype") exec_lua [[ - vim.api.nvim_set_option_value("filetype", "markdown", {buf = 0}) + vim.api.nvim_set_option_value("filetype", "markdown", {}) BUF = vim.api.nvim_create_buf(false, true) vim.api.nvim_set_option_value("modifiable", false, {buf = BUF}) ]] @@ -1519,9 +1519,9 @@ describe('lua stdlib', function() it('vim.wo', function() exec_lua [[ - vim.api.nvim_set_option_value("cole", 2, {win=0}) + vim.api.nvim_set_option_value("cole", 2, {}) vim.cmd "split" - vim.api.nvim_set_option_value("cole", 2, {win=0}) + vim.api.nvim_set_option_value("cole", 2, {}) ]] eq(2, funcs.luaeval "vim.wo.cole") exec_lua [[ -- cgit From 62e0e0349c00c2c1fa1e5ec09aa7028f12ed329b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 23 May 2023 16:12:16 +0800 Subject: fix(colorscheme): try .lua files in 'rtp' before .vim files in 'pp' (#23727) This ensures that colorschemes in 'rtp' are tried before ones in 'pp', because some colorschemes in 'pp' may not work if not added to 'rtp'. This also match the current documentation better. --- test/functional/lua/runtime_spec.lua | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index 72c99ac1f3..cd19ea4e49 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -61,6 +61,38 @@ describe('runtime:', function() eq('vim', eval('g:colorscheme')) end) + + it("loads lua colorscheme in 'rtp' if vim version only exists in 'pp' #23724", function() + local pack_dir = 'Test_Pack' + mkdir_p(pack_dir) + finally(function() + rmdir(pack_dir) + end) + exec('set pp+=' .. pack_dir) + + local pack_opt_dir = pack_dir .. sep .. 'pack' .. sep .. 'some_name' .. sep .. 'opt' + local colors_opt_dir = pack_opt_dir .. sep .. 'some_pack' .. sep .. 'colors' + mkdir_p(colors_opt_dir) + + local rtp_colorscheme_file = colorscheme_folder .. sep .. 'new_colorscheme' + local pp_opt_colorscheme_file = colors_opt_dir .. sep .. 'new_colorscheme' + + write_file(pp_opt_colorscheme_file .. '.lua', [[vim.g.colorscheme = 'lua_pp']]) + exec('colorscheme new_colorscheme') + eq('lua_pp', eval('g:colorscheme')) + + write_file(pp_opt_colorscheme_file .. '.vim', [[let g:colorscheme = 'vim_pp']]) + exec('colorscheme new_colorscheme') + eq('vim_pp', eval('g:colorscheme')) + + write_file(rtp_colorscheme_file .. '.lua', [[vim.g.colorscheme = 'lua_rtp']]) + exec('colorscheme new_colorscheme') + eq('lua_rtp', eval('g:colorscheme')) + + write_file(rtp_colorscheme_file .. '.vim', [[let g:colorscheme = 'vim_rtp']]) + exec('colorscheme new_colorscheme') + eq('vim_rtp', eval('g:colorscheme')) + end) end) describe('compiler', function() -- cgit From 2db719f6c2b677fcbc197b02fe52764a851523b2 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 3 Jun 2023 11:06:00 +0100 Subject: feat(lua): rename vim.loop -> vim.uv (#22846) --- test/functional/lua/highlight_spec.lua | 2 +- test/functional/lua/loop_spec.lua | 18 +++++++-------- test/functional/lua/overrides_spec.lua | 4 ++-- test/functional/lua/thread_spec.lua | 42 +++++++++++++++++----------------- test/functional/lua/vim_spec.lua | 16 ++++++------- 5 files changed, 41 insertions(+), 41 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua index 60d0ed5017..8e499f1e79 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/highlight_spec.lua @@ -24,7 +24,7 @@ describe('vim.highlight.on_yank', function() it('does not close timer twice', function() exec_lua([[ vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y"}}) - vim.loop.sleep(10) + vim.uv.sleep(10) vim.schedule(function() vim.highlight.on_yank({timeout = 0, on_macro = true, event = {operator = "y"}}) end) diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua index 7f3787d7bf..c0924fa0c0 100644 --- a/test/functional/lua/loop_spec.lua +++ b/test/functional/lua/loop_spec.lua @@ -14,24 +14,24 @@ local retry = helpers.retry before_each(clear) -describe('vim.loop', function() +describe('vim.uv', function() it('version', function() - assert(funcs.luaeval('vim.loop.version()')>=72961, "libuv version too old") - matches("(%d+)%.(%d+)%.(%d+)", funcs.luaeval('vim.loop.version_string()')) + assert(funcs.luaeval('vim.uv.version()')>=72961, "libuv version too old") + matches("(%d+)%.(%d+)%.(%d+)", funcs.luaeval('vim.uv.version_string()')) end) it('timer', function() exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {}) local code=[[ - local loop = vim.loop + local uv = vim.uv local touch = 0 local function wait(ms) local this = coroutine.running() assert(this) - local timer = loop.new_timer() + local timer = uv.new_timer() timer:start(ms, 0, vim.schedule_wrap(function () timer:close() touch = touch + 1 @@ -73,7 +73,7 @@ describe('vim.loop', function() -- deferred API functions are disabled, as their safety can't be guaranteed exec_lua([[ - local timer = vim.loop.new_timer() + local timer = vim.uv.new_timer() timer:start(20, 0, function () _G.is_fast = vim.in_fast_event() timer:close() @@ -101,7 +101,7 @@ describe('vim.loop', function() -- callbacks can be scheduled to be executed in the main event loop -- where the entire API is available exec_lua([[ - local timer = vim.loop.new_timer() + local timer = vim.uv.new_timer() timer:start(20, 0, vim.schedule_wrap(function () _G.is_fast = vim.in_fast_event() timer:close() @@ -127,7 +127,7 @@ describe('vim.loop', function() -- fast (not deferred) API functions are allowed to be called directly exec_lua([[ - local timer = vim.loop.new_timer() + local timer = vim.uv.new_timer() timer:start(20, 0, function () timer:close() -- input is queued for processing after the callback returns @@ -151,6 +151,6 @@ describe('vim.loop', function() end) it("is equal to require('luv')", function() - eq(true, exec_lua("return vim.loop == require('luv')")) + eq(true, exec_lua("return vim.uv == require('luv')")) end) end) diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 68e2525151..0fd8cb2f6a 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -119,7 +119,7 @@ describe('print', function() exec_lua([[ local cmd = ... function test() - local timer = vim.loop.new_timer() + local timer = vim.uv.new_timer() local done = false timer:start(10, 0, function() print("very fast") @@ -130,7 +130,7 @@ describe('print', function() -- loop until we know for sure the callback has been executed while not done do os.execute(cmd) - vim.loop.run("nowait") -- fake os_breakcheck() + vim.uv.run("nowait") -- fake os_breakcheck() end print("very slow") vim.api.nvim_command("sleep 1m") -- force deferred event processing diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua index c7f2783cf3..e79d26a641 100644 --- a/test/functional/lua/thread_spec.lua +++ b/test/functional/lua/thread_spec.lua @@ -27,10 +27,10 @@ describe('thread', function() it('entry func is executed in protected mode', function() exec_lua [[ - local thread = vim.loop.new_thread(function() + local thread = vim.uv.new_thread(function() error('Error in thread entry func') end) - vim.loop.thread_join(thread) + vim.uv.thread_join(thread) ]] screen:expect([[ @@ -51,17 +51,17 @@ describe('thread', function() it('callback is executed in protected mode', function() exec_lua [[ - local thread = vim.loop.new_thread(function() - local timer = vim.loop.new_timer() + local thread = vim.uv.new_thread(function() + local timer = vim.uv.new_timer() local function ontimeout() timer:stop() timer:close() error('Error in thread callback') end timer:start(10, 0, ontimeout) - vim.loop.run() + vim.uv.run() end) - vim.loop.thread_join(thread) + vim.uv.thread_join(thread) ]] screen:expect([[ @@ -83,10 +83,10 @@ describe('thread', function() describe('print', function() it('works', function() exec_lua [[ - local thread = vim.loop.new_thread(function() + local thread = vim.uv.new_thread(function() print('print in thread') end) - vim.loop.thread_join(thread) + vim.uv.thread_join(thread) ]] screen:expect([[ @@ -105,10 +105,10 @@ describe('thread', function() it('vim.inspect', function() exec_lua [[ - local thread = vim.loop.new_thread(function() + local thread = vim.uv.new_thread(function() print(vim.inspect({1,2})) end) - vim.loop.thread_join(thread) + vim.uv.thread_join(thread) ]] screen:expect([[ @@ -140,13 +140,13 @@ describe('thread', function() function Thread_Test:do_test() local async local on_async = self.on_async - async = vim.loop.new_async(function(ret) + async = vim.uv.new_async(function(ret) on_async(ret) async:close() end) local thread = - vim.loop.new_thread(self.entry_func, async, self.entry_str, self.args) - vim.loop.thread_join(thread) + vim.uv.new_thread(self.entry_func, async, self.entry_str, self.args) + vim.uv.thread_join(thread) end Thread_Test.new = function(entry, on_async, ...) @@ -175,10 +175,10 @@ describe('thread', function() eq({'notification', 'result', {true}}, next_msg()) end) - it('loop', function() + it('uv', function() exec_lua [[ local entry = function(async) - async:send(vim.loop.version()) + async:send(vim.uv.version()) end local on_async = function(ret) vim.rpcnotify(1, ret) @@ -259,7 +259,7 @@ describe('threadpool', function() local after_work_fn = function(ret) vim.rpcnotify(1, 'result', ret) end - local work = vim.loop.new_work(work_fn, after_work_fn) + local work = vim.uv.new_work(work_fn, after_work_fn) work:queue() ]] @@ -268,7 +268,7 @@ describe('threadpool', function() it('with invalid argument', function() local status = pcall_err(exec_lua, [[ - local work = vim.loop.new_thread(function() end, function() end) + local work = vim.uv.new_thread(function() end, function() end) work:queue({}) ]]) @@ -288,7 +288,7 @@ describe('threadpool', function() }) exec_lua [[ - local work = vim.loop.new_work(function() return {} end, function() end) + local work = vim.uv.new_work(function() return {} end, function() end) work:queue() ]] @@ -319,7 +319,7 @@ describe('threadpool', function() function Threadpool_Test:do_test() local work = - vim.loop.new_work(self.work_fn, self.after_work) + vim.uv.new_work(self.work_fn, self.after_work) work:queue(self.work_fn_str, self.args) end @@ -334,10 +334,10 @@ describe('threadpool', function() ]] end) - it('loop', function() + it('uv', function() exec_lua [[ local work_fn = function() - return vim.loop.version() + return vim.uv.version() end local after_work_fn = function(ret) vim.rpcnotify(1, ret) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 978a4fe0b6..55c03e21b3 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -882,7 +882,7 @@ describe('lua stdlib', function() it('vim.fn is allowed in "fast" context by some functions #18306', function() exec_lua([[ - local timer = vim.loop.new_timer() + local timer = vim.uv.new_timer() timer:start(0, 0, function() timer:close() assert(vim.in_fast_event()) @@ -948,7 +948,7 @@ describe('lua stdlib', function() }) screen:attach() exec_lua([[ - timer = vim.loop.new_timer() + timer = vim.uv.new_timer() timer:start(20, 0, function () -- notify ok (executed later when safe) vim.rpcnotify(chan, 'nvim_set_var', 'yy', {3, vim.NIL}) @@ -2481,7 +2481,7 @@ describe('lua stdlib', function() start_time = get_time() vim.g.timer_result = false - timer = vim.loop.new_timer() + timer = vim.uv.new_timer() timer:start(100, 0, vim.schedule_wrap(function() vim.g.timer_result = true end)) @@ -2503,7 +2503,7 @@ describe('lua stdlib', function() start_time = get_time() vim.g.timer_result = false - timer = vim.loop.new_timer() + timer = vim.uv.new_timer() timer:start(100, 0, vim.schedule_wrap(function() vim.g.timer_result = true end)) @@ -2546,17 +2546,17 @@ describe('lua stdlib', function() it('should allow waiting with no callback, explicit', function() eq(true, exec_lua [[ - local start_time = vim.loop.hrtime() + local start_time = vim.uv.hrtime() vim.wait(50, nil) - return vim.loop.hrtime() - start_time > 25000 + return vim.uv.hrtime() - start_time > 25000 ]]) end) it('should allow waiting with no callback, implicit', function() eq(true, exec_lua [[ - local start_time = vim.loop.hrtime() + local start_time = vim.uv.hrtime() vim.wait(50) - return vim.loop.hrtime() - start_time > 25000 + return vim.uv.hrtime() - start_time > 25000 ]]) end) -- cgit From eceb2dffce3908507092ffe425b1ceef5baeb1ab Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 6 Jun 2023 10:32:30 +0800 Subject: fix(spell): splice extmarks on :spellrepall (#23929) --- test/functional/lua/buffer_updates_spec.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index d415b708be..c19891a794 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -1164,12 +1164,17 @@ describe('lua: nvim_buf_attach on_bytes', function() end) it("works with accepting spell suggestions", function() - local check_events = setup_eventcheck(verify, {"hallo"}) + local check_events = setup_eventcheck(verify, {"hallo world", "hallo world"}) feed("gg0z=4") -- accepts 'Hello' check_events { { "test1", "bytes", 1, 3, 0, 0, 0, 0, 2, 2, 0, 2, 2 }; } + + command("spellrepall") -- replaces whole words + check_events { + { "test1", "bytes", 1, 4, 1, 0, 12, 0, 5, 5, 0, 5, 5 }; + } end) it('works with :diffput and :diffget', function() -- cgit From ca887b80a911df4db4ab5f5496075b9415b9990a Mon Sep 17 00:00:00 2001 From: Gianmaria Bajo Date: Tue, 6 Jun 2023 15:38:45 +0200 Subject: fix: version-range < and <= #23539 vim.version.range() couldn't parse them correctly. For example, vim.version.range('<0.9.0'):has('0.9.0') returned `true`. fix: range:has() accepts vim.version() So that it's possible to compare a range with: vim.version.range(spec):has(vim.version()) --- test/functional/lua/version_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index 75b62e8318..64dcbec983 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -40,6 +40,8 @@ describe('version', function() ['=1.2.3'] = { from = { 1, 2, 3 }, to = { 1, 2, 4 } }, ['>1.2.3'] = { from = { 1, 2, 4 } }, ['>=1.2.3'] = { from = { 1, 2, 3 } }, + ['<1.2.3'] = { from = { 0, 0, 0 }, to = { 1, 2, 3 } }, + ['<=1.2.3'] = { from = { 0, 0, 0 }, to = { 1, 2, 4 } }, ['~1.2.3'] = { from = { 1, 2, 3 }, to = { 1, 3, 0 } }, ['^1.2.3'] = { from = { 1, 2, 3 }, to = { 2, 0, 0 } }, ['^0.2.3'] = { from = { 0, 2, 3 }, to = { 0, 3, 0 } }, -- cgit From c0952e62fd0ee16a3275bb69e0de04c836b39015 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 7 Jun 2023 13:52:23 +0100 Subject: feat(lua): add `vim.system()` feat(lua): add vim.system() Problem: Handling system commands in Lua is tedious and error-prone: - vim.fn.jobstart() is vimscript and comes with all limitations attached to typval. - vim.loop.spawn is too low level Solution: Add vim.system(). Partly inspired by Python's subprocess module Does not expose any libuv objects. --- test/functional/lua/system_spec.lua | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 test/functional/lua/system_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua new file mode 100644 index 0000000000..836d3a83b0 --- /dev/null +++ b/test/functional/lua/system_spec.lua @@ -0,0 +1,57 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local exec_lua = helpers.exec_lua +local eq = helpers.eq + +local function system_sync(cmd, opts) + return exec_lua([[ + return vim.system(...):wait() + ]], cmd, opts) +end + +local function system_async(cmd, opts) + exec_lua([[ + local cmd, opts = ... + _G.done = false + vim.system(cmd, opts, function(obj) + _G.done = true + _G.ret = obj + end) + ]], cmd, opts) + + while true do + if exec_lua[[return _G.done]] then + break + end + end + + return exec_lua[[return _G.ret]] +end + +describe('vim.system', function() + before_each(function() + clear() + end) + + for name, system in pairs{ sync = system_sync, async = system_async, } do + describe('('..name..')', function() + it('can run simple commands', function() + eq('hello\n', system({'echo', 'hello' }, { text = true }).stdout) + end) + + it('handle input', function() + eq('hellocat', system({ 'cat' }, { stdin = 'hellocat', text = true }).stdout) + end) + + it ('supports timeout', function() + eq({ + code = 0, + signal = 2, + stdout = '', + stderr = "Command timed out: 'sleep 10'" + }, system({ 'sleep', '10' }, { timeout = 1 })) + end) + end) + end + +end) -- cgit From 7c661207cc4357553ed2b057b6c8f28400024361 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 8 Jun 2023 12:11:24 +0200 Subject: feat(lua): add ringbuffer (#22894) https://en.wikipedia.org/wiki/Circular_buffer --- test/functional/lua/vim_spec.lua | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 55c03e21b3..d5f550a5d1 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3040,6 +3040,46 @@ describe('lua stdlib', function() eq(4, exec_lua [[ return vim.re.match("abcde", '[a-c]+') ]]) end) + + it("vim.ringbuf", function() + local results = exec_lua([[ + local ringbuf = vim.ringbuf(3) + ringbuf:push("a") -- idx: 0 + local peeka1 = ringbuf:peek() + local peeka2 = ringbuf:peek() + local popa = ringbuf:pop() + local popnil = ringbuf:pop() + ringbuf:push("a") -- idx: 1 + ringbuf:push("b") -- idx: 2 + + -- doesn't read last added item, but uses separate read index + local pop_after_add_b = ringbuf:pop() + + ringbuf:push("c") -- idx: 3 wraps around, overrides idx: 0 "a" + ringbuf:push("d") -- idx: 4 wraps around, overrides idx: 1 "a" + return { + peeka1 = peeka1, + peeka2 = peeka2, + pop1 = popa, + pop2 = popnil, + pop3 = ringbuf:pop(), + pop4 = ringbuf:pop(), + pop5 = ringbuf:pop(), + pop_after_add_b = pop_after_add_b, + } + ]]) + local expected = { + peeka1 = "a", + peeka2 = "a", + pop1 = "a", + pop2 = nil, + pop3 = "b", + pop4 = "c", + pop5 = "d", + pop_after_add_b = "a", + } + eq(expected, results) + end) end) describe('lua: builtin modules', function() -- cgit From 302d3cfb96d7f0c856262e1a4252d058e3300c8b Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 10 Jun 2023 20:33:23 +0200 Subject: feat(lua): use callable table as iterator in vim.iter (#23957) A table passed to `vim.iter` can be a class instance with a `__call` implementation for the iterator protocol. --- test/functional/lua/iter_spec.lua | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/iter_spec.lua b/test/functional/lua/iter_spec.lua index 6e1ecc2f7e..3b603c9911 100644 --- a/test/functional/lua/iter_spec.lua +++ b/test/functional/lua/iter_spec.lua @@ -4,6 +4,15 @@ local matches = helpers.matches local pcall_err = helpers.pcall_err describe('vim.iter', function() + it('new() on iterable class instance', function() + local rb = vim.ringbuf(3) + rb:push("a") + rb:push("b") + + local it = vim.iter(rb) + eq({"a", "b"}, it:totable()) + end) + it('filter()', function() local function odd(v) return v % 2 ~= 0 -- cgit From e6887932539315e02621edb77d5e77c7c2a0b033 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 12 Jun 2023 01:14:33 +0200 Subject: feat: tostring(vim.version()) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: tostring(vim.version()) returns "table: 0x…". Solution: Modify vim.version() to return a string prerelease instead of a boolean. Fix #23863 --- test/functional/lua/version_spec.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/version_spec.lua b/test/functional/lua/version_spec.lua index 64dcbec983..d1c981c388 100644 --- a/test/functional/lua/version_spec.lua +++ b/test/functional/lua/version_spec.lua @@ -17,6 +17,18 @@ describe('version', function() eq({ major = 42, minor = 3, patch = 99 }, exec_lua("return vim.version.parse('v42.3.99')")) end) + it('version() returns Nvim version', function() + local expected = exec_lua('return vim.fn.api_info().version') + local actual = exec_lua('return vim.version()') + eq(expected.major, actual.major) + eq(expected.minor, actual.minor) + eq(expected.patch, actual.patch) + eq(expected.prerelease and 'dev' or nil, actual.prerelease) + + -- tostring() #23863 + matches([[%d+%.%d+%.%d+]], exec_lua('return tostring(vim.version())')) + end) + describe('_version()', function() local tests = { ['v1.2.3'] = { major = 1, minor = 2, patch = 3 }, -- cgit From 79a5b89d66db74560e751561542064674e980146 Mon Sep 17 00:00:00 2001 From: Jon Huhn Date: Wed, 14 Jun 2023 05:40:11 -0500 Subject: perf(lsp): reduce polling handles for workspace/didChangeWatchedFiles (#23500) Co-authored-by: Lewis Russell --- test/functional/lua/watch_spec.lua | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index ad8678c17a..f041f4f1b6 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -107,6 +107,7 @@ describe('vim._watch', function() local result = exec_lua( [[ local root_dir = ... + local lpeg = vim.lpeg local events = {} @@ -118,7 +119,13 @@ describe('vim._watch', function() assert(vim.wait(poll_wait_ms, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) end - local stop = vim._watch.poll(root_dir, { interval = poll_interval_ms }, function(path, change_type) + local incl = lpeg.P(root_dir) * lpeg.P("/file")^-1 + local excl = lpeg.P(root_dir..'/file.unwatched') + local stop = vim._watch.poll(root_dir, { + interval = poll_interval_ms, + include_pattern = incl, + exclude_pattern = excl, + }, function(path, change_type) table.insert(events, { path = path, change_type = change_type }) end) @@ -127,12 +134,17 @@ describe('vim._watch', function() local watched_path = root_dir .. '/file' local watched, err = io.open(watched_path, 'w') assert(not err, err) + local unwatched_path = root_dir .. '/file.unwatched' + local unwatched, err = io.open(unwatched_path, 'w') + assert(not err, err) expected_events = expected_events + 2 wait_for_events() watched:close() os.remove(watched_path) + unwatched:close() + os.remove(unwatched_path) expected_events = expected_events + 2 wait_for_events() -- cgit From 8a7e3353eb5bffb10015254917361266b4b20511 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sun, 18 Jun 2023 14:49:33 +0300 Subject: fix(fs): make `normalize()` work with '/' path (#24047) Problem: Current implementation of "remove trailing /" doesn't account for the case of literal '/' as path. Solution: Remove trailing / only if it preceded by something else. Co-authored by: notomo --- test/functional/lua/fs_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index aae0ed91a7..c1091cff60 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -281,6 +281,12 @@ describe('vim.fs', function() it('works with backward slashes', function() eq('C:/Users/jdoe', exec_lua [[ return vim.fs.normalize('C:\\Users\\jdoe') ]]) end) + it('removes trailing /', function() + eq('/home/user', exec_lua [[ return vim.fs.normalize('/home/user/') ]]) + end) + it('works with /', function() + eq('/', exec_lua [[ return vim.fs.normalize('/') ]]) + end) it('works with ~', function() eq( exec_lua([[ local home = ... -- cgit From 8d4a53fe6e20652946948170f2436ec520f9bdfe Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Wed, 21 Jun 2023 01:10:32 -0700 Subject: fix(vim.json)!: remove global options, "null", "array_mt" #24070 Problem: - `vim.json` exposes various global options which: - affect all Nvim Lua plugins (especially the LSP client) - are undocumented and untested - can cause confusing problems such as: https://github.com/codota/tabnine-nvim/commit/cc76ae3abe2f129d44b5a8edee2529e0ee0dcf69 - `vim.json` exposes redundant mechanisms: - `vim.json.null` is redundant with `vim.NIL`. - `array_mt` is redundant because Nvim uses a metatable (`vim.empty_dict()`) for empty dict instead, which `vim.json` is configured to use by default (see `as_empty_dict`). Example: ``` :lua vim.print(vim.json.decode('{"bar":[],"foo":{}}')) --> { bar = {}, foo = vim.empty_dict() } ``` Thus we don't need to also decorate empty arrays with `array_mt`. Solution: Remove the functions from the public vim.json interface. Comment-out the implementation code to minimize drift from upstream. TODO: - Expose the options as arguments to `vim.json.new()` --- test/functional/lua/json_spec.lua | 111 +++++++++++++++++++++++++------------- 1 file changed, 74 insertions(+), 37 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/json_spec.lua b/test/functional/lua/json_spec.lua index fbb21bfd57..25fdb48eea 100644 --- a/test/functional/lua/json_spec.lua +++ b/test/functional/lua/json_spec.lua @@ -1,20 +1,57 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear -local NIL = helpers.NIL local exec_lua = helpers.exec_lua local eq = helpers.eq +local pcall_err = helpers.pcall_err -describe('vim.json.decode function', function() +describe('vim.json.decode()', function() before_each(function() clear() end) it('parses null, true, false', function() - eq(NIL, exec_lua([[return vim.json.decode('null')]])) + eq(vim.NIL, exec_lua([[return vim.json.decode('null')]])) eq(true, exec_lua([[return vim.json.decode('true')]])) eq(false, exec_lua([[return vim.json.decode('false')]])) end) + it('validation', function() + eq('Expected object key string but found invalid token at character 2', + pcall_err(exec_lua, [[return vim.json.decode('{a:"b"}')]])) + end) + + it('options', function() + local jsonstr = '{"arr":[1,2,null],"bar":[3,7],"foo":{"a":"b"},"baz":null}' + eq({ + arr = { 1, 2, vim.NIL }, + bar = { 3, 7 }, + baz = vim.NIL, + foo = { a = 'b' }, + }, + exec_lua([[return vim.json.decode(..., {})]], jsonstr)) + eq({ + arr = { 1, 2, vim.NIL }, + bar = { 3, 7 }, + -- baz = nil, + foo = { a = 'b' }, + }, + exec_lua([[return vim.json.decode(..., { luanil = { object = true } })]], jsonstr)) + eq({ + arr = { 1, 2 }, + bar = { 3, 7 }, + baz = vim.NIL, + foo = { a = 'b' }, + }, + exec_lua([[return vim.json.decode(..., { luanil = { array = true } })]], jsonstr)) + eq({ + arr = { 1, 2 }, + bar = { 3, 7 }, + -- baz = nil, + foo = { a = 'b' }, + }, + exec_lua([[return vim.json.decode(..., { luanil = { array = true, object = true } })]], jsonstr)) + end) + it('parses integer numbers', function() eq(100000, exec_lua([[return vim.json.decode('100000')]])) eq(-100000, exec_lua([[return vim.json.decode('-100000')]])) @@ -60,7 +97,7 @@ describe('vim.json.decode function', function() it('parses containers', function() eq({1}, exec_lua([[return vim.json.decode('[1]')]])) - eq({NIL, 1}, exec_lua([[return vim.json.decode('[null, 1]')]])) + eq({vim.NIL, 1}, exec_lua([[return vim.json.decode('[null, 1]')]])) eq({['1']=2}, exec_lua([[return vim.json.decode('{"1": 2}')]])) eq({['1']=2, ['3']={{['4']={['5']={{}, 1}}}}}, exec_lua([[return vim.json.decode('{"1": 2, "3": [{"4": {"5": [ [], 1]}}]}')]])) @@ -88,43 +125,43 @@ describe('vim.json.decode function', function() end) -describe('vim.json.encode function', function() +describe('vim.json.encode()', function() before_each(function() clear() end) - it('dumps strings', function() - eq('"Test"', exec_lua([[return vim.json.encode('Test')]])) - eq('""', exec_lua([[return vim.json.encode('')]])) - eq('"\\t"', exec_lua([[return vim.json.encode('\t')]])) - eq('"\\n"', exec_lua([[return vim.json.encode('\n')]])) - -- vim.fn.json_encode return \\u001B - eq('"\\u001b"', exec_lua([[return vim.json.encode('\27')]])) - eq('"þÿþ"', exec_lua([[return vim.json.encode('þÿþ')]])) - end) - - it('dumps numbers', function() - eq('0', exec_lua([[return vim.json.encode(0)]])) - eq('10', exec_lua([[return vim.json.encode(10)]])) - eq('-10', exec_lua([[return vim.json.encode(-10)]])) - end) - - it('dumps floats', function() - eq('10.5', exec_lua([[return vim.json.encode(10.5)]])) - eq('-10.5', exec_lua([[return vim.json.encode(-10.5)]])) - eq('-1e-05', exec_lua([[return vim.json.encode(-1e-5)]])) - end) - - it('dumps lists', function() - eq('[]', exec_lua([[return vim.json.encode({})]])) - eq('[[]]', exec_lua([[return vim.json.encode({{}})]])) - eq('[[],[]]', exec_lua([[return vim.json.encode({{}, {}})]])) - end) - - it('dumps dictionaries', function() - eq('{}', exec_lua([[return vim.json.encode(vim.empty_dict())]])) - eq('{"d":[]}', exec_lua([[return vim.json.encode({d={}})]])) - end) + it('dumps strings', function() + eq('"Test"', exec_lua([[return vim.json.encode('Test')]])) + eq('""', exec_lua([[return vim.json.encode('')]])) + eq('"\\t"', exec_lua([[return vim.json.encode('\t')]])) + eq('"\\n"', exec_lua([[return vim.json.encode('\n')]])) + -- vim.fn.json_encode return \\u001B + eq('"\\u001b"', exec_lua([[return vim.json.encode('\27')]])) + eq('"þÿþ"', exec_lua([[return vim.json.encode('þÿþ')]])) + end) + + it('dumps numbers', function() + eq('0', exec_lua([[return vim.json.encode(0)]])) + eq('10', exec_lua([[return vim.json.encode(10)]])) + eq('-10', exec_lua([[return vim.json.encode(-10)]])) + end) + + it('dumps floats', function() + eq('10.5', exec_lua([[return vim.json.encode(10.5)]])) + eq('-10.5', exec_lua([[return vim.json.encode(-10.5)]])) + eq('-1e-05', exec_lua([[return vim.json.encode(-1e-5)]])) + end) + + it('dumps lists', function() + eq('[]', exec_lua([[return vim.json.encode({})]])) + eq('[[]]', exec_lua([[return vim.json.encode({{}})]])) + eq('[[],[]]', exec_lua([[return vim.json.encode({{}, {}})]])) + end) + + it('dumps dictionaries', function() + eq('{}', exec_lua([[return vim.json.encode(vim.empty_dict())]])) + eq('{"d":[]}', exec_lua([[return vim.json.encode({d={}})]])) + end) it('dumps vim.NIL', function() eq('null', exec_lua([[return vim.json.encode(vim.NIL)]])) -- cgit From 4e6356559c8cd44dbcaa765d1f39e176064526ec Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 22 Jun 2023 03:44:51 -0700 Subject: test: spellcheck :help (vimdoc) files #24109 Enforce consistent terminology (defined in `gen_help_html.lua:spell_dict`) for common misspellings. This does not spellcheck English in general (perhaps a future TODO, though it may be noisy). --- test/functional/lua/help_spec.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/help_spec.lua b/test/functional/lua/help_spec.lua index d66d9f7fbe..cdc7761e48 100644 --- a/test/functional/lua/help_spec.lua +++ b/test/functional/lua/help_spec.lua @@ -21,6 +21,7 @@ describe(':help docs', function() ok(rv.helpfiles > 100, '>100 :help files', rv.helpfiles) eq({}, rv.invalid_links, 'invalid tags in :help docs') eq({}, rv.invalid_urls, 'invalid URLs in :help docs') + eq({}, rv.invalid_spelling, 'invalid spelling in :help docs') -- Check that parse errors did not increase. ok(rv.err_count == 0, 'no parse errors', rv.err_count) end) -- cgit From 036da0d07921e67090d1a62c9a4e382ca09d8584 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 24 Jun 2023 13:47:10 +0200 Subject: fix(docs): vimdoc syntax errors gen_help_html: truncate parse-error sample text --- test/functional/lua/help_spec.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/help_spec.lua b/test/functional/lua/help_spec.lua index cdc7761e48..8d843cd208 100644 --- a/test/functional/lua/help_spec.lua +++ b/test/functional/lua/help_spec.lua @@ -19,11 +19,12 @@ describe(':help docs', function() local rv = exec_lua([[return require('scripts.gen_help_html').validate('./build/runtime/doc')]]) -- Check that we actually found helpfiles. ok(rv.helpfiles > 100, '>100 :help files', rv.helpfiles) + + eq({}, rv.parse_errors, 'no parse errors') + eq(0, rv.err_count, 'no parse errors') eq({}, rv.invalid_links, 'invalid tags in :help docs') eq({}, rv.invalid_urls, 'invalid URLs in :help docs') - eq({}, rv.invalid_spelling, 'invalid spelling in :help docs') - -- Check that parse errors did not increase. - ok(rv.err_count == 0, 'no parse errors', rv.err_count) + eq({}, rv.invalid_spelling, 'invalid spelling in :help docs (see spell_dict in scripts/gen_help_html.lua)') end) it('gen_help_html.lua generates HTML', function() -- cgit From 6cceef6d4c2cece6a9283c9926f3b0d254bbd5db Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 30 Jun 2023 17:01:13 +0800 Subject: test(lua/runtime_spec): add test for ftplugin ordering --- test/functional/lua/runtime_spec.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index cd19ea4e49..e80a65ef3d 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -138,6 +138,30 @@ describe('runtime:', function() exec [[set filetype=new-ft]] eq(1, eval('b:lua_ftplugin')) end) + + it("'rtp' order is respected", function() + local after_ftplugin_folder = table.concat({plug_dir, 'after', 'ftplugin'}, sep) + mkdir_p(table.concat({ftplugin_folder, 'new-ft'}, sep)) + mkdir_p(table.concat({after_ftplugin_folder, 'new-ft'}, sep)) + exec('set rtp+=' .. plug_dir .. '/after') + exec('let g:seq = ""') + -- A .lua file is loaded after a .vim file if they only differ in extension. + -- All files in after/ftplugin/ are loaded after all files in ftplugin/. + write_file(table.concat({ftplugin_folder, 'new-ft.vim'}, sep), [[let g:seq ..= 'A']]) + write_file(table.concat({ftplugin_folder, 'new-ft.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) + write_file(table.concat({ftplugin_folder, 'new-ft_a.vim'}, sep), [[let g:seq ..= 'C']]) + write_file(table.concat({ftplugin_folder, 'new-ft_a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'D']]) + write_file(table.concat({ftplugin_folder, 'new-ft', 'a.vim'}, sep), [[let g:seq ..= 'E']]) + write_file(table.concat({ftplugin_folder, 'new-ft', 'a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'F']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft.vim'}, sep), [[let g:seq ..= 'a']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft_a.vim'}, sep), [[let g:seq ..= 'c']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft_a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'd']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft', 'a.vim'}, sep), [[let g:seq ..= 'e']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft', 'a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'f']]) + exec('setfiletype new-ft') + eq('ABCDEFabcdef', eval('g:seq')) + end) end) describe('indent', function() -- cgit From 92760a7f42a95bb252966c2a38423e5bc9d57cc7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 4 Jul 2023 07:19:02 +0800 Subject: fix(api, lua): make blank lines in a message work properly (#24244) --- test/functional/lua/overrides_spec.lua | 37 ++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 0fd8cb2f6a..1777dd078d 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -15,8 +15,6 @@ local exec_lua = helpers.exec_lua local pcall_err = helpers.pcall_err local is_os = helpers.is_os -local screen - local fname = 'Xtest-functional-lua-overrides-luafile' before_each(clear) @@ -138,9 +136,44 @@ describe('print', function() ]], (is_os('win') and "timeout 1") or "sleep 0.1") eq('very slow\nvery fast', exec_capture('lua test()')) end) + + it('blank line in message works', function() + local screen = Screen.new(40, 8) + screen:attach() + screen:set_default_attr_ids({ + [0] = {bold = true, foreground=Screen.colors.Blue}, + [1] = {bold = true, foreground = Screen.colors.SeaGreen}, + [2] = {bold = true, reverse = true}, + }) + feed([[:lua print('\na')]]) + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {0:~ }| + {2: }| + | + a | + {1:Press ENTER or type command to continue}^ | + ]]} + feed('') + feed([[:lua print('b\n\nc')]]) + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }| + {2: }| + b | + | + c | + {1:Press ENTER or type command to continue}^ | + ]]} + end) end) describe('debug.debug', function() + local screen + before_each(function() screen = Screen.new() screen:attach() -- cgit From 67b2ed1004ae551c9fe1bbd29a86b5a301570800 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 2 Jul 2023 16:51:30 +0200 Subject: fix(gx): visual selection, expand env vars --- Rejected experiment: move vim.ui.open() to vim.env.open() Problem: `vim.ui` is where user-interface "providers" live, which can be overridden. It would also be useful to have a "providers" namespace for platform-specific features such as "open", clipboard, python, and the other providers listed in `:help providers`. We could overload `vim.ui` to serve that purpose as the single "providers" namespace, but `vim.ui.nodejs()` for example seems awkward. Solution: `vim.env` currently has too narrow of a purpose. Overload it to also be a namespace for `vim.env.open`. diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua index 913f1fe20348..17d05ff37595 100644 --- a/runtime/lua/vim/_meta.lua +++ b/runtime/lua/vim/_meta.lua @@ -37,8 +37,28 @@ local options_info = setmetatable({}, { end, }) -vim.env = setmetatable({}, { - __index = function(_, k) +vim.env = setmetatable({ + open = setmetatable({}, { + __call = function(_, uri) + print('xxxxx'..uri) + return true + end, + __tostring = function() + local v = vim.fn.getenv('open') + if v == vim.NIL then + return nil + end + return v + end, + }) + }, + { + __index = function(t, k, ...) + if k == 'open' then + error() + -- vim.print({...}) + -- return rawget(t, k) + end local v = vim.fn.getenv(k) if v == vim.NIL then return nil --- test/functional/lua/ui_spec.lua | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua index 9ee99b4905..0f66aad7b3 100644 --- a/test/functional/lua/ui_spec.lua +++ b/test/functional/lua/ui_spec.lua @@ -1,5 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq +local matches = helpers.matches local exec_lua = helpers.exec_lua local clear = helpers.clear local feed = helpers.feed @@ -11,8 +12,7 @@ describe('vim.ui', function() clear() end) - - describe('select', function() + describe('select()', function() it('can select an item', function() local result = exec_lua[[ local items = { @@ -47,7 +47,7 @@ describe('vim.ui', function() end) end) - describe('input', function() + describe('input()', function() it('can input text', function() local result = exec_lua[[ local opts = { @@ -130,4 +130,18 @@ describe('vim.ui', function() end) end) + + describe('open()', function() + it('validation', function() + exec_lua[[vim.ui.open('non-existent-file')]] + matches('vim.ui.open: command failed %(%d%): { "[^"]+", "non%-existent%-file" }', eval('v:errmsg')) + + exec_lua[[ + vim.fn.has = function() return 0 end + vim.fn.executable = function() return 0 end + ]] + exec_lua[[vim.ui.open('foo')]] + eq('vim.ui.open: no handler found (tried: wslview, xdg-open)', eval('v:errmsg')) + end) + end) end) -- cgit From e644e7ce0b36dd5e75770f3faa0a84f15e2561e8 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 4 Jul 2023 23:33:23 +0200 Subject: fix(vim.ui.open): return (don't show) error message Problem: Showing an error via vim.notify() makes it awkward for callers such as lsp/handlers.lua to avoid showing redundant errors. Solution: Return the message instead of showing it. Let the caller decide whether and when to show the message. --- test/functional/lua/ui_spec.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua index 0f66aad7b3..d1b64419af 100644 --- a/test/functional/lua/ui_spec.lua +++ b/test/functional/lua/ui_spec.lua @@ -5,6 +5,7 @@ local exec_lua = helpers.exec_lua local clear = helpers.clear local feed = helpers.feed local eval = helpers.eval +local is_os = helpers.is_os local poke_eventloop = helpers.poke_eventloop describe('vim.ui', function() @@ -133,15 +134,17 @@ describe('vim.ui', function() describe('open()', function() it('validation', function() - exec_lua[[vim.ui.open('non-existent-file')]] - matches('vim.ui.open: command failed %(%d%): { "[^"]+", "non%-existent%-file" }', eval('v:errmsg')) + if not is_os('bsd') then + matches('vim.ui.open: command failed %(%d%): { "[^"]+", "non%-existent%-file" }', + exec_lua[[local _, err = vim.ui.open('non-existent-file') ; return err]]) + end exec_lua[[ vim.fn.has = function() return 0 end vim.fn.executable = function() return 0 end ]] - exec_lua[[vim.ui.open('foo')]] - eq('vim.ui.open: no handler found (tried: wslview, xdg-open)', eval('v:errmsg')) + eq('vim.ui.open: no handler found (tried: wslview, xdg-open)', + exec_lua[[local _, err = vim.ui.open('foo') ; return err]]) end) end) end) -- cgit From 2afb04758c341e17c70b8d2e3869c901c8cdb7d2 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 6 Jul 2023 12:56:19 +0800 Subject: fix(vim.system): close check handle (#24270) Fix hang after running vim.system() with sanitizers. --- test/functional/lua/ui_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua index d1b64419af..808b25d9ea 100644 --- a/test/functional/lua/ui_spec.lua +++ b/test/functional/lua/ui_spec.lua @@ -5,7 +5,7 @@ local exec_lua = helpers.exec_lua local clear = helpers.clear local feed = helpers.feed local eval = helpers.eval -local is_os = helpers.is_os +local is_ci = helpers.is_ci local poke_eventloop = helpers.poke_eventloop describe('vim.ui', function() @@ -134,7 +134,7 @@ describe('vim.ui', function() describe('open()', function() it('validation', function() - if not is_os('bsd') then + if is_ci('github') then matches('vim.ui.open: command failed %(%d%): { "[^"]+", "non%-existent%-file" }', exec_lua[[local _, err = vim.ui.open('non-existent-file') ; return err]]) end -- cgit From c379d72c490544b3a56eb0e52ce3c8ef740051d8 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 7 Jul 2023 16:37:36 +0100 Subject: feat(lua): allow vim.wo to be double indexed (#20288) * feat(lua): allow vim.wo to be double indexed Problem: `vim.wo` does not implement `setlocal` Solution: Allow `vim.wo` to be double indexed Co-authored-by: Christian Clason --- test/functional/lua/vim_spec.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index d5f550a5d1..f168e6ba1d 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1532,8 +1532,6 @@ describe('lua stdlib', function() eq(0, funcs.luaeval "vim.wo[1001].cole") matches("Invalid option %(not found%): 'notanopt'$", pcall_err(exec_lua, 'return vim.wo.notanopt')) - matches("Expected lua string$", - pcall_err(exec_lua, 'return vim.wo[0][0].list')) matches("Invalid window id: %-1$", pcall_err(exec_lua, 'return vim.wo[-1].list')) eq(2, funcs.luaeval "vim.wo[1000].cole") @@ -1548,6 +1546,11 @@ describe('lua stdlib', function() eq(200, funcs.luaeval "vim.wo.scrolloff") exec_lua [[vim.wo.scrolloff = -1]] eq(100, funcs.luaeval "vim.wo.scrolloff") + exec_lua [[ + vim.wo[0][0].scrolloff = 200 + vim.cmd "split" + ]] + eq(100, funcs.luaeval "vim.wo.scrolloff") end) describe('vim.opt', function() -- cgit From fbeef0d4ef1aadc4e50b9f33946cf4dca8ca6b62 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 8 Jul 2023 23:29:24 +0800 Subject: fix(completion): don't add backslashes to runtime pattern (#24296) Problem: Bashslashes added as regexp in runtime completion may be treated as path separator with some 'isfname' value. Solution: Make curly braces work for runtime completion and use it. --- test/functional/lua/runtime_spec.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index e80a65ef3d..7d3d640265 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -18,7 +18,10 @@ describe('runtime:', function() io.open(init, 'w'):close() -- touch init file clear{args = {'-u', init}} exec('set rtp+=' .. plug_dir) - exec('set completeslash=slash') + exec([[ + set completeslash=slash + set isfname+=(,) + ]]) end) teardown(function() -- cgit From 516b173780e39de3ce1e4525f0a8f0ff250c992b Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 13 Jul 2023 10:17:19 +0100 Subject: perf(rtp): reduce rtp scans (#24191) * perf(rtp): reduce rtp scans Problem: Scanning the filesystem is expensive and particularly affects startuptime. Solution: Reduce the amount of redundant directory scans by relying less on glob patterns and handle vim and lua sourcing lower down. --- test/functional/lua/runtime_spec.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index 7d3d640265..aa682cad19 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -118,12 +118,14 @@ describe('runtime:', function() it('loads vim compilers when both lua and vim version exist', function() local compiler_file = compiler_folder .. sep .. 'new_compiler' - write_file(compiler_file..'.vim', [[let b:compiler = 'vim']]) - write_file(compiler_file..'.lua', [[vim.b.compiler = 'lua']]) + exec('let b:compiler = "compiler"') + write_file(compiler_file..'.vim', [[let b:compiler = b:compiler.'_vim']]) + write_file(compiler_file..'.lua', [[vim.b.compiler = vim.b.compiler..'_lua']]) exec('compiler new_compiler') - eq('vim', eval('b:compiler')) + -- lua version is sourced after vim + eq('compiler_vim_lua', eval('b:compiler')) end) end) -- cgit From dbb840da01c72d8a311e0c55d3248d78a64b63a4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Jul 2023 06:46:16 +0800 Subject: fix(runtime): respect 'rtp' order for all runtime files (#24335) --- test/functional/lua/runtime_spec.lua | 139 +++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 45 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index aa682cad19..1f312fc513 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -19,6 +19,7 @@ describe('runtime:', function() clear{args = {'-u', init}} exec('set rtp+=' .. plug_dir) exec([[ + set shell=doesnotexist set completeslash=slash set isfname+=(,) ]]) @@ -43,8 +44,8 @@ describe('runtime:', function() mkdir_p(colorscheme_folder) end) - it('loads lua colorscheme', function() - local colorscheme_file = colorscheme_folder .. sep .. 'new_colorscheme.lua' + it('lua colorschemes work and are included in cmdline completion', function() + local colorscheme_file = table.concat({colorscheme_folder, 'new_colorscheme.lua'}, sep) write_file(colorscheme_file, [[vim.g.lua_colorscheme = 1]]) eq({'new_colorscheme'}, funcs.getcompletion('new_c', 'color')) @@ -55,17 +56,7 @@ describe('runtime:', function() eq(1, eval('g:lua_colorscheme')) end) - it('loads vim colorscheme when both lua and vim version exist', function() - local colorscheme_file = colorscheme_folder .. sep .. 'new_colorscheme' - write_file(colorscheme_file..'.vim', [[let g:colorscheme = 'vim']]) - write_file(colorscheme_file..'.lua', [[vim.g.colorscheme = 'lua']]) - - exec('colorscheme new_colorscheme') - - eq('vim', eval('g:colorscheme')) - end) - - it("loads lua colorscheme in 'rtp' if vim version only exists in 'pp' #23724", function() + it("'rtp'/'pp' order is respected", function() local pack_dir = 'Test_Pack' mkdir_p(pack_dir) finally(function() @@ -73,38 +64,53 @@ describe('runtime:', function() end) exec('set pp+=' .. pack_dir) - local pack_opt_dir = pack_dir .. sep .. 'pack' .. sep .. 'some_name' .. sep .. 'opt' - local colors_opt_dir = pack_opt_dir .. sep .. 'some_pack' .. sep .. 'colors' + local pack_opt_dir = table.concat({pack_dir, 'pack', 'some_name', 'opt'}, sep) + local colors_opt_dir = table.concat({pack_opt_dir, 'some_pack', 'colors'}, sep) mkdir_p(colors_opt_dir) - local rtp_colorscheme_file = colorscheme_folder .. sep .. 'new_colorscheme' - local pp_opt_colorscheme_file = colors_opt_dir .. sep .. 'new_colorscheme' + local after_colorscheme_folder = table.concat({plug_dir, 'after', 'colors'}, sep) + mkdir_p(after_colorscheme_folder) + exec('set rtp+=' .. plug_dir .. '/after') - write_file(pp_opt_colorscheme_file .. '.lua', [[vim.g.colorscheme = 'lua_pp']]) + write_file(table.concat({colors_opt_dir, 'new_colorscheme.lua'}, sep), + [[vim.g.colorscheme = 'lua_pp']]) exec('colorscheme new_colorscheme') eq('lua_pp', eval('g:colorscheme')) - write_file(pp_opt_colorscheme_file .. '.vim', [[let g:colorscheme = 'vim_pp']]) + write_file(table.concat({colors_opt_dir, 'new_colorscheme.vim'}, sep), + [[let g:colorscheme = 'vim_pp']]) exec('colorscheme new_colorscheme') eq('vim_pp', eval('g:colorscheme')) - write_file(rtp_colorscheme_file .. '.lua', [[vim.g.colorscheme = 'lua_rtp']]) + write_file(table.concat({after_colorscheme_folder, 'new_colorscheme.lua'}, sep), + [[vim.g.colorscheme = 'lua_rtp_after']]) + exec('colorscheme new_colorscheme') + eq('lua_rtp_after', eval('g:colorscheme')) + + write_file(table.concat({after_colorscheme_folder, 'new_colorscheme.vim'}, sep), + [[let g:colorscheme = 'vim_rtp_after']]) + exec('colorscheme new_colorscheme') + eq('vim_rtp_after', eval('g:colorscheme')) + + write_file(table.concat({colorscheme_folder, 'new_colorscheme.lua'}, sep), + [[vim.g.colorscheme = 'lua_rtp']]) exec('colorscheme new_colorscheme') eq('lua_rtp', eval('g:colorscheme')) - write_file(rtp_colorscheme_file .. '.vim', [[let g:colorscheme = 'vim_rtp']]) + write_file(table.concat({colorscheme_folder, 'new_colorscheme.vim'}, sep), + [[let g:colorscheme = 'vim_rtp']]) exec('colorscheme new_colorscheme') eq('vim_rtp', eval('g:colorscheme')) end) end) describe('compiler', function() - local compiler_folder = plug_dir .. sep .. 'compiler' + local compiler_folder = table.concat({plug_dir, 'compiler'}, sep) before_each(function() mkdir_p(compiler_folder) end) - it('loads lua compilers', function() + it('lua compilers work and are included in cmdline completion', function() local compiler_file = compiler_folder .. sep .. 'new_compiler.lua' write_file(compiler_file, [[vim.b.lua_compiler = 1]]) @@ -116,23 +122,27 @@ describe('runtime:', function() eq(1, eval('b:lua_compiler')) end) - it('loads vim compilers when both lua and vim version exist', function() - local compiler_file = compiler_folder .. sep .. 'new_compiler' - exec('let b:compiler = "compiler"') - write_file(compiler_file..'.vim', [[let b:compiler = b:compiler.'_vim']]) - write_file(compiler_file..'.lua', [[vim.b.compiler = vim.b.compiler..'_lua']]) - + it("'rtp' order is respected", function() + local after_compiler_folder = table.concat({plug_dir, 'after', 'compiler'}, sep) + mkdir_p(table.concat({compiler_folder, 'new_compiler'}, sep)) + mkdir_p(table.concat({after_compiler_folder, 'new_compiler'}, sep)) + exec('set rtp+=' .. plug_dir .. '/after') + exec('let g:seq = ""') + -- A .lua file is loaded after a .vim file if they only differ in extension. + -- All files in after/compiler/ are loaded after all files in compiler/. + write_file(table.concat({compiler_folder, 'new_compiler.vim'}, sep), [[let g:seq ..= 'A']]) + write_file(table.concat({compiler_folder, 'new_compiler.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) + write_file(table.concat({after_compiler_folder, 'new_compiler.vim'}, sep), [[let g:seq ..= 'a']]) + write_file(table.concat({after_compiler_folder, 'new_compiler.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) exec('compiler new_compiler') - - -- lua version is sourced after vim - eq('compiler_vim_lua', eval('b:compiler')) + eq('ABab', eval('g:seq')) end) end) describe('ftplugin', function() local ftplugin_folder = table.concat({plug_dir, 'ftplugin'}, sep) - it('loads lua ftplugins', function() + it('lua ftplugins work and are included in cmdline completion', function() mkdir_p(ftplugin_folder) local ftplugin_file = table.concat({ftplugin_folder , 'new-ft.lua'}, sep) write_file(ftplugin_file , [[vim.b.lua_ftplugin = 1]]) @@ -172,7 +182,7 @@ describe('runtime:', function() describe('indent', function() local indent_folder = table.concat({plug_dir, 'indent'}, sep) - it('loads lua indents', function() + it('lua indents work and are included in cmdline completion', function() mkdir_p(indent_folder) local indent_file = table.concat({indent_folder , 'new-ft.lua'}, sep) write_file(indent_file , [[vim.b.lua_indent = 1]]) @@ -183,6 +193,22 @@ describe('runtime:', function() exec [[set filetype=new-ft]] eq(1, eval('b:lua_indent')) end) + + it("'rtp' order is respected", function() + local after_indent_folder = table.concat({plug_dir, 'after', 'indent'}, sep) + mkdir_p(table.concat({indent_folder, 'new-ft'}, sep)) + mkdir_p(table.concat({after_indent_folder, 'new-ft'}, sep)) + exec('set rtp+=' .. plug_dir .. '/after') + exec('let g:seq = ""') + -- A .lua file is loaded after a .vim file if they only differ in extension. + -- All files in after/indent/ are loaded after all files in indent/. + write_file(table.concat({indent_folder, 'new-ft.vim'}, sep), [[let g:seq ..= 'A']]) + write_file(table.concat({indent_folder, 'new-ft.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) + write_file(table.concat({after_indent_folder, 'new-ft.vim'}, sep), [[let g:seq ..= 'a']]) + write_file(table.concat({after_indent_folder, 'new-ft.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) + exec('setfiletype new-ft') + eq('ABab', eval('g:seq')) + end) end) describe('syntax', function() @@ -216,22 +242,45 @@ describe('runtime:', function() eq({'my-lang'}, funcs.getcompletion('my-l', 'syntax')) eq({'syntax/my-lang.lua'}, funcs.getcompletion('syntax/my-l', 'runtime')) end) + + it("'rtp' order is respected", function() + local after_syntax_folder = table.concat({plug_dir, 'after', 'syntax'}, sep) + mkdir_p(table.concat({syntax_folder, 'my-lang'}, sep)) + mkdir_p(table.concat({after_syntax_folder, 'my-lang'}, sep)) + exec('set rtp+=' .. plug_dir .. '/after') + exec('let g:seq = ""') + -- A .lua file is loaded after a .vim file if they only differ in extension. + -- All files in after/syntax/ are loaded after all files in syntax/. + write_file(table.concat({syntax_folder, 'my-lang.vim'}, sep), [[let g:seq ..= 'A']]) + write_file(table.concat({syntax_folder, 'my-lang.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) + write_file(table.concat({syntax_folder, 'my-lang', 'a.vim'}, sep), [[let g:seq ..= 'C']]) + write_file(table.concat({syntax_folder, 'my-lang', 'a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'D']]) + write_file(table.concat({after_syntax_folder, 'my-lang.vim'}, sep), [[let g:seq ..= 'a']]) + write_file(table.concat({after_syntax_folder, 'my-lang.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) + write_file(table.concat({after_syntax_folder, 'my-lang', 'a.vim'}, sep), [[let g:seq ..= 'c']]) + write_file(table.concat({after_syntax_folder, 'my-lang', 'a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'd']]) + exec('setfiletype my-lang') + eq('ABCDabcd', eval('g:seq')) + end) end) describe('spell', function() - local spell_folder = table.concat({plug_dir, 'spell'}, sep) - - it('loads spell/LANG.{vim,lua}', function() - mkdir_p(spell_folder) - local spell_vim = table.concat({spell_folder , 'Xtest.vim'}, sep) - write_file(spell_vim , [[let b:spell_vim = 1]]) - local spell_lua = table.concat({spell_folder , 'Xtest.lua'}, sep) - write_file(spell_lua , [[vim.b.spell_lua = 1]]) + it("loads spell/LANG.{vim,lua} respecting 'rtp' order", function() + local spell_folder = table.concat({plug_dir, 'spell'}, sep) + local after_spell_folder = table.concat({plug_dir, 'after', 'spell'}, sep) + mkdir_p(table.concat({spell_folder, 'Xtest'}, sep)) + mkdir_p(table.concat({after_spell_folder, 'Xtest'}, sep)) + exec('set rtp+=' .. plug_dir .. '/after') + exec('let g:seq = ""') + -- A .lua file is loaded after a .vim file if they only differ in extension. + -- All files in after/spell/ are loaded after all files in spell/. + write_file(table.concat({spell_folder, 'Xtest.vim'}, sep), [[let g:seq ..= 'A']]) + write_file(table.concat({spell_folder, 'Xtest.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) + write_file(table.concat({after_spell_folder, 'Xtest.vim'}, sep), [[let g:seq ..= 'a']]) + write_file(table.concat({after_spell_folder, 'Xtest.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) exec('set spelllang=Xtest') - eq(1, eval('b:spell_vim')) - eq(1, eval('b:spell_lua')) + eq('ABab', eval('g:seq')) end) end) end) - -- cgit From 9176b5e10a6b32ff65c8ba3f532e3bd55c168ec6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 14 Jul 2023 07:57:13 +0800 Subject: fix(runtime): respect 'fileignorecase' when sourcing (#24344) --- test/functional/lua/runtime_spec.lua | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index 1f312fc513..0b8b2234db 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -177,6 +177,31 @@ describe('runtime:', function() exec('setfiletype new-ft') eq('ABCDEFabcdef', eval('g:seq')) end) + + it("'rtp' order is respected with 'fileignorecase'", function() + exec('set fileignorecase') + local after_ftplugin_folder = table.concat({plug_dir, 'after', 'ftplugin'}, sep) + mkdir_p(table.concat({ftplugin_folder, 'new-ft'}, sep)) + mkdir_p(table.concat({after_ftplugin_folder, 'new-ft'}, sep)) + exec('set rtp+=' .. plug_dir .. '/after') + exec('let g:seq = ""') + -- A .lua file is loaded after a .vim file if they only differ in extension. + -- All files in after/ftplugin/ are loaded after all files in ftplugin/. + write_file(table.concat({ftplugin_folder, 'new-ft.VIM'}, sep), [[let g:seq ..= 'A']]) + write_file(table.concat({ftplugin_folder, 'new-ft.LUA'}, sep), [[vim.g.seq = vim.g.seq .. 'B']]) + write_file(table.concat({ftplugin_folder, 'new-ft_a.vim'}, sep), [[let g:seq ..= 'C']]) + write_file(table.concat({ftplugin_folder, 'new-ft_a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'D']]) + write_file(table.concat({ftplugin_folder, 'new-ft', 'a.VIM'}, sep), [[let g:seq ..= 'E']]) + write_file(table.concat({ftplugin_folder, 'new-ft', 'a.LUA'}, sep), [[vim.g.seq = vim.g.seq .. 'F']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft.vim'}, sep), [[let g:seq ..= 'a']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'b']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft_a.VIM'}, sep), [[let g:seq ..= 'c']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft_a.LUA'}, sep), [[vim.g.seq = vim.g.seq .. 'd']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft', 'a.vim'}, sep), [[let g:seq ..= 'e']]) + write_file(table.concat({after_ftplugin_folder, 'new-ft', 'a.lua'}, sep), [[vim.g.seq = vim.g.seq .. 'f']]) + exec('setfiletype new-ft') + eq('ABCDEFabcdef', eval('g:seq')) + end) end) describe('indent', function() -- cgit From f660b794808ac809ee8cafe82ddd824840bc8e2c Mon Sep 17 00:00:00 2001 From: kylo252 <59826753+kylo252@users.noreply.github.com> Date: Sun, 16 Jul 2023 14:50:10 +0200 Subject: test(fs): get tmpdir robustly #23021 Problem: helpers.tmpname() may create a local file, depending on circumstances. Solution: Only use helpers.tmpname() for its parent directory (the "temp root"). Use fs_mkdtemp() to actually get a unique name. --- test/functional/lua/watch_spec.lua | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index f041f4f1b6..d802a955fa 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -3,7 +3,6 @@ local eq = helpers.eq local exec_lua = helpers.exec_lua local clear = helpers.clear local is_os = helpers.is_os -local mkdir = helpers.mkdir describe('vim._watch', function() before_each(function() @@ -12,9 +11,7 @@ describe('vim._watch', function() describe('watch', function() it('detects file changes', function() - local root_dir = helpers.tmpname() - os.remove(root_dir) - mkdir(root_dir) + local root_dir = vim.loop.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') local result = exec_lua( [[ @@ -100,9 +97,7 @@ describe('vim._watch', function() describe('poll', function() it('detects file changes', function() - local root_dir = helpers.tmpname() - os.remove(root_dir) - mkdir(root_dir) + local root_dir = vim.loop.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') local result = exec_lua( [[ -- cgit From 98b22867c33a45aaaf057afbeda8acb0216494e3 Mon Sep 17 00:00:00 2001 From: kylo252 <59826753+kylo252@users.noreply.github.com> Date: Mon, 17 Jul 2023 13:27:55 +0200 Subject: test(fs): vim.loop was renamed to vim.uv (#24376) test(fs): vim.loop has been replaced with vim.uv --- test/functional/lua/watch_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index d802a955fa..ee31975063 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -11,7 +11,7 @@ describe('vim._watch', function() describe('watch', function() it('detects file changes', function() - local root_dir = vim.loop.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') + local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') local result = exec_lua( [[ @@ -97,7 +97,7 @@ describe('vim._watch', function() describe('poll', function() it('detects file changes', function() - local root_dir = vim.loop.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') + local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') local result = exec_lua( [[ -- cgit From e4da418ba8388e94bb186e3f9a2004ee1e96f1e5 Mon Sep 17 00:00:00 2001 From: Mike <4576770+mike325@users.noreply.github.com> Date: Tue, 18 Jul 2023 08:36:04 +0200 Subject: fix(fs.lua): normalize slash truncation (#23753) Preserve last slash in windows' root drive directories --- test/functional/lua/fs_spec.lua | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index c1091cff60..2c7b3ff324 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -301,5 +301,10 @@ describe('vim.fs', function() return vim.fs.normalize('$XDG_CONFIG_HOME/nvim') ]], xdg_config_home)) end) + if is_os('win') then + it('Last slash is not truncated from root drive', function() + eq('C:/', exec_lua [[ return vim.fs.normalize('C:/') ]]) + end) + end end) end) -- cgit From ca9f4a7cb1fea1ef1f22c011679fd8afa0a5d161 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 21 Jul 2023 16:30:05 +0800 Subject: docs: also change "vimL" and "viml" to "Vimscript" (#24414) --- test/functional/lua/vim_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index f168e6ba1d..77c724b8e6 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -276,7 +276,7 @@ describe('lua stdlib', function() | ]]} - -- nvim_command causes a vimL exception, check that it is properly caught + -- nvim_command causes a Vimscript exception, check that it is properly caught -- and propagated as an error message in async contexts.. #10809 exec_lua([[ vim.schedule(function() @@ -831,7 +831,7 @@ describe('lua stdlib', function() it('vim.call, vim.fn', function() eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]])) eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]])) - -- compat: nvim_call_function uses "special" value for vimL float + -- compat: nvim_call_function uses "special" value for Vimscript float eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]])) exec([[ -- cgit From 7907b1fca5fce69e966ab1071df8e6d11afda41d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Fri, 21 Jul 2023 13:34:38 +0200 Subject: test(vim.ui.open): mock failure on Windows Problem: On Windows, `rundll32` exits zero (success) even when given a non-existent file. Solution: Mock vim.system() on Windows to force a "failure" case. --- test/functional/lua/ui_spec.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua index 808b25d9ea..d4c150c5f2 100644 --- a/test/functional/lua/ui_spec.lua +++ b/test/functional/lua/ui_spec.lua @@ -6,6 +6,7 @@ local clear = helpers.clear local feed = helpers.feed local eval = helpers.eval local is_ci = helpers.is_ci +local is_os = helpers.is_os local poke_eventloop = helpers.poke_eventloop describe('vim.ui', function() @@ -134,8 +135,11 @@ describe('vim.ui', function() describe('open()', function() it('validation', function() - if is_ci('github') then - matches('vim.ui.open: command failed %(%d%): { "[^"]+", "non%-existent%-file" }', + if is_os('win') or not is_ci('github') then + exec_lua[[vim.system = function() return { wait=function() return { code=3} end } end]] + end + if not is_os('bsd') then + matches('vim.ui.open: command failed %(%d%): { "[^"]+", .*"non%-existent%-file" }', exec_lua[[local _, err = vim.ui.open('non-existent-file') ; return err]]) end -- cgit From 24e3ee9d07e1433cb13b4d96ec20999f5f02b204 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 22 Jul 2023 09:52:13 +0100 Subject: fix(api/options): validate buf and win Fixes #24398 --- test/functional/lua/vim_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 77c724b8e6..f1a617fb70 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1509,7 +1509,7 @@ describe('lua stdlib', function() ]] eq('', funcs.luaeval "vim.bo.filetype") eq(true, funcs.luaeval "vim.bo[BUF].modifiable") - matches("Invalid option %(not found%): 'nosuchopt'$", + matches("Unknown option 'nosuchopt'$", pcall_err(exec_lua, 'return vim.bo.nosuchopt')) matches("Expected lua string$", pcall_err(exec_lua, 'return vim.bo[0][0].autoread')) @@ -1530,7 +1530,7 @@ describe('lua stdlib', function() eq(0, funcs.luaeval "vim.wo.cole") eq(0, funcs.luaeval "vim.wo[0].cole") eq(0, funcs.luaeval "vim.wo[1001].cole") - matches("Invalid option %(not found%): 'notanopt'$", + matches("Unknown option 'notanopt'$", pcall_err(exec_lua, 'return vim.wo.notanopt')) matches("Invalid window id: %-1$", pcall_err(exec_lua, 'return vim.wo[-1].list')) -- cgit From 0804034c07ad5883bc653d054e549a87d429a8b7 Mon Sep 17 00:00:00 2001 From: Tyler Miller Date: Tue, 1 Aug 2023 08:28:28 -0700 Subject: fix(loader): cache path ambiguity #24491 Problem: cache paths are derived by replacing each reserved/filesystem- path-sensitive char with a `%` char in the original path. With this method, two different files at two different paths (each containing `%` chars) can erroneously resolve to the very same cache path in certain edge-cases. Solution: derive cache paths by url-encoding the original (path) instead using `vim.uri_encode()` with `"rfc2396"`. Increment `Loader.VERSION` to denote this change. --- test/functional/lua/loader_spec.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/loader_spec.lua b/test/functional/lua/loader_spec.lua index e2958d1592..34c36b04ef 100644 --- a/test/functional/lua/loader_spec.lua +++ b/test/functional/lua/loader_spec.lua @@ -33,4 +33,24 @@ describe('vim.loader', function() return _G.TEST ]], tmp)) end) + + it('handles % signs in modpath (#24491)', function() + exec_lua[[ + vim.loader.enable() + ]] + + local tmp1, tmp2 = (function (t) + assert(os.remove(t)) + assert(helpers.mkdir(t)) + assert(helpers.mkdir(t .. '/%')) + return t .. '/%/x', t .. '/%%x' + end)(helpers.tmpname()) + + helpers.write_file(tmp1, 'return 1', true) + helpers.write_file(tmp2, 'return 2', true) + vim.uv.fs_utime(tmp1, 0, 0) + vim.uv.fs_utime(tmp2, 0, 0) + eq(1, exec_lua('return loadfile(...)()', tmp1)) + eq(2, exec_lua('return loadfile(...)()', tmp2)) + end) end) -- cgit From 0b351c3740d621689b17267171e162abd421e759 Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 2 Aug 2023 13:00:13 +0200 Subject: test(api): update tests to new error messages --- test/functional/lua/api_spec.lua | 24 ++++++++++++------------ test/functional/lua/vim_spec.lua | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index ffa2f40e91..5dfc2eb83b 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -173,7 +173,7 @@ describe('luaeval(vim.api.…)', function() it('errors out correctly when working with API', function() -- Conversion errors - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua table', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'obj': Cannot convert given Lua table]], remove_trace(exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]]))) -- Errors in number of arguments eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument', @@ -183,32 +183,32 @@ describe('luaeval(vim.api.…)', function() eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 2 arguments', remove_trace(exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2, 3)")]]))) -- Error in argument types - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua string', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'name': Expected Lua string]], remove_trace(exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2)")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua number', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'start': Expected Lua number]], remove_trace(exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Number is not integral', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'start': Number is not integral]], remove_trace(exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected Lua number', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'window': Expected Lua number]], remove_trace(exc_exec([[call luaeval("vim.api.nvim_win_is_valid(nil)")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'flt': Expected Lua number]], remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'flt': Expected Float-like Lua table]], remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_float({[vim.type_idx]=vim.types.dictionary})")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'arr': Expected Lua table]], remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_array(1)")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'arr': Expected Array-like Lua table]], remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_array({[vim.type_idx]=vim.types.dictionary})")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Lua table]], remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'dct': Expected Dict-like Lua table]], remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]]))) - eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table', + eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected Lua table]], remove_trace(exc_exec([[call luaeval("vim.api.nvim_set_keymap('', '', '', '')")]]))) -- TODO: check for errors with Tabpage argument diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index f1a617fb70..35e87b71da 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1511,7 +1511,7 @@ describe('lua stdlib', function() eq(true, funcs.luaeval "vim.bo[BUF].modifiable") matches("Unknown option 'nosuchopt'$", pcall_err(exec_lua, 'return vim.bo.nosuchopt')) - matches("Expected lua string$", + matches("Expected Lua string$", pcall_err(exec_lua, 'return vim.bo[0][0].autoread')) matches("Invalid buffer id: %-1$", pcall_err(exec_lua, 'return vim.bo[-1].filetype')) -- cgit From dbcba26bf1e4ec717dc488b73351f8a9bb93ff26 Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 9 Aug 2023 20:25:16 +0200 Subject: fix(api): revert unintended change of optional bool params Currently (as of nvim 0.9), the behavior of boolean params in vim.api lua wrappers is inconsistent for optional parameters (part of an `opts` dict) compared to positional parameters. This was inadvertently changed in #24524 . While cleaning up this inconsistency is something we might want eventually, it needs to be discussed separately and the impact of existing code considered. --- test/functional/lua/api_spec.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua index 5dfc2eb83b..d808693a9e 100644 --- a/test/functional/lua/api_spec.lua +++ b/test/functional/lua/api_spec.lua @@ -9,6 +9,7 @@ local eval = helpers.eval local NIL = helpers.NIL local eq = helpers.eq local exec_lua = helpers.exec_lua +local pcall_err = helpers.pcall_err before_each(clear) @@ -171,6 +172,29 @@ describe('luaeval(vim.api.…)', function() eq(4, eval([[type(luaeval('vim.api.nvim__id_dictionary({})'))]])) end) + it('converts booleans in positional args', function() + eq({''}, exec_lua [[ return vim.api.nvim_buf_get_lines(0, 0, 10, false) ]]) + eq({''}, exec_lua [[ return vim.api.nvim_buf_get_lines(0, 0, 10, nil) ]]) + eq('Index out of bounds', pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, true) ]])) + eq('Index out of bounds', pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, 1) ]])) + + -- this follows lua conventions for bools (not api convention for Boolean) + eq('Index out of bounds', pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, 0) ]])) + eq('Index out of bounds', pcall_err(exec_lua, [[ return vim.api.nvim_buf_get_lines(0, 0, 10, {}) ]])) + end) + + it('converts booleans in optional args', function() + eq({}, exec_lua [[ return vim.api.nvim_exec2("echo 'foobar'", {output=false}) ]]) + eq({}, exec_lua [[ return vim.api.nvim_exec2("echo 'foobar'", {}) ]]) -- same as {output=nil} + + -- API conventions (not lua conventions): zero is falsy + eq({}, exec_lua [[ return vim.api.nvim_exec2("echo 'foobar'", {output=0}) ]]) + + eq({output='foobar'}, exec_lua [[ return vim.api.nvim_exec2("echo 'foobar'", {output=true}) ]]) + eq({output='foobar'}, exec_lua [[ return vim.api.nvim_exec2("echo 'foobar'", {output=1}) ]]) + eq([[Invalid 'output': not a boolean]], pcall_err(exec_lua, [[ return vim.api.nvim_exec2("echo 'foobar'", {output={}}) ]])) + end) + it('errors out correctly when working with API', function() -- Conversion errors eq([[Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Invalid 'obj': Cannot convert given Lua table]], -- cgit From 2ee8ace217b8e4405822d3ab1bed5a20bedc4b04 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 9 Aug 2023 15:41:45 -0500 Subject: fix(iter): make pipeline termination conditions consistent (#24614) If an iterator pipeline stage returns nil as its first return value, the other return values are ignored and it is treated as if that stage returned only nil (the semantics of returning nil are different between different stages). This is consistent with how for loops work in Lua more generally, where the for loop breaks when the first return value from the function iterator is nil (see :h for-in for details). --- test/functional/lua/iter_spec.lua | 38 +++----------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/iter_spec.lua b/test/functional/lua/iter_spec.lua index 3b603c9911..ffa28e7b11 100644 --- a/test/functional/lua/iter_spec.lua +++ b/test/functional/lua/iter_spec.lua @@ -154,6 +154,9 @@ describe('vim.iter', function() eq({1, 2}, vim.iter(t):slice(1, 2):totable()) eq({10}, vim.iter(t):slice(10, 10):totable()) eq({8, 9, 10}, vim.iter(t):slice(8, 11):totable()) + + local it = vim.iter(vim.gsplit('a|b|c|d', '|')) + matches('slice%(%) requires a list%-like table', pcall_err(it.slice, it, 1, 3)) end) it('nth()', function() @@ -396,39 +399,4 @@ describe('vim.iter', function() { item_3 = 'test' }, }, output) end) - - it('handles nil values', function() - local t = {1, 2, 3, 4, 5} - do - local it = vim.iter(t):enumerate():map(function(i, v) - if i % 2 == 0 then - return nil, v*v - end - return v, nil - end) - eq({ - { [1] = 1 }, - { [2] = 4 }, - { [1] = 3 }, - { [2] = 16 }, - { [1] = 5 }, - }, it:totable()) - end - - do - local it = vim.iter(ipairs(t)):map(function(i, v) - if i % 2 == 0 then - return nil, v*v - end - return v, nil - end) - eq({ - { [1] = 1 }, - { [2] = 4 }, - { [1] = 3 }, - { [2] = 16 }, - { [1] = 5 }, - }, it:totable()) - end - end) end) -- cgit From e7801775060e2d8f9f20572fac687f438e81caa0 Mon Sep 17 00:00:00 2001 From: Michael Strobel <71396679+Kibadda@users.noreply.github.com> Date: Wed, 16 Aug 2023 15:49:14 +0200 Subject: feat(diagnostic): filter diagnostics by specific severities (#24736) Allow users to filter diagnostics by specifying severities --- test/functional/lua/diagnostic_spec.lua | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 17b2d7da4f..27ba70f057 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -860,7 +860,7 @@ end) ]]) end) - it('returns only requested diagnostics when severity is supplied', function() + it('returns only requested diagnostics when severity range is supplied', function() eq({2, 3, 2}, exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { make_error("Error 1", 1, 1, 1, 5), @@ -882,6 +882,28 @@ end) ]]) end) + it('returns only requested diagnostics when severities are supplied', function() + eq({1, 1, 2}, exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error("Error 1", 1, 1, 1, 5), + make_warning("Warning on Server 1", 1, 1, 2, 3), + make_info("Ignored information", 1, 1, 2, 3), + make_hint("Here's a hint", 1, 1, 2, 3), + }) + + return { + #vim.diagnostic.get(diagnostic_bufnr, { severity = {vim.diagnostic.severity.WARN} }), + #vim.diagnostic.get(diagnostic_bufnr, { severity = {vim.diagnostic.severity.ERROR} }), + #vim.diagnostic.get(diagnostic_bufnr, { + severity = { + vim.diagnostic.severity.INFO, + vim.diagnostic.severity.WARN, + } + }), + } + ]]) + end) + it('allows filtering by line', function() eq(1, exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { -- cgit From 0ba27bb51d3297aec43e78050cc3adcf6879db22 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 23 Aug 2023 16:32:15 +0800 Subject: vim-patch:9.0.1710: scrolloff options work slightly different Problem: sidescrolloff and scrolloff options work slightly different than other global-local options Solution: Make it behave consistent for all global-local options It was noticed, that sidescrolloff and scrolloff options behave differently in comparison to other global-local window options like 'listchars' So make those two behave like other global-local options. Also add some extra documentation for a few special local-window options. Add a few tests to make sure all global-local window options behave similar closes: vim/vim#12956 closes: vim/vim#12643 https://github.com/vim/vim/commit/4a8eb6e7a9df10f79bf95301ced012f0d6a13088 Co-authored-by: Christian Brabandt --- test/functional/lua/vim_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 35e87b71da..9338e95d10 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1548,7 +1548,7 @@ describe('lua stdlib', function() eq(100, funcs.luaeval "vim.wo.scrolloff") exec_lua [[ vim.wo[0][0].scrolloff = 200 - vim.cmd "split" + vim.cmd "enew" ]] eq(100, funcs.luaeval "vim.wo.scrolloff") end) -- cgit From 845d5b8b64190e0e09a6a6dd97bdbc0e6f96eb02 Mon Sep 17 00:00:00 2001 From: Amaan Qureshi Date: Wed, 19 Jul 2023 05:02:49 -0400 Subject: feat(treesitter): improve query error message --- test/functional/lua/overrides_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 1777dd078d..c08f3d06a9 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -54,7 +54,7 @@ describe('print', function() -- TODO(bfredl): these look weird, print() should not use "E5114:" style errors.. eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: [NULL]', pcall_err(command, 'lua print("foo", v_nilerr, "bar")')) - eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:0: abc', + eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc', pcall_err(command, 'lua print("foo", v_abcerr, "bar")')) eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: ', pcall_err(command, 'lua print("foo", v_tblout, "bar")')) @@ -84,9 +84,9 @@ describe('print', function() end ]]) eq('', exec_capture('luafile ' .. fname)) - eq('Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:0: my mistake', + eq('Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:1: my mistake', pcall_err(command, 'lua string_error()')) - eq('Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:0: 1234', + eq('Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:2: 1234', pcall_err(command, 'lua number_error()')) eq('Vim(lua):E5108: Error executing lua [NULL]', pcall_err(command, 'lua nil_error()')) -- cgit From a44521f46e6f79171d034e5cce1a4dc266d23e49 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 3 Sep 2023 10:17:24 +0100 Subject: fix(vim.system): let on_exit handle cleanup after kill Fixes #25000 --- test/functional/lua/system_spec.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua index 836d3a83b0..35b9d5cc37 100644 --- a/test/functional/lua/system_spec.lua +++ b/test/functional/lua/system_spec.lua @@ -54,4 +54,28 @@ describe('vim.system', function() end) end + it('kill processes', function() + exec_lua([[ + local signal + local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r) + signal = r.signal + end) -- run forever + + cmd:kill('sigint') + + -- wait for the process not to exist + local done = vim.wait(2000, function() + return signal ~= nil + end) + + assert(done, 'process did not exit') + + -- Check the process is no longer running + vim.fn.systemlist({'ps', 'p', tostring(cmd.pid)}) + assert(vim.v.shell_error == 1, 'dwqdqd '..vim.v.shell_error) + + assert(signal == 2) + ]]) + end) + end) -- cgit From 6d5f12efd286c684de8608c07bb0f76a9d594b5b Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 4 Sep 2023 11:30:16 +0100 Subject: fix(vim.system): make timeout work properly Mimic the behaviour of timeout(1) from coreutils. --- test/functional/lua/system_spec.lua | 40 ++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua index 35b9d5cc37..9321468f84 100644 --- a/test/functional/lua/system_spec.lua +++ b/test/functional/lua/system_spec.lua @@ -5,27 +5,39 @@ local eq = helpers.eq local function system_sync(cmd, opts) return exec_lua([[ - return vim.system(...):wait() + local obj = vim.system(...) + local pid = obj.pid + local res = obj:wait() + + -- Check the process is no longer running + vim.fn.systemlist({'ps', 'p', tostring(pid)}) + assert(vim.v.shell_error == 1, 'process still exists') + + return res ]], cmd, opts) end local function system_async(cmd, opts) - exec_lua([[ + return exec_lua([[ local cmd, opts = ... _G.done = false - vim.system(cmd, opts, function(obj) + local obj = vim.system(cmd, opts, function(obj) _G.done = true _G.ret = obj end) - ]], cmd, opts) - while true do - if exec_lua[[return _G.done]] then - break - end - end + local done = vim.wait(10000, function() + return _G.done + end) + + assert(done, 'process did not exit') - return exec_lua[[return _G.ret]] + -- Check the process is no longer running + vim.fn.systemlist({'ps', 'p', tostring(obj.pid)}) + assert(vim.v.shell_error == 1, 'process still exists') + + return _G.ret + ]], cmd, opts) end describe('vim.system', function() @@ -43,12 +55,12 @@ describe('vim.system', function() eq('hellocat', system({ 'cat' }, { stdin = 'hellocat', text = true }).stdout) end) - it ('supports timeout', function() + it('supports timeout', function() eq({ - code = 0, - signal = 2, + code = 124, + signal = 15, stdout = '', - stderr = "Command timed out: 'sleep 10'" + stderr = '' }, system({ 'sleep', '10' }, { timeout = 1 })) end) end) -- cgit From 80d1333b7317460c562a982ac21f900d9fbd89f6 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 4 Sep 2023 12:03:03 +0100 Subject: refactor(vim.system): factor out on_exit handling --- test/functional/lua/system_spec.lua | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua index 9321468f84..a988d3f0d7 100644 --- a/test/functional/lua/system_spec.lua +++ b/test/functional/lua/system_spec.lua @@ -5,13 +5,20 @@ local eq = helpers.eq local function system_sync(cmd, opts) return exec_lua([[ + local cmd, opts = ... local obj = vim.system(...) - local pid = obj.pid + + if opts.timeout then + -- Minor delay before calling wait() so the timeout uv timer can have a headstart over the + -- internal call to vim.wait() in wait(). + vim.wait(10) + end + local res = obj:wait() -- Check the process is no longer running - vim.fn.systemlist({'ps', 'p', tostring(pid)}) - assert(vim.v.shell_error == 1, 'process still exists') + local proc = vim.api.nvim_get_proc(obj.pid) + assert(not proc, 'process still exists') return res ]], cmd, opts) @@ -26,15 +33,15 @@ local function system_async(cmd, opts) _G.ret = obj end) - local done = vim.wait(10000, function() + local ok = vim.wait(10000, function() return _G.done end) - assert(done, 'process did not exit') + assert(ok, 'process did not exit') -- Check the process is no longer running - vim.fn.systemlist({'ps', 'p', tostring(obj.pid)}) - assert(vim.v.shell_error == 1, 'process still exists') + local proc = vim.api.nvim_get_proc(obj.pid) + assert(not proc, 'process still exists') return _G.ret ]], cmd, opts) @@ -61,7 +68,7 @@ describe('vim.system', function() signal = 15, stdout = '', stderr = '' - }, system({ 'sleep', '10' }, { timeout = 1 })) + }, system({ 'sleep', '10' }, { timeout = 1000 })) end) end) end @@ -83,8 +90,8 @@ describe('vim.system', function() assert(done, 'process did not exit') -- Check the process is no longer running - vim.fn.systemlist({'ps', 'p', tostring(cmd.pid)}) - assert(vim.v.shell_error == 1, 'dwqdqd '..vim.v.shell_error) + local proc = vim.api.nvim_get_proc(cmd.pid) + assert(not proc, 'process still exists') assert(signal == 2) ]]) -- cgit From d27214331815324ea5762b5aa22996b9019085c6 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Wed, 6 Sep 2023 20:54:18 +0300 Subject: fix(diagnostic): always return copies of diagnostic items (#25010) --- test/functional/lua/diagnostic_spec.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 27ba70f057..8deb2e0726 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -181,6 +181,18 @@ describe('vim.diagnostic', function() eq(0, #diagnostics) end) + it('always returns a copy of diagnostic tables', function() + local result = exec_lua [[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + }) + local diag = vim.diagnostic.get() + diag[1].col = 10000 + return vim.diagnostic.get()[1].col == 10000 + ]] + eq(result, false) + end) + it('resolves buffer number 0 to the current buffer', function() eq(2, exec_lua [[ vim.api.nvim_set_current_buf(diagnostic_bufnr) -- cgit From 2d9e7a33f41c842521c74d45927cfcb1874c711b Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Fri, 15 Sep 2023 10:33:26 +0200 Subject: test(windows): unskip working tests (#25153) Also simplify home detection with os_homedir() --- test/functional/lua/fs_spec.lua | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/fs_spec.lua b/test/functional/lua/fs_spec.lua index 2c7b3ff324..6bdb9ed79d 100644 --- a/test/functional/lua/fs_spec.lua +++ b/test/functional/lua/fs_spec.lua @@ -1,4 +1,5 @@ local helpers = require('test.functional.helpers')(after_each) +local uv = require('luv') local clear = helpers.clear local exec_lua = helpers.exec_lua @@ -288,11 +289,12 @@ describe('vim.fs', function() eq('/', exec_lua [[ return vim.fs.normalize('/') ]]) end) it('works with ~', function() - eq( exec_lua([[ - local home = ... - return home .. '/src/foo' - ]], is_os('win') and vim.fs.normalize(os.getenv('USERPROFILE')) or os.getenv('HOME') - ) , exec_lua [[ return vim.fs.normalize('~/src/foo') ]]) + eq( + exec_lua([[ + local home = ... + return home .. '/src/foo' + ]], vim.fs.normalize(uv.os_homedir())), + exec_lua [[ return vim.fs.normalize('~/src/foo') ]]) end) it('works with environment variables', function() local xdg_config_home = test_build_dir .. '/.config' -- cgit From f5a09f1b035254f6ee773a1f88f79ab5913b48a0 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Fri, 15 Sep 2023 06:45:51 -0400 Subject: fix: invoke changed_bytes when rewriting char #25125 When tabstop and shiftwidth are not equal, tabs are inserted as individual spaces and then rewritten as tab characters in a second pass. That second pass did not call changed_bytes which resulted in events being omitted. Fixes #25092 --- test/functional/lua/buffer_updates_spec.lua | 56 ++++++++++++++--------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index c19891a794..51e4548edb 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -826,53 +826,53 @@ describe('lua: nvim_buf_attach on_bytes', function() feed("u") check_events { - { "test1", "bytes", 1, 8, 0, 0, 0, 0, 1, 1, 0, 4, 4 }, - { "test1", "bytes", 1, 8, 0, 0, 0, 0, 4, 4, 0, 0, 0 } + { "test1", "bytes", 1, 9, 0, 0, 0, 0, 1, 1, 0, 4, 4 }, + { "test1", "bytes", 1, 9, 0, 0, 0, 0, 4, 4, 0, 0, 0 } } -- in REPLACE mode feed("R") check_events { - { "test1", "bytes", 1, 9, 0, 0, 0, 0, 1, 1, 0, 1, 1 }, - { "test1", "bytes", 1, 10, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, - { "test1", "bytes", 1, 11, 0, 2, 2, 0, 1, 1, 0, 1, 1 }, - { "test1", "bytes", 1, 12, 0, 3, 3, 0, 0, 0, 0, 1, 1 }, - { "test1", "bytes", 1, 13, 0, 0, 0, 0, 4, 4, 0, 1, 1 }, + { "test1", "bytes", 1, 10, 0, 0, 0, 0, 1, 1, 0, 1, 1 }, + { "test1", "bytes", 1, 11, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, + { "test1", "bytes", 1, 12, 0, 2, 2, 0, 1, 1, 0, 1, 1 }, + { "test1", "bytes", 1, 13, 0, 3, 3, 0, 0, 0, 0, 1, 1 }, + { "test1", "bytes", 1, 14, 0, 0, 0, 0, 4, 4, 0, 1, 1 }, } feed("u") check_events { - { "test1", "bytes", 1, 14, 0, 0, 0, 0, 1, 1, 0, 4, 4 }, - { "test1", "bytes", 1, 14, 0, 2, 2, 0, 2, 2, 0, 1, 1 }, - { "test1", "bytes", 1, 14, 0, 0, 0, 0, 2, 2, 0, 1, 1 } + { "test1", "bytes", 1, 16, 0, 0, 0, 0, 1, 1, 0, 4, 4 }, + { "test1", "bytes", 1, 16, 0, 2, 2, 0, 2, 2, 0, 1, 1 }, + { "test1", "bytes", 1, 16, 0, 0, 0, 0, 2, 2, 0, 1, 1 } } -- in VISUALREPLACE mode feed("gR") check_events { - { "test1", "bytes", 1, 15, 0, 0, 0, 0, 1, 1, 0, 1, 1 }; - { "test1", "bytes", 1, 16, 0, 1, 1, 0, 1, 1, 0, 1, 1 }; - { "test1", "bytes", 1, 17, 0, 2, 2, 0, 1, 1, 0, 1, 1 }; - { "test1", "bytes", 1, 18, 0, 3, 3, 0, 1, 1, 0, 1, 1 }; - { "test1", "bytes", 1, 19, 0, 3, 3, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 20, 0, 3, 3, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 22, 0, 2, 2, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 23, 0, 2, 2, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 25, 0, 1, 1, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 26, 0, 1, 1, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 28, 0, 0, 0, 0, 1, 1, 0, 0, 0 }; - { "test1", "bytes", 1, 29, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 31, 0, 0, 0, 0, 4, 4, 0, 1, 1 }; + { "test1", "bytes", 1, 17, 0, 0, 0, 0, 1, 1, 0, 1, 1 }; + { "test1", "bytes", 1, 18, 0, 1, 1, 0, 1, 1, 0, 1, 1 }; + { "test1", "bytes", 1, 19, 0, 2, 2, 0, 1, 1, 0, 1, 1 }; + { "test1", "bytes", 1, 20, 0, 3, 3, 0, 1, 1, 0, 1, 1 }; + { "test1", "bytes", 1, 21, 0, 3, 3, 0, 1, 1, 0, 0, 0 }; + { "test1", "bytes", 1, 22, 0, 3, 3, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 24, 0, 2, 2, 0, 1, 1, 0, 0, 0 }; + { "test1", "bytes", 1, 25, 0, 2, 2, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 27, 0, 1, 1, 0, 1, 1, 0, 0, 0 }; + { "test1", "bytes", 1, 28, 0, 1, 1, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 30, 0, 0, 0, 0, 1, 1, 0, 0, 0 }; + { "test1", "bytes", 1, 31, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 33, 0, 0, 0, 0, 4, 4, 0, 1, 1 }; } -- inserting tab after other tabs command("set sw=4") feed("0a") check_events { - { "test1", "bytes", 1, 32, 0, 1, 1, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 33, 0, 2, 2, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 34, 0, 3, 3, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 35, 0, 4, 4, 0, 0, 0, 0, 1, 1 }; - { "test1", "bytes", 1, 36, 0, 1, 1, 0, 4, 4, 0, 1, 1 }; + { "test1", "bytes", 1, 34, 0, 1, 1, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 35, 0, 2, 2, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 36, 0, 3, 3, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 37, 0, 4, 4, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 38, 0, 1, 1, 0, 4, 4, 0, 1, 1 }; } end) -- cgit From 4ab9c5fa46845807a2dc6dd91fc5fb78ccc70856 Mon Sep 17 00:00:00 2001 From: Phelipe Teles <39670535+phelipetls@users.noreply.github.com> Date: Sat, 16 Sep 2023 19:35:12 -0300 Subject: fix(lua): not using global value in vim.opt_global (#25196) --- test/functional/lua/vim_spec.lua | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 9338e95d10..1dfb9a5e10 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2257,8 +2257,8 @@ describe('lua stdlib', function() end) end) -- vim.opt - describe('opt_local', function() - it('should be able to append to an array list type option', function() + describe('vim.opt_local', function() + it('appends into global value when changing local option value', function() eq({ "foo,bar,baz,qux" }, exec_lua [[ local result = {} @@ -2273,6 +2273,19 @@ describe('lua stdlib', function() end) end) + describe('vim.opt_global', function() + it('gets current global option value', function() + eq({ "yes" }, exec_lua [[ + local result = {} + + vim.cmd "setglobal signcolumn=yes" + table.insert(result, vim.opt_global.signcolumn:get()) + + return result + ]]) + end) + end) + it('vim.cmd', function() exec_lua [[ vim.cmd "autocmd BufNew * ++once lua BUF = vim.fn.expand('')" -- cgit From 5331d5772ffbbdb3635d0a4b41306817097e86de Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 23 Sep 2023 15:59:37 +0800 Subject: fix(lua): show error message when failing to set variable (#25321) --- test/functional/lua/vim_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 1dfb9a5e10..cf80478b08 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1491,6 +1491,8 @@ describe('lua stdlib', function() eq(NIL, funcs.luaeval "vim.v.null") matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.v[0].progpath')) + eq('Key is read-only: count', pcall_err(exec_lua, 'vim.v.count = 42')) + eq('Dictionary is locked', pcall_err(exec_lua, 'vim.v.nosuchvar = 42')) end) it('vim.bo', function() -- cgit From 4d3a38ac074fff7e2a4bede4cee7699bdd55ffdc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 24 Sep 2023 10:57:09 +0800 Subject: fix(api, lua): handle setting v: variables properly (#25325) --- test/functional/lua/vim_spec.lua | 56 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index cf80478b08..bd3d8f5247 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1491,8 +1491,60 @@ describe('lua stdlib', function() eq(NIL, funcs.luaeval "vim.v.null") matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.v[0].progpath')) - eq('Key is read-only: count', pcall_err(exec_lua, 'vim.v.count = 42')) - eq('Dictionary is locked', pcall_err(exec_lua, 'vim.v.nosuchvar = 42')) + eq('Key is read-only: count', pcall_err(exec_lua, [[vim.v.count = 42]])) + eq('Dictionary is locked', pcall_err(exec_lua, [[vim.v.nosuchvar = 42]])) + eq('Key is fixed: errmsg', pcall_err(exec_lua, [[vim.v.errmsg = nil]])) + exec_lua([[vim.v.errmsg = 'set by Lua']]) + eq('set by Lua', eval('v:errmsg')) + exec_lua([[vim.v.errmsg = 42]]) + eq('42', eval('v:errmsg')) + exec_lua([[vim.v.oldfiles = { 'one', 'two' }]]) + eq({ 'one', 'two' }, eval('v:oldfiles')) + exec_lua([[vim.v.oldfiles = {}]]) + eq({}, eval('v:oldfiles')) + eq('Setting v:oldfiles to value with wrong type', pcall_err(exec_lua, [[vim.v.oldfiles = 'a']])) + eq({}, eval('v:oldfiles')) + + feed('i foo foo foo0/foo') + eq({1, 1}, meths.win_get_cursor(0)) + eq(1, eval('v:searchforward')) + feed('n') + eq({1, 5}, meths.win_get_cursor(0)) + exec_lua([[vim.v.searchforward = 0]]) + eq(0, eval('v:searchforward')) + feed('n') + eq({1, 1}, meths.win_get_cursor(0)) + exec_lua([[vim.v.searchforward = 1]]) + eq(1, eval('v:searchforward')) + feed('n') + eq({1, 5}, meths.win_get_cursor(0)) + + local screen = Screen.new(60, 3) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {background = Screen.colors.Yellow}, + }) + screen:attach() + eq(1, eval('v:hlsearch')) + screen:expect{grid=[[ + {1:foo} {1:^foo} {1:foo} | + {0:~ }| + | + ]]} + exec_lua([[vim.v.hlsearch = 0]]) + eq(0, eval('v:hlsearch')) + screen:expect{grid=[[ + foo ^foo foo | + {0:~ }| + | + ]]} + exec_lua([[vim.v.hlsearch = 1]]) + eq(1, eval('v:hlsearch')) + screen:expect{grid=[[ + {1:foo} {1:^foo} {1:foo} | + {0:~ }| + | + ]]} end) it('vim.bo', function() -- cgit From 5db076c7ccfef6732516074252ac4b21b12fc629 Mon Sep 17 00:00:00 2001 From: Aayush Ojha Date: Fri, 6 Oct 2023 05:44:50 -0700 Subject: fix(lua): vim.region on linewise selection #25467 fixes #18155 --- test/functional/lua/vim_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index bd3d8f5247..c69990d84b 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2401,6 +2401,14 @@ describe('lua stdlib', function() insert([[αα]]) eq({0,5}, exec_lua[[ return vim.region(0,{0,0},{0,4},'3',true)[0] ]]) end) + it('linewise', function() + insert(dedent( [[ + text tααt tααt text + text tαxt txtα tex + text tαxt tαxt + ]])) + eq({0,-1}, exec_lua[[ return vim.region(0,{1,5},{1,14},'V',true)[1] ]]) + end) it('getpos() input', function() insert('getpos') eq({0,6}, exec_lua[[ return vim.region(0,{0,0},'.','v',true)[0] ]]) -- cgit From bf70a33f5e7de0218704126c149db24542e39766 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 14 Oct 2023 09:58:30 +0800 Subject: vim-patch:8.1.0822: peeking and flushing output slows down execution (#25629) Problem: Peeking and flushing output slows down execution. Solution: Do not update the mode message when global_busy is set. Do not flush when only peeking for a character. (Ken Takata) https://github.com/vim/vim/commit/cb574f415486adff645ce384979bfecf27f5be8c --- test/functional/lua/ui_event_spec.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index de436771f9..373d45da61 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -77,8 +77,7 @@ describe('vim.ui_attach', function() } feed '' - -- There is an intermediate state where the 'showmode' message disappears. - screen:expect_unchanged(true) + screen:expect_unchanged() expect_events { { "popupmenu_hide" }; } -- cgit From 7a6e27958a80b3aebb1335b78aa81c26c79b7f37 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 21 Oct 2023 07:21:19 +0800 Subject: ci(cirrus): don't run lua/help_spec (#25498) --- test/functional/lua/help_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/help_spec.lua b/test/functional/lua/help_spec.lua index 8d843cd208..ef1b8ebf3f 100644 --- a/test/functional/lua/help_spec.lua +++ b/test/functional/lua/help_spec.lua @@ -8,6 +8,8 @@ local exec_lua = helpers.exec_lua local eq = helpers.eq local ok = helpers.ok +if helpers.skip(helpers.is_ci('cirrus'), 'No need to run this on Cirrus') then return end + describe(':help docs', function() before_each(clear) it('validate', function() -- cgit From f1775da07fe48da629468bcfcc2a8a6c4c3f40ed Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Fri, 20 Oct 2023 23:51:26 -0700 Subject: feat(lsp): add snippet API (#25301) --- test/functional/lua/snippet_spec.lua | 157 +++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 test/functional/lua/snippet_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua new file mode 100644 index 0000000000..1ae1bc71d5 --- /dev/null +++ b/test/functional/lua/snippet_spec.lua @@ -0,0 +1,157 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local feed = helpers.feed +local matches = helpers.matches +local pcall_err = helpers.pcall_err + +describe('vim.snippet', function() + before_each(function() + clear() + + exec_lua([[ + vim.keymap.set({ 'i', 's' }, '', function() vim.snippet.jump(1) end, { buffer = true }) + vim.keymap.set({ 'i', 's' }, '', function() vim.snippet.jump(-1) end, { buffer = true }) + ]]) + end) + after_each(clear) + + --- @param snippet string[] + --- @param expected string[] + --- @param settings? string + --- @param prefix? string + local function test_success(snippet, expected, settings, prefix) + if settings then + exec_lua(settings) + end + if prefix then + feed('i' .. prefix) + end + exec_lua('vim.snippet.expand(...)', table.concat(snippet, '\n')) + eq(expected, helpers.buf_lines(0)) + end + + --- @param snippet string + --- @param err string + local function test_fail(snippet, err) + matches(err, pcall_err(exec_lua, string.format('vim.snippet.expand("%s")', snippet))) + end + + it('adds base indentation to inserted text', function() + test_success( + { 'function $1($2)', ' $0', 'end' }, + { ' function ()', ' ', ' end' }, + '', + ' ' + ) + end) + + it('replaces tabs with spaces when expandtab is set', function() + test_success( + { 'function $1($2)', '\t$0', 'end' }, + { 'function ()', ' ', 'end' }, + [[ + vim.o.expandtab = true + vim.o.shiftwidth = 2 + ]] + ) + end) + + it('respects tabs when expandtab is not set', function() + test_success( + { 'function $1($2)', '\t$0', 'end' }, + { 'function ()', '\t', 'end' }, + 'vim.o.expandtab = false' + ) + end) + + it('inserts known variable value', function() + test_success({ '; print($TM_CURRENT_LINE)' }, { 'foo; print(foo)' }, nil, 'foo') + end) + + it('uses default when variable is not set', function() + test_success({ 'print(${TM_CURRENT_WORD:foo})' }, { 'print(foo)' }) + end) + + it('replaces unknown variables by placeholders', function() + test_success({ 'print($UNKNOWN)' }, { 'print(UNKNOWN)' }) + end) + + it('does not jump outside snippet range', function() + test_success({ 'function $1($2)', ' $0', 'end' }, { 'function ()', ' ', 'end' }) + eq(false, exec_lua('return vim.snippet.jumpable(-1)')) + feed('i') + eq(false, exec_lua('return vim.snippet.jumpable(1)')) + end) + + it('navigates backwards', function() + test_success({ 'function $1($2) end' }, { 'function () end' }) + feed('foo') + eq({ 'function foo() end' }, helpers.buf_lines(0)) + end) + + it('visits all tabstops', function() + local function cursor() + return exec_lua('return vim.api.nvim_win_get_cursor(0)') + end + + test_success({ 'function $1($2)', ' $0', 'end' }, { 'function ()', ' ', 'end' }) + eq({ 1, 9 }, cursor()) + feed('') + eq({ 1, 10 }, cursor()) + feed('') + eq({ 2, 2 }, cursor()) + end) + + it('syncs text of tabstops with equal indexes', function() + test_success({ 'var double = ${1:x} + ${1:x}' }, { 'var double = x + x' }) + feed('123') + eq({ 'var double = 123 + 123' }, helpers.buf_lines(0)) + end) + + it('cancels session with changes outside the snippet', function() + test_success({ 'print($1)' }, { 'print()' }) + feed('O-- A comment') + eq(false, exec_lua('return vim.snippet.active()')) + eq({ '-- A comment', 'print()' }, helpers.buf_lines(0)) + end) + + it('handles non-consecutive tabstops', function() + test_success({ 'class $1($3) {', ' $0', '}' }, { 'class () {', ' ', '}' }) + feed('Foo') -- First tabstop + feed('') -- Jump to $0 + feed('// Inside') -- Insert text + eq({ 'class Foo() {', ' // Inside', '}' }, helpers.buf_lines(0)) + end) + + it('handles multiline placeholders', function() + test_success( + { 'public void foo() {', ' ${0:// TODO Auto-generated', ' throw;}', '}' }, + { 'public void foo() {', ' // TODO Auto-generated', ' throw;', '}' } + ) + end) + + it('inserts placeholder in all tabstops when the first tabstop has the placeholder', function() + test_success( + { 'for (${1:int} ${2:x} = ${3:0}; $2 < ${4:N}; $2++) {', ' $0', '}' }, + { 'for (int x = 0; x < N; x++) {', ' ', '}' } + ) + end) + + it('inserts placeholder in all tabstops when a later tabstop has the placeholder', function() + test_success( + { 'for (${1:int} $2 = ${3:0}; ${2:x} < ${4:N}; $2++) {', ' $0', '}' }, + { 'for (int x = 0; x < N; x++) {', ' ', '}' } + ) + end) + + it('errors with multiple placeholders for the same index', function() + test_fail('class ${1:Foo} { void ${1:foo}() {} }', 'multiple placeholders for tabstop $1') + end) + + it('errors with multiple $0 tabstops', function() + test_fail('function $1() { $0 }$0', 'multiple $0 tabstops') + end) +end) -- cgit From 370232dbefb91b7ee773ee9a61a9b1ad77d7f1af Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 22 Oct 2023 21:21:02 -0700 Subject: fix(lsp): track snippet deletion --- test/functional/lua/snippet_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index 1ae1bc71d5..fea9d1e982 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -154,4 +154,10 @@ describe('vim.snippet', function() it('errors with multiple $0 tabstops', function() test_fail('function $1() { $0 }$0', 'multiple $0 tabstops') end) + + it('cancels session when deleting the snippet', function() + test_success({ 'local function $1()', ' $0', 'end' }, { 'local function ()', ' ', 'end' }) + feed('Vjjd') + eq(false, exec_lua('return vim.snippet.active()')) + end) end) -- cgit From 94127cb5df0a513e66777d18a2c7fa6219404280 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 22 Oct 2023 22:38:11 -0700 Subject: fix(lsp): do not add extra indentation --- test/functional/lua/snippet_spec.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index fea9d1e982..738420d87d 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -48,6 +48,10 @@ describe('vim.snippet', function() ) end) + it('adds indentation based on the start of snippet lines', function() + test_success({ 'if $1 then', ' $0', 'end' }, { 'if then', ' ', 'end' }) + end) + it('replaces tabs with spaces when expandtab is set', function() test_success( { 'function $1($2)', '\t$0', 'end' }, -- cgit From 15983cf2c64c527fc13681925d0d00c070c30640 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Wed, 25 Oct 2023 22:29:05 -0700 Subject: fix(lsp): cancel session when leaving snippet region (#25762) --- test/functional/lua/snippet_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index 738420d87d..390f268925 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -164,4 +164,11 @@ describe('vim.snippet', function() feed('Vjjd') eq(false, exec_lua('return vim.snippet.active()')) end) + + it('cancels session when leaving snippet region', function() + feed('i') + test_success({ 'local function $1()', ' $0', 'end' }, { '', 'local function ()', ' ', 'end' }) + feed('k') + eq(false, exec_lua('return vim.snippet.active()')) + end) end) -- cgit From add1b10b79011d1af61419a63cc8ef4645f45bbf Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Fri, 27 Oct 2023 09:17:46 -0400 Subject: fix(diagnostic): virtual_text prefix function should have index and total (#25801) The prefix option of the diagnostic virtual text can be a function, but previously it was only a function of diagnostic. This function should also have additional parameters index and total, more consistently and similarily as in the prefix function for `vim.diagnostic.open_float()`. These additional parameters will be useful when there are too many number of diagnostics in a single line. --- test/functional/lua/diagnostic_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 8deb2e0726..f061fac50a 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -1237,7 +1237,7 @@ end) return prefix .. message ]]) - eq('[err-code] Some error', exec_lua [[ + eq('[(1/1) err-code] Some error', exec_lua [[ local diagnostics = { make_error('Some error', 0, 0, 0, 0, nil, 'err-code'), } @@ -1245,7 +1245,7 @@ end) vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, { underline = false, virtual_text = { - prefix = function(diag) return string.format('[%s]', diag.code) end, + prefix = function(diag, i, total) return string.format('[(%d/%d) %s]', i, total, diag.code) end, suffix = '', } }) -- cgit From 0fe0cf5adaab06b92250eb350306de63c4d4f36f Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Mon, 30 Oct 2023 04:58:28 -0700 Subject: fix(lsp): do not cancel snippet when selecting placeholder (#25835) --- test/functional/lua/snippet_spec.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index 390f268925..70337d1572 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -165,10 +165,10 @@ describe('vim.snippet', function() eq(false, exec_lua('return vim.snippet.active()')) end) - it('cancels session when leaving snippet region', function() + it('cancels session when inserting outside snippet region', function() feed('i') test_success({ 'local function $1()', ' $0', 'end' }, { '', 'local function ()', ' ', 'end' }) - feed('k') + feed('O-- A comment') eq(false, exec_lua('return vim.snippet.active()')) end) end) -- cgit From 224f303ee54c54d2147f03010385e8cc48e42869 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 31 Oct 2023 09:15:32 -0500 Subject: feat(stdlib): add vim.base64 module (#25843) Add base64 encode() and decode() functions to a vim.base64 module. --- test/functional/lua/base64_spec.lua | 105 ++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 test/functional/lua/base64_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/base64_spec.lua b/test/functional/lua/base64_spec.lua new file mode 100644 index 0000000000..f0d112c23e --- /dev/null +++ b/test/functional/lua/base64_spec.lua @@ -0,0 +1,105 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local exec_lua = helpers.exec_lua +local eq = helpers.eq +local pcall_err = helpers.pcall_err +local matches = helpers.matches + +describe('vim.base64', function() + before_each(clear) + + local function encode(s) + return exec_lua([[return vim.base64.encode(...)]], s) + end + + local function decode(s) + return exec_lua([[return vim.base64.decode(...)]], s) + end + + it('works', function() + local values = { + '', + 'Many hands make light work.', + [[ + Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in + my purse, and nothing particular to interest me on shore, I thought I would sail about a + little and see the watery part of the world. + ]], + [[ + It is a truth universally acknowledged, that a single man in possession of a good fortune, + must be in want of a wife. + ]], + 'Happy families are all alike; every unhappy family is unhappy in its own way.', + 'ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя', + 'ÅÍÎÏ˝ÓÔÒÚÆ☃', + '𐐜 𐐔𐐇𐐝𐐀𐐡𐐇𐐓 𐐙𐐊𐐡𐐝𐐓/𐐝𐐇𐐗𐐊𐐤𐐔 𐐒𐐋𐐗 𐐒𐐌 𐐜 𐐡𐐀𐐖𐐇𐐤𐐓𐐝 𐐱𐑂 𐑄 𐐔𐐇𐐝𐐀𐐡𐐇𐐓 𐐏𐐆𐐅𐐤𐐆𐐚𐐊𐐡𐐝𐐆𐐓𐐆', + '👨‍👩‍👦 👨‍👩‍👧‍👦 👨‍👨‍👦 👩‍👩‍👧 👨‍👦 👨‍👧‍👦 👩‍👦 👩‍👧‍👦', + 'مُنَاقَشَةُ سُبُلِ اِسْتِخْدَامِ اللُّغَةِ فِي النُّظُمِ الْقَائِمَةِ وَفِيم يَخُصَّ التَّطْبِيقَاتُ الْحاسُوبِيَّةُ،', + [[ + Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣ + ̡͓̞ͅI̗̘̦͝n͇͇͙v̮̫ok̲̫̙͈i̖͙̭̹̠̞n̡̻̮̣̺g̲͈͙̭͙̬͎ ̰t͔̦h̞̲e̢̤ ͍̬̲͖f̴̘͕̣è͖ẹ̥̩l͖͔͚i͓͚̦͠n͖͍̗͓̳̮g͍ ̨o͚̪͡f̘̣̬ ̖̘͖̟͙̮c҉͔̫͖͓͇͖ͅh̵̤̣͚͔á̗̼͕ͅo̼̣̥s̱͈̺̖̦̻͢.̛̖̞̠̫̰ + ̗̺͖̹̯͓Ṯ̤͍̥͇͈h̲́e͏͓̼̗̙̼̣͔ ͇̜̱̠͓͍ͅN͕͠e̗̱z̘̝̜̺͙p̤̺̹͍̯͚e̠̻̠͜r̨̤͍̺̖͔̖̖d̠̟̭̬̝͟i̦͖̩͓͔̤a̠̗̬͉̙n͚͜ ̻̞̰͚ͅh̵͉i̳̞v̢͇ḙ͎͟-҉̭̩̼͔m̤̭̫i͕͇̝̦n̗͙ḍ̟ ̯̲͕͞ǫ̟̯̰̲͙̻̝f ̪̰̰̗̖̭̘͘c̦͍̲̞͍̩̙ḥ͚a̮͎̟̙͜ơ̩̹͎s̤.̝̝ ҉Z̡̖̜͖̰̣͉̜a͖̰͙̬͡l̲̫̳͍̩g̡̟̼̱͚̞̬ͅo̗͜.̟ + ̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕ + Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮ + ]], + } + + for _, v in ipairs(values) do + eq(v, decode(encode(v))) + end + + -- Explicitly check encoded output + eq('VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZwo=', encode('The quick brown fox jumps over the lazy dog\n')) + + -- Test vectors from rfc4648 + local rfc4648 = { + { '', '' }, + { 'f', 'Zg==', }, + { 'fo', 'Zm8=' }, + { 'foo', 'Zm9v' }, + { 'foob', 'Zm9vYg==' }, + { 'fooba', 'Zm9vYmE=' }, + { 'foobar', 'Zm9vYmFy' }, + } + + for _, v in ipairs(rfc4648) do + local input = v[1] + local output = v[2] + eq(output, encode(input)) + eq(input, decode(output)) + end + end) + + it('detects invalid input', function() + local invalid = { + 'A', + 'AA', + 'AAA', + 'A..A', + 'AA=A', + 'AA/=', + 'A/==', + 'A===', + '====', + 'Zm9vYmFyZm9vYmFyA..A', + 'Zm9vYmFyZm9vYmFyAA=A', + 'Zm9vYmFyZm9vYmFyAA/=', + 'Zm9vYmFyZm9vYmFyA/==', + 'Zm9vYmFyZm9vYmFyA===', + 'A..AZm9vYmFyZm9vYmFy', + 'Zm9vYmFyZm9vAA=A', + 'Zm9vYmFyZm9vAA/=', + 'Zm9vYmFyZm9vA/==', + 'Zm9vYmFyZm9vA===', + } + + for _, v in ipairs(invalid) do + eq('Invalid input', pcall_err(decode, v)) + end + + eq('Expected 1 argument', pcall_err(encode)) + eq('Expected 1 argument', pcall_err(decode)) + matches('expected string', pcall_err(encode, 42)) + matches('expected string', pcall_err(decode, 42)) + end) +end) -- cgit From 3198038224209c41932a305e2a2dee708d4e3ec8 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Tue, 7 Nov 2023 01:33:38 +0100 Subject: fix(lua): correct return value for on_key with no arguments (#25911) --- test/functional/lua/vim_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index c69990d84b..1ebfa9dd1d 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2438,6 +2438,12 @@ describe('lua stdlib', function() end) it('allows removing on_key listeners', function() + -- Create some unused namespaces + meths.create_namespace('unused1') + meths.create_namespace('unused2') + meths.create_namespace('unused3') + meths.create_namespace('unused4') + insert([[hello world]]) exec_lua [[ -- cgit From d5a85d737aa2a5c3a64ef0aa5b01672b7ed49c09 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 10 Nov 2023 15:24:36 +0800 Subject: fix(f_wait): flush UI before blocking (#25962) --- test/functional/lua/vim_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 1ebfa9dd1d..a8a72f20c9 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2559,7 +2559,6 @@ describe('lua stdlib', function() ]]) end) - it('should not block other events', function() eq({time = true, wait_result = true}, exec_lua[[ start_time = get_time() @@ -2601,6 +2600,7 @@ describe('lua stdlib', function() } ]]) end) + it('should work with vim.defer_fn', function() eq({time = true, wait_result = true}, exec_lua[[ start_time = get_time() -- cgit From 4e33ef747ca4b26f67c43e73f3105b174e9ef5b6 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Fri, 10 Nov 2023 17:45:40 +0100 Subject: test: skip failing test on freebsd The watch_file test started failing on bsd after 3ca967387c49c754561c3b11a574797504d40f38. --- test/functional/lua/watch_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index ee31975063..0542522140 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -3,6 +3,7 @@ local eq = helpers.eq local exec_lua = helpers.exec_lua local clear = helpers.clear local is_os = helpers.is_os +local skip = helpers.skip describe('vim._watch', function() before_each(function() @@ -11,6 +12,7 @@ describe('vim._watch', function() describe('watch', function() it('detects file changes', function() + skip(is_os('bsd'), "Stopped working on bsd after 3ca967387c49c754561c3b11a574797504d40f38") local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') local result = exec_lua( -- cgit From 4bf47222c973c4bc935d6fde106329f8a0e103e3 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:35:54 -0600 Subject: feat: add vim.text module (#26069) --- test/functional/lua/text_spec.lua | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 test/functional/lua/text_spec.lua (limited to 'test/functional/lua') diff --git a/test/functional/lua/text_spec.lua b/test/functional/lua/text_spec.lua new file mode 100644 index 0000000000..68206557c3 --- /dev/null +++ b/test/functional/lua/text_spec.lua @@ -0,0 +1,23 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local eq = helpers.eq + +describe('vim.text', function() + before_each(clear) + + describe('hexencode() and hexdecode()', function() + it('works', function() + local cases = { + { 'Hello world!', '48656C6C6F20776F726C6421' }, + { '😂', 'F09F9882' }, + } + + for _, v in ipairs(cases) do + local input, output = unpack(v) + eq(output, vim.text.hexencode(input)) + eq(input, vim.text.hexdecode(output)) + end + end) + end) +end) + -- cgit From 7e36c8e972f0b2e07c6186aa5dca2f70d95a77f2 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Thu, 26 Oct 2023 22:53:38 -0700 Subject: feat(lsp): support for choice snippet nodes --- test/functional/lua/snippet_spec.lua | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index 70337d1572..bf43d5114f 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -6,6 +6,7 @@ local exec_lua = helpers.exec_lua local feed = helpers.feed local matches = helpers.matches local pcall_err = helpers.pcall_err +local sleep = helpers.sleep describe('vim.snippet', function() before_each(function() @@ -171,4 +172,30 @@ describe('vim.snippet', function() feed('O-- A comment') eq(false, exec_lua('return vim.snippet.active()')) end) + + it('inserts choice', function () + test_success({ 'console.${1|assert,log,error|}()' }, { 'console.()' }) + sleep(100) + feed('') + eq({ 'console.log()' }, helpers.buf_lines(0)) + end) + + it('closes the choice completion menu when jumping', function () + test_success({ 'console.${1|assert,log,error|}($2)' }, { 'console.()' }) + sleep(100) + exec_lua('vim.snippet.jump(1)') + eq(0, exec_lua('return vim.fn.pumvisible()')) + end) + + it('jumps to next tabstop after inserting choice', function() + test_success( + { '${1|public,protected,private|} function ${2:name}() {', '\t$0', '}' }, + { ' function name() {', '\t', '}' } + ) + sleep(100) + feed('') + sleep(10) + feed('foo') + eq({ 'public function foo() {', '\t', '}' }, helpers.buf_lines(0)) + end) end) -- cgit From 4972c80489af263c96865c43615bea0977a18b77 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 11 Nov 2023 18:07:46 -0800 Subject: refactor(snippet): rename test utilities --- test/functional/lua/snippet_spec.lua | 65 ++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 32 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index bf43d5114f..f0b3b44139 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -1,5 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) +local buf_lines = helpers.buf_lines local clear = helpers.clear local eq = helpers.eq local exec_lua = helpers.exec_lua @@ -23,7 +24,7 @@ describe('vim.snippet', function() --- @param expected string[] --- @param settings? string --- @param prefix? string - local function test_success(snippet, expected, settings, prefix) + local function test_expand_success(snippet, expected, settings, prefix) if settings then exec_lua(settings) end @@ -31,17 +32,17 @@ describe('vim.snippet', function() feed('i' .. prefix) end exec_lua('vim.snippet.expand(...)', table.concat(snippet, '\n')) - eq(expected, helpers.buf_lines(0)) + eq(expected, buf_lines(0)) end --- @param snippet string --- @param err string - local function test_fail(snippet, err) + local function test_expand_fail(snippet, err) matches(err, pcall_err(exec_lua, string.format('vim.snippet.expand("%s")', snippet))) end it('adds base indentation to inserted text', function() - test_success( + test_expand_success( { 'function $1($2)', ' $0', 'end' }, { ' function ()', ' ', ' end' }, '', @@ -50,11 +51,11 @@ describe('vim.snippet', function() end) it('adds indentation based on the start of snippet lines', function() - test_success({ 'if $1 then', ' $0', 'end' }, { 'if then', ' ', 'end' }) + test_expand_success({ 'if $1 then', ' $0', 'end' }, { 'if then', ' ', 'end' }) end) it('replaces tabs with spaces when expandtab is set', function() - test_success( + test_expand_success( { 'function $1($2)', '\t$0', 'end' }, { 'function ()', ' ', 'end' }, [[ @@ -65,7 +66,7 @@ describe('vim.snippet', function() end) it('respects tabs when expandtab is not set', function() - test_success( + test_expand_success( { 'function $1($2)', '\t$0', 'end' }, { 'function ()', '\t', 'end' }, 'vim.o.expandtab = false' @@ -73,28 +74,28 @@ describe('vim.snippet', function() end) it('inserts known variable value', function() - test_success({ '; print($TM_CURRENT_LINE)' }, { 'foo; print(foo)' }, nil, 'foo') + test_expand_success({ '; print($TM_CURRENT_LINE)' }, { 'foo; print(foo)' }, nil, 'foo') end) it('uses default when variable is not set', function() - test_success({ 'print(${TM_CURRENT_WORD:foo})' }, { 'print(foo)' }) + test_expand_success({ 'print(${TM_CURRENT_WORD:foo})' }, { 'print(foo)' }) end) it('replaces unknown variables by placeholders', function() - test_success({ 'print($UNKNOWN)' }, { 'print(UNKNOWN)' }) + test_expand_success({ 'print($UNKNOWN)' }, { 'print(UNKNOWN)' }) end) it('does not jump outside snippet range', function() - test_success({ 'function $1($2)', ' $0', 'end' }, { 'function ()', ' ', 'end' }) + test_expand_success({ 'function $1($2)', ' $0', 'end' }, { 'function ()', ' ', 'end' }) eq(false, exec_lua('return vim.snippet.jumpable(-1)')) feed('i') eq(false, exec_lua('return vim.snippet.jumpable(1)')) end) it('navigates backwards', function() - test_success({ 'function $1($2) end' }, { 'function () end' }) + test_expand_success({ 'function $1($2) end' }, { 'function () end' }) feed('foo') - eq({ 'function foo() end' }, helpers.buf_lines(0)) + eq({ 'function foo() end' }, buf_lines(0)) end) it('visits all tabstops', function() @@ -102,7 +103,7 @@ describe('vim.snippet', function() return exec_lua('return vim.api.nvim_win_get_cursor(0)') end - test_success({ 'function $1($2)', ' $0', 'end' }, { 'function ()', ' ', 'end' }) + test_expand_success({ 'function $1($2)', ' $0', 'end' }, { 'function ()', ' ', 'end' }) eq({ 1, 9 }, cursor()) feed('') eq({ 1, 10 }, cursor()) @@ -111,84 +112,84 @@ describe('vim.snippet', function() end) it('syncs text of tabstops with equal indexes', function() - test_success({ 'var double = ${1:x} + ${1:x}' }, { 'var double = x + x' }) + test_expand_success({ 'var double = ${1:x} + ${1:x}' }, { 'var double = x + x' }) feed('123') - eq({ 'var double = 123 + 123' }, helpers.buf_lines(0)) + eq({ 'var double = 123 + 123' }, buf_lines(0)) end) it('cancels session with changes outside the snippet', function() - test_success({ 'print($1)' }, { 'print()' }) + test_expand_success({ 'print($1)' }, { 'print()' }) feed('O-- A comment') eq(false, exec_lua('return vim.snippet.active()')) - eq({ '-- A comment', 'print()' }, helpers.buf_lines(0)) + eq({ '-- A comment', 'print()' }, buf_lines(0)) end) it('handles non-consecutive tabstops', function() - test_success({ 'class $1($3) {', ' $0', '}' }, { 'class () {', ' ', '}' }) + test_expand_success({ 'class $1($3) {', ' $0', '}' }, { 'class () {', ' ', '}' }) feed('Foo') -- First tabstop feed('') -- Jump to $0 feed('// Inside') -- Insert text - eq({ 'class Foo() {', ' // Inside', '}' }, helpers.buf_lines(0)) + eq({ 'class Foo() {', ' // Inside', '}' }, buf_lines(0)) end) it('handles multiline placeholders', function() - test_success( + test_expand_success( { 'public void foo() {', ' ${0:// TODO Auto-generated', ' throw;}', '}' }, { 'public void foo() {', ' // TODO Auto-generated', ' throw;', '}' } ) end) it('inserts placeholder in all tabstops when the first tabstop has the placeholder', function() - test_success( + test_expand_success( { 'for (${1:int} ${2:x} = ${3:0}; $2 < ${4:N}; $2++) {', ' $0', '}' }, { 'for (int x = 0; x < N; x++) {', ' ', '}' } ) end) it('inserts placeholder in all tabstops when a later tabstop has the placeholder', function() - test_success( + test_expand_success( { 'for (${1:int} $2 = ${3:0}; ${2:x} < ${4:N}; $2++) {', ' $0', '}' }, { 'for (int x = 0; x < N; x++) {', ' ', '}' } ) end) it('errors with multiple placeholders for the same index', function() - test_fail('class ${1:Foo} { void ${1:foo}() {} }', 'multiple placeholders for tabstop $1') + test_expand_fail('class ${1:Foo} { void ${1:foo}() {} }', 'multiple placeholders for tabstop $1') end) it('errors with multiple $0 tabstops', function() - test_fail('function $1() { $0 }$0', 'multiple $0 tabstops') + test_expand_fail('function $1() { $0 }$0', 'multiple $0 tabstops') end) it('cancels session when deleting the snippet', function() - test_success({ 'local function $1()', ' $0', 'end' }, { 'local function ()', ' ', 'end' }) + test_expand_success({ 'local function $1()', ' $0', 'end' }, { 'local function ()', ' ', 'end' }) feed('Vjjd') eq(false, exec_lua('return vim.snippet.active()')) end) it('cancels session when inserting outside snippet region', function() feed('i') - test_success({ 'local function $1()', ' $0', 'end' }, { '', 'local function ()', ' ', 'end' }) + test_expand_success({ 'local function $1()', ' $0', 'end' }, { '', 'local function ()', ' ', 'end' }) feed('O-- A comment') eq(false, exec_lua('return vim.snippet.active()')) end) it('inserts choice', function () - test_success({ 'console.${1|assert,log,error|}()' }, { 'console.()' }) + test_expand_success({ 'console.${1|assert,log,error|}()' }, { 'console.()' }) sleep(100) feed('') - eq({ 'console.log()' }, helpers.buf_lines(0)) + eq({ 'console.log()' }, buf_lines(0)) end) it('closes the choice completion menu when jumping', function () - test_success({ 'console.${1|assert,log,error|}($2)' }, { 'console.()' }) + test_expand_success({ 'console.${1|assert,log,error|}($2)' }, { 'console.()' }) sleep(100) exec_lua('vim.snippet.jump(1)') eq(0, exec_lua('return vim.fn.pumvisible()')) end) it('jumps to next tabstop after inserting choice', function() - test_success( + test_expand_success( { '${1|public,protected,private|} function ${2:name}() {', '\t$0', '}' }, { ' function name() {', '\t', '}' } ) @@ -196,6 +197,6 @@ describe('vim.snippet', function() feed('') sleep(10) feed('foo') - eq({ 'public function foo() {', '\t', '}' }, helpers.buf_lines(0)) + eq({ 'public function foo() {', '\t', '}' }, buf_lines(0)) end) end) -- cgit From de28a0f84c577e264f37cd001b03d640db7d5ef9 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sun, 19 Nov 2023 14:25:32 +0100 Subject: perf(lsp): replace file polling on linux with per dir watcher (#26108) Should help with https://github.com/neovim/neovim/issues/23291 On linux `new_fs_event` doesn't support recursive watching, but we can still use it to watch folders. The downside of this approach is that we may end up sending some false `Deleted` events. For example, if you save a file named `foo` there will be a intermediate `foo~` due to the save mechanism of neovim. The events we get from vim.uv in that case are: - rename: foo~ - rename: foo~ - rename: foo - rename: foo - change: foo - change: foo The mechanism in this PR uses a debounce to reduce this to: - deleted: foo~ - changed: foo `foo~` will be the false positive. I suspect that for the LSP case this is good enough. If not, we may need to follow up on this and keep a table in memory that tracks available files. --- test/functional/lua/watch_spec.lua | 59 ++++++++++++-------------------------- 1 file changed, 19 insertions(+), 40 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index 0542522140..711719addb 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -108,26 +108,24 @@ describe('vim._watch', function() local events = {} - local poll_interval_ms = 1000 - local poll_wait_ms = poll_interval_ms+200 + local debounce = 100 + local wait_ms = debounce + 200 local expected_events = 0 local function wait_for_events() - assert(vim.wait(poll_wait_ms, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) + assert(vim.wait(wait_ms, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) end local incl = lpeg.P(root_dir) * lpeg.P("/file")^-1 local excl = lpeg.P(root_dir..'/file.unwatched') local stop = vim._watch.poll(root_dir, { - interval = poll_interval_ms, + debounce = debounce, include_pattern = incl, exclude_pattern = excl, }, function(path, change_type) table.insert(events, { path = path, change_type = change_type }) end) - vim.wait(100) - local watched_path = root_dir .. '/file' local watched, err = io.open(watched_path, 'w') assert(not err, err) @@ -135,7 +133,7 @@ describe('vim._watch', function() local unwatched, err = io.open(unwatched_path, 'w') assert(not err, err) - expected_events = expected_events + 2 + expected_events = expected_events + 1 wait_for_events() watched:close() @@ -143,7 +141,7 @@ describe('vim._watch', function() unwatched:close() os.remove(unwatched_path) - expected_events = expected_events + 2 + expected_events = expected_events + 1 wait_for_events() stop() @@ -153,8 +151,6 @@ describe('vim._watch', function() local watched, err = io.open(watched_path, 'w') assert(not err, err) - vim.wait(poll_wait_ms) - watched:close() os.remove(watched_path) @@ -163,36 +159,19 @@ describe('vim._watch', function() root_dir ) - eq(4, #result) - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), - path = root_dir .. '/file', - }, result[1]) - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), - path = root_dir, - }, result[2]) - -- The file delete and corresponding directory change events do not happen in any - -- particular order, so allow either - if result[3].path == root_dir then - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), - path = root_dir, - }, result[3]) - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), - path = root_dir .. '/file', - }, result[4]) - else - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), - path = root_dir .. '/file', - }, result[3]) - eq({ - change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), - path = root_dir, - }, result[4]) - end + local created = exec_lua([[return vim._watch.FileChangeType.Created]]) + local deleted = exec_lua([[return vim._watch.FileChangeType.Deleted]]) + local expected = { + { + change_type = created, + path = root_dir .. "/file", + }, + { + change_type = deleted, + path = root_dir .. "/file", + } + } + eq(expected, result) end) end) end) -- cgit From 7ca2d64e8bbfb73f33cf82a2f9c03808bfea3d95 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sun, 19 Nov 2023 18:37:49 +0100 Subject: test: skip failing watch file tests on freebsd (#26110) Quick fix as follow up to https://github.com/neovim/neovim/pull/26108 kqueue only reports events on a watched folder itself, not for files created or deleted within. So the approach the PR took doesn't work on FreeBSD. We'll either need to bring back polling for it, combine watching with manual file tracking, or disable LSP file watching on FreeBSD --- test/functional/lua/watch_spec.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/watch_spec.lua b/test/functional/lua/watch_spec.lua index 711719addb..cdcef08a1a 100644 --- a/test/functional/lua/watch_spec.lua +++ b/test/functional/lua/watch_spec.lua @@ -99,6 +99,7 @@ describe('vim._watch', function() describe('poll', function() it('detects file changes', function() + skip(is_os('bsd'), "bsd only reports rename on folders if file inside change") local root_dir = vim.uv.fs_mkdtemp(vim.fs.dirname(helpers.tmpname()) .. '/nvim_XXXXXXXXXX') local result = exec_lua( -- cgit From fec5e3ab247bcc1ced67f1d0aa7fa10f694f933b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 21 Nov 2023 14:25:45 +0800 Subject: fix(vim.region): handle multibyte inclusive selection properly (#26129) --- test/functional/lua/vim_spec.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index a8a72f20c9..1533a1823f 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2395,7 +2395,14 @@ describe('lua stdlib', function() text tαxt txtα tex text tαxt tαxt ]])) - eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]]) + eq({5,13}, exec_lua[[ return vim.region(0,{0,5},{0,13},'v',false)[0] ]]) + eq({5,15}, exec_lua[[ return vim.region(0,{0,5},{0,13},'v',true)[0] ]]) + eq({5,15}, exec_lua[[ return vim.region(0,{0,5},{0,14},'v',true)[0] ]]) + eq({5,15}, exec_lua[[ return vim.region(0,{0,5},{0,15},'v',false)[0] ]]) + eq({5,17}, exec_lua[[ return vim.region(0,{0,5},{0,15},'v',true)[0] ]]) + eq({5,17}, exec_lua[[ return vim.region(0,{0,5},{0,16},'v',true)[0] ]]) + eq({5,17}, exec_lua[[ return vim.region(0,{0,5},{0,17},'v',false)[0] ]]) + eq({5,18}, exec_lua[[ return vim.region(0,{0,5},{0,17},'v',true)[0] ]]) end) it('blockwise', function() insert([[αα]]) -- cgit From 84bbe4b0ca935db1f6202db339aee5594a3b3908 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 21 Nov 2023 11:24:30 +0000 Subject: fix(lua): disallow vim.wait() in fast contexts `vim.wait()` cannot be called in a fast callback since the main loop cannot be run in that context as it is not reentrant Fixes #26122 --- test/functional/lua/vim_spec.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 1533a1823f..61fa16f59d 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -2769,6 +2769,19 @@ describe('lua stdlib', function() eq({'notification', 'wait', {-2}}, next_msg(500)) end) end) + + it('should not run in fast callbacks #26122', function() + exec_lua([[ + vim.uv.new_timer():start(0, 100, function() + local count = 0 + vim.wait(100, function() + count = count + 1 + return count == 10 + end, 100) + end) + ]]) + assert_alive() + end) end) it('vim.notify_once', function() -- cgit From a03bd2b87882c2a7e0c9e63dadcb2e5fabda1670 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 Nov 2023 18:24:32 +0800 Subject: test: check vim.wait() error message in fast context (#26242) --- test/functional/lua/vim_spec.lua | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'test/functional/lua') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 61fa16f59d..ebe5fc254e 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -11,6 +11,7 @@ local insert = helpers.insert local clear = helpers.clear local eq = helpers.eq local ok = helpers.ok +local pesc = helpers.pesc local eval = helpers.eval local feed = helpers.feed local pcall_err = helpers.pcall_err @@ -2771,15 +2772,19 @@ describe('lua stdlib', function() end) it('should not run in fast callbacks #26122', function() + local screen = Screen.new(80, 10) + screen:attach() exec_lua([[ - vim.uv.new_timer():start(0, 100, function() - local count = 0 - vim.wait(100, function() - count = count + 1 - return count == 10 - end, 100) + local timer = vim.uv.new_timer() + timer:start(0, 0, function() + timer:close() + vim.wait(100, function() end) end) ]]) + screen:expect({ + any = pesc('E5560: vim.wait must not be called in a lua loop callback'), + }) + feed('') assert_alive() end) end) -- cgit