From da70c394053e2110aedf5a8ea72cbaba0ccf06d9 Mon Sep 17 00:00:00 2001 From: Liad Oz Date: Wed, 7 Dec 2022 19:07:56 +0200 Subject: fix(extmarks): adjust extmarks when inserting prompt prefix --- test/functional/api/extmark_spec.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 00f5b25b8a..9902826c72 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1454,6 +1454,14 @@ describe('API/extmarks', function() }} }, get_extmarks(ns, 0, -1, {details=true})) end) + it('in prompt buffer', function() + feed('dd') + local id = set_extmark(ns, marks[1], 0, 0, {}) + curbufmeths.set_option('buftype', 'prompt') + feed('i') + eq({{id, 0, 2}}, get_extmarks(ns, 0, -1)) + end) + it('can get details', function() set_extmark(ns, marks[1], 0, 0, { end_col = 0, -- cgit From 62f09017e09b7dc7bc837b0b13d9f1598685be46 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 26 Jan 2023 10:58:03 +0800 Subject: test: add test for :runtime completion for .lua --- test/functional/lua/runtime_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/functional') diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index b659f2eacb..884ef3ef8e 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -18,6 +18,7 @@ describe('runtime:', function() io.open(init, 'w'):close() -- touch init file clear{args = {'-u', init}} exec('set rtp+=' .. plug_dir) + exec('set completeslash=slash') end) teardown(function() @@ -42,6 +43,7 @@ describe('runtime:', function() write_file(colorscheme_file, [[vim.g.lua_colorscheme = 1]]) eq({'new_colorscheme'}, funcs.getcompletion('new_c', 'color')) + eq({'colors/new_colorscheme.lua'}, funcs.getcompletion('colors/new_c', 'runtime')) exec('colorscheme new_colorscheme') @@ -71,6 +73,7 @@ describe('runtime:', function() write_file(compiler_file, [[vim.b.lua_compiler = 1]]) eq({'new_compiler'}, funcs.getcompletion('new_c', 'compiler')) + eq({'compiler/new_compiler.lua'}, funcs.getcompletion('compiler/new_c', 'runtime')) exec('compiler new_compiler') @@ -100,6 +103,7 @@ describe('runtime:', function() write_file(ftplugin_file , [[vim.b.lua_ftplugin = 1]]) eq({'new-ft'}, funcs.getcompletion('new-f', 'filetype')) + eq({'ftplugin/new-ft.lua'}, funcs.getcompletion('ftplugin/new-f', 'runtime')) exec [[set filetype=new-ft]] eq(1, eval('b:lua_ftplugin')) @@ -116,6 +120,7 @@ describe('runtime:', function() write_file(indent_file , [[vim.b.lua_indent = 1]]) eq({'new-ft'}, funcs.getcompletion('new-f', 'filetype')) + eq({'indent/new-ft.lua'}, funcs.getcompletion('indent/new-f', 'runtime')) exec [[set filetype=new-ft]] eq(1, eval('b:lua_indent')) @@ -152,6 +157,7 @@ describe('runtime:', function() it('lua syntaxes are included in cmdline completion', function() eq({'my-lang'}, funcs.getcompletion('my-l', 'filetype')) eq({'my-lang'}, funcs.getcompletion('my-l', 'syntax')) + eq({'syntax/my-lang.lua'}, funcs.getcompletion('syntax/my-l', 'runtime')) end) end) -- cgit From 3544082f463e5007371a6ac8092d2cfe8ddc91c3 Mon Sep 17 00:00:00 2001 From: Anton Kriese <62887033+akriese@users.noreply.github.com> Date: Thu, 26 Jan 2023 12:06:29 +0100 Subject: test: exepath() returns correct path with cmd.exe, powershell #21928 test(exepath): test if exepath returns correct path with multiple Windows shells This test covers the changes from #21175 where exepath() is set to prefer file extensions in powershell.exe aswell as in cmd.exe. In both shells, the file with a valid extension should be returned instead of the extensionless file. --- test/functional/vimscript/exepath_spec.lua | 43 ++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 11 deletions(-) (limited to 'test/functional') diff --git a/test/functional/vimscript/exepath_spec.lua b/test/functional/vimscript/exepath_spec.lua index 056f67e0ad..da3d61cbe0 100644 --- a/test/functional/vimscript/exepath_spec.lua +++ b/test/functional/vimscript/exepath_spec.lua @@ -5,21 +5,21 @@ local command = helpers.command local exc_exec = helpers.exc_exec local matches = helpers.matches local is_os = helpers.is_os +local set_shell_powershell = helpers.set_shell_powershell +local eval = helpers.eval + +local find_dummies = function(ext_pat) + local tmp_path = eval('$PATH') + command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') + matches('null' .. ext_pat, call('exepath', 'null')) + matches('true' .. ext_pat, call('exepath', 'true')) + matches('false' .. ext_pat, call('exepath', 'false')) + command("let $PATH = '"..tmp_path.."'") +end describe('exepath()', function() before_each(clear) - it('returns 1 for commands in $PATH', function() - local exe = is_os('win') and 'ping' or 'ls' - local ext_pat = is_os('win') and '%.EXE$' or '$' - matches(exe .. ext_pat, call('exepath', exe)) - command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")') - ext_pat = is_os('win') and '%.CMD$' or '$' - matches('null' .. ext_pat, call('exepath', 'null')) - matches('true' .. ext_pat, call('exepath', 'true')) - matches('false' .. ext_pat, call('exepath', 'false')) - end) - it('fails for invalid values', function() for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do eq('Vim(call):E1174: String required for argument 1', exc_exec('call exepath('..input..')')) @@ -32,11 +32,32 @@ describe('exepath()', function() end) if is_os('win') then + it('returns 1 for commands in $PATH (Windows)', function() + local exe = 'ping' + matches(exe .. '%.EXE$', call('exepath', exe)) + end) + it('append extension if omitted', function() local filename = 'cmd' local pathext = '.exe' clear({env={PATHEXT=pathext}}) eq(call('exepath', filename..pathext), call('exepath', filename)) end) + + it('returns file WITH extension if files both with and without extension exist in $PATH', function() + local ext_pat = '%.CMD$' + find_dummies(ext_pat) + set_shell_powershell() + find_dummies(ext_pat) + end) + else + it('returns 1 for commands in $PATH (not Windows)', function() + local exe = 'ls' + matches(exe .. '$', call('exepath', exe)) + end) + + it('returns file WITHOUT extension if files both with and without extension exist in $PATH', function() + find_dummies('$') + end) end end) -- cgit From c032e83b22994332dd8769ef34cb817906a63cac Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 26 Jan 2023 09:42:23 +0100 Subject: fix(treesitter): validate language name Problem: Some injections (like markdown) allow specifying arbitrary language names for code blocks, which may be lead to errors when looking for a corresponding parser in runtime path. Solution: Validate that the language name only contains alphanumeric characters and `_` (e.g., for `c_sharp`) and error otherwise. --- test/functional/treesitter/language_spec.lua | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index f95b05a1cc..df45c9b384 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -31,6 +31,11 @@ describe('treesitter language API', function() pcall_err(exec_lua, 'vim.treesitter.require_language("c", nil, false, "borklang")')) end) + it('shows error for invalid language name', function() + eq(".../language.lua:0: '/foo/' is not a valid language name", + pcall_err(exec_lua, 'vim.treesitter.require_language("/foo/", nil, false)')) + end) + it('inspects language', function() local keys, fields, symbols = unpack(exec_lua([[ local lang = vim.treesitter.inspect_language('c') -- cgit From 860fea1a3f880c2da0ac351a9523156bcfc67361 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 31 Jan 2023 07:08:23 +0800 Subject: fix(highlight): properly deal with underline mask when listing (#22057) --- test/functional/api/highlight_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 5941d4c68b..7f044977cb 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -214,7 +214,7 @@ describe("API: set highlight", function() bold = true, italic = true, reverse = true, - underline = true, + underdashed = true, strikethrough = true, altfont = true, cterm = { @@ -231,7 +231,7 @@ describe("API: set highlight", function() bold = true, italic = true, reverse = true, - underline = true, + underdashed = true, strikethrough = true, altfont = true, } @@ -297,7 +297,7 @@ describe("API: set highlight", function() exec_capture('highlight Test_hl')) meths.set_hl(0, 'Test_hl2', highlight3_config) - eq('Test_hl2 xxx cterm=italic,reverse,strikethrough,altfont,nocombine ctermfg=8 ctermbg=15 gui=bold,underline,italic,reverse,strikethrough,altfont guifg=#ff0000 guibg=#0032aa', + eq('Test_hl2 xxx cterm=italic,reverse,strikethrough,altfont,nocombine ctermfg=8 ctermbg=15 gui=bold,underdashed,italic,reverse,strikethrough,altfont guifg=#ff0000 guibg=#0032aa', exec_capture('highlight Test_hl2')) -- Colors are stored with the name they are defined, but -- cgit From 50b256d51528fef068e07871e18aa3e324b7e2d8 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 31 Jan 2023 13:08:46 +0100 Subject: fix(tests): use -l mode for lsp tests This fixes "fake server" from leaking memory, which makes ASAN very upset, except on current ASAN CI for some reason. --- test/functional/fixtures/fake-lsp-server.lua | 12 ++++++------ test/functional/plugin/lsp/helpers.lua | 9 +++------ test/functional/plugin/lsp_spec.lua | 8 +++----- 3 files changed, 12 insertions(+), 17 deletions(-) (limited to 'test/functional') diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index aa47198f7a..db0c8c0c3f 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -927,10 +927,13 @@ function tests.basic_formatting() } end --- Tests will be indexed by TEST_NAME +-- Tests will be indexed by test_name +local test_name = arg[1] +local timeout = arg[2] +assert(type(test_name) == 'string', 'test_name must be specified as first arg.') local kill_timer = vim.loop.new_timer() -kill_timer:start(_G.TIMEOUT or 1e3, 0, function() +kill_timer:start(timeout or 1e3, 0, function() kill_timer:stop() kill_timer:close() log('ERROR', 'LSP', 'TIMEOUT') @@ -938,14 +941,11 @@ kill_timer:start(_G.TIMEOUT or 1e3, 0, function() os.exit(100) end) -local test_name = _G.TEST_NAME -- lualint workaround -assert(type(test_name) == 'string', 'TEST_NAME must be specified.') local status, err = pcall(assert(tests[test_name], "Test not found")) kill_timer:stop() kill_timer:close() if not status then log('ERROR', 'LSP', tostring(err)) io.stderr:write(err) - os.exit(101) + vim.cmd [[101cquit]] end -os.exit(0) diff --git a/test/functional/plugin/lsp/helpers.lua b/test/functional/plugin/lsp/helpers.lua index 028ccb9e2c..caab174b4d 100644 --- a/test/functional/plugin/lsp/helpers.lua +++ b/test/functional/plugin/lsp/helpers.lua @@ -80,17 +80,14 @@ M.fake_lsp_logfile = 'Xtest-fake-lsp.log' local function fake_lsp_server_setup(test_name, timeout_ms, options, settings) exec_lua([=[ lsp = require('vim.lsp') - local test_name, fixture_filename, logfile, timeout, options, settings = ... + local test_name, fake_lsp_code, fake_lsp_logfile, timeout, options, settings = ... TEST_RPC_CLIENT_ID = lsp.start_client { cmd_env = { - NVIM_LOG_FILE = logfile; + NVIM_LOG_FILE = fake_lsp_logfile; NVIM_LUA_NOTRACK = "1"; }; cmd = { - vim.v.progpath, '-Es', '-u', 'NONE', '--headless', - "-c", string.format("lua TEST_NAME = %q", test_name), - "-c", string.format("lua TIMEOUT = %d", timeout), - "-c", "luafile "..fixture_filename, + vim.v.progpath, '-l', fake_lsp_code, test_name, tostring(timeout), }; handlers = setmetatable({}, { __index = function(t, method) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 5229022564..fd162961ff 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -46,16 +46,14 @@ describe('LSP', function() local test_name = "basic_init" exec_lua([=[ lsp = require('vim.lsp') - local test_name, fixture_filename, logfile = ... + local test_name, fake_lsp_code, fake_lsp_logfile = ... function test__start_client() return lsp.start_client { cmd_env = { - NVIM_LOG_FILE = logfile; + NVIM_LOG_FILE = fake_lsp_logfile; }; cmd = { - vim.v.progpath, '-Es', '-u', 'NONE', '--headless', - "-c", string.format("lua TEST_NAME = %q", test_name), - "-c", "luafile "..fixture_filename; + vim.v.progpath, '-l', fake_lsp_code, test_name; }; workspace_folders = {{ uri = 'file://' .. vim.loop.cwd(), -- cgit From 13aa23b62af4df3e7f10687b76fe8c04efa2a598 Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 30 Jan 2023 20:36:49 +0100 Subject: refactor(tests): run unittests using main nvim binary in interpreter mode This allows us to get rid of the separate "nvim-test" target --- test/functional/core/startup_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test/functional') diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index 1be5de6488..e9b47a0251 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -102,6 +102,13 @@ describe('startup', function() end) it('os.exit() sets Nvim exitcode', function() + -- tricky: LeakSanitizer triggers on os.exit() and disrupts the return value, disable it + exec_lua [[ + local asan_options = os.getenv 'ASAN_OPTIONS' + if asan_options ~= nil and asan_options ~= '' then + vim.loop.os_setenv('ASAN_OPTIONS', asan_options..':detect_leaks=0') + end + ]] -- nvim -l foo.lua -arg1 -- a b c assert_l_out([[ bufs: -- cgit From 9ce44a750c2a65082962effe6ce4d185b7698d73 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 1 Feb 2023 17:21:42 +0000 Subject: fix(man): use italics for `_` (#22086) fix(man): use italics for _ Even though underline is strictly what this should be. _ was used by nroff to indicate italics which wasn't possible on old typewriters so underline was used. Modern terminals now support italics so lets use that now. See: - https://unix.stackexchange.com/questions/274658/purpose-of-ascii-text-with-overstriking-file-format/274795#274795 - https://cmd.inp.nsk.su/old/cmd2/manuals/unix/UNIX_Unleashed/ch08.htm --- test/functional/plugin/man_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index c6c7d2b03d..58da059be6 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -59,7 +59,7 @@ describe(':Man', function() screen:expect([[ ^this {b:is} {b:a} test | - with {u:overstruck} text | + with {i:overstruck} text | {eob:~ }| {eob:~ }| | @@ -98,7 +98,7 @@ describe(':Man', function() screen:expect([[ ^this {b:is} {b:あ} test | - with {u:överstrũck} te{i:xt¶} | + with {i:överstrũck} te{i:xt¶} | {eob:~ }| {eob:~ }| | @@ -115,7 +115,7 @@ describe(':Man', function() screen:expect([[ {b:^_begins} | {b:mid_dle} | - {u:mid_dle} | + {i:mid_dle} | {eob:~ }| | ]]) -- cgit From 2c5906b55bb6092121f4d3b032d5449da7675c2b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 2 Feb 2023 10:05:03 +0800 Subject: fix(exit): skip unnecessary steps in TUI preserve_exit() (#21897) This prevents the TUI from doing unexpected things when receiving a deadly signal or running out of memory. --- test/functional/terminal/tui_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index b28728057f..1d9e7b8e11 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -14,6 +14,7 @@ local clear = helpers.clear local command = helpers.command local dedent = helpers.dedent local exec = helpers.exec +local exec_lua = helpers.exec_lua local testprg = helpers.testprg local retry = helpers.retry local nvim_prog = helpers.nvim_prog @@ -1506,6 +1507,11 @@ describe('TUI', function() {3:-- TERMINAL --} | ]]} end) + + it('no assert failure on deadly signal #21896', function() + exec_lua([[vim.loop.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]]) + screen:expect({any = '%[Process exited 1%]'}) + end) end) describe('TUI', function() -- cgit From 64fa75a86a9e2e301e884e21911d71688fc8f122 Mon Sep 17 00:00:00 2001 From: luukvbaal <31730729+luukvbaal@users.noreply.github.com> Date: Thu, 2 Feb 2023 10:35:51 +0100 Subject: fix(column): estimate 'statuscolumn' width appropriately Problem: The 'statuscolumn' width is being estimated without the proper context. In particular, this resulted in the fact that a custom fold column could be included in the estimated `number_width()`, and doubly added when actually drawing the statuscolumn due to `win_col_off()` also adding the `'foldcolumn'` width. Resulting in a status column that is `'foldcolumn'` cells wider than necessary. Solution: Estimate 'statuscolumn' width in `get_statuscol_str()` when a buffer's line count has changed. --- test/functional/ui/statuscolumn_spec.lua | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index ae3b95fb0f..3233e6cd19 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -439,7 +439,7 @@ describe('statuscolumn', function() vim.api.nvim_buf_set_extmark(0, ns, 7, 0, { virt_lines_leftcol = true, virt_lines = {{{"virt", ""}}} }) ]]) - feed('lh') -- force update wcol/row + feed('lh') -- force update cursor row screen:expect([[ 4 aaaaa | 5 aaaaa | @@ -458,5 +458,24 @@ describe('statuscolumn', function() ]]) command('set stc=') -- also for the default sign column screen:expect_unchanged() + -- 'statuscolumn' is not too wide with custom (bogus) fold column + command([[set stc=%{foldlevel(v:lnum)>0?repeat('-',foldlevel(v:lnum)):''}%=%l\ ]]) + feed('Gd10Ggg') + screen:expect([[ + 1 ^aaaaa | + 2 aaaaa | + 3 aaaaa | + 4 aaaaa | + 5 aaaaa | + 6 aaaaa | + 7 aaaaa | + virt | + ---------8 aaaaa | + virt | + ---------9 aaaaa | + ~ | + ~ | + | + ]]) end) end) -- cgit From 08fb3b5309dee79585f3eec2450636966cbb01b4 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Tue, 31 Jan 2023 00:52:34 +0100 Subject: perf(column): only build fold/sign column when present in 'statuscolumn' Problem: The fold and sign column is built and stored regardless of whether the corresponding item is present in 'statuscolumn'. Solution: Since the 'statuscolumn' parses itself, we can defer building the columns until the corresponding item is actually encountered. --- test/functional/ui/statuscolumn_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index 3233e6cd19..287686cf37 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -456,7 +456,7 @@ describe('statuscolumn', function() 14 aaaaa | | ]]) - command('set stc=') -- also for the default sign column + command('set stc=') -- also for the default fold column screen:expect_unchanged() -- 'statuscolumn' is not too wide with custom (bogus) fold column command([[set stc=%{foldlevel(v:lnum)>0?repeat('-',foldlevel(v:lnum)):''}%=%l\ ]]) -- cgit From 5c4b503d3cb4a48d083bcf50d4932927e6eb749d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 5 Feb 2023 09:37:12 +0800 Subject: vim-patch:9.0.1279: display shows lines scrolled down erroneously (#22126) Problem: Display shows lines scrolled down erroneously. (Yishai Lerner) Solution: Do not change "wl_lnum" at index zero. (closes vim/vim#11938) https://github.com/vim/vim/commit/61fdbfa1e3c842252b701aec12f45839ca41ece5 Co-authored-by: Bram Moolenaar --- test/functional/legacy/move_spec.lua | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 test/functional/legacy/move_spec.lua (limited to 'test/functional') diff --git a/test/functional/legacy/move_spec.lua b/test/functional/legacy/move_spec.lua new file mode 100644 index 0000000000..855996da8f --- /dev/null +++ b/test/functional/legacy/move_spec.lua @@ -0,0 +1,49 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear = helpers.clear +local feed = helpers.feed +local funcs = helpers.funcs + +before_each(clear) + +describe(':move', function() + -- oldtest: Test_move_undo() + it('redraws correctly when undone', function() + local screen = Screen.new(60, 10) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + }) + screen:attach() + + funcs.setline(1, {'First', 'Second', 'Third', 'Fourth'}) + feed('gg:move +1') + screen:expect([[ + Second | + ^First | + Third | + Fourth | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + :move +1 | + ]]) + + -- here the display would show the last few lines scrolled down + feed('u') + feed(':') + screen:expect([[ + ^First | + Second | + Third | + Fourth | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) +end) -- cgit From bb8845340b1b9c2180fb19f049ff9deff5857d99 Mon Sep 17 00:00:00 2001 From: figsoda Date: Thu, 21 Jul 2022 12:08:37 +0100 Subject: feat(treesitter): allow capture text to be transformed Co-authored-by: Lewis Russell --- test/functional/treesitter/parser_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index f006ad4539..0f187f3d52 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -728,7 +728,7 @@ int x = INT_MAX; return list ]] - eq({ 'offset!', 'set!' }, res_list) + eq({ 'gsub!', 'offset!', 'set!' }, res_list) end) end) end) -- cgit From e1d5ad1cb87d43c3d75619e239312d4ab2029b45 Mon Sep 17 00:00:00 2001 From: figsoda Date: Mon, 26 Dec 2022 16:10:59 -0500 Subject: feat(treesitter): add metadata option for get_node_text --- test/functional/treesitter/parser_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 0f187f3d52..2d0d57fbd0 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -277,6 +277,9 @@ end]] function fake_node:end_() return 3, 0, 23 end + function fake_node:range() + return 3, 0, 3, 0 + end return vim.treesitter.get_node_text(fake_node, 0) == nil ]]) eq(true, result) @@ -296,6 +299,9 @@ end]] function fake_node:end_() return 1, 0, 7 end + function fake_node:range() + return 1, 0, 1, 0 + end return vim.treesitter.get_node_text(fake_node, 0) == '' ]]) eq(true, result) -- cgit From 228684d2fbb6262f761b2b5d7001033bd69880c1 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 5 Feb 2023 23:49:43 +0000 Subject: fix(decoration): don't show signcolumn for non-sign_text extmark (#22135) Fixes: #22127 --- test/functional/ui/decorations_spec.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 489c33d8b1..6ed32a8cd4 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -2109,6 +2109,20 @@ l5 | ]]} end) + + it('does not set signcolumn for signs without text', function() + screen:try_resize(20, 3) + meths.win_set_option(0, 'signcolumn', 'auto') + insert(example_text) + feed 'gg' + meths.buf_set_extmark(0, ns, 0, -1, {number_hl_group='Error'}) + screen:expect{grid=[[ + ^l1 | + l2 | + | + ]]} + end) + end) describe('decorations: virt_text', function() -- cgit From ecc40660d1577835245d99f95e14762a30d36054 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 9 Feb 2023 10:53:47 +0800 Subject: fix(rpc): ignore redraw events when not in UI client (#21892) Otherwise it will crash. --- test/functional/api/server_requests_spec.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index ceff390dc5..e6bfc6b64f 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -337,6 +337,21 @@ describe('server -> client', function() eq('localhost:', string.sub(address,1,10)) connect_test(server, 'tcp', address) end) + + it('does not crash on receiving UI events', function() + local server = spawn(nvim_argv) + set_session(server) + local address = funcs.serverlist()[1] + local client = spawn(nvim_argv, false, nil, true) + set_session(client) + + local id = funcs.sockconnect('pipe', address, {rpc=true}) + funcs.rpcrequest(id, 'nvim_ui_attach', 80, 24, {}) + assert_alive() + + server:close() + client:close() + end) end) describe('connecting to its own pipe address', function() -- cgit From b2b82ff14281a4784790af288cde13984d5d5727 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 9 Feb 2023 14:36:17 +0800 Subject: fix(rpc): ignore redraw events when exiting (#22184) When a TUI client has already stopped, handling UI events will cause a heap-use-after-free, so ignore them. --- test/functional/terminal/tui_spec.lua | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 1d9e7b8e11..7294969ac8 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2407,6 +2407,11 @@ describe("TUI as a client", function() {3:-- TERMINAL --} | ]]} + -- No heap-use-after-free when receiving UI events after deadly signal #22184 + server:request('nvim_input', ('a'):rep(1000)) + exec_lua([[vim.loop.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]]) + screen:expect({any = '%[Process exited 1%]'}) + client_super:close() server:close() end) -- cgit From 1b379ce4302e727e01daa051c047e97359ee34e8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 9 Feb 2023 19:48:17 +0800 Subject: test(exit_spec): make sure that autocommands are triggered (#22188) Previously, if the autocommands are not triggered, the tests may still pass because no assertion is done. Add an assertion so that the tests will fail if the autocommands aren't triggered. --- test/functional/core/exit_spec.lua | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'test/functional') diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua index 05a69e1992..dc4b45b4d9 100644 --- a/test/functional/core/exit_spec.lua +++ b/test/functional/core/exit_spec.lua @@ -25,30 +25,34 @@ describe('v:exiting', function() eq(1, eval('v:exiting is v:null')) end) - it('is 0 on normal exit', function() + local function test_exiting(setup_fn) local function on_setup() - command('autocmd VimLeavePre * call rpcrequest('..cid..', "")') - command('autocmd VimLeave * call rpcrequest('..cid..', "")') - command('quit') + command('autocmd VimLeavePre * call rpcrequest('..cid..', "exit", "VimLeavePre")') + command('autocmd VimLeave * call rpcrequest('..cid..', "exit", "VimLeave")') + setup_fn() end - local function on_request() + local requests_args = {} + local function on_request(name, args) + eq('exit', name) + table.insert(requests_args, args) eq(0, eval('v:exiting')) return '' end run(on_request, nil, on_setup) + eq({{'VimLeavePre'}, {'VimLeave'}}, requests_args) + end + + it('is 0 on normal exit', function() + test_exiting(function() + command('quit') + end) end) + it('is 0 on exit from Ex mode involving try-catch vim-patch:8.0.0184', function() - local function on_setup() - command('autocmd VimLeavePre * call rpcrequest('..cid..', "")') - command('autocmd VimLeave * call rpcrequest('..cid..', "")') + test_exiting(function() feed('gQ') feed_command('try', 'call NoFunction()', 'catch', 'echo "bye"', 'endtry', 'quit') - end - local function on_request() - eq(0, eval('v:exiting')) - return '' - end - run(on_request, nil, on_setup) + end) end) end) -- cgit From 8a985d12dd6b4a5a4ba825939f36b7b1a324d849 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 9 Feb 2023 16:08:22 +0000 Subject: fix(treesitter): don't trample parsers when filetype!=lang This allows vim.treesitter.show_tree() to work on buffers where the filetype does not match the parser language name e.g, bash/sh. --- test/functional/treesitter/language_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index df45c9b384..51d8eb62f3 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -82,7 +82,7 @@ describe('treesitter language API', function() command("set filetype=borklang") -- Should throw an error when filetype changes to borklang eq(".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", - pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0)")) + pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')")) end) it('retrieve the tree given a range', function () -- cgit From d6279f9392073cb1422d76c57baf3fd283ed954e Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 31 Jan 2023 23:35:04 +0100 Subject: refactor(tests): move lua-client into core and use it for functionaltests Eliminates lua-client and non-static libluv as test time dependencies Note: the API for a public lua-client is not yet finished. The interface needs to be adjusted to work in the embedded loop of a nvim instance (to use it to talk between instances) --- test/functional/helpers.lua | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'test/functional') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 6400db9f87..cd6b535477 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -1,14 +1,11 @@ -require('coxpcall') local luv = require('luv') local lfs = require('lfs') -local mpack = require('mpack') local global_helpers = require('test.helpers') --- nvim client: Found in .deps/usr/share/lua//nvim/ if "bundled". -local Session = require('nvim.session') -local TcpStream = require('nvim.tcp_stream') -local SocketStream = require('nvim.socket_stream') -local ChildProcessStream = require('nvim.child_process_stream') +local Session = require('test.client.session') +local uv_stream = require('test.client.uv_stream') +local SocketStream = uv_stream.SocketStream +local ChildProcessStream = uv_stream.ChildProcessStream local check_cores = global_helpers.check_cores local check_logs = global_helpers.check_logs @@ -23,7 +20,6 @@ local tbl_contains = global_helpers.tbl_contains local fail = global_helpers.fail local module = { - NIL = mpack.NIL, mkdir = lfs.mkdir, } @@ -202,7 +198,7 @@ function module.expect_msg_seq(...) end local function call_and_stop_on_error(lsession, ...) - local status, result = copcall(...) -- luacheck: ignore + local status, result = Session.safe_pcall(...) -- luacheck: ignore if not status then lsession:stop() last_error = result @@ -428,7 +424,7 @@ end -- Creates a new Session connected by domain socket (named pipe) or TCP. function module.connect(file_or_address) local addr, port = string.match(file_or_address, "(.*):(%d+)") - local stream = (addr and port) and TcpStream.open(addr, port) or + local stream = (addr and port) and SocketStream.connect(addr, port) or SocketStream.open(file_or_address) return Session.new(stream) end -- cgit From f8f82901cdd0ccd5308e05c73af6deb7d083720f Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 1 Feb 2023 12:54:22 +0100 Subject: fix(tests): fixes for using vim.mpack and more ASAN --- test/functional/api/rpc_fixture.lua | 7 +++---- test/functional/api/server_requests_spec.lua | 2 +- test/functional/api/vim_spec.lua | 2 +- test/functional/shada/shada_spec.lua | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/rpc_fixture.lua b/test/functional/api/rpc_fixture.lua index 94df751363..c860a6da59 100644 --- a/test/functional/api/rpc_fixture.lua +++ b/test/functional/api/rpc_fixture.lua @@ -4,9 +4,8 @@ package.path = arg[1] package.cpath = arg[2] -local mpack = require('mpack') -local StdioStream = require('nvim.stdio_stream') -local Session = require('nvim.session') +local StdioStream = require'test.client.uv_stream'.StdioStream +local Session = require'test.client.session' local stdio_stream = StdioStream.open() local session = Session.new(stdio_stream) @@ -19,7 +18,7 @@ local function on_request(method, args) return "done!" elseif method == "exit" then session:stop() - return mpack.NIL + return vim.NIL end end diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index e6bfc6b64f..cb273aedba 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -237,7 +237,7 @@ describe('server -> client', function() \ } ]]) meths.set_var("args", { - helpers.test_lua_prg, + nvim_prog, '-ll', 'test/functional/api/rpc_fixture.lua', package.path, package.cpath, diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 8fcdd9620b..fc550f5861 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -59,7 +59,7 @@ describe('API', function() -- XXX: This must be the last one, else next one will fail: -- "Packer instance already working. Use another Packer ..." - matches("can't serialize object$", + matches("can't serialize object of type .$", pcall_err(request, nil)) end) diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua index 88a99d9b55..7b1ce5d0ca 100644 --- a/test/functional/shada/shada_spec.lua +++ b/test/functional/shada/shada_spec.lua @@ -126,11 +126,11 @@ describe('ShaDa support code', function() wshada(s .. table.concat(msgpack, e .. s) .. e) eq(0, exc_exec('wshada ' .. shada_fname)) local found = 0 - local typ = mpack.unpack(s) + local typ = mpack.decode(s) for _, v in ipairs(read_shada_file(shada_fname)) do if v.type == typ then found = found + 1 - eq(mpack.unpack(msgpack[found]), v.timestamp) + eq(mpack.decode(msgpack[found]), v.timestamp) end end eq(#msgpack, found) -- cgit From 7d58de11f49c574a8a305e28e96b9ff810493012 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 Feb 2023 18:25:01 +0800 Subject: fix(rpc)!: preseve files when stdio channel is closed (#22137) BREAKING CHANGE: Unsaved changes are now preserved rather than discarded when stdio channel is closed. --- test/functional/ex_cmds/oldfiles_spec.lua | 5 ++ test/functional/ex_cmds/profile_spec.lua | 1 + .../ex_cmds/swapfile_preserve_recover_spec.lua | 63 ++++++++++++++++------ test/functional/shada/helpers.lua | 1 + test/functional/shada/history_spec.lua | 1 - test/functional/shada/shada_spec.lua | 38 ++++++------- 6 files changed, 74 insertions(+), 35 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua index 5f87c3cdd9..19611429e0 100644 --- a/test/functional/ex_cmds/oldfiles_spec.lua +++ b/test/functional/ex_cmds/oldfiles_spec.lua @@ -2,6 +2,8 @@ local Screen = require('test.functional.ui.screen') local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear +local command = helpers.command +local expect_exit = helpers.expect_exit local buf, eq, feed_command = helpers.curbufmeths, helpers.eq, helpers.feed_command local feed, poke_eventloop = helpers.feed, helpers.poke_eventloop local ok = helpers.ok @@ -19,6 +21,7 @@ describe(':oldfiles', function() before_each(_clear) after_each(function() + expect_exit(command, 'qall!') os.remove(shada_file) end) @@ -42,6 +45,7 @@ describe(':oldfiles', function() | Press ENTER or type command to continue^ | ]]) + feed('') end) it('can be filtered with :filter', function() @@ -107,6 +111,7 @@ describe(':browse oldfiles', function() end) after_each(function() + expect_exit(command, 'qall!') os.remove(shada_file) end) diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua index 2b92f8d0de..bf045a4d1d 100644 --- a/test/functional/ex_cmds/profile_spec.lua +++ b/test/functional/ex_cmds/profile_spec.lua @@ -30,6 +30,7 @@ describe(':profile', function() before_each(helpers.clear) after_each(function() + helpers.expect_exit(command, 'qall!') if lfs.attributes(tempfile, 'uid') ~= nil then os.remove(tempfile) end diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua index 8eed00c973..ad59025d47 100644 --- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua +++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua @@ -13,6 +13,7 @@ local nvim_prog = helpers.nvim_prog local ok = helpers.ok local rmdir = helpers.rmdir local new_argv = helpers.new_argv +local new_pipename = helpers.new_pipename local pesc = helpers.pesc local os_kill = helpers.os_kill local set_session = helpers.set_session @@ -37,10 +38,21 @@ describe(':recover', function() end) -describe(':preserve', function() +describe("preserve and (R)ecover with custom 'directory'", function() local swapdir = lfs.currentdir()..'/Xtest_recover_dir' + local testfile = 'Xtest_recover_file1' + -- Put swapdir at the start of the 'directory' list. #1836 + -- Note: `set swapfile` *must* go after `set directory`: otherwise it may + -- attempt to create a swapfile in different directory. + local init = [[ + set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[// + set swapfile fileformat=unix undolevels=-1 + ]] + + local nvim1 before_each(function() - clear() + nvim1 = spawn(new_argv()) + set_session(nvim1) rmdir(swapdir) lfs.mkdir(swapdir) end) @@ -49,25 +61,15 @@ describe(':preserve', function() rmdir(swapdir) end) - it("saves to custom 'directory' and (R)ecovers #1836", function() - local testfile = 'Xtest_recover_file1' - -- Put swapdir at the start of the 'directory' list. #1836 - -- Note: `set swapfile` *must* go after `set directory`: otherwise it may - -- attempt to create a swapfile in different directory. - local init = [[ - set directory^=]]..swapdir:gsub([[\]], [[\\]])..[[// - set swapfile fileformat=unix undolevels=-1 - ]] - + local function setup_swapname() exec(init) command('edit! '..testfile) feed('isometext') - command('preserve') exec('redir => g:swapname | silent swapname | redir END') + return eval('g:swapname') + end - local swappath1 = eval('g:swapname') - - os_kill(eval('getpid()')) + local function test_recover(swappath1) -- Start another Nvim instance. local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed'}, true) @@ -90,6 +92,35 @@ describe(':preserve', function() -- Verify that :swapname was not truncated (:help 'shortmess'). ok(nil == string.find(swappath1, '%.%.%.')) ok(nil == string.find(swappath2, '%.%.%.')) + end + + it('with :preserve and SIGKILL', function() + local swappath1 = setup_swapname() + command('preserve') + os_kill(eval('getpid()')) + test_recover(swappath1) + end) + + it('closing stdio channel without :preserve #22096', function() + local swappath1 = setup_swapname() + nvim1:close() + test_recover(swappath1) + end) + + it('killing TUI process without :preserve #22096', function() + helpers.skip(helpers.is_os('win')) + local screen = Screen.new() + screen:attach() + local child_server = new_pipename() + funcs.termopen({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server}) + screen:expect({any = pesc('[No Name]')}) -- Wait for the child process to start. + local child_session = helpers.connect(child_server) + set_session(child_session) + local swappath1 = setup_swapname() + set_session(nvim1) + command('call chanclose(&channel)') -- Kill the child process. + screen:expect({any = pesc('[Process exited 1]')}) -- Wait for the child process to stop. + test_recover(swappath1) end) end) diff --git a/test/functional/shada/helpers.lua b/test/functional/shada/helpers.lua index fb3ec4a87c..cd99d38345 100644 --- a/test/functional/shada/helpers.lua +++ b/test/functional/shada/helpers.lua @@ -33,6 +33,7 @@ local function reset(o) end local clear = function() + helpers.expect_exit(helpers.command, 'qall!') os.remove(tmpname) end diff --git a/test/functional/shada/history_spec.lua b/test/functional/shada/history_spec.lua index d1daf6c7cc..aa4106ad63 100644 --- a/test/functional/shada/history_spec.lua +++ b/test/functional/shada/history_spec.lua @@ -32,7 +32,6 @@ describe('ShaDa support code', function() nvim_command('rshada') eq('" Test 2', funcs.histget(':', -1)) eq('" Test', funcs.histget(':', -2)) - expect_exit(nvim_command, 'qall') end) it('respects &history when dumping', diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua index 7b1ce5d0ca..24bd363e95 100644 --- a/test/functional/shada/shada_spec.lua +++ b/test/functional/shada/shada_spec.lua @@ -136,24 +136,6 @@ describe('ShaDa support code', function() eq(#msgpack, found) end) - it('does not write NONE file', function() - local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', - '--headless', '--cmd', 'qall'}, true) - session:close() - eq(nil, lfs.attributes('NONE')) - eq(nil, lfs.attributes('NONE.tmp.a')) - end) - - it('does not read NONE file', function() - write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-') - local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', - '--headless'}, true) - set_session(session) - eq('', funcs.getreg('a')) - session:close() - os.remove('NONE') - end) - local marklike = {[7]=true, [8]=true, [10]=true, [11]=true} local find_file = function(fname) local found = {} @@ -263,3 +245,23 @@ describe('ShaDa support code', function() meths.set_option('shada', '') end) end) + +describe('ShaDa support code', function() + it('does not write NONE file', function() + local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', + '--headless', '--cmd', 'qall'}, true) + session:close() + eq(nil, lfs.attributes('NONE')) + eq(nil, lfs.attributes('NONE.tmp.a')) + end) + + it('does not read NONE file', function() + write_file('NONE', '\005\001\015\131\161na\162rX\194\162rc\145\196\001-') + local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', + '--headless'}, true) + set_session(session) + eq('', funcs.getreg('a')) + session:close() + os.remove('NONE') + end) +end) -- cgit From 9437800d280385c018a99aa0fbe9043e4d7715aa Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 Feb 2023 18:44:06 +0800 Subject: vim-patch:9.0.1298: inserting register on the cmdline does not trigger incsearch Problem: Inserting a register on the command line does not trigger incsearch or update hlsearch. Solution: Have cmdline_insert_reg() return CMDLINE_CHANGED when appropriate and handle it correctly. (Ken Takata, closes vim/vim#11960) https://github.com/vim/vim/commit/c4b7dec38292fe1cfad7aa5f244031fc6f7c7a09 Co-authored-by: K.Takata --- test/functional/ui/searchhl_spec.lua | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 18bbb56a61..404cc6d043 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -10,7 +10,6 @@ local testprg = helpers.testprg describe('search highlighting', function() local screen - local colors = Screen.colors before_each(function() clear() @@ -18,9 +17,9 @@ describe('search highlighting', function() screen:attach() screen:set_default_attr_ids( { [1] = {bold=true, foreground=Screen.colors.Blue}, - [2] = {background = colors.Yellow}, -- Search + [2] = {background = Screen.colors.Yellow}, -- Search [3] = {reverse = true}, - [4] = {foreground = colors.Red}, -- Message + [4] = {foreground = Screen.colors.Red}, -- Message [6] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey}, -- Folded }) end) @@ -498,6 +497,20 @@ describe('search highlighting', function() {1:~ }│{1:~ }| //^ | ]]) + feed('') + + -- incsearch works after c_CTRL-R_CTRL-R + command('let @" = "file"') + feed('/"') + screen:expect([[ + the first line │the first line | + in a little {3:file} │in a little {2:file} | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + /file^ | + ]]) end) it('works with incsearch and offset', function() @@ -572,12 +585,12 @@ describe('search highlighting', function() it('works with matchadd and syntax', function() screen:set_default_attr_ids { [1] = {bold=true, foreground=Screen.colors.Blue}; - [2] = {background = colors.Yellow}; + [2] = {background = Screen.colors.Yellow}; [3] = {reverse = true}; - [4] = {foreground = colors.Red}; - [5] = {bold = true, background = colors.Green}; - [6] = {italic = true, background = colors.Magenta}; - [7] = {bold = true, background = colors.Yellow}; + [4] = {foreground = Screen.colors.Red}; + [5] = {bold = true, background = Screen.colors.Green}; + [6] = {italic = true, background = Screen.colors.Magenta}; + [7] = {bold = true, background = Screen.colors.Yellow}; [8] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGray}; } feed_command('set hlsearch') -- cgit From c5b34fa55483d84d1de32937ffff0b7cf1aeba78 Mon Sep 17 00:00:00 2001 From: glacambre Date: Sat, 11 Feb 2023 09:45:11 +0100 Subject: refactor: move init_default_autocmds to lua The original motivation for this change came from developping https://github.com/neovim/neovim/pull/22159, which will require adding more autocommand creation to Neovim's startup sequence. This change requires lightly editing a test that expected no autocommand to have been created from lua. --- test/functional/api/autocmd_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index 22a1311ee9..af13736aa9 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -209,7 +209,7 @@ describe('autocmd api', function() local aus = meths.get_autocmds({ event = 'User', pattern = 'Test' }) local first = aus[1] - eq(first.id, 1) + eq(true, first.id > 0) meths.set_var("some_condition", true) meths.exec_autocmds("User", {pattern = "Test"}) -- cgit 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') 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 c2375efe56b3918f83ee143f48fb7a763fa50289 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 12 Feb 2023 17:32:49 +0800 Subject: fix(ui): make sure screen is valid after resizing Problem: When not inside an Ex command, screen_resize() calls update_screen(), which calls screenclear() and set the screen as valid. However, when inside an Ex command, redrawing is postponed so update_screen() screen doesn't do anything, and the screen is still invalid after the resize, causing ui_comp_raw_line() to be no-op until update_screen() is called on the main loop. Solution: Restore the call to screenclear() inside screen_resize() so that the screen is invalid after screen_resize(). Since screenclear() changes redraw type from UPD_CLEAR to UPD_NOT_VALID, it is called at most once for each resize, so this shouldn't change how much code is run in the common (not inside an Ex command) case. --- test/functional/ui/screen_basic_spec.lua | 81 ++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 3bd2289a73..439021ad87 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -61,6 +61,7 @@ local function screen_tests(linegrid) [5] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Fuchsia}, [6] = {bold = true, foreground = Screen.colors.Fuchsia}, [7] = {bold = true, foreground = Screen.colors.SeaGreen}, + [8] = {foreground = Screen.colors.White, background = Screen.colors.Red}, } ) end) @@ -866,12 +867,9 @@ local function screen_tests(linegrid) end) describe('resize', function() - before_each(function() + it('rebuilds the whole screen', function() screen:try_resize(25, 5) feed('iresize') - end) - - it('rebuilds the whole screen', function() screen:expect([[ resize^ | {0:~ }| @@ -882,6 +880,7 @@ local function screen_tests(linegrid) end) it('has minimum width/height values', function() + feed('iresize') screen:try_resize(1, 1) screen:expect([[ resize^ | @@ -896,7 +895,8 @@ local function screen_tests(linegrid) end) it('VimResized autocommand does not cause invalid UI events #20692 #20759', function() - feed('') + screen:try_resize(25, 5) + feed('iresize') command([[autocmd VimResized * redrawtabline]]) command([[autocmd VimResized * lua vim.api.nvim_echo({ { 'Hello' } }, false, {})]]) command([[autocmd VimResized * let g:echospace = v:echospace]]) @@ -919,6 +919,77 @@ local function screen_tests(linegrid) ]]) eq(29, meths.get_var('echospace')) end) + + it('messages from the same Ex command as resize are visible #22225', function() + feed(':set columns=20 | call') + screen:expect([[ + | + | + | + | + | + | + | + | + | + {1: }| + {8:E471: Argument requi}| + {8:red} | + {7:Press ENTER or type }| + {7:command to continue}^ | + ]]) + feed('') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + feed(':set columns=0') + screen:expect([[ + | + | + | + | + | + {1: }| + {8:E594: Need a}| + {8:t least 12 c}| + {8:olumns: colu}| + {8:mns=0} | + {7:Press ENTER }| + {7:or type comm}| + {7:and to conti}| + {7:nue}^ | + ]]) + feed('') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) end) describe('press enter', 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') 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 5a8039a0cb544eac91c569439c61ba0a35950506 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 13 Feb 2023 17:39:28 +0800 Subject: test(tui_spec): remove unnecessary arguments for remote UI --- test/functional/terminal/tui_spec.lua | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 7294969ac8..31e1f27363 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2365,18 +2365,18 @@ describe("TUI as a client", function() set_session(client_super) local screen_client = thelpers.screen_setup(0, - string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=], + string.format([=[["%s", "--server", "%s", "--remote-ui"]]=], nvim_prog, server_pipe)) - screen_client:expect{grid=[[ - Hello, Worl{1:d} | - {4:~ }| - {4:~ }| - {4:~ }| - {5:[No Name] [+] }| - | - {3:-- TERMINAL --} | - ]]} + screen_client:expect{grid=[[ + Hello, Worl{1:d} | + {4:~ }| + {4:~ }| + {4:~ }| + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]} feed_data(":q!\n") @@ -2394,7 +2394,7 @@ describe("TUI as a client", function() set_session(client_super) local screen = thelpers.screen_setup(0, - string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=], + string.format([=[["%s", "--server", "%s", "--remote-ui"]]=], nvim_prog, server_pipe)) screen:expect{grid=[[ @@ -2416,11 +2416,10 @@ describe("TUI as a client", function() server:close() end) - it("throws error when no server exists", function() clear() local screen = thelpers.screen_setup(0, - string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "127.0.0.1:2436546", "--remote-ui"]]=], + string.format([=[["%s", "--server", "127.0.0.1:2436546", "--remote-ui"]]=], nvim_prog), 60) screen:expect([[ @@ -2467,7 +2466,7 @@ describe("TUI as a client", function() set_session(client_super) local screen_client = thelpers.screen_setup(0, - string.format([=[["%s", "-u", "NONE", "-i", "NONE", "--server", "%s", "--remote-ui"]]=], + string.format([=[["%s", "--server", "%s", "--remote-ui"]]=], nvim_prog, server_pipe)) screen_client:expect{grid=[[ -- cgit From 820430dc0bb84011edae801262e64a10be7ebb9d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 13 Feb 2023 16:33:20 +0800 Subject: fix(tui): exit on input eof --- test/functional/terminal/tui_spec.lua | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 31e1f27363..4e62354ed8 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2412,6 +2412,11 @@ describe("TUI as a client", function() exec_lua([[vim.loop.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]]) screen:expect({any = '%[Process exited 1%]'}) + eq(0, meths.get_vvar('shell_error')) + -- exits on input eof #22244 + funcs.system({nvim_prog, '--server', server_pipe, '--remote-ui'}) + eq(1, meths.get_vvar('shell_error')) + client_super:close() server:close() end) -- cgit From 53968082675cd3b8d1809e53a47c0311b7347ef9 Mon Sep 17 00:00:00 2001 From: luukvbaal <31730729+luukvbaal@users.noreply.github.com> Date: Tue, 14 Feb 2023 08:52:22 +0100 Subject: fix(folds): cursorline highlight is not always applied on closed folds (#22242) Problem: The cursorline highlight logic checks for `w_cursor.lnum` which may be different from the line number passed to `win_line()` even when the cursor is actually on that line. Solution: Update cursor line highlight logic to check for the line number of the start of a closed fold if necessary. --- test/functional/ui/fold_spec.lua | 132 ++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 44 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 46a478c1ea..420a4654f8 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -10,6 +10,7 @@ local meths = helpers.meths local exec = helpers.exec local exec_lua = helpers.exec_lua local assert_alive = helpers.assert_alive +local poke_eventloop = helpers.poke_eventloop local content1 = [[ @@ -90,10 +91,10 @@ describe("folded lines", function() end) it("highlights with CursorLineFold when 'cursorline' is set", function() - command("set cursorline foldcolumn=2 foldmethod=marker") + command("set number cursorline foldcolumn=2") command("hi link CursorLineFold Search") insert(content1) - feed("zf3j") + feed("ggzf3jj") if multigrid then screen:expect([[ ## grid 1 @@ -106,26 +107,26 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }in his cave. | - {6: }{12:^ }| + {7:+ }{8: 1 }{5:+-- 4 lines: This is a················}| + {6: }{9: 5 }{12:^in his cave. }| + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| {1:~ }| ## grid 3 | ]]) else screen:expect([[ - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }in his cave. | - {6: }{12:^ }| - {1:~ }| - | + {7:+ }{8: 1 }{5:+-- 4 lines: This is a················}| + {6: }{9: 5 }{12:^in his cave. }| + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | ]]) end feed("k") @@ -141,28 +142,36 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {6: }{12:^in his cave. }| - {7: } | + {6:+ }{9: 1 }{12:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| {1:~ }| ## grid 3 | ]]) else screen:expect([[ - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {6: }{12:^in his cave. }| - {7: } | - {1:~ }| - | + {6:+ }{9: 1 }{12:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | ]]) end + -- CursorLine is applied correctly with screenrow motions #22232 + feed("jgk") + poke_eventloop() + screen:expect_unchanged() + -- CursorLine is applied correctly when closing a fold when cursor is not at fold start + feed("zo4Gzc") + poke_eventloop() + screen:expect_unchanged() command("set cursorlineopt=line") if multigrid then screen:expect([[ @@ -176,26 +185,61 @@ describe("folded lines", function() [2:---------------------------------------------]| [3:---------------------------------------------]| ## grid 2 - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }{12:^in his cave. }| - {7: } | + {7:+ }{8: 1 }{12:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| {1:~ }| ## grid 3 | ]]) else screen:expect([[ - {7: }This is a | - {7: }valid English | - {7: }sentence composed by | - {7: }an exhausted developer | - {7: }{12:^in his cave. }| - {7: } | - {1:~ }| - | + {7:+ }{8: 1 }{12:^+-- 4 lines: This is a················}| + {7: }{8: 5 }in his cave. | + {7: }{8: 6 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + command("set relativenumber cursorlineopt=number") + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {6:+ }{9:1 }{5:^+-- 4 lines: This is a················}| + {7: }{8: 1 }in his cave. | + {7: }{8: 2 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {6:+ }{9:1 }{5:^+-- 4 lines: This is a················}| + {7: }{8: 1 }in his cave. | + {7: }{8: 2 } | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | ]]) end end) -- 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/api/autocmd_spec.lua | 18 +++++----- test/functional/api/buffer_updates_spec.lua | 2 +- test/functional/api/command_spec.lua | 2 +- test/functional/api/extmark_spec.lua | 14 ++++---- test/functional/api/vim_spec.lua | 56 ++++++++++++++++------------- test/functional/lua/vim_spec.lua | 4 +-- test/functional/ui/bufhl_spec.lua | 4 +-- 7 files changed, 53 insertions(+), 47 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index 22a1311ee9..56b0a4d9b2 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -21,7 +21,7 @@ describe('autocmd api', function() callback = "NotAllowed", }) - eq("specify either 'callback' or 'command', not both", rv) + eq("Cannot use both 'callback' and 'command'", rv) end) it('doesnt leak when you use ++once', function() @@ -66,7 +66,7 @@ describe('autocmd api', function() pattern = "*.py", }) - eq("cannot pass both: 'pattern' and 'buffer' for the same autocmd", rv) + eq("Cannot use both 'pattern' and 'buffer' for the same autocmd", rv) end) it('does not allow passing invalid buffers', function() @@ -407,8 +407,8 @@ describe('autocmd api', function() pattern = "", }}, aus) - eq("Invalid value for 'buffer': must be an integer or array of integers", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" })) - eq("Invalid value for 'buffer': must be an integer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } })) + eq("Invalid buffer: expected Integer or Array, got String", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" })) + eq("Invalid buffer: expected Integer, got String", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } })) eq("Invalid buffer id: 42", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { 42 } })) local bufs = {} @@ -416,7 +416,7 @@ describe('autocmd api', function() table.insert(bufs, meths.create_buf(true, false)) end - eq("Too many buffers. Please limit yourself to 256 or fewer", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs })) + eq("Too many buffers (maximum of 256)", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs })) end) it('should return autocmds when group is specified by id', function() @@ -578,7 +578,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches('invalid augroup: NotDefined', code) + matches("Invalid group: 'NotDefined'", code) end) it('raises error for undefined augroup id', function() @@ -596,7 +596,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches('invalid augroup: 1', code) + matches('Invalid group: 1', code) end) it('raises error for invalid group type', function() @@ -611,7 +611,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches("'group' must be a string or an integer", code) + matches("Invalid group: expected String or Integer, got Boolean", code) end) it('raises error for invalid pattern array', function() @@ -625,7 +625,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches("All entries in 'pattern' must be strings", code) + matches("Invalid 'pattern' item type: expected String, got Array", code) end) end) diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua index d5f06c8f1f..1510d31945 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -762,7 +762,7 @@ describe('API: buffer events:', function() it('returns a proper error on nonempty options dict', function() clear() local b = editoriginal(false) - eq("unexpected key: builtin", pcall_err(buffer, 'attach', b, false, {builtin="asfd"})) + eq("Invalid key: 'builtin'", pcall_err(buffer, 'attach', b, false, {builtin="asfd"})) end) it('nvim_buf_attach returns response after delay #8634', function() diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index d0fb26edc7..189f9d4f98 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -543,7 +543,7 @@ describe('nvim_create_user_command', function() end) it('does not allow invalid command names', function() - matches("'name' must begin with an uppercase letter", pcall_err(exec_lua, [[ + matches("Invalid command name %(must begin with an uppercase letter%): 'test'", pcall_err(exec_lua, [[ vim.api.nvim_create_user_command('test', 'echo "hi"', {}) ]])) diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 9902826c72..fc68f11a67 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -106,7 +106,7 @@ describe('API/extmarks', function() end_col = 0, end_row = 1 }) - eq("end_col value outside range", + eq("Invalid end_col: '(out of range)'", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = 1 })) end) @@ -1344,10 +1344,10 @@ describe('API/extmarks', function() it('throws consistent error codes', function() local ns_invalid = ns2 + 1 - eq("Invalid ns_id", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) - eq("Invalid ns_id", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) - eq("Invalid ns_id", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) - eq("Invalid ns_id", pcall_err(get_extmark_by_id, ns_invalid, marks[1])) + eq("Invalid ns_id: 3", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) + eq("Invalid ns_id: 3", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) + eq("Invalid ns_id: 3", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) + eq("Invalid ns_id: 3", pcall_err(get_extmark_by_id, ns_invalid, marks[1])) end) it('when col = line-length, set the mark on eol', function() @@ -1362,13 +1362,13 @@ describe('API/extmarks', function() it('when col = line-length, set the mark on eol', function() local invalid_col = init_text:len() + 1 - eq("col value outside range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) + eq("Invalid col: '(out of range)'", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) end) it('fails when line > line_count', function() local invalid_col = init_text:len() + 1 local invalid_lnum = 3 - eq('line value outside range', pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) + eq("Invalid line: '(out of range)'", pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) eq({}, get_extmark_by_id(ns, marks[1])) end) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index fc550f5861..5c56c90952 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1155,7 +1155,7 @@ describe('API', function() describe('nvim_put', function() it('validates args', function() - eq('Invalid lines (expected array of strings)', + eq("Invalid line: expected String, got Integer", pcall_err(request, 'nvim_put', {42}, 'l', false, false)) eq("Invalid type: 'x'", pcall_err(request, 'nvim_put', {'foo'}, 'x', false, false)) @@ -1410,6 +1410,15 @@ describe('API', function() ok(not nvim('get_option_value', 'equalalways', {})) end) + it('validation', function() + eq("Invalid scope (expected 'local' or 'global')", + pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 'bogus'})) + eq("Invalid scope (expected 'local' or 'global')", + pcall_err(nvim, 'set_option_value', 'scrolloff', 1, {scope = 'bogus'})) + eq("Invalid scope: expected String, got Integer", + pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 42})) + end) + it('can get local values when global value is set', function() eq(0, nvim('get_option_value', 'scrolloff', {})) eq(-1, nvim('get_option_value', 'scrolloff', {scope = 'local'})) @@ -1780,9 +1789,9 @@ describe('API', function() it('validates args', function() eq("Invalid key: 'blah'", pcall_err(nvim, 'get_context', {blah={}})) - eq('invalid value for key: types', + eq("Invalid types: expected Array, got Integer", pcall_err(nvim, 'get_context', {types=42})) - eq('unexpected type: zub', + eq("Invalid type: 'zub'", pcall_err(nvim, 'get_context', {types={'jumps', 'zub', 'zam',}})) end) it('returns map of current editor state', function() @@ -2223,15 +2232,14 @@ describe('API', function() eq(5, meths.get_var('avar')) end) - it('throws error on malformed arguments', function() + it('validation', function() local req = { {'nvim_set_var', {'avar', 1}}, {'nvim_set_var'}, {'nvim_set_var', {'avar', 2}}, } - local status, err = pcall(meths.call_atomic, req) - eq(false, status) - ok(err:match('Items in calls array must be arrays of size 2') ~= nil) + eq('Items in calls array must be arrays of size 2', + pcall_err(meths.call_atomic, req)) -- call before was done, but not after eq(1, meths.get_var('avar')) @@ -2239,18 +2247,16 @@ describe('API', function() { 'nvim_set_var', { 'bvar', { 2, 3 } } }, 12, } - status, err = pcall(meths.call_atomic, req) - eq(false, status) - ok(err:match('Items in calls array must be arrays') ~= nil) + eq("Invalid calls item: expected Array, got Integer", + pcall_err(meths.call_atomic, req)) eq({2,3}, meths.get_var('bvar')) req = { {'nvim_set_current_line', 'little line'}, {'nvim_set_var', {'avar', 3}}, } - status, err = pcall(meths.call_atomic, req) - eq(false, status) - ok(err:match('Args must be Array') ~= nil) + eq("Invalid args: expected Array, got String", + pcall_err(meths.call_atomic, req)) -- call before was done, but not after eq(1, meths.get_var('avar')) eq({''}, meths.buf_get_lines(0, 0, -1, true)) @@ -2750,7 +2756,7 @@ describe('API', function() describe('nvim_get_option_info', function() it('should error for unknown options', function() - eq("no such option: 'bogus'", pcall_err(meths.get_option_info, 'bogus')) + eq("Invalid option (not found): 'bogus'", pcall_err(meths.get_option_info, 'bogus')) end) it('should return the same options for short and long name', function() @@ -3031,10 +3037,10 @@ describe('API', function() eq(true, meths.del_mark('F')) eq({0, 0}, meths.buf_get_mark(buf, 'F')) end) - it('fails when invalid marks are used', function() - eq(false, pcall(meths.del_mark, 'f')) - eq(false, pcall(meths.del_mark, '!')) - eq(false, pcall(meths.del_mark, 'fail')) + it('validation', function() + eq("Invalid mark name (must be file/uppercase): 'f'", pcall_err(meths.del_mark, 'f')) + eq("Invalid mark name (must be file/uppercase): '!'", pcall_err(meths.del_mark, '!')) + eq("Invalid mark name (must be a single char): 'fail'", pcall_err(meths.del_mark, 'fail')) end) end) describe('nvim_get_mark', function() @@ -3048,10 +3054,10 @@ describe('API', function() assert(string.find(mark[4], "mybuf$")) eq({2, 2, buf.id, mark[4]}, mark) end) - it('fails when invalid marks are used', function() - eq(false, pcall(meths.del_mark, 'f')) - eq(false, pcall(meths.del_mark, '!')) - eq(false, pcall(meths.del_mark, 'fail')) + it('validation', function() + eq("Invalid mark name (must be file/uppercase): 'f'", pcall_err(meths.get_mark, 'f', {})) + eq("Invalid mark name (must be file/uppercase): '!'", pcall_err(meths.get_mark, '!', {})) + eq("Invalid mark name (must be a single char): 'fail'", pcall_err(meths.get_mark, 'fail', {})) end) it('returns the expected when mark is not set', function() eq(true, meths.del_mark('A')) @@ -3113,15 +3119,15 @@ describe('API', function() meths.eval_statusline('a%=b', { fillchar = '\031', maxwidth = 5 })) end) it('rejects multiple-character fillchar', function() - eq('fillchar must be a single character', + eq('Invalid fillchar (not a single character)', pcall_err(meths.eval_statusline, '', { fillchar = 'aa' })) end) it('rejects empty string fillchar', function() - eq('fillchar must be a single character', + eq('Invalid fillchar (not a single character)', pcall_err(meths.eval_statusline, '', { fillchar = '' })) end) it('rejects non-string fillchar', function() - eq('fillchar must be a single character', + eq("Invalid fillchar: expected String, got Integer", pcall_err(meths.eval_statusline, '', { fillchar = 1 })) end) it('rejects invalid string', function() 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')) diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 46bfae8de2..76baf2cddb 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -751,8 +751,8 @@ describe('Buffer highlighting', function() it('validates contents', function() -- this used to leak memory - eq('Chunk is not an array', pcall_err(set_virtual_text, id1, 0, {"texty"}, {})) - eq('Chunk is not an array', pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {})) + eq('Invalid chunk: expected Array, got String', pcall_err(set_virtual_text, id1, 0, {"texty"}, {})) + eq('Invalid chunk: expected Array, got String', pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {})) end) it('can be retrieved', function() -- cgit From 3a6a7add57d2ac141f474b54659bbbf596b76059 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 14 Feb 2023 18:26:22 +0800 Subject: test: remove unused field ext_float (#22243) --- test/functional/ui/screen.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 3b9cce0e6f..a059fb5b89 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -214,7 +214,7 @@ function Screen:attach(options, session) -- simplify test code by doing the same. self._options.rgb = true end - if self._options.ext_multigrid or self._options.ext_float then + if self._options.ext_multigrid then self._options.ext_linegrid = true end end -- 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/api/autocmd_spec.lua | 104 ++++++++++++++++++++++----------- test/functional/api/buffer_spec.lua | 20 +++---- test/functional/api/extmark_spec.lua | 6 +- test/functional/api/highlight_spec.lua | 67 +++++++++------------ test/functional/api/proc_spec.lua | 4 +- test/functional/api/ui_spec.lua | 26 ++++++++- test/functional/api/vim_spec.lua | 10 ++-- test/functional/lua/api_spec.lua | 2 +- 8 files changed, 142 insertions(+), 97 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index 56b0a4d9b2..f10f18174e 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -14,14 +14,31 @@ before_each(clear) describe('autocmd api', function() describe('nvim_create_autocmd', function() - it('"command" and "callback" are mutually exclusive', function() - local rv = pcall_err(meths.create_autocmd, "BufReadPost", { - pattern = "*.py,*.pyi", + it('validation', function() + eq("Cannot use both 'callback' and 'command'", pcall_err(meths.create_autocmd, 'BufReadPost', { + pattern = '*.py,*.pyi', command = "echo 'Should Have Errored", - callback = "NotAllowed", - }) - - eq("Cannot use both 'callback' and 'command'", rv) + callback = 'NotAllowed', + })) + eq("Cannot use both 'pattern' and 'buffer' for the same autocmd", pcall_err(meths.create_autocmd, 'FileType', { + command = 'let g:called = g:called + 1', + buffer = 0, + pattern = '*.py', + })) + eq("Required: 'event'", pcall_err(meths.create_autocmd, {}, { + command = 'ls', + })) + eq("Required: 'command' or 'callback'", pcall_err(meths.create_autocmd, 'FileType', { + })) + eq('Invalid desc: expected String, got Integer', pcall_err(meths.create_autocmd, 'FileType', { + command = 'ls', + desc = 42, + })) + eq('Invalid callback: expected Lua function or Vim function name, got Integer', pcall_err(meths.create_autocmd, 'FileType', { + callback = 0, + })) + eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.create_autocmd, + {'FileType', {}}, {})) end) it('doesnt leak when you use ++once', function() @@ -59,18 +76,8 @@ describe('autocmd api', function() eq(1, meths.get_var('called')) end) - it('does not allow passing buffer and patterns', function() - local rv = pcall_err(meths.create_autocmd, "Filetype", { - command = "let g:called = g:called + 1", - buffer = 0, - pattern = "*.py", - }) - - eq("Cannot use both 'pattern' and 'buffer' for the same autocmd", rv) - end) - it('does not allow passing invalid buffers', function() - local ok, msg = pcall(meths.create_autocmd, "Filetype", { + local ok, msg = pcall(meths.create_autocmd, 'FileType', { command = "let g:called = g:called + 1", buffer = -1, }) @@ -295,7 +302,7 @@ describe('autocmd api', function() describe('nvim_get_autocmds', function() describe('events', function() - it('should return one autocmd when there is only one for an event', function() + it('returns one autocmd when there is only one for an event', function() command [[au! InsertEnter]] command [[au InsertEnter * :echo "1"]] @@ -303,7 +310,7 @@ describe('autocmd api', function() eq(1, #aus) end) - it('should return two autocmds when there are two for an event', function() + it('returns two autocmds when there are two for an event', function() command [[au! InsertEnter]] command [[au InsertEnter * :echo "1"]] command [[au InsertEnter * :echo "2"]] @@ -312,7 +319,7 @@ describe('autocmd api', function() eq(2, #aus) end) - it('should return the same thing if you use string or list', function() + it('returns the same thing if you use string or list', function() command [[au! InsertEnter]] command [[au InsertEnter * :echo "1"]] command [[au InsertEnter * :echo "2"]] @@ -322,7 +329,7 @@ describe('autocmd api', function() eq(string_aus, array_aus) end) - it('should return two autocmds when there are two for an event', function() + it('returns two autocmds when there are two for an event', function() command [[au! InsertEnter]] command [[au! InsertLeave]] command [[au InsertEnter * :echo "1"]] @@ -332,7 +339,7 @@ describe('autocmd api', function() eq(2, #aus) end) - it('should return different IDs for different autocmds', function() + it('returns different IDs for different autocmds', function() command [[au! InsertEnter]] command [[au! InsertLeave]] command [[au InsertEnter * :echo "1"]] @@ -356,7 +363,7 @@ describe('autocmd api', function() eq(first, new_aus[1]) end) - it('should return event name', function() + it('returns event name', function() command [[au! InsertEnter]] command [[au InsertEnter * :echo "1"]] @@ -364,7 +371,7 @@ describe('autocmd api', function() eq({ { buflocal = false, command = ':echo "1"', event = "InsertEnter", once = false, pattern = "*" } }, aus) end) - it('should work with buffer numbers', function() + it('works with buffer numbers', function() command [[new]] command [[au! InsertEnter]] command [[au InsertEnter :echo "1"]] @@ -419,7 +426,7 @@ describe('autocmd api', function() eq("Too many buffers (maximum of 256)", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = bufs })) end) - it('should return autocmds when group is specified by id', function() + it('returns autocmds when group is specified by id', function() local auid = meths.create_augroup("nvim_test_augroup", { clear = true }) meths.create_autocmd("FileType", { group = auid, command = 'echo "1"' }) meths.create_autocmd("FileType", { group = auid, command = 'echo "2"' }) @@ -431,7 +438,7 @@ describe('autocmd api', function() eq(0, #aus2) end) - it('should return autocmds when group is specified by name', function() + it('returns autocmds when group is specified by name', function() local auname = "nvim_test_augroup" meths.create_augroup(auname, { clear = true }) meths.create_autocmd("FileType", { group = auname, command = 'echo "1"' }) @@ -531,7 +538,7 @@ describe('autocmd api', function() command [[augroup END]] end) - it('should return all groups if no group is specified', function() + it('returns all groups if no group is specified', function() local aus = meths.get_autocmds { event = "InsertEnter" } if #aus ~= 4 then eq({}, aus) @@ -540,7 +547,7 @@ describe('autocmd api', function() eq(4, #aus) end) - it('should return only the group specified', function() + it('returns only the group specified', function() local aus = meths.get_autocmds { event = "InsertEnter", group = "GroupOne", @@ -551,7 +558,7 @@ describe('autocmd api', function() eq("GroupOne", aus[1].group_name) end) - it('should return only the group specified, multiple values', function() + it('returns only the group specified, multiple values', function() local aus = meths.get_autocmds { event = "InsertEnter", group = "GroupTwo", @@ -625,7 +632,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches("Invalid 'pattern' item type: expected String, got Array", code) + matches("Invalid 'pattern' item: expected String, got Array", code) end) end) @@ -640,7 +647,7 @@ describe('autocmd api', function() command [[au InsertEnter :echo "Buffer"]] end) - it('should should return for literal match', function() + it('returns for literal match', function() local aus = meths.get_autocmds { event = "InsertEnter", pattern = "*" @@ -650,7 +657,7 @@ describe('autocmd api', function() eq([[:echo "No Group"]], aus[1].command) end) - it('should return for multiple matches', function() + it('returns for multiple matches', function() -- vim.api.nvim_get_autocmds local aus = meths.get_autocmds { event = "InsertEnter", @@ -687,6 +694,23 @@ describe('autocmd api', function() end) describe('nvim_exec_autocmds', function() + it('validation', function() + eq('Invalid group: 9997999', pcall_err(meths.exec_autocmds, 'FileType', { + group = 9997999, + })) + eq("Invalid group: 'bogus'", pcall_err(meths.exec_autocmds, 'FileType', { + group = 'bogus', + })) + eq('Invalid group: expected String or Integer, got Array', pcall_err(meths.exec_autocmds, 'FileType', { + group = {}, + })) + eq('Invalid buffer: expected Integer, got Array', pcall_err(meths.exec_autocmds, 'FileType', { + buffer = {}, + })) + eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.exec_autocmds, + {'FileType', {}}, {})) + end) + it("can trigger builtin autocmds", function() meths.set_var("autocmd_executed", false) @@ -1036,7 +1060,7 @@ describe('autocmd api', function() local augroup = "WillBeDeleted" meths.create_augroup(augroup, { clear = true }) - meths.create_autocmd({"Filetype"}, { + meths.create_autocmd({"FileType"}, { pattern = "*", command = "echo 'does not matter'", }) @@ -1055,7 +1079,7 @@ describe('autocmd api', function() meths.set_var("value_set", false) meths.create_augroup(augroup, { clear = true }) - meths.create_autocmd("Filetype", { + meths.create_autocmd("FileType", { pattern = "", command = "let g:value_set = v:true", }) @@ -1171,6 +1195,16 @@ describe('autocmd api', function() end) describe('nvim_clear_autocmds', function() + it('validation', function() + eq("Cannot use both 'pattern' and 'buffer'", pcall_err(meths.clear_autocmds, { + pattern = '*', + buffer = 42, + })) + eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.clear_autocmds, { + event = {'FileType', {}} + })) + end) + it('should clear based on event + pattern', function() command('autocmd InsertEnter *.py :echo "Python can be cool sometimes"') command('autocmd InsertEnter *.txt :echo "Text Files Are Cool"') diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 6b13729994..d454765edb 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -193,7 +193,7 @@ describe('api/buf', function() it('fails correctly when input is not valid', function() eq(1, api.curbufmeths.get_number()) - eq([[String cannot contain newlines]], + eq([['replacement string' item contains newlines]], pcall_err(bufmeths.set_lines, 1, 1, 2, false, {'b\na'})) end) @@ -553,20 +553,20 @@ describe('api/buf', function() insert([[ hello foo! text]]) - eq('start_row out of bounds', pcall_err(set_text, 2, 0, 3, 0, {})) - eq('start_row out of bounds', pcall_err(set_text, -3, 0, 0, 0, {})) - eq('end_row out of bounds', pcall_err(set_text, 0, 0, 2, 0, {})) - eq('end_row out of bounds', pcall_err(set_text, 0, 0, -3, 0, {})) - eq('start_col out of bounds', pcall_err(set_text, 1, 5, 1, 5, {})) - eq('end_col out of bounds', pcall_err(set_text, 1, 0, 1, 5, {})) + eq("Invalid 'start_row': out of range", pcall_err(set_text, 2, 0, 3, 0, {})) + eq("Invalid 'start_row': out of range", pcall_err(set_text, -3, 0, 0, 0, {})) + eq("Invalid 'end_row': out of range", pcall_err(set_text, 0, 0, 2, 0, {})) + eq("Invalid 'end_row': out of range", pcall_err(set_text, 0, 0, -3, 0, {})) + eq("Invalid 'start_col': out of range", pcall_err(set_text, 1, 5, 1, 5, {})) + eq("Invalid 'end_col': out of range", pcall_err(set_text, 1, 0, 1, 5, {})) end) it('errors when start is greater than end', function() insert([[ hello foo! text]]) - eq('start is higher than end', pcall_err(set_text, 1, 0, 0, 0, {})) - eq('start is higher than end', pcall_err(set_text, 0, 1, 0, 0, {})) + eq("'start' is higher than 'end'", pcall_err(set_text, 1, 0, 0, 0, {})) + eq("'start' is higher than 'end'", pcall_err(set_text, 0, 1, 0, 0, {})) end) it('no heap-use-after-free when called consecutively #19643', function() @@ -611,7 +611,7 @@ describe('api/buf', function() end) it('errors when start is greater than end', function() - eq('start is higher than end', pcall_err(get_text, 1, 0, 0, 0, {})) + eq("'start' is higher than 'end'", pcall_err(get_text, 1, 0, 0, 0, {})) eq('start_col must be less than end_col', pcall_err(get_text, 0, 1, 0, 0, {})) end) end) diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index fc68f11a67..fab1557204 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -106,7 +106,7 @@ describe('API/extmarks', function() end_col = 0, end_row = 1 }) - eq("Invalid end_col: '(out of range)'", + eq("Invalid 'end_col': out of range", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = 1 })) end) @@ -1362,13 +1362,13 @@ describe('API/extmarks', function() it('when col = line-length, set the mark on eol', function() local invalid_col = init_text:len() + 1 - eq("Invalid col: '(out of range)'", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) + eq("Invalid 'col': out of range", pcall_err(set_extmark, ns, marks[1], 0, invalid_col)) end) it('fails when line > line_count', function() local invalid_col = init_text:len() + 1 local invalid_lnum = 3 - eq("Invalid line: '(out of range)'", pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) + eq("Invalid 'line': out of range", pcall_err(set_extmark, ns, marks[1], invalid_lnum, invalid_col)) eq({}, get_extmark_by_id(ns, marks[1])) end) diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 7f044977cb..73551de42e 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -57,9 +57,7 @@ describe('API: highlight',function() eq(expected_rgb, nvim("get_hl_by_id", hl_id, true)) -- Test invalid id. - local err, emsg = pcall(meths.get_hl_by_id, 30000, false) - eq(false, err) - eq('Invalid highlight id: 30000', string.match(emsg, 'Invalid.*')) + eq('Invalid highlight id: 30000', pcall_err(meths.get_hl_by_id, 30000, false)) -- Test all highlight properties. command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine') @@ -70,22 +68,14 @@ describe('API: highlight',function() eq(expected_undercurl, nvim("get_hl_by_id", hl_id, true)) -- Test nil argument. - err, emsg = pcall(meths.get_hl_by_id, { nil }, false) - eq(false, err) eq('Wrong type for argument 1 when calling nvim_get_hl_by_id, expecting Integer', - string.match(emsg, 'Wrong.*')) + pcall_err(meths.get_hl_by_id, { nil }, false)) -- Test 0 argument. - err, emsg = pcall(meths.get_hl_by_id, 0, false) - eq(false, err) - eq('Invalid highlight id: 0', - string.match(emsg, 'Invalid.*')) + eq('Invalid highlight id: 0', pcall_err(meths.get_hl_by_id, 0, false)) -- Test -1 argument. - err, emsg = pcall(meths.get_hl_by_id, -1, false) - eq(false, err) - eq('Invalid highlight id: -1', - string.match(emsg, 'Invalid.*')) + eq('Invalid highlight id: -1', pcall_err(meths.get_hl_by_id, -1, false)) -- Test highlight group without ctermbg value. command('hi Normal ctermfg=red ctermbg=yellow') @@ -119,22 +109,16 @@ describe('API: highlight',function() eq(expected_normal, nvim("get_hl_by_name", 'Normal', true)) -- Test invalid name. - local err, emsg = pcall(meths.get_hl_by_name , 'unknown_highlight', false) - eq(false, err) - eq('Invalid highlight name: unknown_highlight', - string.match(emsg, 'Invalid.*')) + eq("Invalid highlight name: 'unknown_highlight'", + pcall_err(meths.get_hl_by_name , 'unknown_highlight', false)) -- Test nil argument. - err, emsg = pcall(meths.get_hl_by_name , { nil }, false) - eq(false, err) eq('Wrong type for argument 1 when calling nvim_get_hl_by_name, expecting String', - string.match(emsg, 'Wrong.*')) + pcall_err(meths.get_hl_by_name , { nil }, false)) -- Test empty string argument. - err, emsg = pcall(meths.get_hl_by_name , '', false) - eq(false, err) - eq('Invalid highlight name: ', - string.match(emsg, 'Invalid.*')) + eq('Invalid highlight name', + pcall_err(meths.get_hl_by_name , '', false)) -- Test "standout" attribute. #8054 eq({ underline = true, }, @@ -155,7 +139,7 @@ describe('API: highlight',function() it('nvim_get_hl_id_by_name', function() -- precondition: use a hl group that does not yet exist - eq('Invalid highlight name: Shrubbery', pcall_err(meths.get_hl_by_name, "Shrubbery", true)) + eq("Invalid highlight name: 'Shrubbery'", pcall_err(meths.get_hl_by_name, "Shrubbery", true)) eq(0, funcs.hlID("Shrubbery")) local hl_id = meths.get_hl_id_by_name("Shrubbery") @@ -253,25 +237,32 @@ describe("API: set highlight", function() before_each(clear) - it ("can set gui highlight", function() + it('validation', function() + eq("Invalid 'blend': out of range", + pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend=999})) + eq("Invalid blend: expected Integer, got Array", + pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend={}})) + end) + + it("can set gui highlight", function() local ns = get_ns() meths.set_hl(ns, 'Test_hl', highlight1) eq(highlight1, meths.get_hl_by_name('Test_hl', true)) end) - it ("can set cterm highlight", function() + it("can set cterm highlight", function() local ns = get_ns() meths.set_hl(ns, 'Test_hl', highlight2_config) eq(highlight2_result, meths.get_hl_by_name('Test_hl', false)) end) - it ("can set empty cterm attr", function() + it("can set empty cterm attr", function() local ns = get_ns() meths.set_hl(ns, 'Test_hl', { cterm = {} }) eq({}, meths.get_hl_by_name('Test_hl', false)) end) - it ("cterm attr defaults to gui attr", function() + it("cterm attr defaults to gui attr", function() local ns = get_ns() meths.set_hl(ns, 'Test_hl', highlight1) eq({ @@ -280,14 +271,14 @@ describe("API: set highlight", function() }, meths.get_hl_by_name('Test_hl', false)) end) - it ("can overwrite attr for cterm", function() + it("can overwrite attr for cterm", function() local ns = get_ns() meths.set_hl(ns, 'Test_hl', highlight3_config) eq(highlight3_result_gui, meths.get_hl_by_name('Test_hl', true)) eq(highlight3_result_cterm, meths.get_hl_by_name('Test_hl', false)) end) - it ("can set a highlight in the global namespace", function() + it("can set a highlight in the global namespace", function() meths.set_hl(0, 'Test_hl', highlight2_config) eq('Test_hl xxx cterm=underline,reverse ctermfg=8 ctermbg=15 gui=underline,reverse', exec_capture('highlight Test_hl')) @@ -307,7 +298,7 @@ describe("API: set highlight", function() exec_capture('highlight Test_hl3')) end) - it ("can modify a highlight in the global namespace", function() + it("can modify a highlight in the global namespace", function() meths.set_hl(0, 'Test_hl3', { bg = 'red', fg = 'blue'}) eq('Test_hl3 xxx guifg=Blue guibg=Red', exec_capture('highlight Test_hl3')) @@ -328,17 +319,17 @@ describe("API: set highlight", function() eq('Test_hl3 xxx ctermbg=9', exec_capture('highlight Test_hl3')) - eq("'redd' is not a valid color", + eq("Invalid highlight color: 'redd'", pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='redd'})) - eq("'bleu' is not a valid color", + eq("Invalid highlight color: 'bleu'", pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='bleu'})) meths.set_hl(0, 'Test_hl3', {fg='#FF00FF'}) eq('Test_hl3 xxx guifg=#ff00ff', exec_capture('highlight Test_hl3')) - eq("'#FF00FF' is not a valid color", + eq("Invalid highlight color: '#FF00FF'", pcall_err(meths.set_hl, 0, 'Test_hl3', {ctermfg='#FF00FF'})) for _, fg_val in ipairs{ nil, 'NONE', 'nOnE', '', -1 } do @@ -353,14 +344,14 @@ describe("API: set highlight", function() end) - it ("correctly sets 'Normal' internal properties", function() + it("correctly sets 'Normal' internal properties", function() -- Normal has some special handling internally. #18024 meths.set_hl(0, 'Normal', {fg='#000083', bg='#0000F3'}) eq({foreground = 131, background = 243}, nvim("get_hl_by_name", 'Normal', true)) end) it('does not segfault on invalid group name #20009', function() - eq('Invalid highlight name: foo bar', pcall_err(meths.set_hl, 0, 'foo bar', {bold = true})) + eq("Invalid highlight name: 'foo bar'", pcall_err(meths.set_hl, 0, 'foo bar', {bold = true})) assert_alive() end) end) diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua index 2028a8fba5..315653af14 100644 --- a/test/functional/api/proc_spec.lua +++ b/test/functional/api/proc_spec.lua @@ -42,7 +42,7 @@ describe('API', function() end) end) - it('validates input', function() + it('validation', function() local status, rv = pcall(request, "nvim_get_proc_children", -1) eq(false, status) eq("Invalid pid: -1", string.match(rv, "Invalid.*")) @@ -68,7 +68,7 @@ describe('API', function() neq(pid, pinfo.ppid) end) - it('validates input', function() + it('validation', function() local status, rv = pcall(request, "nvim_get_proc", -1) eq(false, status) eq("Invalid pid: -1", string.match(rv, "Invalid.*")) diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua index 279cd1856d..5654ef31ef 100644 --- a/test/functional/api/ui_spec.lua +++ b/test/functional/api/ui_spec.lua @@ -11,17 +11,37 @@ describe('nvim_ui_attach()', function() before_each(function() clear() end) + it('handles very large width/height #2180', function() local screen = Screen.new(999, 999) screen:attach() eq(999, eval('&lines')) eq(999, eval('&columns')) end) - it('invalid option returns error', function() + + it('validation', function() eq('No such UI option: foo', pcall_err(meths.ui_attach, 80, 24, { foo={'foo'} })) - end) - it('validates channel arg', function() + + eq('Invalid ext_linegrid: expected Boolean, got Array', + pcall_err(meths.ui_attach, 80, 24, { ext_linegrid={} })) + eq('Invalid override: expected Boolean, got Array', + pcall_err(meths.ui_attach, 80, 24, { override={} })) + eq('Invalid rgb: expected Boolean, got Array', + pcall_err(meths.ui_attach, 80, 24, { rgb={} })) + eq('Invalid term_name: expected String, got Boolean', + pcall_err(meths.ui_attach, 80, 24, { term_name=true })) + eq('Invalid term_colors: expected Integer, got Boolean', + pcall_err(meths.ui_attach, 80, 24, { term_colors=true })) + eq('Invalid term_background: expected String, got Boolean', + pcall_err(meths.ui_attach, 80, 24, { term_background=true })) + eq('Invalid stdin_fd: expected Integer, got String', + pcall_err(meths.ui_attach, 80, 24, { stdin_fd='foo' })) + eq('Invalid stdin_tty: expected Boolean, got String', + pcall_err(meths.ui_attach, 80, 24, { stdin_tty='foo' })) + eq('Invalid stdout_tty: expected Boolean, got String', + pcall_err(meths.ui_attach, 80, 24, { stdout_tty='foo' })) + eq('UI not attached to channel: 1', pcall_err(request, 'nvim_ui_try_resize', 40, 10)) eq('UI not attached to channel: 1', diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 5c56c90952..469d8e8b6a 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1411,9 +1411,9 @@ describe('API', function() end) it('validation', function() - eq("Invalid scope (expected 'local' or 'global')", + eq("Invalid scope: expected 'local' or 'global'", pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 'bogus'})) - eq("Invalid scope (expected 'local' or 'global')", + eq("Invalid scope: expected 'local' or 'global'", pcall_err(nvim, 'set_option_value', 'scrolloff', 1, {scope = 'bogus'})) eq("Invalid scope: expected String, got Integer", pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 42})) @@ -2238,7 +2238,7 @@ describe('API', function() {'nvim_set_var'}, {'nvim_set_var', {'avar', 2}}, } - eq('Items in calls array must be arrays of size 2', + eq('calls item must be a 2-item Array', pcall_err(meths.call_atomic, req)) -- call before was done, but not after eq(1, meths.get_var('avar')) @@ -3119,11 +3119,11 @@ describe('API', function() meths.eval_statusline('a%=b', { fillchar = '\031', maxwidth = 5 })) end) it('rejects multiple-character fillchar', function() - eq('Invalid fillchar (not a single character)', + eq('Invalid fillchar: expected single character', pcall_err(meths.eval_statusline, '', { fillchar = 'aa' })) end) it('rejects empty string fillchar', function() - eq('Invalid fillchar (not a single character)', + eq('Invalid fillchar: expected single character', pcall_err(meths.eval_statusline, '', { fillchar = '' })) end) it('rejects non-string fillchar', function() 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 39f8aaeb815c2e31cffec12ef36ad4f25df91602 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 24 Jan 2020 09:48:58 +0100 Subject: fix(status): handle unprintable chars in the statusline --- test/functional/ui/multibyte_spec.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua index d4e237bcb4..9f413f8bff 100644 --- a/test/functional/ui/multibyte_spec.lua +++ b/test/functional/ui/multibyte_spec.lua @@ -158,6 +158,7 @@ describe('multibyte rendering: statusline', function() screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, [2] = {bold = true, reverse = true}, + [3] = {background = Screen.colors.Red, foreground = Screen.colors.Gray100}; }) screen:attach() command('set laststatus=2') @@ -220,4 +221,27 @@ describe('multibyte rendering: statusline', function() | ]]} end) + + it('unprintable chars in filename with default stl', function() + command("file 🧑‍💻") + -- TODO: this is wrong but avoids a crash + screen:expect{grid=[[ + ^ | + {1:~ }| + {2:🧑�💻 }| + | + ]]} + end) + + it('unprintable chars in filename with custom stl', function() + command('set statusline=xx%#ErrorMsg#%f%##yy') + command("file 🧑‍💻") + -- TODO: this is also wrong but also avoids a crash + screen:expect{grid=[[ + ^ | + {1:~ }| + {2:xx}{3:🧑<200d>💻}{2:yy }| + | + ]]} + end) end) -- cgit From 556f8646c01d1751cf39fe4df9c622899dceab9d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 14 Feb 2023 14:19:28 -0500 Subject: refactor(api): consistent VALIDATE messages #22262 Problem: Validation messages are not consistently formatted. - Parameter names sometimes are NOT quoted. - Descriptive names (non-parameters) sometimes ARE quoted. Solution: Always quote the `name` value passed to a VALIDATE macro _unless_ the value has whitespace. --- test/functional/api/autocmd_spec.lua | 43 +++++++++++++++++------- test/functional/api/buffer_updates_spec.lua | 2 +- test/functional/api/command_spec.lua | 14 +++----- test/functional/api/extmark_spec.lua | 16 ++++++--- test/functional/api/highlight_spec.lua | 2 +- test/functional/api/proc_spec.lua | 8 ++--- test/functional/api/ui_spec.lua | 18 +++++----- test/functional/api/vim_spec.lua | 51 ++++++++++++++++------------- test/functional/ui/bufhl_spec.lua | 4 +-- 9 files changed, 95 insertions(+), 63 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua index f10f18174e..d1a93b5a86 100644 --- a/test/functional/api/autocmd_spec.lua +++ b/test/functional/api/autocmd_spec.lua @@ -30,11 +30,11 @@ describe('autocmd api', function() })) eq("Required: 'command' or 'callback'", pcall_err(meths.create_autocmd, 'FileType', { })) - eq('Invalid desc: expected String, got Integer', pcall_err(meths.create_autocmd, 'FileType', { + eq("Invalid 'desc': expected String, got Integer", pcall_err(meths.create_autocmd, 'FileType', { command = 'ls', desc = 42, })) - eq('Invalid callback: expected Lua function or Vim function name, got Integer', pcall_err(meths.create_autocmd, 'FileType', { + eq("Invalid 'callback': expected Lua function or Vim function name, got Integer", pcall_err(meths.create_autocmd, 'FileType', { callback = 0, })) eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.create_autocmd, @@ -301,6 +301,27 @@ describe('autocmd api', function() end) describe('nvim_get_autocmds', function() + it('validation', function() + eq("Invalid 'group': 9997999", pcall_err(meths.get_autocmds, { + group = 9997999, + })) + eq("Invalid 'group': 'bogus'", pcall_err(meths.get_autocmds, { + group = 'bogus', + })) + eq("Invalid 'group': expected String or Integer, got Array", pcall_err(meths.get_autocmds, { + group = {}, + })) + eq("Invalid 'buffer': expected Integer or Array, got Boolean", pcall_err(meths.get_autocmds, { + buffer = true, + })) + eq("Invalid 'event': expected String or Array", pcall_err(meths.get_autocmds, { + event = true, + })) + eq("Invalid 'pattern': expected String or Array, got Boolean", pcall_err(meths.get_autocmds, { + pattern = true, + })) + end) + describe('events', function() it('returns one autocmd when there is only one for an event', function() command [[au! InsertEnter]] @@ -414,8 +435,8 @@ describe('autocmd api', function() pattern = "", }}, aus) - eq("Invalid buffer: expected Integer or Array, got String", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" })) - eq("Invalid buffer: expected Integer, got String", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } })) + eq("Invalid 'buffer': expected Integer or Array, got String", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = "foo" })) + eq("Invalid 'buffer': expected Integer, got String", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { "foo", 42 } })) eq("Invalid buffer id: 42", pcall_err(meths.get_autocmds, { event = "InsertEnter", buffer = { 42 } })) local bufs = {} @@ -585,7 +606,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches("Invalid group: 'NotDefined'", code) + matches("Invalid 'group': 'NotDefined'", code) end) it('raises error for undefined augroup id', function() @@ -603,7 +624,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches('Invalid group: 1', code) + matches("Invalid 'group': 1", code) end) it('raises error for invalid group type', function() @@ -618,7 +639,7 @@ describe('autocmd api', function() ]], {})) eq(false, success) - matches("Invalid group: expected String or Integer, got Boolean", code) + matches("Invalid 'group': expected String or Integer, got Boolean", code) end) it('raises error for invalid pattern array', function() @@ -695,16 +716,16 @@ describe('autocmd api', function() describe('nvim_exec_autocmds', function() it('validation', function() - eq('Invalid group: 9997999', pcall_err(meths.exec_autocmds, 'FileType', { + eq("Invalid 'group': 9997999", pcall_err(meths.exec_autocmds, 'FileType', { group = 9997999, })) - eq("Invalid group: 'bogus'", pcall_err(meths.exec_autocmds, 'FileType', { + eq("Invalid 'group': 'bogus'", pcall_err(meths.exec_autocmds, 'FileType', { group = 'bogus', })) - eq('Invalid group: expected String or Integer, got Array', pcall_err(meths.exec_autocmds, 'FileType', { + eq("Invalid 'group': expected String or Integer, got Array", pcall_err(meths.exec_autocmds, 'FileType', { group = {}, })) - eq('Invalid buffer: expected Integer, got Array', pcall_err(meths.exec_autocmds, 'FileType', { + eq("Invalid 'buffer': expected Integer, got Array", pcall_err(meths.exec_autocmds, 'FileType', { buffer = {}, })) eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.exec_autocmds, diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua index 1510d31945..25b838a4af 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -762,7 +762,7 @@ describe('API: buffer events:', function() it('returns a proper error on nonempty options dict', function() clear() local b = editoriginal(false) - eq("Invalid key: 'builtin'", pcall_err(buffer, 'attach', b, false, {builtin="asfd"})) + eq("Invalid 'opts' key: 'builtin'", pcall_err(buffer, 'attach', b, false, {builtin="asfd"})) end) it('nvim_buf_attach returns response after delay #8634', function() diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index 189f9d4f98..9db687cc37 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -543,23 +543,19 @@ describe('nvim_create_user_command', function() end) it('does not allow invalid command names', function() - matches("Invalid command name %(must begin with an uppercase letter%): 'test'", pcall_err(exec_lua, [[ + eq("Invalid command name (must start with uppercase): 'test'", pcall_err(exec_lua, [[ vim.api.nvim_create_user_command('test', 'echo "hi"', {}) ]])) - - matches('Invalid command name', pcall_err(exec_lua, [[ + eq("Invalid command name: 't@'", pcall_err(exec_lua, [[ vim.api.nvim_create_user_command('t@', 'echo "hi"', {}) ]])) - - matches('Invalid command name', pcall_err(exec_lua, [[ + eq("Invalid command name: 'T@st'", pcall_err(exec_lua, [[ vim.api.nvim_create_user_command('T@st', 'echo "hi"', {}) ]])) - - matches('Invalid command name', pcall_err(exec_lua, [[ + eq("Invalid command name: 'Test!'", pcall_err(exec_lua, [[ vim.api.nvim_create_user_command('Test!', 'echo "hi"', {}) ]])) - - matches('Invalid command name', pcall_err(exec_lua, [[ + eq("Invalid command name: '💩'", pcall_err(exec_lua, [[ vim.api.nvim_create_user_command('💩', 'echo "hi"', {}) ]])) end) diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index fab1557204..3f9cb94260 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -101,6 +101,14 @@ describe('API/extmarks', function() ns2 = request('nvim_create_namespace', "my-fancy-plugin2") end) + it('validation', function() + eq("Invalid 'end_col': expected Integer, got Array", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = {}, end_row = 1 })) + eq("Invalid 'end_row': expected Integer, got Array", pcall_err(set_extmark, ns, marks[2], 0, 0, { end_col = 1, end_row = {} })) + eq("Invalid 'id': expected positive Integer", pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 })) + eq("Invalid mark position: expected 2 Integer items", pcall_err(get_extmarks, ns, {}, {-1, -1})) + eq("Invalid mark position: expected mark id Integer or 2-item Array", pcall_err(get_extmarks, ns, true, {-1, -1})) + end) + it("can end extranges past final newline using end_col = 0", function() set_extmark(ns, marks[1], 0, 0, { end_col = 0, @@ -1344,10 +1352,10 @@ describe('API/extmarks', function() it('throws consistent error codes', function() local ns_invalid = ns2 + 1 - eq("Invalid ns_id: 3", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) - eq("Invalid ns_id: 3", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) - eq("Invalid ns_id: 3", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) - eq("Invalid ns_id: 3", pcall_err(get_extmark_by_id, ns_invalid, marks[1])) + eq("Invalid 'ns_id': 3", pcall_err(set_extmark, ns_invalid, marks[1], positions[1][1], positions[1][2])) + eq("Invalid 'ns_id': 3", pcall_err(curbufmeths.del_extmark, ns_invalid, marks[1])) + eq("Invalid 'ns_id': 3", pcall_err(get_extmarks, ns_invalid, positions[1], positions[2])) + eq("Invalid 'ns_id': 3", pcall_err(get_extmark_by_id, ns_invalid, marks[1])) end) it('when col = line-length, set the mark on eol', function() diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 73551de42e..e1b3562329 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -240,7 +240,7 @@ describe("API: set highlight", function() it('validation', function() eq("Invalid 'blend': out of range", pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend=999})) - eq("Invalid blend: expected Integer, got Array", + eq("Invalid 'blend': expected Integer, got Array", pcall_err(meths.set_hl, 0, 'Test_hl3', {fg='#FF00FF', blend={}})) end) diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua index 315653af14..20edea3feb 100644 --- a/test/functional/api/proc_spec.lua +++ b/test/functional/api/proc_spec.lua @@ -45,11 +45,11 @@ describe('API', function() it('validation', function() local status, rv = pcall(request, "nvim_get_proc_children", -1) eq(false, status) - eq("Invalid pid: -1", string.match(rv, "Invalid.*")) + eq("Invalid 'pid': -1", string.match(rv, "Invalid.*")) status, rv = pcall(request, "nvim_get_proc_children", 0) eq(false, status) - eq("Invalid pid: 0", string.match(rv, "Invalid.*")) + eq("Invalid 'pid': 0", string.match(rv, "Invalid.*")) -- Assume PID 99999 does not exist. status, rv = pcall(request, "nvim_get_proc_children", 99999) @@ -71,11 +71,11 @@ describe('API', function() it('validation', function() local status, rv = pcall(request, "nvim_get_proc", -1) eq(false, status) - eq("Invalid pid: -1", string.match(rv, "Invalid.*")) + eq("Invalid 'pid': -1", string.match(rv, "Invalid.*")) status, rv = pcall(request, "nvim_get_proc", 0) eq(false, status) - eq("Invalid pid: 0", string.match(rv, "Invalid.*")) + eq("Invalid 'pid': 0", string.match(rv, "Invalid.*")) -- Assume PID 99999 does not exist. status, rv = pcall(request, "nvim_get_proc", 99999) diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua index 5654ef31ef..b616f51d10 100644 --- a/test/functional/api/ui_spec.lua +++ b/test/functional/api/ui_spec.lua @@ -23,23 +23,23 @@ describe('nvim_ui_attach()', function() eq('No such UI option: foo', pcall_err(meths.ui_attach, 80, 24, { foo={'foo'} })) - eq('Invalid ext_linegrid: expected Boolean, got Array', + eq("Invalid 'ext_linegrid': expected Boolean, got Array", pcall_err(meths.ui_attach, 80, 24, { ext_linegrid={} })) - eq('Invalid override: expected Boolean, got Array', + eq("Invalid 'override': expected Boolean, got Array", pcall_err(meths.ui_attach, 80, 24, { override={} })) - eq('Invalid rgb: expected Boolean, got Array', + eq("Invalid 'rgb': expected Boolean, got Array", pcall_err(meths.ui_attach, 80, 24, { rgb={} })) - eq('Invalid term_name: expected String, got Boolean', + eq("Invalid 'term_name': expected String, got Boolean", pcall_err(meths.ui_attach, 80, 24, { term_name=true })) - eq('Invalid term_colors: expected Integer, got Boolean', + eq("Invalid 'term_colors': expected Integer, got Boolean", pcall_err(meths.ui_attach, 80, 24, { term_colors=true })) - eq('Invalid term_background: expected String, got Boolean', + eq("Invalid 'term_background': expected String, got Boolean", pcall_err(meths.ui_attach, 80, 24, { term_background=true })) - eq('Invalid stdin_fd: expected Integer, got String', + eq("Invalid 'stdin_fd': expected Integer, got String", pcall_err(meths.ui_attach, 80, 24, { stdin_fd='foo' })) - eq('Invalid stdin_tty: expected Boolean, got String', + eq("Invalid 'stdin_tty': expected Boolean, got String", pcall_err(meths.ui_attach, 80, 24, { stdin_tty='foo' })) - eq('Invalid stdout_tty: expected Boolean, got String', + eq("Invalid 'stdout_tty': expected Boolean, got String", pcall_err(meths.ui_attach, 80, 24, { stdout_tty='foo' })) eq('UI not attached to channel: 1', diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 469d8e8b6a..981fc19b36 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -490,7 +490,7 @@ describe('API', function() eq('', eval('v:errmsg')) -- v:errmsg was not updated. end) - it('validates args', function() + it('validation', function() local too_many_args = { 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x' } source([[ function! Foo(...) abort @@ -532,7 +532,7 @@ describe('API', function() eq('@it works@', nvim('call_dict_function', { result = 'it works', G = 'G'}, 'G', {})) end) - it('validates args', function() + it('validation', function() command('let g:d={"baz":"zub","meep":[]}') eq('Not found: bogus', pcall_err(request, 'nvim_call_dict_function', 'g:d', 'bogus', {1,2})) @@ -648,10 +648,10 @@ describe('API', function() end) describe('nvim_paste', function() - it('validates args', function() - eq('Invalid phase: -2', + it('validation', function() + eq("Invalid 'phase': -2", pcall_err(request, 'nvim_paste', 'foo', true, -2)) - eq('Invalid phase: 4', + eq("Invalid 'phase': 4", pcall_err(request, 'nvim_paste', 'foo', true, 4)) end) local function run_streamed_paste_tests() @@ -1154,10 +1154,10 @@ describe('API', function() end) describe('nvim_put', function() - it('validates args', function() - eq("Invalid line: expected String, got Integer", + it('validation', function() + eq("Invalid 'line': expected String, got Integer", pcall_err(request, 'nvim_put', {42}, 'l', false, false)) - eq("Invalid type: 'x'", + eq("Invalid 'type': 'x'", pcall_err(request, 'nvim_put', {'foo'}, 'x', false, false)) end) it("fails if 'nomodifiable'", function() @@ -1259,9 +1259,9 @@ describe('API', function() yyybc line 2 line 3 ]]) - eq("Invalid type: 'bx'", + eq("Invalid 'type': 'bx'", pcall_err(meths.put, {'xxx', 'yyy'}, 'bx', false, true)) - eq("Invalid type: 'b3x'", + eq("Invalid 'type': 'b3x'", pcall_err(meths.put, {'xxx', 'yyy'}, 'b3x', false, true)) end) end) @@ -1288,6 +1288,11 @@ describe('API', function() end) describe('set/get/del variables', function() + it('validation', function() + eq('Key not found: bogus', pcall_err(meths.get_var, 'bogus')) + eq('Key not found: bogus', pcall_err(meths.del_var, 'bogus')) + end) + it('nvim_get_var, nvim_set_var, nvim_del_var', function() nvim('set_var', 'lua', {1, 2, {['3'] = 1}}) eq({1, 2, {['3'] = 1}}, nvim('get_var', 'lua')) @@ -1411,12 +1416,14 @@ describe('API', function() end) it('validation', function() - eq("Invalid scope: expected 'local' or 'global'", + eq("Invalid 'scope': expected 'local' or 'global'", pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 'bogus'})) - eq("Invalid scope: expected 'local' or 'global'", + eq("Invalid 'scope': expected 'local' or 'global'", pcall_err(nvim, 'set_option_value', 'scrolloff', 1, {scope = 'bogus'})) - eq("Invalid scope: expected String, got Integer", + eq("Invalid 'scope': expected String, got Integer", pcall_err(nvim, 'get_option_value', 'scrolloff', {scope = 42})) + eq("Invalid 'scrolloff': expected Integer/Boolean/String, got Array", + pcall_err(nvim, 'set_option_value', 'scrolloff', {}, {})) end) it('can get local values when global value is set', function() @@ -1786,12 +1793,12 @@ describe('API', function() end) describe('nvim_get_context', function() - it('validates args', function() + it('validation', function() eq("Invalid key: 'blah'", pcall_err(nvim, 'get_context', {blah={}})) - eq("Invalid types: expected Array, got Integer", + eq("Invalid 'types': expected Array, got Integer", pcall_err(nvim, 'get_context', {types=42})) - eq("Invalid type: 'zub'", + eq("Invalid 'type': 'zub'", pcall_err(nvim, 'get_context', {types={'jumps', 'zub', 'zam',}})) end) it('returns map of current editor state', function() @@ -2238,7 +2245,7 @@ describe('API', function() {'nvim_set_var'}, {'nvim_set_var', {'avar', 2}}, } - eq('calls item must be a 2-item Array', + eq("Invalid 'calls' item: expected 2-item Array", pcall_err(meths.call_atomic, req)) -- call before was done, but not after eq(1, meths.get_var('avar')) @@ -2247,7 +2254,7 @@ describe('API', function() { 'nvim_set_var', { 'bvar', { 2, 3 } } }, 12, } - eq("Invalid calls item: expected Array, got Integer", + eq("Invalid 'calls' item: expected Array, got Integer", pcall_err(meths.call_atomic, req)) eq({2,3}, meths.get_var('bvar')) @@ -2255,7 +2262,7 @@ describe('API', function() {'nvim_set_current_line', 'little line'}, {'nvim_set_var', {'avar', 3}}, } - eq("Invalid args: expected Array, got String", + eq("Invalid call args: expected Array, got String", pcall_err(meths.call_atomic, req)) -- call before was done, but not after eq(1, meths.get_var('avar')) @@ -3119,15 +3126,15 @@ describe('API', function() meths.eval_statusline('a%=b', { fillchar = '\031', maxwidth = 5 })) end) it('rejects multiple-character fillchar', function() - eq('Invalid fillchar: expected single character', + eq("Invalid 'fillchar': expected single character", pcall_err(meths.eval_statusline, '', { fillchar = 'aa' })) end) it('rejects empty string fillchar', function() - eq('Invalid fillchar: expected single character', + eq("Invalid 'fillchar': expected single character", pcall_err(meths.eval_statusline, '', { fillchar = '' })) end) it('rejects non-string fillchar', function() - eq("Invalid fillchar: expected String, got Integer", + eq("Invalid 'fillchar': expected String, got Integer", pcall_err(meths.eval_statusline, '', { fillchar = 1 })) end) it('rejects invalid string', function() diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 76baf2cddb..418294ac07 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -751,8 +751,8 @@ describe('Buffer highlighting', function() it('validates contents', function() -- this used to leak memory - eq('Invalid chunk: expected Array, got String', pcall_err(set_virtual_text, id1, 0, {"texty"}, {})) - eq('Invalid chunk: expected Array, got String', pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {})) + eq("Invalid 'chunk': expected Array, got String", pcall_err(set_virtual_text, id1, 0, {"texty"}, {})) + eq("Invalid 'chunk': expected Array, got String", pcall_err(set_virtual_text, id1, 0, {{"very"}, "texty"}, {})) end) it('can be retrieved', function() -- 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/legacy/search_stat_spec.lua | 8 +++----- test/functional/lua/ui_event_spec.lua | 9 ++------- test/functional/ui/fold_spec.lua | 9 ++------- test/functional/ui/inccommand_spec.lua | 3 ++- test/functional/ui/screen.lua | 12 ++++++++---- test/functional/ui/searchhl_spec.lua | 1 + test/functional/vimscript/timer_spec.lua | 10 +--------- 7 files changed, 19 insertions(+), 33 deletions(-) (limited to 'test/functional') diff --git a/test/functional/legacy/search_stat_spec.lua b/test/functional/legacy/search_stat_spec.lua index 9fcf798836..06e0b2320a 100644 --- a/test/functional/legacy/search_stat_spec.lua +++ b/test/functional/legacy/search_stat_spec.lua @@ -1,7 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, exec, command = helpers.clear, helpers.feed, helpers.exec, helpers.command -local poke_eventloop = helpers.poke_eventloop describe('search stat', function() local screen @@ -80,12 +79,11 @@ describe('search stat', function() {1:~ }| /foo [1/2] | ]]) + -- Note: there is an intermediate state where the search stat disappears. feed('n') - poke_eventloop() - screen:expect_unchanged() + screen:expect_unchanged(true) feed('n') - poke_eventloop() - screen:expect_unchanged() + screen:expect_unchanged(true) end) -- oldtest: Test_search_stat_then_gd() 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" }; } diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 420a4654f8..c8a3397a86 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -10,7 +10,6 @@ local meths = helpers.meths local exec = helpers.exec local exec_lua = helpers.exec_lua local assert_alive = helpers.assert_alive -local poke_eventloop = helpers.poke_eventloop local content1 = [[ @@ -30,8 +29,6 @@ describe("folded lines", function() local function with_ext_multigrid(multigrid) local screen before_each(function() - clear() - command('hi VertSplit gui=reverse') screen = Screen.new(45, 8) screen:attach({rgb=true, ext_multigrid=multigrid}) screen:set_default_attr_ids({ @@ -166,12 +163,10 @@ describe("folded lines", function() end -- CursorLine is applied correctly with screenrow motions #22232 feed("jgk") - poke_eventloop() - screen:expect_unchanged() + screen:expect_unchanged(true) -- CursorLine is applied correctly when closing a fold when cursor is not at fold start feed("zo4Gzc") - poke_eventloop() - screen:expect_unchanged() + screen:expect_unchanged(true) command("set cursorlineopt=line") if multigrid then screen:expect([[ diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index 6fbf9b72c8..96634be327 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -2886,7 +2886,8 @@ it(':substitute with inccommand during :terminal activity', function() feed('gg') feed(':%s/foo/ZZZ') sleep(20) -- Allow some terminal activity. - helpers.poke_eventloop() + poke_eventloop() + screen:sleep(0) screen:expect_unchanged() end) end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index a059fb5b89..7760f26fca 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -470,15 +470,19 @@ screen:redraw_debug() to show all intermediate screen states. ]]) end, expected) end -function Screen:expect_unchanged(waittime_ms, ignore_attrs, request_cb) +function Screen:expect_unchanged(intermediate, waittime_ms, ignore_attrs) waittime_ms = waittime_ms and waittime_ms or 100 -- Collect the current screen state. - self:sleep(0, request_cb) local kwargs = self:get_snapshot(nil, ignore_attrs) - -- Check that screen state does not change. - kwargs.unchanged = true + if intermediate then + kwargs.intermediate = true + else + kwargs.unchanged = true + end + kwargs.timeout = waittime_ms + -- Check that screen state does not change. self:expect(kwargs) end diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 404cc6d043..916a5eb537 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -317,6 +317,7 @@ describe('search highlighting', function() ]]) feed('/foo') helpers.poke_eventloop() + screen:sleep(0) screen:expect_unchanged() end) diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua index 1818a71ea2..a58cd6ae7f 100644 --- a/test/functional/vimscript/timer_spec.lua +++ b/test/functional/vimscript/timer_spec.lua @@ -251,15 +251,7 @@ describe('timers', function() :good^ | ]]) command('let g:val = 1') - - screen:expect{grid=[[ - | - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - :good^ | - ]], intermediate=true, timeout=load_adjust(200)} + screen:expect_unchanged(true, load_adjust(200)) eq(2, eval('g:val')) end) -- cgit From 968cd1ed933c039b8d60b0110bc6b539c71e387d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 16 Feb 2023 07:25:16 +0800 Subject: vim-patch:9.0.1309: scrolling two lines with even line count and 'scrolloff' set Problem: Scrolling two lines with even line count and 'scrolloff' set. Solution: Adjust how the topline is computed. (closes vim/vim#10545) https://github.com/vim/vim/commit/1d6539cf36a7b6d1afe76fb6316fe662f543bf60 Cherry-pick test_scroll_opt.vim changes from patch 8.2.1432. Co-authored-by: Bram Moolenaar --- test/functional/legacy/search_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua index 3f1f85cf28..4228940eda 100644 --- a/test/functional/legacy/search_spec.lua +++ b/test/functional/legacy/search_spec.lua @@ -290,8 +290,8 @@ describe('search cmdline', function() -- First match feed('/thei') screen:expect([[ + 3 the | 4 {inc:thei}r | - 5 there | /thei^ | ]]) -- Match from initial cursor position when modifying search -- cgit From d34c64e342dfba9248d1055e702d02620a1b31a8 Mon Sep 17 00:00:00 2001 From: Ghjuvan Lacambre Date: Thu, 16 Feb 2023 13:15:02 +0100 Subject: feat: $NVIM_APPNAME #22128 This commit implements the ability to control all of the XDG paths Neovim should use. This is done by setting an environment variable named NVIM_APPNAME. For example, setting $NVIM_APPNAME makes Neovim look for its configuration directory in $XDG_CONFIG_HOME/$NVIM_APPNAME instead of $XDG_CONFIG_HOME/nvim. If NVIM_APPNAME is not set or is an empty string, "nvim" will be used as default. The usecase for this feature is to enable an easy way to switch from configuration to configuration. One might argue that the various $XDG environment variables can already be used for this usecase. However, setting $XDG environment variables also affects tools spawned by Neovim. For example, while setting $XDG_CONFIG_HOME will enable Neovim to use a different configuration directory, it will also prevent Git from finding its "default" configuration. Closes https://github.com/neovim/neovim/issues/21691 --- test/functional/options/defaults_spec.lua | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index 84ec43f4cb..4242b6e493 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -566,8 +566,12 @@ end) describe('stdpath()', function() -- Windows appends 'nvim-data' instead of just 'nvim' to prevent collisions -- due to XDG_CONFIG_HOME, XDG_DATA_HOME and XDG_STATE_HOME being the same. - local datadir = is_os('win') and 'nvim-data' or 'nvim' - local statedir = is_os('win') and 'nvim-data' or 'nvim' + local function maybe_data(name) + return is_os('win') and name .. '-data' or name + end + + local datadir = maybe_data('nvim') + local statedir = maybe_data('nvim') local env_sep = is_os('win') and ';' or ':' it('acceptance', function() @@ -583,6 +587,24 @@ describe('stdpath()', function() assert_alive() -- Check for crash. #8393 end) + it('reacts to #NVIM_APPNAME', function() + local appname = "NVIM_APPNAME_TEST____________________________________" .. + "______________________________________________________________________" + clear({env={ NVIM_APPNAME=appname }}) + eq(appname, funcs.fnamemodify(funcs.stdpath('config'), ':t')) + eq(appname, funcs.fnamemodify(funcs.stdpath('cache'), ':t')) + eq(maybe_data(appname), funcs.fnamemodify(funcs.stdpath('log'), ':t')) + eq(maybe_data(appname), funcs.fnamemodify(funcs.stdpath('data'), ':t')) + eq(maybe_data(appname), funcs.fnamemodify(funcs.stdpath('state'), ':t')) + -- config_dirs and data_dirs are empty on windows, so don't check them on + -- that platform + if not is_os('win') then + eq(appname, funcs.fnamemodify(funcs.stdpath('config_dirs')[1], ':t')) + eq(appname, funcs.fnamemodify(funcs.stdpath('data_dirs')[1], ':t')) + end + assert_alive() -- Check for crash. #8393 + end) + context('returns a String', function() describe('with "config"' , function () -- cgit From 09b3432eaff3abcadb56d61b6f247f992b80b63f Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 16 Feb 2023 10:07:18 -0500 Subject: fix(api): allow empty Lua table for nested dicts #22268 Problem: The Lua-API bridge allows Dict params to be empty Lua (list) tables at the function-signature level. But not for _nested_ Dicts, because they are not modeled: https://github.com/neovim/neovim/blob/fae754073289566051433fae74ec65783f9e7a6a/src/nvim/api/keysets.lua#L184 Some API functions like nvim_cmd check for kObjectTypeDictionary and don't handle the case of empty Lua tables (treated as "Array"). Solution: Introduce VALIDATE_T_DICT and use it in places where kObjectTypeDictionary was being checked directly. fixes #21005 --- test/functional/api/command_spec.lua | 2 +- test/functional/api/vim_spec.lua | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua index 9db687cc37..1ddb289ded 100644 --- a/test/functional/api/command_spec.lua +++ b/test/functional/api/command_spec.lua @@ -24,7 +24,7 @@ describe('nvim_get_commands', function() eq({}, meths.get_commands({builtin=false})) end) - it('validates input', function() + it('validation', function() eq('builtin=true not implemented', pcall_err(meths.get_commands, {builtin=true})) eq("Invalid key: 'foo'", pcall_err(meths.get_commands, diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 981fc19b36..3e40967dd5 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3826,14 +3826,71 @@ describe('API', function() meths.cmd({ cmd = "set", args = { "cursorline" } }, {}) eq(true, meths.get_option_value("cursorline", {})) end) + + it('validation', function() + eq("Invalid 'cmd': expected non-empty String", + pcall_err(meths.cmd, { cmd = ""}, {})) + eq("Invalid 'cmd': expected non-empty String", + pcall_err(meths.cmd, { cmd = {}}, {})) + eq("Invalid 'args': expected Array, got Boolean", + pcall_err(meths.cmd, { cmd = "set", args = true }, {})) + eq("Invalid 'magic': expected Dict, got Array", + pcall_err(meths.cmd, { cmd = "set", args = {}, magic = {} }, {})) + eq("Invalid command arg: expected non-whitespace", + pcall_err(meths.cmd, { cmd = "set", args = {' '}, }, {})) + eq("Invalid command arg: expected valid type, got Array", + pcall_err(meths.cmd, { cmd = "set", args = {{}}, }, {})) + eq("Wrong number of arguments", + pcall_err(meths.cmd, { cmd = "aboveleft", args = {}, }, {})) + eq("Command cannot accept bang: print", + pcall_err(meths.cmd, { cmd = "print", args = {}, bang = true }, {})) + + eq("Command cannot accept range: set", + pcall_err(meths.cmd, { cmd = "set", args = {}, range = {1} }, {})) + eq("Invalid 'range': expected Array, got Boolean", + pcall_err(meths.cmd, { cmd = "print", args = {}, range = true }, {})) + eq("Invalid 'range': expected <=2 elements", + pcall_err(meths.cmd, { cmd = "print", args = {}, range = {1,2,3,4} }, {})) + eq("Invalid range element: expected non-negative Integer", + pcall_err(meths.cmd, { cmd = "print", args = {}, range = {-1} }, {})) + + eq("Command cannot accept count: set", + pcall_err(meths.cmd, { cmd = "set", args = {}, count = 1 }, {})) + eq("Invalid 'count': expected non-negative Integer", + pcall_err(meths.cmd, { cmd = "print", args = {}, count = true }, {})) + eq("Invalid 'count': expected non-negative Integer", + pcall_err(meths.cmd, { cmd = "print", args = {}, count = -1 }, {})) + + eq("Command cannot accept register: set", + pcall_err(meths.cmd, { cmd = "set", args = {}, reg = 'x' }, {})) + eq('Cannot use register "=', + pcall_err(meths.cmd, { cmd = "put", args = {}, reg = '=' }, {})) + eq("Invalid 'reg': expected single character, got xx", + pcall_err(meths.cmd, { cmd = "put", args = {}, reg = 'xx' }, {})) + + -- Lua call allows empty {} for dict item. + eq('', exec_lua([[return vim.cmd{ cmd = "set", args = {}, magic = {} }]])) + eq('', exec_lua([[return vim.cmd{ cmd = "set", args = {}, mods = {} }]])) + + -- Lua call does not allow non-empty list-like {} for dict item. + eq("Invalid 'magic': expected Dict, got Array", + pcall_err(exec_lua, [[return vim.cmd{ cmd = "set", args = {}, magic = { 'a' } }]])) + eq("Invalid key: 'bogus'", + pcall_err(exec_lua, [[return vim.cmd{ cmd = "set", args = {}, magic = { bogus = true } }]])) + eq("Invalid key: 'bogus'", + pcall_err(exec_lua, [[return vim.cmd{ cmd = "set", args = {}, mods = { bogus = true } }]])) + end) + it('captures output', function() eq("foo", meths.cmd({ cmd = "echo", args = { '"foo"' } }, { output = true })) end) + it('sets correct script context', function() meths.cmd({ cmd = "set", args = { "cursorline" } }, {}) local str = meths.exec([[verbose set cursorline?]], true) neq(nil, str:find("cursorline\n\tLast set from API client %(channel id %d+%)")) end) + it('works with range', function() insert [[ line1 -- 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/editor/mark_spec.lua | 2 +- test/functional/ex_cmds/trust_spec.lua | 117 +++------------------------------ test/functional/lua/secure_spec.lua | 11 ++-- test/functional/terminal/tui_spec.lua | 2 +- test/functional/ui/bufhl_spec.lua | 2 +- test/functional/ui/messages_spec.lua | 4 +- test/functional/ui/screen.lua | 19 +++++- 7 files changed, 37 insertions(+), 120 deletions(-) (limited to 'test/functional') diff --git a/test/functional/editor/mark_spec.lua b/test/functional/editor/mark_spec.lua index b3b190ef79..0670176719 100644 --- a/test/functional/editor/mark_spec.lua +++ b/test/functional/editor/mark_spec.lua @@ -413,7 +413,7 @@ describe('named marks view', function() 6 line | ^7 line | 8 line | - {MATCH:.*} | + {MATCH:.*marks} | | ]]) end) diff --git a/test/functional/ex_cmds/trust_spec.lua b/test/functional/ex_cmds/trust_spec.lua index 10ee02a790..fe13bd7cd2 100644 --- a/test/functional/ex_cmds/trust_spec.lua +++ b/test/functional/ex_cmds/trust_spec.lua @@ -1,9 +1,10 @@ local helpers = require('test.functional.helpers')(after_each) -local Screen = require('test.functional.ui.screen') local eq = helpers.eq local clear = helpers.clear local command = helpers.command +local exec_capture = helpers.exec_capture +local matches = helpers.matches local pathsep = helpers.get_pathsep() local is_os = helpers.is_os local funcs = helpers.funcs @@ -29,147 +30,49 @@ describe(':trust', function() end) it('trust then deny then remove a file using current buffer', function() - local screen = Screen.new(80, 8) - screen:attach() - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - }) - local cwd = funcs.getcwd() local hash = funcs.sha256(helpers.read_file('test_file')) command('edit test_file') - command('trust') - screen:expect([[ - ^test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - "]] .. cwd .. pathsep .. [[test_file" trusted.{MATCH:%s+}| - ]]) + matches('^Allowed ".*test_file" in trust database%.$', exec_capture('trust')) local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, cwd .. pathsep .. 'test_file'), vim.trim(trust)) - command('trust ++deny') - screen:expect([[ - ^test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - "]] .. cwd .. pathsep .. [[test_file" denied.{MATCH:%s+}| - ]]) + matches('^Denied ".*test_file" in trust database%.$', exec_capture('trust ++deny')) trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust)) - command('trust ++remove') - screen:expect([[ - ^test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - "]] .. cwd .. pathsep .. [[test_file" removed.{MATCH:%s+}| - ]]) + matches('^Removed ".*test_file" from trust database%.$', exec_capture('trust ++remove')) trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') eq(string.format(''), vim.trim(trust)) end) it('deny then trust then remove a file using current buffer', function() - local screen = Screen.new(80, 8) - screen:attach() - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - }) - local cwd = funcs.getcwd() local hash = funcs.sha256(helpers.read_file('test_file')) command('edit test_file') - command('trust ++deny') - screen:expect([[ - ^test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - "]] .. cwd .. pathsep .. [[test_file" denied.{MATCH:%s+}| - ]]) + matches('^Denied ".*test_file" in trust database%.$', exec_capture('trust ++deny')) local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust)) - command('trust') - screen:expect([[ - ^test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - "]] .. cwd .. pathsep .. [[test_file" trusted.{MATCH:%s+}| - ]]) + matches('^Allowed ".*test_file" in trust database%.$', exec_capture('trust')) trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') eq(string.format('%s %s', hash, cwd .. pathsep .. 'test_file'), vim.trim(trust)) - command('trust ++remove') - screen:expect([[ - ^test | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - "]] .. cwd .. pathsep .. [[test_file" removed.{MATCH:%s+}| - ]]) + matches('^Removed ".*test_file" from trust database%.$', exec_capture('trust ++remove')) trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') eq(string.format(''), vim.trim(trust)) end) it('deny then remove a file using file path', function() - local screen = Screen.new(80, 8) - screen:attach() - screen:set_default_attr_ids({ - [1] = {bold = true, foreground = Screen.colors.Blue1}, - }) - local cwd = funcs.getcwd() - command('trust ++deny test_file') - screen:expect([[ - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - "]] .. cwd .. pathsep .. [[test_file" denied.{MATCH:%s+}| - ]]) + matches('^Denied ".*test_file" in trust database%.$', exec_capture('trust ++deny test_file')) local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust)) - command('trust ++remove test_file') - screen:expect([[ - ^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - "]] .. cwd .. pathsep .. [[test_file" removed.{MATCH:%s+}| - ]]) + matches('^Removed ".*test_file" from trust database%.$', exec_capture('trust ++remove test_file')) trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust') eq(string.format(''), vim.trim(trust)) end) 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] }| diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 4e62354ed8..4a0c482004 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1544,7 +1544,7 @@ describe('TUI', function() {2:~ }│{4:~ }| {2:~ }│{5:[No Name] 0,0-1 All}| {2:~ }│ | - {5:new }{MATCH:<.*[/\]nvim }| + {5:new }{1:{MATCH:<.*[/\]nvim }}| | ]]) end) diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 418294ac07..adec0770de 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -303,7 +303,7 @@ describe('Buffer highlighting', function() {1:~ }| {1:~ }| {1:~ }| - 2 change3; before #3 {MATCH:.*}| + 2 changes; before #3 {MATCH:.*}| ]]} command('undo') diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 3052a74f38..212d3aee7d 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1322,7 +1322,7 @@ describe('ui/ext_messages', function() {1:~ }type :q{5:} to exit {1: }| {1:~ }type :help{5:} for help {1: }| {1:~ }| - {1:~ }type :help news{5:} to see changes in v{MATCH:%d+%.%d+}| + {1:~{MATCH: +}}type :help news{5:} to see changes in v{MATCH:%d+%.%d+}{1:{MATCH: +}}| {1:~ }| {MATCH:.*}| {MATCH:.*}| @@ -1378,7 +1378,7 @@ describe('ui/ext_messages', function() type :q{5:} to exit | type :help{5:} for help | | - type :help news{5:} to see changes in v{MATCH:%d+%.%d+}| + {MATCH: +}type :help news{5:} to see changes in v{MATCH:%d+%.%d+ +}| | {MATCH:.*}| {MATCH:.*}| diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 7760f26fca..14ce050578 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -75,6 +75,7 @@ local busted = require('busted') local deepcopy = helpers.deepcopy local shallowcopy = helpers.shallowcopy local concat_tables = helpers.concat_tables +local pesc = helpers.pesc local run_session = helpers.run_session local eq = helpers.eq local dedent = helpers.dedent @@ -257,7 +258,7 @@ local ext_keys = { -- grid: Expected screen state (string). Each line represents a screen -- row. Last character of each row (typically "|") is stripped. -- Common indentation is stripped. --- "{MATCH:x}|" lines are matched against Lua pattern `x`. +-- "{MATCH:x}" in a line is matched against Lua pattern `x`. -- attr_ids: Expected text attributes. Screen rows are transformed according -- to this table, as follows: each substring S composed of -- characters having the same attributes will be substituted by @@ -382,8 +383,20 @@ function Screen:expect(expected, attr_ids, ...) end for i, row in ipairs(expected_rows) do msg_expected_rows[i] = row - local m = (row ~= actual_rows[i] and row:match('{MATCH:(.*)}') or nil) - if row ~= actual_rows[i] and (not m or not (actual_rows[i] and actual_rows[i]:match(m))) then + local pat = nil + if actual_rows[i] and row ~= actual_rows[i] then + local after = row + while true do + local s, e, m = after:find('{MATCH:(.-)}') + if not s then + pat = pat and (pat .. pesc(after)) + break + end + pat = (pat or '') .. pesc(after:sub(1, s - 1)) .. m + after = after:sub(e + 1) + end + end + if row ~= actual_rows[i] and (not pat or not actual_rows[i]:match(pat)) then msg_expected_rows[i] = '*' .. msg_expected_rows[i] if i <= #actual_rows then actual_rows[i] = '*' .. actual_rows[i] -- cgit From 9381d08e2916d6114c06336714e416bb834e5566 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 18 Feb 2023 10:22:22 +0800 Subject: test(tui_spec): use RPC request to setup autocommands This avoids changing cmdline and fixes a warning. --- test/functional/terminal/tui_spec.lua | 61 +++++++++++++++-------------------- 1 file changed, 26 insertions(+), 35 deletions(-) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 4a0c482004..792ad63e76 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -109,14 +109,14 @@ describe('TUI', function() end) it('accepts resize while pager is active', function() - child_session:request("nvim_command", [[ + child_session:request("nvim_exec", [[ set more func! ManyErr() for i in range(10) echoerr "FAIL ".i endfor endfunc - ]]) + ]], false) feed_data(':call ManyErr()\r') screen:expect{grid=[[ {8:Error detected while processing function ManyErr:} | @@ -302,11 +302,11 @@ describe('TUI', function() end) it('accepts mouse wheel events #19992', function() - child_session:request('nvim_command', [[ + child_session:request('nvim_exec', [[ set number nostartofline nowrap mousescroll=hor:1,ver:1 call setline(1, repeat([join(range(10), '----')], 10)) vsplit - ]]) + ]], false) screen:expect([[ {11: 1 }{1:0}----1----2----3----4│{11: 1 }0----1----2----3----| {11: 2 }0----1----2----3----4│{11: 2 }0----1----2----3----| @@ -632,11 +632,11 @@ describe('TUI', function() | {3:-- TERMINAL --} | ]]) - child_session:request('nvim_command', [[ + child_session:request('nvim_exec', [[ tab split tabnew highlight Tabline ctermbg=NONE ctermfg=NONE cterm=underline - ]]) + ]], false) screen:expect([[ {12: + [No Name] + [No Name] }{3: [No Name] }{1: }{12:X}| {1: } | @@ -669,7 +669,7 @@ describe('TUI', function() end) it('mouse events work with right-click menu', function() - child_session:request('nvim_command', [[ + child_session:request('nvim_exec', [[ call setline(1, 'popup menu test') set mouse=a mousemodel=popup @@ -679,7 +679,7 @@ describe('TUI', function() menu PopUp.baz :let g:menustr = 'baz' highlight Pmenu ctermbg=NONE ctermfg=NONE cterm=underline,reverse highlight PmenuSel ctermbg=NONE ctermfg=NONE cterm=underline,reverse,bold - ]]) + ]], false) meths.input_mouse('right', 'press', '', 0, 0, 4) screen:expect([[ {1:p}opup menu test | @@ -1626,12 +1626,16 @@ end) describe('TUI FocusGained/FocusLost', function() local screen + local child_session before_each(function() clear() - screen = thelpers.screen_setup(0, '["'..nvim_prog - ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]') - screen:expect{grid=[[ + local child_server = new_pipename() + screen = thelpers.screen_setup(0, + string.format( + [=[["%s", "--listen", "%s", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]]=], + nvim_prog, child_server)) + screen:expect([[ {1: } | {4:~ }| {4:~ }| @@ -1639,22 +1643,16 @@ describe('TUI FocusGained/FocusLost', function() {5:[No Name] }| | {3:-- TERMINAL --} | - ]]} - feed_data(":autocmd FocusGained * echo 'gained'\n") - feed_data(":autocmd FocusLost * echo 'lost'\n") + ]]) + child_session = helpers.connect(child_server) + child_session:request('nvim_exec', [[ + autocmd FocusGained * echo 'gained' + autocmd FocusLost * echo 'lost' + ]], false) feed_data("\034\016") -- CTRL-\ CTRL-N end) it('in normal-mode', function() - screen:expect{grid=[[ - {1: } | - {4:~ }| - {4:~ }| - {4:~ }| - {5:[No Name] }| - :autocmd FocusLost * echo 'lost' | - {3:-- TERMINAL --} | - ]]} retry(2, 3 * screen.timeout, function() feed_data('\027[I') screen:expect([[ @@ -1746,18 +1744,11 @@ describe('TUI FocusGained/FocusLost', function() -- Set up autocmds that modify the buffer, instead of just calling :echo. -- This is how we can test handling of focus gained/lost during cmdline-mode. -- See commit: 5cc87d4dabd02167117be7a978b5c8faaa975419. - feed_data(":autocmd!\n") - feed_data(":autocmd FocusLost * call append(line('$'), 'lost')\n") - feed_data(":autocmd FocusGained * call append(line('$'), 'gained')\n") - screen:expect{grid=[[ - {1: } | - {4:~ }| - {4:~ }| - {4:~ }| - {5:[No Name] }| - | - {3:-- TERMINAL --} | - ]]} + child_session:request('nvim_exec', [[ + autocmd! + autocmd FocusLost * call append(line('$'), 'lost') + autocmd FocusGained * call append(line('$'), 'gained') + ]], false) retry(2, 3 * screen.timeout, function() -- Enter cmdline-mode. feed_data(':') -- cgit From f43fa301c1a2817239e046a242902af65b7cac71 Mon Sep 17 00:00:00 2001 From: Eduard Baturin Date: Sat, 18 Feb 2023 09:43:59 +0300 Subject: fix(lsp): check if the buffer is a directory before w! it (#22289) --- test/functional/plugin/lsp_spec.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index fd162961ff..f1aad08140 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2067,6 +2067,8 @@ describe('LSP', function() end) describe('lsp.util.rename', function() + local pathsep = helpers.get_pathsep() + it('Can rename an existing file', function() local old = helpers.tmpname() write_file(old, 'Test content') @@ -2089,6 +2091,32 @@ describe('LSP', function() eq(true, exists) os.remove(new) end) + it('Can rename a direcory', function() + -- only reserve the name, file must not exist for the test scenario + local old_dir = helpers.tmpname() + local new_dir = helpers.tmpname() + os.remove(old_dir) + os.remove(new_dir) + + helpers.mkdir_p(old_dir) + + local file = "file" + write_file(old_dir .. pathsep .. file, 'Test content') + + exec_lua([[ + local old_dir = select(1, ...) + local new_dir = select(2, ...) + + vim.lsp.util.rename(old_dir, new_dir) + ]], old_dir, new_dir) + + eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', old_dir)) + eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', new_dir)) + eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', new_dir .. pathsep .. file)) + eq('Test content', read_file(new_dir .. pathsep .. file)) + + os.remove(new_dir) + end) it('Does not rename file if target exists and ignoreIfExists is set or overwrite is false', function() local old = helpers.tmpname() write_file(old, 'Old File') -- cgit From fec1181ecde75de1754f1d27a7ba7cbf2b9f43d6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 21 Feb 2023 17:43:53 +0800 Subject: test(legacy/prompt_buffer_spec): align script with oldtest more (#22354) --- test/functional/legacy/prompt_buffer_spec.lua | 88 +++++++++++---------------- 1 file changed, 36 insertions(+), 52 deletions(-) (limited to 'test/functional') diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index 63338b8dba..602593d632 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -3,7 +3,6 @@ local Screen = require('test.functional.ui.screen') local feed = helpers.feed local source = helpers.source local clear = helpers.clear -local feed_command = helpers.feed_command local poke_eventloop = helpers.poke_eventloop local meths = helpers.meths local eq = helpers.eq @@ -16,64 +15,74 @@ describe('prompt buffer', function() screen = Screen.new(25, 10) screen:attach() source([[ + set laststatus=0 nohidden + func TextEntered(text) if a:text == "exit" + " Reset &modified to allow the buffer to be closed. set nomodified stopinsert close else + " Add the output above the current prompt. call append(line("$") - 1, 'Command: "' . a:text . '"') + " Reset &modified to allow the buffer to be closed. set nomodified call timer_start(20, {id -> TimerFunc(a:text)}) endif endfunc func TimerFunc(text) + " Add the output above the current prompt. call append(line("$") - 1, 'Result: "' . a:text .'"') + " Reset &modified to allow the buffer to be closed. + set nomodified endfunc func SwitchWindows() call timer_start(0, {-> execute("wincmd p", "")}) endfunc - ]]) - feed_command("set noshowmode | set laststatus=0") - feed_command("call setline(1, 'other buffer')") - feed_command("new") - feed_command("set buftype=prompt") - feed_command("call prompt_setcallback(bufnr(''), function('TextEntered'))") - feed_command("eval bufnr('')->prompt_setprompt('cmd: ')") - end) - - after_each(function() - screen:detach() - end) - it('works', function() + call setline(1, "other buffer") + set nomodified + new + set buftype=prompt + call prompt_setcallback(bufnr(''), function("TextEntered")) + eval bufnr("")->prompt_setprompt("cmd: ") + startinsert + ]]) screen:expect([[ - ^ | + cmd: ^ | ~ | ~ | ~ | - [Prompt] | + [Prompt] [+] | other buffer | ~ | ~ | ~ | - | + -- INSERT -- | ]]) - feed("i") + end) + + after_each(function() + screen:detach() + end) + + -- oldtest: Test_prompt_basic() + it('works', function() feed("hello\n") screen:expect([[ cmd: hello | Command: "hello" | Result: "hello" | cmd: ^ | - [Prompt] [+] | + [Prompt] | other buffer | ~ | ~ | ~ | - | + -- INSERT -- | ]]) feed("exit\n") screen:expect([[ @@ -90,20 +99,8 @@ describe('prompt buffer', function() ]]) end) + -- oldtest: Test_prompt_editing() it('editing', function() - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - [Prompt] | - other buffer | - ~ | - ~ | - ~ | - | - ]]) - feed("i") feed("hello") screen:expect([[ cmd: hel^ | @@ -115,7 +112,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - | + -- INSERT -- | ]]) feed("-") screen:expect([[ @@ -128,7 +125,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - | + -- INSERT -- | ]]) feed("lz") screen:expect([[ @@ -141,7 +138,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - | + -- INSERT -- | ]]) feed("x") screen:expect([[ @@ -154,7 +151,7 @@ describe('prompt buffer', function() ~ | ~ | ~ | - | + -- INSERT -- | ]]) feed("exit\n") screen:expect([[ @@ -171,21 +168,8 @@ describe('prompt buffer', function() ]]) end) + -- oldtest: Test_prompt_switch_windows() it('switch windows', function() - feed_command("set showmode") - feed("i") - screen:expect([[ - cmd: ^ | - ~ | - ~ | - ~ | - [Prompt] [+] | - other buffer | - ~ | - ~ | - ~ | - -- INSERT -- | - ]]) feed(":call SwitchWindows()") screen:expect{grid=[[ cmd: | @@ -227,11 +211,11 @@ describe('prompt buffer', function() ]]) end) + -- oldtest: Test_prompt_while_writing_to_hidden_buffer() it('keeps insert mode after aucmd_restbuf in callback', function() source [[ let s:buf = nvim_create_buf(1, 1) call timer_start(0, {-> nvim_buf_set_lines(s:buf, -1, -1, 0, ['walrus'])}) - startinsert ]] poke_eventloop() eq({ mode = "i", blocking = false }, meths.get_mode()) -- cgit From 8714a4009c0f0be0bb27a6b3eb486eeb3d9f3049 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 21 Feb 2023 17:09:18 +0000 Subject: feat(treesitter): add filetype -> lang API Problem: vim.treesitter does not know how to map a specific filetype to a parser. This creates problems since in a few places (including in vim.treesitter itself), the filetype is incorrectly used in place of lang. Solution: Add an API to enable this: - Add vim.treesitter.language.add() as a replacement for vim.treesitter.language.require_language(). - Optional arguments are now passed via an opts table. - Also takes a filetype (or list of filetypes) so we can keep track of what filetypes are associated with which langs. - Deprecated vim.treesitter.language.require_language(). - Add vim.treesitter.language.get_lang() which returns the associated lang for a given filetype. - Add vim.treesitter.language.register() to associate filetypes to a lang without loading the parser. --- test/functional/treesitter/language_spec.lua | 11 ++++++----- test/functional/treesitter/parser_spec.lua | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 51d8eb62f3..a8831b9a9b 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -18,22 +18,23 @@ describe('treesitter language API', function() -- actual message depends on platform matches("Failed to load parser for language 'borklang': uv_dlopen: .+", - pcall_err(exec_lua, "parser = vim.treesitter.require_language('borklang', 'borkbork.so')")) + pcall_err(exec_lua, "parser = vim.treesitter.add('borklang', { path = 'borkbork.so' })")) -- Should not throw an error when silent - eq(false, exec_lua("return vim.treesitter.require_language('borklang', nil, true)")) - eq(false, exec_lua("return vim.treesitter.require_language('borklang', 'borkbork.so', true)")) + eq(false, exec_lua("return vim.treesitter.add('borklang', { silent = true })")) + + eq(false, exec_lua("return vim.treesitter.add('borklang', { path = 'borkbork.so', silent = true })")) eq(".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) matches("Failed to load parser: uv_dlsym: .+", - pcall_err(exec_lua, 'vim.treesitter.require_language("c", nil, false, "borklang")')) + pcall_err(exec_lua, 'vim.treesitter.add("c", { symbol_name = "borklang" })')) end) it('shows error for invalid language name', function() eq(".../language.lua:0: '/foo/' is not a valid language name", - pcall_err(exec_lua, 'vim.treesitter.require_language("/foo/", nil, false)')) + pcall_err(exec_lua, 'vim.treesitter.add("/foo/", nil, false)')) end) it('inspects language', function() diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 2d0d57fbd0..2430021617 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -182,8 +182,9 @@ void ui_refresh(void) local firstrun = q(1) local manyruns = q(100) + local factor = is_os('win') and 3 or 4 -- First run should be at least 4x slower. - assert(400 * manyruns < firstrun, ('firstrun: %d ms, manyruns: %d ms'):format(firstrun / 1000, manyruns / 1000)) + assert(factor * 100 * manyruns < firstrun, ('firstrun: %d ms, manyruns: %d ms'):format(firstrun / 1000, manyruns / 1000)) end) it('support query and iter by capture', function() -- 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') 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 524e1a06432ed7a88c1e183d81812dd48dc18cfb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 23 Feb 2023 16:15:04 +0800 Subject: fix(highlight): avoid ORing underline flags (#22372) When combining attributes use the one that takes priority. For :highlight command use the last one specified. For API use a hard-coded order same as the order in docs. --- test/functional/api/highlight_spec.lua | 14 ++++++ test/functional/ex_cmds/highlight_spec.lua | 9 ++++ test/functional/ui/decorations_spec.lua | 77 ++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index e1b3562329..eb7d0f7b47 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -278,6 +278,20 @@ describe("API: set highlight", function() eq(highlight3_result_cterm, meths.get_hl_by_name('Test_hl', false)) end) + it("only allows one underline attribute #22371", function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', { + underdouble = true, + underdotted = true, + cterm = { + underline = true, + undercurl = true, + }, + }) + eq({ undercurl = true }, meths.get_hl_by_name('Test_hl', false)) + eq({ underdotted = true }, meths.get_hl_by_name('Test_hl', true)) + end) + it("can set a highlight in the global namespace", function() meths.set_hl(0, 'Test_hl', highlight2_config) eq('Test_hl xxx cterm=underline,reverse ctermfg=8 ctermbg=15 gui=underline,reverse', diff --git a/test/functional/ex_cmds/highlight_spec.lua b/test/functional/ex_cmds/highlight_spec.lua index 1cd6759a53..18f215cf75 100644 --- a/test/functional/ex_cmds/highlight_spec.lua +++ b/test/functional/ex_cmds/highlight_spec.lua @@ -36,4 +36,13 @@ describe(':highlight', function() command('highlight normal ctermbg=red') eq('9', eval('synIDattr(hlID("Normal"), "bg", "cterm")')) end) + + it('only the last underline style takes effect #22371', function() + command('highlight NonText gui=underline,undercurl') + eq('', eval('synIDattr(hlID("NonText"), "underline", "gui")')) + eq('1', eval('synIDattr(hlID("NonText"), "undercurl", "gui")')) + command('highlight NonText gui=undercurl,underline') + eq('', eval('synIDattr(hlID("NonText"), "undercurl", "gui")')) + eq('1', eval('synIDattr(hlID("NonText"), "underline", "gui")')) + end) end) diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 6ed32a8cd4..4759d68200 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -1045,6 +1045,83 @@ end]] end) + it('underline attribute with higher priority takes effect #22371', function() + screen:try_resize(50, 3) + insert('aaabbbaaa') + exec([[ + hi TestUL gui=underline guifg=Blue + hi TestUC gui=undercurl guisp=Red + hi TestBold gui=bold + ]]) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}; + [1] = {underline = true, foreground = Screen.colors.Blue}; + [2] = {undercurl = true, special = Screen.colors.Red}; + [3] = {underline = true, foreground = Screen.colors.Blue, special = Screen.colors.Red}; + [4] = {undercurl = true, foreground = Screen.colors.Blue, special = Screen.colors.Red}; + [5] = {bold = true, underline = true, foreground = Screen.colors.Blue}; + [6] = {bold = true, undercurl = true, special = Screen.colors.Red}; + }) + + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 20 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUC', priority = 30 }) + screen:expect([[ + {1:aaa}{4:bbb}{1:aa^a} | + {0:~ }| + | + ]]) + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 20 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUL', priority = 30 }) + screen:expect([[ + {2:aaa}{3:bbb}{2:aa^a} | + {0:~ }| + | + ]]) + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 30 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUC', priority = 20 }) + screen:expect([[ + {1:aaa}{3:bbb}{1:aa^a} | + {0:~ }| + | + ]]) + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 30 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestUL', priority = 20 }) + screen:expect([[ + {2:aaa}{4:bbb}{2:aa^a} | + {0:~ }| + | + ]]) + + -- When only one highlight group has an underline attribute, it should always take effect. + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 20 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 30 }) + screen:expect([[ + {1:aaa}{5:bbb}{1:aa^a} | + {0:~ }| + | + ]]) + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUL', priority = 30 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 20 }) + screen:expect_unchanged(true) + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 20 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 30 }) + screen:expect([[ + {2:aaa}{6:bbb}{2:aa^a} | + {0:~ }| + | + ]]) + meths.buf_clear_namespace(0, ns, 0, -1) + meths.buf_set_extmark(0, ns, 0, 0, { end_col = 9, hl_group = 'TestUC', priority = 30 }) + meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 20 }) + screen:expect_unchanged(true) + end) + end) describe('decorations: virtual lines', function() -- 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') 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 75e53341f37eeeda7d9be7f934249f7e5e4397e9 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 23 Feb 2023 15:19:52 +0000 Subject: perf(treesitter): smarter languagetree invalidation Problem: Treesitter injections are slow because all injected trees are invalidated on every change. Solution: Implement smarter invalidation to avoid reparsing injected regions. - In on_bytes, try and update self._regions as best we can. This PR just offsets any regions after the change. - Add valid flags for each region in self._regions. - Call on_bytes recursively for all children. - We still need to run the query every time for the top level tree. I don't know how to avoid this. However, if the new injection ranges don't change, then we re-use the old trees and avoid reparsing children. This should result in roughly a 2-3x reduction in tree parsing when the comment injections are enabled. --- test/functional/treesitter/parser_spec.lua | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 2430021617..fdd6403859 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -639,6 +639,17 @@ int x = INT_MAX; {1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) {2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) }, get_ranges()) + + helpers.feed('ggo') + eq(5, exec_lua("return #parser:children().c:trees()")) + eq({ + {0, 0, 8, 0}, -- root tree + {4, 14, 4, 17}, -- VALUE 123 + {5, 15, 5, 18}, -- VALUE1 123 + {6, 15, 6, 18}, -- VALUE2 123 + {2, 26, 2, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + {3, 29, 3, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + }, get_ranges()) end) end) @@ -660,6 +671,18 @@ int x = INT_MAX; {1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) }, get_ranges()) + + helpers.feed('ggo') + eq("table", exec_lua("return type(parser:children().c)")) + eq(2, exec_lua("return #parser:children().c:trees()")) + eq({ + {0, 0, 8, 0}, -- root tree + {4, 14, 6, 18}, -- VALUE 123 + -- VALUE1 123 + -- VALUE2 123 + {2, 26, 3, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + }, get_ranges()) end) end) @@ -688,6 +711,18 @@ int x = INT_MAX; {1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) }, get_ranges()) + + helpers.feed('ggo') + eq("table", exec_lua("return type(parser:children().c)")) + eq(2, exec_lua("return #parser:children().c:trees()")) + eq({ + {0, 0, 8, 0}, -- root tree + {4, 14, 6, 18}, -- VALUE 123 + -- VALUE1 123 + -- VALUE2 123 + {2, 26, 3, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + }, get_ranges()) end) it("should not inject bad languages", function() -- cgit From 1df3f5ec6aca24cbe7b78ead5c37ad06a65c84e8 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 23 Feb 2023 17:05:20 +0000 Subject: feat(treesitter): upstream foldexpr from nvim-treesitter --- test/functional/treesitter/parser_spec.lua | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index fdd6403859..67aad4d1b7 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -871,4 +871,38 @@ int x = INT_MAX; end) end) end) + + it("can fold via foldexpr", function() + insert(test_text) + exec_lua([[vim.treesitter.get_parser(0, "c")]]) + + local levels = exec_lua([[ + local res = {} + for i = 1, vim.api.nvim_buf_line_count(0) do + res[i] = vim.treesitter.foldexpr(i) + end + return res + ]]) + + eq({ + [1] = '>1', + [2] = '1', + [3] = '1', + [4] = '1', + [5] = '>2', + [6] = '2', + [7] = '2', + [8] = '1', + [9] = '1', + [10] = '>2', + [11] = '2', + [12] = '2', + [13] = '2', + [14] = '2', + [15] = '>3', + [16] = '3', + [17] = '3', + [18] = '2', + [19] = '1' }, levels) + end) end) -- cgit From c57af5d41cd039194dbd9c6fb5b68b377d2a5b59 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 24 Feb 2023 09:50:59 +0000 Subject: feat(treesitter)!: remove silent option from language.add() Simply use `pcall` if you want to silence an error. --- test/functional/treesitter/language_spec.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index a8831b9a9b..2cf18242ff 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -20,10 +20,9 @@ describe('treesitter language API', function() matches("Failed to load parser for language 'borklang': uv_dlopen: .+", pcall_err(exec_lua, "parser = vim.treesitter.add('borklang', { path = 'borkbork.so' })")) - -- Should not throw an error when silent - eq(false, exec_lua("return vim.treesitter.add('borklang', { silent = true })")) + eq(false, exec_lua("return pcall(vim.treesitter.add, 'borklang')")) - eq(false, exec_lua("return vim.treesitter.add('borklang', { path = 'borkbork.so', silent = true })")) + eq(false, exec_lua("return pcall(vim.treesitter.add, 'borklang', { path = 'borkbork.so' })")) eq(".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) -- 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 ++++++++++++ test/functional/plugin/lsp/watchfiles_spec.lua | 173 ++++++++++ test/functional/plugin/lsp_spec.lua | 421 +++++++++++++++++++++++++ 3 files changed, 789 insertions(+) create mode 100644 test/functional/lua/watch_spec.lua create mode 100644 test/functional/plugin/lsp/watchfiles_spec.lua (limited to 'test/functional') 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) diff --git a/test/functional/plugin/lsp/watchfiles_spec.lua b/test/functional/plugin/lsp/watchfiles_spec.lua new file mode 100644 index 0000000000..c5d6803a7f --- /dev/null +++ b/test/functional/plugin/lsp/watchfiles_spec.lua @@ -0,0 +1,173 @@ +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local has_err = require('luassert').has.errors + +describe('vim.lsp._watchfiles', function() + before_each(helpers.clear) + after_each(helpers.clear) + + local match = function(...) + return exec_lua('return require("vim.lsp._watchfiles")._match(...)', ...) + end + + describe('glob matching', function() + it('should match literal strings', function() + eq(true, match('', '')) + eq(false, match('', 'a')) + eq(true, match('a', 'a')) + eq(true, match('abc', 'abc')) + eq(false, match('abc', 'abcdef')) + eq(false, match('abc', 'a')) + eq(false, match('a', 'b')) + eq(false, match('.', 'a')) + eq(true, match('$', '$')) + eq(false, match('dir/subdir', 'dir/subdir/file')) + end) + + it('should match * wildcards', function() + -- eq(false, match('*', '')) -- TODO: this fails + eq(true, match('*', 'a')) + eq(false, match('*', '/a')) + eq(false, match('*', 'a/')) + eq(true, match('*', 'aaa')) + eq(true, match('*.txt', 'file.txt')) + eq(false, match('*.txt', 'file.txtxt')) + eq(false, match('*.txt', 'dir/file.txt')) + eq(false, match('*.txt', '/dir/file.txt')) + eq(false, match('*.txt', 'C:/dir/file.txt')) + eq(false, match('*.dir', 'test.dir/file')) + eq(true, match('file.*', 'file.txt')) + eq(false, match('file.*', 'not-file.txt')) + eq(false, match('dir/*.txt', 'file.txt')) + eq(true, match('dir/*.txt', 'dir/file.txt')) + eq(false, match('dir/*.txt', 'dir/subdir/file.txt')) + end) + + it('should match ? wildcards', function() + eq(false, match('?', '')) + eq(true, match('?', 'a')) + eq(false, match('??', 'a')) + eq(false, match('?', 'ab')) + eq(true, match('??', 'ab')) + eq(true, match('a?c', 'abc')) + eq(false, match('a?c', 'a/c')) + end) + + it('should match ** wildcards', function() + eq(true, match('**', '')) + eq(true, match('**', 'a')) + eq(true, match('**', 'a/')) + eq(true, match('**', '/a')) + eq(true, match('**', 'C:/a')) + eq(true, match('**', 'a/a')) + eq(true, match('**', 'a/a/a')) + eq(false, match('a**', '')) + eq(true, match('a**', 'a')) + eq(true, match('a**', 'abcd')) + eq(false, match('a**', 'ba')) + eq(false, match('a**', 'a/b')) + eq(false, match('**a', '')) + eq(true, match('**a', 'a')) + eq(true, match('**a', 'dcba')) + eq(false, match('**a', 'ab')) + eq(false, match('**a', 'b/a')) + eq(false, match('a/**', '')) + eq(true, match('a/**', 'a')) + eq(true, match('a/**', 'a/b')) + eq(false, match('a/**', 'b/a')) + eq(false, match('a/**', '/a')) + eq(false, match('**/a', '')) + eq(true, match('**/a', 'a')) + eq(false, match('**/a', 'a/b')) + eq(true, match('**/a', '/a')) + eq(false, match('a/**/c', 'a')) + eq(false, match('a/**/c', 'c')) + eq(true, match('a/**/c', 'a/c')) + eq(true, match('a/**/c', 'a/b/c')) + eq(true, match('a/**/c', 'a/b/b/c')) + eq(true, match('**/a/**', 'a')) + eq(true, match('**/a/**', '/dir/a')) + eq(true, match('**/a/**', 'a/dir')) + eq(true, match('**/a/**', 'dir/a/dir')) + eq(true, match('**/a/**', '/a/dir')) + eq(true, match('**/a/**', 'C:/a/dir')) + -- eq(false, match('**/a/**', 'a.txt')) -- TODO: this fails + end) + + it('should match {} groups', function() + eq(false, match('{}', '')) + eq(true, match('{,}', '')) + eq(false, match('{}', 'a')) + eq(true, match('{a}', 'a')) + eq(false, match('{a}', 'aa')) + eq(false, match('{a}', 'ab')) + eq(false, match('{ab}', 'a')) + eq(true, match('{ab}', 'ab')) + eq(true, match('{a,b}', 'a')) + eq(true, match('{a,b}', 'b')) + eq(false, match('{a,b}', 'ab')) + eq(true, match('{ab,cd}', 'ab')) + eq(false, match('{ab,cd}', 'a')) + eq(true, match('{ab,cd}', 'cd')) + eq(true, match('{a,b,c}', 'c')) + eq(false, match('{a,{b,c}}', 'c')) -- {} can't nest + end) + + it('should match [] groups', function() + eq(true, match('[]', '')) + eq(false, match('[a-z]', '')) + eq(true, match('[a-z]', 'a')) + eq(false, match('[a-z]', 'ab')) + eq(true, match('[a-z]', 'z')) + eq(true, match('[a-z]', 'j')) + eq(false, match('[a-f]', 'j')) + eq(false, match('[a-z]', '`')) -- 'a' - 1 + eq(false, match('[a-z]', '{')) -- 'z' + 1 + eq(false, match('[a-z]', 'A')) + eq(false, match('[a-z]', '5')) + eq(true, match('[A-Z]', 'A')) + eq(true, match('[A-Z]', 'Z')) + eq(true, match('[A-Z]', 'J')) + eq(false, match('[A-Z]', '@')) -- 'A' - 1 + eq(false, match('[A-Z]', '[')) -- 'Z' + 1 + eq(false, match('[A-Z]', 'a')) + eq(false, match('[A-Z]', '5')) + eq(true, match('[a-zA-Z0-9]', 'z')) + eq(true, match('[a-zA-Z0-9]', 'Z')) + eq(true, match('[a-zA-Z0-9]', '9')) + eq(false, match('[a-zA-Z0-9]', '&')) + end) + + it('should match [!...] groups', function() + has_err(function() match('[!]', '') end) -- not a valid pattern + eq(false, match('[!a-z]', '')) + eq(false, match('[!a-z]', 'a')) + eq(false, match('[!a-z]', 'z')) + eq(false, match('[!a-z]', 'j')) + eq(true, match('[!a-f]', 'j')) + eq(false, match('[!a-f]', 'jj')) + eq(true, match('[!a-z]', '`')) -- 'a' - 1 + eq(true, match('[!a-z]', '{')) -- 'z' + 1 + eq(false, match('[!a-zA-Z0-9]', 'a')) + eq(false, match('[!a-zA-Z0-9]', 'A')) + eq(false, match('[!a-zA-Z0-9]', '0')) + eq(true, match('[!a-zA-Z0-9]', '!')) + end) + + it('should match complex patterns', function() + eq(false, match('**/*.{c,h}', '')) + eq(false, match('**/*.{c,h}', 'c')) + eq(true, match('**/*.{c,h}', 'file.c')) + eq(true, match('**/*.{c,h}', 'file.h')) + eq(true, match('**/*.{c,h}', '/file.c')) + eq(true, match('**/*.{c,h}', 'dir/subdir/file.c')) + eq(true, match('**/*.{c,h}', 'dir/subdir/file.h')) + + eq(true, match('{[0-9],[a-z]}', '0')) + eq(true, match('{[0-9],[a-z]}', 'a')) + eq(false, match('{[0-9],[a-z]}', 'A')) + end) + end) +end) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index f1aad08140..5eb367b0b8 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1,5 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) local lsp_helpers = require('test.functional.plugin.lsp.helpers') +local lfs = require('lfs') local assert_log = helpers.assert_log local buf_lines = helpers.buf_lines @@ -3589,4 +3590,424 @@ describe('LSP', function() eq(expected, result) end) end) + + describe('vim.lsp._watchfiles', function() + it('sends notifications when files change', function() + local root_dir = helpers.tmpname() + os.remove(root_dir) + lfs.mkdir(root_dir) + + exec_lua(create_server_definition) + local result = exec_lua([[ + local root_dir = ... + + local server = _create_server() + local client_id = vim.lsp.start({ + name = 'watchfiles-test', + cmd = server.cmd, + root_dir = root_dir, + }) + + local expected_messages = 2 -- initialize, initialized + + local msg_wait_timeout = require('vim.lsp._watchfiles')._watchfunc == vim._watch.poll and 2500 or 200 + local function wait_for_messages() + assert(vim.wait(msg_wait_timeout, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + end + + wait_for_messages() + + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-0', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = { + { + globPattern = '**/watch', + kind = 7, + }, + }, + }, + }, + }, + }, { client_id = client_id }) + + local path = root_dir .. '/watch' + local file = io.open(path, 'w') + file:close() + + expected_messages = expected_messages + 1 + wait_for_messages() + + os.remove(path) + + expected_messages = expected_messages + 1 + wait_for_messages() + + return server.messages + ]], root_dir) + + local function watched_uri(fname) + return exec_lua([[ + local root_dir, fname = ... + return vim.uri_from_fname(root_dir .. '/' .. fname) + ]], root_dir, fname) + end + + eq(4, #result) + eq('workspace/didChangeWatchedFiles', result[3].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('watch'), + }, + }, + }, result[3].params) + eq('workspace/didChangeWatchedFiles', result[4].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = watched_uri('watch'), + }, + }, + }, result[4].params) + end) + + it('correctly registers and unregisters', function() + local root_dir = 'some_dir' + exec_lua(create_server_definition) + local result = exec_lua([[ + local root_dir = ... + + local server = _create_server() + local client_id = vim.lsp.start({ + name = 'watchfiles-test', + cmd = server.cmd, + root_dir = root_dir, + }) + + local expected_messages = 2 -- initialize, initialized + local function wait_for_messages() + assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + end + + wait_for_messages() + + local send_event + require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) + local stoppped = false + send_event = function(...) + if not stoppped then + callback(...) + end + end + return function() + stoppped = true + end + end + + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-0', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = { + { + globPattern = '**/*.watch0', + }, + }, + }, + }, + }, + }, { client_id = client_id }) + + send_event(root_dir .. '/file.watch0', vim._watch.FileChangeType.Created) + send_event(root_dir .. '/file.watch1', vim._watch.FileChangeType.Created) + + expected_messages = expected_messages + 1 + wait_for_messages() + + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-1', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = { + { + globPattern = '**/*.watch1', + }, + }, + }, + }, + }, + }, { client_id = client_id }) + + vim.lsp.handlers['client/unregisterCapability'](nil, { + unregisterations = { + { + id = 'watchfiles-test-0', + method = 'workspace/didChangeWatchedFiles', + }, + }, + }, { client_id = client_id }) + + send_event(root_dir .. '/file.watch0', vim._watch.FileChangeType.Created) + send_event(root_dir .. '/file.watch1', vim._watch.FileChangeType.Created) + + expected_messages = expected_messages + 1 + wait_for_messages() + + return server.messages + ]], root_dir) + + local function watched_uri(fname) + return exec_lua([[ + local root_dir, fname = ... + return vim.uri_from_fname(root_dir .. '/' .. fname) + ]], root_dir, fname) + end + + eq(4, #result) + eq('workspace/didChangeWatchedFiles', result[3].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('file.watch0'), + }, + }, + }, result[3].params) + eq('workspace/didChangeWatchedFiles', result[4].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('file.watch1'), + }, + }, + }, result[4].params) + end) + + it('correctly handles the registered watch kind', function() + local root_dir = 'some_dir' + exec_lua(create_server_definition) + local result = exec_lua([[ + local root_dir = ... + + local server = _create_server() + local client_id = vim.lsp.start({ + name = 'watchfiles-test', + cmd = server.cmd, + root_dir = root_dir, + }) + + local expected_messages = 2 -- initialize, initialized + local function wait_for_messages() + assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + end + + wait_for_messages() + + local watch_callbacks = {} + local function send_event(...) + for _, cb in ipairs(watch_callbacks) do + cb(...) + end + end + require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) + table.insert(watch_callbacks, callback) + return function() + -- noop because this test never stops the watch + end + end + + local protocol = require('vim.lsp.protocol') + + local watchers = {} + local max_kind = protocol.WatchKind.Create + protocol.WatchKind.Change + protocol.WatchKind.Delete + for i = 0, max_kind do + local j = i + table.insert(watchers, { + globPattern = { + baseUri = vim.uri_from_fname('/dir'..tostring(i)), + pattern = 'watch'..tostring(i), + }, + kind = i, + }) + end + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-kind', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = watchers, + }, + }, + }, + }, { client_id = client_id }) + + for i = 0, max_kind do + local filename = 'watch'..tostring(i) + send_event(filename, vim._watch.FileChangeType.Created) + send_event(filename, vim._watch.FileChangeType.Changed) + send_event(filename, vim._watch.FileChangeType.Deleted) + end + + expected_messages = expected_messages + 1 + wait_for_messages() + + return server.messages + ]], root_dir) + + local function watched_uri(fname) + return exec_lua([[ + return vim.uri_from_fname(...) + ]], fname) + end + + eq(3, #result) + eq('workspace/didChangeWatchedFiles', result[3].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('watch1'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + uri = watched_uri('watch2'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('watch3'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + uri = watched_uri('watch3'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = watched_uri('watch4'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('watch5'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = watched_uri('watch5'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + uri = watched_uri('watch6'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = watched_uri('watch6'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('watch7'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + uri = watched_uri('watch7'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = watched_uri('watch7'), + }, + }, + }, result[3].params) + end) + + it('prunes duplicate events', function() + local root_dir = 'some_dir' + exec_lua(create_server_definition) + local result = exec_lua([[ + local root_dir = ... + + local server = _create_server() + local client_id = vim.lsp.start({ + name = 'watchfiles-test', + cmd = server.cmd, + root_dir = root_dir, + }) + + local expected_messages = 2 -- initialize, initialized + local function wait_for_messages() + assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + end + + wait_for_messages() + + local send_event + require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) + send_event = callback + return function() + -- noop because this test never stops the watch + end + end + + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-kind', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = { + { + globPattern = '**/*', + }, + }, + }, + }, + }, + }, { client_id = client_id }) + + send_event('file1', vim._watch.FileChangeType.Created) + send_event('file1', vim._watch.FileChangeType.Created) -- pruned + send_event('file1', vim._watch.FileChangeType.Changed) + send_event('file2', vim._watch.FileChangeType.Created) + send_event('file1', vim._watch.FileChangeType.Changed) -- pruned + + expected_messages = expected_messages + 1 + wait_for_messages() + + return server.messages + ]], root_dir) + + local function watched_uri(fname) + return exec_lua([[ + return vim.uri_from_fname(...) + ]], fname) + end + + eq(3, #result) + eq('workspace/didChangeWatchedFiles', result[3].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('file1'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + uri = watched_uri('file1'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('file2'), + }, + }, + }, result[3].params) + 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 ------------ test/functional/plugin/lsp/watchfiles_spec.lua | 173 ---------- test/functional/plugin/lsp_spec.lua | 421 ------------------------- 3 files changed, 789 deletions(-) delete mode 100644 test/functional/lua/watch_spec.lua delete mode 100644 test/functional/plugin/lsp/watchfiles_spec.lua (limited to 'test/functional') 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) diff --git a/test/functional/plugin/lsp/watchfiles_spec.lua b/test/functional/plugin/lsp/watchfiles_spec.lua deleted file mode 100644 index c5d6803a7f..0000000000 --- a/test/functional/plugin/lsp/watchfiles_spec.lua +++ /dev/null @@ -1,173 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local eq = helpers.eq -local exec_lua = helpers.exec_lua -local has_err = require('luassert').has.errors - -describe('vim.lsp._watchfiles', function() - before_each(helpers.clear) - after_each(helpers.clear) - - local match = function(...) - return exec_lua('return require("vim.lsp._watchfiles")._match(...)', ...) - end - - describe('glob matching', function() - it('should match literal strings', function() - eq(true, match('', '')) - eq(false, match('', 'a')) - eq(true, match('a', 'a')) - eq(true, match('abc', 'abc')) - eq(false, match('abc', 'abcdef')) - eq(false, match('abc', 'a')) - eq(false, match('a', 'b')) - eq(false, match('.', 'a')) - eq(true, match('$', '$')) - eq(false, match('dir/subdir', 'dir/subdir/file')) - end) - - it('should match * wildcards', function() - -- eq(false, match('*', '')) -- TODO: this fails - eq(true, match('*', 'a')) - eq(false, match('*', '/a')) - eq(false, match('*', 'a/')) - eq(true, match('*', 'aaa')) - eq(true, match('*.txt', 'file.txt')) - eq(false, match('*.txt', 'file.txtxt')) - eq(false, match('*.txt', 'dir/file.txt')) - eq(false, match('*.txt', '/dir/file.txt')) - eq(false, match('*.txt', 'C:/dir/file.txt')) - eq(false, match('*.dir', 'test.dir/file')) - eq(true, match('file.*', 'file.txt')) - eq(false, match('file.*', 'not-file.txt')) - eq(false, match('dir/*.txt', 'file.txt')) - eq(true, match('dir/*.txt', 'dir/file.txt')) - eq(false, match('dir/*.txt', 'dir/subdir/file.txt')) - end) - - it('should match ? wildcards', function() - eq(false, match('?', '')) - eq(true, match('?', 'a')) - eq(false, match('??', 'a')) - eq(false, match('?', 'ab')) - eq(true, match('??', 'ab')) - eq(true, match('a?c', 'abc')) - eq(false, match('a?c', 'a/c')) - end) - - it('should match ** wildcards', function() - eq(true, match('**', '')) - eq(true, match('**', 'a')) - eq(true, match('**', 'a/')) - eq(true, match('**', '/a')) - eq(true, match('**', 'C:/a')) - eq(true, match('**', 'a/a')) - eq(true, match('**', 'a/a/a')) - eq(false, match('a**', '')) - eq(true, match('a**', 'a')) - eq(true, match('a**', 'abcd')) - eq(false, match('a**', 'ba')) - eq(false, match('a**', 'a/b')) - eq(false, match('**a', '')) - eq(true, match('**a', 'a')) - eq(true, match('**a', 'dcba')) - eq(false, match('**a', 'ab')) - eq(false, match('**a', 'b/a')) - eq(false, match('a/**', '')) - eq(true, match('a/**', 'a')) - eq(true, match('a/**', 'a/b')) - eq(false, match('a/**', 'b/a')) - eq(false, match('a/**', '/a')) - eq(false, match('**/a', '')) - eq(true, match('**/a', 'a')) - eq(false, match('**/a', 'a/b')) - eq(true, match('**/a', '/a')) - eq(false, match('a/**/c', 'a')) - eq(false, match('a/**/c', 'c')) - eq(true, match('a/**/c', 'a/c')) - eq(true, match('a/**/c', 'a/b/c')) - eq(true, match('a/**/c', 'a/b/b/c')) - eq(true, match('**/a/**', 'a')) - eq(true, match('**/a/**', '/dir/a')) - eq(true, match('**/a/**', 'a/dir')) - eq(true, match('**/a/**', 'dir/a/dir')) - eq(true, match('**/a/**', '/a/dir')) - eq(true, match('**/a/**', 'C:/a/dir')) - -- eq(false, match('**/a/**', 'a.txt')) -- TODO: this fails - end) - - it('should match {} groups', function() - eq(false, match('{}', '')) - eq(true, match('{,}', '')) - eq(false, match('{}', 'a')) - eq(true, match('{a}', 'a')) - eq(false, match('{a}', 'aa')) - eq(false, match('{a}', 'ab')) - eq(false, match('{ab}', 'a')) - eq(true, match('{ab}', 'ab')) - eq(true, match('{a,b}', 'a')) - eq(true, match('{a,b}', 'b')) - eq(false, match('{a,b}', 'ab')) - eq(true, match('{ab,cd}', 'ab')) - eq(false, match('{ab,cd}', 'a')) - eq(true, match('{ab,cd}', 'cd')) - eq(true, match('{a,b,c}', 'c')) - eq(false, match('{a,{b,c}}', 'c')) -- {} can't nest - end) - - it('should match [] groups', function() - eq(true, match('[]', '')) - eq(false, match('[a-z]', '')) - eq(true, match('[a-z]', 'a')) - eq(false, match('[a-z]', 'ab')) - eq(true, match('[a-z]', 'z')) - eq(true, match('[a-z]', 'j')) - eq(false, match('[a-f]', 'j')) - eq(false, match('[a-z]', '`')) -- 'a' - 1 - eq(false, match('[a-z]', '{')) -- 'z' + 1 - eq(false, match('[a-z]', 'A')) - eq(false, match('[a-z]', '5')) - eq(true, match('[A-Z]', 'A')) - eq(true, match('[A-Z]', 'Z')) - eq(true, match('[A-Z]', 'J')) - eq(false, match('[A-Z]', '@')) -- 'A' - 1 - eq(false, match('[A-Z]', '[')) -- 'Z' + 1 - eq(false, match('[A-Z]', 'a')) - eq(false, match('[A-Z]', '5')) - eq(true, match('[a-zA-Z0-9]', 'z')) - eq(true, match('[a-zA-Z0-9]', 'Z')) - eq(true, match('[a-zA-Z0-9]', '9')) - eq(false, match('[a-zA-Z0-9]', '&')) - end) - - it('should match [!...] groups', function() - has_err(function() match('[!]', '') end) -- not a valid pattern - eq(false, match('[!a-z]', '')) - eq(false, match('[!a-z]', 'a')) - eq(false, match('[!a-z]', 'z')) - eq(false, match('[!a-z]', 'j')) - eq(true, match('[!a-f]', 'j')) - eq(false, match('[!a-f]', 'jj')) - eq(true, match('[!a-z]', '`')) -- 'a' - 1 - eq(true, match('[!a-z]', '{')) -- 'z' + 1 - eq(false, match('[!a-zA-Z0-9]', 'a')) - eq(false, match('[!a-zA-Z0-9]', 'A')) - eq(false, match('[!a-zA-Z0-9]', '0')) - eq(true, match('[!a-zA-Z0-9]', '!')) - end) - - it('should match complex patterns', function() - eq(false, match('**/*.{c,h}', '')) - eq(false, match('**/*.{c,h}', 'c')) - eq(true, match('**/*.{c,h}', 'file.c')) - eq(true, match('**/*.{c,h}', 'file.h')) - eq(true, match('**/*.{c,h}', '/file.c')) - eq(true, match('**/*.{c,h}', 'dir/subdir/file.c')) - eq(true, match('**/*.{c,h}', 'dir/subdir/file.h')) - - eq(true, match('{[0-9],[a-z]}', '0')) - eq(true, match('{[0-9],[a-z]}', 'a')) - eq(false, match('{[0-9],[a-z]}', 'A')) - end) - end) -end) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 5eb367b0b8..f1aad08140 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1,6 +1,5 @@ local helpers = require('test.functional.helpers')(after_each) local lsp_helpers = require('test.functional.plugin.lsp.helpers') -local lfs = require('lfs') local assert_log = helpers.assert_log local buf_lines = helpers.buf_lines @@ -3590,424 +3589,4 @@ describe('LSP', function() eq(expected, result) end) end) - - describe('vim.lsp._watchfiles', function() - it('sends notifications when files change', function() - local root_dir = helpers.tmpname() - os.remove(root_dir) - lfs.mkdir(root_dir) - - exec_lua(create_server_definition) - local result = exec_lua([[ - local root_dir = ... - - local server = _create_server() - local client_id = vim.lsp.start({ - name = 'watchfiles-test', - cmd = server.cmd, - root_dir = root_dir, - }) - - local expected_messages = 2 -- initialize, initialized - - local msg_wait_timeout = require('vim.lsp._watchfiles')._watchfunc == vim._watch.poll and 2500 or 200 - local function wait_for_messages() - assert(vim.wait(msg_wait_timeout, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) - end - - wait_for_messages() - - vim.lsp.handlers['client/registerCapability'](nil, { - registrations = { - { - id = 'watchfiles-test-0', - method = 'workspace/didChangeWatchedFiles', - registerOptions = { - watchers = { - { - globPattern = '**/watch', - kind = 7, - }, - }, - }, - }, - }, - }, { client_id = client_id }) - - local path = root_dir .. '/watch' - local file = io.open(path, 'w') - file:close() - - expected_messages = expected_messages + 1 - wait_for_messages() - - os.remove(path) - - expected_messages = expected_messages + 1 - wait_for_messages() - - return server.messages - ]], root_dir) - - local function watched_uri(fname) - return exec_lua([[ - local root_dir, fname = ... - return vim.uri_from_fname(root_dir .. '/' .. fname) - ]], root_dir, fname) - end - - eq(4, #result) - eq('workspace/didChangeWatchedFiles', result[3].method) - eq({ - changes = { - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), - uri = watched_uri('watch'), - }, - }, - }, result[3].params) - eq('workspace/didChangeWatchedFiles', result[4].method) - eq({ - changes = { - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), - uri = watched_uri('watch'), - }, - }, - }, result[4].params) - end) - - it('correctly registers and unregisters', function() - local root_dir = 'some_dir' - exec_lua(create_server_definition) - local result = exec_lua([[ - local root_dir = ... - - local server = _create_server() - local client_id = vim.lsp.start({ - name = 'watchfiles-test', - cmd = server.cmd, - root_dir = root_dir, - }) - - local expected_messages = 2 -- initialize, initialized - local function wait_for_messages() - assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) - end - - wait_for_messages() - - local send_event - require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) - local stoppped = false - send_event = function(...) - if not stoppped then - callback(...) - end - end - return function() - stoppped = true - end - end - - vim.lsp.handlers['client/registerCapability'](nil, { - registrations = { - { - id = 'watchfiles-test-0', - method = 'workspace/didChangeWatchedFiles', - registerOptions = { - watchers = { - { - globPattern = '**/*.watch0', - }, - }, - }, - }, - }, - }, { client_id = client_id }) - - send_event(root_dir .. '/file.watch0', vim._watch.FileChangeType.Created) - send_event(root_dir .. '/file.watch1', vim._watch.FileChangeType.Created) - - expected_messages = expected_messages + 1 - wait_for_messages() - - vim.lsp.handlers['client/registerCapability'](nil, { - registrations = { - { - id = 'watchfiles-test-1', - method = 'workspace/didChangeWatchedFiles', - registerOptions = { - watchers = { - { - globPattern = '**/*.watch1', - }, - }, - }, - }, - }, - }, { client_id = client_id }) - - vim.lsp.handlers['client/unregisterCapability'](nil, { - unregisterations = { - { - id = 'watchfiles-test-0', - method = 'workspace/didChangeWatchedFiles', - }, - }, - }, { client_id = client_id }) - - send_event(root_dir .. '/file.watch0', vim._watch.FileChangeType.Created) - send_event(root_dir .. '/file.watch1', vim._watch.FileChangeType.Created) - - expected_messages = expected_messages + 1 - wait_for_messages() - - return server.messages - ]], root_dir) - - local function watched_uri(fname) - return exec_lua([[ - local root_dir, fname = ... - return vim.uri_from_fname(root_dir .. '/' .. fname) - ]], root_dir, fname) - end - - eq(4, #result) - eq('workspace/didChangeWatchedFiles', result[3].method) - eq({ - changes = { - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), - uri = watched_uri('file.watch0'), - }, - }, - }, result[3].params) - eq('workspace/didChangeWatchedFiles', result[4].method) - eq({ - changes = { - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), - uri = watched_uri('file.watch1'), - }, - }, - }, result[4].params) - end) - - it('correctly handles the registered watch kind', function() - local root_dir = 'some_dir' - exec_lua(create_server_definition) - local result = exec_lua([[ - local root_dir = ... - - local server = _create_server() - local client_id = vim.lsp.start({ - name = 'watchfiles-test', - cmd = server.cmd, - root_dir = root_dir, - }) - - local expected_messages = 2 -- initialize, initialized - local function wait_for_messages() - assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) - end - - wait_for_messages() - - local watch_callbacks = {} - local function send_event(...) - for _, cb in ipairs(watch_callbacks) do - cb(...) - end - end - require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) - table.insert(watch_callbacks, callback) - return function() - -- noop because this test never stops the watch - end - end - - local protocol = require('vim.lsp.protocol') - - local watchers = {} - local max_kind = protocol.WatchKind.Create + protocol.WatchKind.Change + protocol.WatchKind.Delete - for i = 0, max_kind do - local j = i - table.insert(watchers, { - globPattern = { - baseUri = vim.uri_from_fname('/dir'..tostring(i)), - pattern = 'watch'..tostring(i), - }, - kind = i, - }) - end - vim.lsp.handlers['client/registerCapability'](nil, { - registrations = { - { - id = 'watchfiles-test-kind', - method = 'workspace/didChangeWatchedFiles', - registerOptions = { - watchers = watchers, - }, - }, - }, - }, { client_id = client_id }) - - for i = 0, max_kind do - local filename = 'watch'..tostring(i) - send_event(filename, vim._watch.FileChangeType.Created) - send_event(filename, vim._watch.FileChangeType.Changed) - send_event(filename, vim._watch.FileChangeType.Deleted) - end - - expected_messages = expected_messages + 1 - wait_for_messages() - - return server.messages - ]], root_dir) - - local function watched_uri(fname) - return exec_lua([[ - return vim.uri_from_fname(...) - ]], fname) - end - - eq(3, #result) - eq('workspace/didChangeWatchedFiles', result[3].method) - eq({ - changes = { - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), - uri = watched_uri('watch1'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), - uri = watched_uri('watch2'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), - uri = watched_uri('watch3'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), - uri = watched_uri('watch3'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), - uri = watched_uri('watch4'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), - uri = watched_uri('watch5'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), - uri = watched_uri('watch5'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), - uri = watched_uri('watch6'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), - uri = watched_uri('watch6'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), - uri = watched_uri('watch7'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), - uri = watched_uri('watch7'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), - uri = watched_uri('watch7'), - }, - }, - }, result[3].params) - end) - - it('prunes duplicate events', function() - local root_dir = 'some_dir' - exec_lua(create_server_definition) - local result = exec_lua([[ - local root_dir = ... - - local server = _create_server() - local client_id = vim.lsp.start({ - name = 'watchfiles-test', - cmd = server.cmd, - root_dir = root_dir, - }) - - local expected_messages = 2 -- initialize, initialized - local function wait_for_messages() - assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) - end - - wait_for_messages() - - local send_event - require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) - send_event = callback - return function() - -- noop because this test never stops the watch - end - end - - vim.lsp.handlers['client/registerCapability'](nil, { - registrations = { - { - id = 'watchfiles-test-kind', - method = 'workspace/didChangeWatchedFiles', - registerOptions = { - watchers = { - { - globPattern = '**/*', - }, - }, - }, - }, - }, - }, { client_id = client_id }) - - send_event('file1', vim._watch.FileChangeType.Created) - send_event('file1', vim._watch.FileChangeType.Created) -- pruned - send_event('file1', vim._watch.FileChangeType.Changed) - send_event('file2', vim._watch.FileChangeType.Created) - send_event('file1', vim._watch.FileChangeType.Changed) -- pruned - - expected_messages = expected_messages + 1 - wait_for_messages() - - return server.messages - ]], root_dir) - - local function watched_uri(fname) - return exec_lua([[ - return vim.uri_from_fname(...) - ]], fname) - end - - eq(3, #result) - eq('workspace/didChangeWatchedFiles', result[3].method) - eq({ - changes = { - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), - uri = watched_uri('file1'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), - uri = watched_uri('file1'), - }, - { - type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), - uri = watched_uri('file2'), - }, - }, - }, result[3].params) - end) - end) end) -- cgit From 7f424e2b65779c59fc0cac3cc7508ba2ec07f200 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 23 Feb 2023 18:29:36 +0100 Subject: feat(api): more fields in nvim_list_uis Problem: nvim_list_uis does not report all ":help ui-option" fields. Solution: Store ":help ui-option" fields on the `UI` object and update ui_array. --- test/functional/api/vim_spec.lua | 18 +++++++++++------ test/functional/terminal/tui_spec.lua | 37 ++++++++++++++++++++++++----------- 2 files changed, 38 insertions(+), 17 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 3e40967dd5..08abf82f47 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -2549,20 +2549,26 @@ describe('API', function() { chan = 1, ext_cmdline = false, - ext_popupmenu = false, - ext_tabline = false, - ext_wildmenu = false, + ext_hlstate = false, ext_linegrid = screen._options.ext_linegrid or false, + ext_messages = false, ext_multigrid = false, - ext_hlstate = false, + ext_popupmenu = false, + ext_tabline = false, ext_termcolors = false, - ext_messages = false, + ext_wildmenu = false, height = 4, - rgb = true, override = true, + rgb = true, + stdin_tty = false, + stdout_tty = false, + term_background = '', + term_colors = 0, + term_name = '', width = 20, } } + eq(expected, nvim("list_uis")) screen:detach() diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 792ad63e76..9db80e0db2 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1398,17 +1398,32 @@ describe('TUI', function() ]]} end) - it('is included in nvim_list_uis()', function() - feed_data(':echo map(nvim_list_uis(), {k,v -> sort(items(filter(v, {k,v -> k[:3] !=# "ext_" })))})\r') - screen:expect([=[ - | - {4:~ }| - {5: }| - [[['chan', 1], ['height', 6], ['override', v:false| - ], ['rgb', v:false], ['width', 50]]] | - {10:Press ENTER or type command to continue}{1: } | - {3:-- TERMINAL --} | - ]=]) + it('in nvim_list_uis()', function() + local expected = { + { + chan = 1, + ext_cmdline = false, + ext_hlstate = false, + ext_linegrid = true, + ext_messages = false, + ext_multigrid = false, + ext_popupmenu = false, + ext_tabline = false, + ext_termcolors = true, + ext_wildmenu = false, + height = 6, + override = false, + rgb = false, + stdin_tty = true, + stdout_tty = true, + term_background = '', + term_colors = 256, + term_name = 'xterm-256color', -- $TERM in :terminal. + width = 50 + }, + } + local _, rv = child_session:request('nvim_list_uis') + eq(expected, rv) end) it('allows grid to assume wider ambiguous-width characters than host terminal #19686', function() -- cgit From ce597235a26839826de88ecd8b949ec54c310fbd Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Mon, 27 Feb 2023 16:31:05 +0100 Subject: feat(ui): restore has('gui_running') Problem: has('gui_running') is still common in the wild and our answer has changed over time, causing frustration. https://github.com/vimpostor/vim-tpipeline/commit/95a6ccbe9f33bc42dd4cee45731d8bc3fbcd92d1 Solution: Use stdin_tty/stdout_tty to decide if a UI is (not) a GUI. --- test/functional/terminal/tui_spec.lua | 4 +++- test/functional/vimscript/has_spec.lua | 21 +++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 9db80e0db2..76ea6256a1 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1399,6 +1399,8 @@ describe('TUI', function() end) it('in nvim_list_uis()', function() + -- $TERM in :terminal. + local exp_term = is_os('bsd') and 'builtin_xterm' or 'xterm-256color' local expected = { { chan = 1, @@ -1418,7 +1420,7 @@ describe('TUI', function() stdout_tty = true, term_background = '', term_colors = 256, - term_name = 'xterm-256color', -- $TERM in :terminal. + term_name = exp_term, width = 50 }, } diff --git a/test/functional/vimscript/has_spec.lua b/test/functional/vimscript/has_spec.lua index 2e26d603b3..78a761d370 100644 --- a/test/functional/vimscript/has_spec.lua +++ b/test/functional/vimscript/has_spec.lua @@ -1,8 +1,11 @@ local helpers = require('test.functional.helpers')(after_each) -local eq = helpers.eq +local Screen = require('test.functional.ui.screen') local clear = helpers.clear +local connect = helpers.connect +local eq = helpers.eq local funcs = helpers.funcs local is_os = helpers.is_os +local nvim_prog = helpers.nvim_prog describe('has()', function() before_each(clear) @@ -69,8 +72,22 @@ describe('has()', function() end end) + it('"gui_running"', function() + eq(0, funcs.has('gui_running')) + local tui = Screen.new(50,15) + local gui_session = connect(funcs.serverstart()) + local gui = Screen.new(50,15) + eq(0, funcs.has('gui_running')) + tui:attach({ext_linegrid=true, rgb=true, stdin_tty=true, stdout_tty=true}) + gui:attach({ext_multigrid=true, rgb=true}, gui_session) + eq(1, funcs.has('gui_running')) + tui:detach() + eq(1, funcs.has('gui_running')) + gui:detach() + eq(0, funcs.has('gui_running')) + end) + it('does not change v:shell_error', function() - local nvim_prog = helpers.nvim_prog funcs.system({nvim_prog, '-es', '+73cquit'}) funcs.has('python3') -- use a call whose implementation shells out eq(73, funcs.eval('v:shell_error')) -- cgit From 2630341db65772e0a636c2a1cfbd6bba8ca9b28d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 Feb 2023 07:19:03 +0800 Subject: fix(tui): avoid stack-use-after-scope with cursor color (#22435) --- test/functional/terminal/tui_spec.lua | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'test/functional') diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 792ad63e76..bbcf5ecad7 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -1512,6 +1512,42 @@ describe('TUI', function() exec_lua([[vim.loop.kill(vim.fn.jobpid(vim.bo.channel), 'sigterm')]]) screen:expect({any = '%[Process exited 1%]'}) end) + + it('no stack-use-after-scope with cursor color #22432', function() + screen:set_option('rgb', true) + command('set termguicolors') + child_session:request('nvim_exec', [[ + set tgc + hi Cursor guifg=Red guibg=Green + set guicursor=n:block-Cursor/lCursor + ]], false) + screen:set_default_attr_ids({ + [1] = {reverse = true}, + [2] = {bold = true, foreground = Screen.colors.Blue}, + [3] = {foreground = Screen.colors.Blue}, + [4] = {reverse = true, bold = true}, + [5] = {bold = true}, + }) + screen:expect([[ + {1: } | + {2:~}{3: }| + {2:~}{3: }| + {2:~}{3: }| + {4:[No Name] }| + | + {5:-- TERMINAL --} | + ]]) + feed('i') + screen:expect([[ + {1: } | + {2:~}{3: }| + {2:~}{3: }| + {2:~}{3: }| + {4:[No Name] }| + {5:-- INSERT --} | + {5:-- TERMINAL --} | + ]]) + end) end) describe('TUI', function() -- cgit From 9a271f6afd7a9b1c17d694b57ee1f489496000aa Mon Sep 17 00:00:00 2001 From: luukvbaal <31730729+luukvbaal@users.noreply.github.com> Date: Tue, 28 Feb 2023 03:19:58 +0100 Subject: fix(column): cmdwin cursor is offset with 'statuscolumn' (#22445) --- test/functional/ui/statuscolumn_spec.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index 287686cf37..f997546c7c 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -478,4 +478,24 @@ describe('statuscolumn', function() | ]]) end) + + it('works with cmdwin', function() + feed(':set stc=%lq:k$') + screen:expect([[ + 7 aaaaa | + 8 aaaaa | + 9 aaaaa | + 10aaaaa | + [No Name] [+] | + :1set stc=%^l | + :2 | + ~ | + ~ | + ~ | + ~ | + ~ | + [Command Line] | + : | + ]]) + end) end) -- cgit From 7e19cabeb192d2e7f20d7bb965a3f62e1543d2ac Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 28 Feb 2023 12:38:33 +0100 Subject: perf(lsp): only redraw the windows containing LSP tokens redraw! redraws the entire screen instead of just the windows with the buffer which were actually changed. I considered trying to calculating the range for the delta but it looks tricky. Could a follow-up. --- .../functional/plugin/lsp/semantic_tokens_spec.lua | 160 ++++++++++++++++++--- 1 file changed, 143 insertions(+), 17 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index 9c1ba86fe1..004fce4983 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -24,6 +24,25 @@ end) describe('semantic token highlighting', function() + local screen + before_each(function() + screen = Screen.new(40, 16) + screen:attach() + screen:set_default_attr_ids { + [1] = { bold = true, foreground = Screen.colors.Blue1 }; + [2] = { foreground = Screen.colors.DarkCyan }; + [3] = { foreground = Screen.colors.SlateBlue }; + [4] = { bold = true, foreground = Screen.colors.SeaGreen }; + [5] = { foreground = tonumber('0x6a0dad') }; + [6] = { foreground = Screen.colors.Blue1 }; + [7] = { bold = true, foreground = Screen.colors.DarkCyan }; + [8] = { bold = true, foreground = Screen.colors.SlateBlue }; + } + command([[ hi link @namespace Type ]]) + command([[ hi link @function Special ]]) + command([[ hi @declaration gui=bold ]]) + end) + describe('general', function() local text = dedent([[ #include @@ -58,24 +77,7 @@ describe('semantic token highlighting', function() "resultId":"2" }]] - local screen before_each(function() - screen = Screen.new(40, 16) - screen:attach() - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }; - [2] = { foreground = Screen.colors.DarkCyan }; - [3] = { foreground = Screen.colors.SlateBlue }; - [4] = { bold = true, foreground = Screen.colors.SeaGreen }; - [5] = { foreground = tonumber('0x6a0dad') }; - [6] = { foreground = Screen.colors.Blue1 }; - [7] = { bold = true, foreground = Screen.colors.DarkCyan }; - [8] = { bold = true, foreground = Screen.colors.SlateBlue }; - } - command([[ hi link @namespace Type ]]) - command([[ hi link @function Special ]]) - command([[ hi @declaration gui=bold ]]) - exec_lua(create_server_definition) exec_lua([[ local legend, response, edit_response = ... @@ -928,6 +930,46 @@ b = "as"]], extmark_added = true, } }, + expected_screen1 = function() + screen:expect{grid=[[ + char* {7:foo} = "\n"^; | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end, + expected_screen2 = function() + screen:expect{grid=[[ + ^ | + char* {7:foo} = "\n"; | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end, }, { it = 'response with multiple delta edits', @@ -1127,6 +1169,46 @@ int main() extmark_added = true, } }, + expected_screen1 = function() + screen:expect{grid=[[ + #include | + | + int {8:main}() | + { | + int {7:x}; | + #ifdef {5:__cplusplus} | + {4:std}::{2:cout} << {2:x} << "\n"; | + {6:#else} | + {6: printf("%d\n", x);} | + {6:#endif} | + ^} | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end, + expected_screen2 = function() + screen:expect{grid=[[ + #include | + | + int {8:main}() | + { | + int {8:x}(); | + double {7:y}; | + #ifdef {5:__cplusplus} | + {4:std}::{2:cout} << {3:x} << "\n"; | + {6:#else} | + {6: printf("%d\n", x);} | + {6:^#endif} | + } | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end, }, { it = 'optional token_edit.data on deletion', @@ -1156,6 +1238,46 @@ int main() }, expected2 = { }, + expected_screen1 = function() + screen:expect{grid=[[ + {7:string} = "test^" | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end, + expected_screen2 = function() + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + end, }, }) do it(test.it, function() @@ -1192,6 +1314,8 @@ int main() insert(test.text1) + test.expected_screen1() + local highlights = exec_lua([[ return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights ]]) @@ -1208,6 +1332,8 @@ int main() ]], test.text2) end + test.expected_screen2() + highlights = exec_lua([[ return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights ]]) -- cgit From aa840ab5668aa9bc013461a48da771f778b39e49 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 1 Mar 2023 09:56:25 +0800 Subject: test(termxx_spec): fix TermClose bdelete test flakiness (#22463) Problem: If shell-test finishes before the next RPC call, TermClose has already been triggered, so the test fails. Solution: Add INTERACT argument so that shell-test keeps running. --- test/functional/autocmd/termxx_spec.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test/functional') diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua index 0a33f1b2ac..63b5617eef 100644 --- a/test/functional/autocmd/termxx_spec.lua +++ b/test/functional/autocmd/termxx_spec.lua @@ -22,6 +22,8 @@ describe('autocmd TermClose', function() local function test_termclose_delete_own_buf() + -- The terminal process needs to keep running so that TermClose isn't triggered immediately. + nvim('set_option', 'shell', string.format('"%s" INTERACT', testprg('shell-test'))) command('autocmd TermClose * bdelete!') command('terminal') matches('^TermClose Autocommands for "%*": Vim%(bdelete%):E937: Attempt to delete a buffer that is in use: term://', -- cgit From d66832c76d6fce1627c33ae60a1b8efec1e32bdd Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 1 Mar 2023 20:16:57 +0800 Subject: test(ui): wait for another success with failure after success Problem: In a success-failure-success situation, if minimal timeout is reached between the failure and the second success, the session is stopped without waiting for the second success, causing the test to fail. Solution: Wait for another success if a failure is seen after a success. Ref #22155 #22464 --- test/functional/ui/screen.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test/functional') diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 14ce050578..e5a449fa66 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -557,6 +557,7 @@ function Screen:_wait(check, flags) self._session:stop() end elseif success_seen and #args > 0 then + success_seen = false failure_after_success = true -- print(inspect(args)) end -- cgit From 896d672736b32a8f4a4fa51844b44f266dcdcc6c Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Wed, 1 Mar 2023 15:33:13 +0100 Subject: fix(lsp): use buffer scheme for files not stored on disk (#22407) Sending `didOpen` with a `file` scheme causes problems with some language servers because they expect the file to exist on disk. See https://github.com/microsoft/language-server-protocol/pull/1679 --- test/functional/fixtures/fake-lsp-server.lua | 37 ++++++++++++++++------------ 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'test/functional') diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index db0c8c0c3f..dbb66a42e8 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -272,6 +272,7 @@ function tests.text_document_save_did_open() end; body = function() notify('start') + expect_notification('textDocument/didClose') expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave') notify('shutdown') @@ -292,6 +293,8 @@ function tests.text_document_sync_save_bool() end; body = function() notify('start') + expect_notification('textDocument/didClose') + expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave', {textDocument = { uri = "file://" }}) notify('shutdown') end; @@ -313,6 +316,8 @@ function tests.text_document_sync_save_includeText() end; body = function() notify('start') + expect_notification('textDocument/didClose') + expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave', { textDocument = { uri = "file://" @@ -459,7 +464,7 @@ function tests.basic_check_buffer_open() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; + uri = "buffer://"; version = 0; }; }) @@ -486,13 +491,13 @@ function tests.basic_check_buffer_open_and_change() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { @@ -522,13 +527,13 @@ function tests.basic_check_buffer_open_and_change_noeol() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n"); - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { @@ -557,13 +562,13 @@ function tests.basic_check_buffer_open_and_change_multi() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { @@ -572,7 +577,7 @@ function tests.basic_check_buffer_open_and_change_multi() }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 4; }; contentChanges = { @@ -602,13 +607,13 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { @@ -617,7 +622,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 4; }; contentChanges = { @@ -626,7 +631,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() }) expect_notification('textDocument/didClose', { textDocument = { - uri = "file://"; + uri = "buffer://"; }; }) expect_notification("finish") @@ -660,13 +665,13 @@ function tests.basic_check_buffer_open_and_change_incremental() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { @@ -703,13 +708,13 @@ function tests.basic_check_buffer_open_and_change_incremental_editing() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n"); - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { -- 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') 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 fb1db80f5ab707e188be3c60539fa38eaf996f24 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 2 Mar 2023 14:42:15 +0800 Subject: test(treesitter/parser_spec): correct time unit (#22471) --- test/functional/treesitter/parser_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 67aad4d1b7..fd9822d1c0 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -182,9 +182,9 @@ void ui_refresh(void) local firstrun = q(1) local manyruns = q(100) - local factor = is_os('win') and 3 or 4 - -- First run should be at least 4x slower. - assert(factor * 100 * manyruns < firstrun, ('firstrun: %d ms, manyruns: %d ms'):format(firstrun / 1000, manyruns / 1000)) + -- First run should be at least 400x slower than an 100 subsequent runs. + local factor = is_os('win') and 300 or 400 + assert(factor * manyruns < firstrun, ('firstrun: %f ms, manyruns: %f ms'):format(firstrun / 1e6, manyruns / 1e6)) end) it('support query and iter by capture', function() -- cgit From 6d4f48182131c36d57589eefd4cefe3c70256d04 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 3 Mar 2023 09:44:02 +0000 Subject: fix(treesitter): disallow empty filetypes Fixes #22473 --- test/functional/treesitter/language_spec.lua | 7 ++++++- test/functional/treesitter/parser_spec.lua | 14 +++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 2cf18242ff..747aea54b7 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -33,7 +33,12 @@ describe('treesitter language API', function() it('shows error for invalid language name', function() eq(".../language.lua:0: '/foo/' is not a valid language name", - pcall_err(exec_lua, 'vim.treesitter.add("/foo/", nil, false)')) + pcall_err(exec_lua, 'vim.treesitter.add("/foo/")')) + end) + + it('shows error for invalid filetype', function() + eq('.../language.lua:0: \'\' is not a valid filetype', + pcall_err(exec_lua, [[vim.treesitter.add('foo', { filetype = '' })]])) end) it('inspects language', function() diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index fd9822d1c0..27f2e81ab2 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -4,6 +4,7 @@ local clear = helpers.clear local eq = helpers.eq local insert = helpers.insert local exec_lua = helpers.exec_lua +local pcall_err = helpers.pcall_err local feed = helpers.feed local is_os = helpers.is_os local skip = helpers.skip @@ -124,6 +125,16 @@ void ui_refresh(void) }, res) end) + it('does not get parser for empty filetype', function() + insert(test_text); + + eq(".../language.lua:0: '' is not a valid filetype", + pcall_err(exec_lua, 'vim.treesitter.get_parser(0)')) + + -- Must provide language for buffers with an empty filetype + exec_lua("vim.treesitter.get_parser(0, 'c')") + end) + it('allows to get a child by field', function() insert(test_text); @@ -874,9 +885,10 @@ int x = INT_MAX; it("can fold via foldexpr", function() insert(test_text) - exec_lua([[vim.treesitter.get_parser(0, "c")]]) local levels = exec_lua([[ + vim.opt.filetype = 'c' + vim.treesitter.get_parser(0, "c") local res = {} for i = 1, vim.api.nvim_buf_line_count(0) do res[i] = vim.treesitter.foldexpr(i) -- cgit From b7d59649acf43c76cc72b25c04bcae926a40b4fe Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 4 Mar 2023 12:23:04 +0800 Subject: fix(redraw): get the line again after evaluating something --- test/functional/ui/statuscolumn_spec.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index f997546c7c..08b5d1913b 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -375,6 +375,28 @@ describe('statuscolumn', function() {1:wrapped 1 9}aaaaaaaa | | ]]) + -- Also test virt_lines at the end of buffer + exec_lua([[ + local ns = vim.api.nvim_create_namespace("ns") + vim.api.nvim_buf_set_extmark(0, ns, 15, 0, { virt_lines = {{{"END", ""}}} }) + ]]) + feed('Gzz') + screen:expect([[ + {1:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:wrapped 1 13}aaaaaaaaa | + {1:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:wrapped 1 14}aaaaaaaaa | + {1:buffer 0 15}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:wrapped 1 15}aaaaaaaaa | + {4:buffer 0 16}{5:^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {4:wrapped 1 16}{5:aaaaaaaaa }| + {1:virtual-1 16}END | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) end) it("works with 'statuscolumn' clicks", function() -- cgit From 39842be8cd8808c7da2638a6cc84d7c3fe40b996 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 5 Mar 2023 07:09:28 +0800 Subject: fix(extmarks): don't leak memory on error (#22507) --- test/functional/api/extmark_spec.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 3f9cb94260..30e75b8061 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -107,6 +107,13 @@ describe('API/extmarks', function() eq("Invalid 'id': expected positive Integer", pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 })) eq("Invalid mark position: expected 2 Integer items", pcall_err(get_extmarks, ns, {}, {-1, -1})) eq("Invalid mark position: expected mark id Integer or 2-item Array", pcall_err(get_extmarks, ns, true, {-1, -1})) + -- No memory leak with virt_text, virt_lines, sign_text + eq("right_gravity is not a boolean", pcall_err(set_extmark, ns, marks[2], 0, 0, { + virt_text = {{'foo', 'Normal'}}, + virt_lines = {{{'bar', 'Normal'}}}, + sign_text = 'a', + right_gravity = 'baz', + })) end) it("can end extranges past final newline using end_col = 0", function() -- 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 ++++++++++++ test/functional/plugin/lsp/watchfiles_spec.lua | 173 ++++++++++ test/functional/plugin/lsp_spec.lua | 421 +++++++++++++++++++++++++ 3 files changed, 789 insertions(+) create mode 100644 test/functional/lua/watch_spec.lua create mode 100644 test/functional/plugin/lsp/watchfiles_spec.lua (limited to 'test/functional') 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) diff --git a/test/functional/plugin/lsp/watchfiles_spec.lua b/test/functional/plugin/lsp/watchfiles_spec.lua new file mode 100644 index 0000000000..c5d6803a7f --- /dev/null +++ b/test/functional/plugin/lsp/watchfiles_spec.lua @@ -0,0 +1,173 @@ +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq +local exec_lua = helpers.exec_lua +local has_err = require('luassert').has.errors + +describe('vim.lsp._watchfiles', function() + before_each(helpers.clear) + after_each(helpers.clear) + + local match = function(...) + return exec_lua('return require("vim.lsp._watchfiles")._match(...)', ...) + end + + describe('glob matching', function() + it('should match literal strings', function() + eq(true, match('', '')) + eq(false, match('', 'a')) + eq(true, match('a', 'a')) + eq(true, match('abc', 'abc')) + eq(false, match('abc', 'abcdef')) + eq(false, match('abc', 'a')) + eq(false, match('a', 'b')) + eq(false, match('.', 'a')) + eq(true, match('$', '$')) + eq(false, match('dir/subdir', 'dir/subdir/file')) + end) + + it('should match * wildcards', function() + -- eq(false, match('*', '')) -- TODO: this fails + eq(true, match('*', 'a')) + eq(false, match('*', '/a')) + eq(false, match('*', 'a/')) + eq(true, match('*', 'aaa')) + eq(true, match('*.txt', 'file.txt')) + eq(false, match('*.txt', 'file.txtxt')) + eq(false, match('*.txt', 'dir/file.txt')) + eq(false, match('*.txt', '/dir/file.txt')) + eq(false, match('*.txt', 'C:/dir/file.txt')) + eq(false, match('*.dir', 'test.dir/file')) + eq(true, match('file.*', 'file.txt')) + eq(false, match('file.*', 'not-file.txt')) + eq(false, match('dir/*.txt', 'file.txt')) + eq(true, match('dir/*.txt', 'dir/file.txt')) + eq(false, match('dir/*.txt', 'dir/subdir/file.txt')) + end) + + it('should match ? wildcards', function() + eq(false, match('?', '')) + eq(true, match('?', 'a')) + eq(false, match('??', 'a')) + eq(false, match('?', 'ab')) + eq(true, match('??', 'ab')) + eq(true, match('a?c', 'abc')) + eq(false, match('a?c', 'a/c')) + end) + + it('should match ** wildcards', function() + eq(true, match('**', '')) + eq(true, match('**', 'a')) + eq(true, match('**', 'a/')) + eq(true, match('**', '/a')) + eq(true, match('**', 'C:/a')) + eq(true, match('**', 'a/a')) + eq(true, match('**', 'a/a/a')) + eq(false, match('a**', '')) + eq(true, match('a**', 'a')) + eq(true, match('a**', 'abcd')) + eq(false, match('a**', 'ba')) + eq(false, match('a**', 'a/b')) + eq(false, match('**a', '')) + eq(true, match('**a', 'a')) + eq(true, match('**a', 'dcba')) + eq(false, match('**a', 'ab')) + eq(false, match('**a', 'b/a')) + eq(false, match('a/**', '')) + eq(true, match('a/**', 'a')) + eq(true, match('a/**', 'a/b')) + eq(false, match('a/**', 'b/a')) + eq(false, match('a/**', '/a')) + eq(false, match('**/a', '')) + eq(true, match('**/a', 'a')) + eq(false, match('**/a', 'a/b')) + eq(true, match('**/a', '/a')) + eq(false, match('a/**/c', 'a')) + eq(false, match('a/**/c', 'c')) + eq(true, match('a/**/c', 'a/c')) + eq(true, match('a/**/c', 'a/b/c')) + eq(true, match('a/**/c', 'a/b/b/c')) + eq(true, match('**/a/**', 'a')) + eq(true, match('**/a/**', '/dir/a')) + eq(true, match('**/a/**', 'a/dir')) + eq(true, match('**/a/**', 'dir/a/dir')) + eq(true, match('**/a/**', '/a/dir')) + eq(true, match('**/a/**', 'C:/a/dir')) + -- eq(false, match('**/a/**', 'a.txt')) -- TODO: this fails + end) + + it('should match {} groups', function() + eq(false, match('{}', '')) + eq(true, match('{,}', '')) + eq(false, match('{}', 'a')) + eq(true, match('{a}', 'a')) + eq(false, match('{a}', 'aa')) + eq(false, match('{a}', 'ab')) + eq(false, match('{ab}', 'a')) + eq(true, match('{ab}', 'ab')) + eq(true, match('{a,b}', 'a')) + eq(true, match('{a,b}', 'b')) + eq(false, match('{a,b}', 'ab')) + eq(true, match('{ab,cd}', 'ab')) + eq(false, match('{ab,cd}', 'a')) + eq(true, match('{ab,cd}', 'cd')) + eq(true, match('{a,b,c}', 'c')) + eq(false, match('{a,{b,c}}', 'c')) -- {} can't nest + end) + + it('should match [] groups', function() + eq(true, match('[]', '')) + eq(false, match('[a-z]', '')) + eq(true, match('[a-z]', 'a')) + eq(false, match('[a-z]', 'ab')) + eq(true, match('[a-z]', 'z')) + eq(true, match('[a-z]', 'j')) + eq(false, match('[a-f]', 'j')) + eq(false, match('[a-z]', '`')) -- 'a' - 1 + eq(false, match('[a-z]', '{')) -- 'z' + 1 + eq(false, match('[a-z]', 'A')) + eq(false, match('[a-z]', '5')) + eq(true, match('[A-Z]', 'A')) + eq(true, match('[A-Z]', 'Z')) + eq(true, match('[A-Z]', 'J')) + eq(false, match('[A-Z]', '@')) -- 'A' - 1 + eq(false, match('[A-Z]', '[')) -- 'Z' + 1 + eq(false, match('[A-Z]', 'a')) + eq(false, match('[A-Z]', '5')) + eq(true, match('[a-zA-Z0-9]', 'z')) + eq(true, match('[a-zA-Z0-9]', 'Z')) + eq(true, match('[a-zA-Z0-9]', '9')) + eq(false, match('[a-zA-Z0-9]', '&')) + end) + + it('should match [!...] groups', function() + has_err(function() match('[!]', '') end) -- not a valid pattern + eq(false, match('[!a-z]', '')) + eq(false, match('[!a-z]', 'a')) + eq(false, match('[!a-z]', 'z')) + eq(false, match('[!a-z]', 'j')) + eq(true, match('[!a-f]', 'j')) + eq(false, match('[!a-f]', 'jj')) + eq(true, match('[!a-z]', '`')) -- 'a' - 1 + eq(true, match('[!a-z]', '{')) -- 'z' + 1 + eq(false, match('[!a-zA-Z0-9]', 'a')) + eq(false, match('[!a-zA-Z0-9]', 'A')) + eq(false, match('[!a-zA-Z0-9]', '0')) + eq(true, match('[!a-zA-Z0-9]', '!')) + end) + + it('should match complex patterns', function() + eq(false, match('**/*.{c,h}', '')) + eq(false, match('**/*.{c,h}', 'c')) + eq(true, match('**/*.{c,h}', 'file.c')) + eq(true, match('**/*.{c,h}', 'file.h')) + eq(true, match('**/*.{c,h}', '/file.c')) + eq(true, match('**/*.{c,h}', 'dir/subdir/file.c')) + eq(true, match('**/*.{c,h}', 'dir/subdir/file.h')) + + eq(true, match('{[0-9],[a-z]}', '0')) + eq(true, match('{[0-9],[a-z]}', 'a')) + eq(false, match('{[0-9],[a-z]}', 'A')) + end) + end) +end) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index f1aad08140..5eb367b0b8 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1,5 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) local lsp_helpers = require('test.functional.plugin.lsp.helpers') +local lfs = require('lfs') local assert_log = helpers.assert_log local buf_lines = helpers.buf_lines @@ -3589,4 +3590,424 @@ describe('LSP', function() eq(expected, result) end) end) + + describe('vim.lsp._watchfiles', function() + it('sends notifications when files change', function() + local root_dir = helpers.tmpname() + os.remove(root_dir) + lfs.mkdir(root_dir) + + exec_lua(create_server_definition) + local result = exec_lua([[ + local root_dir = ... + + local server = _create_server() + local client_id = vim.lsp.start({ + name = 'watchfiles-test', + cmd = server.cmd, + root_dir = root_dir, + }) + + local expected_messages = 2 -- initialize, initialized + + local msg_wait_timeout = require('vim.lsp._watchfiles')._watchfunc == vim._watch.poll and 2500 or 200 + local function wait_for_messages() + assert(vim.wait(msg_wait_timeout, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + end + + wait_for_messages() + + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-0', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = { + { + globPattern = '**/watch', + kind = 7, + }, + }, + }, + }, + }, + }, { client_id = client_id }) + + local path = root_dir .. '/watch' + local file = io.open(path, 'w') + file:close() + + expected_messages = expected_messages + 1 + wait_for_messages() + + os.remove(path) + + expected_messages = expected_messages + 1 + wait_for_messages() + + return server.messages + ]], root_dir) + + local function watched_uri(fname) + return exec_lua([[ + local root_dir, fname = ... + return vim.uri_from_fname(root_dir .. '/' .. fname) + ]], root_dir, fname) + end + + eq(4, #result) + eq('workspace/didChangeWatchedFiles', result[3].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('watch'), + }, + }, + }, result[3].params) + eq('workspace/didChangeWatchedFiles', result[4].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = watched_uri('watch'), + }, + }, + }, result[4].params) + end) + + it('correctly registers and unregisters', function() + local root_dir = 'some_dir' + exec_lua(create_server_definition) + local result = exec_lua([[ + local root_dir = ... + + local server = _create_server() + local client_id = vim.lsp.start({ + name = 'watchfiles-test', + cmd = server.cmd, + root_dir = root_dir, + }) + + local expected_messages = 2 -- initialize, initialized + local function wait_for_messages() + assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + end + + wait_for_messages() + + local send_event + require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) + local stoppped = false + send_event = function(...) + if not stoppped then + callback(...) + end + end + return function() + stoppped = true + end + end + + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-0', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = { + { + globPattern = '**/*.watch0', + }, + }, + }, + }, + }, + }, { client_id = client_id }) + + send_event(root_dir .. '/file.watch0', vim._watch.FileChangeType.Created) + send_event(root_dir .. '/file.watch1', vim._watch.FileChangeType.Created) + + expected_messages = expected_messages + 1 + wait_for_messages() + + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-1', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = { + { + globPattern = '**/*.watch1', + }, + }, + }, + }, + }, + }, { client_id = client_id }) + + vim.lsp.handlers['client/unregisterCapability'](nil, { + unregisterations = { + { + id = 'watchfiles-test-0', + method = 'workspace/didChangeWatchedFiles', + }, + }, + }, { client_id = client_id }) + + send_event(root_dir .. '/file.watch0', vim._watch.FileChangeType.Created) + send_event(root_dir .. '/file.watch1', vim._watch.FileChangeType.Created) + + expected_messages = expected_messages + 1 + wait_for_messages() + + return server.messages + ]], root_dir) + + local function watched_uri(fname) + return exec_lua([[ + local root_dir, fname = ... + return vim.uri_from_fname(root_dir .. '/' .. fname) + ]], root_dir, fname) + end + + eq(4, #result) + eq('workspace/didChangeWatchedFiles', result[3].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('file.watch0'), + }, + }, + }, result[3].params) + eq('workspace/didChangeWatchedFiles', result[4].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('file.watch1'), + }, + }, + }, result[4].params) + end) + + it('correctly handles the registered watch kind', function() + local root_dir = 'some_dir' + exec_lua(create_server_definition) + local result = exec_lua([[ + local root_dir = ... + + local server = _create_server() + local client_id = vim.lsp.start({ + name = 'watchfiles-test', + cmd = server.cmd, + root_dir = root_dir, + }) + + local expected_messages = 2 -- initialize, initialized + local function wait_for_messages() + assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + end + + wait_for_messages() + + local watch_callbacks = {} + local function send_event(...) + for _, cb in ipairs(watch_callbacks) do + cb(...) + end + end + require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) + table.insert(watch_callbacks, callback) + return function() + -- noop because this test never stops the watch + end + end + + local protocol = require('vim.lsp.protocol') + + local watchers = {} + local max_kind = protocol.WatchKind.Create + protocol.WatchKind.Change + protocol.WatchKind.Delete + for i = 0, max_kind do + local j = i + table.insert(watchers, { + globPattern = { + baseUri = vim.uri_from_fname('/dir'..tostring(i)), + pattern = 'watch'..tostring(i), + }, + kind = i, + }) + end + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-kind', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = watchers, + }, + }, + }, + }, { client_id = client_id }) + + for i = 0, max_kind do + local filename = 'watch'..tostring(i) + send_event(filename, vim._watch.FileChangeType.Created) + send_event(filename, vim._watch.FileChangeType.Changed) + send_event(filename, vim._watch.FileChangeType.Deleted) + end + + expected_messages = expected_messages + 1 + wait_for_messages() + + return server.messages + ]], root_dir) + + local function watched_uri(fname) + return exec_lua([[ + return vim.uri_from_fname(...) + ]], fname) + end + + eq(3, #result) + eq('workspace/didChangeWatchedFiles', result[3].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('watch1'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + uri = watched_uri('watch2'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('watch3'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + uri = watched_uri('watch3'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = watched_uri('watch4'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('watch5'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = watched_uri('watch5'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + uri = watched_uri('watch6'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = watched_uri('watch6'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('watch7'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + uri = watched_uri('watch7'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Deleted]]), + uri = watched_uri('watch7'), + }, + }, + }, result[3].params) + end) + + it('prunes duplicate events', function() + local root_dir = 'some_dir' + exec_lua(create_server_definition) + local result = exec_lua([[ + local root_dir = ... + + local server = _create_server() + local client_id = vim.lsp.start({ + name = 'watchfiles-test', + cmd = server.cmd, + root_dir = root_dir, + }) + + local expected_messages = 2 -- initialize, initialized + local function wait_for_messages() + assert(vim.wait(200, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) + end + + wait_for_messages() + + local send_event + require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) + send_event = callback + return function() + -- noop because this test never stops the watch + end + end + + vim.lsp.handlers['client/registerCapability'](nil, { + registrations = { + { + id = 'watchfiles-test-kind', + method = 'workspace/didChangeWatchedFiles', + registerOptions = { + watchers = { + { + globPattern = '**/*', + }, + }, + }, + }, + }, + }, { client_id = client_id }) + + send_event('file1', vim._watch.FileChangeType.Created) + send_event('file1', vim._watch.FileChangeType.Created) -- pruned + send_event('file1', vim._watch.FileChangeType.Changed) + send_event('file2', vim._watch.FileChangeType.Created) + send_event('file1', vim._watch.FileChangeType.Changed) -- pruned + + expected_messages = expected_messages + 1 + wait_for_messages() + + return server.messages + ]], root_dir) + + local function watched_uri(fname) + return exec_lua([[ + return vim.uri_from_fname(...) + ]], fname) + end + + eq(3, #result) + eq('workspace/didChangeWatchedFiles', result[3].method) + eq({ + changes = { + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('file1'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Changed]]), + uri = watched_uri('file1'), + }, + { + type = exec_lua([[return vim.lsp.protocol.FileChangeType.Created]]), + uri = watched_uri('file2'), + }, + }, + }, result[3].params) + 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') 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 e389b189021cb6b72cfd7583ce6fb5d8d3346d45 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 6 Mar 2023 07:52:11 +0800 Subject: vim-patch:9.0.1385: g'Esc is considered an error (#22544) Problem: g'Esc is considered an error. Solution: Make g'Esc silently abandon the command. (closes vim/vim#12110) https://github.com/vim/vim/commit/f86dea8119f3141e3d2c680219036d1511101f9b --- test/functional/ui/mode_spec.lua | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua index cf4eb034e0..e870d6f25f 100644 --- a/test/functional/ui/mode_spec.lua +++ b/test/functional/ui/mode_spec.lua @@ -44,7 +44,10 @@ describe('ui mode_change event', function() {0:~ }| | ]], mode="normal"} + end) + -- oldtest: Test_mouse_shape_after_failed_change() + it('is restored to Normal mode after failed "c"', function() screen:try_resize(50, 4) command('set nomodifiable') @@ -65,6 +68,25 @@ describe('ui mode_change event', function() ]], mode="normal"} end) + -- oldtest: Test_mouse_shape_after_cancelling_gr() + it('is restored to Normal mode after cancelling "gr"', function() + feed('gr') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + | + ]], mode="replace"} + + feed('') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + | + ]], mode="normal"} + end) + it('works in insert mode', function() feed('i') screen:expect{grid=[[ -- 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') 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') 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') 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 1cc23e1109ed88275df5c986c352f73b99a0301c Mon Sep 17 00:00:00 2001 From: swarn Date: Mon, 6 Mar 2023 12:03:13 -0600 Subject: feat(lsp)!: add rule-based sem token highlighting (#22022) feat(lsp)!: change semantic token highlighting Change the default highlights used, and add more highlights per token. Add an LspTokenUpdate event and a highlight_token function. :Inspect now shows any highlights applied by token highlighting rules, default or user-defined. BREAKING CHANGE: change the default highlight groups used by semantic token highlighting. --- .../functional/plugin/lsp/semantic_tokens_spec.lua | 211 ++++++++++++--------- 1 file changed, 125 insertions(+), 86 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index 004fce4983..780d18fce9 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -37,10 +37,12 @@ describe('semantic token highlighting', function() [6] = { foreground = Screen.colors.Blue1 }; [7] = { bold = true, foreground = Screen.colors.DarkCyan }; [8] = { bold = true, foreground = Screen.colors.SlateBlue }; + [9] = { bold = true, foreground = tonumber('0x6a0dad') }; } - command([[ hi link @namespace Type ]]) - command([[ hi link @function Special ]]) - command([[ hi @declaration gui=bold ]]) + command([[ hi link @lsp.type.namespace Type ]]) + command([[ hi link @lsp.type.function Special ]]) + command([[ hi link @lsp.type.comment Comment ]]) + command([[ hi @lsp.mod.declaration gui=bold ]]) end) describe('general', function() @@ -129,6 +131,46 @@ describe('semantic token highlighting', function() ]] } end) + it('use LspTokenUpdate and highlight_token', function() + exec_lua([[ + vim.api.nvim_create_autocmd("LspTokenUpdate", { + callback = function(args) + local token = args.data.token + if token.type == "function" and token.modifiers.declaration then + vim.lsp.semantic_tokens.highlight_token( + token, args.buf, args.data.client_id, "Macro" + ) + end + end, + }) + bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_win_set_buf(0, bufnr) + client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + ]]) + + insert(text) + + screen:expect { grid = [[ + #include | + | + int {9:main}() | + { | + int {7:x}; | + #ifdef {5:__cplusplus} | + {4:std}::{2:cout} << {2:x} << "\n"; | + {6:#else} | + {6: printf("%d\n", x);} | + {6:#endif} | + } | + ^} | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]] } + + end) + it('buffer is unhighlighted when client is detached', function() exec_lua([[ bufnr = vim.api.nvim_get_current_buf() @@ -580,14 +622,11 @@ describe('semantic token highlighting', function() expected = { { line = 0, - modifiers = { - 'declaration', - 'globalScope', - }, + modifiers = { declaration = true, globalScope = true }, start_col = 6, end_col = 9, type = 'variable', - extmark_added = true, + marked = true, }, }, }, @@ -615,67 +654,67 @@ int main() expected = { { -- main line = 1, - modifiers = { 'declaration', 'globalScope' }, + modifiers = { declaration = true, globalScope = true }, start_col = 4, end_col = 8, type = 'function', - extmark_added = true, + marked = true, }, { -- __cplusplus line = 3, - modifiers = { 'globalScope' }, + modifiers = { globalScope = true }, start_col = 9, end_col = 20, type = 'macro', - extmark_added = true, + marked = true, }, { -- x line = 4, - modifiers = { 'declaration', 'readonly', 'functionScope' }, + modifiers = { declaration = true, readonly = true, functionScope = true }, start_col = 12, end_col = 13, type = 'variable', - extmark_added = true, + marked = true, }, { -- std line = 5, - modifiers = { 'defaultLibrary', 'globalScope' }, + modifiers = { defaultLibrary = true, globalScope = true }, start_col = 2, end_col = 5, type = 'namespace', - extmark_added = true, + marked = true, }, { -- cout line = 5, - modifiers = { 'defaultLibrary', 'globalScope' }, + modifiers = { defaultLibrary = true, globalScope = true }, start_col = 7, end_col = 11, type = 'variable', - extmark_added = true, + marked = true, }, { -- x line = 5, - modifiers = { 'readonly', 'functionScope' }, + modifiers = { readonly = true, functionScope = true }, start_col = 15, end_col = 16, type = 'variable', - extmark_added = true, + marked = true, }, { -- std line = 5, - modifiers = { 'defaultLibrary', 'globalScope' }, + modifiers = { defaultLibrary = true, globalScope = true }, start_col = 20, end_col = 23, type = 'namespace', - extmark_added = true, + marked = true, }, { -- endl line = 5, - modifiers = { 'defaultLibrary', 'globalScope' }, + modifiers = { defaultLibrary = true, globalScope = true }, start_col = 25, end_col = 29, type = 'function', - extmark_added = true, + marked = true, }, { -- #else comment #endif line = 6, @@ -683,7 +722,7 @@ int main() start_col = 0, end_col = 7, type = 'comment', - extmark_added = true, + marked = true, }, { line = 7, @@ -691,7 +730,7 @@ int main() start_col = 0, end_col = 11, type = 'comment', - extmark_added = true, + marked = true, }, { line = 8, @@ -699,7 +738,7 @@ int main() start_col = 0, end_col = 8, type = 'comment', - extmark_added = true, + marked = true, }, }, }, @@ -724,23 +763,23 @@ b = "as"]], start_col = 0, end_col = 10, type = 'comment', -- comment - extmark_added = true, + marked = true, }, { line = 1, - modifiers = { 'declaration' }, -- a + modifiers = { declaration = true }, -- a start_col = 6, end_col = 7, type = 'variable', - extmark_added = true, + marked = true, }, { line = 2, - modifiers = { 'static' }, -- b (global) + modifiers = { static = true }, -- b (global) start_col = 0, end_col = 1, type = 'variable', - extmark_added = true, + marked = true, }, }, }, @@ -770,7 +809,7 @@ b = "as"]], start_col = 0, end_col = 3, -- pub type = 'keyword', - extmark_added = true, + marked = true, }, { line = 0, @@ -778,15 +817,15 @@ b = "as"]], start_col = 4, end_col = 6, -- fn type = 'keyword', - extmark_added = true, + marked = true, }, { line = 0, - modifiers = { 'declaration', 'public' }, + modifiers = { declaration = true, public = true }, start_col = 7, end_col = 11, -- main type = 'function', - extmark_added = true, + marked = true, }, { line = 0, @@ -794,7 +833,7 @@ b = "as"]], start_col = 11, end_col = 12, type = 'parenthesis', - extmark_added = true, + marked = true, }, { line = 0, @@ -802,7 +841,7 @@ b = "as"]], start_col = 12, end_col = 13, type = 'parenthesis', - extmark_added = true, + marked = true, }, { line = 0, @@ -810,15 +849,15 @@ b = "as"]], start_col = 14, end_col = 15, type = 'brace', - extmark_added = true, + marked = true, }, { line = 1, - modifiers = { 'controlFlow' }, + modifiers = { controlFlow = true }, start_col = 4, end_col = 9, -- break type = 'keyword', - extmark_added = true, + marked = true, }, { line = 1, @@ -826,7 +865,7 @@ b = "as"]], start_col = 10, end_col = 13, -- rust type = 'unresolvedReference', - extmark_added = true, + marked = true, }, { line = 1, @@ -834,15 +873,15 @@ b = "as"]], start_col = 13, end_col = 13, type = 'semicolon', - extmark_added = true, + marked = true, }, { line = 2, - modifiers = { 'documentation' }, + modifiers = { documentation = true }, start_col = 4, end_col = 11, type = 'comment', -- /// what? - extmark_added = true, + marked = true, }, { line = 3, @@ -850,7 +889,7 @@ b = "as"]], start_col = 0, end_col = 1, type = 'brace', - extmark_added = true, + marked = true, }, }, }, @@ -908,26 +947,26 @@ b = "as"]], { line = 0, modifiers = { - 'declaration', - 'globalScope', + declaration = true, + globalScope = true, }, start_col = 6, end_col = 9, type = 'variable', - extmark_added = true, + marked = true, } }, expected2 = { { line = 1, modifiers = { - 'declaration', - 'globalScope', + declaration = true, + globalScope = true, }, start_col = 6, end_col = 9, type = 'variable', - extmark_added = true, + marked = true, } }, expected_screen1 = function() @@ -1018,55 +1057,55 @@ int main() line = 2, start_col = 4, end_col = 8, - modifiers = { 'declaration', 'globalScope' }, + modifiers = { declaration = true, globalScope = true }, type = 'function', - extmark_added = true, + marked = true, }, { line = 4, start_col = 8, end_col = 9, - modifiers = { 'declaration', 'functionScope' }, + modifiers = { declaration = true, functionScope = true }, type = 'variable', - extmark_added = true, + marked = true, }, { line = 5, start_col = 7, end_col = 18, - modifiers = { 'globalScope' }, + modifiers = { globalScope = true }, type = 'macro', - extmark_added = true, + marked = true, }, { line = 6, start_col = 4, end_col = 7, - modifiers = { 'defaultLibrary', 'globalScope' }, + modifiers = { defaultLibrary = true, globalScope = true }, type = 'namespace', - extmark_added = true, + marked = true, }, { line = 6, start_col = 9, end_col = 13, - modifiers = { 'defaultLibrary', 'globalScope' }, + modifiers = { defaultLibrary = true, globalScope = true }, type = 'variable', - extmark_added = true, + marked = true, }, { line = 6, start_col = 17, end_col = 18, - extmark_added = true, - modifiers = { 'functionScope' }, + marked = true, + modifiers = { functionScope = true }, type = 'variable', }, { line = 7, start_col = 0, end_col = 5, - extmark_added = true, + marked = true, modifiers = {}, type = 'comment', }, @@ -1076,7 +1115,7 @@ int main() modifiers = {}, start_col = 0, type = 'comment', - extmark_added = true, + marked = true, }, { line = 9, @@ -1084,7 +1123,7 @@ int main() end_col = 6, modifiers = {}, type = 'comment', - extmark_added = true, + marked = true, } }, expected2 = { @@ -1092,63 +1131,63 @@ int main() line = 2, start_col = 4, end_col = 8, - modifiers = { 'declaration', 'globalScope' }, + modifiers = { declaration = true, globalScope = true }, type = 'function', - extmark_added = true, + marked = true, }, { line = 4, start_col = 8, end_col = 9, - modifiers = { 'declaration', 'globalScope' }, + modifiers = { declaration = true, globalScope = true }, type = 'function', - extmark_added = true, + marked = true, }, { line = 5, end_col = 12, start_col = 11, - modifiers = { 'declaration', 'functionScope' }, + modifiers = { declaration = true, functionScope = true }, type = 'variable', - extmark_added = true, + marked = true, }, { line = 6, start_col = 7, end_col = 18, - modifiers = { 'globalScope' }, + modifiers = { globalScope = true }, type = 'macro', - extmark_added = true, + marked = true, }, { line = 7, start_col = 4, end_col = 7, - modifiers = { 'defaultLibrary', 'globalScope' }, + modifiers = { defaultLibrary = true, globalScope = true }, type = 'namespace', - extmark_added = true, + marked = true, }, { line = 7, start_col = 9, end_col = 13, - modifiers = { 'defaultLibrary', 'globalScope' }, + modifiers = { defaultLibrary = true, globalScope = true }, type = 'variable', - extmark_added = true, + marked = true, }, { line = 7, start_col = 17, end_col = 18, - extmark_added = true, - modifiers = { 'globalScope' }, + marked = true, + modifiers = { globalScope = true }, type = 'function', }, { line = 8, start_col = 0, end_col = 5, - extmark_added = true, + marked = true, modifiers = {}, type = 'comment', }, @@ -1158,7 +1197,7 @@ int main() modifiers = {}, start_col = 0, type = 'comment', - extmark_added = true, + marked = true, }, { line = 10, @@ -1166,7 +1205,7 @@ int main() end_col = 6, modifiers = {}, type = 'comment', - extmark_added = true, + marked = true, } }, expected_screen1 = function() @@ -1228,12 +1267,12 @@ int main() { line = 0, modifiers = { - 'declaration', + declaration = true, }, start_col = 0, end_col = 6, type = 'variable', - extmark_added = true, + marked = true, } }, expected2 = { -- 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') 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 bf4eada2c83f5402fc56370fd22af11029a4a3aa Mon Sep 17 00:00:00 2001 From: luukvbaal <31730729+luukvbaal@users.noreply.github.com> Date: Tue, 7 Mar 2023 01:45:08 +0100 Subject: fix(column): issues with 'statuscolumn' width (#22542) Problem: 'statuscolumn' width can be incorrect when toggling 'number' or setting 'statuscolumn'. Solution: Make sure the width is reset and re-estimated when 'statuscolumn' and 'number' are set. (When 'relativenumber' is set this already happens because it always changes "nrwidth_line_count".) --- test/functional/ui/statuscolumn_spec.lua | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index 08b5d1913b..dfbdbb4898 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -520,4 +520,42 @@ describe('statuscolumn', function() : | ]]) end) + + it("has correct width when toggling '(relative)number'", function() + screen:try_resize(screen._width, 6) + command('call setline(1, repeat(["aaaaa"], 100))') + command('set relativenumber') + command([[set stc=%{!&nu&&!&rnu?'':&rnu?v:relnum?v:relnum:&nu?v:lnum:'0':v:lnum}]]) + screen:expect([[ + 1 aaaaa | + 8 ^aaaaa | + 1 aaaaa | + 2 aaaaa | + 3 aaaaa | + | + ]]) + -- width correctly estimated with "w_nrwidth_line_count" when setting 'stc' + command([[set stc=%{!&nu&&!&rnu?'':&rnu?v:relnum?v:relnum:&nu?v:lnum:'0':v:lnum}]]) + screen:expect_unchanged() + -- zero width when disabling 'number' + command('set norelativenumber nonumber') + screen:expect([[ + aaaaa | + ^aaaaa | + aaaaa | + aaaaa | + aaaaa | + | + ]]) + -- width correctly estimated with "w_nrwidth_line_count" when setting 'nu' + command('set number') + screen:expect([[ + 7 aaaaa | + 8 ^aaaaa | + 9 aaaaa | + 10 aaaaa | + 11 aaaaa | + | + ]]) + end) end) -- cgit From af23d173883f47fd02a9a380c719e4428370b484 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 7 Mar 2023 04:13:04 +0100 Subject: test: move oldtests to test directory (#22536) The new oldtest directory is in test/old/testdir. The reason for this is that many tests have hardcoded the parent directory name to be 'testdir'. --- test/functional/helpers.lua | 2 +- test/functional/legacy/options_spec.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index cd6b535477..43e5b73608 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -898,7 +898,7 @@ local load_factor = 1 if global_helpers.is_ci() then -- Compute load factor only once (but outside of any tests). module.clear() - module.request('nvim_command', 'source src/nvim/testdir/load.vim') + module.request('nvim_command', 'source test/old/testdir/load.vim') load_factor = module.request('nvim_eval', 'g:test_load_factor') end function module.load_adjust(num) diff --git a/test/functional/legacy/options_spec.lua b/test/functional/legacy/options_spec.lua index bd14f3bc53..ce46ea013d 100644 --- a/test/functional/legacy/options_spec.lua +++ b/test/functional/legacy/options_spec.lua @@ -1,4 +1,4 @@ --- See also: src/nvim/testdir/test_options.vim +-- See also: test/old/testdir/test_options.vim local helpers = require('test.functional.helpers')(after_each) local command, clear = helpers.command, helpers.clear local source, expect = helpers.source, helpers.expect -- cgit From 160a019ffa104eebd65f4037729954d98aca6ad0 Mon Sep 17 00:00:00 2001 From: Eriks Muhins Date: Fri, 3 Mar 2023 21:44:13 +0200 Subject: feat(man.lua): support spaces in manpage names Problem: :Man command errors if given more than two arguments. Thus, it is impossible to open man pages that contain spaces in their names. Solution: Adjust :Man so that it tries variants with spaces and underscores, and uses the first found. --- test/functional/plugin/man_spec.lua | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index 58da059be6..a1a7274e5d 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -10,6 +10,26 @@ local write_file = helpers.write_file local tmpname = helpers.tmpname local skip = helpers.skip local is_ci = helpers.is_ci +local table_contains = vim.tbl_contains + +-- Returns a table composed of all man page name arguments +-- that were passed to search_for_path after attempting to +-- open 'name'. +local function get_search_history(name) + local as_table = string.gsub(name, ' ', '\', \'') + as_table = '\'' .. as_table .. '\'' + local code = ([[ + local man = require('runtime.lua.man') + local res = {} + man.attempt_to_get_path = function(sect, name, silent) + table.insert(res, name) + return nil + end + pcall(man.open_page, 0, {tab = 0}, {%s}) + return res + ]]):format(as_table) + return exec_lua(code) +end clear() if funcs.executable('man') == 0 then @@ -173,4 +193,10 @@ describe(':Man', function() funcs.system(args, {''})) os.remove(actual_file) end) + + it('searches for manpage name with variants with spaces, underscores', function() + local tried = get_search_history('NAME WITH SPACES') + table_contains(tried, 'NAME WITH SPACES') + table_contains(tried, 'NAME_WITH_SPACES') + end) end) -- cgit From 304477ff3504373a336c83127654e65eddfa2ef9 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 7 Mar 2023 15:13:09 +0100 Subject: fix(man.lua): tests, naming --- test/functional/plugin/man_spec.lua | 39 +++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index a1a7274e5d..9730bf4bf6 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -8,27 +8,27 @@ local nvim_prog = helpers.nvim_prog local matches = helpers.matches local write_file = helpers.write_file local tmpname = helpers.tmpname +local eq = helpers.eq local skip = helpers.skip local is_ci = helpers.is_ci -local table_contains = vim.tbl_contains --- Returns a table composed of all man page name arguments --- that were passed to search_for_path after attempting to --- open 'name'. +-- Collects all names passed to find_path() after attempting ":Man foo". local function get_search_history(name) - local as_table = string.gsub(name, ' ', '\', \'') - as_table = '\'' .. as_table .. '\'' - local code = ([[ + local args = vim.split(name, ' ') + local code = [[ + local args = ... local man = require('runtime.lua.man') local res = {} - man.attempt_to_get_path = function(sect, name, silent) + man.find_path = function(sect, name) table.insert(res, name) return nil end - pcall(man.open_page, 0, {tab = 0}, {%s}) + local ok, rv = pcall(man.open_page, 0, {tab = 0}, args) + assert(not ok) + assert(rv and rv:match('no manual entry')) return res - ]]):format(as_table) - return exec_lua(code) + ]] + return exec_lua(code, args) end clear() @@ -194,9 +194,18 @@ describe(':Man', function() os.remove(actual_file) end) - it('searches for manpage name with variants with spaces, underscores', function() - local tried = get_search_history('NAME WITH SPACES') - table_contains(tried, 'NAME WITH SPACES') - table_contains(tried, 'NAME_WITH_SPACES') + it('tries variants with spaces, underscores #22503', function() + eq({ + 'NAME WITH SPACES', + 'NAME_WITH_SPACES', + }, get_search_history('NAME WITH SPACES')) + eq({ + 'some other man', + 'some_other_man', + }, get_search_history('3 some other man')) + eq({ + 'other_man', + 'other_man', + }, get_search_history('other_man(1)')) end) end) -- cgit From 1fb585a9db32ddfa563328a4ffb18b6f1e1dec1e Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Mon, 6 Mar 2023 16:50:27 +0100 Subject: test(statusline): UI elements are not redrawn on K_EVENT unnecessarily --- test/functional/ui/statusline_spec.lua | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index 1c184ff27d..c59ade0e31 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -10,6 +10,7 @@ local meths = helpers.meths local exec = helpers.exec local exec_lua = helpers.exec_lua local eval = helpers.eval +local sleep = helpers.sleep describe('statusline clicks', function() local screen @@ -589,3 +590,35 @@ it('showcmdloc=statusline does not show if statusline is too narrow', function() feed('1234') screen:expect_unchanged() end) + +it('K_EVENT does not trigger a statusline redraw unnecessarily', function() + clear() + local screen = Screen.new(40, 8) + screen:attach() + -- does not redraw on vim.schedule (#17937) + command([[ + set laststatus=2 + let g:counter = 0 + func Status() + let g:counter += 1 + lua vim.schedule(function() end) + return g:counter + endfunc + set statusline=%!Status() + ]]) + sleep(50) + eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter')) + -- also in insert mode + feed('i') + sleep(50) + eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter')) + -- does not redraw on timer call (#14303) + command([[ + let g:counter = 0 + func Timer(timer) + endfunc + call timer_start(1, 'Timer', {'repeat': 100}) + ]]) + sleep(50) + eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter')) +end) -- cgit From be0461e3c216c2e4e2c3397c739b7727a5bf6df8 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 8 Mar 2023 23:45:43 +0000 Subject: fix(treesitter): is_in_node_range (#22582) TS ranges are end column exclusive, so fix is_in_node_range to account for that. --- test/functional/treesitter/utils_spec.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/utils_spec.lua b/test/functional/treesitter/utils_spec.lua index 7f5a864c3d..9c07959098 100644 --- a/test/functional/treesitter/utils_spec.lua +++ b/test/functional/treesitter/utils_spec.lua @@ -28,4 +28,21 @@ describe('treesitter utils', function() eq(true, exec_lua('return vim.treesitter.is_ancestor(ancestor, child)')) eq(false, exec_lua('return vim.treesitter.is_ancestor(child, ancestor)')) end) + + it('can detect if a position is contained in a node', function() + exec_lua([[ + node = { + range = function() + return 0, 4, 0, 8 + end, + } + ]]) + + eq(false, exec_lua('return vim.treesitter.is_in_node_range(node, 0, 3)')) + for i = 4, 7 do + eq(true, exec_lua('return vim.treesitter.is_in_node_range(node, 0, ...)', i)) + end + -- End column exclusive + eq(false, exec_lua('return vim.treesitter.is_in_node_range(node, 0, 8)')) + end) end) -- 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') 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 ce0fddf5ae334f0c79dcd95b379999e11df1486b Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 9 Mar 2023 08:07:36 -0500 Subject: feat: try to recover from missing tempdir #22573 Problem: If vim_tempdir mysteriously goes missing (typically by "antivirus" on Windows), any plugins using tempname() will be broken for the rest of the session. #1432 #9833 https://groups.google.com/g/vim_use/c/ef55jNm5czI Steps: mkdir foo TMPDIR=./foo nvim :echo tempname() !rm -r foo :echo tempname() tempname() still uses the foo path even though it was deleted. Solution: - Don't assume that vim_tempdir exists. - If it goes missing once, retry vim_mktempdir and log (silently) an error. - If it goes missing again, retry vim_mktempdir and show an error. Rejected in Vim for performance reasons: https://groups.google.com/g/vim_use/c/qgRob9SWDv8/m/FAOFVVcDTv0J https://groups.google.com/g/vim_dev/c/cogp-Vye4oo/m/d_SVFXBbnnoJ But, logging shows that `vim_gettempdir` is not called frequently. Fixes #1432 Fixes #9833 Fixes #11250 Related: stdpath("run") f50135a32e11c535e1dc3a8e9460c5b4e640ee86 --- test/functional/core/fileio_spec.lua | 64 +++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 12 deletions(-) (limited to 'test/functional') diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index 4e9891a4de..153b53dce2 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -15,6 +15,7 @@ local request = helpers.request local retry = helpers.retry local rmdir = helpers.rmdir local matches = helpers.matches +local meths = helpers.meths local mkdir = helpers.mkdir local sleep = helpers.sleep local read_file = helpers.read_file @@ -261,13 +262,13 @@ end) describe('tmpdir', function() local tmproot_pat = [=[.*[/\\]nvim%.[^/\\]+]=] local testlog = 'Xtest_tmpdir_log' - local faketmp + local os_tmpdir before_each(function() -- Fake /tmp dir so that we can mess it up. - faketmp = tmpname() - os.remove(faketmp) - mkdir(faketmp) + os_tmpdir = tmpname() + os.remove(os_tmpdir) + mkdir(os_tmpdir) end) after_each(function() @@ -275,16 +276,21 @@ describe('tmpdir', function() os.remove(testlog) end) - it('failure modes', function() - clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=faketmp, } }) - assert_nolog('tempdir is not a directory', testlog) - assert_nolog('tempdir has invalid permissions', testlog) - + local function get_tmproot() -- Tempfiles typically look like: "…/nvim./xxx/0". -- - "…/nvim./xxx/" is the per-process tmpdir, not shared with other Nvims. -- - "…/nvim./" is the tmpdir root, shared by all Nvims (normally). local tmproot = (funcs.tempname()):match(tmproot_pat) ok(tmproot:len() > 4, 'tmproot like "nvim.foo"', tmproot) + return tmproot + end + + it('failure modes', function() + clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) + assert_nolog('tempdir is not a directory', testlog) + assert_nolog('tempdir has invalid permissions', testlog) + + local tmproot = get_tmproot() -- Test how Nvim handles invalid tmpdir root (by hostile users or accidents). -- @@ -292,7 +298,7 @@ describe('tmpdir', function() expect_exit(command, ':qall!') rmdir(tmproot) write_file(tmproot, '') -- Not a directory, vim_mktempdir() should skip it. - clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=faketmp, } }) + clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). -- Assert that broken tmpdir root was handled. assert_log('tempdir root not a directory', testlog, 100) @@ -303,18 +309,52 @@ describe('tmpdir', function() os.remove(tmproot) mkdir(tmproot) funcs.setfperm(tmproot, 'rwxr--r--') -- Invalid permissions, vim_mktempdir() should skip it. - clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=faketmp, } }) + clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). -- Assert that broken tmpdir root was handled. assert_log('tempdir root has invalid permissions', testlog, 100) end) it('too long', function() - local bigname = ('%s/%s'):format(faketmp, ('x'):rep(666)) + local bigname = ('%s/%s'):format(os_tmpdir, ('x'):rep(666)) mkdir(bigname) clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=bigname, } }) matches(tmproot_pat, funcs.stdpath('run')) -- Tickle vim_mktempdir(). local len = (funcs.tempname()):len() ok(len > 4 and len < 256, '4 < len < 256', tostring(len)) end) + + it('disappeared #1432', function() + clear({ env={ NVIM_LOG_FILE=testlog, TMPDIR=os_tmpdir, } }) + assert_nolog('tempdir disappeared', testlog) + + local function rm_tmpdir() + local tmpname1 = funcs.tempname() + local tmpdir1 = funcs.fnamemodify(tmpname1, ':h') + eq(funcs.stdpath('run'), tmpdir1) + + rmdir(tmpdir1) + retry(nil, 1000, function() + eq(0, funcs.isdirectory(tmpdir1)) + end) + local tmpname2 = funcs.tempname() + local tmpdir2 = funcs.fnamemodify(tmpname2, ':h') + neq(tmpdir1, tmpdir2) + end + + -- Your antivirus hates you... + rm_tmpdir() + assert_log('tempdir disappeared', testlog, 100) + funcs.tempname() + funcs.tempname() + funcs.tempname() + eq('', meths.get_vvar('errmsg')) + rm_tmpdir() + funcs.tempname() + funcs.tempname() + funcs.tempname() + eq('E5431: tempdir disappeared (2 times)', meths.get_vvar('errmsg')) + rm_tmpdir() + eq('E5431: tempdir disappeared (3 times)', meths.get_vvar('errmsg')) + end) end) -- cgit From 9ef7297ef142354ace8b1f3f277d0eee3cfdc6d4 Mon Sep 17 00:00:00 2001 From: Michal Liszcz Date: Thu, 9 Mar 2023 15:12:56 +0100 Subject: feat(lsp): overwrite omnifunc/tagfunc set by ftplugin #22267 Problem: Some built-in ftplugins set omnifunc/tagfunc/formatexpr which causes lsp.lua:set_defaults() to skip setup of defaults for those filetypes. For example the C++ ftplugin has: omnifunc=ccomplete#Complete Last set from /usr/share/nvim/runtime/ftplugin/c.vim line 30 so the changes done in #95c65a6b221fe6e1cf91e8322e7d7571dc511a71 will always be skipped for C++ files. Solution: Overwrite omnifunc/tagfunc/formatexpr options that were set by stock ftplugin. Fixes #21001 --- test/functional/fixtures/fake-lsp-server.lua | 17 +++++ test/functional/plugin/lsp_spec.lua | 103 +++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) (limited to 'test/functional') diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index dbb66a42e8..9cc2f6fa27 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -932,6 +932,23 @@ function tests.basic_formatting() } end +function tests.set_defaults_all_capabilities() + skeleton { + on_init = function(_) + return { + capabilities = { + definitionProvider = true, + completionProvider = true, + documentRangeFormattingProvider = true, + } + } + end; + body = function() + notify('test') + end; + } +end + -- Tests will be indexed by test_name local test_name = arg[1] local timeout = arg[2] diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 5eb367b0b8..56c53a6fed 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -31,6 +31,11 @@ local fake_lsp_code = lsp_helpers.fake_lsp_code local fake_lsp_logfile = lsp_helpers.fake_lsp_logfile local test_rpc_server = lsp_helpers.test_rpc_server +local function get_buf_option(name, bufnr) + bufnr = bufnr or "BUFFER" + return exec_lua(string.format("return vim.api.nvim_buf_get_option(%s, '%s')", bufnr, name)) +end + -- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837 if skip(is_os('win')) then return end @@ -313,6 +318,104 @@ describe('LSP', function() } end) + it('should set default options on attach', function() + local client + test_rpc_server { + test_name = "set_defaults_all_capabilities"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + ]] + end; + on_init = function(_client) + client = _client + exec_lua("lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)") + end; + on_handler = function(_, _, ctx) + if ctx.method == 'test' then + eq('v:lua.vim.lsp.tagfunc', get_buf_option("tagfunc")) + eq('v:lua.vim.lsp.omnifunc', get_buf_option("omnifunc")) + eq('v:lua.vim.lsp.formatexpr()', get_buf_option("formatexpr")) + client.stop() + end + end; + on_exit = function(_, _) + eq('', get_buf_option("tagfunc")) + eq('', get_buf_option("omnifunc")) + eq('', get_buf_option("formatexpr")) + end; + } + end) + + it('should overwrite options set by ftplugins', function() + local client + test_rpc_server { + test_name = "set_defaults_all_capabilities"; + on_setup = function() + exec_lua [[ + vim.api.nvim_command('filetype plugin on') + BUFFER_1 = vim.api.nvim_create_buf(false, true) + BUFFER_2 = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_option(BUFFER_1, 'filetype', 'man') + vim.api.nvim_buf_set_option(BUFFER_2, 'filetype', 'xml') + ]] + eq('v:lua.require\'man\'.goto_tag', get_buf_option("tagfunc", "BUFFER_1")) + eq('xmlcomplete#CompleteTags', get_buf_option("omnifunc", "BUFFER_2")) + eq('xmlformat#Format()', get_buf_option("formatexpr", "BUFFER_2")) + end; + on_init = function(_client) + client = _client + exec_lua("lsp.buf_attach_client(BUFFER_1, TEST_RPC_CLIENT_ID)") + exec_lua("lsp.buf_attach_client(BUFFER_2, TEST_RPC_CLIENT_ID)") + end; + on_handler = function(_, _, ctx) + if ctx.method == 'test' then + eq('v:lua.vim.lsp.tagfunc', get_buf_option("tagfunc", "BUFFER_1")) + eq('v:lua.vim.lsp.omnifunc', get_buf_option("omnifunc", "BUFFER_2")) + eq('v:lua.vim.lsp.formatexpr()', get_buf_option("formatexpr", "BUFFER_2")) + client.stop() + end + end; + on_exit = function(_, _) + eq('', get_buf_option("tagfunc", "BUFFER_1")) + eq('', get_buf_option("omnifunc", "BUFFER_2")) + eq('', get_buf_option("formatexpr", "BUFFER_2")) + end; + } + end) + + it('should not overwrite user-defined options', function() + local client + test_rpc_server { + test_name = "set_defaults_all_capabilities"; + on_setup = function() + exec_lua [[ + BUFFER = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_option(BUFFER, 'tagfunc', 'tfu') + vim.api.nvim_buf_set_option(BUFFER, 'omnifunc', 'ofu') + vim.api.nvim_buf_set_option(BUFFER, 'formatexpr', 'fex') + ]] + end; + on_init = function(_client) + client = _client + exec_lua("lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)") + end; + on_handler = function(_, _, ctx) + if ctx.method == 'test' then + eq('tfu', get_buf_option("tagfunc")) + eq('ofu', get_buf_option("omnifunc")) + eq('fex', get_buf_option("formatexpr")) + client.stop() + end + end; + on_exit = function(_, _) + eq('tfu', get_buf_option("tagfunc")) + eq('ofu', get_buf_option("omnifunc")) + eq('fex', get_buf_option("formatexpr")) + end; + } + end) + it('should detach buffer on bufwipe', function() clear() exec_lua(create_server_definition) -- cgit From adfa9de8ebc4bce96d212280eccddc0306d1b013 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 10 Mar 2023 10:12:57 +0000 Subject: fix(treesitter): do not error on empty filetype Ignore instead --- test/functional/treesitter/language_spec.lua | 5 ----- 1 file changed, 5 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 747aea54b7..48e7b4b018 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -36,11 +36,6 @@ describe('treesitter language API', function() pcall_err(exec_lua, 'vim.treesitter.add("/foo/")')) end) - it('shows error for invalid filetype', function() - eq('.../language.lua:0: \'\' is not a valid filetype', - pcall_err(exec_lua, [[vim.treesitter.add('foo', { filetype = '' })]])) - end) - it('inspects language', function() local keys, fields, symbols = unpack(exec_lua([[ local lang = vim.treesitter.inspect_language('c') -- cgit From c5b9643bf1b0f6d5166b4abf6a7c3f29532aefeb Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 10 Mar 2023 10:25:10 +0000 Subject: fix(treesitter): better lang handling of get_parser() --- test/functional/treesitter/parser_spec.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 27f2e81ab2..dd36c6c9e7 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -128,7 +128,9 @@ void ui_refresh(void) it('does not get parser for empty filetype', function() insert(test_text); - eq(".../language.lua:0: '' is not a valid filetype", + eq('.../treesitter.lua:0: There is no parser available for buffer 1 and one' + .. ' could not be created because lang could not be determined. Either' + .. ' pass lang or set the buffer filetype', pcall_err(exec_lua, 'vim.treesitter.get_parser(0)')) -- Must provide language for buffers with an empty filetype -- cgit From 46b73bf22cb951151de9bf0712d42e194000b677 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 9 Mar 2023 15:28:55 +0000 Subject: perf(treesitter): more efficient foldexpr --- test/functional/treesitter/parser_spec.lua | 51 +++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 11 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index dd36c6c9e7..0f00fcfe0d 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -888,18 +888,20 @@ int x = INT_MAX; it("can fold via foldexpr", function() insert(test_text) - local levels = exec_lua([[ - vim.opt.filetype = 'c' - vim.treesitter.get_parser(0, "c") - local res = {} - for i = 1, vim.api.nvim_buf_line_count(0) do - res[i] = vim.treesitter.foldexpr(i) - end - return res - ]]) + local function get_fold_levels() + return exec_lua([[ + local res = {} + for i = 1, vim.api.nvim_buf_line_count(0) do + res[i] = vim.treesitter.foldexpr(i) + end + return res + ]]) + end + + exec_lua([[vim.treesitter.get_parser(0, "c")]]) eq({ - [1] = '>1', + [1] = '>1', [2] = '1', [3] = '1', [4] = '1', @@ -917,6 +919,33 @@ int x = INT_MAX; [16] = '3', [17] = '3', [18] = '2', - [19] = '1' }, levels) + [19] = '1' }, get_fold_levels()) + + helpers.command('1,2d') + helpers.poke_eventloop() + + exec_lua([[vim.treesitter.get_parser():parse()]]) + + helpers.poke_eventloop() + helpers.sleep(100) + + eq({ + [1] = '0', + [2] = '0', + [3] = '>1', + [4] = '1', + [5] = '1', + [6] = '0', + [7] = '0', + [8] = '>1', + [9] = '1', + [10] = '1', + [11] = '1', + [12] = '1', + [13] = '>2', + [14] = '2', + [15] = '2', + [16] = '1', + [17] = '0' }, get_fold_levels()) end) end) -- cgit From d3c8d104bc921a27d56d2438f98bf7e80b623e47 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 10 Mar 2023 17:30:40 +0100 Subject: fix(lsp): prevent lsp tests from picking up local user config (#22606) Sets `NVIM_APPNAME` for the lsp server instances and also for the `exec_lua` environment to ensure local user config doesn't interfere with the test cases. My local `ftplugin/xml.lua` broke the LSP test cases about setting `omnifunc` defaults. --- test/functional/plugin/lsp/helpers.lua | 2 ++ test/functional/plugin/lsp_spec.lua | 1 + 2 files changed, 3 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/helpers.lua b/test/functional/plugin/lsp/helpers.lua index caab174b4d..86f7da0d2c 100644 --- a/test/functional/plugin/lsp/helpers.lua +++ b/test/functional/plugin/lsp/helpers.lua @@ -13,6 +13,7 @@ function M.clear_notrace() -- solution: don't look too closely for dragons clear {env={ NVIM_LUA_NOTRACK="1"; + NVIM_APPNAME="nvim_lsp_test"; VIMRUNTIME=os.getenv"VIMRUNTIME"; }} end @@ -85,6 +86,7 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options, settings) cmd_env = { NVIM_LOG_FILE = fake_lsp_logfile; NVIM_LUA_NOTRACK = "1"; + NVIM_APPNAME = "nvim_lsp_test"; }; cmd = { vim.v.progpath, '-l', fake_lsp_code, test_name, tostring(timeout), diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 56c53a6fed..c621a5eae2 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -57,6 +57,7 @@ describe('LSP', function() return lsp.start_client { cmd_env = { NVIM_LOG_FILE = fake_lsp_logfile; + NVIM_APPNAME = "nvim_lsp_test"; }; cmd = { vim.v.progpath, '-l', fake_lsp_code, test_name; -- cgit From 8cb5b995b6e4d86035e6950d92c0c68ab4e46787 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 Mar 2023 10:05:47 +0800 Subject: vim-patch:9.0.1397: highlight for popupmenu kind and extra cannot be set (#22619) Problem: Highlight for popupmenu kind and extra cannot be set. Solution: Add PmenuKind, PmenuKindSel, PmenuExtra and PmenuExtraSel highlight groups and use them. (Gianmaria Bajo, closes vim/vim#12114) https://github.com/vim/vim/commit/6a7c7749204b256e779c245b1e999bf852ad7b64 Co-authored-by: Gianmaria Bajo --- test/functional/ui/cursor_spec.lua | 4 +-- test/functional/ui/popupmenu_spec.lua | 62 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index e261f0dfab..7e28caea04 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -212,10 +212,10 @@ describe('ui/cursor', function() if m.blinkwait then m.blinkwait = 700 end end if m.hl_id then - m.hl_id = 60 + m.hl_id = 64 m.attr = {background = Screen.colors.DarkGray} end - if m.id_lm then m.id_lm = 62 end + if m.id_lm then m.id_lm = 66 end end -- Assert the new expectation. diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index c681453294..944319c443 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -3490,6 +3490,68 @@ describe('builtin popupmenu', function() pasted | ]]) end) + + describe('"kind" and "menu"', function() + before_each(function() + screen:try_resize(30, 8) + exec([[ + func CompleteFunc( findstart, base ) + if a:findstart + return 0 + endif + return { + \ 'words': [ + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', }, + \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', }, + \ { 'word': 'aword3', 'menu': 'extra text 3', 'kind': 'W', }, + \]} + endfunc + set completeopt=menu + set completefunc=CompleteFunc + ]]) + end) + + -- oldtest: Test_pum_highlights_default() + it('default highlight groups', function() + feed('iaw') + screen:expect([[ + aword1^ | + {s:aword1 W extra text 1 }{1: }| + {n:aword2 W extra text 2 }{1: }| + {n:aword3 W extra text 3 }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{5:match 1 of 3} | + ]]) + end) + + -- oldtest: Test_pum_highlights_custom() + it('custom highlight groups', function() + exec([[ + hi PmenuKind guifg=Red guibg=Magenta + hi PmenuKindSel guifg=Red guibg=Grey + hi PmenuExtra guifg=White guibg=Magenta + hi PmenuExtraSel guifg=Black guibg=Grey + ]]) + local attrs = screen:get_default_attr_ids() + attrs.kn = {foreground = Screen.colors.Red, background = Screen.colors.Magenta} + attrs.ks = {foreground = Screen.colors.Red, background = Screen.colors.Grey} + attrs.xn = {foreground = Screen.colors.White, background = Screen.colors.Magenta} + attrs.xs = {foreground = Screen.colors.Black, background = Screen.colors.Grey} + feed('iaw') + screen:expect([[ + aword1^ | + {s:aword1 }{ks:W }{xs:extra text 1 }{1: }| + {n:aword2 }{kn:W }{xn:extra text 2 }{1: }| + {n:aword3 }{kn:W }{xn:extra text 3 }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{5:match 1 of 3} | + ]], attrs) + end) + end) end) describe('builtin popupmenu with ui/ext_multigrid', function() -- cgit From 236c20795eb9f11e21e0719b735ea741711acc08 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 11 Mar 2023 07:35:23 +0100 Subject: revert: "fix(lsp): use buffer scheme for files not stored on disk" (#22604) Although using `buffer://` for unsaved file buffers fixes issues with language servers like eclipse.jdt.ls or ansible-language-server, it breaks completion and signature help for clangd. A regression is worse than a fix for something else, so this reverts commit 896d672736b32a8f4a4fa51844b44f266dcdcc6c. The spec change is also still in dicussion, see https://github.com/microsoft/language-server-protocol/pull/1679#discussion_r1130704886 --- test/functional/fixtures/fake-lsp-server.lua | 37 ++++++++++++---------------- 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'test/functional') diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index 9cc2f6fa27..5fb86d029d 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -272,7 +272,6 @@ function tests.text_document_save_did_open() end; body = function() notify('start') - expect_notification('textDocument/didClose') expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave') notify('shutdown') @@ -293,8 +292,6 @@ function tests.text_document_sync_save_bool() end; body = function() notify('start') - expect_notification('textDocument/didClose') - expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave', {textDocument = { uri = "file://" }}) notify('shutdown') end; @@ -316,8 +313,6 @@ function tests.text_document_sync_save_includeText() end; body = function() notify('start') - expect_notification('textDocument/didClose') - expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave', { textDocument = { uri = "file://" @@ -464,7 +459,7 @@ function tests.basic_check_buffer_open() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "buffer://"; + uri = "file://"; version = 0; }; }) @@ -491,13 +486,13 @@ function tests.basic_check_buffer_open_and_change() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { @@ -527,13 +522,13 @@ function tests.basic_check_buffer_open_and_change_noeol() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n"); - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { @@ -562,13 +557,13 @@ function tests.basic_check_buffer_open_and_change_multi() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { @@ -577,7 +572,7 @@ function tests.basic_check_buffer_open_and_change_multi() }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 4; }; contentChanges = { @@ -607,13 +602,13 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { @@ -622,7 +617,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 4; }; contentChanges = { @@ -631,7 +626,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() }) expect_notification('textDocument/didClose', { textDocument = { - uri = "buffer://"; + uri = "file://"; }; }) expect_notification("finish") @@ -665,13 +660,13 @@ function tests.basic_check_buffer_open_and_change_incremental() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { @@ -708,13 +703,13 @@ function tests.basic_check_buffer_open_and_change_incremental_editing() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n"); - uri = "buffer://"; + uri = "file://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "buffer://"; + uri = "file://"; version = 3; }; contentChanges = { -- 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') 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 8065fc9aaeff734f38109aec52bf852379a5a183 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 Mar 2023 20:12:58 +0800 Subject: fix(edit): don't subtract msg_scrolled when removing double quote (#22630) With msg_grid there is no need to subtract msg_scrolled. --- test/functional/editor/mode_insert_spec.lua | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'test/functional') diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua index cd51a65be3..b00661ac3a 100644 --- a/test/functional/editor/mode_insert_spec.lua +++ b/test/functional/editor/mode_insert_spec.lua @@ -1,6 +1,7 @@ -- Insert-mode tests. local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert local expect = helpers.expect local command = helpers.command @@ -48,6 +49,48 @@ describe('insert-mode', function() feed('i"') expect('påskägg') end) + + it('double quote is removed after hit-enter prompt #22609', function() + local screen = Screen.new(60, 6) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {foreground = Screen.colors.Blue}, + [2] = {foreground = Screen.colors.SlateBlue}, + [3] = {bold = true}, + [4] = {reverse = true, bold = true}, + [5] = {background = Screen.colors.Red, foreground = Screen.colors.Red}, + [6] = {background = Screen.colors.Red, foreground = Screen.colors.White}, + [7] = {foreground = Screen.colors.SeaGreen, bold = true}, + }) + screen:attach() + feed('i') + screen:expect([[ + {1:^"} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + feed('={}') + screen:expect([[ + {1:"} | + {0:~ }| + {4: }| + ={5:{}{2:}} | + {6:E731: using Dictionary as a String} | + {7:Press ENTER or type command to continue}^ | + ]]) + feed('') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + end) end) describe('Ctrl-O', function() -- cgit From 6d0c61d90d316473eee0729363e20bf06825b09b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 11 Mar 2023 21:09:11 +0800 Subject: fix(api): set script context when setting usercmd or option (#22624) --- test/functional/api/vim_spec.lua | 18 ++++++++++++++++++ test/functional/ex_cmds/verbose_spec.lua | 17 ++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 08abf82f47..48ac491ade 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -2832,6 +2832,24 @@ describe('API', function() type = "boolean", was_set = true }, meths.get_option_info'showcmd') + + meths.set_option_value('showcmd', true, {}) + + eq({ + allows_duplicates = true, + commalist = false, + default = true, + flaglist = false, + global_local = false, + last_set_chan = 1, + last_set_linenr = 0, + last_set_sid = -9, + name = "showcmd", + scope = "global", + shortname = "sc", + type = "boolean", + was_set = true + }, meths.get_option_info'showcmd') end) end) diff --git a/test/functional/ex_cmds/verbose_spec.lua b/test/functional/ex_cmds/verbose_spec.lua index 000e746f1c..e55372e993 100644 --- a/test/functional/ex_cmds/verbose_spec.lua +++ b/test/functional/ex_cmds/verbose_spec.lua @@ -7,7 +7,7 @@ local exec_capture = helpers.exec_capture local write_file = helpers.write_file local call_viml_function = helpers.meths.call_function -describe('lua :verbose', function() +local function last_set_tests(cmd) local script_location, script_file -- All test cases below use the same nvim instance. setup(function() @@ -46,7 +46,7 @@ endfunction\ let &tw = s:return80()\ ", true) ]]) - exec(':source '..script_file) + exec(cmd .. ' ' .. script_file) end) teardown(function() @@ -106,6 +106,9 @@ test_group FileType end) it('"Last set" for command defined by nvim_command', function() + if cmd == 'luafile' then + pending('nvim_command does not set the script context') + end local result = exec_capture(':verbose command Bdelete') eq(string.format([[ Name Args Address Complete Definition @@ -123,7 +126,7 @@ test_group FileType script_location), result) end) - it('"Last set for function', function() + it('"Last set" for function', function() local result = exec_capture(':verbose function Close_Window') eq(string.format([[ function Close_Window() abort @@ -140,6 +143,14 @@ test_group FileType Last set from %s line 22]], script_location), result) end) +end + +describe('lua :verbose when using :source', function() + last_set_tests('source') +end) + +describe('lua :verbose when using :luafile', function() + last_set_tests('luafile') end) describe('lua verbose:', function() -- cgit From 23dc2a59b6e13b0dbab47c6c64ac5a55095b258b Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 11 Mar 2023 14:50:14 +0100 Subject: fix(lsp): send didClose on buffer rename (#22623) Subset of https://github.com/neovim/neovim/pull/22407 that was reverted in https://github.com/neovim/neovim/pull/22604 If a buffer is renamed sending `didClose` for the old buffer helps ensure the language server doesn't keep a stale document in memory. --- test/functional/fixtures/fake-lsp-server.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'test/functional') diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index 5fb86d029d..001cd5770a 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -272,6 +272,7 @@ function tests.text_document_save_did_open() end; body = function() notify('start') + expect_notification('textDocument/didClose') expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave') notify('shutdown') -- cgit From 58bbc2ea0b3dfed13471e8cc0447d7598be24276 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 10 Mar 2023 16:40:27 +0000 Subject: refactor(treesitter): add Range type aliase for Range4|Range6 --- test/functional/treesitter/parser_spec.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 0f00fcfe0d..c6ca65f9a1 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -196,7 +196,7 @@ void ui_refresh(void) local manyruns = q(100) -- First run should be at least 400x slower than an 100 subsequent runs. - local factor = is_os('win') and 300 or 400 + local factor = is_os('win') and 200 or 400 assert(factor * manyruns < firstrun, ('firstrun: %f ms, manyruns: %f ms'):format(firstrun / 1e6, manyruns / 1e6)) end) @@ -277,13 +277,13 @@ void ui_refresh(void) eq('void', res2) end) - it('support getting text where start of node is past EOF', function() + it('support getting text where start of node is one past EOF', function() local text = [[ def run a = <<~E end]] insert(text) - local result = exec_lua([[ + eq('', exec_lua[[ local fake_node = {} function fake_node:start() return 3, 0, 23 @@ -291,12 +291,14 @@ end]] function fake_node:end_() return 3, 0, 23 end - function fake_node:range() + function fake_node:range(bytes) + if bytes then + return 3, 0, 23, 3, 0, 23 + end return 3, 0, 3, 0 end - return vim.treesitter.get_node_text(fake_node, 0) == nil + return vim.treesitter.get_node_text(fake_node, 0) ]]) - eq(true, result) end) it('support getting empty text if node range is zero width', function() -- cgit From 9d574f8dd7248a4cf8dcbe615f3058d34efb7ac3 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 11 Mar 2023 22:56:16 +0100 Subject: ci: bump to windows 2022 Skip failing funcitonaltests. Use jobstart() instead termopen() for oldtests to prevent CI freezing. --- test/functional/autocmd/termxx_spec.lua | 1 + test/functional/ex_cmds/mksession_spec.lua | 2 ++ test/functional/ui/output_spec.lua | 1 + 3 files changed, 4 insertions(+) (limited to 'test/functional') diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua index 63b5617eef..a9980dda04 100644 --- a/test/functional/autocmd/termxx_spec.lua +++ b/test/functional/autocmd/termxx_spec.lua @@ -50,6 +50,7 @@ describe('autocmd TermClose', function() end) it('triggers when long-running terminal job gets stopped', function() + skip(is_os('win')) nvim('set_option', 'shell', is_os('win') and 'cmd.exe' or 'sh') command('autocmd TermClose * let g:test_termclose = 23') command('terminal') diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua index 0a0c7ca410..0a1cdd93aa 100644 --- a/test/functional/ex_cmds/mksession_spec.lua +++ b/test/functional/ex_cmds/mksession_spec.lua @@ -18,6 +18,8 @@ local is_os = helpers.is_os local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec' +if helpers.skip(helpers.is_os('win')) then return end + describe(':mksession', function() local session_file = file_prefix .. '.vim' local tab_dir = file_prefix .. '.d' diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index 223844405e..954431d689 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -54,6 +54,7 @@ describe("shell command :!", function() it("throttles shell-command output greater than ~10KB", function() skip(is_os('openbsd'), 'FIXME #10804') + skip(is_os('win')) child_session.feed_data((":!%s REP 30001 foo\n"):format(testprg('shell-test'))) -- If we observe any line starting with a dot, then throttling occurred. -- cgit From 1c4b3d41b538078234282cfba74e5cf07c42c916 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 12 Mar 2023 10:40:27 +0800 Subject: fix(sleep): correct cursor placement (#22639) Just setcursor_mayforce(true) is enough as Nvim uses msg_grid. --- test/functional/ui/float_spec.lua | 274 +++++++++++++++++++++++++++++++++++++- 1 file changed, 273 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 6759510ad1..6e67ec1f24 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -8909,7 +8909,6 @@ describe('float window', function() ]], win_viewport={ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; }} - else screen:expect{grid=[[ ^ | @@ -8952,6 +8951,279 @@ describe('float window', function() test_float_move_close('autocmd BufWinLeave * ++once redraw') end) end) + + it(':sleep cursor placement #22639', function() + local float_opts = {relative = 'editor', row = 1, col = 1, width = 4, height = 3} + local win = meths.open_win(meths.create_buf(false, false), true, float_opts) + feed('iabcd') + feed(':sleep 100') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100^ | + ## grid 4 + {1:ab }| + {1:cd }| + {2:~ }| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2}; + }} + else + screen:expect{grid=[[ + | + {0:~}{1:ab }{0: }| + {0:~}{1:cd }{0: }| + {0:~}{2:~ }{0: }| + {0:~ }| + {0:~ }| + :sleep 100^ | + ]]} + end + + feed('') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100 | + ## grid 4 + {1:ab }| + {1:c^d }| + {2:~ }| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2}; + }} + else + screen:expect{grid=[[ + | + {0:~}{1:ab }{0: }| + {0:~}{1:c^d }{0: }| + {0:~}{2:~ }{0: }| + {0:~ }| + {0:~ }| + :sleep 100 | + ]]} + end + feed('') + screen:expect_unchanged() + + meths.win_set_config(win, {border = 'single'}) + feed(':sleep 100') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100^ | + ## grid 4 + {5:┌────┐}| + {5:│}{1:ab }{5:│}| + {5:│}{1:cd }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2}; + }} + else + screen:expect{grid=[[ + | + {0:~}{5:┌────┐}{0: }| + {0:~}{5:│}{1:ab }{5:│}{0: }| + {0:~}{5:│}{1:cd }{5:│}{0: }| + {0:~}{5:│}{2:~ }{5:│}{0: }| + {0:~}{5:└────┘}{0: }| + :sleep 100^ | + ]]} + end + + feed('') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100 | + ## grid 4 + {5:┌────┐}| + {5:│}{1:ab }{5:│}| + {5:│}{1:c^d }{5:│}| + {5:│}{2:~ }{5:│}| + {5:└────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2}; + }} + else + screen:expect{grid=[[ + | + {0:~}{5:┌────┐}{0: }| + {0:~}{5:│}{1:ab }{5:│}{0: }| + {0:~}{5:│}{1:c^d }{5:│}{0: }| + {0:~}{5:│}{2:~ }{5:│}{0: }| + {0:~}{5:└────┘}{0: }| + :sleep 100 | + ]]} + end + feed('') + screen:expect_unchanged() + + command('setlocal winbar=foo') + feed(':sleep 100') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100^ | + ## grid 4 + {5:┌────┐}| + {5:│}{3:foo }{5:│}| + {5:│}{1:ab }{5:│}| + {5:│}{1:cd }{5:│}| + {5:└────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 1, curcol = 1, linecount = 2}; + }} + else + screen:expect{grid=[[ + | + {0:~}{5:┌────┐}{0: }| + {0:~}{5:│}{3:foo }{5:│}{0: }| + {0:~}{5:│}{1:ab }{5:│}{0: }| + {0:~}{5:│}{1:cd }{5:│}{0: }| + {0:~}{5:└────┘}{0: }| + :sleep 100^ | + ]]} + end + + feed('') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + :sleep 100 | + ## grid 4 + {5:┌────┐}| + {5:│}{3:foo }{5:│}| + {5:│}{1:ab }{5:│}| + {5:│}{1:c^d }{5:│}| + {5:└────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 1, curcol = 1, linecount = 2}; + }} + else + screen:expect{grid=[[ + | + {0:~}{5:┌────┐}{0: }| + {0:~}{5:│}{3:foo }{5:│}{0: }| + {0:~}{5:│}{1:ab }{5:│}{0: }| + {0:~}{5:│}{1:c^d }{5:│}{0: }| + {0:~}{5:└────┘}{0: }| + :sleep 100 | + ]]} + end + feed('') + screen:expect_unchanged() + end) end describe('with ext_multigrid', function() -- cgit From 172227a44642b67ec8af5b438e5373a3daf61fdb Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 12 Mar 2023 12:10:27 +0800 Subject: fix(screen): correctly draw background and eob with 'rightleft' (#22640) --- test/functional/ui/float_spec.lua | 49 +++++++++++++++++++++++++++++++++++ test/functional/ui/highlight_spec.lua | 16 ++++++++++++ 2 files changed, 65 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 6e67ec1f24..4e691512c1 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -9224,6 +9224,55 @@ describe('float window', function() feed('') screen:expect_unchanged() end) + + it('with rightleft and border #22640', function() + local float_opts = {relative='editor', width=5, height=3, row=1, col=1, border='single'} + meths.open_win(meths.create_buf(false, false), true, float_opts) + command('setlocal rightleft') + feed('iabcdef') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {5:┌─────┐}| + {5:│}{1: cba}{5:│}| + {5:│}{1: ^fed}{5:│}| + {5:│}{2: ~}{5:│}| + {5:└─────┘}| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 2}; + }} + else + screen:expect{grid=[[ + | + {0:~}{5:┌─────┐}{0: }| + {0:~}{5:│}{1: cba}{5:│}{0: }| + {0:~}{5:│}{1: ^fed}{5:│}{0: }| + {0:~}{5:│}{2: ~}{5:│}{0: }| + {0:~}{5:└─────┘}{0: }| + | + ]]} + end + end) end describe('with ext_multigrid', function() diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 288c2a214f..2bbc29b78f 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -1812,6 +1812,22 @@ describe("'winhighlight' highlight", function() ]]) end) + it('works for background color in rightleft window in vsplit #22640', function() + screen:try_resize(40, 6) + insert('aa') + command('setlocal rightleft') + command('botright vsplit') + command('setlocal winhl=Normal:Background1') + screen:expect([[ + aa│{1: ^aa}| + {0: ~}│{2: ~}| + {0: ~}│{2: ~}| + {0: ~}│{2: ~}| + {4:[No Name] [+] }{3:[No Name] [+] }| + | + ]]) + end) + it('handles undefined groups', function() command("set winhl=Normal:Background1") screen:expect([[ -- cgit From 314f20a44fdfdc382b0ce9d124290d3e7d702d42 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 12 Mar 2023 15:41:39 +0800 Subject: test: use a wider screen in the rightleft winhl test (#22641) With a wide screen this actually previously caused an overflow. --- test/functional/ui/highlight_spec.lua | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 2bbc29b78f..d5e0eefb41 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -1812,19 +1812,28 @@ describe("'winhighlight' highlight", function() ]]) end) - it('works for background color in rightleft window in vsplit #22640', function() - screen:try_resize(40, 6) + it('works for background color in rightleft window #22640', function() + -- Use a wide screen to also check that this doesn't overflow linebuf_attr. + screen:try_resize(80, 6) insert('aa') command('setlocal rightleft') - command('botright vsplit') command('setlocal winhl=Normal:Background1') screen:expect([[ - aa│{1: ^aa}| - {0: ~}│{2: ~}| - {0: ~}│{2: ~}| - {0: ~}│{2: ~}| - {4:[No Name] [+] }{3:[No Name] [+] }| - | + {1: ^aa}| + {2: ~}| + {2: ~}| + {2: ~}| + {2: ~}| + | + ]]) + command('botright vsplit') + screen:expect([[ + {1: aa│ ^aa}| + {2: ~}{1:│}{2: ~}| + {2: ~}{1:│}{2: ~}| + {2: ~}{1:│}{2: ~}| + {4:[No Name] [+] }{3:[No Name] [+] }| + | ]]) end) -- cgit From d15abd1be4ae85b10174e3ee139d3b7605e87577 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sun, 12 Mar 2023 09:45:28 +0100 Subject: fix(lsp): use line start/end for visual line selection (#22632) Fixes https://github.com/neovim/neovim/issues/22629 --- test/functional/plugin/lsp_spec.lua | 47 +++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index c621a5eae2..a6e50ac82c 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -3554,6 +3554,7 @@ describe('LSP', function() vim.cmd.normal('v') vim.api.nvim_win_set_cursor(0, { 2, 3 }) vim.lsp.buf.format({ bufnr = bufnr, false }) + vim.lsp.stop_client(client_id) return server.messages ]]) eq("textDocument/rangeFormatting", result[3].method) @@ -3563,6 +3564,52 @@ describe('LSP', function() } eq(expected_range, result[3].params.range) end) + it('format formats range in visual line mode', function() + exec_lua(create_server_definition) + local result = exec_lua([[ + local server = _create_server({ capabilities = { + documentFormattingProvider = true, + documentRangeFormattingProvider = true, + }}) + local bufnr = vim.api.nvim_get_current_buf() + local client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + vim.api.nvim_win_set_buf(0, bufnr) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {'foo', 'bar baz'}) + vim.api.nvim_win_set_cursor(0, { 1, 2 }) + vim.cmd.normal('V') + vim.api.nvim_win_set_cursor(0, { 2, 1 }) + vim.lsp.buf.format({ bufnr = bufnr, false }) + + -- Format again with visual lines going from bottom to top + -- Must result in same formatting + vim.cmd.normal("") + vim.api.nvim_win_set_cursor(0, { 2, 1 }) + vim.cmd.normal('V') + vim.api.nvim_win_set_cursor(0, { 1, 2 }) + vim.lsp.buf.format({ bufnr = bufnr, false }) + + vim.lsp.stop_client(client_id) + return server.messages + ]]) + local expected_methods = { + "initialize", + "initialized", + "textDocument/rangeFormatting", + "$/cancelRequest", + "textDocument/rangeFormatting", + "$/cancelRequest", + "shutdown", + "exit", + } + eq(expected_methods, vim.tbl_map(function(x) return x.method end, result)) + -- uses first column of start line and last column of end line + local expected_range = { + start = { line = 0, character = 0 }, + ['end'] = { line = 1, character = 7 }, + } + eq(expected_range, result[3].params.range) + eq(expected_range, result[5].params.range) + end) it('Aborts with notify if no clients support requested method', function() exec_lua(create_server_definition) exec_lua([[ -- cgit From 846a056744bf458d4376cd7638c94f7c82862046 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 9 Mar 2023 11:45:20 +0100 Subject: refactor(redraw): make cursor position redraw use the "redraw later" pattern --- test/functional/ex_cmds/map_spec.lua | 2 +- test/functional/ui/messages_spec.lua | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ex_cmds/map_spec.lua b/test/functional/ex_cmds/map_spec.lua index ec912053b2..a197b81cc5 100644 --- a/test/functional/ex_cmds/map_spec.lua +++ b/test/functional/ex_cmds/map_spec.lua @@ -152,7 +152,7 @@ describe('Screen', function() ~ | ~ | ~ | - > | + -- INSERT -- | ]]) end) diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 212d3aee7d..db45e80dae 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -474,8 +474,7 @@ describe('ui/ext_messages', function() ]], msg_history={{ content = {{ "stuff" }}, kind = "echomsg", - }}, showmode={{ "-- INSERT --", 3 }}, - messages={{ + }}, messages={{ content = {{ "Press ENTER or type command to continue", 4}}, kind = "return_prompt" }}} -- cgit From fd2ece278b0941ec6673489e88868120e86b834a Mon Sep 17 00:00:00 2001 From: Matthias Deiml Date: Sun, 12 Mar 2023 23:58:46 +0100 Subject: feat(ui): add scroll_delta to win_viewport event #19270 scroll_delta contains how much the top line of a window moved since the last time win_viewport was emitted. It is expected to be used to implement smooth scrolling. For this purpose it only counts "virtual" or "displayed" so folds should count as one line. Because of this it adds extra information that cannot be computed from the topline parameter. Fixes #19227 --- test/functional/ui/cmdline_spec.lua | 4 +- test/functional/ui/float_spec.lua | 169 +++++++++++++++++----------------- test/functional/ui/multigrid_spec.lua | 91 ++++++++++++++---- test/functional/ui/screen.lua | 9 +- test/functional/ui/searchhl_spec.lua | 4 +- 5 files changed, 167 insertions(+), 110 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 1c9ac7f7ba..a9469bdf2d 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -1241,7 +1241,7 @@ describe('cmdheight=0', function() {1:~ }| ## grid 3 ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} feed '/p' @@ -1261,7 +1261,7 @@ describe('cmdheight=0', function() ## grid 3 /p^ | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} end) diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 4e691512c1..62e8221e87 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -1433,8 +1433,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1476,8 +1476,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1519,8 +1519,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1562,8 +1562,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1606,8 +1606,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1647,8 +1647,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1688,8 +1688,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1731,8 +1731,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1781,8 +1781,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 5, curcol = 0, linecount = 6}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 5, curcol = 0, linecount = 6, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1868,8 +1868,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1911,8 +1911,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1954,8 +1954,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -1997,8 +1997,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -2048,8 +2048,8 @@ describe('float window', function() ]], float_pos={ [4] = { { id = 1001 }, "NW", 1, 0, 0, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -2106,8 +2106,8 @@ describe('float window', function() ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 0, 5, true } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -2165,8 +2165,8 @@ describe('float window', function() [5] = { { id = 1002 }, "NW", 1, 0, 5, true, 50 }, [6] = { { id = -1 }, "NW", 5, 4, 0, false, 100 } }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3, linecount=3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3, linecount=3, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -2618,7 +2618,8 @@ describe('float window', function() curline = 0, curcol = 3, linecount = 2, - win = { id = 1000 } + sum_scroll_delta = 0, + win = { id = 1000 }, }, [4] = { topline = 0, @@ -2626,6 +2627,7 @@ describe('float window', function() curline = 0, curcol = 3, linecount = 2, + sum_scroll_delta = 0, win = { id = 1001 } }, [5] = { @@ -2634,6 +2636,7 @@ describe('float window', function() curline = 0, curcol = 0, linecount = 1, + sum_scroll_delta = 0, win = { id = 1002 } } }} @@ -7149,8 +7152,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "NW", 1, 2, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} meths.input_mouse('left', 'press', '', 5, 0, 0) @@ -7179,8 +7182,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "NW", 1, 2, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} meths.input_mouse('left', 'drag', '', 5, 1, 2) @@ -7209,8 +7212,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "NW", 1, 2, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -7279,8 +7282,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} meths.input_mouse('left', 'press', '', 5, 1, 1) @@ -7311,8 +7314,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} meths.input_mouse('left', 'drag', '', 5, 2, 3) @@ -7343,8 +7346,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -7413,8 +7416,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} meths.input_mouse('left', 'press', '', 5, 1, 0) @@ -7444,8 +7447,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 3, sum_scroll_delta = 0}; }} meths.input_mouse('left', 'drag', '', 5, 2, 2) @@ -7475,8 +7478,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "NW", 1, 1, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 3, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8228,8 +8231,8 @@ describe('float window', function() ]], float_pos={ [4] = { { id = 1001 }, "NW", 1, 2, 5, true }; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8285,10 +8288,10 @@ describe('float window', function() [5] = { { id = 1002 }, "NW", 1, 3, 8, true }; [6] = { { id = 1003 }, "NW", 1, 4, 10, true }; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1}; - [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0}; + [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8333,8 +8336,8 @@ describe('float window', function() ]], float_pos={ [4] = { { id = 1001 }, "NW", 1, 2, 5, true }; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8390,10 +8393,10 @@ describe('float window', function() [5] = { { id = 1002 }, "NW", 1, 4, 10, true }; [6] = { { id = 1003 }, "NW", 1, 3, 8, true }; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8453,10 +8456,10 @@ describe('float window', function() [5] = {{id = 1002}, "NW", 1, 2, 6, true, 50}; [6] = {{id = 1003}, "NW", 1, 3, 7, true, 40}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8502,8 +8505,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 1, 5, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8549,8 +8552,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 0, 4, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8604,8 +8607,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "SW", 1, 9, 0, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8658,8 +8661,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "SW", 1, 9, 0, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8701,7 +8704,7 @@ describe('float window', function() {0:~ }| ## grid 3 ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8756,8 +8759,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8816,8 +8819,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8865,8 +8868,8 @@ describe('float window', function() ]], float_pos={ [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -8907,7 +8910,7 @@ describe('float window', function() ## grid 3 | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index 71adeb42a4..2525314b8e 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -2127,7 +2127,7 @@ describe('ext_multigrid', function() ## grid 3 | ]], win_viewport={ - [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1} + [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0} }} insert([[ Lorem ipsum dolor sit amet, consectetur @@ -2162,7 +2162,7 @@ describe('ext_multigrid', function() ## grid 3 | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7, linecount = 11}, + [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7, linecount = 11, sum_scroll_delta = 5}, }} @@ -2187,7 +2187,7 @@ describe('ext_multigrid', function() ## grid 3 | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 2, botline = 9, curline = 7, curcol = 0, linecount = 11}, + [2] = {win = {id = 1000}, topline = 2, botline = 9, curline = 7, curcol = 0, linecount = 11, sum_scroll_delta = 2}, }} command("split") @@ -2211,8 +2211,8 @@ describe('ext_multigrid', function() reprehenderit in voluptate velit esse cillum | ^dolore eu fugiat nulla pariatur. Excepteur sint | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11}, - [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 7, curcol = 0, linecount = 11}, + [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11, sum_scroll_delta = 6}, + [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 7, curcol = 0, linecount = 11, sum_scroll_delta = 5}, }} feed("b") @@ -2236,8 +2236,8 @@ describe('ext_multigrid', function() reprehenderit in voluptate velit esse ^cillum | dolore eu fugiat nulla pariatur. Excepteur sint | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11}, - [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 6, curcol = 38, linecount = 11}, + [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11, sum_scroll_delta = 6}, + [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 6, curcol = 38, linecount = 11, sum_scroll_delta = 5}, }} feed("2k") @@ -2261,8 +2261,8 @@ describe('ext_multigrid', function() ea commodo consequat. Duis aute irure dolor in | reprehenderit in voluptate velit esse cillum | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11}, - [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38, linecount = 11}, + [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11, sum_scroll_delta = 6}, + [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38, linecount = 11, sum_scroll_delta = 4}, }} -- handles non-current window @@ -2287,8 +2287,59 @@ describe('ext_multigrid', function() ea commodo consequat. Duis aute irure dolor in | reprehenderit in voluptate velit esse cillum | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10, linecount = 11}, - [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38, linecount = 11}, + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}, + [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38, linecount = 11, sum_scroll_delta = 4}, + }} + + -- sum_scroll_delta works with folds + feed('zfj') + screen:expect{grid=[[ + ## grid 1 + [4:------------------------------------------------]| + [4:------------------------------------------------]| + [4:------------------------------------------------]| + {11:[No Name] [+] }| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + ## grid 3 + | + ## grid 4 + {13:^+-- 2 lines: exercitation ullamco laboris nisi }| + reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}, + [4] = {win = {id = 1001}, topline = 4, botline = 9, curline = 4, curcol = 38, linecount = 11, sum_scroll_delta = 4}, + }} + + feed('') + screen:expect{grid=[[ + ## grid 1 + [4:------------------------------------------------]| + [4:------------------------------------------------]| + [4:------------------------------------------------]| + {11:[No Name] [+] }| + [2:------------------------------------------------]| + [2:------------------------------------------------]| + {12:[No Name] [+] }| + [3:------------------------------------------------]| + ## grid 2 + Lorem ipsum dolor sit amet, consectetur | + adipisicing elit, sed do eiusmod tempor | + ## grid 3 + | + ## grid 4 + ^reprehenderit in voluptate velit esse cillum | + dolore eu fugiat nulla pariatur. Excepteur sint | + occaecat cupidatat non proident, sunt in culpa | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10, linecount = 11, sum_scroll_delta = 0}, + [4] = {win = {id = 1001}, topline = 6, botline = 10, curline = 6, curcol = 0, linecount = 11, sum_scroll_delta = 5}, }} end) @@ -2314,7 +2365,7 @@ describe('ext_multigrid', function() ## grid 3 | ]], win_viewport={ - [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1} + [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0} }} insert([[ Lorem ipsum dolor sit amet, consectetur @@ -2349,7 +2400,7 @@ describe('ext_multigrid', function() ## grid 3 | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7, linecount = 11}, + [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7, linecount = 11, sum_scroll_delta = 5}, }} meths.input_mouse('left', 'press', '', 1,5, 1) @@ -2376,7 +2427,7 @@ describe('ext_multigrid', function() ## grid 3 {7:-- VISUAL --} | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 6, botline = 12, curline = 10, curcol = 1, linecount = 11}, + [2] = {win = {id = 1000}, topline = 6, botline = 12, curline = 10, curcol = 1, linecount = 11, sum_scroll_delta = 6}, }} end) @@ -2414,8 +2465,8 @@ describe('ext_multigrid', function() {1:~ }| {1:~ }| ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} -- XXX: hack to get notifications. Could use next_msg() also. @@ -2459,8 +2510,8 @@ describe('ext_multigrid', function() {1:~ }| {1:~ }| ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} eq({}, win_pos) @@ -2497,8 +2548,8 @@ describe('ext_multigrid', function() {1:~ }| {1:~ }| ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; }} eq({}, win_pos) end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index e5a449fa66..f5ae9c8e89 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -803,14 +803,17 @@ function Screen:_handle_win_pos(grid, win, startrow, startcol, width, height) self.float_pos[grid] = nil end -function Screen:_handle_win_viewport(grid, win, topline, botline, curline, curcol, linecount) +function Screen:_handle_win_viewport(grid, win, topline, botline, curline, curcol, linecount, scroll_delta) + -- accumulate scroll delta + local last_scroll_delta = self.win_viewport[grid] and self.win_viewport[grid].sum_scroll_delta or 0 self.win_viewport[grid] = { win = win, topline = topline, botline = botline, curline = curline, curcol = curcol, - linecount = linecount + linecount = linecount, + sum_scroll_delta = scroll_delta + last_scroll_delta } end @@ -1348,7 +1351,7 @@ local function fmt_ext_state(name, state) for k,v in pairs(state) do str = (str.." ["..k.."] = {win = {id = "..v.win.id.."}, topline = " ..v.topline..", botline = "..v.botline..", curline = "..v.curline - ..", curcol = "..v.curcol..", linecount = "..v.linecount.."};\n") + ..", curcol = "..v.curcol..", linecount = "..v.linecount..", scroll_delta = "..v.scroll_delta.."};\n") end return str .. "}" elseif name == "float_pos" then diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 916a5eb537..3c8dceb8cb 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -52,7 +52,7 @@ describe('search highlighting', function() {1:~ }| /text^ | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 9, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 9, linecount = 2, sum_scroll_delta = 0}; }} end) @@ -616,7 +616,7 @@ describe('search highlighting', function() {1:~ }| {4:search hit BOTTOM, continuing at TOP} | ]], win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 11, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 11, linecount = 2, sum_scroll_delta = 0}; }} -- check highlights work also in folds -- cgit From 5aec6114693dea442023857e071bf6f90c8c109a Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 13 Mar 2023 08:14:02 +0800 Subject: test(float_spec): add missing sum_scroll_delta #22648 --- test/functional/ui/float_spec.lua | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 62e8221e87..bae83537e5 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -8986,8 +8986,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -9028,8 +9028,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -9075,8 +9075,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -9119,8 +9119,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -9166,8 +9166,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 1, curcol = 1, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -9210,8 +9210,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 1, curcol = 1, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 1, curcol = 1, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ @@ -9261,8 +9261,8 @@ describe('float window', function() ]], float_pos={ [4] = {{id = 1001}, "NW", 1, 1, 1, true, 50}; }, win_viewport={ - [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; - [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 2}; + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 3, curline = 1, curcol = 2, linecount = 2, sum_scroll_delta = 0}; }} else screen:expect{grid=[[ -- 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/api/vim_spec.lua | 2 +- test/functional/lua/commands_spec.lua | 30 +++++++++++++++++++----------- test/functional/lua/vim_spec.lua | 21 ++++++++++++++++++++- 3 files changed, 40 insertions(+), 13 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 48ac491ade..2af041c706 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -4042,7 +4042,7 @@ describe('API', function() it('splits arguments correctly for Lua callback', function() meths.exec_lua([[ local function FooFunc(opts) - vim.pretty_print(opts.fargs) + vim.print(opts.fargs) end vim.api.nvim_create_user_command("Foo", FooFunc, { nargs = '+' }) 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 2daf0b37dbfe54a4510c1033531dbaefd168c387 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Mon, 13 Mar 2023 03:29:11 +0100 Subject: feat(options)!: deprecate paste, remove pastetoggle (#22647) we cannot remove 'paste'. It is very common in plugins and configs. 'pastetoggle' can and should be removed though, it's a total waste of everyone's time because it generates bug reports and doesn't work well, and is useless because bracketed-paste works better. --- test/functional/options/pastetoggle_spec.lua | 90 ---------------------------- 1 file changed, 90 deletions(-) delete mode 100644 test/functional/options/pastetoggle_spec.lua (limited to 'test/functional') diff --git a/test/functional/options/pastetoggle_spec.lua b/test/functional/options/pastetoggle_spec.lua deleted file mode 100644 index 40c14fa187..0000000000 --- a/test/functional/options/pastetoggle_spec.lua +++ /dev/null @@ -1,90 +0,0 @@ -local helpers = require('test.functional.helpers')(after_each) - -local clear = helpers.clear -local feed = helpers.feed -local command = helpers.command -local eq = helpers.eq -local expect = helpers.expect -local eval = helpers.eval -local insert = helpers.insert -local meths = helpers.meths -local sleep = helpers.sleep - -describe("'pastetoggle' option", function() - before_each(clear) - it("toggles 'paste'", function() - command('set pastetoggle=a') - eq(0, eval('&paste')) - feed('a') - -- Need another key so that the vgetorpeek() function returns. - feed('j') - eq(1, eval('&paste')) - end) - describe("multiple key 'pastetoggle'", function() - before_each(function() - eq(0, eval('&paste')) - command('set timeoutlen=1 ttimeoutlen=10000') - end) - it('is waited for when chars are typed', function() - local pastetoggle = 'lllll' - command('set pastetoggle=' .. pastetoggle) - feed(pastetoggle:sub(0, 2)) - -- sleep() for long enough that vgetorpeek() is gotten into, but short - -- enough that ttimeoutlen is not reached. - sleep(200) - feed(pastetoggle:sub(3, -1)) - -- Need another key so that the vgetorpeek() function returns. - feed('j') - eq(1, eval('&paste')) - end) - - it('is not waited for when there are no typed chars after mapped chars', function() - command('set pastetoggle=abc') - command('imap d a') - meths.feedkeys('id', 't', true) - -- sleep() for long enough that vgetorpeek() is gotten into, but short - -- enough that ttimeoutlen is not reached. - sleep(200) - feed('bc') - -- Need another key so that the vgetorpeek() function returns. - feed('j') - -- 'ttimeoutlen' should NOT apply - eq(0, eval('&paste')) - end) - - it('is waited for when there are typed chars after mapped chars', function() - command('set pastetoggle=abc') - command('imap d a') - meths.feedkeys('idb', 't', true) - -- sleep() for long enough that vgetorpeek() is gotten into, but short - -- enough that ttimeoutlen is not reached. - sleep(200) - feed('c') - -- Need another key so that the vgetorpeek() function returns. - feed('j') - -- 'ttimeoutlen' should apply - eq(1, eval('&paste')) - end) - - it('is waited for when there are typed chars after noremapped chars', function() - command('set pastetoggle=abc') - command('inoremap d a') - meths.feedkeys('idb', 't', true) - -- sleep() for long enough that vgetorpeek() is gotten into, but short - -- enough that ttimeoutlen is not reached. - sleep(200) - feed('c') - -- Need another key so that the vgetorpeek() function returns. - feed('j') - -- 'ttimeoutlen' should apply - eq(1, eval('&paste')) - end) - end) - it('does not interfere with character-find', function() - insert('foo,bar') - feed('0') - command('set pastetoggle=,sp') - feed('dt,') - expect(',bar') - end) -end) -- cgit From b466e1d289180fad212a93b173034787fd6be9a8 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Mon, 13 Mar 2023 04:15:24 +0100 Subject: test: unskip working Windows tests (#22537) Some tests that were previously not working have started to work again for unspecified reasons, so let's enable them. --- test/functional/core/job_spec.lua | 2 -- test/functional/terminal/mouse_spec.lua | 2 -- test/functional/terminal/scrollback_spec.lua | 2 -- test/functional/treesitter/parser_spec.lua | 2 -- 4 files changed, 8 deletions(-) (limited to 'test/functional') diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 1bae626b98..613dff577a 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -88,7 +88,6 @@ describe('jobs', function() end) it('append environment with pty #env', function() - skip(is_os('win')) nvim('command', "let $VAR = 'abc'") nvim('command', "let $TOTO = 'goodbye world'") nvim('command', "let g:job_opts.pty = v:true") @@ -806,7 +805,6 @@ describe('jobs', function() end) it('can be called recursively', function() - skip(is_os('win'), "TODO: Need `cat`") source([[ let g:opts = {} let g:counter = 0 diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index 50c8f5e7df..ac76217023 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -68,7 +68,6 @@ describe(':terminal mouse', function() end) it('does not leave terminal mode on left-release', function() - skip(is_os('win')) feed('') eq('t', eval('mode(1)')) end) @@ -232,7 +231,6 @@ describe(':terminal mouse', function() end) describe('with a split window and other buffer', function() - skip(is_os('win')) before_each(function() feed(':vsp') screen:expect([[ diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index a4899c8219..00a35a5c6c 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -140,7 +140,6 @@ describe(':terminal scrollback', function() describe('and height decreased by 1', function() - if skip(is_os('win')) then return end local function will_hide_top_line() feed([[]]) screen:try_resize(screen._width - 2, screen._height - 1) @@ -347,7 +346,6 @@ end) describe(':terminal prints more lines than the screen height and exits', function() it('will push extra lines to scrollback', function() - skip(is_os('win')) clear() local screen = Screen.new(30, 7) screen:attach({rgb=false}) diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index c6ca65f9a1..e872861d2a 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -7,7 +7,6 @@ local exec_lua = helpers.exec_lua local pcall_err = helpers.pcall_err local feed = helpers.feed local is_os = helpers.is_os -local skip = helpers.skip before_each(clear) @@ -741,7 +740,6 @@ int x = INT_MAX; end) it("should not inject bad languages", function() - skip(is_os('win')) exec_lua([=[ vim.treesitter.add_directive("inject-bad!", function(match, _, _, pred, metadata) metadata.language = "{" -- cgit From 3e8955094a615f2a805350050bc1703a294b1b85 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 14 Mar 2023 02:12:26 +0100 Subject: test: re-bundle cat on windows (#21255) The builtin cat was removed in 4bc9229ecbec514e9a87cfc4be88ea27a971e9a1 as it is not used during runtime but only for tests. However, it is a very small and useful utility program that we need for a lot of our tests, so there's no harm in bundling it, and it helps us avoid complicating our build system by having two versions of neovim (neovim for users and neovim for testing). Also skip tests if "grep" or "sleep" isn't available. --- test/functional/core/channels_spec.lua | 2 ++ test/functional/provider/perl_spec.lua | 5 ----- test/functional/ui/messages_spec.lua | 3 +++ 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'test/functional') diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua index 8275575c24..5771ddcb94 100644 --- a/test/functional/core/channels_spec.lua +++ b/test/functional/core/channels_spec.lua @@ -230,6 +230,7 @@ describe('channels', function() end) it('can use buffered output mode', function() + skip(funcs.executable('grep') == 0, 'missing "grep" command') source([[ let g:job_opts = { \ 'on_stdout': function('OnEvent'), @@ -262,6 +263,7 @@ describe('channels', function() end) it('can use buffered output mode with no stream callback', function() + skip(funcs.executable('grep') == 0, 'missing "grep" command') source([[ function! OnEvent(id, data, event) dict call rpcnotify(1, a:event, a:id, a:data, self.stdout) diff --git a/test/functional/provider/perl_spec.lua b/test/functional/provider/perl_spec.lua index ce92831f4c..5ab807e90d 100644 --- a/test/functional/provider/perl_spec.lua +++ b/test/functional/provider/perl_spec.lua @@ -9,8 +9,6 @@ local curbufmeths = helpers.curbufmeths local insert = helpers.insert local expect = helpers.expect local feed = helpers.feed -local is_os = helpers.is_os -local skip = helpers.skip do clear() @@ -26,8 +24,6 @@ before_each(function() end) describe('legacy perl provider', function() - skip(is_os('win')) - it('feature test', function() eq(1, eval('has("perl")')) end) @@ -70,7 +66,6 @@ describe('legacy perl provider', function() end) describe('perl provider', function() - skip(is_os('win')) teardown(function () os.remove('Xtest-perl-hello.pl') os.remove('Xtest-perl-hello-plugin.pl') diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index db45e80dae..a92b55ae5d 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -16,6 +16,8 @@ local poke_eventloop = helpers.poke_eventloop local assert_alive = helpers.assert_alive local is_os = helpers.is_os local is_ci = helpers.is_ci +local funcs = helpers.funcs +local skip = helpers.skip describe('ui/ext_messages', function() local screen @@ -1916,6 +1918,7 @@ aliquip ex ea commodo consequat.]]) end) it('with :!cmd does not crash on resize', function() + skip(funcs.executable('sleep') == 0, 'missing "sleep" command') feed(':!sleep 1') screen:expect{grid=[[ | -- cgit From 0f1e2b6686694d878795fa090d4a08ba0f8acb4d Mon Sep 17 00:00:00 2001 From: bfredl Date: Mon, 13 Mar 2023 20:38:21 +0100 Subject: fix(screen): redraw the ruler for a current floating window Semi-regression. The "ruler" behavior for a floating window was never really specified but in practice followed the users cursor movements in normal mode in a focused float, which seems like a reasonable behavior to now specify. --- test/functional/ui/float_spec.lua | 92 +++++++++++++++++++++++++++++++++++++++ test/functional/ui/screen.lua | 2 +- 2 files changed, 93 insertions(+), 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index bae83537e5..5916c8e238 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -2184,6 +2184,98 @@ describe('float window', function() end end) + it('show ruler of current floating window', function() + command 'set ruler' + local buf = meths.create_buf(false, false) + meths.buf_set_lines(buf, 0, -1, true, {'aaa aab ', + 'abb acc '}) + meths.open_win(buf, true, {relative='editor', width=9, height=3, row=0, col=5}) + feed 'gg' + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + 1,1 All | + ## grid 5 + {1:^aaa aab }| + {1:abb acc }| + {2:~ }| + ]], float_pos={ + [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + {1:^aaa aab } | + {0:~ }{1:abb acc }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + 1,1 All | + ]]} + end + + feed 'w' + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + 1,5 All | + ## grid 5 + {1:aaa ^aab }| + {1:abb acc }| + {2:~ }| + ]], float_pos={ + [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 0, curcol = 4, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + {1:aaa ^aab } | + {0:~ }{1:abb acc }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + 1,5 All | + ]]} + end + end) + it('can have minimum size', function() insert("the background text") local buf = meths.create_buf(false, true) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index f5ae9c8e89..83424d3bea 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -1351,7 +1351,7 @@ local function fmt_ext_state(name, state) for k,v in pairs(state) do str = (str.." ["..k.."] = {win = {id = "..v.win.id.."}, topline = " ..v.topline..", botline = "..v.botline..", curline = "..v.curline - ..", curcol = "..v.curcol..", linecount = "..v.linecount..", scroll_delta = "..v.scroll_delta.."};\n") + ..", curcol = "..v.curcol..", linecount = "..v.linecount..", sum_scroll_delta = "..v.sum_scroll_delta.."};\n") end return str .. "}" elseif name == "float_pos" then -- cgit From 8dde7c907ca9ad365895bded2c2f59e08f65d3ed Mon Sep 17 00:00:00 2001 From: hrsh7th <629908+hrsh7th@users.noreply.github.com> Date: Tue, 14 Mar 2023 20:59:43 +0900 Subject: fix(lsp): vim.lsp.util.apply_text_edits cursor validation #22636 Problem Using wrong variable when checking the cursor position is valid or not in vim.lsp.util.apply_text_edits. Solution Use the correct variable. --- test/functional/plugin/lsp_spec.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index a6e50ac82c..ddbeef6d84 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1714,6 +1714,9 @@ describe('LSP', function() end) it('fix the cursor col', function() + -- append empty last line. See #22636 + exec_lua('vim.api.nvim_buf_set_lines(...)', 1, -1, -1, true, {''}) + funcs.nvim_win_set_cursor(0, { 2, 11 }) local edits = { make_edit(1, 7, 1, 11, '') @@ -1725,6 +1728,7 @@ describe('LSP', function() 'Third line of text'; 'Fourth line of text'; 'å å ɧ 汉语 ↥ 🤦 🦄'; + ''; }, buf_lines(1)) eq({ 2, 7 }, funcs.nvim_win_get_cursor(0)) end) -- cgit From 4f7879dff0f0dc22ddf4cb2a2095b88605a3bab0 Mon Sep 17 00:00:00 2001 From: Ivan Date: Tue, 14 Mar 2023 13:08:37 +0100 Subject: fix(lsp): kill buffers after renaming a directory #22618 Problem: When LSP client renames a directory, opened buffers in the edfitor are not renamed or closed. Then `:wall` shows errors. https://github.com/neovim/neovim/blob/master/runtime/lua/vim/lsp/util.lua#L776 works correctly if you try to rename a single file, but doesn't delete old buffers with `old_fname` is a dir. Solution: Update the logic in runtime/lua/vim/lsp/util.lua:rename() Fixes #22617 --- test/functional/plugin/lsp_spec.lua | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'test/functional') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index ddbeef6d84..8b5e7d56ac 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2200,7 +2200,22 @@ describe('LSP', function() eq(true, exists) os.remove(new) end) - it('Can rename a direcory', function() + it("Kills old buffer after renaming an existing file", function() + local old = helpers.tmpname() + write_file(old, 'Test content') + local new = helpers.tmpname() + os.remove(new) -- only reserve the name, file must not exist for the test scenario + local lines = exec_lua([[ + local old = select(1, ...) + local oldbufnr = vim.fn.bufadd(old) + local new = select(2, ...) + vim.lsp.util.rename(old, new) + return vim.fn.bufloaded(oldbufnr) + ]], old, new) + eq(0, lines) + os.remove(new) + end) + it('Can rename a directory', function() -- only reserve the name, file must not exist for the test scenario local old_dir = helpers.tmpname() local new_dir = helpers.tmpname() @@ -2209,16 +2224,19 @@ describe('LSP', function() helpers.mkdir_p(old_dir) - local file = "file" + local file = 'file.txt' write_file(old_dir .. pathsep .. file, 'Test content') - exec_lua([[ + local lines = exec_lua([[ local old_dir = select(1, ...) local new_dir = select(2, ...) + local pathsep = select(3, ...) + local oldbufnr = vim.fn.bufadd(old_dir .. pathsep .. 'file') vim.lsp.util.rename(old_dir, new_dir) - ]], old_dir, new_dir) - + return vim.fn.bufloaded(oldbufnr) + ]], old_dir, new_dir, pathsep) + eq(0, lines) eq(false, exec_lua('return vim.loop.fs_stat(...) ~= nil', old_dir)) eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', new_dir)) eq(true, exec_lua('return vim.loop.fs_stat(...) ~= nil', new_dir .. pathsep .. file)) -- 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') 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 eb3fcf652bbcab01cd6d55a0e2c120c09cbe69d3 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 17 Mar 2023 21:19:34 +0800 Subject: vim-patch:9.0.0194: cursor displayed in wrong position after removing text prop (#22706) Problem: Cursor displayed in wrong position after removing text prop. (Ben Jackson) Solution: Invalidate the cursor position. (closes vim/vim#10898) https://github.com/vim/vim/commit/326c5d36e7cb8526330565109c17b4a13ff790ae Co-authored-by: Bram Moolenaar --- test/functional/ui/decorations_spec.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 4759d68200..d03d2f1374 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -1247,6 +1247,7 @@ if (h->n_buckets < new_n_buckets) { // expand ]]} meths.buf_clear_namespace(0, ns, 0, -1) + -- Cursor should be drawn on the correct line. #22704 screen:expect{grid=[[ if (h->n_buckets < new_n_buckets) { // expand | khkey_t *new_keys = (khkey_t *) | @@ -1254,8 +1255,8 @@ if (h->n_buckets < new_n_buckets) { // expand hkey_t)); | h->keys = new_keys; | if (kh_is_map && val_size) { | - char *new_vals = {3:krealloc}( h->vals_buf, new_n_| - buck^ets * val_size); | + ^char *new_vals = {3:krealloc}( h->vals_buf, new_n_| + buckets * val_size); | h->vals_buf = new_vals; | } | } | @@ -1263,7 +1264,6 @@ if (h->n_buckets < new_n_buckets) { // expand ]]} end) - it('works with text at the beginning of the buffer', function() insert(example_text) feed 'gg' -- 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') 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 8bdcc91dc8ae1d7a0734945935300e002eb879c1 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 18 Mar 2023 16:50:22 +0800 Subject: test(highlight_spec): fix warning in Visual highlight test (#22719) Problem: Warning in Visual highlight test. Solution: Don't move cursor back and forth. --- test/functional/ui/highlight_spec.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index d5e0eefb41..dce886ac91 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -376,7 +376,6 @@ describe('highlight', function() -- Vertical cursor: highlights char-at-cursor. #8983 command('set guicursor=a:block-blinkon175') - feed('gg$vhhh') screen:expect([[ line1 foo{1:^ bar} | | -- cgit From 8916669d50243f6d4cdfb9480ef1b4e7ccdcfbb6 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 18 Mar 2023 19:06:24 +0800 Subject: test(statuscolumn_spec): remove unnecessary feed('lh') It is no longer needed after #22706. --- test/functional/ui/statuscolumn_spec.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'test/functional') diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index dfbdbb4898..d9385ef221 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -461,7 +461,6 @@ describe('statuscolumn', function() vim.api.nvim_buf_set_extmark(0, ns, 7, 0, { virt_lines_leftcol = true, virt_lines = {{{"virt", ""}}} }) ]]) - feed('lh') -- force update cursor row screen:expect([[ 4 aaaaa | 5 aaaaa | -- cgit From 204a8b17c8ebab1619cc47a920a06dcc348d75f7 Mon Sep 17 00:00:00 2001 From: luukvbaal <31730729+luukvbaal@users.noreply.github.com> Date: Sat, 18 Mar 2023 12:44:44 +0100 Subject: fix(column): rebuild status column when sign column is invalidated (#22690) * fix(column): rebuild status column when sign column is invalidated Problem: When implementing a custom sign column through `'statuscolumn'`, the status column is not properly rebuilt when the sign column width changes. Solution: Force a rebuild of the status column when the sign column width is invalidated. * test(column): 'statuscolumn' has correct width when (un)placing signs --- test/functional/ui/statuscolumn_spec.lua | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index d9385ef221..0a253455ad 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -557,4 +557,40 @@ describe('statuscolumn', function() | ]]) end) + + it("has correct width with custom sign column when (un)placing signs", function() + screen:try_resize(screen._width, 6) + exec_lua([[ + vim.cmd.norm('gg') + vim.o.signcolumn = 'no' + vim.fn.sign_define('sign', { text = 'ss' }) + _G.StatusCol = function() + local s = vim.fn.sign_getplaced(1)[1].signs + local sign = '' + if #s > 0 then + sign = vim.v.lnum == 5 and 'ss' or ' ' + end + return vim.v.lnum .. '%=' .. sign + end + vim.o.statuscolumn = "%!v:lua.StatusCol()" + vim.fn.sign_place(0, '', 'sign', 1, { lnum = 5 }) + ]]) + screen:expect([[ + 1 ^aaaaa | + 2 aaaaa | + 3 aaaaa | + 4 aaaaa | + 5 ssaaaaa | + | + ]]) + command('sign unplace 1') + screen:expect([[ + 1 ^aaaaa | + 2 aaaaa | + 3 aaaaa | + 4 aaaaa | + 5 aaaaa | + | + ]]) + end) end) -- cgit From 3b28fb4cd9e1ef877968b4ffabf4d6b1cb17aa07 Mon Sep 17 00:00:00 2001 From: Patrick McFarland Date: Tue, 14 Mar 2023 13:21:53 -0400 Subject: fix(float): remove -1 in height clamp Problem: Clamp for height in floating windows enforced no more than editor height - 1, disallowing full editor height floating windows when using cmdheight=0 Solution: Clamp to full height, removing the -1. Tested to give the intended results with cmdheight=0, 1, or more than 1. This also inadvertently fixes a rendering error with cmdheight >1 where the bottom border would be overlapped by the cmdline. --- test/functional/ui/float_spec.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 5916c8e238..32f28dce26 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -2015,7 +2015,7 @@ describe('float window', function() it('terminates border on edge of viewport when window extends past viewport', function() local buf = meths.create_buf(false, false) - meths.open_win(buf, false, {relative='editor', width=40, height=7, row=0, col=0, border="single"}) + meths.open_win(buf, false, {relative='editor', width=40, height=7, row=0, col=0, border="single", zindex=201}) if multigrid then screen:expect{grid=[[ ## grid 1 @@ -2046,7 +2046,7 @@ describe('float window', function() {5:│}{2:~ }{5:│}| {5:└────────────────────────────────────────┘}| ]], float_pos={ - [4] = { { id = 1001 }, "NW", 1, 0, 0, true } + [4] = { { id = 1001 }, "NW", 1, 0, 0, true, 201 } }, win_viewport={ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; @@ -2058,8 +2058,8 @@ describe('float window', function() {5:│}{2:~ }{5:│}| {5:│}{2:~ }{5:│}| {5:│}{2:~ }{5:│}| + {5:│}{2:~ }{5:│}| {5:└──────────────────────────────────────┘}| - | ]]} end end) @@ -3723,9 +3723,9 @@ describe('float window', function() ]], float_pos=expected_pos} else screen:expect([[ - {1:very } | - {0:~ }{1:^float }{0: }| - | + {1:such } | + {0:~ }{1:very }{0: }| + ^ | ]]) end -- cgit From 8786b2066d39e45295eacfe7b10263af4a330f2e Mon Sep 17 00:00:00 2001 From: Enan Ajmain <3nan.ajmain@gmail.com> Date: Sun, 19 Mar 2023 23:23:34 +0600 Subject: fix: pasting in terminal buffer on windows #22566 Problem: On Windows, pasting multiple lines on a terminal buffer cause all the lines to appear on the same line, i.e., the line breaks are lost. Cause: Windows shells expect "\r\n" as line break but "terminal_paste" function uses "\n". Solution: Use "\r\n" as line break for pasting in terminal buffer on Windows. Note: Although this issue was reported with powershell set as 'shell', it occurs in cmd too. Fixes #14621 --- test/functional/terminal/buffer_spec.lua | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'test/functional') diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 9c8b983ff7..676be151ee 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -429,3 +429,71 @@ it('terminal truncates number of composing characters to 5', function() meths.chan_send(chan, 'a' .. composing:rep(8)) retry(nil, nil, function() eq('a' .. composing:rep(5), meths.get_current_line()) end) end) + +if is_os('win') then + describe(':terminal in Windows', function() + local screen + + before_each(function() + clear() + feed_command('set modifiable swapfile undolevels=20') + poke_eventloop() + local cmd = '["cmd.exe","/K","PROMPT=$g$s"]' + screen = thelpers.screen_setup(nil, cmd) + end) + + it('"put" operator sends data normally', function() + feed('G') + feed_command('let @a = ":: tty ready"') + feed_command('let @a = @a . "\\n:: appended " . @a . "\\n\\n"') + feed('"ap"ap') + screen:expect([[ + | + > :: tty ready | + > :: appended :: tty ready | + > :: tty ready | + > :: appended :: tty ready | + ^> {2: } | + :let @a = @a . "\n:: appended " . @a . "\n\n" | + ]]) + -- operator count is also taken into consideration + feed('3"ap') + screen:expect([[ + > :: appended :: tty ready | + > :: tty ready | + > :: appended :: tty ready | + > :: tty ready | + > :: appended :: tty ready | + ^> {2: } | + :let @a = @a . "\n:: appended " . @a . "\n\n" | + ]]) + end) + + it('":put" command sends data normally', function() + feed('G') + feed_command('let @a = ":: tty ready"') + feed_command('let @a = @a . "\\n:: appended " . @a . "\\n\\n"') + feed_command('put a') + screen:expect([[ + | + > :: tty ready | + > :: appended :: tty ready | + > {2: } | + | + ^ | + :put a | + ]]) + -- line argument is only used to move the cursor + feed_command('6put a') + screen:expect([[ + | + > :: tty ready | + > :: appended :: tty ready | + > :: tty ready | + > :: appended :: tty ready | + ^> {2: } | + :6put a | + ]]) + end) + end) +end -- cgit From ecc4d0e435d618828b938d78fbded7fbe1314760 Mon Sep 17 00:00:00 2001 From: Enan Ajmain <3nan.ajmain@gmail.com> Date: Mon, 20 Mar 2023 03:25:12 +0600 Subject: fix(shell): on Windows :make does not echo #22728 Problem: On Windows, :make does not display the output of the program it runs. The cause is the default 'shellpipe'. On Linux, nvim uses `tee` to redirect the output to both stdout and the error file. In Windows, for both cmd.exe and powershell, the output is only redirected to the error file. Solution: - On Windows, change the 'shellpipe' default to "2>&1| tee". - Nvim includes `tee` in its Windows package. - Document recommended defaults for powershell. Fixes #12910 --- test/functional/ex_cmds/make_spec.lua | 4 ++-- test/functional/helpers.lua | 12 +++++++----- test/functional/vimscript/system_spec.lua | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'test/functional') diff --git a/test/functional/ex_cmds/make_spec.lua b/test/functional/ex_cmds/make_spec.lua index bf585ee44c..f42e21e4cb 100644 --- a/test/functional/ex_cmds/make_spec.lua +++ b/test/functional/ex_cmds/make_spec.lua @@ -34,8 +34,8 @@ describe(':make', function() nvim('set_option', 'makeprg', testprg('shell-test')) local out = eval('execute("make")') -- Ensure there are no "shell returned X" messages between - -- command and last line (indicating zero exit) - matches('LastExitCode%s+[(]', out) + -- command and last line (indicating zero exit) + matches('LastExitCode%s+ready [$]%s+[(]', out) matches('\n.*%: ready [$]', out) end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 43e5b73608..b485352c94 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -553,16 +553,18 @@ function module.set_shell_powershell(fake) assert(found) end local shell = found and (is_os('win') and 'powershell' or 'pwsh') or module.testprg('pwsh-test') - local set_encoding = '[Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();' - local cmd = set_encoding..'Remove-Item -Force '..table.concat(is_os('win') + local cmd = 'Remove-Item -Force '..table.concat(is_os('win') and {'alias:cat', 'alias:echo', 'alias:sleep', 'alias:sort'} or {'alias:echo'}, ',')..';' module.exec([[ let &shell = ']]..shell..[[' set shellquote= shellxquote= - let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ]]..cmd..[[' - let &shellpipe = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode' - let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode' + let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command ' + let &shellcmdflag .= '[Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.UTF8Encoding]::new();' + let &shellcmdflag .= '$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';' + let &shellcmdflag .= ']]..cmd..[[' + let &shellredir = '2>&1 | %%{ "$_" } | Out-File %s; exit $LastExitCode' + let &shellpipe = '2>&1 | %%{ "$_" } | Tee-Object %s; exit $LastExitCode' ]]) return found end diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua index 7ada1c4bea..158dfe86d7 100644 --- a/test/functional/vimscript/system_spec.lua +++ b/test/functional/vimscript/system_spec.lua @@ -644,12 +644,12 @@ describe('shell :!', function() if is_os('win') then feed(':4verbose %!sort /R') screen:expect{ - any=[[Executing command: .?& { Get%-Content .* | & sort /R } 2>&1 | Out%-File %-Encoding UTF8 .*; exit $LastExitCode"]] + any=[[Executing command: .?& { Get%-Content .* | & sort /R } 2>&1 | %%{ "$_" } | Out%-File .*; exit $LastExitCode"]] } else feed(':4verbose %!sort -r') screen:expect{ - any=[[Executing command: .?& { Get%-Content .* | & sort %-r } 2>&1 | Out%-File %-Encoding UTF8 .*; exit $LastExitCode"]] + any=[[Executing command: .?& { Get%-Content .* | & sort %-r } 2>&1 | %%{ "$_" } | Out%-File .*; exit $LastExitCode"]] } end feed('') -- 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/api/vim_spec.lua | 25 +++++++++++++++++++++++++ test/functional/lua/filetype_spec.lua | 15 +++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 2af041c706..ff1bfef591 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1518,6 +1518,31 @@ describe('API', function() nvim('get_option_value', 'filetype', {buf = buf}) eq({1, 9}, nvim('win_get_cursor', win)) end) + + it('can get default option values for filetypes', 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, nvim('get_option_value', option, { filetype = ft })) + end + end + + command'au FileType lua setlocal commentstring=NEW\\ %s' + + eq('NEW %s', nvim('get_option_value', 'commentstring', { filetype = 'lua' })) + end) + + it('errors for bad FileType autocmds', function() + command'au FileType lua setlocal commentstring=BAD' + eq([[FileType Autocommands for "lua": Vim(setlocal):E537: 'commentstring' must be empty or contain %s: commentstring=BAD]], + pcall_err(nvim, 'get_option_value', 'commentstring', { filetype = 'lua' })) + end) + end) describe('nvim_{get,set}_current_buf, nvim_list_bufs', function() 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') 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') 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 +++++++++++++------------------ test/functional/terminal/buffer_spec.lua | 2 +- 2 files changed, 55 insertions(+), 80 deletions(-) (limited to 'test/functional') 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) diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 676be151ee..b983ea89d5 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -202,7 +202,7 @@ describe(':terminal buffer', function() -- Save the buffer number of the terminal for later testing. local tbuf = eval('bufnr("%")') - local exitcmd = helpers.is_os('win') + local exitcmd = is_os('win') and "['cmd', '/c', 'exit']" or "['sh', '-c', 'exit']" source([[ -- 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') 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') 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') 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') 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 c0fe6c040e19ef9102a8507ffcbd88b83186326a Mon Sep 17 00:00:00 2001 From: Null Chilly <56817415+nullchilly@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:31:39 +0700 Subject: feat(api): add nvim_get_hl (#22693) Problem: no way of getting all highlight group definitions in a namespace. Solution: add `nvim_get_hl()`, deprecate `nvim_get_hl_by_name()` and `nvim_get_hl_by_id()`. --- test/functional/api/highlight_spec.lua | 219 +++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index eb7d0f7b47..de3eb4e798 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -369,3 +369,222 @@ describe("API: set highlight", function() assert_alive() end) end) + +describe('API: get highlight', function() + local highlight_color = { + fg = tonumber('0xff0000'), + bg = tonumber('0x0032aa'), + ctermfg = 8, + ctermbg = 15, + } + local highlight1 = { + bg = highlight_color.bg, + fg = highlight_color.fg, + bold = true, + italic = true, + } + local highlight2 = { + ctermbg = highlight_color.ctermbg, + ctermfg = highlight_color.ctermfg, + underline = true, + reverse = true, + } + local highlight3_config = { + bg = highlight_color.bg, + fg = highlight_color.fg, + ctermbg = highlight_color.ctermbg, + ctermfg = highlight_color.ctermfg, + bold = true, + italic = true, + reverse = true, + underdashed = true, + strikethrough = true, + altfont = true, + cterm = { + italic = true, + reverse = true, + strikethrough = true, + altfont = true, + nocombine = true, + }, + } + local highlight3_result = { + bg = highlight_color.bg, + fg = highlight_color.fg, + ctermbg = highlight_color.ctermbg, + ctermfg = highlight_color.ctermfg, + bold = true, + italic = true, + nocombine = true, + reverse = true, + underdashed = true, + strikethrough = true, + altfont = true, + } + + local function get_ns() + -- Test namespace filtering behavior + local ns2 = meths.create_namespace('Another_namespace') + meths.set_hl(ns2, 'Test_hl', { ctermfg = 23 }) + meths.set_hl(ns2, 'Test_another_hl', { link = 'Test_hl' }) + meths.set_hl(ns2, 'Test_hl_link', { link = 'Test_another_hl' }) + meths.set_hl(ns2, 'Test_another_hl_link', { link = 'Test_hl_link' }) + + local ns = meths.create_namespace('Test_set_hl') + meths.set_hl_ns(ns) + + return ns + end + + before_each(clear) + + it('validation', function() + eq( + 'Invalid highlight name: expected String, got Integer', + pcall_err(meths.get_hl, 0, { name = 177 }) + ) + eq('Highlight id out of bounds', pcall_err(meths.get_hl, 0, { name = 'Test set hl' })) + end) + + it('can get all highlights in current namespace', function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', { bg = '#B4BEFE' }) + meths.set_hl(ns, 'Test_hl_link', { link = 'Test_hl' }) + eq({ + Test_hl = { + bg = 11845374 + }, + Test_hl_link = { + link = 'Test_hl' + } + }, meths.get_hl(ns, {})) + end) + + it('can get gui highlight', function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', highlight1) + eq(highlight1, meths.get_hl(ns, { name = 'Test_hl' })) + end) + + it('can get cterm highlight', function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', highlight2) + eq(highlight2, meths.get_hl(ns, { name = 'Test_hl' })) + end) + + it('can get empty cterm attr', function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', { cterm = {} }) + eq({}, meths.get_hl(ns, { name = 'Test_hl' })) + end) + + it('cterm attr defaults to gui attr', function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', highlight1) + eq(highlight1, meths.get_hl(ns, { name = 'Test_hl' })) + end) + + it('can overwrite attr for cterm', function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', highlight3_config) + eq(highlight3_result, meths.get_hl(ns, { name = 'Test_hl' })) + end) + + it('only allows one underline attribute #22371', function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', { + underdouble = true, + underdotted = true, + cterm = { + underline = true, + undercurl = true, + }, + }) + eq({ undercurl = true, underdotted = true }, meths.get_hl(ns, { name = 'Test_hl' })) + end) + + it('can get a highlight in the global namespace', function() + meths.set_hl(0, 'Test_hl', highlight2) + eq(highlight2, meths.get_hl(0, { name = 'Test_hl' })) + + meths.set_hl(0, 'Test_hl', { background = highlight_color.bg }) + eq({ + bg = 12970, + }, meths.get_hl(0, { name = 'Test_hl' })) + + meths.set_hl(0, 'Test_hl2', highlight3_config) + eq(highlight3_result, meths.get_hl(0, { name = 'Test_hl2' })) + + -- Colors are stored with the name they are defined, but + -- with canonical casing + meths.set_hl(0, 'Test_hl3', { bg = 'reD', fg = 'bLue' }) + eq({ + bg = 16711680, + fg = 255, + }, meths.get_hl(0, { name = 'Test_hl3' })) + end) + + local expected_rgb = { + altfont = true, + bg = 16776960, + bold = true, + ctermbg = 10, + fg = 16711680, + italic = true, + nocombine = true, + reverse = true, + sp = 255, + strikethrough = true, + underline = true, + } + local expected = { + bg = 16776960, + bold = true, + ctermbg = 10, + fg = 16711680, + sp = 255, + underline = true, + } + local expected_undercurl = { + bg = 16776960, + ctermbg = 10, + fg = 16711680, + sp = 255, + undercurl = true, + underline = true, + } + + it('nvim_get_hl by id', function() + local hl_id = meths.get_hl_id_by_name('NewHighlight') + + command( + 'hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold' + ) + eq(expected, meths.get_hl(0, { id = hl_id })) + + -- Test 0 argument + eq('Highlight id out of bounds', pcall_err(meths.get_hl, 0, { id = 0 })) + + eq( + 'Invalid highlight id: expected Integer, got String', + pcall_err(meths.get_hl, 0, { id = 'Test_set_hl' }) + ) + + -- Test all highlight properties. + command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine') + eq(expected_rgb, meths.get_hl(0, { id = hl_id })) + + -- Test undercurl + command('hi NewHighlight gui=undercurl') + eq(expected_undercurl, meths.get_hl(0, { id = hl_id })) + end) + + it('can correctly detect links', function() + command('hi String guifg=#a6e3a1') + command('hi link @string string') + command('hi link @string.cpp @string') + eq({ fg = 10937249 }, meths.get_hl(0, { name = 'String' })) + eq({ link = 'String' }, meths.get_hl(0, { name = '@string' })) + eq({ fg = 10937249 }, meths.get_hl(0, { name = '@string.cpp', link = false })) + end) +end) -- 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') 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 6d267ad30cf539f520b46e3c92939f7031ce116f Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 23 Mar 2023 12:44:05 +0100 Subject: fix(api): make nvim_get_hl return 'cterm' attrs properly --- test/functional/api/highlight_spec.lua | 64 ++++++++++------------------------ 1 file changed, 19 insertions(+), 45 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index de3eb4e798..65b13bebf7 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -380,14 +380,14 @@ describe('API: get highlight', function() local highlight1 = { bg = highlight_color.bg, fg = highlight_color.fg, - bold = true, - italic = true, + bold = true, italic = true, + cterm = {bold = true, italic = true}, } local highlight2 = { ctermbg = highlight_color.ctermbg, ctermfg = highlight_color.ctermfg, - underline = true, - reverse = true, + underline = true, reverse = true, + cterm = {underline = true, reverse = true}, } local highlight3_config = { bg = highlight_color.bg, @@ -413,13 +413,8 @@ describe('API: get highlight', function() fg = highlight_color.fg, ctermbg = highlight_color.ctermbg, ctermfg = highlight_color.ctermfg, - bold = true, - italic = true, - nocombine = true, - reverse = true, - underdashed = true, - strikethrough = true, - altfont = true, + bold = true, italic = true, reverse = true, underdashed = true, strikethrough = true, altfont = true, + cterm = {italic = true, nocombine = true, reverse = true, strikethrough = true, altfont = true} } local function get_ns() @@ -500,7 +495,8 @@ describe('API: get highlight', function() undercurl = true, }, }) - eq({ undercurl = true, underdotted = true }, meths.get_hl(ns, { name = 'Test_hl' })) + eq({ underdotted = true, cterm = { undercurl = true} }, + meths.get_hl(ns, { name = 'Test_hl' })) end) it('can get a highlight in the global namespace', function() @@ -524,43 +520,15 @@ describe('API: get highlight', function() }, meths.get_hl(0, { name = 'Test_hl3' })) end) - local expected_rgb = { - altfont = true, - bg = 16776960, - bold = true, - ctermbg = 10, - fg = 16711680, - italic = true, - nocombine = true, - reverse = true, - sp = 255, - strikethrough = true, - underline = true, - } - local expected = { - bg = 16776960, - bold = true, - ctermbg = 10, - fg = 16711680, - sp = 255, - underline = true, - } - local expected_undercurl = { - bg = 16776960, - ctermbg = 10, - fg = 16711680, - sp = 255, - undercurl = true, - underline = true, - } - it('nvim_get_hl by id', function() local hl_id = meths.get_hl_id_by_name('NewHighlight') command( 'hi NewHighlight cterm=underline ctermbg=green guifg=red guibg=yellow guisp=blue gui=bold' ) - eq(expected, meths.get_hl(0, { id = hl_id })) + eq({ fg = 16711680, bg = 16776960, sp = 255, bold = true, + ctermbg = 10, cterm = { underline = true }, + }, meths.get_hl(0, { id = hl_id })) -- Test 0 argument eq('Highlight id out of bounds', pcall_err(meths.get_hl, 0, { id = 0 })) @@ -572,11 +540,17 @@ describe('API: get highlight', function() -- Test all highlight properties. command('hi NewHighlight gui=underline,bold,italic,reverse,strikethrough,altfont,nocombine') - eq(expected_rgb, meths.get_hl(0, { id = hl_id })) + eq({ fg = 16711680, bg = 16776960, sp = 255, + altfont = true, bold = true, italic = true, nocombine = true, reverse = true, strikethrough = true, underline = true, + ctermbg = 10, cterm = {underline = true}, + }, meths.get_hl(0, { id = hl_id })) -- Test undercurl command('hi NewHighlight gui=undercurl') - eq(expected_undercurl, meths.get_hl(0, { id = hl_id })) + eq({ fg = 16711680, bg = 16776960, sp = 255, undercurl = true, + ctermbg = 10, + cterm = {underline = true}, + }, meths.get_hl(0, { id = hl_id })) end) it('can correctly detect links', function() -- cgit From cbbf8bd666c8419fdab80a0887948c8a36279c19 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 24 Mar 2023 14:43:14 +0000 Subject: feat(treesitter)!: deprecate top level indexes to modules (#22761) The following top level Treesitter functions have been moved: - vim.treesitter.inspect_language() -> vim.treesitter.language.inspect() - vim.treesitter.get_query_files() -> vim.treesitter.query.get_files() - vim.treesitter.set_query() -> vim.treesitter.query.set() - vim.treesitter.query.set_query() -> vim.treesitter.query.set() - vim.treesitter.get_query() -> vim.treesitter.query.get() - vim.treesitter.query.get_query() -> vim.treesitter.query.get() - vim.treesitter.parse_query() -> vim.treesitter.query.parse() - vim.treesitter.query.parse_query() -> vim.treesitter.query.parse() - vim.treesitter.add_predicate() -> vim.treesitter.query.add_predicate() - vim.treesitter.add_directive() -> vim.treesitter.query.add_directive() - vim.treesitter.list_predicates() -> vim.treesitter.query.list_predicates() - vim.treesitter.list_directives() -> vim.treesitter.query.list_directives() - vim.treesitter.query.get_range() -> vim.treesitter.get_range() - vim.treesitter.query.get_node_text() -> vim.treesitter.get_node_text() --- test/functional/treesitter/highlight_spec.lua | 6 ++-- test/functional/treesitter/language_spec.lua | 14 ++++----- test/functional/treesitter/node_spec.lua | 2 +- test/functional/treesitter/parser_spec.lua | 44 +++++++++++++-------------- 4 files changed, 33 insertions(+), 33 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 2a2311c0fa..44e6500008 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -376,7 +376,7 @@ describe('treesitter highlighting', function() exec_lua [[ parser = vim.treesitter.get_parser(0, "c") - query = vim.treesitter.parse_query("c", "(declaration) @decl") + query = vim.treesitter.query.parse("c", "(declaration) @decl") local nodes = {} for _, node in query:iter_captures(parser:parse()[1]:root(), 0, 0, 19) do @@ -481,8 +481,8 @@ describe('treesitter highlighting', function() exec_lua [[ local injection_query = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)" - require('vim.treesitter.query').set_query("c", "highlights", hl_query) - require('vim.treesitter.query').set_query("c", "injections", injection_query) + vim.treesitter.query.set("c", "highlights", hl_query) + vim.treesitter.query.set("c", "injections", injection_query) vim.treesitter.highlighter.new(vim.treesitter.get_parser(0, "c")) ]] diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 48e7b4b018..9b871a72fb 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -18,27 +18,27 @@ describe('treesitter language API', function() -- actual message depends on platform matches("Failed to load parser for language 'borklang': uv_dlopen: .+", - pcall_err(exec_lua, "parser = vim.treesitter.add('borklang', { path = 'borkbork.so' })")) + pcall_err(exec_lua, "parser = vim.treesitter.language.add('borklang', { path = 'borkbork.so' })")) - eq(false, exec_lua("return pcall(vim.treesitter.add, 'borklang')")) + eq(false, exec_lua("return pcall(vim.treesitter.language.add, 'borklang')")) - eq(false, exec_lua("return pcall(vim.treesitter.add, 'borklang', { path = 'borkbork.so' })")) + eq(false, exec_lua("return pcall(vim.treesitter.language.add, 'borklang', { path = 'borkbork.so' })")) eq(".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers", - pcall_err(exec_lua, "parser = vim.treesitter.inspect_language('borklang')")) + pcall_err(exec_lua, "parser = vim.treesitter.language.inspect('borklang')")) matches("Failed to load parser: uv_dlsym: .+", - pcall_err(exec_lua, 'vim.treesitter.add("c", { symbol_name = "borklang" })')) + pcall_err(exec_lua, 'vim.treesitter.language.add("c", { symbol_name = "borklang" })')) end) it('shows error for invalid language name', function() eq(".../language.lua:0: '/foo/' is not a valid language name", - pcall_err(exec_lua, 'vim.treesitter.add("/foo/")')) + pcall_err(exec_lua, 'vim.treesitter.language.add("/foo/")')) end) it('inspects language', function() local keys, fields, symbols = unpack(exec_lua([[ - local lang = vim.treesitter.inspect_language('c') + local lang = vim.treesitter.language.inspect('c') local keys, symbols = {}, {} for k,_ in pairs(lang) do keys[k] = true diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua index a82dce47b7..5ff73d3a8d 100644 --- a/test/functional/treesitter/node_spec.lua +++ b/test/functional/treesitter/node_spec.lua @@ -26,7 +26,7 @@ describe('treesitter node API', function() parser = vim.treesitter.get_parser(0, "c") tree = parser:parse()[1] root = tree:root() - lang = vim.treesitter.inspect_language('c') + lang = vim.treesitter.language.inspect('c') function node_text(node) return query.get_node_text(node, 0) diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index e872861d2a..72a8cd9e9b 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -23,7 +23,7 @@ describe('treesitter parser API', function() parser = vim.treesitter.get_parser(0, "c") tree = parser:parse()[1] root = tree:root() - lang = vim.treesitter.inspect_language('c') + lang = vim.treesitter.language.inspect('c') ]]) eq("", exec_lua("return tostring(tree)")) @@ -171,7 +171,7 @@ void ui_refresh(void) it("supports runtime queries", function() local ret = exec_lua [[ - return require"vim.treesitter.query".get_query("c", "highlights").captures[1] + return vim.treesitter.query.get("c", "highlights").captures[1] ]] eq('variable', ret) @@ -184,7 +184,7 @@ void ui_refresh(void) local query, n = ... local before = vim.loop.hrtime() for i=1,n,1 do - cquery = vim.treesitter.parse_query("c", ...) + cquery = vim.treesitter.query.parse("c", ...) end local after = vim.loop.hrtime() return after - before @@ -203,7 +203,7 @@ void ui_refresh(void) insert(test_text) local res = exec_lua([[ - cquery = vim.treesitter.parse_query("c", ...) + cquery = vim.treesitter.query.parse("c", ...) parser = vim.treesitter.get_parser(0, "c") tree = parser:parse()[1] res = {} @@ -232,7 +232,7 @@ void ui_refresh(void) insert(test_text) local res = exec_lua([[ - cquery = vim.treesitter.parse_query("c", ...) + cquery = vim.treesitter.query.parse("c", ...) parser = vim.treesitter.get_parser(0, "c") tree = parser:parse()[1] res = {} @@ -326,7 +326,7 @@ end]] insert('char* astring = "\\n"; (1 + 1) * 2 != 2;') local res = exec_lua([[ - cquery = vim.treesitter.parse_query("c", '([_] @plus (#vim-match? @plus "^\\\\+$"))'.. + cquery = vim.treesitter.query.parse("c", '([_] @plus (#vim-match? @plus "^\\\\+$"))'.. '([_] @times (#vim-match? @times "^\\\\*$"))'.. '([_] @paren (#vim-match? @paren "^\\\\($"))'.. '([_] @escape (#vim-match? @escape "^\\\\\\\\n$"))'.. @@ -376,7 +376,7 @@ end]] ]]) exec_lua([[ function get_query_result(query_text) - cquery = vim.treesitter.parse_query("c", query_text) + cquery = vim.treesitter.query.parse("c", query_text) parser = vim.treesitter.get_parser(0, "c") tree = parser:parse()[1] res = {} @@ -416,7 +416,7 @@ end]] insert('char* astring = "Hello World!";') local res = exec_lua([[ - cquery = vim.treesitter.parse_query("c", '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))') + cquery = vim.treesitter.query.parse("c", '([_] @quote (#vim-match? @quote "^\\"$")) ([_] @quote (#lua-match? @quote "^\\"$"))') parser = vim.treesitter.get_parser(0, "c") tree = parser:parse()[1] res = {} @@ -449,7 +449,7 @@ end]] local custom_query = "((identifier) @main (#is-main? @main))" local res = exec_lua([[ - local query = require"vim.treesitter.query" + local query = vim.treesitter.query local function is_main(match, pattern, bufnr, predicate) local node = match[ predicate[2] ] @@ -461,7 +461,7 @@ end]] query.add_predicate("is-main?", is_main) - local query = query.parse_query("c", ...) + local query = query.parse("c", ...) local nodes = {} for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do @@ -474,7 +474,7 @@ end]] eq({{0, 4, 0, 8}}, res) local res_list = exec_lua[[ - local query = require'vim.treesitter.query' + local query = vim.treesitter.query local list = query.list_predicates() @@ -533,7 +533,7 @@ end]] local res = exec_lua [[ parser = vim.treesitter.get_parser(0, "c") - query = vim.treesitter.parse_query("c", "(declaration) @decl") + query = vim.treesitter.query.parse("c", "(declaration) @decl") local nodes = {} for _, node in query:iter_captures(parser:parse()[1]:root(), 0) do @@ -581,7 +581,7 @@ end]] local parser = vim.treesitter.get_string_parser(str, "c") local nodes = {} - local query = vim.treesitter.parse_query("c", '((identifier) @id (eq? @id "foo"))') + local query = vim.treesitter.query.parse("c", '((identifier) @id (eq? @id "foo"))') for _, node in query:iter_captures(parser:parse()[1]:root(), str) do table.insert(nodes, { node:range() }) @@ -603,7 +603,7 @@ end]] local parser = vim.treesitter.get_string_parser(str, "c") local nodes = {} - local query = vim.treesitter.parse_query("c", '((identifier) @foo)') + local query = vim.treesitter.query.parse("c", '((identifier) @foo)') local first_child = parser:parse()[1]:root():child(1) for _, node in query:iter_captures(first_child, str) do @@ -703,7 +703,7 @@ int x = INT_MAX; describe("when providing parsing information through a directive", function() it("should inject a language", function() exec_lua([=[ - vim.treesitter.add_directive("inject-clang!", function(match, _, _, pred, metadata) + vim.treesitter.query.add_directive("inject-clang!", function(match, _, _, pred, metadata) metadata.language = "c" metadata.combined = true metadata.content = pred[2] @@ -741,7 +741,7 @@ int x = INT_MAX; it("should not inject bad languages", function() exec_lua([=[ - vim.treesitter.add_directive("inject-bad!", function(match, _, _, pred, metadata) + vim.treesitter.query.add_directive("inject-bad!", function(match, _, _, pred, metadata) metadata.language = "{" metadata.combined = true metadata.content = pred[2] @@ -774,7 +774,7 @@ int x = INT_MAX; end) it("should list all directives", function() local res_list = exec_lua[[ - local query = require'vim.treesitter.query' + local query = vim.treesitter.query local list = query.list_directives() @@ -820,7 +820,7 @@ int x = INT_MAX; local result = exec_lua([[ local result - query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! "key" "value"))') + query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! "key" "value"))') parser = vim.treesitter.get_parser(0, "c") for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do @@ -840,10 +840,10 @@ int x = INT_MAX; ]]) local result = exec_lua([[ - local query = require("vim.treesitter.query") + local query = vim.treesitter.query local value - query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value"))') + query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! @number "key" "value"))') parser = vim.treesitter.get_parser(0, "c") for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do @@ -862,10 +862,10 @@ int x = INT_MAX; ]]) local result = exec_lua([[ - local query = require("vim.treesitter.query") + local query = vim.treesitter.query local result - query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))') + query = vim.treesitter.query.parse("c", '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))') parser = vim.treesitter.get_parser(0, "c") for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do -- cgit From 257d894d75bc583bb16f4dbe441907eb273d20ad Mon Sep 17 00:00:00 2001 From: Roberto Pommella Alegro Date: Sat, 25 Mar 2023 13:46:07 -0300 Subject: feat(lsp): render markdown in docs hover #22766 Problem: LSP docs hover (textDocument/hover) doesn't handle HTML escape seqs in markdown. Solution: Convert common HTML escape seqs to a nicer form, to display in the float. closees #22757 Signed-off-by: Kasama --- test/functional/plugin/lsp/utils_spec.lua | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 test/functional/plugin/lsp/utils_spec.lua (limited to 'test/functional') diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua new file mode 100644 index 0000000000..3e53b6d574 --- /dev/null +++ b/test/functional/plugin/lsp/utils_spec.lua @@ -0,0 +1,75 @@ +local helpers = require('test.functional.helpers')(after_each) + +local eq = helpers.eq +local exec_lua = helpers.exec_lua + +describe('vim.lsp.util', function() + before_each(helpers.clear) + + describe('stylize_markdown', function() + local stylize_markdown = function(content, opts) + return exec_lua([[ + local bufnr = vim.uri_to_bufnr("file:///fake/uri") + vim.fn.bufload(bufnr) + + local args = { ... } + local content = args[1] + local opts = args[2] + local stripped_content = vim.lsp.util.stylize_markdown(bufnr, content, opts) + + return stripped_content + ]], content, opts) + end + + it('code fences', function() + local lines = { + "```lua", + "local hello = 'world'", + "```", + } + local expected = { + "local hello = 'world'", + } + local opts = {} + eq(expected, stylize_markdown(lines, opts)) + end) + + it('adds separator after code block', function() + local lines = { + "```lua", + "local hello = 'world'", + "```", + "", + "something", + } + local expected = { + "local hello = 'world'", + "─────────────────────", + "something", + } + local opts = { separator = true } + eq(expected, stylize_markdown(lines, opts)) + end) + + it('replaces supported HTML entities', function() + local lines = { + "1 < 2", + "3 > 2", + ""quoted"", + "'apos'", + "   ", + "&", + } + local expected = { + "1 < 2", + "3 > 2", + '"quoted"', + "'apos'", + " ", + "&", + } + local opts = {} + eq(expected, stylize_markdown(lines, opts)) + end) + end) +end) -- cgit From fe9cbcb3a5c82932ecfb8f49d07e98a1fc2b31e5 Mon Sep 17 00:00:00 2001 From: Evgeni Chasnovski Date: Sat, 25 Mar 2023 18:58:48 +0200 Subject: feat(api): nvim_exec2(), deprecate nvim_exec() #19032 Problem: The signature of nvim_exec() is not extensible per ":help api-contract". Solution: Introduce nvim_exec2() and deprecate nvim_exec(). --- test/functional/api/extmark_spec.lua | 6 +- test/functional/api/keymap_spec.lua | 12 +- test/functional/api/vim_spec.lua | 149 ++++++++++++----------- test/functional/autocmd/autocmd_oldtest_spec.lua | 2 +- test/functional/core/exit_spec.lua | 6 +- test/functional/core/remote_spec.lua | 4 +- test/functional/core/startup_spec.lua | 7 +- test/functional/editor/mark_spec.lua | 24 ++-- test/functional/ex_cmds/script_spec.lua | 4 +- test/functional/ex_cmds/source_spec.lua | 20 +-- test/functional/ex_cmds/verbose_spec.lua | 4 +- test/functional/helpers.lua | 6 +- test/functional/legacy/assert_spec.lua | 8 +- test/functional/options/keymap_spec.lua | 2 +- test/functional/ui/cmdline_highlight_spec.lua | 8 +- test/functional/ui/messages_spec.lua | 4 +- 16 files changed, 141 insertions(+), 125 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 30e75b8061..e9a175625b 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1413,12 +1413,12 @@ describe('API/extmarks', function() end) it('does not crash with append/delete/undo sequence', function() - meths.exec([[ + meths.exec2([[ let ns = nvim_create_namespace('myplugin') call nvim_buf_set_extmark(0, ns, 0, 0, {}) call append(0, '') %delete - undo]],false) + undo]], { output = false }) assert_alive() end) @@ -1450,7 +1450,7 @@ describe('API/extmarks', function() feed('u') -- handles pasting - meths.exec([[let @a='asdfasdf']], false) + meths.exec2([[let @a='asdfasdf']], { output = false }) feed([["ap]]) eq({ {1, 0, 0}, {2, 0, 8} }, meths.buf_get_extmarks(0, ns, 0, -1, {})) diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index 5be4425162..78281be195 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -681,13 +681,13 @@ describe('nvim_set_keymap, nvim_del_keymap', function() end) it('can set mappings whose RHS change dynamically', function() - meths.exec([[ + meths.exec2([[ function! FlipFlop() abort if !exists('g:flip') | let g:flip = 0 | endif let g:flip = !g:flip return g:flip endfunction - ]], true) + ]], { output = false }) eq(1, meths.call_function('FlipFlop', {})) eq(0, meths.call_function('FlipFlop', {})) eq(1, meths.call_function('FlipFlop', {})) @@ -827,8 +827,12 @@ describe('nvim_set_keymap, nvim_del_keymap', function() exec_lua [[ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end }) ]] - assert.truthy(string.match(exec_lua[[return vim.api.nvim_exec(':nmap asdf', true)]], - "^\nn asdf ")) + assert.truthy( + string.match( + exec_lua[[return vim.api.nvim_exec2(':nmap asdf', { output = true }).output]], + "^\nn asdf " + ) + ) end) it ('mapcheck() returns lua mapping correctly', function() diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index ff1bfef591..162735dbd7 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -89,132 +89,145 @@ describe('API', function() eq({mode='i', blocking=false}, nvim("get_mode")) end) - describe('nvim_exec', function() + describe('nvim_exec2', function() + it('always returns table', function() + -- In built version this results into `vim.empty_dict()` + eq({}, nvim('exec2', 'echo "Hello"', {})) + eq({}, nvim('exec2', 'echo "Hello"', { output = false })) + eq({ output = 'Hello' }, nvim('exec2', 'echo "Hello"', { output = true })) + end) + + it('default options', function() + -- Should be equivalent to { output = false } + nvim('exec2', "let x0 = 'a'", {}) + eq('a', nvim('get_var', 'x0')) + end) + it('one-line input', function() - nvim('exec', "let x1 = 'a'", false) + nvim('exec2', "let x1 = 'a'", { output = false }) eq('a', nvim('get_var', 'x1')) end) it(':verbose set {option}?', function() - nvim('exec', 'set nowrap', false) - eq('nowrap\n\tLast set from anonymous :source', - nvim('exec', 'verbose set wrap?', true)) + nvim('exec2', 'set nowrap', { output = false }) + eq({ output = 'nowrap\n\tLast set from anonymous :source' }, + nvim('exec2', 'verbose set wrap?', { output = true })) -- Using script var to force creation of a script item - nvim('exec', [[ + nvim('exec2', [[ let s:a = 1 set nowrap - ]], false) - eq('nowrap\n\tLast set from anonymous :source (script id 1)', - nvim('exec', 'verbose set wrap?', true)) + ]], { output = false }) + eq({ output = 'nowrap\n\tLast set from anonymous :source (script id 1)' }, + nvim('exec2', 'verbose set wrap?', { output = true })) end) it('multiline input', function() -- Heredoc + empty lines. - nvim('exec', "let x2 = 'a'\n", false) + nvim('exec2', "let x2 = 'a'\n", { output = false }) eq('a', nvim('get_var', 'x2')) - nvim('exec','lua <avast_ye_hades('ahoy!') - ]], true)) + ]], { output = true })) - eq('ahoy! script-scoped varrrrr', nvim('exec', [[ + eq({ output = "{'output': 'ahoy! script-scoped varrrrr'}" }, nvim('exec2', [[ let s:pirate = 'script-scoped varrrrr' function! Avast_ye_hades(s) abort return a:s .. ' ' .. s:pirate endfunction - echo nvim_exec('echo Avast_ye_hades(''ahoy!'')', 1) - ]], true)) + echo nvim_exec2('echo Avast_ye_hades(''ahoy!'')', {'output': v:true}) + ]], { output = true })) matches('Vim%(echo%):E121: Undefined variable: s:pirate$', - pcall_err(request, 'nvim_exec', [[ + pcall_err(request, 'nvim_exec2', [[ let s:pirate = 'script-scoped varrrrr' - call nvim_exec('echo s:pirate', 1) - ]], false)) + call nvim_exec2('echo s:pirate', {'output': v:true}) + ]], { output = false })) -- Script items are created only on script var access - eq('1\n0', nvim('exec', [[ + eq({ output = '1\n0' }, nvim('exec2', [[ echo expand("")->empty() let s:a = 123 echo expand("")->empty() - ]], true)) + ]], { output = true })) - eq('1\n0', nvim('exec', [[ + eq({ output = '1\n0' }, nvim('exec2', [[ echo expand("")->empty() function s:a() abort endfunction echo expand("")->empty() - ]], true)) + ]], { output = true })) end) it('non-ASCII input', function() - nvim('exec', [=[ + nvim('exec2', [=[ new exe "normal! i ax \n Ax " :%s/ax/--a1234--/g | :%s/Ax/--A1234--/g - ]=], false) + ]=], { output = false }) nvim('command', '1') eq(' --a1234-- ', nvim('get_current_line')) nvim('command', '2') eq(' --A1234-- ', nvim('get_current_line')) - nvim('exec', [[ + nvim('exec2', [[ new call setline(1,['xxx']) call feedkeys('r') call feedkeys('ñ', 'xt') - ]], false) + ]], { output = false }) eq('ñxx', nvim('get_current_line')) end) it('execution error', function() - eq('nvim_exec(): Vim:E492: Not an editor command: bogus_command', - pcall_err(request, 'nvim_exec', 'bogus_command', false)) + eq('nvim_exec2(): Vim:E492: Not an editor command: bogus_command', + pcall_err(request, 'nvim_exec2', 'bogus_command', {})) eq('', nvim('eval', 'v:errmsg')) -- v:errmsg was not updated. eq('', eval('v:exception')) - eq('nvim_exec(): Vim(buffer):E86: Buffer 23487 does not exist', - pcall_err(request, 'nvim_exec', 'buffer 23487', false)) + eq('nvim_exec2(): Vim(buffer):E86: Buffer 23487 does not exist', + pcall_err(request, 'nvim_exec2', 'buffer 23487', {})) eq('', eval('v:errmsg')) -- v:errmsg was not updated. eq('', eval('v:exception')) end) @@ -222,17 +235,17 @@ describe('API', function() it('recursion', function() local fname = tmpname() write_file(fname, 'let x1 = "set from :source file"\n') - -- nvim_exec + -- nvim_exec2 -- :source - -- nvim_exec - request('nvim_exec', [[ + -- nvim_exec2 + request('nvim_exec2', [[ let x2 = substitute('foo','o','X','g') let x4 = 'should be overwritten' - call nvim_exec("source ]]..fname..[[\nlet x3 = substitute('foo','foo','set by recursive nvim_exec','g')\nlet x5='overwritten'\nlet x4=x5\n", v:false) - ]], false) + call nvim_exec2("source ]]..fname..[[\nlet x3 = substitute('foo','foo','set by recursive nvim_exec2','g')\nlet x5='overwritten'\nlet x4=x5\n", {'output': v:false}) + ]], { output = false }) eq('set from :source file', request('nvim_get_var', 'x1')) eq('fXX', request('nvim_get_var', 'x2')) - eq('set by recursive nvim_exec', request('nvim_get_var', 'x3')) + eq('set by recursive nvim_exec2', request('nvim_get_var', 'x3')) eq('overwritten', request('nvim_get_var', 'x4')) eq('overwritten', request('nvim_get_var', 'x5')) os.remove(fname) @@ -242,35 +255,35 @@ describe('API', function() local fname = tmpname() write_file(fname, 'echo "hello"\n') local sourcing_fname = tmpname() - write_file(sourcing_fname, 'call nvim_exec("source '..fname..'", v:false)\n') - meths.exec('set verbose=2', false) + write_file(sourcing_fname, 'call nvim_exec2("source '..fname..'", {"output": v:false})\n') + meths.exec2('set verbose=2', { output = false }) local traceback_output = 'line 0: sourcing "'..sourcing_fname..'"\n'.. 'line 0: sourcing "'..fname..'"\n'.. 'hello\n'.. 'finished sourcing '..fname..'\n'.. - 'continuing in nvim_exec() called at '..sourcing_fname..':1\n'.. + 'continuing in nvim_exec2() called at '..sourcing_fname..':1\n'.. 'finished sourcing '..sourcing_fname..'\n'.. - 'continuing in nvim_exec() called at nvim_exec():0' - eq(traceback_output, - meths.exec('call nvim_exec("source '..sourcing_fname..'", v:false)', true)) + 'continuing in nvim_exec2() called at nvim_exec2():0' + eq({ output = traceback_output }, + meths.exec2('call nvim_exec2("source '..sourcing_fname..'", {"output": v:false})', { output = true })) os.remove(fname) os.remove(sourcing_fname) end) it('returns output', function() - eq('this is spinal tap', - nvim('exec', 'lua <]]) @@ -575,7 +588,7 @@ describe('API', function() it('sets previous directory', function() meths.set_current_dir("Xtestdir") - meths.exec('cd -', false) + meths.exec2('cd -', { output = false }) eq(funcs.getcwd(), start_dir) end) end) @@ -2674,7 +2687,7 @@ describe('API', function() eq(' 1 %a "[No Name]" line 1\n'.. ' 3 h "[Scratch]" line 0\n'.. ' 4 h "[Scratch]" line 0', - meths.exec('ls', true)) + meths.exec2('ls', { output = true }).output) -- current buffer didn't change eq({id=1}, meths.get_current_buf()) @@ -2788,7 +2801,7 @@ describe('API', function() end) it('should not crash when echoed', function() - meths.exec("echo nvim_get_all_options_info()", true) + meths.exec2("echo nvim_get_all_options_info()", { output = true }) end) end) @@ -2941,13 +2954,13 @@ describe('API', function() it('can save message history', function() nvim('command', 'set cmdheight=2') -- suppress Press ENTER nvim("echo", {{"msg\nmsg"}, {"msg"}}, true, {}) - eq("msg\nmsgmsg", meths.exec('messages', true)) + eq("msg\nmsgmsg", meths.exec2('messages', { output = true }).output) end) it('can disable saving message history', function() nvim('command', 'set cmdheight=2') -- suppress Press ENTER nvim_async("echo", {{"msg\nmsg"}, {"msg"}}, false, {}) - eq("", meths.exec("messages", true)) + eq("", meths.exec2("messages", { output = true }).output) end) end) @@ -3936,7 +3949,7 @@ describe('API', function() it('sets correct script context', function() meths.cmd({ cmd = "set", args = { "cursorline" } }, {}) - local str = meths.exec([[verbose set cursorline?]], true) + local str = meths.exec2([[verbose set cursorline?]], { output = true }).output neq(nil, str:find("cursorline\n\tLast set from API client %(channel id %d+%)")) end) @@ -3986,7 +3999,7 @@ describe('API', function() line6 ]] meths.cmd({ cmd = "del", range = { 2, 4 }, reg = 'a' }, {}) - meths.exec("1put a", false) + meths.exec2("1put a", { output = false }) expect [[ line1 line2 @@ -4051,11 +4064,11 @@ describe('API', function() { output = true })) end) it('splits arguments correctly', function() - meths.exec([[ + meths.exec2([[ function! FooFunc(...) echo a:000 endfunction - ]], false) + ]], { output = false }) meths.create_user_command("Foo", "call FooFunc()", { nargs = '+' }) eq([=[['a quick', 'brown fox', 'jumps over the', 'lazy dog']]=], meths.cmd({ cmd = "Foo", args = { "a quick", "brown fox", "jumps over the", "lazy dog"}}, diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua index ad3687d7b0..7d475e5015 100644 --- a/test/functional/autocmd/autocmd_oldtest_spec.lua +++ b/test/functional/autocmd/autocmd_oldtest_spec.lua @@ -6,7 +6,7 @@ local meths = helpers.meths local funcs = helpers.funcs local exec = function(str) - meths.exec(str, false) + meths.exec2(str, { output = false }) end describe('oldtests', function() diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua index dc4b45b4d9..d474b77806 100644 --- a/test/functional/core/exit_spec.lua +++ b/test/functional/core/exit_spec.lua @@ -93,14 +93,14 @@ describe(':cquit', function() end) it('exits with redir msg for multiple exit codes after :cquit 1 2', function() - test_cq('cquit 1 2', nil, 'nvim_exec(): Vim(cquit):E488: Trailing characters: 2: cquit 1 2') + test_cq('cquit 1 2', nil, 'nvim_exec2(): Vim(cquit):E488: Trailing characters: 2: cquit 1 2') end) it('exits with redir msg for non-number exit code after :cquit X', function() - test_cq('cquit X', nil, 'nvim_exec(): Vim(cquit):E488: Trailing characters: X: cquit X') + test_cq('cquit X', nil, 'nvim_exec2(): Vim(cquit):E488: Trailing characters: X: cquit X') end) it('exits with redir msg for negative exit code after :cquit -1', function() - test_cq('cquit -1', nil, 'nvim_exec(): Vim(cquit):E488: Trailing characters: -1: cquit -1') + test_cq('cquit -1', nil, 'nvim_exec2(): Vim(cquit):E488: Trailing characters: -1: cquit -1') end) end) diff --git a/test/functional/core/remote_spec.lua b/test/functional/core/remote_spec.lua index 846d79abf3..b2a1679023 100644 --- a/test/functional/core/remote_spec.lua +++ b/test/functional/core/remote_spec.lua @@ -101,7 +101,7 @@ describe('Remote', function() expect(contents) eq(1, #funcs.getbufinfo()) -- Since we didn't pass silent, we should get a complaint - neq(nil, string.find(meths.exec('messages', true), 'E247')) + neq(nil, string.find(meths.exec2('messages', { output = true }).output, 'E247')) end) it('creates server if not found with tabs', function() @@ -110,7 +110,7 @@ describe('Remote', function() eq(2, #funcs.gettabinfo()) eq(2, #funcs.getbufinfo()) -- We passed silent, so no message should be issued about the server not being found - eq(nil, string.find(meths.exec('messages', true), 'E247')) + eq(nil, string.find(meths.exec2('messages', { output = true }).output, 'E247')) end) pending('exits with error on', function() diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index e9b47a0251..4ae8b1c95e 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -58,7 +58,7 @@ describe('startup', function() ^ | | Entering Debug mode. Type "cont" to continue. | - nvim_exec() | + nvim_exec2() | cmd: aunmenu * | > | | @@ -691,7 +691,6 @@ describe('sysinit', function() eq('loaded 1 xdg 0 vim 1', eval('printf("loaded %d xdg %d vim %d", g:loaded, get(g:, "xdg", 0), get(g:, "vim", 0))')) end) - end) describe('user config init', function() @@ -824,7 +823,7 @@ describe('user config init', function() clear{ args_rm={'-u'}, env=xenv } feed('') -- Dismiss "Conflicting config …" message. eq(1, eval('g:lua_rc')) - matches('^E5422: Conflicting configs', meths.exec('messages', true)) + matches('^E5422: Conflicting configs', meths.exec2('messages', { output = true }).output) end) end) end) @@ -873,7 +872,7 @@ describe('runtime:', function() eq(2, eval('g:lua_plugin')) -- Check if plugin_file_path is listed in :scriptname - local scripts = meths.exec(':scriptnames', true) + local scripts = meths.exec2(':scriptnames', { output = true }).output assert(scripts:find(plugin_file_path)) -- Check if plugin_file_path is listed in startup profile diff --git a/test/functional/editor/mark_spec.lua b/test/functional/editor/mark_spec.lua index 0670176719..365f8527a0 100644 --- a/test/functional/editor/mark_spec.lua +++ b/test/functional/editor/mark_spec.lua @@ -40,59 +40,59 @@ describe('named marks', function() it("errors when set out of range with :mark", function() command("edit " .. file1) local err = pcall_err(helpers.exec_capture, "1000mark x") - eq("nvim_exec(): Vim(mark):E16: Invalid range: 1000mark x", err) + eq("nvim_exec2(): Vim(mark):E16: Invalid range: 1000mark x", err) end) it("errors when set out of range with :k", function() command("edit " .. file1) local err = pcall_err(helpers.exec_capture, "1000kx") - eq("nvim_exec(): Vim(k):E16: Invalid range: 1000kx", err) + eq("nvim_exec2(): Vim(k):E16: Invalid range: 1000kx", err) end) it("errors on unknown mark name with :mark", function() command("edit " .. file1) local err = pcall_err(helpers.exec_capture, "mark #") - eq("nvim_exec(): Vim(mark):E191: Argument must be a letter or forward/backward quote", err) + eq("nvim_exec2(): Vim(mark):E191: Argument must be a letter or forward/backward quote", err) end) it("errors on unknown mark name with '", function() command("edit " .. file1) local err = pcall_err(helpers.exec_capture, "normal! '#") - eq("nvim_exec(): Vim(normal):E78: Unknown mark", err) + eq("nvim_exec2(): Vim(normal):E78: Unknown mark", err) end) it("errors on unknown mark name with `", function() command("edit " .. file1) local err = pcall_err(helpers.exec_capture, "normal! `#") - eq("nvim_exec(): Vim(normal):E78: Unknown mark", err) + eq("nvim_exec2(): Vim(normal):E78: Unknown mark", err) end) it("errors when moving to a mark that is not set with '", function() command("edit " .. file1) local err = pcall_err(helpers.exec_capture, "normal! 'z") - eq("nvim_exec(): Vim(normal):E20: Mark not set", err) + eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) err = pcall_err(helpers.exec_capture, "normal! '.") - eq("nvim_exec(): Vim(normal):E20: Mark not set", err) + eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) end) it("errors when moving to a mark that is not set with `", function() command("edit " .. file1) local err = pcall_err(helpers.exec_capture, "normal! `z") - eq("nvim_exec(): Vim(normal):E20: Mark not set", err) + eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) err = pcall_err(helpers.exec_capture, "normal! `>") - eq("nvim_exec(): Vim(normal):E20: Mark not set", err) + eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) end) it("errors when moving to a global mark that is not set with '", function() command("edit " .. file1) local err = pcall_err(helpers.exec_capture, "normal! 'Z") - eq("nvim_exec(): Vim(normal):E20: Mark not set", err) + eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) end) it("errors when moving to a global mark that is not set with `", function() command("edit " .. file1) local err = pcall_err(helpers.exec_capture, "normal! `Z") - eq("nvim_exec(): Vim(normal):E20: Mark not set", err) + eq("nvim_exec2(): Vim(normal):E20: Mark not set", err) end) it("can move to them using '", function() @@ -153,7 +153,7 @@ describe('named marks', function() command("next") command("bw! " .. file1 ) local err = pcall_err(helpers.exec_capture, "normal! 'A") - eq("nvim_exec(): Vim(normal):E92: Buffer 1 not found", err) + eq("nvim_exec2(): Vim(normal):E92: Buffer 1 not found", err) os.remove(file1) end) diff --git a/test/functional/ex_cmds/script_spec.lua b/test/functional/ex_cmds/script_spec.lua index bf69ada820..d13268c97c 100644 --- a/test/functional/ex_cmds/script_spec.lua +++ b/test/functional/ex_cmds/script_spec.lua @@ -34,7 +34,7 @@ describe('script_get-based command', function() %s %s endif ]])):format(cmd, garbage))) - eq('', meths.exec('messages', true)) + eq('', meths.exec2('messages', { output = true }).output) if check_neq then neq(0, exc_exec(dedent([[ %s %s @@ -49,7 +49,7 @@ describe('script_get-based command', function() EOF endif ]])):format(cmd, garbage))) - eq('', meths.exec('messages', true)) + eq('', meths.exec2('messages', { output = true }).output) if check_neq then eq(true, pcall(source, (dedent([[ let g:exc = 0 diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua index 64c3464be7..e12ead240d 100644 --- a/test/functional/ex_cmds/source_spec.lua +++ b/test/functional/ex_cmds/source_spec.lua @@ -96,12 +96,12 @@ describe(':source', function() let d = s:s]]) command('source') - eq('2', meths.exec('echo a', true)) - eq("{'k': 'v'}", meths.exec('echo b', true)) + eq('2', meths.exec2('echo a', { output = true }).output) + eq("{'k': 'v'}", meths.exec2('echo b', { output = true }).output) -- Script items are created only on script var access - eq("1", meths.exec('echo c', true)) - eq("0zBEEFCAFE", meths.exec('echo d', true)) + eq("1", meths.exec2('echo c', { output = true }).output) + eq("0zBEEFCAFE", meths.exec2('echo d', { output = true }).output) exec('set cpoptions+=C') eq('Vim(let):E723: Missing end of Dictionary \'}\': ', exc_exec('source')) @@ -124,14 +124,14 @@ describe(':source', function() -- Source the 2nd line only feed('ggjV') feed_command(':source') - eq('3', meths.exec('echo a', true)) + eq('3', meths.exec2('echo a', { output = true }).output) -- Source from 2nd line to end of file feed('ggjVG') feed_command(':source') - eq('4', meths.exec('echo a', true)) - eq("{'K': 'V'}", meths.exec('echo b', true)) - eq("1_C()", meths.exec('echo D()', true)) + eq('4', meths.exec2('echo a', { output = true }).output) + eq("{'K': 'V'}", meths.exec2('echo b', { output = true }).output) + eq("1_C()", meths.exec2('echo D()', { output = true }).output) -- Source last line only feed_command(':$source') @@ -147,7 +147,7 @@ describe(':source', function() let a = 123 ]] command('source') - eq('123', meths.exec('echo a', true)) + eq('123', meths.exec2('echo a', { output = true }).output) end) it('multiline heredoc command', function() @@ -157,7 +157,7 @@ describe(':source', function() EOF]]) command('source') - eq('4', meths.exec('echo luaeval("y")', true)) + eq('4', meths.exec2('echo luaeval("y")', { output = true }).output) end) it('can source lua files', function() diff --git a/test/functional/ex_cmds/verbose_spec.lua b/test/functional/ex_cmds/verbose_spec.lua index e55372e993..2482fd912f 100644 --- a/test/functional/ex_cmds/verbose_spec.lua +++ b/test/functional/ex_cmds/verbose_spec.lua @@ -24,11 +24,11 @@ vim.opt.number = true vim.api.nvim_set_keymap('n', 'key1', ':echo "test"', {noremap = true}) vim.keymap.set('n', 'key2', ':echo "test"') -vim.api.nvim_exec("augroup test_group\ +vim.api.nvim_exec2("augroup test_group\ autocmd!\ autocmd FileType c setl cindent\ augroup END\ - ", false) + ", { output = false }) vim.api.nvim_command("command Bdelete :bd") vim.api.nvim_create_user_command("TestCommand", ":echo 'Hello'", {}) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index b485352c94..de5fe96934 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -533,7 +533,7 @@ function module.feed_command(...) end end --- @deprecated use nvim_exec() +-- @deprecated use nvim_exec2() function module.source(code) module.exec(dedent(code)) end @@ -826,11 +826,11 @@ function module.skip_fragile(pending_fn, cond) end function module.exec(code) - return module.meths.exec(code, false) + module.meths.exec2(code, { output = false }) end function module.exec_capture(code) - return module.meths.exec(code, true) + return module.meths.exec2(code, { output = true }).output end function module.exec_lua(code, ...) diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua index 4829a0bbe1..d49d7d665a 100644 --- a/test/functional/legacy/assert_spec.lua +++ b/test/functional/legacy/assert_spec.lua @@ -145,10 +145,10 @@ describe('assert function:', function() call assert_true('', 'file two') ]]) expected_errors({ - "nvim_exec(): equal assertion failed: Expected 1 but got 100", - "nvim_exec(): true assertion failed: Expected False but got 'true'", - "nvim_exec(): false assertion failed: Expected True but got 'false'", - "nvim_exec(): file two: Expected True but got ''", + "nvim_exec2(): equal assertion failed: Expected 1 but got 100", + "nvim_exec2(): true assertion failed: Expected False but got 'true'", + "nvim_exec2(): false assertion failed: Expected True but got 'false'", + "nvim_exec2(): file two: Expected True but got ''", }) end) end) diff --git a/test/functional/options/keymap_spec.lua b/test/functional/options/keymap_spec.lua index 4fdc6ef4be..7ff86438b2 100644 --- a/test/functional/options/keymap_spec.lua +++ b/test/functional/options/keymap_spec.lua @@ -30,7 +30,7 @@ describe("'keymap' / :lmap", function() command('lmapclear ') command('set keymap=dvorak') command('set nomore') - local bindings = funcs.nvim_exec('lmap', true) + local bindings = funcs.nvim_exec2('lmap', { output = true }).output eq(dedent([[ l " @_ diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua index eb5de693bd..d6c8408f04 100644 --- a/test/functional/ui/cmdline_highlight_spec.lua +++ b/test/functional/ui/cmdline_highlight_spec.lua @@ -362,7 +362,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.exec('messages', true)) + eq('', meths.exec2('messages', { output = true }).output) end) it('silences :echon', function() set_color_cb('Echoning') @@ -377,7 +377,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.exec('messages', true)) + eq('', meths.exec2('messages', { output = true }).output) end) it('silences :echomsg', function() set_color_cb('Echomsging') @@ -392,7 +392,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.exec('messages', true)) + eq('', meths.exec2('messages', { output = true }).output) end) it('does the right thing when throwing', function() set_color_cb('Throwing') @@ -858,7 +858,7 @@ describe('Ex commands coloring', function() ]]) feed('') eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: empty buffer', - meths.exec('messages', true)) + meths.exec2('messages', { output = true }).output) end) it('errors out when failing to get callback', function() meths.set_var('Nvim_color_cmdline', 42) diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index a92b55ae5d..81602ef92e 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -986,7 +986,7 @@ describe('ui/builtin messages', function() -- screen size doesn't affect internal output #10285 eq('ErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red', - meths.exec("hi ErrorMsg", true)) + meths.exec2("hi ErrorMsg", { output = true }).output) end) it(':syntax list langGroup output', function() @@ -1025,7 +1025,7 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim match /\ Date: Sun, 26 Mar 2023 09:24:04 +0800 Subject: vim-patch:9.0.1428: cursor in wrong position when leaving insert mode (#22786) Problem: Cursor in wrong position when leaving insert mode. Solution: Update the w_valid flags. Position the cursor also when not redrawing. (closes vim/vim#12137) https://github.com/vim/vim/commit/c174c2e58c9e24a75b189e01143e6d057b84e96e Co-authored-by: Bram Moolenaar --- test/functional/editor/mode_insert_spec.lua | 30 +++++++++----- test/functional/legacy/edit_spec.lua | 64 +++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 11 deletions(-) (limited to 'test/functional') diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua index b00661ac3a..6f16b4e685 100644 --- a/test/functional/editor/mode_insert_spec.lua +++ b/test/functional/editor/mode_insert_spec.lua @@ -53,14 +53,13 @@ describe('insert-mode', function() it('double quote is removed after hit-enter prompt #22609', function() local screen = Screen.new(60, 6) screen:set_default_attr_ids({ - [0] = {bold = true, foreground = Screen.colors.Blue}, - [1] = {foreground = Screen.colors.Blue}, + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {foreground = Screen.colors.Blue}, -- SpecialKey [2] = {foreground = Screen.colors.SlateBlue}, - [3] = {bold = true}, - [4] = {reverse = true, bold = true}, - [5] = {background = Screen.colors.Red, foreground = Screen.colors.Red}, - [6] = {background = Screen.colors.Red, foreground = Screen.colors.White}, - [7] = {foreground = Screen.colors.SeaGreen, bold = true}, + [3] = {bold = true}, -- ModeMsg + [4] = {reverse = true, bold = true}, -- MsgSeparator + [5] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg + [6] = {foreground = Screen.colors.SeaGreen, bold = true}, -- MoreMsg }) screen:attach() feed('i') @@ -72,14 +71,23 @@ describe('insert-mode', function() {0:~ }| {3:-- INSERT --} | ]]) - feed('={}') + feed('={}') + screen:expect([[ + {1:"} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ={2:{}}^ | + ]]) + feed('') screen:expect([[ {1:"} | {0:~ }| {4: }| - ={5:{}{2:}} | - {6:E731: using Dictionary as a String} | - {7:Press ENTER or type command to continue}^ | + ={2:{}} | + {5:E731: using Dictionary as a String} | + {6:Press ENTER or type command to continue}^ | ]]) feed('') screen:expect([[ diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua index 362d33a0fd..a0d8ca63a2 100644 --- a/test/functional/legacy/edit_spec.lua +++ b/test/functional/legacy/edit_spec.lua @@ -55,4 +55,68 @@ describe('edit', function() =^ | ]]) end) + + -- oldtest: Test_edit_ctrl_r_failed() + it('positioning cursor after CTRL-R expression failed', function() + local screen = Screen.new(60, 6) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText + [1] = {foreground = Screen.colors.Blue}, -- SpecialKey + [2] = {foreground = Screen.colors.SlateBlue}, + [3] = {bold = true}, -- ModeMsg + [4] = {reverse = true, bold = true}, -- MsgSeparator + [5] = {background = Screen.colors.Red, foreground = Screen.colors.White}, -- ErrorMsg + [6] = {foreground = Screen.colors.SeaGreen, bold = true}, -- MoreMsg + }) + screen:attach() + + feed('i') + screen:expect([[ + {1:^"} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + feed('={}') + screen:expect([[ + {1:"} | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ={2:{}}^ | + ]]) + -- trying to insert a dictionary produces an error + feed('') + screen:expect([[ + {1:"} | + {0:~ }| + {4: }| + ={2:{}} | + {5:E731: using Dictionary as a String} | + {6:Press ENTER or type command to continue}^ | + ]]) + + feed(':') + screen:expect([[ + :^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {3:-- INSERT --} | + ]]) + -- ending Insert mode should put the cursor back on the ':' + feed('') + screen:expect([[ + ^: | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) end) -- cgit From 4863ca6b8902c5b0aab95f2af640118cd417d379 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 Mar 2023 10:49:32 +0800 Subject: test: use exec_capture() in more places (#22787) Problem: Using `meths.exec2("code", { output = true })` is too verbose. Solution: Use exec_capture() in more places. --- test/functional/api/extmark_spec.lua | 7 ++++--- test/functional/api/keymap_spec.lua | 4 ++-- test/functional/api/vim_spec.lua | 17 +++++++++-------- test/functional/autocmd/autocmd_oldtest_spec.lua | 5 +---- test/functional/core/remote_spec.lua | 6 +++--- test/functional/core/startup_spec.lua | 5 +++-- test/functional/ex_cmds/script_spec.lua | 5 +++-- test/functional/ex_cmds/source_spec.lua | 20 ++++++++++---------- test/functional/ex_cmds/verbose_spec.lua | 2 +- test/functional/helpers.lua | 2 +- test/functional/options/keymap_spec.lua | 4 ++-- test/functional/ui/cmdline_highlight_spec.lua | 9 +++++---- test/functional/ui/messages_spec.lua | 5 +++-- 13 files changed, 47 insertions(+), 44 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index e9a175625b..3882fc90ca 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -11,6 +11,7 @@ local insert = helpers.insert local feed = helpers.feed local clear = helpers.clear local command = helpers.command +local exec = helpers.exec local meths = helpers.meths local assert_alive = helpers.assert_alive @@ -1413,12 +1414,12 @@ describe('API/extmarks', function() end) it('does not crash with append/delete/undo sequence', function() - meths.exec2([[ + exec([[ let ns = nvim_create_namespace('myplugin') call nvim_buf_set_extmark(0, ns, 0, 0, {}) call append(0, '') %delete - undo]], { output = false }) + undo]]) assert_alive() end) @@ -1450,7 +1451,7 @@ describe('API/extmarks', function() feed('u') -- handles pasting - meths.exec2([[let @a='asdfasdf']], { output = false }) + exec([[let @a='asdfasdf']]) feed([["ap]]) eq({ {1, 0, 0}, {2, 0, 8} }, meths.buf_get_extmarks(0, ns, 0, -1, {})) diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua index 78281be195..f2817ff627 100644 --- a/test/functional/api/keymap_spec.lua +++ b/test/functional/api/keymap_spec.lua @@ -681,13 +681,13 @@ describe('nvim_set_keymap, nvim_del_keymap', function() end) it('can set mappings whose RHS change dynamically', function() - meths.exec2([[ + exec([[ function! FlipFlop() abort if !exists('g:flip') | let g:flip = 0 | endif let g:flip = !g:flip return g:flip endfunction - ]], { output = false }) + ]]) eq(1, meths.call_function('FlipFlop', {})) eq(0, meths.call_function('FlipFlop', {})) eq(1, meths.call_function('FlipFlop', {})) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 162735dbd7..d8fb1bc623 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -9,6 +9,7 @@ local NIL = helpers.NIL local clear, nvim, eq, neq = helpers.clear, helpers.nvim, helpers.eq, helpers.neq local command = helpers.command local exec = helpers.exec +local exec_capture = helpers.exec_capture local eval = helpers.eval local expect = helpers.expect local funcs = helpers.funcs @@ -588,7 +589,7 @@ describe('API', function() it('sets previous directory', function() meths.set_current_dir("Xtestdir") - meths.exec2('cd -', { output = false }) + command('cd -') eq(funcs.getcwd(), start_dir) end) end) @@ -2687,7 +2688,7 @@ describe('API', function() eq(' 1 %a "[No Name]" line 1\n'.. ' 3 h "[Scratch]" line 0\n'.. ' 4 h "[Scratch]" line 0', - meths.exec2('ls', { output = true }).output) + exec_capture('ls')) -- current buffer didn't change eq({id=1}, meths.get_current_buf()) @@ -2954,13 +2955,13 @@ describe('API', function() it('can save message history', function() nvim('command', 'set cmdheight=2') -- suppress Press ENTER nvim("echo", {{"msg\nmsg"}, {"msg"}}, true, {}) - eq("msg\nmsgmsg", meths.exec2('messages', { output = true }).output) + eq("msg\nmsgmsg", exec_capture('messages')) end) it('can disable saving message history', function() nvim('command', 'set cmdheight=2') -- suppress Press ENTER nvim_async("echo", {{"msg\nmsg"}, {"msg"}}, false, {}) - eq("", meths.exec2("messages", { output = true }).output) + eq("", exec_capture('messages')) end) end) @@ -3949,7 +3950,7 @@ describe('API', function() it('sets correct script context', function() meths.cmd({ cmd = "set", args = { "cursorline" } }, {}) - local str = meths.exec2([[verbose set cursorline?]], { output = true }).output + local str = exec_capture([[verbose set cursorline?]]) neq(nil, str:find("cursorline\n\tLast set from API client %(channel id %d+%)")) end) @@ -3999,7 +4000,7 @@ describe('API', function() line6 ]] meths.cmd({ cmd = "del", range = { 2, 4 }, reg = 'a' }, {}) - meths.exec2("1put a", { output = false }) + command('1put a') expect [[ line1 line2 @@ -4064,11 +4065,11 @@ describe('API', function() { output = true })) end) it('splits arguments correctly', function() - meths.exec2([[ + exec([[ function! FooFunc(...) echo a:000 endfunction - ]], { output = false }) + ]]) meths.create_user_command("Foo", "call FooFunc()", { nargs = '+' }) eq([=[['a quick', 'brown fox', 'jumps over the', 'lazy dog']]=], meths.cmd({ cmd = "Foo", args = { "a quick", "brown fox", "jumps over the", "lazy dog"}}, diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua index 7d475e5015..29d589a296 100644 --- a/test/functional/autocmd/autocmd_oldtest_spec.lua +++ b/test/functional/autocmd/autocmd_oldtest_spec.lua @@ -4,10 +4,7 @@ local clear = helpers.clear local eq = helpers.eq local meths = helpers.meths local funcs = helpers.funcs - -local exec = function(str) - meths.exec2(str, { output = false }) -end +local exec = helpers.exec describe('oldtests', function() before_each(clear) diff --git a/test/functional/core/remote_spec.lua b/test/functional/core/remote_spec.lua index b2a1679023..f74bb65553 100644 --- a/test/functional/core/remote_spec.lua +++ b/test/functional/core/remote_spec.lua @@ -3,11 +3,11 @@ local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local command = helpers.command local eq = helpers.eq +local exec_capture = helpers.exec_capture local exec_lua = helpers.exec_lua local expect = helpers.expect local funcs = helpers.funcs local insert = helpers.insert -local meths = helpers.meths local new_argv = helpers.new_argv local neq = helpers.neq local set_session = helpers.set_session @@ -101,7 +101,7 @@ describe('Remote', function() expect(contents) eq(1, #funcs.getbufinfo()) -- Since we didn't pass silent, we should get a complaint - neq(nil, string.find(meths.exec2('messages', { output = true }).output, 'E247')) + neq(nil, string.find(exec_capture('messages'), 'E247:')) end) it('creates server if not found with tabs', function() @@ -110,7 +110,7 @@ describe('Remote', function() eq(2, #funcs.gettabinfo()) eq(2, #funcs.getbufinfo()) -- We passed silent, so no message should be issued about the server not being found - eq(nil, string.find(meths.exec2('messages', { output = true }).output, 'E247')) + eq(nil, string.find(exec_capture('messages'), 'E247:')) end) pending('exits with error on', function() diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index 4ae8b1c95e..cc94623df3 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -9,6 +9,7 @@ local ok = helpers.ok local eq = helpers.eq local matches = helpers.matches local eval = helpers.eval +local exec_capture = helpers.exec_capture local exec_lua = helpers.exec_lua local feed = helpers.feed local funcs = helpers.funcs @@ -823,7 +824,7 @@ describe('user config init', function() clear{ args_rm={'-u'}, env=xenv } feed('') -- Dismiss "Conflicting config …" message. eq(1, eval('g:lua_rc')) - matches('^E5422: Conflicting configs', meths.exec2('messages', { output = true }).output) + matches('^E5422: Conflicting configs', exec_capture('messages')) end) end) end) @@ -872,7 +873,7 @@ describe('runtime:', function() eq(2, eval('g:lua_plugin')) -- Check if plugin_file_path is listed in :scriptname - local scripts = meths.exec2(':scriptnames', { output = true }).output + local scripts = exec_capture('scriptnames') assert(scripts:find(plugin_file_path)) -- Check if plugin_file_path is listed in startup profile diff --git a/test/functional/ex_cmds/script_spec.lua b/test/functional/ex_cmds/script_spec.lua index d13268c97c..62249caa5e 100644 --- a/test/functional/ex_cmds/script_spec.lua +++ b/test/functional/ex_cmds/script_spec.lua @@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq local neq = helpers.neq local command = helpers.command +local exec_capture = helpers.exec_capture local write_file = helpers.write_file local meths = helpers.meths local clear = helpers.clear @@ -34,7 +35,7 @@ describe('script_get-based command', function() %s %s endif ]])):format(cmd, garbage))) - eq('', meths.exec2('messages', { output = true }).output) + eq('', exec_capture('messages')) if check_neq then neq(0, exc_exec(dedent([[ %s %s @@ -49,7 +50,7 @@ describe('script_get-based command', function() EOF endif ]])):format(cmd, garbage))) - eq('', meths.exec2('messages', { output = true }).output) + eq('', exec_capture('messages')) if check_neq then eq(true, pcall(source, (dedent([[ let g:exc = 0 diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua index e12ead240d..41045f5cb4 100644 --- a/test/functional/ex_cmds/source_spec.lua +++ b/test/functional/ex_cmds/source_spec.lua @@ -96,12 +96,12 @@ describe(':source', function() let d = s:s]]) command('source') - eq('2', meths.exec2('echo a', { output = true }).output) - eq("{'k': 'v'}", meths.exec2('echo b', { output = true }).output) + eq('2', exec_capture('echo a')) + eq("{'k': 'v'}", exec_capture('echo b')) -- Script items are created only on script var access - eq("1", meths.exec2('echo c', { output = true }).output) - eq("0zBEEFCAFE", meths.exec2('echo d', { output = true }).output) + eq("1", exec_capture('echo c')) + eq("0zBEEFCAFE", exec_capture('echo d')) exec('set cpoptions+=C') eq('Vim(let):E723: Missing end of Dictionary \'}\': ', exc_exec('source')) @@ -124,14 +124,14 @@ describe(':source', function() -- Source the 2nd line only feed('ggjV') feed_command(':source') - eq('3', meths.exec2('echo a', { output = true }).output) + eq('3', exec_capture('echo a')) -- Source from 2nd line to end of file feed('ggjVG') feed_command(':source') - eq('4', meths.exec2('echo a', { output = true }).output) - eq("{'K': 'V'}", meths.exec2('echo b', { output = true }).output) - eq("1_C()", meths.exec2('echo D()', { output = true }).output) + eq('4', exec_capture('echo a')) + eq("{'K': 'V'}", exec_capture('echo b')) + eq("1_C()", exec_capture('echo D()')) -- Source last line only feed_command(':$source') @@ -147,7 +147,7 @@ describe(':source', function() let a = 123 ]] command('source') - eq('123', meths.exec2('echo a', { output = true }).output) + eq('123', exec_capture('echo a')) end) it('multiline heredoc command', function() @@ -157,7 +157,7 @@ describe(':source', function() EOF]]) command('source') - eq('4', meths.exec2('echo luaeval("y")', { output = true }).output) + eq('4', exec_capture('echo luaeval("y")')) end) it('can source lua files', function() diff --git a/test/functional/ex_cmds/verbose_spec.lua b/test/functional/ex_cmds/verbose_spec.lua index 2482fd912f..def09e2f9e 100644 --- a/test/functional/ex_cmds/verbose_spec.lua +++ b/test/functional/ex_cmds/verbose_spec.lua @@ -28,7 +28,7 @@ vim.api.nvim_exec2("augroup test_group\ autocmd!\ autocmd FileType c setl cindent\ augroup END\ - ", { output = false }) + ", {}) vim.api.nvim_command("command Bdelete :bd") vim.api.nvim_create_user_command("TestCommand", ":echo 'Hello'", {}) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index de5fe96934..188c196eb3 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -826,7 +826,7 @@ function module.skip_fragile(pending_fn, cond) end function module.exec(code) - module.meths.exec2(code, { output = false }) + module.meths.exec2(code, {}) end function module.exec_capture(code) diff --git a/test/functional/options/keymap_spec.lua b/test/functional/options/keymap_spec.lua index 7ff86438b2..c390e3d943 100644 --- a/test/functional/options/keymap_spec.lua +++ b/test/functional/options/keymap_spec.lua @@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each) local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq local expect, command, eval = helpers.expect, helpers.command, helpers.eval local insert, call = helpers.insert, helpers.call -local funcs, dedent = helpers.funcs, helpers.dedent +local exec_capture, dedent = helpers.exec_capture, helpers.dedent -- First test it's implemented using the :lmap and :lnoremap commands, then -- check those mappings behave as expected. @@ -30,7 +30,7 @@ describe("'keymap' / :lmap", function() command('lmapclear ') command('set keymap=dvorak') command('set nomore') - local bindings = funcs.nvim_exec2('lmap', { output = true }).output + local bindings = exec_capture('lmap') eq(dedent([[ l " @_ diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua index d6c8408f04..783246c6e4 100644 --- a/test/functional/ui/cmdline_highlight_spec.lua +++ b/test/functional/ui/cmdline_highlight_spec.lua @@ -7,6 +7,7 @@ local clear = helpers.clear local meths = helpers.meths local funcs = helpers.funcs local source = helpers.source +local exec_capture = helpers.exec_capture local dedent = helpers.dedent local command = helpers.command local curbufmeths = helpers.curbufmeths @@ -362,7 +363,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.exec2('messages', { output = true }).output) + eq('', exec_capture('messages')) end) it('silences :echon', function() set_color_cb('Echoning') @@ -377,7 +378,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.exec2('messages', { output = true }).output) + eq('', exec_capture('messages')) end) it('silences :echomsg', function() set_color_cb('Echomsging') @@ -392,7 +393,7 @@ describe('Command-line coloring', function() {EOB:~ }| :e^ | ]]) - eq('', meths.exec2('messages', { output = true }).output) + eq('', exec_capture('messages')) end) it('does the right thing when throwing', function() set_color_cb('Throwing') @@ -858,7 +859,7 @@ describe('Ex commands coloring', function() ]]) feed('') eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: empty buffer', - meths.exec2('messages', { output = true }).output) + exec_capture('messages')) end) it('errors out when failing to get callback', function() meths.set_var('Nvim_color_cmdline', 42) diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 81602ef92e..5220f3fa89 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -10,6 +10,7 @@ local async_meths = helpers.async_meths local test_build_dir = helpers.test_build_dir local nvim_prog = helpers.nvim_prog local exec = helpers.exec +local exec_capture = helpers.exec_capture local exc_exec = helpers.exc_exec local exec_lua = helpers.exec_lua local poke_eventloop = helpers.poke_eventloop @@ -986,7 +987,7 @@ describe('ui/builtin messages', function() -- screen size doesn't affect internal output #10285 eq('ErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red', - meths.exec2("hi ErrorMsg", { output = true }).output) + exec_capture("hi ErrorMsg")) end) it(':syntax list langGroup output', function() @@ -1025,7 +1026,7 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim match /\ Date: Sun, 26 Mar 2023 04:41:27 -0500 Subject: test: fix flaky watchfiles tests (#22637) --- test/functional/lua/watch_spec.lua | 2 ++ test/functional/plugin/lsp_spec.lua | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'test/functional') 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) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 8b5e7d56ac..3de4c6275e 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -3783,7 +3783,8 @@ describe('LSP', function() local expected_messages = 2 -- initialize, initialized - local msg_wait_timeout = require('vim.lsp._watchfiles')._watchfunc == vim._watch.poll and 2500 or 200 + local watchfunc = require('vim.lsp._watchfiles')._watchfunc + local msg_wait_timeout = watchfunc == vim._watch.poll and 2500 or 200 local function wait_for_messages() assert(vim.wait(msg_wait_timeout, function() return #server.messages == expected_messages end), 'Timed out waiting for expected number of messages. Current messages seen so far: ' .. vim.inspect(server.messages)) end @@ -3807,6 +3808,10 @@ describe('LSP', function() }, }, { client_id = client_id }) + if watchfunc == vim._watch.poll then + vim.wait(100) + end + local path = root_dir .. '/watch' local file = io.open(path, 'w') file:close() -- cgit From b7748662ed5b06c12a74560690b728fdf770666f Mon Sep 17 00:00:00 2001 From: Michal Liszcz Date: Wed, 29 Mar 2023 09:59:01 +0200 Subject: fix(api): Use local LastSet structure in nvim_get_option_info (#22741) fix(api): use local LastSet structure in nvim_get_option_info * nvim_get_option_info is deprecated. It is always using the global LastSet information as reported in #15232. * nvim_get_option_info2 is added. The new function additionally accepts an 'opts' table {scope, buf, win} allowing to specify the option scope and query local options from another buffer or window. --- test/functional/api/vim_spec.lua | 93 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d8fb1bc623..9d5a0c4b4e 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -2892,6 +2892,99 @@ describe('API', function() end) end) + describe('nvim_get_option_info2', function() + local fname + local bufs + local wins + + before_each(function() + fname = tmpname() + write_file(fname, [[ + setglobal dictionary=mydict " 1, global-local (buffer) + setlocal formatprg=myprg " 2, global-local (buffer) + setglobal equalprg=prg1 " 3, global-local (buffer) + setlocal equalprg=prg2 " 4, global-local (buffer) + setglobal fillchars=stl:x " 5, global-local (window) + setlocal listchars=eol:c " 6, global-local (window) + setglobal showbreak=aaa " 7, global-local (window) + setlocal showbreak=bbb " 8, global-local (window) + setglobal completeopt=menu " 9, global + ]]) + + exec_lua 'vim.cmd.vsplit()' + meths.create_buf(false, false) + + bufs = meths.list_bufs() + wins = meths.list_wins() + + meths.win_set_buf(wins[1].id, bufs[1].id) + meths.win_set_buf(wins[2].id, bufs[2].id) + + meths.set_current_win(wins[2].id) + meths.exec('source ' .. fname, false) + + meths.set_current_win(wins[1].id) + end) + + after_each(function() + os.remove(fname) + end) + + it('should return option information', function() + eq(meths.get_option_info('dictionary'), meths.get_option_info2('dictionary', {})) -- buffer + eq(meths.get_option_info('fillchars'), meths.get_option_info2('fillchars', {})) -- window + eq(meths.get_option_info('completeopt'), meths.get_option_info2('completeopt', {})) -- global + end) + + describe('last set', function() + local tests = { + {desc="(buf option, global requested, global set) points to global", linenr=1, sid=1, args={'dictionary', {scope='global'}}}, + {desc="(buf option, global requested, local set) is not set", linenr=0, sid=0, args={'formatprg', {scope='global'}}}, + {desc="(buf option, global requested, both set) points to global", linenr=3, sid=1, args={'equalprg', {scope='global'}}}, + {desc="(buf option, local requested, global set) is not set", linenr=0, sid=0, args={'dictionary', {scope='local'}}}, + {desc="(buf option, local requested, local set) points to local", linenr=2, sid=1, args={'formatprg', {scope='local'}}}, + {desc="(buf option, local requested, both set) points to local", linenr=4, sid=1, args={'equalprg', {scope='local'}}}, + {desc="(buf option, fallback requested, global set) points to global", linenr=1, sid=1, args={'dictionary', {}}}, + {desc="(buf option, fallback requested, local set) points to local", linenr=2, sid=1, args={'formatprg', {}}}, + {desc="(buf option, fallback requested, both set) points to local", linenr=4, sid=1, args={'equalprg', {}}}, + {desc="(win option, global requested, global set) points to global", linenr=5, sid=1, args={'fillchars', {scope='global'}}}, + {desc="(win option, global requested, local set) is not set", linenr=0, sid=0, args={'listchars', {scope='global'}}}, + {desc="(win option, global requested, both set) points to global", linenr=7, sid=1, args={'showbreak', {scope='global'}}}, + {desc="(win option, local requested, global set) is not set", linenr=0, sid=0, args={'fillchars', {scope='local'}}}, + {desc="(win option, local requested, local set) points to local", linenr=6, sid=1, args={'listchars', {scope='local'}}}, + {desc="(win option, local requested, both set) points to local", linenr=8, sid=1, args={'showbreak', {scope='local'}}}, + {desc="(win option, fallback requested, global set) points to global", linenr=5, sid=1, args={'fillchars', {}}}, + {desc="(win option, fallback requested, local set) points to local", linenr=6, sid=1, args={'listchars', {}}}, + {desc="(win option, fallback requested, both set) points to local", linenr=8, sid=1, args={'showbreak', {}}}, + {desc="(global option, global requested) points to global", linenr=9, sid=1, args={'completeopt', {scope='global'}}}, + {desc="(global option, local requested) is not set", linenr=0, sid=0, args={'completeopt', {scope='local'}}}, + {desc="(global option, fallback requested) points to global", linenr=9, sid=1, args={'completeopt', {}}}, + } + + for _, t in pairs(tests) do + it(t.desc, function() + -- Switch to the target buffer/window so that curbuf/curwin are used. + meths.set_current_win(wins[2].id) + local info = meths.get_option_info2(unpack(t.args)) + eq(t.linenr, info.last_set_linenr) + eq(t.sid, info.last_set_sid) + end) + end + + it('is provided for cross-buffer requests', function() + local info = meths.get_option_info2('formatprg', {buf=bufs[2].id}) + eq(2, info.last_set_linenr) + eq(1, info.last_set_sid) + end) + + it('is provided for cross-window requests', function() + local info = meths.get_option_info2('listchars', {win=wins[2].id}) + eq(6, info.last_set_linenr) + eq(1, info.last_set_sid) + end) + end) + end) + describe('nvim_echo', function() local screen -- 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 ++ test/functional/plugin/lsp/diagnostic_spec.lua | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'test/functional') 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', diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index f73ffc29b0..f58016bf01 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -97,7 +97,6 @@ describe('vim.lsp.diagnostic', function() } diagnostics[1].code = 42 - diagnostics[1].tags = {"foo", "bar"} diagnostics[1].data = "Hello world" vim.lsp.diagnostic.on_publish_diagnostics(nil, { @@ -110,10 +109,9 @@ describe('vim.lsp.diagnostic', function() vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)[1], } ]] - eq({code = 42, tags = {"foo", "bar"}, data = "Hello world"}, result[1].user_data.lsp) + eq({code = 42, data = "Hello world"}, result[1].user_data.lsp) eq(42, result[1].code) eq(42, result[2].code) - eq({"foo", "bar"}, result[2].tags) eq("Hello world", result[2].data) end) end) -- cgit From b34097fe6d2ea5c84bcec65a834a430d9f58eb64 Mon Sep 17 00:00:00 2001 From: "Sindre T. Strøm" Date: Fri, 31 Mar 2023 12:52:53 +0200 Subject: fix(api): return both link and attributes with nvim_get_hl (#22824) Problem: No way to get the actual highlight attributes for a linked group through |nvim_get_hl()| (not the attributes from the link target). Solution: Return the actual attributes as well as the link target name. --- test/functional/api/highlight_spec.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 65b13bebf7..a4bd574a56 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -561,4 +561,18 @@ describe('API: get highlight', function() eq({ link = 'String' }, meths.get_hl(0, { name = '@string' })) eq({ fg = 10937249 }, meths.get_hl(0, { name = '@string.cpp', link = false })) end) + + it('can get all attributes for a linked group', function() + command('hi Bar guifg=red') + command('hi Foo guifg=#00ff00 gui=bold,underline') + command('hi! link Foo Bar') + eq({ link = 'Bar', fg = tonumber('00ff00', 16), bold = true, underline = true }, meths.get_hl(0, { name = 'Foo', link = true })) + end) + + it('can set link as well as other attributes', function() + command('hi Bar guifg=red') + local hl = { link = 'Bar', fg = tonumber('00ff00', 16), bold = true, cterm = { bold = true } } + meths.set_hl(0, 'Foo', hl) + eq(hl, meths.get_hl(0, { name = 'Foo', link = true })) + end) end) -- cgit From e3a3d300636872f786f0c8a338ed1a3749d0a1f6 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 1 Apr 2023 03:55:43 +0200 Subject: fix(ui): recording change doesn't trigger statusline redraw --- test/functional/ui/statusline_spec.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index c59ade0e31..ffd45a59a3 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -622,3 +622,17 @@ it('K_EVENT does not trigger a statusline redraw unnecessarily', function() sleep(50) eq(1, eval('g:counter < 50'), 'g:counter=' .. eval('g:counter')) end) + +it('statusline is redrawn on recording state change #22683', function() + clear() + local screen = Screen.new(40, 4) + screen:attach() + command('set ls=2 stl=%{repeat(reg_recording(),5)}') + feed('qQ') + screen:expect([[ + ^ | + ~ | + QQQQQ | + recording @Q | + ]]) +end) -- cgit From 90fdaf55c913d07bc80eec6442b02d8c001659b4 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 1 Apr 2023 12:11:24 +0200 Subject: fix(tests): adapt treesitter/highlight_spec priority test Still relied on the old `@Foo`->`Foo` capture to highlight mechanism; use capture with default highlight instead. --- test/functional/treesitter/highlight_spec.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'test/functional') diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 44e6500008..faeb4befcd 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -575,14 +575,14 @@ describe('treesitter highlighting', function() exec_lua [[ local parser = vim.treesitter.get_parser(0, "c") - test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query..'\n((translation_unit) @Error (set! "priority" 101))\n'}}) + test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query..'\n((translation_unit) @constant (#set! "priority" 101))\n'}}) ]] - -- expect everything to have Error highlight + -- expect everything to have Constant highlight screen:expect{grid=[[ {12:int}{8: x = INT_MAX;} | - {8:#define READ_STRING(x, y) (}{12:char_u}{8: *)read_string((x), (}{12:size_t}{8:)(y))}| - {8:#define foo }{12:void}{8: main() { \} | - {8: }{12:return}{8: 42; \} | + {8:#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))}| + {8:#define foo void main() { \} | + {8: return 42; \} | {8: }} | ^ | {1:~ }| @@ -599,13 +599,13 @@ describe('treesitter highlighting', function() | ]], attr_ids={ [1] = {bold = true, foreground = Screen.colors.Blue1}; - [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}; + [8] = {foreground = Screen.colors.Magenta1}; -- bold will not be overwritten at the moment - [12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Grey100}; + [12] = {bold = true, foreground = Screen.colors.Magenta1}; }} eq({ - {capture='Error', metadata = { priority='101' }, lang='c' }; + {capture='constant', metadata = { priority='101' }, lang='c' }; {capture='type', metadata = { }, lang='c' }; }, exec_lua [[ return vim.treesitter.get_captures_at_pos(0, 0, 2) ]]) end) -- cgit From 2a10f64e254375e77e1c5a6aeae3cd65cd122afb Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 25 Mar 2023 02:24:24 +0100 Subject: feat(extmarks): extend nvim_buf_get_extmarks() Problem: Can not get all extmarks in a buffer. Properties are missing from the details array. Solution: Allow getting all extmarks in a buffer by supplying a -1 "ns_id". Add missing properties to the details array. --- test/functional/api/extmark_spec.lua | 68 ++++++++++++++++++++++++++++-------- test/functional/ui/bufhl_spec.lua | 2 ++ 2 files changed, 56 insertions(+), 14 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 3882fc90ca..4bd8f51904 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1463,6 +1463,7 @@ describe('API/extmarks', function() end_line = 1 }) eq({ {1, 0, 0, { + ns_id = 1, end_col = 0, end_row = 1, right_gravity = true, @@ -1480,20 +1481,27 @@ describe('API/extmarks', function() it('can get details', function() set_extmark(ns, marks[1], 0, 0, { + conceal = "c", + cursorline_hl_group = "Statement", end_col = 0, - end_row = 1, - right_gravity = false, end_right_gravity = true, - priority = 0, + end_row = 1, hl_eol = true, - hl_mode = "blend", hl_group = "String", - virt_text = { { "text", "Statement" } }, - virt_text_pos = "right_align", - virt_text_hide = true, + hl_mode = "blend", + line_hl_group = "Statement", + number_hl_group = "Statement", + priority = 0, + right_gravity = false, + sign_hl_group = "Statement", + sign_text = ">>", + spell = true, virt_lines = { { { "lines", "Statement" } }}, virt_lines_above = true, virt_lines_leftcol = true, + virt_text = { { "text", "Statement" } }, + virt_text_hide = true, + virt_text_pos = "right_align", }) set_extmark(ns, marks[2], 0, 0, { priority = 0, @@ -1501,22 +1509,31 @@ describe('API/extmarks', function() virt_text_win_col = 1, }) eq({0, 0, { + conceal = "c", + cursorline_hl_group = "Statement", end_col = 0, - end_row = 1, - right_gravity = false, end_right_gravity = true, - priority = 0, + end_row = 1, hl_eol = true, - hl_mode = "blend", hl_group = "String", - virt_text = { { "text", "Statement" } }, - virt_text_pos = "right_align", - virt_text_hide = true, + hl_mode = "blend", + line_hl_group = "Statement", + ns_id = 1, + number_hl_group = "Statement", + priority = 0, + right_gravity = false, + sign_hl_group = "Statement", + sign_text = ">>", + spell = true, virt_lines = { { { "lines", "Statement" } }}, virt_lines_above = true, virt_lines_leftcol = true, + virt_text = { { "text", "Statement" } }, + virt_text_hide = true, + virt_text_pos = "right_align", } }, get_extmark_by_id(ns, marks[1], { details = true })) eq({0, 0, { + ns_id = 1, right_gravity = true, priority = 0, virt_text = { { "text", "Statement" } }, @@ -1525,6 +1542,29 @@ describe('API/extmarks', function() virt_text_win_col = 1, } }, get_extmark_by_id(ns, marks[2], { details = true })) end) + + it('can get marks from anonymous namespaces', function() + ns = request('nvim_create_namespace', "") + ns2 = request('nvim_create_namespace', "") + set_extmark(ns, 1, 0, 0, {}) + set_extmark(ns2, 2, 1, 0, {}) + eq({{ 1, 0, 0, { ns_id = ns, right_gravity = true }}, + { 2, 1, 0, { ns_id = ns2, right_gravity = true }}}, + get_extmarks(-1, 0, -1, { details = true })) + end) + + it('can filter by extmark properties', function() + set_extmark(ns, 1, 0, 0, {}) + set_extmark(ns, 2, 0, 0, { hl_group = 'Normal' }) + set_extmark(ns, 3, 0, 0, { sign_text = '>>' }) + set_extmark(ns, 4, 0, 0, { virt_text = {{'text', 'Normal'}}}) + set_extmark(ns, 5, 0, 0, { virt_lines = {{{ 'line', 'Normal' }}}}) + eq(5, #get_extmarks(-1, 0, -1, { details = true })) + eq({{ 2, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'highlight' })) + eq({{ 3, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'sign' })) + eq({{ 4, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'virt_text' })) + eq({{ 5, 0, 0 }}, get_extmarks(-1, 0, -1, { type = 'virt_lines' })) + end) end) describe('Extmarks buffer api with many marks', function() diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index adec0770de..5263fb4c24 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -766,6 +766,7 @@ describe('Buffer highlighting', function() -- an existing virtual text. We might add a prioritation system. set_virtual_text(id1, 0, s1, {}) eq({{1, 0, 0, { + ns_id = 1, priority = 0, virt_text = s1, -- other details @@ -778,6 +779,7 @@ describe('Buffer highlighting', function() local lastline = line_count() set_virtual_text(id1, line_count(), s2, {}) eq({{3, lastline, 0, { + ns_id = 1, priority = 0, virt_text = s2, -- other details -- 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') 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 - test/functional/treesitter/highlight_spec.lua | 14 ++++++------ test/functional/treesitter/parser_spec.lua | 32 +++++++++++++-------------- 3 files changed, 23 insertions(+), 24 deletions(-) (limited to 'test/functional') 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; diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index faeb4befcd..4e1efec404 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -413,7 +413,7 @@ describe('treesitter highlighting', function() it("supports injected languages", function() insert([[ int x = INT_MAX; - #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + #define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) #define foo void main() { \ return 42; \ } @@ -421,7 +421,7 @@ describe('treesitter highlighting', function() screen:expect{grid=[[ int x = INT_MAX; | - #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))| + #define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) | #define foo void main() { \ | return 42; \ | } | @@ -450,7 +450,7 @@ describe('treesitter highlighting', function() screen:expect{grid=[[ {3:int} x = {5:INT_MAX}; | - #define {5:READ_STRING}(x, y) ({3:char_u} *)read_string((x), ({3:size_t})(y))| + #define {5:READ_STRING}(x, y) ({3:char} *)read_string((x), ({3:size_t})(y)) | #define foo {3:void} main() { \ | {4:return} {5:42}; \ | } | @@ -473,7 +473,7 @@ describe('treesitter highlighting', function() it("supports overriding queries, like ", function() insert([[ int x = INT_MAX; - #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + #define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) #define foo void main() { \ return 42; \ } @@ -489,7 +489,7 @@ describe('treesitter highlighting', function() screen:expect{grid=[[ {3:int} x = {5:INT_MAX}; | - #define {5:READ_STRING}(x, y) ({3:char_u} *)read_string((x), ({3:size_t})(y))| + #define {5:READ_STRING}(x, y) ({3:char} *)read_string((x), ({3:size_t})(y)) | #define foo {3:void} main() { \ | {4:return} {5:42}; \ | } | @@ -567,7 +567,7 @@ describe('treesitter highlighting', function() it("supports highlighting with priority", function() insert([[ int x = INT_MAX; - #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + #define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) #define foo void main() { \ return 42; \ } @@ -580,7 +580,7 @@ describe('treesitter highlighting', function() -- expect everything to have Constant highlight screen:expect{grid=[[ {12:int}{8: x = INT_MAX;} | - {8:#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))}| + {8:#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y))} | {8:#define foo void main() { \} | {8: return 42; \} | {8: }} | diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index 72a8cd9e9b..ea9958b12a 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -627,8 +627,8 @@ end]] before_each(function() insert([[ int x = INT_MAX; -#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) -#define READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) +#define READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) +#define READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y)) #define VALUE 123 #define VALUE1 123 #define VALUE2 123 @@ -650,8 +650,8 @@ int x = INT_MAX; {3, 14, 3, 17}, -- VALUE 123 {4, 15, 4, 18}, -- VALUE1 123 {5, 15, 5, 18}, -- VALUE2 123 - {1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - {2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + {1, 26, 1, 63}, -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) + {2, 29, 2, 66} -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y)) }, get_ranges()) helpers.feed('ggo') @@ -661,8 +661,8 @@ int x = INT_MAX; {4, 14, 4, 17}, -- VALUE 123 {5, 15, 5, 18}, -- VALUE1 123 {6, 15, 6, 18}, -- VALUE2 123 - {2, 26, 2, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - {3, 29, 3, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + {2, 26, 2, 63}, -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) + {3, 29, 3, 66} -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y)) }, get_ranges()) end) end) @@ -682,8 +682,8 @@ int x = INT_MAX; {3, 14, 5, 18}, -- VALUE 123 -- VALUE1 123 -- VALUE2 123 - {1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + {1, 26, 2, 66} -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) + -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y)) }, get_ranges()) helpers.feed('ggo') @@ -694,8 +694,8 @@ int x = INT_MAX; {4, 14, 6, 18}, -- VALUE 123 -- VALUE1 123 -- VALUE2 123 - {2, 26, 3, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + {2, 26, 3, 66} -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) + -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y)) }, get_ranges()) end) end) @@ -722,8 +722,8 @@ int x = INT_MAX; {3, 14, 5, 18}, -- VALUE 123 -- VALUE1 123 -- VALUE2 123 - {1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + {1, 26, 2, 66} -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) + -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y)) }, get_ranges()) helpers.feed('ggo') @@ -734,8 +734,8 @@ int x = INT_MAX; {4, 14, 6, 18}, -- VALUE 123 -- VALUE1 123 -- VALUE2 123 - {2, 26, 3, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + {2, 26, 3, 66} -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) + -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y)) }, get_ranges()) end) @@ -768,8 +768,8 @@ int x = INT_MAX; {3, 15, 3, 16}, -- VALUE 123 {4, 16, 4, 17}, -- VALUE1 123 {5, 16, 5, 17}, -- VALUE2 123 - {1, 26, 1, 65}, -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) - {2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + {1, 26, 1, 63}, -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y)) + {2, 29, 2, 66} -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y)) }, get_ranges()) end) it("should list all directives", function() -- cgit From c8a28b847e2b814b44fe77b46f7f4564ab59f0ac Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 1 Apr 2023 03:11:56 +0200 Subject: fix(ui): ruler is not redrawn in cmdline with redrawstatus --- test/functional/ui/statusline_spec.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index ffd45a59a3..8e301dc70c 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -636,3 +636,20 @@ it('statusline is redrawn on recording state change #22683', function() recording @Q | ]]) end) + +it('ruler is redrawn in cmdline with redrawstatus #22804', function() + clear() + local screen = Screen.new(40, 2) + screen:attach() + command([[ + let g:n = 'initial value' + set ls=1 ru ruf=%{g:n} + redraw + let g:n = 'other value' + redrawstatus + ]]) + screen:expect([[ + ^ | + other value | + ]]) +end) -- cgit From 269dd747b6e61842856031ca14ac26ee884ede4c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Apr 2023 23:01:48 +0800 Subject: refactor(defaults)!: change default 'commentstring' value to empty (#22862) --- test/functional/api/buffer_updates_spec.lua | 2 +- test/functional/legacy/window_cmd_spec.lua | 1 + test/functional/ui/fold_spec.lua | 7 +++++-- 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua index 25b838a4af..80e29c1ff2 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -75,7 +75,7 @@ local function reopenwithfolds(b) local tick = reopen(b, origlines) -- use markers for folds, make all folds open by default - command('setlocal foldmethod=marker foldlevel=20') + command('setlocal foldmethod=marker foldlevel=20 commentstring=/*%s*/') -- add a fold command('2,4fold') diff --git a/test/functional/legacy/window_cmd_spec.lua b/test/functional/legacy/window_cmd_spec.lua index 0e9775060d..c7b5878b92 100644 --- a/test/functional/legacy/window_cmd_spec.lua +++ b/test/functional/legacy/window_cmd_spec.lua @@ -116,6 +116,7 @@ describe('splitkeep', function() -- oldtest: Test_splitkeep_fold() it('does not scroll when window has closed folds', function() exec([[ + set commentstring=/*%s*/ set splitkeep=screen set foldmethod=marker set number diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index c8a3397a86..96e28c1978 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -2032,8 +2032,11 @@ describe("folded lines", function() end) it('multibyte fold markers work #20438', function() - meths.win_set_option(0, 'foldmethod', 'marker') - meths.win_set_option(0, 'foldmarker', '«,»') + exec([[ + setlocal foldmethod=marker + setlocal foldmarker=«,» + setlocal commentstring=/*%s*/ + ]]) insert([[ bbbbb bbbbb -- 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') 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 10baf89712724b4b95f7c641f2012f051737003c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 3 Apr 2023 08:36:14 +0800 Subject: vim-patch:9.0.1439: start Insert mode when accessing a hidden prompt buffer (#22867) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Start Insert mode when accessing a hidden prompt buffer. Solution: Call leaving_window() in aucmd_restbuf(). (Thorben Tröbst, closes vim/vim#12148, closes vim/vim#12147) https://github.com/vim/vim/commit/cde8de034524d00aba4ff4142e658baff511e12d Cherry-pick test_prompt_buffer.vim changes from patch 9.0.0631. Co-authored-by: orbital --- test/functional/legacy/prompt_buffer_spec.lua | 45 ++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) (limited to 'test/functional') diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index 602593d632..6c72cde855 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -3,9 +3,11 @@ local Screen = require('test.functional.ui.screen') local feed = helpers.feed local source = helpers.source local clear = helpers.clear +local command = helpers.command local poke_eventloop = helpers.poke_eventloop local meths = helpers.meths local eq = helpers.eq +local neq = helpers.neq describe('prompt buffer', function() local screen @@ -14,9 +16,11 @@ describe('prompt buffer', function() clear() screen = Screen.new(25, 10) screen:attach() - source([[ - set laststatus=0 nohidden + command('set laststatus=0 nohidden') + end) + local function source_script() + source([[ func TextEntered(text) if a:text == "exit" " Reset &modified to allow the buffer to be closed. @@ -63,7 +67,7 @@ describe('prompt buffer', function() ~ | -- INSERT -- | ]]) - end) + end after_each(function() screen:detach() @@ -71,6 +75,7 @@ describe('prompt buffer', function() -- oldtest: Test_prompt_basic() it('works', function() + source_script() feed("hello\n") screen:expect([[ cmd: hello | @@ -101,6 +106,7 @@ describe('prompt buffer', function() -- oldtest: Test_prompt_editing() it('editing', function() + source_script() feed("hello") screen:expect([[ cmd: hel^ | @@ -170,6 +176,7 @@ describe('prompt buffer', function() -- oldtest: Test_prompt_switch_windows() it('switch windows', function() + source_script() feed(":call SwitchWindows()") screen:expect{grid=[[ cmd: | @@ -213,11 +220,41 @@ describe('prompt buffer', function() -- oldtest: Test_prompt_while_writing_to_hidden_buffer() it('keeps insert mode after aucmd_restbuf in callback', function() + source_script() source [[ let s:buf = nvim_create_buf(1, 1) call timer_start(0, {-> nvim_buf_set_lines(s:buf, -1, -1, 0, ['walrus'])}) ]] poke_eventloop() - eq({ mode = "i", blocking = false }, meths.get_mode()) + eq({ mode = 'i', blocking = false }, meths.get_mode()) + end) + + -- oldtest: Test_prompt_appending_while_hidden() + it('accessing hidden prompt buffer does not start insert mode', function() + local prev_win = meths.get_current_win() + source([[ + new prompt + set buftype=prompt + set bufhidden=hide + + func s:TextEntered(text) + if a:text == 'exit' + close + endif + let g:entered = a:text + endfunc + call prompt_setcallback(bufnr(), function('s:TextEntered')) + + func DoAppend() + call appendbufline('prompt', '$', 'Test') + endfunc + ]]) + feed('asomething') + eq('something', meths.get_var('entered')) + neq(prev_win, meths.get_current_win()) + feed('exit') + eq(prev_win, meths.get_current_win()) + command('call DoAppend()') + eq({ mode = 'n', blocking = false }, meths.get_mode()) end) end) -- cgit From 7c8c1550737b34fabb3e4cecbc6b6bf3581b2235 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 4 Apr 2023 08:59:11 +0800 Subject: fix(api): avoid double hit-enter prompt with nvim_err_writeln (#22879) --- test/functional/api/vim_spec.lua | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 9d5a0c4b4e..83347a499b 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -2080,6 +2080,46 @@ describe('API', function() end) end) + describe('nvim_err_writeln', function() + local screen + + before_each(function() + screen = Screen.new(40, 8) + screen:attach() + screen:set_default_attr_ids({ + [0] = {bold=true, foreground=Screen.colors.Blue}, + [1] = {foreground = Screen.colors.White, background = Screen.colors.Red}, + [2] = {bold = true, foreground = Screen.colors.SeaGreen}, + [3] = {bold = true, reverse = true}, + }) + end) + + it('shows only one return prompt after all lines are shown', function() + nvim_async('err_writeln', 'FAILURE\nERROR\nEXCEPTION\nTRACEBACK') + screen:expect([[ + | + {0:~ }| + {3: }| + {1:FAILURE} | + {1:ERROR} | + {1:EXCEPTION} | + {1:TRACEBACK} | + {2:Press ENTER or type command to continue}^ | + ]]) + feed('') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) + end) + describe('nvim_list_chans, nvim_get_chan_info', function() before_each(function() command('autocmd ChanOpen * let g:opened_event = deepcopy(v:event)') -- cgit From a5c572bd446a89be2dccb2f7479ff1b017074640 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 4 Apr 2023 19:07:33 +0200 Subject: docs: fix typos Co-authored-by: Gregory Anders Co-authored-by: Raphael Co-authored-by: C.D. MacEachern Co-authored-by: himanoa --- test/functional/api/vim_spec.lua | 2 +- test/functional/plugin/lsp/semantic_tokens_spec.lua | 2 +- test/functional/plugin/lsp_spec.lua | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 83347a499b..de0d82119c 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -4180,7 +4180,7 @@ describe('API', function() meths.cmd({ cmd = "buffers", mods = { filter = { pattern = "foo", force = true } } }, { output = true })) - -- with emsg_silent = true error is suppresed + -- with emsg_silent = true error is suppressed feed([[:lua vim.api.nvim_cmd({ cmd = 'call', mods = { emsg_silent = true } }, {})]]) eq('', meths.cmd({ cmd = 'messages' }, { output = true })) -- error from the next command typed is not suppressed #21420 diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index 780d18fce9..ec4d20974d 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -1367,7 +1367,7 @@ int main() exec_lua([[ local text = ... vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.fn.split(text, "\n")) - vim.wait(15) -- wait fot debounce + vim.wait(15) -- wait for debounce ]], test.text2) end diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 3de4c6275e..7d287d38fa 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -3877,14 +3877,14 @@ describe('LSP', function() local send_event require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback) - local stoppped = false + local stopped = false send_event = function(...) - if not stoppped then + if not stopped then callback(...) end end return function() - stoppped = true + stopped = true end end -- 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/api/vim_spec.lua | 3 +-- test/functional/autocmd/dirchanged_spec.lua | 4 ++-- test/functional/autocmd/focus_spec.lua | 5 +++-- test/functional/core/fileio_spec.lua | 6 +++--- test/functional/core/main_spec.lua | 12 +++++------ test/functional/core/spellfile_spec.lua | 6 +++--- test/functional/ex_cmds/cd_spec.lua | 9 ++++---- test/functional/ex_cmds/file_spec.lua | 7 ++++--- test/functional/ex_cmds/mksession_spec.lua | 4 ++-- test/functional/ex_cmds/mkview_spec.lua | 6 +++--- test/functional/ex_cmds/profile_spec.lua | 12 +++++------ .../ex_cmds/swapfile_preserve_recover_spec.lua | 13 ++++++------ test/functional/ex_cmds/write_spec.lua | 4 ++-- test/functional/ex_cmds/wviminfo_spec.lua | 8 ++++---- test/functional/helpers.lua | 24 ++++++++-------------- test/functional/legacy/011_autocommands_spec.lua | 6 +++--- test/functional/legacy/012_directory_spec.lua | 15 +++++++------- .../legacy/074_global_var_in_viminfo_spec.lua | 4 ++-- test/functional/legacy/autochdir_spec.lua | 4 ++-- test/functional/lua/buffer_updates_spec.lua | 5 +++-- test/functional/lua/fs_spec.lua | 10 ++++----- test/functional/lua/watch_spec.lua | 6 +++--- test/functional/options/autochdir_spec.lua | 9 ++++---- test/functional/plugin/lsp_spec.lua | 4 ++-- test/functional/shada/shada_spec.lua | 10 ++++----- test/functional/vimscript/api_functions_spec.lua | 4 ++-- test/functional/vimscript/buf_functions_spec.lua | 11 +++++----- test/functional/vimscript/eval_spec.lua | 6 +++--- test/functional/vimscript/glob_spec.lua | 7 ++++--- test/functional/vimscript/writefile_spec.lua | 11 +++++----- 30 files changed, 118 insertions(+), 117 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index de0d82119c..ab26425425 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1,6 +1,5 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local lfs = require('lfs') local luv = require('luv') local fmt = string.format @@ -4193,7 +4192,7 @@ describe('API', function() vim.api.nvim_echo({{ opts.fargs[1] }}, false, {}) end, { nargs = 1 }) ]]) - eq(lfs.currentdir(), + eq(luv.cwd(), meths.cmd({ cmd = "Foo", args = { '%:p:h' }, magic = { file = true } }, { output = true })) end) diff --git a/test/functional/autocmd/dirchanged_spec.lua b/test/functional/autocmd/dirchanged_spec.lua index 828cffa460..20aa07d058 100644 --- a/test/functional/autocmd/dirchanged_spec.lua +++ b/test/functional/autocmd/dirchanged_spec.lua @@ -1,4 +1,4 @@ -local lfs = require('lfs') +local luv = require('luv') local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear @@ -9,7 +9,7 @@ local request = helpers.request local is_os = helpers.is_os describe('autocmd DirChanged and DirChangedPre', function() - local curdir = string.gsub(lfs.currentdir(), '\\', '/') + local curdir = string.gsub(luv.cwd(), '\\', '/') local dirs = { curdir .. '/Xtest-functional-autocmd-dirchanged.dir1', curdir .. '/Xtest-functional-autocmd-dirchanged.dir2', diff --git a/test/functional/autocmd/focus_spec.lua b/test/functional/autocmd/focus_spec.lua index d7a87e17ed..33e4d88c7b 100644 --- a/test/functional/autocmd/focus_spec.lua +++ b/test/functional/autocmd/focus_spec.lua @@ -1,6 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) local thelpers = require('test.functional.terminal.helpers') -local lfs = require('lfs') +local luv = require('luv') local clear = helpers.clear local nvim_prog = helpers.nvim_prog local feed_command = helpers.feed_command @@ -32,7 +32,8 @@ describe('autoread TUI FocusGained/FocusLost', function() ]] helpers.write_file(path, '') - lfs.touch(path, os.time() - 10) + local atime = os.time() - 10 + luv.fs_utime(path, atime, atime) screen:expect{grid=[[ {1: } | diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index 153b53dce2..4236a4ff47 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -1,4 +1,4 @@ -local lfs = require('lfs') +local luv = require('luv') local helpers = require('test.functional.helpers')(after_each) local assert_log = helpers.assert_log @@ -142,7 +142,7 @@ describe('fileio', function() local backup_file_name = link_file_name .. '~' write_file('Xtest_startup_file1', initial_content, false) - lfs.link('Xtest_startup_file1', link_file_name, true) + luv.fs_symlink('Xtest_startup_file1', link_file_name) command('set backup') command('set backupcopy=yes') command('edit ' .. link_file_name) @@ -166,7 +166,7 @@ describe('fileio', function() local backup_file_name = backup_dir .. sep .. link_file_name .. '~' write_file('Xtest_startup_file1', initial_content, false) - lfs.link('Xtest_startup_file1', link_file_name, true) + luv.fs_symlink('Xtest_startup_file1', link_file_name) mkdir(backup_dir) command('set backup') command('set backupcopy=yes') diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua index ab11e14a67..efab40dd11 100644 --- a/test/functional/core/main_spec.lua +++ b/test/functional/core/main_spec.lua @@ -1,4 +1,4 @@ -local lfs = require('lfs') +local luv = require('luv') local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') @@ -28,18 +28,18 @@ describe('Command-line option', function() os.remove(dollar_fname) end) it('treats - as stdin', function() - eq(nil, lfs.attributes(fname)) + eq(nil, luv.fs_stat(fname)) funcs.system( {nvim_prog_abs(), '-u', 'NONE', '-i', 'NONE', '--headless', '--cmd', 'set noswapfile shortmess+=IFW fileformats=unix', '-s', '-', fname}, {':call setline(1, "42")', ':wqall!', ''}) eq(0, eval('v:shell_error')) - local attrs = lfs.attributes(fname) + local attrs = luv.fs_stat(fname) eq(#('42\n'), attrs.size) end) it('does not expand $VAR', function() - eq(nil, lfs.attributes(fname)) + eq(nil, luv.fs_stat(fname)) eq(true, not not dollar_fname:find('%$%w+')) write_file(dollar_fname, ':call setline(1, "100500")\n:wqall!\n') funcs.system( @@ -47,7 +47,7 @@ describe('Command-line option', function() '--cmd', 'set noswapfile shortmess+=IFW fileformats=unix', '-s', dollar_fname, fname}) eq(0, eval('v:shell_error')) - local attrs = lfs.attributes(fname) + local attrs = luv.fs_stat(fname) eq(#('100500\n'), attrs.size) end) it('does not crash after reading from stdin in non-headless mode', function() @@ -121,7 +121,7 @@ describe('Command-line option', function() '--cmd', 'language C', '-s', fname, '-s', dollar_fname, fname_2})) eq(2, eval('v:shell_error')) - eq(nil, lfs.attributes(fname_2)) + eq(nil, luv.fs_stat(fname_2)) end) end) end) diff --git a/test/functional/core/spellfile_spec.lua b/test/functional/core/spellfile_spec.lua index afd2c1bce4..378899eece 100644 --- a/test/functional/core/spellfile_spec.lua +++ b/test/functional/core/spellfile_spec.lua @@ -1,5 +1,4 @@ local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') local eq = helpers.eq local clear = helpers.clear @@ -7,6 +6,7 @@ local meths = helpers.meths local exc_exec = helpers.exc_exec local rmdir = helpers.rmdir local write_file = helpers.write_file +local mkdir = helpers.mkdir local testdir = 'Xtest-functional-spell-spellfile.d' @@ -14,8 +14,8 @@ describe('spellfile', function() before_each(function() clear() rmdir(testdir) - lfs.mkdir(testdir) - lfs.mkdir(testdir .. '/spell') + mkdir(testdir) + mkdir(testdir .. '/spell') end) after_each(function() rmdir(testdir) diff --git a/test/functional/ex_cmds/cd_spec.lua b/test/functional/ex_cmds/cd_spec.lua index 5ed71651c7..b6a3713158 100644 --- a/test/functional/ex_cmds/cd_spec.lua +++ b/test/functional/ex_cmds/cd_spec.lua @@ -1,6 +1,6 @@ -- Specs for :cd, :tcd, :lcd and getcwd() -local lfs = require('lfs') +local luv = require('luv') local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq @@ -11,6 +11,7 @@ local exc_exec = helpers.exc_exec local pathsep = helpers.get_pathsep() local skip = helpers.skip local is_os = helpers.is_os +local mkdir = helpers.mkdir -- These directories will be created for testing local directories = { @@ -36,14 +37,14 @@ for _, cmd in ipairs {'cd', 'chdir'} do before_each(function() clear() for _, d in pairs(directories) do - lfs.mkdir(d) + mkdir(d) end directories.start = cwd() end) after_each(function() for _, d in pairs(directories) do - lfs.rmdir(d) + luv.fs_rmdir(d) end end) @@ -273,7 +274,7 @@ end describe("getcwd()", function () before_each(function() clear() - lfs.mkdir(directories.global) + mkdir(directories.global) end) after_each(function() diff --git a/test/functional/ex_cmds/file_spec.lua b/test/functional/ex_cmds/file_spec.lua index 771c283134..131661828e 100644 --- a/test/functional/ex_cmds/file_spec.lua +++ b/test/functional/ex_cmds/file_spec.lua @@ -1,17 +1,18 @@ local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') +local luv = require('luv') local clear = helpers.clear local command = helpers.command local eq = helpers.eq local funcs = helpers.funcs local rmdir = helpers.rmdir +local mkdir = helpers.mkdir describe(':file', function() - local swapdir = lfs.currentdir()..'/Xtest-file_spec' + local swapdir = luv.cwd()..'/Xtest-file_spec' before_each(function() clear() rmdir(swapdir) - lfs.mkdir(swapdir) + mkdir(swapdir) end) after_each(function() command('%bwipeout!') diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua index 0a1cdd93aa..d70ccb5b39 100644 --- a/test/functional/ex_cmds/mksession_spec.lua +++ b/test/functional/ex_cmds/mksession_spec.lua @@ -1,4 +1,3 @@ -local lfs = require('lfs') local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') @@ -15,6 +14,7 @@ local sleep = helpers.sleep local meths = helpers.meths local skip = helpers.skip local is_os = helpers.is_os +local mkdir = helpers.mkdir local file_prefix = 'Xtest-functional-ex_cmds-mksession_spec' @@ -26,7 +26,7 @@ describe(':mksession', function() before_each(function() clear() - lfs.mkdir(tab_dir) + mkdir(tab_dir) end) after_each(function() diff --git a/test/functional/ex_cmds/mkview_spec.lua b/test/functional/ex_cmds/mkview_spec.lua index fef8065b2e..f71b826210 100644 --- a/test/functional/ex_cmds/mkview_spec.lua +++ b/test/functional/ex_cmds/mkview_spec.lua @@ -1,4 +1,3 @@ -local lfs = require('lfs') local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear @@ -7,6 +6,7 @@ local get_pathsep = helpers.get_pathsep local eq = helpers.eq local funcs = helpers.funcs local rmdir = helpers.rmdir +local mkdir = helpers.mkdir local file_prefix = 'Xtest-functional-ex_cmds-mkview_spec' @@ -17,8 +17,8 @@ describe(':mkview', function() before_each(function() clear() - lfs.mkdir(view_dir) - lfs.mkdir(local_dir) + mkdir(view_dir) + mkdir(local_dir) end) after_each(function() diff --git a/test/functional/ex_cmds/profile_spec.lua b/test/functional/ex_cmds/profile_spec.lua index bf045a4d1d..249373a9c4 100644 --- a/test/functional/ex_cmds/profile_spec.lua +++ b/test/functional/ex_cmds/profile_spec.lua @@ -1,5 +1,5 @@ require('os') -local lfs = require('lfs') +local luv = require('luv') local helpers = require('test.functional.helpers')(after_each) local eval = helpers.eval @@ -12,18 +12,16 @@ local read_file = helpers.read_file -- tmpname() also creates the file on POSIX systems. Remove it again. -- We just need the name, ignoring any race conditions. -if lfs.attributes(tempfile, 'uid') then +if luv.fs_stat(tempfile).uid then os.remove(tempfile) end local function assert_file_exists(filepath) - -- Use 2-argument lfs.attributes() so no extra table gets created. - -- We don't really care for the uid. - neq(nil, lfs.attributes(filepath, 'uid')) + neq(nil, luv.fs_stat(filepath).uid) end local function assert_file_exists_not(filepath) - eq(nil, lfs.attributes(filepath, 'uid')) + eq(nil, luv.fs_stat(filepath)) end describe(':profile', function() @@ -31,7 +29,7 @@ describe(':profile', function() after_each(function() helpers.expect_exit(command, 'qall!') - if lfs.attributes(tempfile, 'uid') ~= nil then + if luv.fs_stat(tempfile).uid ~= nil then os.remove(tempfile) end end) diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua index ad59025d47..639bc6c94e 100644 --- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua +++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua @@ -1,6 +1,5 @@ local Screen = require('test.functional.ui.screen') local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') local luv = require('luv') local eq, eval, expect, exec = helpers.eq, helpers.eval, helpers.expect, helpers.exec @@ -21,6 +20,7 @@ local spawn = helpers.spawn local nvim_async = helpers.nvim_async local expect_msg_seq = helpers.expect_msg_seq local pcall_err = helpers.pcall_err +local mkdir = helpers.mkdir describe(':recover', function() before_each(clear) @@ -39,7 +39,7 @@ describe(':recover', function() end) describe("preserve and (R)ecover with custom 'directory'", function() - local swapdir = lfs.currentdir()..'/Xtest_recover_dir' + local swapdir = luv.cwd()..'/Xtest_recover_dir' local testfile = 'Xtest_recover_file1' -- Put swapdir at the start of the 'directory' list. #1836 -- Note: `set swapfile` *must* go after `set directory`: otherwise it may @@ -54,7 +54,7 @@ describe("preserve and (R)ecover with custom 'directory'", function() nvim1 = spawn(new_argv()) set_session(nvim1) rmdir(swapdir) - lfs.mkdir(swapdir) + mkdir(swapdir) end) after_each(function() command('%bwipeout!') @@ -126,7 +126,7 @@ describe("preserve and (R)ecover with custom 'directory'", function() end) describe('swapfile detection', function() - local swapdir = lfs.currentdir()..'/Xtest_swapdialog_dir' + local swapdir = luv.cwd()..'/Xtest_swapdialog_dir' local nvim0 -- Put swapdir at the start of the 'directory' list. #1836 -- Note: `set swapfile` *must* go after `set directory`: otherwise it may @@ -139,7 +139,7 @@ describe('swapfile detection', function() nvim0 = spawn(new_argv()) set_session(nvim0) rmdir(swapdir) - lfs.mkdir(swapdir) + mkdir(swapdir) end) after_each(function() set_session(nvim0) @@ -361,7 +361,8 @@ describe('swapfile detection', function() ]]) -- pretend that the swapfile was created before boot - lfs.touch(swname, os.time() - luv.uptime() - 10) + local atime = os.time() - luv.uptime() - 10 + luv.fs_utime(swname, atime, atime) feed(':edit Xswaptest') screen:expect({any = table.concat({ diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua index 1ccd27875e..126646f21a 100644 --- a/test/functional/ex_cmds/write_spec.lua +++ b/test/functional/ex_cmds/write_spec.lua @@ -1,5 +1,5 @@ local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') +local luv = require('luv') local eq, eval, clear, write_file, source, insert = helpers.eq, helpers.eval, helpers.clear, helpers.write_file, helpers.source, helpers.insert @@ -153,7 +153,7 @@ describe(':write', function() end write_file(fname_bak, 'TTYX') skip(is_os('win'), [[FIXME: exc_exec('write!') outputs 0 in Windows]]) - lfs.link(fname_bak .. ('/xxxxx'):rep(20), fname, true) + luv.fs_symlink(fname_bak .. ('/xxxxx'):rep(20), fname) eq('Vim(write):E166: Can\'t open linked file for writing', pcall_err(command, 'write!')) end) diff --git a/test/functional/ex_cmds/wviminfo_spec.lua b/test/functional/ex_cmds/wviminfo_spec.lua index 861a977ea6..7525343891 100644 --- a/test/functional/ex_cmds/wviminfo_spec.lua +++ b/test/functional/ex_cmds/wviminfo_spec.lua @@ -1,5 +1,5 @@ local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') +local luv = require('luv') local clear = helpers.clear local command, eq, neq, write_file = helpers.command, helpers.eq, helpers.neq, helpers.write_file @@ -21,10 +21,10 @@ describe(':wshada', function() it('creates a shada file', function() -- file should _not_ exist - eq(nil, lfs.attributes(shada_file)) + eq(nil, luv.fs_stat(shada_file)) command('wsh! '..shada_file) -- file _should_ exist - neq(nil, lfs.attributes(shada_file)) + neq(nil, luv.fs_stat(shada_file)) end) it('overwrites existing files', function() @@ -35,7 +35,7 @@ describe(':wshada', function() -- sanity check eq(text, read_file(shada_file)) - neq(nil, lfs.attributes(shada_file)) + neq(nil, luv.fs_stat(shada_file)) command('wsh! '..shada_file) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 188c196eb3..2e373467d0 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -1,5 +1,4 @@ local luv = require('luv') -local lfs = require('lfs') local global_helpers = require('test.helpers') local Session = require('test.client.session') @@ -20,10 +19,9 @@ local tbl_contains = global_helpers.tbl_contains local fail = global_helpers.fail local module = { - mkdir = lfs.mkdir, } -local start_dir = lfs.currentdir() +local start_dir = luv.cwd() local runtime_set = 'set runtimepath^=./build/lib/nvim/' module.nvim_prog = ( os.getenv('NVIM_PRG') @@ -730,21 +728,17 @@ function module.assert_visible(bufnr, visible) end local function do_rmdir(path) - local mode, errmsg, errcode = lfs.attributes(path, 'mode') - if mode == nil then - if errcode == 2 then - -- "No such file or directory", don't complain. - return - end - error(string.format('rmdir: %s (%d)', errmsg, errcode)) + local stat = luv.fs_stat(path) + if stat == nil then + return end - if mode ~= 'directory' then + if stat.type ~= 'directory' then error(string.format('rmdir: not a directory: %s', path)) end - for file in lfs.dir(path) do + for file in vim.fs.dir(path) do if file ~= '.' and file ~= '..' then local abspath = path..'/'..file - if lfs.attributes(abspath, 'mode') == 'directory' then + if global_helpers.isdir(abspath) then do_rmdir(abspath) -- recurse else local ret, err = os.remove(abspath) @@ -764,9 +758,9 @@ local function do_rmdir(path) end end end - local ret, err = lfs.rmdir(path) + local ret, err = luv.fs_rmdir(path) if not ret then - error('lfs.rmdir('..path..'): '..err) + error('luv.fs_rmdir('..path..'): '..err) end end diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua index 7ae851467f..5b6d030567 100644 --- a/test/functional/legacy/011_autocommands_spec.lua +++ b/test/functional/legacy/011_autocommands_spec.lua @@ -13,7 +13,7 @@ -- being modified outside of Vim (noticed on Solaris). local helpers= require('test.functional.helpers')(after_each) -local lfs = require('lfs') +local luv = require('luv') local clear, feed_command, expect, eq, neq, dedent, write_file, feed = helpers.clear, helpers.feed_command, helpers.expect, helpers.eq, helpers.neq, helpers.dedent, helpers.write_file, helpers.feed @@ -31,8 +31,8 @@ local function prepare_gz_file(name, text) -- Compress the file with gzip. command([[call system(['gzip', '--force', ']]..name..[['])]]) -- This should create the .gz file and delete the original. - neq(nil, lfs.attributes(name..'.gz')) - eq(nil, lfs.attributes(name)) + neq(nil, luv.fs_stat(name..'.gz')) + eq(nil, luv.fs_stat(name)) end describe('file reading, writing and bufnew and filter autocommands', function() diff --git a/test/functional/legacy/012_directory_spec.lua b/test/functional/legacy/012_directory_spec.lua index dd207ca0b4..050e3855fe 100644 --- a/test/functional/legacy/012_directory_spec.lua +++ b/test/functional/legacy/012_directory_spec.lua @@ -4,7 +4,7 @@ -- - "dir", in directory relative to current dir local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') +local luv = require('luv') local eq = helpers.eq local neq = helpers.neq @@ -17,10 +17,11 @@ local command = helpers.command local write_file = helpers.write_file local curbufmeths = helpers.curbufmeths local expect_exit = helpers.expect_exit +local mkdir = helpers.mkdir local function ls_dir_sorted(dirname) local files = {} - for f in lfs.dir(dirname) do + for f in vim.fs.dir(dirname) do if f ~= "." and f~= ".." then table.insert(files, f) end @@ -38,8 +39,8 @@ describe("'directory' option", function() end of testfile ]] write_file('Xtest1', text) - lfs.mkdir('Xtest.je') - lfs.mkdir('Xtest2') + mkdir('Xtest.je') + mkdir('Xtest2') write_file('Xtest2/Xtest3', text) clear() end) @@ -62,21 +63,21 @@ describe("'directory' option", function() meths.set_option('directory', '.') -- sanity check: files should not exist yet. - eq(nil, lfs.attributes('.Xtest1.swp')) + eq(nil, luv.fs_stat('.Xtest1.swp')) command('edit! Xtest1') poke_eventloop() eq('Xtest1', funcs.buffer_name('%')) -- Verify that the swapfile exists. In the legacy test this was done by -- reading the output from :!ls. - neq(nil, lfs.attributes('.Xtest1.swp')) + neq(nil, luv.fs_stat('.Xtest1.swp')) meths.set_option('directory', './Xtest2,.') command('edit Xtest1') poke_eventloop() -- swapfile should no longer exist in CWD. - eq(nil, lfs.attributes('.Xtest1.swp')) + eq(nil, luv.fs_stat('.Xtest1.swp')) eq({ "Xtest1.swp", "Xtest3" }, ls_dir_sorted("Xtest2")) diff --git a/test/functional/legacy/074_global_var_in_viminfo_spec.lua b/test/functional/legacy/074_global_var_in_viminfo_spec.lua index 445d742c1f..06d8b276d7 100644 --- a/test/functional/legacy/074_global_var_in_viminfo_spec.lua +++ b/test/functional/legacy/074_global_var_in_viminfo_spec.lua @@ -1,7 +1,7 @@ -- Tests for storing global variables in the .shada file local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') +local luv = require('luv') local clear, command, eq, neq, eval, poke_eventloop = helpers.clear, helpers.command, helpers.eq, helpers.neq, helpers.eval, helpers.poke_eventloop @@ -39,7 +39,7 @@ describe('storing global variables in ShaDa files', function() poke_eventloop() -- Assert that the shada file exists. - neq(nil, lfs.attributes(tempname)) + neq(nil, luv.fs_stat(tempname)) command('unlet MY_GLOBAL_DICT') command('unlet MY_GLOBAL_LIST') -- Assert that the variables where deleted. diff --git a/test/functional/legacy/autochdir_spec.lua b/test/functional/legacy/autochdir_spec.lua index 13cb6cd287..5da54b4850 100644 --- a/test/functional/legacy/autochdir_spec.lua +++ b/test/functional/legacy/autochdir_spec.lua @@ -1,8 +1,8 @@ -local lfs = require('lfs') local helpers = require('test.functional.helpers')(after_each) local clear, eq, matches = helpers.clear, helpers.eq, helpers.matches local eval, command, call, meths = helpers.eval, helpers.command, helpers.call, helpers.meths local source, exec_capture = helpers.source, helpers.exec_capture +local mkdir = helpers.mkdir local function expected_empty() eq({}, meths.get_vvar('errors')) @@ -12,7 +12,7 @@ describe('autochdir behavior', function() local dir = 'Xtest_functional_legacy_autochdir' before_each(function() - lfs.mkdir(dir) + mkdir(dir) clear() command('set shellslash') end) 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( [[ diff --git a/test/functional/options/autochdir_spec.lua b/test/functional/options/autochdir_spec.lua index 0b6fe9533c..c75a98f35b 100644 --- a/test/functional/options/autochdir_spec.lua +++ b/test/functional/options/autochdir_spec.lua @@ -1,9 +1,10 @@ -local lfs = require('lfs') +local luv = require('luv') local helpers = require('test.functional.helpers')(after_each) local clear = helpers.clear local eq = helpers.eq local funcs = helpers.funcs local command = helpers.command +local mkdir = helpers.mkdir describe("'autochdir'", function() it('given on the shell gets processed properly', function() @@ -20,11 +21,11 @@ describe("'autochdir'", function() end) it('is not overwritten by getwinvar() call #17609',function() - local curdir = string.gsub(lfs.currentdir(), '\\', '/') + local curdir = string.gsub(luv.cwd(), '\\', '/') local dir_a = curdir..'/Xtest-functional-options-autochdir.dir_a' local dir_b = curdir..'/Xtest-functional-options-autochdir.dir_b' - lfs.mkdir(dir_a) - lfs.mkdir(dir_b) + mkdir(dir_a) + mkdir(dir_b) clear() command('set shellslash') command('set autochdir') diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 7d287d38fa..da05b09593 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -1,6 +1,5 @@ local helpers = require('test.functional.helpers')(after_each) local lsp_helpers = require('test.functional.plugin.lsp.helpers') -local lfs = require('lfs') local assert_log = helpers.assert_log local buf_lines = helpers.buf_lines @@ -24,6 +23,7 @@ local is_ci = helpers.is_ci local meths = helpers.meths local is_os = helpers.is_os local skip = helpers.skip +local mkdir = helpers.mkdir local clear_notrace = lsp_helpers.clear_notrace local create_server_definition = lsp_helpers.create_server_definition @@ -3768,7 +3768,7 @@ describe('LSP', function() it('sends notifications when files change', function() local root_dir = helpers.tmpname() os.remove(root_dir) - lfs.mkdir(root_dir) + mkdir(root_dir) exec_lua(create_server_definition) local result = exec_lua([[ diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua index 24bd363e95..cc21d08620 100644 --- a/test/functional/shada/shada_spec.lua +++ b/test/functional/shada/shada_spec.lua @@ -8,7 +8,7 @@ local write_file, spawn, set_session, nvim_prog, exc_exec = local is_os = helpers.is_os local skip = helpers.skip -local lfs = require('lfs') +local luv = require('luv') local paths = require('test.cmakeconfig.paths') local mpack = require('mpack') @@ -29,7 +29,7 @@ describe('ShaDa support code', function() after_each(function() clear() clean() - lfs.rmdir(dirname) + luv.fs_rmdir(dirname) end) it('preserves `s` item size limit with unknown entries', function() @@ -81,7 +81,7 @@ describe('ShaDa support code', function() wshada('Some text file') eq(0, exc_exec('wshada! ' .. shada_fname)) eq(1, read_shada_file(shada_fname)[1].type) - eq(nil, lfs.attributes(shada_fname .. '.tmp.a')) + eq(nil, luv.fs_stat(shada_fname .. '.tmp.a')) end) it('leaves .tmp.b in-place when there is error in original ShaDa and it has .tmp.a', function() @@ -251,8 +251,8 @@ describe('ShaDa support code', function() local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', '--headless', '--cmd', 'qall'}, true) session:close() - eq(nil, lfs.attributes('NONE')) - eq(nil, lfs.attributes('NONE.tmp.a')) + eq(nil, luv.fs_stat('NONE')) + eq(nil, luv.fs_stat('NONE.tmp.a')) end) it('does not read NONE file', function() diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua index c032ac3030..dc591c3e0d 100644 --- a/test/functional/vimscript/api_functions_spec.lua +++ b/test/functional/vimscript/api_functions_spec.lua @@ -1,6 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local lfs = require('lfs') +local luv = require('luv') local neq, eq, command = helpers.neq, helpers.eq, helpers.command local clear, curbufmeths = helpers.clear, helpers.curbufmeths local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval @@ -118,7 +118,7 @@ describe('eval-API', function() end) it('are highlighted by vim.vim syntax file', function() - if lfs.attributes("build/runtime/syntax/vim/generated.vim",'uid') == nil then + if luv.fs_stat("build/runtime/syntax/vim/generated.vim").uid == nil then pending("runtime was not built, skipping test") return end diff --git a/test/functional/vimscript/buf_functions_spec.lua b/test/functional/vimscript/buf_functions_spec.lua index b521620320..7a54f479e0 100644 --- a/test/functional/vimscript/buf_functions_spec.lua +++ b/test/functional/vimscript/buf_functions_spec.lua @@ -1,6 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') +local luv = require('luv') local eq = helpers.eq local clear = helpers.clear @@ -16,6 +16,7 @@ local curtabmeths = helpers.curtabmeths local get_pathsep = helpers.get_pathsep local rmdir = helpers.rmdir local pcall_err = helpers.pcall_err +local mkdir = helpers.mkdir local fname = 'Xtest-functional-eval-buf_functions' local fname2 = fname .. '.2' @@ -62,7 +63,7 @@ describe('bufname() function', function() eq('', funcs.bufname('X')) end) before_each(function() - lfs.mkdir(dirname) + mkdir(dirname) end) after_each(function() rmdir(dirname) @@ -70,7 +71,7 @@ describe('bufname() function', function() it('returns expected buffer name', function() eq('', funcs.bufname('%')) -- Buffer has no name yet command('file ' .. fname) - local wd = lfs.currentdir() + local wd = luv.cwd() local sep = get_pathsep() local curdirname = funcs.fnamemodify(wd, ':t') for _, arg in ipairs({'%', 1, 'X', wd}) do @@ -103,7 +104,7 @@ describe('bufnr() function', function() it('returns expected buffer number', function() eq(1, funcs.bufnr('%')) command('file ' .. fname) - local wd = lfs.currentdir() + local wd = luv.cwd() local curdirname = funcs.fnamemodify(wd, ':t') eq(1, funcs.bufnr(fname)) eq(1, funcs.bufnr(wd)) @@ -144,7 +145,7 @@ describe('bufwinnr() function', function() eq(-1, funcs.bufwinnr('X')) end) before_each(function() - lfs.mkdir(dirname) + mkdir(dirname) end) after_each(function() rmdir(dirname) diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua index a8a901042b..b995aaa5a6 100644 --- a/test/functional/vimscript/eval_spec.lua +++ b/test/functional/vimscript/eval_spec.lua @@ -12,7 +12,7 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') -local lfs = require('lfs') +local mkdir = helpers.mkdir local clear = helpers.clear local eq = helpers.eq local exc_exec = helpers.exc_exec @@ -56,11 +56,11 @@ end) describe("backtick expansion", function() setup(function() clear() - lfs.mkdir("test-backticks") + mkdir("test-backticks") write_file("test-backticks/file1", "test file 1") write_file("test-backticks/file2", "test file 2") write_file("test-backticks/file3", "test file 3") - lfs.mkdir("test-backticks/subdir") + mkdir("test-backticks/subdir") write_file("test-backticks/subdir/file4", "test file 4") -- Long path might cause "Press ENTER" prompt; use :silent to avoid it. command('silent cd test-backticks') diff --git a/test/functional/vimscript/glob_spec.lua b/test/functional/vimscript/glob_spec.lua index b8807ecfcc..948a63f050 100644 --- a/test/functional/vimscript/glob_spec.lua +++ b/test/functional/vimscript/glob_spec.lua @@ -1,17 +1,18 @@ -local lfs = require('lfs') +local luv = require('luv') local helpers = require('test.functional.helpers')(after_each) local clear, command, eval, eq = helpers.clear, helpers.command, helpers.eval, helpers.eq +local mkdir = helpers.mkdir before_each(function() clear() - lfs.mkdir('test-glob') + mkdir('test-glob') -- Long path might cause "Press ENTER" prompt; use :silent to avoid it. command('silent cd test-glob') end) after_each(function() - lfs.rmdir('test-glob') + luv.fs_rmdir('test-glob') end) describe('glob()', function() diff --git a/test/functional/vimscript/writefile_spec.lua b/test/functional/vimscript/writefile_spec.lua index 8c8da9dc88..c816efd37b 100644 --- a/test/functional/vimscript/writefile_spec.lua +++ b/test/functional/vimscript/writefile_spec.lua @@ -1,6 +1,7 @@ local helpers = require('test.functional.helpers')(after_each) -local lfs = require('lfs') +local luv = require('luv') +local mkdir = helpers.mkdir local clear = helpers.clear local eq = helpers.eq local funcs = helpers.funcs @@ -19,16 +20,16 @@ local ddname_tail = '2' local ddname = dname .. '/' .. ddname_tail before_each(function() - lfs.mkdir(dname) - lfs.mkdir(ddname) + mkdir(dname) + mkdir(ddname) clear() end) after_each(function() os.remove(fname) os.remove(dfname) - lfs.rmdir(ddname) - lfs.rmdir(dname) + luv.fs_rmdir(ddname) + luv.fs_rmdir(dname) end) describe('writefile()', function() -- cgit From f0ac91c58b42ed4f38dea7352d89fd39a88142f4 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Sat, 1 Apr 2023 14:58:52 +0200 Subject: feat(api): evaluate 'statuscolumn' with nvim_eval_statusline() --- test/functional/api/vim_spec.lua | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index ab26425425..cddea48a76 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3421,6 +3421,40 @@ describe('API', function() 'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight', { use_winbar = true, highlights = true })) end) + it('works with statuscolumn', function() + command([[ + let &stc='%C%s%=%l ' + set cul nu nuw=3 scl=yes:2 fdc=2 + call setline(1, repeat(['aaaaa'], 5)) + let g:ns = nvim_create_namespace('') + call sign_define('a', {'text':'aa', 'texthl':'IncSearch', 'numhl':'Normal'}) + call sign_place(2, 1, 'a', bufnr(), {'lnum':4}) + call nvim_buf_set_extmark(0, g:ns, 3, 1, { 'sign_text':'bb', 'sign_hl_group':'ErrorMsg' }) + 1,5fold | 1,5 fold | foldopen! + ]]) + command('norm 4G') + command('let v:lnum=4') + eq({ + str = '││aabb 4 ', + width = 9, + highlights = { + { group = 'CursorLineFold', start = 0 }, + { group = 'Normal', start = 6 }, + { group = 'IncSearch', start = 6 }, + { group = 'ErrorMsg', start = 8 }, + { group = 'Normal', start = 10 } + } + }, meths.eval_statusline('%C%s%=%l ', { use_statuscol = true, highlights = true })) + command('let v:lnum=3') + eq({ + str = '3 ' , + width = 2, + highlights = { + { group = 'LineNr', start = 0 }, + { group = 'ErrorMsg', start = 1 } + } + }, meths.eval_statusline('%l%#ErrorMsg# ', { use_statuscol = true, highlights = true })) + end) it('no memory leak with click functions', function() meths.eval_statusline('%@ClickFunc@StatusLineStringWithClickFunc%T', {}) eq({ -- 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 +++++++++++------------ test/functional/terminal/scrollback_spec.lua | 19 +++++----- test/functional/ui/decorations_spec.lua | 52 ++++++++++++++-------------- test/functional/ui/float_spec.lua | 12 +++---- 4 files changed, 63 insertions(+), 64 deletions(-) (limited to 'test/functional') 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 [[ diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index 00a35a5c6c..5d967e0340 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -575,12 +575,12 @@ describe("pending scrollback line handling", function() it("does not crash after setting 'number' #14891", function() exec_lua [[ - local a = vim.api - local buf = a.nvim_create_buf(true, true) - local chan = a.nvim_open_term(buf, {}) - a.nvim_win_set_option(0, "number", true) - a.nvim_chan_send(chan, ("a\n"):rep(11) .. "a") - a.nvim_win_set_buf(0, buf) + local api = vim.api + local buf = api.nvim_create_buf(true, true) + local chan = api.nvim_open_term(buf, {}) + api.nvim_win_set_option(0, "number", true) + api.nvim_chan_send(chan, ("a\n"):rep(11) .. "a") + api.nvim_win_set_buf(0, buf) ]] screen:expect [[ {1: 1 }^a | @@ -607,12 +607,11 @@ describe("pending scrollback line handling", function() it("does not crash after nvim_buf_call #14891", function() skip(is_os('win')) exec_lua [[ - local a = vim.api - local bufnr = a.nvim_create_buf(false, true) - a.nvim_buf_call(bufnr, function() + local bufnr = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_call(bufnr, function() vim.fn.termopen({"echo", ("hi\n"):rep(11)}) end) - a.nvim_win_set_buf(0, bufnr) + vim.api.nvim_win_set_buf(0, bufnr) vim.cmd("startinsert") ]] screen:expect [[ diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index d03d2f1374..80e5b6230e 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -47,15 +47,15 @@ describe('decorations providers', function() local function setup_provider(code) return exec_lua ([[ - local a = vim.api - _G.ns1 = a.nvim_create_namespace "ns1" + local api = vim.api + _G.ns1 = api.nvim_create_namespace "ns1" ]] .. (code or [[ beamtrace = {} local function on_do(kind, ...) table.insert(beamtrace, {kind, ...}) end ]]) .. [[ - a.nvim_set_decoration_provider(_G.ns1, { + api.nvim_set_decoration_provider(_G.ns1, { on_start = on_do; on_buf = on_do; on_win = on_do; on_line = on_do; on_end = on_do; _on_spell_nav = on_do; @@ -75,8 +75,8 @@ describe('decorations providers', function() -- rather than append, which used to spin in an infinite loop allocating -- memory until nvim crashed/was killed. setup_provider([[ - local ns2 = a.nvim_create_namespace "ns2" - a.nvim_set_decoration_provider(ns2, {}) + local ns2 = api.nvim_create_namespace "ns2" + api.nvim_set_decoration_provider(ns2, {}) ]]) helpers.assert_alive() end) @@ -132,12 +132,12 @@ describe('decorations providers', function() it('can have single provider', function() insert(mulholland) setup_provider [[ - local hl = a.nvim_get_hl_id_by_name "ErrorMsg" - local test_ns = a.nvim_create_namespace "mulholland" + local hl = api.nvim_get_hl_id_by_name "ErrorMsg" + local test_ns = api.nvim_create_namespace "mulholland" function on_do(event, ...) if event == "line" then local win, buf, line = ... - a.nvim_buf_set_extmark(buf, test_ns, line, line, + api.nvim_buf_set_extmark(buf, test_ns, line, line, { end_line = line, end_col = line+1, hl_group = hl, ephemeral = true @@ -172,11 +172,11 @@ describe('decorations providers', function() ]] setup_provider [[ - local ns = a.nvim_create_namespace "spell" + local ns = api.nvim_create_namespace "spell" beamtrace = {} local function on_do(kind, ...) if kind == 'win' or kind == 'spell' then - a.nvim_buf_set_extmark(0, ns, 0, 0, { + api.nvim_buf_set_extmark(0, ns, 0, 0, { end_row = 2, end_col = 23, spell = true, @@ -330,12 +330,12 @@ describe('decorations providers', function() ]]} exec_lua [[ - local a = vim.api - local thewin = a.nvim_get_current_win() - local ns2 = a.nvim_create_namespace 'ns2' - a.nvim_set_decoration_provider (ns2, { + local api = vim.api + local thewin = api.nvim_get_current_win() + local ns2 = api.nvim_create_namespace 'ns2' + api.nvim_set_decoration_provider (ns2, { on_win = function (_, win, buf) - a.nvim_set_hl_ns_fast(win == thewin and _G.ns1 or ns2) + api.nvim_set_hl_ns_fast(win == thewin and _G.ns1 or ns2) end; }) ]] @@ -436,12 +436,12 @@ describe('decorations providers', function() it('can have virtual text', function() insert(mulholland) setup_provider [[ - local hl = a.nvim_get_hl_id_by_name "ErrorMsg" - local test_ns = a.nvim_create_namespace "mulholland" + local hl = api.nvim_get_hl_id_by_name "ErrorMsg" + local test_ns = api.nvim_create_namespace "mulholland" function on_do(event, ...) if event == "line" then local win, buf, line = ... - a.nvim_buf_set_extmark(buf, test_ns, line, 0, { + api.nvim_buf_set_extmark(buf, test_ns, line, 0, { virt_text = {{'+', 'ErrorMsg'}}; virt_text_pos='overlay'; ephemeral = true; @@ -465,12 +465,12 @@ describe('decorations providers', function() it('can have virtual text of the style: right_align', function() insert(mulholland) setup_provider [[ - local hl = a.nvim_get_hl_id_by_name "ErrorMsg" - local test_ns = a.nvim_create_namespace "mulholland" + local hl = api.nvim_get_hl_id_by_name "ErrorMsg" + local test_ns = api.nvim_create_namespace "mulholland" function on_do(event, ...) if event == "line" then local win, buf, line = ... - a.nvim_buf_set_extmark(buf, test_ns, line, 0, { + api.nvim_buf_set_extmark(buf, test_ns, line, 0, { virt_text = {{'+'}, {string.rep(' ', line+1), 'ErrorMsg'}}; virt_text_pos='right_align'; ephemeral = true; @@ -494,12 +494,12 @@ describe('decorations providers', function() it('can highlight beyond EOL', function() insert(mulholland) setup_provider [[ - local test_ns = a.nvim_create_namespace "veberod" + local test_ns = api.nvim_create_namespace "veberod" function on_do(event, ...) if event == "line" then local win, buf, line = ... - if string.find(a.nvim_buf_get_lines(buf, line, line+1, true)[1], "buf") then - a.nvim_buf_set_extmark(buf, test_ns, line, 0, { + if string.find(api.nvim_buf_get_lines(buf, line, line+1, true)[1], "buf") then + api.nvim_buf_set_extmark(buf, test_ns, line, 0, { end_line = line+1; hl_group = 'DiffAdd'; hl_eol = true; @@ -534,9 +534,9 @@ describe('decorations providers', function() local function on_do(kind, winid, bufnr, topline, botline_guess) if kind == 'win' then if topline < 100 and botline_guess > 100 then - vim.api.nvim_buf_set_extmark(bufnr, ns1, 99, -1, { sign_text = 'X' }) + api.nvim_buf_set_extmark(bufnr, ns1, 99, -1, { sign_text = 'X' }) else - vim.api.nvim_buf_clear_namespace(bufnr, ns1, 0, -1) + api.nvim_buf_clear_namespace(bufnr, ns1, 0, -1) end end end diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 32f28dce26..4612ffe56f 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -65,20 +65,20 @@ describe('float window', function() it('closed immediately by autocmd #11383', function() eq('Window was closed immediately', pcall_err(exec_lua, [[ - local a = vim.api + local api = vim.api local function crashes(contents) - local buf = a.nvim_create_buf(false, true) - local floatwin = a.nvim_open_win(buf, true, { + local buf = api.nvim_create_buf(false, true) + local floatwin = api.nvim_open_win(buf, true, { relative = 'cursor'; style = 'minimal'; row = 0; col = 0; height = #contents; width = 10; }) - a.nvim_buf_set_lines(buf, 0, -1, true, contents) + api.nvim_buf_set_lines(buf, 0, -1, true, contents) local winnr = vim.fn.win_id2win(floatwin) - a.nvim_command('wincmd p') - a.nvim_command('autocmd CursorMoved * ++once '..winnr..'wincmd c') + api.nvim_command('wincmd p') + api.nvim_command('autocmd CursorMoved * ++once '..winnr..'wincmd c') return buf, floatwin end crashes{'foo'} -- 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') 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 e29bc03c046b3a137c2e36b4d34c119b277d62b2 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 6 Apr 2023 15:16:44 +0100 Subject: fix(treesitter): do not track ranges of the root tree (#22912) Fixes #22911 --- test/functional/treesitter/parser_spec.lua | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'test/functional') diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index ea9958b12a..9afce0b3a0 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -948,4 +948,48 @@ int x = INT_MAX; [16] = '1', [17] = '0' }, get_fold_levels()) end) + + it('tracks the root range properly (#22911)', function() + insert([[ + int main() { + int x = 3; + }]]) + + local query0 = [[ + (declaration) @declaration + (function_definition) @function + ]] + + exec_lua([[ + vim.treesitter.start(0, 'c') + ]]) + + local function run_query() + return exec_lua([[ + local query = vim.treesitter.query.parse("c", ...) + parser = vim.treesitter.get_parser() + tree = parser:parse()[1] + res = {} + for id, node in query:iter_captures(tree:root()) do + table.insert(res, {query.captures[id], node:range()}) + end + return res + ]], query0) + end + + eq({ + { 'function', 0, 0, 2, 1 }, + { 'declaration', 1, 2, 1, 12 } + }, run_query()) + + helpers.command'normal ggO' + insert('int a;') + + eq({ + { 'declaration', 0, 0, 0, 6 }, + { 'function', 1, 0, 3, 1 }, + { 'declaration', 2, 2, 2, 12 } + }, run_query()) + + end) end) -- cgit From 0f42aa1f2a860ce6d72a825b397fe09c875613b5 Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 6 Apr 2023 10:03:37 +0200 Subject: fix(highlight): use winhl=Foo:Bar even when Bar is empty fixes #22906 --- test/functional/ui/float_spec.lua | 47 +++++++++++++++++++++++++++++++++++ test/functional/ui/highlight_spec.lua | 17 +++++++++++++ 2 files changed, 64 insertions(+) (limited to 'test/functional') diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 32f28dce26..890678e363 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -4935,6 +4935,53 @@ describe('float window', function() end) end) + it("can use Normal as background", function() + local buf = meths.create_buf(false,false) + meths.buf_set_lines(buf,0,-1,true,{"here", "float"}) + local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5}) + meths.set_option_value('winhl', 'Normal:Normal', {win=win}) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + here | + float | + ]], float_pos={ + [5] = {{id = 1002}, "NW", 1, 2, 5, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2, sum_scroll_delta = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }here {0: }| + {0:~ }float {0: }| + {0:~ }| + {0:~ }| + | + ]]} + end + end) + describe("handles :wincmd", function() local win local expected_pos diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index dce886ac91..fedfaca7ba 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -2432,6 +2432,23 @@ describe("'winhighlight' highlight", function() | ]]} end) + + it('can link to empty highlight group', function() + command 'hi NormalNC guibg=Red' -- czerwone time + command 'set winhl=NormalNC:Normal' + command 'split' + + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {3:[No Name] }| + | + {0:~ }| + {4:[No Name] }| + | + ]]} + end) end) describe('highlight namespaces', function() -- cgit From 824639c7c17c4870cde83dd28fed7ed6be0ed4c9 Mon Sep 17 00:00:00 2001 From: Brandon Simmons <34775764+simmsbra@users.noreply.github.com> Date: Thu, 6 Apr 2023 11:08:46 -0500 Subject: fix(folds): handle visual blockwise indent insertion correctly (#22898) Previously, the fold information was incorrect because it wasn't being updated during the blockwise insertion. (Solution by zeertzjq) --- test/functional/editor/fold_spec.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test/functional') diff --git a/test/functional/editor/fold_spec.lua b/test/functional/editor/fold_spec.lua index 00e83bedc8..01a30f87bf 100644 --- a/test/functional/editor/fold_spec.lua +++ b/test/functional/editor/fold_spec.lua @@ -359,4 +359,14 @@ a]], '13m7') eq(10, funcs.foldclosedend(7)) eq(14, funcs.foldclosedend(11)) end) + it('updates correctly with indent method and visual blockwise insertion', function() + insert([[ + a + b + ]]) + feed_command('set foldmethod=indent', 'set shiftwidth=2') + feed('gg0jI ') -- indent both lines using visual blockwise mode + eq(1, funcs.foldlevel(1)) + eq(1, funcs.foldlevel(2)) + end) end) -- cgit From 25dfed6e0148771cdb659df8c616df3860583c47 Mon Sep 17 00:00:00 2001 From: Luuk van Baal Date: Thu, 6 Apr 2023 03:33:57 +0200 Subject: feat(api): set statuscolumn line number in nvim_eval_statusline() Having the user set `v:lnum` before calling `nvim_eval_statusline()` is unnecesarily fragile. Redraws inbetween setting `v:lnum` and the `nvim_eval_statusline()` call will overwrite `v:lnum`. --- test/functional/api/vim_spec.lua | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'test/functional') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index cddea48a76..af6fbf092a 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3422,7 +3422,7 @@ describe('API', function() { use_winbar = true, highlights = true })) end) it('works with statuscolumn', function() - command([[ + exec([[ let &stc='%C%s%=%l ' set cul nu nuw=3 scl=yes:2 fdc=2 call setline(1, repeat(['aaaaa'], 5)) @@ -3431,9 +3431,8 @@ describe('API', function() call sign_place(2, 1, 'a', bufnr(), {'lnum':4}) call nvim_buf_set_extmark(0, g:ns, 3, 1, { 'sign_text':'bb', 'sign_hl_group':'ErrorMsg' }) 1,5fold | 1,5 fold | foldopen! + norm 4G ]]) - command('norm 4G') - command('let v:lnum=4') eq({ str = '││aabb 4 ', width = 9, @@ -3444,8 +3443,7 @@ describe('API', function() { group = 'ErrorMsg', start = 8 }, { group = 'Normal', start = 10 } } - }, meths.eval_statusline('%C%s%=%l ', { use_statuscol = true, highlights = true })) - command('let v:lnum=3') + }, meths.eval_statusline('%C%s%=%l ', { use_statuscol_lnum = 4, highlights = true })) eq({ str = '3 ' , width = 2, @@ -3453,7 +3451,7 @@ describe('API', function() { group = 'LineNr', start = 0 }, { group = 'ErrorMsg', start = 1 } } - }, meths.eval_statusline('%l%#ErrorMsg# ', { use_statuscol = true, highlights = true })) + }, meths.eval_statusline('%l%#ErrorMsg# ', { use_statuscol_lnum = 3, highlights = true })) end) it('no memory leak with click functions', function() meths.eval_statusline('%@ClickFunc@StatusLineStringWithClickFunc%T', {}) -- cgit From 73060f00dd84b2fcfaed74ba061644975707c225 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 7 Apr 2023 09:29:12 +0800 Subject: test: improve editor/fold_spec.lua and editor/put_spec.lua (#22916) - Close and open a new window each time so that window options have their default values in each test. - Change feed_command() to command() as the latter is faster. --- test/functional/editor/fold_spec.lua | 106 +++++++++++++++++++++++++---------- test/functional/editor/put_spec.lua | 39 +++++++------ test/functional/ui/fold_spec.lua | 26 --------- 3 files changed, 96 insertions(+), 75 deletions(-) (limited to 'test/functional') diff --git a/test/functional/editor/fold_spec.lua b/test/functional/editor/fold_spec.lua index 01a30f87bf..3115c20410 100644 --- a/test/functional/editor/fold_spec.lua +++ b/test/functional/editor/fold_spec.lua @@ -4,17 +4,17 @@ local clear = helpers.clear local insert = helpers.insert local feed = helpers.feed local expect = helpers.expect -local feed_command = helpers.feed_command +local command = helpers.command local funcs = helpers.funcs -local foldlevel = funcs.foldlevel -local foldclosedend = funcs.foldclosedend local eq = helpers.eq describe('Folds', function() local tempfname = 'Xtest-fold.txt' - clear() - before_each(function() feed_command('enew!') end) + + setup(clear) + before_each(function() command('bwipe! | new') end) after_each(function() os.remove(tempfname) end) + it('manual folding adjusts with filter', function() insert([[ 1 @@ -37,8 +37,11 @@ describe('Folds', function() 18 19 20]]) - feed_command('4,$fold', '%foldopen', '10,$fold', '%foldopen') - feed_command('1,8! cat') + command('4,$fold') + command('%foldopen') + command('10,$fold') + command('%foldopen') + command('1,8! cat') feed('5ggzdzMGdd') expect([[ 1 @@ -51,22 +54,24 @@ describe('Folds', function() 8 9]]) end) + describe('adjusting folds after :move', function() local function manually_fold_indent() -- setting foldmethod twice is a trick to get vim to set the folds for me - feed_command('set foldmethod=indent', 'set foldmethod=manual') + command('set foldmethod=indent') + command('set foldmethod=manual') -- Ensure that all folds will get closed (makes it easier to test the -- length of folds). - feed_command('set foldminlines=0') + command('set foldminlines=0') -- Start with all folds open (so :move ranges aren't affected by closed -- folds). - feed_command('%foldopen!') + command('%foldopen!') end local function get_folds() local rettab = {} for i = 1, funcs.line('$') do - table.insert(rettab, foldlevel(i)) + table.insert(rettab, funcs.foldlevel(i)) end return rettab end @@ -75,16 +80,16 @@ describe('Folds', function() -- This test is easy because we just need to ensure that the resulting -- fold is the same as calculated when creating folds from scratch. insert(insert_string) - feed_command(move_command) + command(move_command) local after_move_folds = get_folds() -- Doesn't change anything, but does call foldUpdateAll() - feed_command('set foldminlines=0') + command('set foldminlines=0') eq(after_move_folds, get_folds()) -- Set up the buffer with insert_string for the manual fold testing. - feed_command('enew!') + command('enew!') insert(insert_string) manually_fold_indent() - feed_command(move_command) + command(move_command) end it('neither closes nor corrupts folds', function() @@ -130,19 +135,20 @@ a for i = 1,funcs.line('$') do eq(-1, funcs.foldclosed(i)) if i == 1 or i == 7 or i == 13 then - eq(0, foldlevel(i)) + eq(0, funcs.foldlevel(i)) elseif i == 4 then - eq(2, foldlevel(i)) + eq(2, funcs.foldlevel(i)) else - eq(1, foldlevel(i)) + eq(1, funcs.foldlevel(i)) end end -- folds are not corrupted feed('zM') - eq(6, foldclosedend(2)) - eq(12, foldclosedend(8)) - eq(18, foldclosedend(14)) + eq(6, funcs.foldclosedend(2)) + eq(12, funcs.foldclosedend(8)) + eq(18, funcs.foldclosedend(14)) end) + it("doesn't split a fold when the move is within it", function() test_move_indent([[ a @@ -157,6 +163,7 @@ a a]], '5m6') eq({0, 1, 1, 2, 2, 2, 2, 1, 1, 0}, get_folds()) end) + it('truncates folds that end in the moved range', function() test_move_indent([[ a @@ -168,6 +175,7 @@ a a]], '4,5m6') eq({0, 1, 2, 0, 0, 0, 0}, get_folds()) end) + it('moves folds that start between moved range and destination', function() test_move_indent([[ a @@ -185,6 +193,7 @@ a a]], '3,4m$') eq({0, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1, 0, 0}, get_folds()) end) + it('does not affect folds outside changed lines', function() test_move_indent([[ a @@ -198,6 +207,7 @@ a a]], '4m5') eq({1, 1, 1, 0, 0, 0, 1, 1, 1}, get_folds()) end) + it('moves and truncates folds that start in moved range', function() test_move_indent([[ a @@ -212,6 +222,7 @@ a a]], '1,3m7') eq({0, 0, 0, 0, 0, 1, 2, 0, 0, 0}, get_folds()) end) + it('breaks a fold when moving text into it', function() test_move_indent([[ a @@ -223,6 +234,7 @@ a a]], '$m4') eq({0, 1, 2, 2, 0, 0, 0}, get_folds()) end) + it('adjusts correctly when moving a range backwards', function() test_move_indent([[ a @@ -232,6 +244,7 @@ a a]], '2,3m0') eq({1, 2, 0, 0, 0}, get_folds()) end) + it('handles shifting all remaining folds', function() test_move_indent([[ a @@ -252,6 +265,7 @@ a]], '13m7') eq({1, 2, 2, 2, 1, 2, 2, 1, 1, 1, 2, 2, 2, 1, 0}, get_folds()) end) end) + it('updates correctly on :read', function() -- luacheck: ignore 621 helpers.write_file(tempfname, [[ @@ -265,8 +279,10 @@ a]], '13m7') a a ]]) - feed_command('set foldmethod=indent', '2', '%foldopen') - feed_command('read ' .. tempfname) + command('set foldmethod=indent') + command('2') + command('%foldopen') + command('read ' .. tempfname) -- Just to check we have the correct file text. expect([[ a @@ -288,6 +304,7 @@ a]], '13m7') eq(1, funcs.foldlevel(i)) end end) + it('combines folds when removing separating space', function() -- luacheck: ignore 621 insert([[ @@ -300,9 +317,11 @@ a]], '13m7') a a ]]) - feed_command('set foldmethod=indent', '3,5d') + command('set foldmethod=indent') + command('3,5d') eq(5, funcs.foldclosedend(1)) end) + it("doesn't combine folds that have a specified end", function() insert([[ {{{ @@ -314,9 +333,12 @@ a]], '13m7') }}} ]]) - feed_command('set foldmethod=marker', '3,5d', '%foldclose') + command('set foldmethod=marker') + command('3,5d') + command('%foldclose') eq(2, funcs.foldclosedend(1)) end) + it('splits folds according to >N and jI ') -- indent both lines using visual blockwise mode eq(1, funcs.foldlevel(1)) eq(1, funcs.foldlevel(2)) diff --git a/test/functional/editor/put_spec.lua b/test/functional/editor/put_spec.lua index 5050edff5c..fb55b71e43 100644 --- a/test/functional/editor/put_spec.lua +++ b/test/functional/editor/put_spec.lua @@ -9,22 +9,21 @@ local eq = helpers.eq local map = helpers.tbl_map local filter = helpers.tbl_filter local feed_command = helpers.feed_command +local command = helpers.command local curbuf_contents = helpers.curbuf_contents local funcs = helpers.funcs local dedent = helpers.dedent -local getreg = funcs.getreg local function reset() - feed_command('enew!') + command('bwipe! | new') insert([[ Line of words 1 Line of words 2]]) - feed_command('goto 1') + command('goto 1') feed('itest_string.u') funcs.setreg('a', 'test_stringa', 'V') funcs.setreg('b', 'test_stringb\ntest_stringb\ntest_stringb', 'b') funcs.setreg('"', 'test_string"', 'v') - feed_command('set virtualedit=') end -- We check the last inserted register ". in each of these tests because it is @@ -508,10 +507,10 @@ describe('put command', function() test_expect(exception_table, after_redo) if selection_string then if not conversion_table.put_backwards then - eq(selection_string, getreg('"')) + eq(selection_string, funcs.getreg('"')) end else - eq('test_string"', getreg('"')) + eq('test_string"', funcs.getreg('"')) end end end @@ -644,7 +643,7 @@ describe('put command', function() -- Set curswant to '8' to be at the end of the tab character -- This is where the cursor is put back after the 'u' command. funcs.setpos('.', {0, 2, 1, 0, 8}) - feed_command('set autoindent') + command('set autoindent') end ) end) @@ -655,7 +654,7 @@ describe('put command', function() test_stringx" Line of words 2]] run_normal_mode_tests(test_string, 'p', function() funcs.setline('$', ' Line of words 2') - feed_command('set virtualedit=all') + command('setlocal virtualedit=all') funcs.setpos('.', {0, 2, 1, 2, 3}) end) end) @@ -667,7 +666,7 @@ describe('put command', function() Line of words 2]] run_normal_mode_tests(test_string, 'p', function() funcs.setline('$', ' Line of words 2') - feed_command('set virtualedit=all') + command('setlocal virtualedit=all') funcs.setpos('.', {0, 1, 16, 1, 17}) end, true) end) @@ -717,7 +716,7 @@ describe('put command', function() return function(exception_table, after_redo) test_expect(exception_table, after_redo) if not conversion_table.put_backwards then - eq('Line of words 1\n', getreg('"')) + eq('Line of words 1\n', funcs.getreg('"')) end end end @@ -753,7 +752,7 @@ describe('put command', function() return function(e,c) test_expect(e,c) if not conversion_table.put_backwards then - eq('Lin\nLin', getreg('"')) + eq('Lin\nLin', funcs.getreg('"')) end end end @@ -836,7 +835,7 @@ describe('put command', function() 'vp', function() funcs.setline('$', ' Line of words 2') - feed_command('set virtualedit=all') + command('setlocal virtualedit=all') funcs.setpos('.', {0, 2, 1, 2, 3}) end, nil, @@ -851,7 +850,7 @@ describe('put command', function() base_expect_string, 'vp', function() - feed_command('set virtualedit=all') + command('setlocal virtualedit=all') funcs.setpos('.', {0, 1, 16, 2, 18}) end, true, @@ -920,12 +919,12 @@ describe('put command', function() end) it('should ring the bell when deleting if not appropriate', function() - feed_command('goto 2') - feed('i') - expect([[ - ine of words 1 - Line of words 2]]) - bell_test(function() feed('".P') end, true) + command('goto 2') + feed('i') + expect([[ + ine of words 1 + Line of words 2]]) + bell_test(function() feed('".P') end, true) end) it('should restore cursor position after undo of ".p', function() @@ -935,7 +934,7 @@ describe('put command', function() end) it("should be unaffected by 'autoindent' with V\".2p", function() - feed_command('set autoindent') + command('set autoindent') feed('i test_string.u') feed('V".2p') expect([[ diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 96e28c1978..a99b77f707 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -4,7 +4,6 @@ local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq local command = helpers.command local feed_command = helpers.feed_command local insert = helpers.insert -local expect = helpers.expect local funcs = helpers.funcs local meths = helpers.meths local exec = helpers.exec @@ -2023,29 +2022,4 @@ describe("folded lines", function() describe('without ext_multigrid', function() with_ext_multigrid(false) end) - - it('no folds remains if :delete makes buffer empty #19671', function() - funcs.setline(1, {'foo', 'bar', 'baz'}) - command('2,3fold') - command('%delete') - eq(0, funcs.foldlevel(1)) - end) - - it('multibyte fold markers work #20438', function() - exec([[ - setlocal foldmethod=marker - setlocal foldmarker=«,» - setlocal commentstring=/*%s*/ - ]]) - insert([[ - bbbbb - bbbbb - bbbbb]]) - feed('zfgg') - expect([[ - bbbbb/*«*/ - bbbbb - bbbbb/*»*/]]) - eq(1, funcs.foldlevel(1)) - end) end) -- 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') 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 040f1459849ab05b04f6bb1e77b3def16b4c2f2b Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 7 Apr 2023 13:26:29 +0200 Subject: NVIM v0.9.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For a summary of notable changes, see runtime/doc/news.txt or run `:help news` within nvim. BREAKING CHANGES - Remove hardcopy - Make iconv a non-optional dep - Remove has("debug") (#22060) - Make libintl a required dependency - Rename vim.pretty_print => vim.print - Rename sanitizer options from CLANG_* to ENABLE_* - Remove the .deb release (#22773) - **column**: Ensure 'statuscolumn' works with virtual and wrapped lines - **cscope**: Remove - **defaults**: Change default 'commentstring' value to empty (#22862) - **edit**: Remove old c implementation of hebrew keymap - **editorconfig**: Change editorconfig_enable to editorconfig - **exepath**: Prefers extensionless for powershell - **health**: Remove deprecated health.lua - **lsp**: Add rule-based sem token highlighting (#22022) - **lua**: Execute Lua with "nvim -l" - **messages**: Graduate the 'msgsep' feature - **options**: Deprecate paste, remove pastetoggle (#22647) - **rpc**: Preseve files when stdio channel is closed (#22137) - **runtime**: Remove filetype.vim (#20428) - **treesitter**: Remove g:ts_highlight_lua (#22257) - **treesitter**: Remove silent option from language.add() - **treesitter**: Consolidate query util functions - **treesitter**: Remove deprecated show_tree func - **treesitter**: Deprecate top level indexes to modules (#22761) - **treesitter**: Rename help parser to vimdoc FEATURES - Added support for @generic to lua2dox.lua - Added support for optional params to lua2dox - Added support for specifying types for lua2dox - Mention ":help news" in intro #20674 - ":write ++p" creates parent dirs #20835 - Add vim.secure.read() - `vim.inspect_pos`, `vim.show_pos`, `:Inspect` - $NVIM_APPNAME #22128 - Try to recover from missing tempdir #22573 - Add `vim.filetype.get_option()` - Add `vim.treesitter.language.get_filetypes()` (#22643) - Allow function passed to defaulttable to take an argument (#22839) - **api**: Nvim_select_popupmenu_item support cmdline pum (#20652) - **api**: Add command name to Lua command callback opts - **api**: Show more exception info - **api**: More fields in nvim_list_uis - **api**: Add filetype option nvim_get_option_value - **api**: Add nvim_get_hl (#22693) - **api**: Nvim_exec2(), deprecate nvim_exec() #19032 - **api**: Evaluate 'statuscolumn' with nvim_eval_statusline() - **api**: Set statuscolumn line number in nvim_eval_statusline() - **aucmd_win**: Allow crazy things with hidden buffers (#21250) - **checkhealth**: Improve treesitter report - **checkhealth**: Check runtime ($VIMRUNTIME) - **checkhealth**: Use "help" syntax, avoid tabpage #20879 - **clipboard**: Copy to system clipboard in tmux when supported (#20936) - **clipboard**: Added wayclip support (#21091) - **diagnostic**: Add `suffix` option to `open_float()` (#21130) - **diagnostic**: Add `suffix` option to `virt_text` config (#21140) - **diagnostic**: Don't open quickfix/loclist if no diagnostics #21397 - **diagnostic**: Vim.diagnostic.is_disabled() #21527 - **diagnostic**: Add support for tags - **docs**: Nested lists in HTML, update :help parser - **docs**: Format parameters as a list #20485 - **docs**: Update parser, HTML gen #20720 - **docs-html**: Try to use tags for ToC headings - **editorconfig**: Add builtin EditorConfig support - **editorconfig**: Add editorconfig syntax file - **editorconfig**: Allow editorconfig to be toggled dynamically - **exrc**: Use vim.secure.read() for 'exrc' option - **exrc**: Support .nvim.lua (#21436) - **extmarks**: Allow preventing spellchecking with spell = false - **extmarks**: Extend nvim_buf_get_extmarks() - **filetype**: Fall back to file extension when matching from hashbang (#22140) - **float**: Open float relative to mouse #21531 - **fs**: Add opts argument to vim.fs.dir() - **gen_help_html.lua**: Remove old AWK scripts - **health**: Detect tmux RGB support via `client_termfeatures` - **help**: Highlighted codeblocks - **highlight**: Add DiagnosticOk (and associated) highlight groups (#21286) - **highlight**: Define the concept of altfont as a (c)term rendering attribute - **l10n**: Update Turkish translations (#20444) - **l10n**: Update zh_CN translations (#21085) - **lsp**: Add bufnr option to lsp.start (#20473) - **lsp**: Support window/showDocument (#19977) - **lsp**: Run handler in coroutine to support async response (#21026) - **lsp**: Support set title in lsp relate floatwindow (#21110) - **lsp**: Support willSave & willSaveWaitUntil capability (#21315) - **lsp**: Initial support for semantic token highlighting - **lsp**: Highlight semantic token modifiers (#21390) - **lsp**: Add function to get semantic tokens at cursor - **lsp**: Add function to clear codelens (#21504) - **lsp**: Show active clients in :checkhealth vim.lsp (#21670) - **lsp**: Add triggerKind option for vim.lsp.buf.code_action (#21905) - **lsp**: Implement workspace/didChangeWatchedFiles (#21293) - **lsp**: Implement workspace/didChangeWatchedFiles (#22405) - **lsp**: Overwrite omnifunc/tagfunc set by ftplugin #22267 - **lsp**: Render markdown in docs hover #22766 - **lsp**: Create default link from @lsp.type.comment to Comment (#22888) - **lua**: Send "--" literally to Lua "-l" script - **lua**: Exit 1 on Lua "-l" script error - **lua**: Execute stdin ("-") as Lua - **lua**: Store "nvim -l" scriptname in _G.arg[0] - **lua**: Low-level interpreter mode (nvim -ll) - **lua**: Make sure require'bit' always works, even with PUC lua 5.1 - **lua**: Add semver api - **lua**: Omnifunc for builting lua interpreter - **lua**: Use vim.empty_dict() for empty return value in new api functions (#22737) - **lua**: Allow `:=expr` as a shorter version of `:lua =expr` - **lua**: Add `vim.loader` - **lua-api**: Avoid unnecessary allocations (#19877) - **man**: Add health check - **man.lua**: Support spaces in manpage names - **message**: Avoid spam on failed os_msg - **packaging**: Add start menu and desktop shortcuts on Windows - **provider**: Add support for Yarn node modules on Windows (#21246) - **secure**: Add `:trust` command and vim.secure.trust() (#21107) - **spell**: Support nospell in treesitter queries - **spell**: Also source `spell/LANG.lua` when setting `spelllang` (#22111) - **test**: Add Lua forms for API methods (#20152) - **treesitter**: Add vim.treesitter.show_tree() (#21322) - **treesitter**: Add 'lang' option to show_tree() (#21341) - **treesitter**: Show filetype associated with parser (#17633) - **treesitter**: Allow capture text to be transformed - **treesitter**: Add metadata option for get_node_text - **treesitter**: Respect metadata[id].range for offset! - **treesitter**: Playground improvements - **treesitter**: Add filetype -> lang API - **treesitter**: Upstream foldexpr from nvim-treesitter - **treesitter**: Expand the API - **treesitter**: Add :InspectTree command (#22477) - **treesitter**: Bundle query parser and queries (#22483) - **treesitter**: Use upstream format for injection queries - **tui**: Run TUI as external process - **tui**: Graduate the +tui feature - **tui**: Support altfont mode in tui.c - **ui**: Add support to display a title in the border of a float (#20184) - **ui**: Add 'statuscolumn' option - **ui**: Restore has('gui_running') - **ui**: Add scroll_delta to win_viewport event #19270 - **vim-patch**: Mention original author #20772 - **vim.diff**: Allow passing an integer for linematch - **vim.fs**: Pass path to find() predicate, lazy evaluate #22378 - **vim.fs**: Improve normalize - **vim.gsplit**: Gain features of vim.split - **vim.version**: More coercion with strict=false - **web**: Syntax highlighting via highlight.js - **window/ui**: Add splitkeep option (#19243) - **windows**: Show icon in terminal titlebar, taskbar #20607 PERFORMANCE - **column**: Only build fold/sign column when present in 'statuscolumn' - **completion**: Use one call to globpath() for .vim and .lua #21942 - **diagnostic**: Use api variable and improve validate (#21111) - **lsp**: Update semantic tokens algorithm for parsing modifiers (#21383) - **lsp**: Only redraw the windows containing LSP tokens - **lsp**: Better binary search mid calculation in semantic token (#22607) - **statuscolumn**: Only fill click defs array once per redraw (#21884) - **statusline**: UI elements are always redrawn on K_EVENT - **treesitter**: Smarter languagetree invalidation - **treesitter**: More efficient foldexpr - **ui**: Mitigate redraw latency regression from TUI refactor BUG FIXES - Make_filter_cmd for :! powershell - :! pwsh redirection for `command not found` - Find multibyte file name in line (#20519) - Change did_emsg back to int - 'scroll' is not set correctly for floats with 'splitkeep' - Setting tabline option not redrawing tabline - Avoid unsigned overflow in home_replace() (#20854) - Add lfs to luarc.json (#20979) - Vim.ui.input always calls callback #21006 - Don't disable compositor widgets when a GUI with multigrid attaches - Pvs warnings (#21145) - Clang warnings (#21247) - Vim.opt_local:append ignoring global option value (#21382) - Issues with command line if ui elements are externalized - Properly close builtin popup in ext_popupmenu - Failing XDG test on Windows CI - Pass value instead of pointer to isalpha (#21898) - Use correct number for INT_MAX (#21951) - Add manifest file to correctly determine Windows version (#21953) - Uv_tty_set_mode failed in Windows #22264 - Lsp github issue template example (#22285) - Remove "Features" section from --version/:version (#22315) - Remove "Compiled by:" from :version/--version (#22316) - Add missing void as function argument (#22317) - Windows assertion failure due to incorrect path length (#22324) - Resolve error from -Werror=maybe-uninitialized - Address -Wmaybe-uninitialized warnings (#22436) - Pasting in terminal buffer on windows #22566 - Invalid buffer size argument to snprintf #22729 - Snprintf buffer overflow detected by -D_FORTIFY_SOURCE=3 (#22780) - **MSVC**: Set the active code page to utf-8 (#22384) - **Windows**: Restore console title at exit #21922 - **api**: Dynamically allocate line buffer for nvim_out_write (#20537) - **api**: Nvim_buf_get_text regression (#21071) - **api**: Nvim_win_set_cursor redraw cursorcolumn for non-current window (#21072) - **api**: Set correct curbuf when temporarily changing curwin (#21371) - **api**: "emsg_silent" should imply "silent" in nvim_cmd (#21438) - **api**: Nvim_create_autocmd crash on invalid types inside pattern array - **api**: Avoid memory leak with click functions in nvim_eval_statusline() (#21845) - **api**: Don't allow hiding aucmd_win from another tabpage (#21975) - **api**: Allow empty Lua table for nested dicts #22268 - **api**: Set script context when setting usercmd or option (#22624) - **api**: Vim.filetype.get_option() (#22753) - **api**: Make nvim_get_hl return 'cterm' attrs properly - **api**: Use local LastSet structure in nvim_get_option_info (#22741) - **api**: Return both link and attributes with nvim_get_hl (#22824) - **api**: Avoid double hit-enter prompt with nvim_err_writeln (#22879) - **autocmd**: Handle recursion for force set (#22820) - **buffer_updates**: Save and restore current window cursor (#16732) - **build**: "make clean" fails - **build**: Duplicate version string "v0.8.0-v0.8.0" #20578 - **build**: Fix invalid use of EXITFREE - **chansend**: Sending lines to terminal in reverse order on Windows #19315 - **ci**: Skip test on windows (#21502) - **ci/release/winget**: Bump action version - **client**: Wait for session to exit - **clint**: Disable whitespace/newline #20619 - **clipboard**: Prefer xsel #20918 - **clipboard**: Update version regex pattern (#21012) - **clipboard**: Show provider warning when not during batch changes #21451 - **column**: Avoid drawing columns for virt_lines_leftcol - **column**: Estimate 'statuscolumn' width appropriately - **column**: No longer reset nrwidth_line_count for 'statuscolumn' - **column**: Cmdwin cursor is offset with 'statuscolumn' (#22445) - **column**: Issues with 'statuscolumn' width (#22542) - **column**: Rebuild status column when sign column is invalidated (#22690) - **column**: Invalidate statuscolumn width when UPD_NOT_VALID (#22723) - **completion**: Set pum_size even if ext_popupmenu is used (#20648) - **completion**: Correct what modes support fuzzy completion - **completion**: Include lua syntaxes in :ownsyntax completion (#21941) - **coverity/433537**: Don't call kv_concat_len() when read_size is 0 (#21664) - **decoration**: Redraw correctly when re-using ids - **decoration**: Call providers in win_update() earlier - **decoration**: Do not reset must_redraw after calling providers (#21459) - **decoration**: Don't show signcolumn for non-sign_text extmark (#22135) - **diagnostic**: Correct type annotations; add Diagnostic type (#21120) - **diagnostic**: Clear stale cache on reset (#21454) - **diagnostic**: Sort diagnostics by column (#21457) - **diagnostic**: Revert notification on missing diagnostics (#21632) - **diagnostic**: Use correct field name for tags (#22835) - **diff**: Remove size_t underflow (#20929) - **diff**: Fix a crash in diff mode with linematch enabled (#21070) - **diff**: Handle long lines without crashing (#21389) - **diff**: Avoid restoring invalid 'foldcolumn' value (#21650) - **diff**: "nvim -d" should only diff arglist files #21829 - **diff**: Adjust extmarks after diffput/diffget (#22440) - **diff**: Add NULL check - **diff**: Trigger on_bytes only once after diffget/diffput - **diff.c**: Regression in diffgetput (#20843) - **docs**: Missing "(" in :help HTML - **docs**: Nil as viable argument for goto_prev (#20852) - **docs-html**: Keycodes, taglinks, column_heading #20498 - **docs-html**: Update parser - **docs-html**: Misaligned tabs after conceal #20690 - **edit**: Don't subtract msg_scrolled when removing double quote (#22630) - **editorconfig**: Do not highlight unknown properties as errors (#21673) - **embed**: Handle stdio in server properly - **eval**: Make error number of charidx() same as Vim - **eval**: Change some tv_dict_add() usages back to hash_add() - **events**: Save v:event for cmdline autocommands separately (#21316) - **events**: Skip WinScrolled for newly-created float windows (#21333) - **ex_cmds**: Fix a mistake in the porting of Vim patch 8.1.0306 (#21096) - **exit**: The TUI should not ui_flush() itself (#21625) - **exit**: Skip unnecessary steps in TUI preserve_exit() (#21897) - **extmarks**: Adjust extmarks when inserting prompt prefix - **extmarks**: Problems with folded virtual lines (#21930) - **extmarks**: Don't leak memory on error (#22507) - **fileio**: Use first available directory in backupdir for backupcopy (#20655) - **fileio.c**: Don't use uninitialized memory (#22031) - **filetype**: Don't pass empty string to detect (#20766) - **filetype**: Correctly detect tex files - **filetype**: Make vim.filetype.match() work with contents only (#22181) - **filetype**: Avoid recursive FileType autocmds (#22813) - **filetype**: Make recursive work...again (#22826) - **float**: Make closing float in another tab return to correct window - **float**: Fix ml_get error with bufpos - **float**: Fix crash with bufpos and non-existent window (#21319) - **float**: Remove -1 in height clamp - **folds**: Fix fold marker multibyte comparison (#20439) - **folds**: Use long for number of folded lines (#21447) - **folds**: Cursorline highlight is not always applied on closed folds (#22242) - **folds**: Handle visual blockwise indent insertion correctly (#22898) - **fs**: Duplicate path separator #21509 - **health**: Correct tmux rgb verification (#20868) - **health**: Fix `tmux_esc_time` comparison - **health**: Iterate using ipairs correctly (#22119) - **health**: Stop using deprecated ts.language.inspect_language() (#22850) - **help**: Force tree reparse after local addition insertion - **helpers**: Restore channel id after a call to WITH_SCRIPT_CONTEXT - **highlight**: Link more treesitter groups by default (#20711) - **highlight**: Properly deal with underline mask when listing (#22057) - **highlight**: Avoid ORing underline flags (#22372) - **highlight**: Use winhl=Foo:Bar even when Bar is empty - **inspect**: Alwasy resolve full treesitter lang hl groups - **intro**: Omit patch version in ":help news" item #20713 - **intro**: Make :help news line easier to translate (#21974) - **lintcommit**: Capitalized description #22282 - **loader**: Disable profiling by default - **lsp**: Reporting bogus capabilities in CodeActionKind #20678 - **lsp**: Ignore hover and signatureHelp responses on buffer change (#21121) - **lsp**: Render
{lang} code blocks and set separator default to false (#21271)
- **lsp**: Remove workspaceFolders field (#21284)
- **lsp**: Call show_document with correct args
- **lsp**: Ensure open_logfile is safe for fast events (#21288)
- **lsp**: Followup fixes for semantic tokens support (#21357)
- **lsp**: Correct some type annotations (#21365)
- **lsp**: Fix get_active_clients bufnr parameter (#21366)
- **lsp**: Ignore null responses for semanticTokens request (#21364)
- **lsp**: Token_edit.data might be null on deletion (#21462)
- **lsp**: Adjust gravity of semantic tokens extmarks (#21574)
- **lsp**: Fix nil client access in get_active_clients (#21524)
- **lsp**: Change vim.lsp.get_active_clients.filter name annotation to string (#21624)
- **lsp**: Correct callHierarchy capability to fix lsp.buf.incoming_calls() (#21665)
- **lsp**: Fix `removed` param value in add_workspace_folder (#21915)
- **lsp**: Assert workspace/applyEdit receives params (#21945)
- **lsp**: Check method is supported when range formatting (#21970)
- **lsp**: Check if the buffer is a directory before w! it (#22289)
- **lsp**: Wrong format of bufnr and client order in error message (#22336)
- **lsp**: Fix some type annotations (#22397)
- **lsp**: CallHierarchy methods also require the callHierarchyProvider (#22427)
- **lsp**: Use buffer scheme for files not stored on disk (#22407)
- **lsp**: Only fire LspDetach for attached buffers (#22468)
- **lsp**: Don't monitor files if workspace_folders is nil (#22531)
- **lsp**: Change LspTokenUpdate to use buffer instead of pattern (#22559)
- **lsp**: Prevent lsp tests from picking up local user config (#22606)
- **lsp**: Send didClose on buffer rename (#22623)
- **lsp**: Use line start/end for visual line selection (#22632)
- **lsp**: Remove_workspace_folders fails if client has no workspace_folders #22633
- **lsp**: Vim.lsp.util.apply_text_edits cursor validation #22636
- **lsp**: Kill buffers after renaming a directory #22618
- **lsp**: Avoid switching buffers on lsp attach (#22689)
- **lsp**: Jump to tag locations reliably when :ltag is used (#22750)
- **lsp**: Add missing silent check in lsp hover handler (#22763)
- **lsp/window_showDocument**: Correctly handle external resources #20867
- **lua**: Properly configure luacheck and remove `local vim = ...` lines (#20551)
- **lua**: Assert failure with vim.regex() error inside :silent! (#20555)
- **lua**: On_yank error with blockwise multibyte region #20162
- **lua**: Pesc, tbl_islist result types #20751
- **lua**: Make `vim.deepcopy` work with `vim.NIL`
- **lua**: Always return nil values in vim.tbl_get when no results
- **lua**: Mark some eval functions that can run in API-fast
- **lua**: Vim.deprecate() shows ":help deprecated" #22677
- **luado**: Get old_line length before executing Lua code
- **man**: Support MacOS 13
- **man**: Handle absolute paths as `:Man` targets (#20624)
- **man**: Use italics for `_` (#22086)
- **man.lua**: Set modifiable before writing page (#20914)
- **man.lua**: Use `env` command (#21007)
- **man.lua**: Open in current window if it's already a man page (#21987)
- **man.lua**: Tests, naming
- **mappings**: Use all buckets in second round of unmap (#21534)
- **mappings**: Fix check for cpo-B inverted in completion
- **mappings**: Make "<" escaping in completion match Vim
- **mark**: Do not restore view in op-pending mode (#20889)
- **memline**: Use long instead of linenr_T for db_line_count
- **memory**: Fix memory alignment for dynamic allocation
- **messages**: Reset msg_grid_scroll_discount when redrawing (#21000)
- **messages**: Don't set cmdline_row when messages have scrolled (#21015)
- **mouse**: Ensure no scrolling with "ver:0" in 'mousescroll' (#20861)
- **mouse**: Statusline click registered as statuscolumn (#21748)
- **options**: No matter what is said, 'cmdheight' is tab-local (susy baka)
- **options**: Fix local 'sidescrolloff' doesn't work for mouse (#21162)
- **options**: Restore exists() behavior for options (#21510)
- **paste**: Feed keys as typed in cmdline mode (#20959)
- **path**: Don't remove trailing slash when getting absolute path (#20853)
- **powershell**: Wrong length allocation for ":%w !" #20530
- **qflist**: Avoid read of uninitialized memory (#20709)
- **rbuffer**: Handle edge case where write_ptr has wrapped around
- **redraw**: Get the line again after evaluating something
- **remote**: Don't leak memory on failure to connect to server (#21931)
- **rpc**: Don't free args on error in rpc_send_event
- **rpc**: Don't parse msgpack if buflen is 0 (#21899)
- **rpc**: Ignore redraw events when not in UI client (#21892)
- **rpc**: Ignore redraw events when exiting (#22184)
- **runtime**: Properly rely on t_Co for colorschemes (#20602)
- **runtime**: Use `g:terminal_color_{0-15}` in colorschemes (#20637)
- **screen**: Correctly draw background and eob with 'rightleft' (#22640)
- **screen**: Redraw the ruler for a current floating window
- **secure**: Crash when hitting escape in prompt (#21283)
- **shell**: On Windows :make does not echo #22728
- **showcmd**: Assert failure with cmdheight=0 (#21536)
- **sleep**: Correct cursor placement (#22639)
- **spell**: Fix wrong cast (#20810)
- **spell**: Properly source spell/LANG.{vim,lua} (#22716)
- **startup**: Support .exrc or .nvimrc with init.lua (#21181)
- **status**: Handle unprintable chars in the statusline
- **statuscolumn**: Fix crashes and clang/PVS warnings (#21725)
- **statuscolumn**: Fix sign column highlights (#21727)
- **statuscolumn**: Foldcolumn buffer is too small (#21761)
- **statuscolumn**: Make %l/%r respect 'number'/'relativenumber' (#21747)
- **statuscolumn**: Always fill click defs array (#21878)
- **statusline**: Don't show showcmd when not enough space (#21550)
- **statusline**: Make nvim_eval_statusline() work with %S (#21553)
- **statusline**: Don't leak memory with zero-width click labels
- **statusline**: Don't leak memory with truncated click labels
- **stdpath**: Default to /tmp if stdpath('run') cannot be created #20952
- **syntax**: Correct conceal for annotated code blocks (#21272)
- **tabline**: Avoid memory leak in tabline click definitions (#21847)
- **terminal**: Fix 'mousescroll' not respected in terminal mode (#21415)
- **test**: Unset XDG_CONFIG_HOME when running oldtest
- **test**: Fix issues detected by running unittests in ASAN/UBSAN
- **test**: Fix C imports on macOS arm64
- **tests**: Only get the color map once, even for multiple test files
- **tests**: Initialize Screen.colors in API highlight tests
- **tests**: Use -l mode for lsp tests
- **tests**: Fixes for using vim.mpack and more ASAN
- **tests**: Adapt treesitter/highlight_spec priority test
- **treesitter**: Properly restore `'syntax'` (#21358)
- **treesitter**: Really restore syntax
- **treesitter**: Validate language name
- **treesitter**: Fix most diagnostics
- **treesitter**: Don't trample parsers when filetype!=lang
- **treesitter**: Make params optional
- **treesitter**: Fixup language invalidation (#22381)
- **treesitter**: Remove virtual text from playground
- **treesitter**: Ipairs -> pairs
- **treesitter**: Fixup for health
- **treesitter**: Maintain cursor position when toggling anonymous nodes
- **treesitter**: Disallow empty filetypes
- **treesitter**: Typos in _range.lua
- **treesitter**: Break early from loop when match is found (#22499)
- **treesitter**: Raise ts_match_limit to 256 (#22497)
- **treesitter**: Is_in_node_range (#22582)
- **treesitter**: Correct include_bytes arg for parse()
- **treesitter**: Do not error on empty filetype
- **treesitter**: Better lang handling of get_parser()
- **treesitter**: Foldexpr (#22652)
- **treesitter**: InspectTree does not respect 'splitright' #22692
- **treesitter**: Annotations
- **treesitter**: Add missing deprecate
- **treesitter**: Update queries from nvim-treesitter
- **treesitter**: Use capture metadata range if exists
- **treesitter**: Disable folding in inspect_tree() (#22885)
- **treesitter**: Do not track ranges of the root tree (#22912)
- **ts**: Check buffer is loaded when restoring options (#21419)
- **tui**: Resume main thread if suspending isn't implemented (#20523)
- **tui**: Set cursor color param as string when required #21407
- **tui**: More work in the TUI
- **tui**: Do not set ui_client_termname if it is already set (#21607)
- **tui**: Make a copy of data->params before unibi_format() (#21643)
- **tui**: Do not invoke loop recursively for pad()
- **tui**: Set stdin as "blocking" on exit (#21973)
- **tui**: Detach/attach on suspend/resume (#22040)
- **tui**: Exit on input eof
- **tui**: Set taskbar, icon in Windows #22270
- **tui**: Only forward stdin_fd on first attach (#22293)
- **tui**: Properly check if stdin is a tty (#22321)
- **tui**: Avoid stack-use-after-scope with cursor color (#22435)
- **tutor**: Failing to get buf name #20933
- **ui**: Msg_ext_set_kind for nvim_echo (#20476)
- **ui**: Setting 'cmdheight' with global statusline (#20515)
- **ui**: Send grid_resize events before triggering VimResized (#20760)
- **ui**: Fix some cases of stale highlight definitions
- **ui**: Allow resize commands to set 'cmdheight' to 0
- **ui**: Fix fragile UI_CALL macro invocation (#21656)
- **ui**: Convert title_pos string in nvim_win_get_config
- **ui**: Set stc to empty in floatwin with minimal style (#21720)
- **ui**: Command line issues with external messages (#21709)
- **ui**: Re-organize tty fd handling and fix issues
- **ui**: Make sure screen is valid after resizing
- **ui**: Recording change doesn't trigger statusline redraw
- **ui**: Ruler is not redrawn in cmdline with redrawstatus
- **ui-ext**: Correct message kind in history before vim.ui_attach()
- **ui-ext**: Log and clear error in ui_comp_event (#21147)
- **ui-ext**: Force cursor update after resize in char-based UI
- **unittest**: Delete unused duplicated code
- **unittests**: Do not consider process crash to be a success
- **unittests**: Fix TUI broken test previously ignored
- **vim-patches**: Ensure libfuse is installed
- **vim.diff**: Correctly apply hunk offsets with linematch (#20931)
- **vim.diff**: Fix fastforward off-by-1 (#20937)
- **vim.ui.input**: Return empty string when inputs nothing (#20883)
- **vim.version**: Incorrect version.cmp()
- **vim.version**: Prerelease compare
- **win_close**: Remove float grid after closing buffer (#21551)
- **win_update**: Don't use unintialized memory in edge case (#22266)
- **windows**: Set console icon later in startup
- **windows**: Consistent normalization in fs.find

BUILD SYSTEM!
- Remove unused variable CMAKE_C_COMPILER_ARG1
- Remove code for cross-compilation
- Remove url for 32-bit winyank
- Remove unnecessary translation-related code
- Rely on builtin cmake downloading rather than custom script
- Define EP_PREFIX property
- Only generate compilation database for the nvim target (#20449)
- Remove EXITFREE for debug builds
- Generate compilation database for older cmake versions
- Add clang-tidy configuration file (#15601)
- Fix incorrect clang-tidy identifier rules (#20650)
- Rely on default cmake installation if possible
- Give example on complex regexes
- Preprocess vim patches with uncrustify #20786
- Copy each treesitter parser library individually #20797
- Fix plural messages missing from .po files (#20830)
- Make update-po support optwin.vim (#20840)
- Remove python linting #20851
- Add EXCLUDE option to add_glob_target
- Always ignore user's cmake preset (#20935)
- Allow IWYU to fix includes for all .c files
- Restrict `git describe` to top level source directory (#20993)
- Fix help tags generation when SHELL=fish (#21562)
- Add git sha to version when built with nix flake (#21210)
- Remove workaround for old luajit versions
- Remove workaround for ancient clang versions
- Use modern cmake (#21589)
- Include our libraries before system libraries (#21746)
- Enable iwyu with target properties instead of variables (#21797)
- Exclude tui/terminfo_defs.h from lintc-clint (#21822)
- Enable cmake workflow presets (#21860)
- Remove nvim as a dependency of unittests (#21903)
- Various cmake fixes (#21902)
- Bump MSVC warning to level two (#21890)
- Use CMAKE_POSITION_INDEPENDENT_CODE instead of -fPIC (#21947)
- Make generated source files reproducible #21586
- Remove unnecessary unit test code (#21940)
- Use cmake for all platforms for unibilium and libtermkey (#21926)
- Simplify treesitter installation (#21969)
- Use upstream CMakeLists.txt for unibilium (#21976)
- Delete pthreads import (#21732)
- Remove GNU make check (#21977)
- Remove tests for libtermkey (#21983)
- Use cmake to build treesitter on all platforms (#21984)
- Introduce default build variables (#21991)
- Use cmake to build libvterm on all platform (#21986)
- Check if libvterm version meets requirement (#22010)
- Find unibilium without relying on libfindmacros (#22015)
- Fix dependencies in find modules (#22017)
- Enable ccache by default if available (#22020)
- Enable ccache project-wide (#22045)
- Add uninstall make target (#22059)
- Remove unnecessary file generation (#22099)
- Update release data
- Stop relying on CMAKE_BUILD_TYPE to determine the build type (#22051)
- Unbreak building neovim with multi-config generators (#22104)
- Don't build libnvim when running the CI (#22149)
- Remove duplicate INTERFACE keyword (#22106)
- Prefer -D = over -D= (#22164)
- Replace check-single-includes with clang-tidy (#22061)
- Remove unused function get_test_target (#22176)
- Reuse source files with interface library (#22177)
- Create test/CMakeLists.txt and move test-related code (#22179)
- Remove codecov related files (#20859)
- Mark uninteresting variables as advanced (#22208)
- Enable MSVC level 3 warnings (#21934)
- Don't check environment variable to detect CI (#22234)
- Treat clang-tidy warnings as errors (#22238)
- Remove ENABLE_COMPILER_SUGGESTIONS option (#22249)
- Only use HOSTNAME_PRG if HOSTNAME is undefined (#22288)
- Use custom command to create single versiondef (#22290)
- Use libuv config file (#22209)
- Test multi-config generator (#22310)
- Build all dependencies in parallel (#22329)
- Remove unused dependency penlight (#22334)
- Build luajit in parallel (#22327)
- Set libtermkey project language to C (#22410)
- Remove pkgconfig-related code (#22422)
- Remove libfindmacros library (#22423)
- Cmake cleanup (#22251)
- Unset variables ending with "URL" if USE_EXISTING_SRC_DIR is ON
- Show build type specific compiler flags when using --version
- Fix unknown pragma warning with mingw (#22533)
- Consistently use the provided option paths
- Fix USE_EXISTING_SRC_DIR option
- Silence git describe error output
- Remove workaround for incorrectly packaged libluv
- Enable unit testing on release builds (#22554)
- Fix build warning when using gcc 4.9.2
- Explicitly add dependency include dir for header generation
- Sanitizers for gcc
- Set CMAKE_C_STANDARD to 99 for all dependencies
- Drop curl.exe on Windows
- Download wintools executables separately
- Cmake cleanup
- **MSVC**: Enable assertions on RelWithDebInfo build type (#22326)
- **Windows**: Fix redoing version generation (#21880)
- **Windows**: Make bundling nvim-qt optional (#21866)
- **Windows**: Allow building without custom md5sum
- **bump_deps.lua**: Run command -v in shell (#22030)
- **ci**: Let ASAN print tracebacks for more errors (SIGABORT, SIGILL)
- **cmake**: Add modelines to enable syntax highlighting
- **deps**: Restore support for USE_EXISTING_SRC_DIR (#20491)
- **deps**: Add build type for libuv (#20575)
- **deps**: Disable shared library for libvterm. (#20566)
- **deps**: Bump tree-sitter to v0.20.8 (#22663)
- **deps**: Bump luarocks to v3.9.2
- **deps**: Bump coxpcall to 1.17.0-1
- **deps**: Bump luacheck to 1.1.0-1
- **deps**: Bump mpack to 1.0.10
- **deps**: Bump lua parser to v0.0.14 (#20897)
- **deps**: Switch vim parser to maintained fork (#22896)
- **deps**: Bump vimdoc parser to v2.0.0 (#22870)
- **deps**: Set query parser to release (#22603)
- **deps**: Bump libvterm to v0.3.1
- **deps**: Bump msgpack-c to v6.0.0 (#22522)
- **deps**: Bump win32yank to v0.1.1 (#22700)
- **deps**: Bump actions/stale from 7 to 8
- **deps**: Switch to Launchpad for libvterm and libtermkey (#22811)
- **editorconfig**: Set indent_size to 4 for python files (#21135)
- **lint**: Remove clint.py rules for braces #20880
- **lint**: Add more shell scripts to lintsh
- **lintsh**: Double quote to prevent word splitting (#21571)
- **luarocks**: Update busted version to v2.1.1 (#22029)
- **nix**: Change the pkgs to final, add new version of libvterm (#20410)
- **nix**: Update nixpkgs
- **nix**: Clean up nix flake (#21565)
- **nix**: Remove pylint as it has been removed (#21572)
- **nix**: Fixed build (#22918)
- **vim-patch.sh**: Handle added/removed files properly
- **vim-patch.sh**: Checkout files with path for uncrustify (#20863)
- **windows**: Export extern symbols for use in FFI #22756
- **windows**: Specify Windows 8 as the minimum version (#22173)
- **windows**: Work around luarocks not finding its own md5sum

DOCUMENTATION
- Refer to vim.lsp.start() in LSP issue template #20422
- Fix incorrect :help tag (#20511)
- Added proper annotations to functions in shared.lua
- Fix typos
- Fix/remove invalid URLs #20647
- "supported platforms" matrix #19615
- Update vimdoc parser #20747
- ":che" is ":checkhealth" #20147
- .git-blame-ignore-revs (#20820)
- Swap CursorLineFold and CursorLineSign (#20875)
- Add language annotation to Nvim manual
- Add missing docs from some Vim patches (#21296)
- Dark/light color/accessibilty pass for generated html docs #21345
- Add links to extmarks and namespaces (#21378)
- Remove "How-to disable mouse" menu item #21394
- Add security policy (#17338)
- Fix order of numbers in syntax.txt (#21581)
- Clarify line about converse of lua-heredoc (#21592)
- Fix treesitter parsing errors
- Add 'statuscolumn' docstrings (#21717)
- Builtin TUI is no longer channel 0 (#21794)
- Treesitter.add_directive, add_predicate #21206
- Docs: use codeblocks in runtime/doc/options.txt (#21919)
- Clarify :runtime behavior without [where] again (#22003)
- Clarify "pipe" mode for sockconnect
- Reword news.txt to ensure a consistent style (#22215)
- Remove mentions of 'balloonexpr' #22049
- Remove the test badge from the README (#22350)
- Mention getmousepos() for click execute function label
- Naming conventions, guidelines
- Fix more treesitter parsing errors
- Use build/bin/nvim instead of nvim in gen_vimdoc (#22398)
- Fix vim.treesitter tags
- Lua2dox.lua debugging
- Module-level docstrings (@defgroup) #22498
- Add missing highlight groups for floats
- Add removed features in news.txt
- Fix g:terminal_color_x terminal colors #22746
- More details about vim.region (#21116)
- How to debug TUI using gdb/lldb #22771
- Add vim.treesitter.query.get_query() to deprecated.txt
- **README**: Add Kotlin as a language which can use the API (#21567)
- **README**: Fix CI status badge (#22308)
- **api**: Pattern is not expanded for autocommands (#20812)
- **api**: Fix treesitter parsing errors
- **api**: Tweak data arg for nvim_create_autocmd (#22008)
- **api**: Link to nvim_set_hl_ns from nvim_set_hl (#22678)
- **dev-style**: Remove rule about variable declarations (#20446)
- **dev-style**: Remove rules covered by uncrustify
- **diagnostic**: Number → integer (#22512)
- **docstrings**: Fix runtime type annotations
- **editorconfig**: Update news.txt
- **editorconfig**: Add editorconfig.txt
- **editorconfig**: Number → integer (#22514)
- **filetype**: Number → integer (#22516)
- **gen**: Support language annotation in docstrings
- **gitignore**: Correct oldtest path
- **help**: Consistent headers for local additions
- **highlight**: Fix type annotations (#22272)
- **html**: Render @see items as a list #22675
- **inspect**: Number → integer (#22511)
- **lsp**: Add formatting APIs to deprecated.txt (#20487)
- **lsp**: Update buf_notify and rpc.notify params types (#21753)
- **lsp**: Fix type annotation on convert_input_to_markdown_lines (#21772)
- **lsp**: Format arguments to start_client() (#21980)
- **lsp**: Update cmd_env description (#22438)
- **lsp**: Change type annotations from number → integer (#22510)
- **lsp**: Type annotation for lsp.client (#22509)
- **lsp**: More precise type annotations (#22621)
- **lsp**: Opt-out of default LSP "gq" #22615
- **lua**: Add clarifications for fs.find() and fs.normalize() (#21132)
- **lua**: Correct the tags for vim.opt_local and vim.opt_global (#21138)
- **lua**: Correct vim.spell.check example (#21311)
- **lua**: Add guide to using Lua in Neovim (#21137)
- **lua**: Add `vim.json` (#21538)
- **lua**: Fix treesitter parsing errors
- **lua**: Adjust some type annotations
- **lua**: Lua-guide:  is for rhs of vim.keymap.set(), not lhs (#21814)
- **lua**: Use luaref tag instead of www.lua.org #21813
- **lua**: Number → integer (#22517)
- **luvref**: Fix treesitter parsing errors
- **luvref**: Update to version bump
- **maintain**: CI strategy #20778
- **maintain**: Add note on updating luvref.txt
- **manual**: Fix treesitter parsing errors
- **news**: Add news.txt and link from README (#20426)
- **options**: Remove mentions of 'imactivatefunc' and 'imstatusfunc'
- **shell**: Mention "&" for piping with powershell #20459
- **support**: Update tested versions (#21126)
- **test**: Using cmake directly (without make) #22781
- **treesitter**: Fix predicate syntax (#21016)
- **treesitter**: Change links for `eq?` and `set!` to codeblocks  (#21047)
- **treesitter**: Use full function names in tags (#21321)
- **treesitter**: Fix parse errors
- **treesitter**: Number → integer (#22513)
- **treesitter**: Add query injections
- **tutor**: Fix TODO line demo (#21965)
- **uri**: Number → integer (#22515)
- **usr**: Make usr_05.txt more coherent with Nvim changes (#22428)
- **usr_05**: Update sentence about Nvim default behavior of Q (#20817)
- **vim.fs**: Normalize Windows example was incorrect (#21966)
- **website**: Soft wrap code blocks #21644

REFACTOR
- Remove char_u type and replace with char, uint8_t, etc
- remove STRNCMP (#21208) and STRLCPY (#21235)
- Remove clint error suppression as all errors has been fixed #21782
- Explicitly convert HANDLE to intptr_t for _open_osfhandle()
- Clang-tidy fixes to silence clangd warning (#20683)
- Fix uncrustify lint errors
- Move do_mouse() and its helpers to mouse.c (#20895)
- Fix clang-tidy warnings
- Click definition functions #20923
- Remove stray emsg check after #20992 (#20996)
- Move tabline code to statusline.c (#21008)
- Convert drawline.c draw states to enum (#21067)
- Remove __STDC_ISO_10646__ check
- Deprecate 'secure' option
- Remove old TODO comments that aren't relevant anymore (#21144)
- Maybe suppress a PVS warning
- Rework parameter validation in vim.secure.trust() (#21223)
- Buffer_ensure_loaded()
- Move ex_retab() to indent.c
- Remove COMMA (#21260)
- Make sure getting a callback doesn't modify argument
- Rename mch_msg => os_msg
- Rename mch_get_acl => os_get_acl
- Eliminate os_unix.c #21621
- Extract code to open stdin for reading
- Eliminate bump-deps.sh using "nvim -l"
- Fix IWYU mapping file and use IWYU (#21802)
- Format with stylua (#21821)
- Remove E5500, adjust tests
- Fix sign conversion warning from gcc (#21833)
- Use uint8_t for blobs and ga_append() (#21916)
- Use flexible arrays instead of the length-of-one trick (#22072)
- Reduce scope of locals as per the style guide (#22206)
- Move init_default_autocmds to lua
- Rename show_tree => inspect_tree #22474
- Move ga_loaded to runtime.c (#22626)
- Do more in TRY_WRAP
- Add const and remove unnecessary casts (#22841)
- Use bool type for global variables (#22842)
- Rename local API alias from a to api
- Make error message definitions const
- Remove use of reserved c++ keywords
- **PVS**: Suppress false positive V547 in drawline.c (#21875)
- **PVS/V1048**: Remove unnecessary assignment (#21870)
- **PVS/V1048**: Remove redundant assignment (#21871)
- **PVS/V1048**: Remove duplicated assignments (#21873)
- **PVS/V581**: Merge identical if statements (#22390)
- **api**: Do not allocate temporaries for internal events
- **api**: VALIDATE macros #22187 #22256 #22262
- **build**: Remove unused stdlib function and include checks
- **build**: Graduate HAVE_LOCALE_H feature
- **build**: Graduate libtreesitter features which are 1+ years old
- **build**: Graduate msgpack-c FLOAT32 "feature" since forever
- **build**: Graduate unibilium VAR_FROM feature from 2017
- **build**: Graduate -Wvla, -fno-common and -Og "features"
- **build**: Make installation of runtime/ more effective
- **checkhealth**: Convert "nvim" check to Lua
- **clint**: Convert short to int16_t (#20815)
- **column**: Remove unused build_statuscol_str() arguments
- **completion**: Don't add and remove '^' for Lua (#22702)
- **diagnostic**: Remove deprecated function (#20423)
- **diagnostic**: DRY for loop #21521
- **diff.c**: Reduce scope of variables (#20781)
- **diff.c**: Break up ex_diffgetput()
- **diff.c**: Allocate hunks directly in ga_array
- **diff.c**: Factor out hunk extraction
- **diff.c**: Factor out hunk processing
- **diff.c**: Simplify diff_buf_idx()
- **diff.c**: Internal does not need diffstyle
- **diff.c**: Factor out diffblock deletion
- **diff.c**: Copy lines via memmove
- **drawline.c**: Leadcol/trailcol
- **drawline.c**: Move number column helpers function together
- **drawscreen.c**: Reduce scopes of locals (#20668)
- **eval**: Make get_lval() explicitly check for v:lua
- **eval.c**: Factor out get_number_tv() (#21893)
- **exit**: Pass error message to preserve_exit() (#22097)
- **extmarks**: Some minor internal API changes
- **f_has**: Remove wrong comment (#21561)
- **fileio.c**: Reduce scope of locals
- **fileio.c**: Refactor match_file_path()
- **fileio.c**: Refactor vim_rename()
- **fileio.c**: Refactor buf_write_bytes
- **fileio.c**: Refactor buf_write_bytes (2)
- **fileio.c**: Remove HAS_BW_FLAGS
- **fileio.c**: Factor out autocmd handling from buf_write()
- **fileio.c**: More bools
- **fileio.c**: Reduce scope of locals
- **fileio.c**: Do not use macros for error handling
- **fileio.c**: Factor out buf_write post autocmds
- **fileio.c**: Factor out file info calc
- **fileio.c**: Make unreadable expression readable
- **fileio.c**: Factor out backup creation
- **fileio.c**: Remove HAVE_ACL ifdefs
- **fileio.c**: Normalize ifdefs
- **fs**: Replace vim.fn/vim.env in vim.fs (#20379)
- **highlight**: Rename FloatBorderTitle #20988
- **highlight**: Reshape the HL_UNDER* bits into a 3-bit integer mask
- **highlight_group.c**: Reduce scope of locals
- **intro**: Avoid Coverity warning (#22000)
- **loader**: Use vim.fs
- **loader**: Remove BufWritePost autocmd
- **loader**: Add typing for package.loaders
- **loader**: Simplify tracking logic
- **loader**: Cache hash information
- **log**: Reduce compile time LOG_LEVEL granularity
- **lsp**: Remove deprecated lsp functions (#20421)
- **lsp**: Extract a _create_server method in lsp_spec
- **lsp**: Remove deprecated vim.lsp.buf_get_clients calls (#21337)
- **lsp**: Remove workaround for missing bit module (#22373)
- **lsp**: Remove deprecated code (#22389)
- **lsp**: Remove _resolve_capabilities_compat (#22628)
- **lsp**: Do not parse verbose output when overwriting options (#22810)
- **lua**: Move _G.arg init to nlua_init()
- **lua**: Get all marks instead of iterating over namespaces
- **lua2dox**: Format with stylua
- **main.c**: Remove unreachable use_builtin_ui conditions (#22338)
- **man**: Pass env directly to spawn() (#20591)
- **man**: Add type annotations
- **memory**: Simplify new alignment logic
- **option.c**: Reduce scope of locals
- **option.c**: Add get_varp_from and get_varp_scope_from
- **option.c**: De-nest set_option_value
- **option.c**: Use intermediate for options ref
- **option.c**: Add do_set_num
- **option.c**: Add do_set_bool
- **option.c**: Simplify do_set_string
- **option.c**: Factor out common skip check
- **option.c**: Factor out loop code from do_set()
- **option.c**: Remove goto
- **option.c**: Change nextchar to uint8_t
- **option.c**: Use skiptowhite_esc
- **option.c**: Factor out set op parsing
- **option.c**: Factor out option prefix parsing
- **option.c**: Factor out option name parsing
- **option.c**: Factor out opt_idx validation
- **option.c**: De-nest code in do_set_option
- **option.c**: Move bool prefix check
- **option.c**: Add do_set_option_value
- **option.c**: Factor out some nextchar checks
- **option.c**: Factor out string option special case handling
- **options**: Don't pass negative number to illegal_char() (#21999)
- **optionstr.c**: Reduce scope of locals
- **optionstr.c**: Break up did_set_string_option 1-52
- **optionstr.c**: Remove some simple did_set_* functions
- **optionstr.c**: Add did_set_string_option_for
- **optionstr.c**: Break up did_option_listflags
- **optionstr.c**: Remove some redundant parens
- **optionstr.c**: Break up did_set_expropt
- **optionstr.c**: Move handling of formatlistpat
- **optionstr.c**: Align comments (#22070)
- **params**: Open -s and -w script files after parsing commands
- **pty**: Remove old logic for inheriting termios from host terminal
- **redraw**: No type argument in update_screen()
- **redraw**: Various simplifications
- **redraw**: Make cursor position redraw use the "redraw later" pattern
- **runtime**: Use vim.version to compare versions #22550
- **runtime.c**: Factor out find_script_by_name() (#22620)
- **screen**: Screen.c delenda est
- **sleep**: Simplify rube goldberg implementation of :sleep
- **spell**: Use uint8_t for "byts" variables (#22519)
- **statusline**: Move statusline defs to statusline_defs.h
- **tag**: Remove return type from do_tag()
- **test**: Create an lsp-specific helpers.lua file
- **tests**: Lift retry() into assert_log()
- **tests**: Run unittests using main nvim binary in interpreter mode
- **tests**: Move lua-client into core and use it for functionaltests
- **treesitter**: Add vim.treesitter.get_node() (#22360)
- **treesitter**: Use string.format to create lines
- **treesitter**: Simplify some range functions
- **treesitter**: Delegate region calculation to treesitter (#22553)
- **treesitter**: Use byte ranges from treesitter (#22589)
- **treesitter**: Add Range type aliase for Range4|Range6
- **treesitter**: Delegate region calculation to treesitter (#22576)
- **treesitter**: Move inspect_tree impl
- **tui**: Use nvim_echo() for verbose terminfo
- **tui/input.c**: Remove unused multithreading code (#22342)
- **ui**: Statusbar invalidation to win_set_inner_size()
- **ui**: Devirtualize the ui layer
- **ui**: Cleanup 'redrawdebug', introduce "flush" mode
- **ui**: Don't reimplement redrawing in focus gained handling
- **ui**: Remove some superfluous ui_flush() calls
- **ui**: Ui_log() can now just be a function
- **uncrustify**: Move macros definitions to enable formatting
- **uncrustify**: Improved formatting rules
- **vim.gsplit**: Remove "keepsep"
- **vim.version**: Cleanup
- **vim.version**: Use lazy.nvim semver module
- **vim.version**: Use lazy.nvim semver module
- **win_close**: Remove "force", don't pass on "free_buf" (#21921)
- **win_line**: Rename attr to vi_attr (#21487)
- **win_line**: Move some variables into a struct (#22490)
- **window**: Remove aucmd_win check from one_window() (#21972)
- **window.c**: Reduce scope of locals (#20301)
- **windows**: Move os_icon_xx functions

TESTING
- Introduce skip() #21010
- Remove skip for 32-bit MSVC (#21030)
- Don't skip parser_spec on windows (#20294)
- Add a Lua test for swap file created before boot
- Fix failing tui_spec.lua tests (#21117)
- Use isCI to simplify CI detection (#21134)
- Simplify platform detection (#21020)
- Adding/removing winbar should not cause win_pos events (#21226)
- Use luv.os_uname for fast platform detection (#21157)
- Add more tests for float window bufpos (#21318)
- Convert another test in test_matchadd_conceal.vim to Lua (#21353)
- Remove unused variable (#21552)
- Add test cases for command line issues
- Add more tests for Unicode
- Avoid consecutive mouse input at different positions (#21781)
- Align Test_shell_options, Test_shellslash with Nvim default
- Avoid noise in NVIM_LOG_FILE
- Exepath() returns correct path with cmd.exe, powershell #21928
- Remove unused field ext_float (#22243)
- Make expect_unchanged() less confusing (#22255)
- Make {MATCH:} behave less unexpectedly in screen:expect()
- Don't search entire repo for files
- Move oldtests to test directory (#22536)
- Use a wider screen in the rightleft winhl test (#22641)
- Unskip working Windows tests (#22537)
- Re-bundle cat on windows (#21255)
- Windows not detected in msys shells #22671
- Use exec_capture() in more places (#22787)
- Fix flaky watchfiles tests (#22637)
- Replace lfs with luv and vim.fs
- Improve editor/fold_spec.lua and editor/put_spec.lua (#22916)
- **Windows**: Normalize paths for test summary
- **api**: Migrate screenchar() test in in window API to screen test
- **editorconfig**: Add editorconfig tests
- **exit_spec**: Make sure that autocommands are triggered (#22188)
- **fileio_spec**: Avoid expect_exit() without calling clear() (#21810)
- **float_spec**: Add missing sum_scroll_delta #22648
- **help**: Drop treesitter parse error to 0
- **highlight_spec**: Fix warning in Visual highlight test (#22719)
- **legacy/prompt_buffer_spec**: Align script with oldtest more (#22354)
- **lsp**: Call clear() before willSave tests (#21336)
- **lsp**: Add a screen:expect() between insert() and feed_command() (#21577)
- **lua/diagnostic_spec**: Remove unnecessary after_each()
- **lua/fs_spec**: Fix vim.fs.dir() test (#21503)
- **lua/ui_spec**: Fix Ctrl-C test flakiness (#21039)
- **old**: Test_lambda.vim garbagecollect() -> test_garbagecollect_now()
- **old**: Remove stray test42 files (#20966)
- **old**: Make Test_help_tagjump() test order match upstream
- **old**: Add missing lines from Vim patch 8.2.0522 (#21048)
- **old**: Make ":h local-additions" work properly in test_help.vim
- **old**: Skip Vim9 script with less divergence
- **old**: Change $TMPDIR from Xtest-tmpdir to X-test-tmpdir (#21346)
- **old**: Make test_signs.vim closer to upstream (#21479)
- **old**: Run some part of 'cpoptions' tests
- **old**: Make getting an unused PID work (#22529)
- **old**: Move memfile_test.c to test/old/ (#22567)
- **old**: Unskip working tests on Windows (#22650)
- **shada**: Fix shada syntax definitions test
- **statuscolumn**: Add more tests for wrapped lines (#21718)
- **statuscolumn**: %l should follow default wrap behavior (#21766)
- **statuscolumn_spec**: Remove unnecessary feed('lh')
- **statusline**: UI elements are not redrawn on K_EVENT unnecessarily
- **syn_attr_spec**: Add more information (#21912)
- **termxx_spec**: Fix TermClose bdelete test flakiness (#22463)
- **treesitter/parser_spec**: Correct time unit (#22471)
- **tui_spec**: Don't use nested terminal for resize at startup (#21583)
- **tui_spec**: Avoid race between nvim_paste and nvim_input (#21639)
- **tui_spec**: Improve cursor_address test (#21700)
- **tui_spec**: Doesn't use Unicode in cursor_address test (#21703)
- **tui_spec**: Make rapid resize test test what it wants to test (#21933)
- **tui_spec**: Don't expect exact screen in rapid resize test (#21935)
- **tui_spec**: Remove unnecessary arguments for remote UI
- **tui_spec**: Use RPC request to setup autocommands
- **ui**: Wait for another success with failure after success
- **undo_spec**: Add more tests for writing in Insert mode
- **unit**: Use file:close() properly (#21505)
- **vim.fs.normalize**: Enable test on Windows
---
 test/functional/fixtures/api_level_11.mpack | Bin 0 -> 31225 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test/functional/fixtures/api_level_11.mpack

(limited to 'test/functional')

diff --git a/test/functional/fixtures/api_level_11.mpack b/test/functional/fixtures/api_level_11.mpack
new file mode 100644
index 0000000000..2399854c42
Binary files /dev/null and b/test/functional/fixtures/api_level_11.mpack differ
-- 
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')

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 4ce0ada0d4c8c57a181ab08717a3d052d46ae158 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sat, 8 Apr 2023 16:57:47 +0800
Subject: fix(highlight): add missing g: prefix for colors_name (#22952)

Fix #22951.
This was fixed in Vim in patch 8.2.0613.
---
 test/functional/ex_cmds/highlight_spec.lua | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ex_cmds/highlight_spec.lua b/test/functional/ex_cmds/highlight_spec.lua
index 18f215cf75..45764e6719 100644
--- a/test/functional/ex_cmds/highlight_spec.lua
+++ b/test/functional/ex_cmds/highlight_spec.lua
@@ -3,6 +3,9 @@ local helpers = require("test.functional.helpers")(after_each)
 local eq, command = helpers.eq, helpers.command
 local clear = helpers.clear
 local eval, exc_exec = helpers.eval, helpers.exc_exec
+local exec = helpers.exec
+local funcs = helpers.funcs
+local meths = helpers.meths
 
 describe(':highlight', function()
   local screen
@@ -45,4 +48,20 @@ describe(':highlight', function()
     eq('', eval('synIDattr(hlID("NonText"), "undercurl", "gui")'))
     eq('1', eval('synIDattr(hlID("NonText"), "underline", "gui")'))
   end)
+
+  it('clear', function()
+    meths.set_var('colors_name', 'foo')
+    eq(1, funcs.exists('g:colors_name'))
+    command('hi clear')
+    eq(0, funcs.exists('g:colors_name'))
+    meths.set_var('colors_name', 'foo')
+    eq(1, funcs.exists('g:colors_name'))
+    exec([[
+      func HiClear()
+        hi clear
+      endfunc
+    ]])
+    funcs.HiClear()
+    eq(0, funcs.exists('g:colors_name'))
+  end)
 end)
-- 
cgit 


From d52cc668c736ef6ca7ee3655a7eb7fe6475afadc Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 10 Apr 2023 07:33:26 +0800
Subject: vim-patch:9.0.1443: ending Insert mode when accessing a hidden prompt
 buffer (#22984)

Problem:    Ending Insert mode when accessing a hidden prompt buffer.
Solution:   Don't stop Insert mode when it was active before. (closes vim/vim#12237)

https://github.com/vim/vim/commit/05a627c3d4e42a18f76c14828d68ee4747118211

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/prompt_buffer_spec.lua | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua
index 6c72cde855..5c3f8a6f8c 100644
--- a/test/functional/legacy/prompt_buffer_spec.lua
+++ b/test/functional/legacy/prompt_buffer_spec.lua
@@ -247,6 +247,7 @@ describe('prompt buffer', function()
 
       func DoAppend()
         call appendbufline('prompt', '$', 'Test')
+        return ''
       endfunc
     ]])
     feed('asomething')
@@ -254,7 +255,12 @@ describe('prompt buffer', function()
     neq(prev_win, meths.get_current_win())
     feed('exit')
     eq(prev_win, meths.get_current_win())
+    eq({ mode = 'n', blocking = false }, meths.get_mode())
     command('call DoAppend()')
     eq({ mode = 'n', blocking = false }, meths.get_mode())
+    feed('i')
+    eq({ mode = 'i', blocking = false }, meths.get_mode())
+    command('call DoAppend()')
+    eq({ mode = 'i', blocking = false }, meths.get_mode())
   end)
 end)
-- 
cgit 


From 3c724fe1f3efae0d00b43e381523ea2ec7229328 Mon Sep 17 00:00:00 2001
From: luukvbaal <31730729+luukvbaal@users.noreply.github.com>
Date: Mon, 10 Apr 2023 02:39:27 +0200
Subject: fix(column): 'statuscolumn' not drawn after virt_lines with "n" in
 'cpo' (#22967)

Problem:    The 'statuscolumn' is not drawn and the line itself is drawn
            at an offset to the rest of the buffer after virt_lines if
            'cpoptions' includes "n".
Solution:   Make sure 'statuscolumn' is drawn.
---
 test/functional/ui/statuscolumn_spec.lua | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index 0a253455ad..83c49e56a0 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -397,6 +397,29 @@ describe('statuscolumn', function()
       {0:~                                                    }|
                                                            |
     ]])
+    -- Also test virt_lines when 'cpoptions' includes "n"
+    exec_lua([[
+      vim.opt.cpoptions:append("n")
+      local ns = vim.api.nvim_create_namespace("ns")
+      vim.api.nvim_buf_set_extmark(0, ns, 14, 0, { virt_lines = {{{"virt_line1", ""}}} })
+      vim.api.nvim_buf_set_extmark(0, ns, 14, 0, { virt_lines = {{{"virt_line2", ""}}} })
+    ]])
+    screen:expect([[
+      {1:buffer  0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+      aaaaaaaaa                                            |
+      {1:buffer  0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+      aaaaaaaaa                                            |
+      {1:buffer  0 15}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+      aaaaaaaaa                                            |
+      {1:virtual-2 15}virt_line1                               |
+      {1:virtual-2 15}virt_line2                               |
+      {1:buffer  0 16}{5:^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+      {5:aaaaaaaaa                                            }|
+      {1:virtual-1 16}END                                      |
+      {0:~                                                    }|
+      {0:~                                                    }|
+                                                           |
+    ]])
   end)
 
   it("works with 'statuscolumn' clicks", function()
-- 
cgit 


From 0e4086b74189c2b31ce63c6c5e85124edaf20d08 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 10 Apr 2023 18:06:59 +0800
Subject: fix(eval): prevent double-free in garbage collection (#22990)

---
 test/functional/vimscript/eval_spec.lua | 35 +++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua
index b995aaa5a6..b411b1e379 100644
--- a/test/functional/vimscript/eval_spec.lua
+++ b/test/functional/vimscript/eval_spec.lua
@@ -220,3 +220,38 @@ describe('listing functions using :function', function()
     assert_alive()
   end)
 end)
+
+it('no double-free in garbage collection #16287', function()
+  clear()
+  -- Don't use exec() here as using a named script reproduces the issue better.
+  write_file('Xgarbagecollect.vim', [[
+    func Foo() abort
+      let s:args = [a:000]
+      let foo0 = ""
+      let foo1 = ""
+      let foo2 = ""
+      let foo3 = ""
+      let foo4 = ""
+      let foo5 = ""
+      let foo6 = ""
+      let foo7 = ""
+      let foo8 = ""
+      let foo9 = ""
+      let foo10 = ""
+      let foo11 = ""
+      let foo12 = ""
+      let foo13 = ""
+      let foo14 = ""
+    endfunc
+
+    set updatetime=1
+    call Foo()
+    call Foo()
+  ]])
+  finally(function()
+    os.remove('Xgarbagecollect.vim')
+  end)
+  command('source Xgarbagecollect.vim')
+  sleep(10)
+  assert_alive()
+end)
-- 
cgit 


From da979ae04b7a8c56586ed0233957600ad6af99f0 Mon Sep 17 00:00:00 2001
From: Munif Tanjim 
Date: Sun, 2 Apr 2023 23:01:10 +0600
Subject: fix(api): do not re-apply win_config.style when missing

---
 test/functional/ui/float_spec.lua | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 32f28dce26..6d9197e1df 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -432,6 +432,25 @@ describe('float window', function()
     assert_alive()
   end)
 
+  it("should re-apply 'style' when present", function()
+    local float_opts = {style = 'minimal', relative = 'editor', row = 1, col = 1, width = 1, height = 1}
+    local float_win = meths.open_win(0, true, float_opts)
+    meths.win_set_option(float_win, 'number', true)
+    float_opts.row = 2
+    meths.win_set_config(float_win, float_opts)
+    eq(false, meths.win_get_option(float_win, 'number'))
+  end)
+
+  it("should not re-apply 'style' when missing", function()
+    local float_opts = {style = 'minimal', relative = 'editor', row = 1, col = 1, width = 1, height = 1}
+    local float_win = meths.open_win(0, true, float_opts)
+    meths.win_set_option(float_win, 'number', true)
+    float_opts.row = 2
+    float_opts.style = nil
+    meths.win_set_config(float_win, float_opts)
+    eq(true, meths.win_get_option(float_win, 'number'))
+  end)
+
   it("'scroll' is computed correctly when opening float with splitkeep=screen #20684", function()
     meths.set_option('splitkeep', 'screen')
     local float_opts = {relative = 'editor', row = 1, col = 1, width = 10, height = 10}
-- 
cgit 


From 0451391ec514eb83c7e366b80fcab21de9f8d4ed Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 10 Apr 2023 22:49:32 +0800
Subject: fix(mark): properly init mark views (#22996)

---
 test/functional/editor/mark_spec.lua | 44 ++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/editor/mark_spec.lua b/test/functional/editor/mark_spec.lua
index 365f8527a0..a6e4b0c5eb 100644
--- a/test/functional/editor/mark_spec.lua
+++ b/test/functional/editor/mark_spec.lua
@@ -417,4 +417,48 @@ describe('named marks view', function()
                   |
       ]])
   end)
+
+  it('fallback to standard behavior when mark is loaded from shada', function()
+    local screen = Screen.new(10, 6)
+    screen:attach()
+    command('edit ' .. file1)
+    feed('G')
+    feed('mA')
+    screen:expect([[
+      26 line     |
+      27 line     |
+      28 line     |
+      29 line     |
+      ^30 line     |
+                  |
+    ]])
+    command('set shadafile=Xtestfile-functional-editor-marks-shada')
+    finally(function()
+      command('set shadafile=NONE')
+      os.remove('Xtestfile-functional-editor-marks-shada')
+    end)
+    command('wshada!')
+    command('bwipe!')
+    screen:expect([[
+      ^            |
+      ~           |
+      ~           |
+      ~           |
+      ~           |
+                  |
+    ]])
+    command('rshada!')
+    command('edit ' .. file1)
+    feed('`"')
+    screen:expect([[
+      26 line     |
+      27 line     |
+      28 line     |
+      29 line     |
+      ^30 line     |
+                  |
+    ]])
+    feed('`A')
+    screen:expect_unchanged()
+  end)
 end)
-- 
cgit 


From dcaf2073369c672655722472aa4e7bcba7757f4c Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Tue, 11 Apr 2023 16:51:31 +0800
Subject: fix(highlight): combine ColorColumn with low-priority CursorLine
 (#23017)

---
 test/functional/ui/highlight_spec.lua | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index fedfaca7ba..89b503141b 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -1411,10 +1411,10 @@ describe('ColorColumn highlight', function()
       [3] = {foreground = Screen.colors.Brown},  -- LineNr
       [4] = {foreground = Screen.colors.Brown, bold = true},  -- CursorLineNr
       [5] = {foreground = Screen.colors.Blue, bold = true},  -- NonText
-      -- NonText and ColorColumn
       [6] = {foreground = Screen.colors.Blue, background = Screen.colors.LightRed, bold = true},
       [7] = {reverse = true, bold = true},  -- StatusLine
       [8] = {reverse = true},  -- StatusLineNC
+      [9] = {background = Screen.colors.Grey90, foreground = Screen.colors.Red},
     })
     screen:attach()
   end)
@@ -1500,6 +1500,25 @@ describe('ColorColumn highlight', function()
                                               |
     ]])
   end)
+
+  it('is combined with low-priority CursorLine highlight #23016', function()
+    screen:try_resize(40, 2)
+    command('set colorcolumn=30 cursorline')
+    screen:expect([[
+      {2:^                             }{1: }{2:          }|
+                                              |
+    ]])
+    command('hi clear ColorColumn')
+    screen:expect([[
+      {2:^                                        }|
+                                              |
+    ]])
+    command('hi ColorColumn guifg=Red')
+    screen:expect([[
+      {2:^                             }{9: }{2:          }|
+                                              |
+    ]])
+  end)
 end)
 
 describe("MsgSeparator highlight and msgsep fillchar", function()
-- 
cgit 


From aab95ec67e4d80e63cc5c5acc42f3832e76e0781 Mon Sep 17 00:00:00 2001
From: kylo252 <59826753+kylo252@users.noreply.github.com>
Date: Tue, 11 Apr 2023 11:18:54 +0200
Subject: test: avoid name collisions with Xtest directory (#23019)

---
 test/functional/autocmd/autocmd_oldtest_spec.lua |  7 ++++---
 test/functional/legacy/061_undo_tree_spec.lua    | 17 +++++++++--------
 test/functional/ui/messages_spec.lua             |  9 +++++----
 test/functional/vimscript/system_spec.lua        |  4 ++--
 4 files changed, 20 insertions(+), 17 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua
index 29d589a296..29a6171269 100644
--- a/test/functional/autocmd/autocmd_oldtest_spec.lua
+++ b/test/functional/autocmd/autocmd_oldtest_spec.lua
@@ -50,6 +50,7 @@ describe('oldtests', function()
   it('should fire on unload buf', function()
     funcs.writefile({'Test file Xxx1'}, 'Xxx1')
     funcs.writefile({'Test file Xxx2'}, 'Xxx2')
+    local fname = 'Xtest_functional_autocmd_unload'
 
     local content = [[
       func UnloadAllBufs()
@@ -69,15 +70,15 @@ describe('oldtests', function()
       q
     ]]
 
-    funcs.writefile(funcs.split(content, "\n"), 'Xtest')
+    funcs.writefile(funcs.split(content, "\n"), fname)
 
     funcs.delete('Xout')
-    funcs.system(meths.get_vvar('progpath') .. ' -u NORC -i NONE -N -S Xtest')
+    funcs.system(string.format('%s -u NORC -i NONE -N -S %s', meths.get_vvar('progpath'), fname))
     eq(1, funcs.filereadable('Xout'))
 
     funcs.delete('Xxx1')
     funcs.delete('Xxx2')
-    funcs.delete('Xtest')
+    funcs.delete(fname)
     funcs.delete('Xout')
   end)
 end)
diff --git a/test/functional/legacy/061_undo_tree_spec.lua b/test/functional/legacy/061_undo_tree_spec.lua
index 1a8ef067d0..b5af8f7d52 100644
--- a/test/functional/legacy/061_undo_tree_spec.lua
+++ b/test/functional/legacy/061_undo_tree_spec.lua
@@ -22,29 +22,30 @@ end
 
 describe('undo tree:', function()
   before_each(clear)
+  local fname = 'Xtest_functional_legacy_undotree'
   teardown(function()
-    os.remove('Xtest.source')
+    os.remove(fname .. '.source')
   end)
 
   describe(':earlier and :later', function()
     before_each(function()
-      os.remove('Xtest')
+      os.remove(fname)
     end)
     teardown(function()
-      os.remove('Xtest')
+      os.remove(fname)
     end)
 
     it('time specifications, g- g+', function()
       -- We write the test text to a file in order to prevent nvim to record
       -- the inserting of the text into the undo history.
-      write_file('Xtest', '\n123456789\n')
+      write_file(fname, '\n123456789\n')
 
       -- `:earlier` and `:later` are (obviously) time-sensitive, so this test
       -- sometimes fails if the system is under load. It is wrapped in a local
       -- function to allow multiple attempts.
       local function test_earlier_later()
         clear()
-        feed_command('e Xtest')
+        feed_command('e ' .. fname)
         -- Assert that no undo history is present.
         eq({}, eval('undotree().entries'))
         -- Delete three characters and undo.
@@ -103,7 +104,7 @@ describe('undo tree:', function()
 
     it('file-write specifications', function()
       feed('ione one one')
-      feed_command('w Xtest')
+      feed_command('w ' .. fname)
       feed('otwo')
       feed('otwo')
       feed_command('w')
@@ -187,7 +188,7 @@ describe('undo tree:', function()
 
   it('undo an expression-register', function()
     local normal_commands = 'o1\027a2\018=string(123)\n\027'
-    write_file('Xtest.source', normal_commands)
+    write_file(fname .. '.source', normal_commands)
 
     feed('oa')
     feed('ob')
@@ -221,7 +222,7 @@ describe('undo tree:', function()
       c
       12]])
     feed('od')
-    feed_command('so! Xtest.source')
+    feed_command('so! ' .. fname .. '.source')
     expect([[
 
       a
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 5220f3fa89..1a7fe26d26 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -22,6 +22,7 @@ local skip = helpers.skip
 
 describe('ui/ext_messages', function()
   local screen
+  local fname = 'Xtest_functional_ui_messages_spec'
 
   before_each(function()
     clear()
@@ -41,7 +42,7 @@ describe('ui/ext_messages', function()
     })
   end)
   after_each(function()
-    os.remove('Xtest')
+    os.remove(fname)
   end)
 
   it('msg_clear follows msg_show kind of confirm', function()
@@ -126,7 +127,7 @@ describe('ui/ext_messages', function()
     feed('nq')
 
     -- kind=wmsg (editing readonly file)
-    command('write Xtest')
+    command('write ' .. fname)
     command('set readonly nohls')
     feed('G$x')
     screen:expect{grid=[[
@@ -912,9 +913,9 @@ stack traceback:
   end)
 
   it('does not truncate messages', function()
-    command('write Xtest')
+    command('write '.. fname)
     screen:expect({messages={
-      {content = { { '"Xtest" [New] 0L, 0B written' } }, kind = "" }
+      {content = { { string.format('"%s" [New] 0L, 0B written', fname) } }, kind = "" }
     }})
   end)
 end)
diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua
index 158dfe86d7..130d5d81fa 100644
--- a/test/functional/vimscript/system_spec.lua
+++ b/test/functional/vimscript/system_spec.lua
@@ -393,7 +393,7 @@ describe('system()', function()
   end)
 
   describe('with output containing NULs', function()
-    local fname = 'Xtest'
+    local fname = 'Xtest_functional_vimscript_system_nuls'
 
     before_each(create_file_with_nuls(fname))
     after_each(delete_file(fname))
@@ -549,7 +549,7 @@ describe('systemlist()', function()
   end)
 
   describe('with output containing NULs', function()
-    local fname = 'Xtest'
+    local fname = 'Xtest_functional_vimscript_systemlist_nuls'
 
     before_each(function()
       command('set ff=unix')
-- 
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')

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 3c697f62fa0d941a8cfd287f38a159293905bac4 Mon Sep 17 00:00:00 2001
From: Michal Liszcz 
Date: Tue, 11 Apr 2023 18:37:27 +0200
Subject: test(lsp): fix unstable tests for set_defaults (#23002)

In the `test_rpc_server` procedure, both `on_setup` and `on_init`
callbacks can run concurrently in some scenarios. This caused some CI
failures in tests for the LSP set_defaults feature.

This commit attempts to fix this by merging those two callbacks in the
impacted tests.

See: https://github.com/neovim/neovim/actions/runs/4553550710/attempts/1
---
 test/functional/plugin/lsp_spec.lua | 31 +++++++++++++++----------------
 1 file changed, 15 insertions(+), 16 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index da05b09593..5ba0706208 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -323,15 +323,13 @@ describe('LSP', function()
       local client
       test_rpc_server {
         test_name = "set_defaults_all_capabilities";
-        on_setup = function()
+        on_init = function(_client)
+          client = _client
           exec_lua [[
             BUFFER = vim.api.nvim_create_buf(false, true)
+            lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
           ]]
         end;
-        on_init = function(_client)
-          client = _client
-          exec_lua("lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)")
-        end;
         on_handler = function(_, _, ctx)
           if ctx.method == 'test' then
             eq('v:lua.vim.lsp.tagfunc', get_buf_option("tagfunc"))
@@ -352,7 +350,8 @@ describe('LSP', function()
       local client
       test_rpc_server {
         test_name = "set_defaults_all_capabilities";
-        on_setup = function()
+        on_init = function(_client)
+          client = _client
           exec_lua [[
             vim.api.nvim_command('filetype plugin on')
             BUFFER_1 = vim.api.nvim_create_buf(false, true)
@@ -360,14 +359,16 @@ describe('LSP', function()
             vim.api.nvim_buf_set_option(BUFFER_1, 'filetype', 'man')
             vim.api.nvim_buf_set_option(BUFFER_2, 'filetype', 'xml')
           ]]
+
+          -- Sanity check to ensure that some values are set after setting filetype.
           eq('v:lua.require\'man\'.goto_tag', get_buf_option("tagfunc", "BUFFER_1"))
           eq('xmlcomplete#CompleteTags', get_buf_option("omnifunc", "BUFFER_2"))
           eq('xmlformat#Format()', get_buf_option("formatexpr", "BUFFER_2"))
-        end;
-        on_init = function(_client)
-          client = _client
-          exec_lua("lsp.buf_attach_client(BUFFER_1, TEST_RPC_CLIENT_ID)")
-          exec_lua("lsp.buf_attach_client(BUFFER_2, TEST_RPC_CLIENT_ID)")
+
+          exec_lua [[
+            lsp.buf_attach_client(BUFFER_1, TEST_RPC_CLIENT_ID)
+            lsp.buf_attach_client(BUFFER_2, TEST_RPC_CLIENT_ID)
+          ]]
         end;
         on_handler = function(_, _, ctx)
           if ctx.method == 'test' then
@@ -389,18 +390,16 @@ describe('LSP', function()
       local client
       test_rpc_server {
         test_name = "set_defaults_all_capabilities";
-        on_setup = function()
+        on_init = function(_client)
+          client = _client
           exec_lua [[
             BUFFER = vim.api.nvim_create_buf(false, true)
             vim.api.nvim_buf_set_option(BUFFER, 'tagfunc', 'tfu')
             vim.api.nvim_buf_set_option(BUFFER, 'omnifunc', 'ofu')
             vim.api.nvim_buf_set_option(BUFFER, 'formatexpr', 'fex')
+            lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
           ]]
         end;
-        on_init = function(_client)
-          client = _client
-          exec_lua("lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)")
-        end;
         on_handler = function(_, _, ctx)
           if ctx.method == 'test' then
             eq('tfu', get_buf_option("tagfunc"))
-- 
cgit 


From 2b35de386ee8854e1012feb4a6cc53b099220677 Mon Sep 17 00:00:00 2001
From: dundargoc <33953936+dundargoc@users.noreply.github.com>
Date: Wed, 12 Apr 2023 00:01:34 +0200
Subject: refactor: remove :CheckHealth

Using :CheckHealth invokes an error, and many of the features from :checkhealth
doesn't even work such as calling only a specific check. Users should use
:checkhealth instead.
---
 test/functional/core/startup_spec.lua | 2 --
 1 file changed, 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index cc94623df3..2a9d3edb33 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -402,8 +402,6 @@ describe('startup', function()
       local line1 = string.match(out, '^.-\n')
       -- updatecount=0 means swapfile was disabled.
       eq("  swapfile  updatecount=0  shadafile=\n", line1)
-      -- Standard plugins were loaded, but not user config.
-      eq('health.vim', string.match(out, 'health.vim'))
       eq(nil, string.match(out, 'init.vim'))
     end
   end)
-- 
cgit 


From 57e9b7f2e5c82316661888a88cad711fc72d5043 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 12 Apr 2023 09:17:32 +0800
Subject: test(startup_spec): use getscriptinfo() instead of :scriptnames
 (#23034)

---
 test/functional/core/startup_spec.lua | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 2a9d3edb33..b8a3c1dcd5 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -28,6 +28,9 @@ local meths = helpers.meths
 local alter_slashes = helpers.alter_slashes
 local is_os = helpers.is_os
 local dedent = helpers.dedent
+local tbl_map = helpers.tbl_map
+local tbl_filter = helpers.tbl_filter
+local endswith = helpers.endswith
 
 local testfile = 'Xtest_startuptime'
 after_each(function()
@@ -202,12 +205,12 @@ describe('startup', function()
     end)
 
     it('disables swapfile/shada/config/plugins', function()
-      assert_l_out('updatecount=0 shadafile=NONE loadplugins=false scriptnames=1',
+      assert_l_out('updatecount=0 shadafile=NONE loadplugins=false scripts=1',
         nil,
         nil,
         '-',
-        [[print(('updatecount=%d shadafile=%s loadplugins=%s scriptnames=%d'):format(
-          vim.o.updatecount, vim.o.shadafile, tostring(vim.o.loadplugins), math.max(1, #vim.fn.split(vim.fn.execute('scriptnames'),'\n'))))]])
+        [[print(('updatecount=%d shadafile=%s loadplugins=%s scripts=%d'):format(
+          vim.o.updatecount, vim.o.shadafile, tostring(vim.o.loadplugins), math.max(1, #vim.fn.getscriptinfo())))]])
     end)
   end)
 
@@ -398,11 +401,13 @@ describe('startup', function()
     for _,arg in ipairs({'-es', '-Es'}) do
       local out = funcs.system({nvim_prog, arg,
                                 '+set swapfile? updatecount? shadafile?',
-                                "+put =execute('scriptnames')", '+%print'})
+                                "+put =map(getscriptinfo(), {-> v:val.name})", '+%print'})
       local line1 = string.match(out, '^.-\n')
       -- updatecount=0 means swapfile was disabled.
       eq("  swapfile  updatecount=0  shadafile=\n", line1)
-      eq(nil, string.match(out, 'init.vim'))
+      -- Standard plugins were loaded, but not user config.
+      ok(string.find(out, 'man.lua') ~= nil)
+      ok(string.find(out, 'init.vim') == nil)
     end
   end)
 
@@ -863,6 +868,10 @@ describe('runtime:', function()
     local plugin_file_path = table.concat({plugin_folder_path, 'plugin.lua'},
     pathsep)
     local profiler_file = 'test_startuptime.log'
+    finally(function()
+      os.remove(profiler_file)
+      rmdir(plugin_path)
+    end)
 
     mkdir_p(plugin_folder_path)
     write_file(plugin_file_path, [[vim.g.lua_plugin = 2]])
@@ -870,18 +879,15 @@ describe('runtime:', function()
     clear{ args_rm={'-u'}, args={'--startuptime', profiler_file}, env=xenv }
 
     eq(2, eval('g:lua_plugin'))
-    -- Check if plugin_file_path is listed in :scriptname
-    local scripts = exec_capture('scriptnames')
-    assert(scripts:find(plugin_file_path))
+    -- Check if plugin_file_path is listed in getscriptinfo()
+    local scripts = tbl_map(function(s) return s.name end, funcs.getscriptinfo())
+    ok(#tbl_filter(function(s) return endswith(s, plugin_file_path) end, scripts) > 0)
 
     -- Check if plugin_file_path is listed in startup profile
     local profile_reader = io.open(profiler_file, 'r')
     local profile_log = profile_reader:read('*a')
     profile_reader:close()
-    assert(profile_log:find(plugin_file_path))
-
-    os.remove(profiler_file)
-    rmdir(plugin_path)
+    ok(profile_log:find(plugin_file_path) ~= nil)
   end)
 
   it('loads plugin/*.lua from site packages', function()
-- 
cgit 


From cdc028e97d9808c21e26fffe2d282b6517eaffc0 Mon Sep 17 00:00:00 2001
From: luukvbaal <31730729+luukvbaal@users.noreply.github.com>
Date: Wed, 12 Apr 2023 17:40:58 +0200
Subject: fix(column): add truncated width during estimation for 'statuscolumn'

Problem:    Estimated 'statuscolumn' width estimated is not properly used,
            executing the `w_redr_statuscol` path unnecessarily.
Solution:   Adjust `w_nrwidth` and 'statuscolumn' width before anything
            is actually drawn in a `win_update()`.
---
 test/functional/ui/statuscolumn_spec.lua | 13 +++++++++++++
 1 file changed, 13 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index 83c49e56a0..a2fe875e65 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -616,4 +616,17 @@ describe('statuscolumn', function()
                                                            |
     ]])
   end)
+
+  it("is only evaluated twice, once to estimate and once to draw", function()
+    command([[
+      let g:stcnr = 0
+      func! Stc()
+        let g:stcnr += 1
+        return '12345'
+      endfunc
+      set stc=%!Stc()
+      norm ggdG
+    ]])
+    eq(2, eval('g:stcnr'))
+  end)
 end)
-- 
cgit 


From d05d63a18ff8394b31b3f3b85bfaebe2af358437 Mon Sep 17 00:00:00 2001
From: bfredl 
Date: Thu, 13 Apr 2023 14:08:36 +0200
Subject: fix(api): make nvim_get_hl not return non-existing groups

fixes #23063
---
 test/functional/api/highlight_spec.lua | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index a4bd574a56..a6e9f9a42b 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -575,4 +575,25 @@ describe('API: get highlight', function()
     meths.set_hl(0, 'Foo', hl)
     eq(hl, meths.get_hl(0, { name = 'Foo', link = true }))
   end)
+
+  it("doesn't contain unset groups", function()
+    local id = meths.get_hl_id_by_name "@foobar.hubbabubba"
+    ok(id > 0)
+
+    local data = meths.get_hl(0, {})
+    eq(nil, data["@foobar.hubbabubba"])
+    eq(nil, data["@foobar"])
+
+    command 'hi @foobar.hubbabubba gui=bold'
+    data = meths.get_hl(0, {})
+    eq({bold = true}, data["@foobar.hubbabubba"])
+    eq(nil, data["@foobar"])
+
+    -- @foobar.hubbabubba was explicitly cleared and thus shows up
+    -- but @foobar was never touched, and thus doesn't
+    command 'hi clear @foobar.hubbabubba'
+    data = meths.get_hl(0, {})
+    eq({}, data["@foobar.hubbabubba"])
+    eq(nil, data["@foobar"])
+  end)
 end)
-- 
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')

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 bfb28b62dab756ec76a73506c2070ddf491a0cdd Mon Sep 17 00:00:00 2001
From: Gregory Anders <8965202+gpanders@users.noreply.github.com>
Date: Thu, 13 Apr 2023 15:29:13 -0600
Subject: refactor: remove modelines from Lua files

Now that we have builtin EditorConfig support and a formatting check in
CI, these are not necessary.
---
 test/functional/shada/merging_spec.lua | 2 --
 1 file changed, 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/shada/merging_spec.lua b/test/functional/shada/merging_spec.lua
index da2fbbe029..dad7aa851d 100644
--- a/test/functional/shada/merging_spec.lua
+++ b/test/functional/shada/merging_spec.lua
@@ -1115,5 +1115,3 @@ describe('ShaDa changes support code', function()
     eq(found, 100)
   end)
 end)
-
--- vim: ts=2 sw=2
-- 
cgit 


From 80f6d55521cd25e7746e34b899be5532ea88c09b Mon Sep 17 00:00:00 2001
From: quintik <28828855+quintik@users.noreply.github.com>
Date: Thu, 13 Apr 2023 06:17:05 -0400
Subject: test(winbar_spec): properly update winbar when 'showcmdloc' is
 "statusline"

Co-authored-by: zeertzjq 
Co-authored-by: Luuk van Baal 
---
 test/functional/ui/winbar_spec.lua | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua
index ece27ec3ff..970f9c3d76 100644
--- a/test/functional/ui/winbar_spec.lua
+++ b/test/functional/ui/winbar_spec.lua
@@ -114,6 +114,41 @@ describe('winbar', function()
       {2:[No Name]                     [No Name]                     }|
                                                                   |
     ]])
+    -- 'showcmdloc' "statusline" should not interfere with winbar redrawing #23030
+    command('set showcmd showcmdloc=statusline')
+    feed('w')
+    feed('')
+    screen:expect([[
+      {6:Set Up The Bars              }│{6:Set Up The Bars               }|
+                                   │                              |
+      {3:~                            }│{3:~                             }|
+      {3:~                            }│{2:[No Name]                     }|
+      {3:~                            }│{5:Set Up The Bars               }|
+      {3:~                            }│^                              |
+      {3:~                            }│{3:~                             }|
+      {3:~                            }│{4:[No Name]          ^W         }|
+      {3:~                            }│{6:Set Up The Bars               }|
+      {3:~                            }│                              |
+      {3:~                            }│{3:~                             }|
+      {2:[No Name]                     [No Name]                     }|
+                                                                  |
+    ]])
+    feed('wW')
+    screen:expect([[
+      {6:Set Up The Bars              }│{6:Set Up The Bars               }|
+                                   │                              |
+      {3:~                            }│{3:~                             }|
+      {3:~                            }│{2:[No Name]                     }|
+      {3:~                            }│{5:Set Up The Bars               }|
+      {3:~                            }│^                              |
+      {3:~                            }│{3:~                             }|
+      {3:~                            }│{4:[No Name]                     }|
+      {3:~                            }│{6:Set Up The Bars               }|
+      {3:~                            }│                              |
+      {3:~                            }│{3:~                             }|
+      {2:[No Name]                     [No Name]                     }|
+                                                                  |
+    ]])
   end)
 
   it('works when switching value of \'winbar\'', function()
-- 
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')

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')

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 c08b03076167837cff9eb66c19440d727e6dad31 Mon Sep 17 00:00:00 2001
From: dundargoc <33953936+dundargoc@users.noreply.github.com>
Date: Sat, 15 Apr 2023 23:40:48 +0200
Subject: refactor: deprecate checkhealth functions

The following functions are deprecated and will be removed in
Nvim v0.11:

- health#report_start()
- health#report_info()
- health#report_ok()
- health#report_warn()
- health#report_error()
- vim.health.report_start()
- vim.health.report_info()
- vim.health.report_ok()
- vim.health.report_warn()
- vim.health.report_error()

Users should instead use these:

- vim.health.start()
- vim.health.info()
- vim.health.ok()
- vim.health.warn()
- vim.health.error()
---
 .../functional/fixtures/autoload/health/broken.vim |   3 -
 .../fixtures/autoload/health/full_render.vim       |   8 --
 .../fixtures/autoload/health/success1.vim          |   6 --
 .../fixtures/autoload/health/success2.vim          |   4 -
 .../lua/test_plug/autoload/health/test_plug.vim    |   3 -
 .../fixtures/lua/test_plug/full_render/health.lua  |  12 +++
 .../fixtures/lua/test_plug/health/init.lua         |   8 +-
 .../fixtures/lua/test_plug/submodule/health.lua    |   8 +-
 .../lua/test_plug/submodule_failed/health.lua      |  11 ---
 .../fixtures/lua/test_plug/success1/health.lua     |  10 ++
 .../fixtures/lua/test_plug/success2/health.lua     |   8 ++
 test/functional/plugin/health_spec.lua             | 109 ++-------------------
 12 files changed, 47 insertions(+), 143 deletions(-)
 delete mode 100644 test/functional/fixtures/autoload/health/broken.vim
 delete mode 100644 test/functional/fixtures/autoload/health/full_render.vim
 delete mode 100644 test/functional/fixtures/autoload/health/success1.vim
 delete mode 100644 test/functional/fixtures/autoload/health/success2.vim
 delete mode 100644 test/functional/fixtures/lua/test_plug/autoload/health/test_plug.vim
 create mode 100644 test/functional/fixtures/lua/test_plug/full_render/health.lua
 delete mode 100644 test/functional/fixtures/lua/test_plug/submodule_failed/health.lua
 create mode 100644 test/functional/fixtures/lua/test_plug/success1/health.lua
 create mode 100644 test/functional/fixtures/lua/test_plug/success2/health.lua

(limited to 'test/functional')

diff --git a/test/functional/fixtures/autoload/health/broken.vim b/test/functional/fixtures/autoload/health/broken.vim
deleted file mode 100644
index a2a595b96f..0000000000
--- a/test/functional/fixtures/autoload/health/broken.vim
+++ /dev/null
@@ -1,3 +0,0 @@
-function! health#broken#check()
-  throw 'caused an error'
-endfunction
diff --git a/test/functional/fixtures/autoload/health/full_render.vim b/test/functional/fixtures/autoload/health/full_render.vim
deleted file mode 100644
index 2064b8606e..0000000000
--- a/test/functional/fixtures/autoload/health/full_render.vim
+++ /dev/null
@@ -1,8 +0,0 @@
-function! health#full_render#check()
-  call health#report_start("report 1")
-  call health#report_ok("life is fine")
-  call health#report_warn("no what installed", ["pip what", "make what"])
-  call health#report_start("report 2")
-  call health#report_info("stuff is stable")
-  call health#report_error("why no hardcopy", [":h :hardcopy", ":h :TOhtml"])
-endfunction
diff --git a/test/functional/fixtures/autoload/health/success1.vim b/test/functional/fixtures/autoload/health/success1.vim
deleted file mode 100644
index a360347455..0000000000
--- a/test/functional/fixtures/autoload/health/success1.vim
+++ /dev/null
@@ -1,6 +0,0 @@
-function! health#success1#check()
-  call health#report_start("report 1")
-  call health#report_ok("everything is fine")
-  call health#report_start("report 2")
-  call health#report_ok("nothing to see here")
-endfunction
diff --git a/test/functional/fixtures/autoload/health/success2.vim b/test/functional/fixtures/autoload/health/success2.vim
deleted file mode 100644
index b742b4879d..0000000000
--- a/test/functional/fixtures/autoload/health/success2.vim
+++ /dev/null
@@ -1,4 +0,0 @@
-function! health#success2#check()
-  call health#report_start("another 1")
-  call health#report_ok("ok")
-endfunction
diff --git a/test/functional/fixtures/lua/test_plug/autoload/health/test_plug.vim b/test/functional/fixtures/lua/test_plug/autoload/health/test_plug.vim
deleted file mode 100644
index de05f56e9e..0000000000
--- a/test/functional/fixtures/lua/test_plug/autoload/health/test_plug.vim
+++ /dev/null
@@ -1,3 +0,0 @@
-function! health#success1#check()
-  call health#report_start("If you see this I'm broken")
-endfunction
diff --git a/test/functional/fixtures/lua/test_plug/full_render/health.lua b/test/functional/fixtures/lua/test_plug/full_render/health.lua
new file mode 100644
index 0000000000..10833f6239
--- /dev/null
+++ b/test/functional/fixtures/lua/test_plug/full_render/health.lua
@@ -0,0 +1,12 @@
+local M = {}
+
+M.check = function()
+  vim.health.start('report 1')
+  vim.health.ok('life is fine')
+  vim.health.warn('no what installed', { 'pip what', 'make what' })
+  vim.health.start('report 2')
+  vim.health.info('stuff is stable')
+  vim.health.error('why no hardcopy', { ':h :hardcopy', ':h :TOhtml' })
+end
+
+return M
diff --git a/test/functional/fixtures/lua/test_plug/health/init.lua b/test/functional/fixtures/lua/test_plug/health/init.lua
index 58162d4515..ef0c5ae3cd 100644
--- a/test/functional/fixtures/lua/test_plug/health/init.lua
+++ b/test/functional/fixtures/lua/test_plug/health/init.lua
@@ -1,10 +1,10 @@
 local M = {}
 
 M.check = function()
-  vim.health.report_start("report 1")
-  vim.health.report_ok("everything is fine")
-  vim.health.report_start("report 2")
-  vim.health.report_ok("nothing to see here")
+  vim.health.start('report 1')
+  vim.health.ok('everything is fine')
+  vim.health.start('report 2')
+  vim.health.ok('nothing to see here')
 end
 
 return M
diff --git a/test/functional/fixtures/lua/test_plug/submodule/health.lua b/test/functional/fixtures/lua/test_plug/submodule/health.lua
index 58162d4515..ef0c5ae3cd 100644
--- a/test/functional/fixtures/lua/test_plug/submodule/health.lua
+++ b/test/functional/fixtures/lua/test_plug/submodule/health.lua
@@ -1,10 +1,10 @@
 local M = {}
 
 M.check = function()
-  vim.health.report_start("report 1")
-  vim.health.report_ok("everything is fine")
-  vim.health.report_start("report 2")
-  vim.health.report_ok("nothing to see here")
+  vim.health.start('report 1')
+  vim.health.ok('everything is fine')
+  vim.health.start('report 2')
+  vim.health.ok('nothing to see here')
 end
 
 return M
diff --git a/test/functional/fixtures/lua/test_plug/submodule_failed/health.lua b/test/functional/fixtures/lua/test_plug/submodule_failed/health.lua
deleted file mode 100644
index ee5f4e404b..0000000000
--- a/test/functional/fixtures/lua/test_plug/submodule_failed/health.lua
+++ /dev/null
@@ -1,11 +0,0 @@
-local M = {}
-
-M.check = function()
-  vim.health.report_start("report 1")
-  vim.health.report_ok("everything is fine")
-  vim.health.report_warn("About to add a number to nil")
-  local a = nil + 2
-  return a
-end
-
-return M
diff --git a/test/functional/fixtures/lua/test_plug/success1/health.lua b/test/functional/fixtures/lua/test_plug/success1/health.lua
new file mode 100644
index 0000000000..ef0c5ae3cd
--- /dev/null
+++ b/test/functional/fixtures/lua/test_plug/success1/health.lua
@@ -0,0 +1,10 @@
+local M = {}
+
+M.check = function()
+  vim.health.start('report 1')
+  vim.health.ok('everything is fine')
+  vim.health.start('report 2')
+  vim.health.ok('nothing to see here')
+end
+
+return M
diff --git a/test/functional/fixtures/lua/test_plug/success2/health.lua b/test/functional/fixtures/lua/test_plug/success2/health.lua
new file mode 100644
index 0000000000..240a2d33de
--- /dev/null
+++ b/test/functional/fixtures/lua/test_plug/success2/health.lua
@@ -0,0 +1,8 @@
+local M = {}
+
+M.check = function()
+  vim.health.start('another 1')
+  vim.health.ok('ok')
+end
+
+return M
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index 97d32313e5..926e12ec32 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -1,5 +1,4 @@
 local helpers = require('test.functional.helpers')(after_each)
-local global_helpers = require('test.helpers')
 local Screen = require('test.functional.ui.screen')
 
 local clear = helpers.clear
@@ -43,20 +42,17 @@ end)
 describe('health.vim', function()
   before_each(function()
     clear{args={'-u', 'NORC'}}
-    -- Provides functions:
-    --    health#broken#check()
-    --    health#success1#check()
-    --    health#success2#check()
+    -- Provides healthcheck functions
     command("set runtimepath+=test/functional/fixtures")
   end)
 
   describe(":checkhealth", function()
-    it("functions health#report_*() render correctly", function()
+    it("functions report_*() render correctly", function()
       command("checkhealth full_render")
       helpers.expect([[
 
       ==============================================================================
-      full_render: health#full_render#check
+      test_plug.full_render: require("test_plug.full_render.health").check()
 
       report 1 ~
       - OK life is fine
@@ -79,7 +75,7 @@ describe('health.vim', function()
       helpers.expect([[
 
         ==============================================================================
-        success1: health#success1#check
+        test_plug: require("test_plug.health").check()
 
         report 1 ~
         - OK everything is fine
@@ -88,36 +84,19 @@ describe('health.vim', function()
         - OK nothing to see here
 
         ==============================================================================
-        success2: health#success2#check
-
-        another 1 ~
-        - OK ok
-
-        ==============================================================================
-        test_plug: require("test_plug.health").check()
+        test_plug.success1: require("test_plug.success1.health").check()
 
         report 1 ~
         - OK everything is fine
 
         report 2 ~
         - OK nothing to see here
-        ]])
-    end)
-
-    it("lua plugins, skips vimscript healthchecks with the same name", function()
-      command("checkhealth test_plug")
-      -- Existing file in test/functional/fixtures/lua/test_plug/autoload/health/test_plug.vim
-      -- and the Lua healthcheck is used instead.
-      helpers.expect([[
 
         ==============================================================================
-        test_plug: require("test_plug.health").check()
-
-        report 1 ~
-        - OK everything is fine
+        test_plug.success2: require("test_plug.success2.health").check()
 
-        report 2 ~
-        - OK nothing to see here
+        another 1 ~
+        - OK ok
         ]])
     end)
 
@@ -136,57 +115,6 @@ describe('health.vim', function()
         ]])
     end)
 
-    it("lua plugins submodules with expression '*'", function()
-      command("checkhealth test_plug*")
-      local buf_lines = helpers.curbuf('get_lines', 0, -1, true)
-      -- avoid dealing with path separators
-      local received = table.concat(buf_lines, '\n', 1, #buf_lines - 5)
-      local expected = helpers.dedent([[
-
-        ==============================================================================
-        test_plug: require("test_plug.health").check()
-
-        report 1 ~
-        - OK everything is fine
-
-        report 2 ~
-        - OK nothing to see here
-
-        ==============================================================================
-        test_plug.submodule: require("test_plug.submodule.health").check()
-
-        report 1 ~
-        - OK everything is fine
-
-        report 2 ~
-        - OK nothing to see here
-
-        ==============================================================================
-        test_plug.submodule_empty: require("test_plug.submodule_empty.health").check()
-
-        - ERROR The healthcheck report for "test_plug.submodule_empty" plugin is empty.
-
-        ==============================================================================
-        test_plug.submodule_failed: require("test_plug.submodule_failed.health").check()
-
-        - ERROR Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
-          function health#check, line 25]])
-      eq(expected, received)
-    end)
-
-    it("gracefully handles broken healthcheck", function()
-      command("checkhealth broken")
-      helpers.expect([[
-
-        ==============================================================================
-        broken: health#broken#check
-
-        - ERROR Failed to run healthcheck for "broken" plugin. Exception:
-          function health#check[25]..health#broken#check, line 1
-          caused an error
-        ]])
-    end)
-
     it("... including empty reports", function()
       command("checkhealth test_plug.submodule_empty")
       helpers.expect([[
@@ -198,25 +126,6 @@ describe('health.vim', function()
       ]])
     end)
 
-    it("gracefully handles broken lua healthcheck", function()
-      command("checkhealth test_plug.submodule_failed")
-      local buf_lines = helpers.curbuf('get_lines', 0, -1, true)
-      local received = table.concat(buf_lines, '\n', 1, #buf_lines - 5)
-      -- avoid dealing with path separators
-      local lua_err = "attempt to perform arithmetic on a nil value"
-      local last_line = buf_lines[#buf_lines - 4]
-      assert(string.find(last_line, lua_err) ~= nil, "Lua error not present")
-
-      local expected = global_helpers.dedent([[
-
-        ==============================================================================
-        test_plug.submodule_failed: require("test_plug.submodule_failed.health").check()
-
-        - ERROR Failed to run healthcheck for "test_plug.submodule_failed" plugin. Exception:
-          function health#check, line 25]])
-      eq(expected, received)
-    end)
-
     it("highlights OK, ERROR", function()
       local screen = Screen.new(50, 12)
       screen:attach()
@@ -236,7 +145,7 @@ describe('health.vim', function()
         - {Error:ERROR} No healthcheck found for "foo" plugin.    |
                                                           |
         {Bar:──────────────────────────────────────────────────}|
-        {Heading:success1: health#success1#check}                   |
+        {Heading:test_plug.success1: require("test_plug.success1.he}|
                                                           |
         {Heading:report 1}                                          |
         - {Ok:OK} everything is fine                           |
-- 
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')

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')

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/legacy/delete_spec.lua |  2 +-
 test/functional/lua/api_spec.lua       |  4 ++--
 test/functional/lua/luaeval_spec.lua   | 10 +++++-----
 3 files changed, 8 insertions(+), 8 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/delete_spec.lua b/test/functional/legacy/delete_spec.lua
index cefcd6c6c4..1b9ec9af62 100644
--- a/test/functional/legacy/delete_spec.lua
+++ b/test/functional/legacy/delete_spec.lua
@@ -63,6 +63,6 @@ describe('Test for delete()', function()
 
   it('gives correct emsgs', function()
     eq('Vim(call):E474: Invalid argument', exc_exec("call delete('')"))
-    eq('Vim(call):E15: Invalid expression: 0', exc_exec("call delete('foo', 0)"))
+    eq('Vim(call):E15: Invalid expression: "0"', exc_exec("call delete('foo', 0)"))
   end)
 end)
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 75d9c413d49261b8f9a96f45edda0af9f0e8d947 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 17 Apr 2023 17:44:08 +0800
Subject: fix(excmd): make :def unknown rather than unimplemented (#23150)

---
 test/functional/ex_cmds/excmd_spec.lua | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ex_cmds/excmd_spec.lua b/test/functional/ex_cmds/excmd_spec.lua
index e243f3c524..b313d6428c 100644
--- a/test/functional/ex_cmds/excmd_spec.lua
+++ b/test/functional/ex_cmds/excmd_spec.lua
@@ -2,6 +2,7 @@ local helpers = require("test.functional.helpers")(after_each)
 local command = helpers.command
 local eq = helpers.eq
 local clear = helpers.clear
+local funcs = helpers.funcs
 local pcall_err = helpers.pcall_err
 local assert_alive = helpers.assert_alive
 
@@ -26,5 +27,18 @@ describe('Ex cmds', function()
       pcall_err(command, ':bdelete 9999999999999999999999999999999999999999'))
     assert_alive()
   end)
-end)
 
+  it(':def is an unknown command #23149', function()
+    eq('Vim:E492: Not an editor command: def', pcall_err(command, 'def'))
+    eq(1, funcs.exists(':d'))
+    eq('delete', funcs.fullcommand('d'))
+    eq(1, funcs.exists(':de'))
+    eq('delete', funcs.fullcommand('de'))
+    eq(0, funcs.exists(':def'))
+    eq('', funcs.fullcommand('def'))
+    eq(1, funcs.exists(':defe'))
+    eq('defer', funcs.fullcommand('defe'))
+    eq(2, funcs.exists(':defer'))
+    eq('defer', funcs.fullcommand('defer'))
+  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')

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')

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 7095f8ff9d9ce3519abe34a3da4c8f4bdc3fc865 Mon Sep 17 00:00:00 2001
From: Sean Dewar 
Date: Mon, 17 Apr 2023 17:32:32 +0100
Subject: vim-patch:9.0.1461: ruler not drawn correctly when using
 'rulerformat'

Problem:    Ruler not drawn correctly when using 'rulerformat'.
Solution:   Adjust formatting depending on whether the ruler is drawn in the
            statusline or the command line. (Sean Dewar, closes vim/vim#12246)

https://github.com/vim/vim/commit/fc8a601c3251c0388a88c1235b18c529385f7196

This issue was made apparent after neovim/neovim@0f1e2b6, as `showmode()` calls
`win_redr_ruler()` with `curwin` now if it's floating, rather than the last
window if there's no statusline (which usually already shares its right side
with that of the editor).

Co-authored-by: Sean Dewar 
---
 test/functional/legacy/cmdline_spec.lua | 19 ++++++++++++++
 test/functional/ui/float_spec.lua       | 45 +++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua
index 2fceb6a132..f7df6ae8d7 100644
--- a/test/functional/legacy/cmdline_spec.lua
+++ b/test/functional/legacy/cmdline_spec.lua
@@ -239,6 +239,25 @@ describe('cmdline', function()
                                                                   |
     ]])
   end)
+
+  -- oldtest: Test_rulerformat_position()
+  it("ruler has correct position with 'rulerformat' set", function()
+    local screen = Screen.new(20, 3)
+    screen:set_default_attr_ids {
+      [0] = {bold = true, foreground = Screen.colors.Blue},  -- NonText
+    }
+    screen:attach()
+    meths.set_option('ruler', true)
+    meths.set_option('rulerformat', 'longish')
+    meths.set_option('laststatus', 0)
+    meths.set_option('winwidth', 1)
+    feed [[v|p]]
+    screen:expect [[
+                        │^ |
+      {0:~                 }│{0:~}|
+                longish   |
+    ]]
+  end)
 end)
 
 describe('cmdwin', function()
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 3203b187cc..0e1842d087 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -2295,6 +2295,51 @@ describe('float window', function()
       end
     end)
 
+    it("correct ruler position in current float with 'rulerformat' set", function()
+      command 'set ruler rulerformat=fish:<><'
+      meths.open_win(0, true, {relative='editor', width=9, height=3, row=0, col=5})
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [3:----------------------------------------]|
+        ## grid 2
+                                                  |
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+        ## grid 3
+                                fish:<><          |
+        ## grid 4
+          {1:^         }|
+          {2:~        }|
+          {2:~        }|
+        ]], float_pos={
+          [4] = {{id = 1001}, "NW", 1, 0, 5, true, 50};
+        }, win_viewport={
+          [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+          [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+        }}
+      else
+        screen:expect{grid=[[
+               {1:^         }                          |
+          {0:~    }{2:~        }{0:                          }|
+          {0:~    }{2:~        }{0:                          }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+                                fish:<><          |
+        ]]}
+      end
+    end)
+
     it('can have minimum size', function()
       insert("the background text")
       local buf = meths.create_buf(false, true)
-- 
cgit 


From 65dd3c1180cef5ec15a46bd278ab3a0cb1c3460d Mon Sep 17 00:00:00 2001
From: Sean Dewar 
Date: Mon, 10 Apr 2023 21:40:35 +0100
Subject: fix(ruler): show ruler of curwin with no statusline in cmdline

Problem: After neovim/neovim@846a056, only the ruler for current floating or
last window without a statusline is drawn in the cmdline. This means that if the
current window is not one of these, but has no statusline, its ruler will not be
drawn anymore.

Solution: Make `showmode()` draw the ruler of the current window or the last
window in the cmdline if it has no statusline. This also maintains the
previously restored floating window case (`float->w_status_height` should be 0).

This behaviour should again match Vim, but without the overdraw it seems to do
to achieve the same effect; it calls `showmode()` to draw the ruler for the last
window without a statusline, then may draw over it in `showruler()` (which is
now `show_cursor_info_later()` in Nvim) to show the ruler for the current
window..? It's very confusing.

Also update the logic in `win_redr_ruler()` to mirror the check done in
`showmode()`, so that the ruler doesn't potentially draw over the long
ins-completion mode message in some cases.
---
 test/functional/ui/float_spec.lua      | 115 +++++++++++++++++++++++++++++++++
 test/functional/ui/statusline_spec.lua |  59 +++++++++++++++++
 2 files changed, 174 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 0e1842d087..e2fe0a2df5 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -2340,6 +2340,121 @@ describe('float window', function()
       end
     end)
 
+    it('does not show ruler of not-last current float during ins-completion', function()
+      screen:try_resize(50,9)
+      command 'set ruler showmode'
+      meths.open_win(0, false, {relative='editor', width=3, height=3, row=0, col=0})
+      meths.open_win(0, false, {relative='editor', width=3, height=3, row=0, col=5})
+      feed 'w'
+      neq('', meths.win_get_config(0).relative)
+      neq(funcs.winnr '$', funcs.winnr())
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [3:--------------------------------------------------]|
+        ## grid 2
+                                                            |
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+        ## grid 3
+                                          0,0-1         All |
+        ## grid 4
+          {1:   }|
+          {2:~  }|
+          {2:~  }|
+        ## grid 5
+          {1:^   }|
+          {2:~  }|
+          {2:~  }|
+        ]], float_pos={
+          [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50};
+          [4] = {{id = 1001}, "NW", 1, 0, 0, true, 50};
+        }, win_viewport={
+          [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+          [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+          [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+        }}
+      else
+        screen:expect{grid=[[
+          {1:   }  {1:^   }                                          |
+          {2:~  }{0:  }{2:~  }{0:                                          }|
+          {2:~  }{0:  }{2:~  }{0:                                          }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+                                          0,0-1         All |
+        ]]}
+      end
+      feed 'i'
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [3:--------------------------------------------------]|
+        ## grid 2
+                                                            |
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+        ## grid 3
+          {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)}          |
+        ## grid 4
+          {1:   }|
+          {2:~  }|
+          {2:~  }|
+        ## grid 5
+          {1:^   }|
+          {2:~  }|
+          {2:~  }|
+        ]], float_pos={
+          [5] = {{id = 1002}, "NW", 1, 0, 5, true, 50};
+          [4] = {{id = 1001}, "NW", 1, 0, 0, true, 50};
+        }, win_viewport={
+          [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+          [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+          [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+        }}
+      else
+        screen:expect{grid=[[
+          {1:   }  {1:^   }                                          |
+          {2:~  }{0:  }{2:~  }{0:                                          }|
+          {2:~  }{0:  }{2:~  }{0:                                          }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {0:~                                                 }|
+          {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)}          |
+        ]]}
+      end
+    end)
+
     it('can have minimum size', function()
       insert("the background text")
       local buf = meths.create_buf(false, true)
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
index 8e301dc70c..c41d4983a7 100644
--- a/test/functional/ui/statusline_spec.lua
+++ b/test/functional/ui/statusline_spec.lua
@@ -653,3 +653,62 @@ it('ruler is redrawn in cmdline with redrawstatus #22804', function()
                           other value       |
   ]])
 end)
+
+it("shows correct ruler in cmdline with no statusline", function()
+  clear()
+  local screen = Screen.new(30, 8)
+  screen:set_default_attr_ids {
+    [1] = {bold = true, foreground = Screen.colors.Blue},  -- NonText
+    [2] = {bold = true, reverse = true},  -- StatusLine
+    [3] = {reverse = true},  -- StatusLineNC
+  }
+  screen:attach()
+  -- Use long ruler to check 'ruler' with 'rulerformat' set has correct width.
+  command [[
+    set ruler rulerformat=%{winnr()}longlonglong ls=0 winwidth=10
+    split
+    wincmd b
+    vsplit
+    wincmd t
+    wincmd |
+    mode
+  ]]
+  -- Window 1 is current. It has a statusline, so cmdline should show the
+  -- last window's ruler, which has no statusline.
+  command '1wincmd w'
+  screen:expect [[
+    ^                              |
+    {1:~                             }|
+    {1:~                             }|
+    {2:[No Name]      1longlonglong  }|
+                   │              |
+    {1:~              }│{1:~             }|
+    {1:~              }│{1:~             }|
+                   3longlonglong  |
+  ]]
+  -- Window 2 is current. It has no statusline, so cmdline should show its
+  -- ruler instead.
+  command '2wincmd w'
+  screen:expect [[
+                                  |
+    {1:~                             }|
+    {1:~                             }|
+    {3:[No Name]      1longlonglong  }|
+    ^               │              |
+    {1:~              }│{1:~             }|
+    {1:~              }│{1:~             }|
+                   2longlonglong  |
+  ]]
+  -- Window 3 is current. Cmdline should again show its ruler.
+  command '3wincmd w'
+  screen:expect [[
+                                  |
+    {1:~                             }|
+    {1:~                             }|
+    {3:[No Name]      1longlonglong  }|
+                   │^              |
+    {1:~              }│{1:~             }|
+    {1:~              }│{1:~             }|
+                   3longlonglong  |
+  ]]
+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')

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 84a4319545ad280d48a41e4cafaf0622c4278a16 Mon Sep 17 00:00:00 2001
From: luukvbaal 
Date: Tue, 18 Apr 2023 02:00:49 +0200
Subject: fix(mouse): cmdline click registered as statuscolumn (#23163)

---
 test/functional/ui/statuscolumn_spec.lua | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index a2fe875e65..0eec693182 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -457,6 +457,9 @@ describe('statuscolumn', function()
     -- Check that statusline click doesn't register as statuscolumn click
     meths.input_mouse('right', 'press', '', 0, 12, 0)
     eq('', eval("g:testvar"))
+    -- Check that cmdline click doesn't register as statuscolumn click
+    meths.input_mouse('right', 'press', '', 0, 13, 0)
+    eq('', eval("g:testvar"))
   end)
 
   it('click labels do not leak memory', function()
-- 
cgit 


From 59fed8bb6457eb6c5204dc39a49d7ea0e1781482 Mon Sep 17 00:00:00 2001
From: luukvbaal 
Date: Tue, 18 Apr 2023 15:07:37 +0200
Subject: fix(api): extmark highlight groups not always included in details
 (#23179)

Problem:    Erroneous for loop condition.
Solution:   Remove for loop condition.
---
 test/functional/api/extmark_spec.lua | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index 4bd8f51904..e30ffc92b6 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -1541,6 +1541,12 @@ describe('API/extmarks', function()
       virt_text_pos = "win_col",
       virt_text_win_col = 1,
     } }, get_extmark_by_id(ns, marks[2], { details = true }))
+    set_extmark(ns, marks[3], 0, 0, { cursorline_hl_group = "Statement" })
+    eq({0, 0, {
+      ns_id = 1,
+      cursorline_hl_group = "Statement",
+      right_gravity = true,
+    } }, get_extmark_by_id(ns, marks[3], { details = true }))
   end)
 
   it('can get marks from anonymous namespaces', function()
-- 
cgit 


From d799456a6b4d9f3000a4a4adb8b71ddee96351b9 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Tue, 18 Apr 2023 03:20:18 +0200
Subject: test(column): statuscolumn is rebuild when signs are (un)placed

---
 test/functional/ui/statuscolumn_spec.lua | 60 ++++++++++++++++++++++++--------
 1 file changed, 45 insertions(+), 15 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index 0eec693182..886e264a5f 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -15,6 +15,7 @@ describe('statuscolumn', function()
     clear('--cmd', 'set number nuw=1 | call setline(1, repeat(["aaaaa"], 16)) | norm GM')
     screen = Screen.new()
     screen:attach()
+    exec_lua('ns = vim.api.nvim_create_namespace("")')
   end)
 
   it("fails with invalid 'statuscolumn'", function()
@@ -352,7 +353,6 @@ describe('statuscolumn', function()
     ]])
     -- Status column is re-evaluated for virt_lines, buffer line, and wrapped line
     exec_lua([[
-      local ns = vim.api.nvim_create_namespace("ns")
       vim.api.nvim_buf_set_extmark(0, ns, 5, 0, {
         virt_lines_above = true, virt_lines = {{{"virt_line above", ""}}} })
       vim.api.nvim_buf_set_extmark(0, ns, 4, 0, { virt_lines = {{{"virt_line", ""}}} })
@@ -377,7 +377,6 @@ describe('statuscolumn', function()
     ]])
     -- Also test virt_lines at the end of buffer
     exec_lua([[
-      local ns = vim.api.nvim_create_namespace("ns")
       vim.api.nvim_buf_set_extmark(0, ns, 15, 0, { virt_lines = {{{"END", ""}}} })
     ]])
     feed('Gzz')
@@ -400,7 +399,6 @@ describe('statuscolumn', function()
     -- Also test virt_lines when 'cpoptions' includes "n"
     exec_lua([[
       vim.opt.cpoptions:append("n")
-      local ns = vim.api.nvim_create_namespace("ns")
       vim.api.nvim_buf_set_extmark(0, ns, 14, 0, { virt_lines = {{{"virt_line1", ""}}} })
       vim.api.nvim_buf_set_extmark(0, ns, 14, 0, { virt_lines = {{{"virt_line2", ""}}} })
     ]])
@@ -481,7 +479,6 @@ describe('statuscolumn', function()
     for _ = 0,8 do command('norm zfjzo') end
     -- 'statuscolumn' is not drawn for `virt_lines_leftcol` lines
     exec_lua([[
-      local ns = vim.api.nvim_create_namespace("ns")
       vim.api.nvim_buf_set_extmark(0, ns, 6, 0, {
         virt_lines_leftcol = true, virt_lines = {{{"virt", ""}}} })
       vim.api.nvim_buf_set_extmark(0, ns, 7, 0, {
@@ -585,37 +582,70 @@ describe('statuscolumn', function()
   end)
 
   it("has correct width with custom sign column when (un)placing signs", function()
-    screen:try_resize(screen._width, 6)
+    screen:try_resize(screen._width, 3)
     exec_lua([[
       vim.cmd.norm('gg')
       vim.o.signcolumn = 'no'
       vim.fn.sign_define('sign', { text = 'ss' })
       _G.StatusCol = function()
         local s = vim.fn.sign_getplaced(1)[1].signs
+        local es = vim.api.nvim_buf_get_extmarks(0, ns, 0, -1, {type = "sign"})
         local sign = ''
-        if #s > 0 then
-          sign = vim.v.lnum == 5 and 'ss' or '  '
+        local signs = #s + #es
+        if signs > 0 then
+          sign = (vim.v.lnum == 2 and 'ss' or '  '):rep(signs)
         end
         return vim.v.lnum .. '%=' .. sign
       end
       vim.o.statuscolumn = "%!v:lua.StatusCol()"
-      vim.fn.sign_place(0, '', 'sign', 1, { lnum = 5 })
     ]])
+    command('sign place 1 line=2 name=sign')
+    screen:expect([[
+      1   ^aaaaa                                            |
+      2 ssaaaaa                                            |
+                                                           |
+    ]])
+    command('sign place 2 line=2 name=sign')
+    screen:expect([[
+      1     ^aaaaa                                          |
+      2 ssssaaaaa                                          |
+                                                           |
+    ]])
+    command('sign unplace 2')
     screen:expect([[
       1   ^aaaaa                                            |
-      2   aaaaa                                            |
-      3   aaaaa                                            |
-      4   aaaaa                                            |
-      5 ssaaaaa                                            |
+      2 ssaaaaa                                            |
                                                            |
     ]])
     command('sign unplace 1')
     screen:expect([[
       1 ^aaaaa                                              |
       2 aaaaa                                              |
-      3 aaaaa                                              |
-      4 aaaaa                                              |
-      5 aaaaa                                              |
+                                                           |
+    ]])
+    -- Also for extmark signs
+    exec_lua('id1 = vim.api.nvim_buf_set_extmark(0, ns, 1, 0, {sign_text = "ss"})')
+    screen:expect([[
+      1   ^aaaaa                                            |
+      2 ssaaaaa                                            |
+                                                           |
+    ]])
+    exec_lua('id2 = vim.api.nvim_buf_set_extmark(0, ns, 1, 0, {sign_text = "ss"})')
+    screen:expect([[
+      1     ^aaaaa                                          |
+      2 ssssaaaaa                                          |
+                                                           |
+    ]])
+    exec_lua("vim.api.nvim_buf_del_extmark(0, ns, id1)")
+    screen:expect([[
+      1   ^aaaaa                                            |
+      2 ssaaaaa                                            |
+                                                           |
+    ]])
+    exec_lua("vim.api.nvim_buf_del_extmark(0, ns, id2)")
+    screen:expect([[
+      1 ^aaaaa                                              |
+      2 aaaaa                                              |
                                                            |
     ]])
   end)
-- 
cgit 


From 44d4f0357341d661a8fa7bd88c244e0ab196a838 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 19 Apr 2023 00:19:26 +0200
Subject: fix(column): rebuild status column when sign column is invalid

---
 test/functional/ui/statuscolumn_spec.lua | 8 ++++++++
 1 file changed, 8 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index 886e264a5f..c4b055d289 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -648,6 +648,14 @@ describe('statuscolumn', function()
       2 aaaaa                                              |
                                                            |
     ]])
+    -- In all windows
+    command('wincmd v | set ls=0')
+    command('sign place 1 line=2 name=sign')
+    screen:expect([[
+      1   ^aaaaa                 │1   aaaaa                 |
+      2 ssaaaaa                 │2 ssaaaaa                 |
+                                                           |
+    ]])
   end)
 
   it("is only evaluated twice, once to estimate and once to draw", function()
-- 
cgit 


From 95c6e1b7418e37530352418e93a18366acef6242 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 19 Apr 2023 12:10:06 +0800
Subject: test(terminal/channel_spec): fix screen test immediate success
 (#23192)

Check for the [No Name] after wiping the buffer.
---
 test/functional/terminal/channel_spec.lua | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index 2ca7cdb0a2..2cd02be321 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -95,15 +95,19 @@ describe('terminal channel is closed and later released if', function()
 end)
 
 it('chansend sends lines to terminal channel in proper order', function()
-  clear()
+  clear({args = {'--cmd', 'set laststatus=2'}})
   local screen = Screen.new(100, 20)
   screen:attach()
   local shells = is_os('win') and {'cmd.exe', 'pwsh.exe -nop', 'powershell.exe -nop'} or {'sh'}
   for _, sh in ipairs(shells) do
-    command([[bdelete! | let id = termopen(']] .. sh .. [[')]])
+    command([[let id = termopen(']] .. sh .. [[')]])
     command([[call chansend(id, ['echo "hello"', 'echo "world"', ''])]])
     screen:expect{
       any=[[echo "hello".*echo "world"]]
     }
+    command('bdelete!')
+    screen:expect{
+      any='%[No Name%]'
+    }
   end
 end)
-- 
cgit 


From 14caad32b6472414d97b588d172d70437c8ebc1d Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 19 Apr 2023 13:45:30 +0800
Subject: test: convert tests in test_conceal.vim to Lua

---
 test/functional/legacy/088_conceal_tabs_spec.lua |  97 ----
 test/functional/legacy/conceal_spec.lua          | 554 +++++++++++++++++++++++
 2 files changed, 554 insertions(+), 97 deletions(-)
 delete mode 100644 test/functional/legacy/088_conceal_tabs_spec.lua
 create mode 100644 test/functional/legacy/conceal_spec.lua

(limited to 'test/functional')

diff --git a/test/functional/legacy/088_conceal_tabs_spec.lua b/test/functional/legacy/088_conceal_tabs_spec.lua
deleted file mode 100644
index a4c7e26583..0000000000
--- a/test/functional/legacy/088_conceal_tabs_spec.lua
+++ /dev/null
@@ -1,97 +0,0 @@
--- Tests for correct display (cursor column position) with +conceal and
--- tabulators.
-
-local helpers = require('test.functional.helpers')(after_each)
-local feed, insert, clear, feed_command =
-  helpers.feed, helpers.insert, helpers.clear, helpers.feed_command
-
-local expect_pos = function(row, col)
-  return helpers.eq({row, col}, helpers.eval('[screenrow(), screencol()]'))
-end
-
-describe('cursor and column position with conceal and tabulators', function()
-  setup(clear)
-
-  -- luacheck: ignore 621 (Indentation)
-  it('are working', function()
-    insert([[
-      start:
-      .concealed.     text
-      |concealed|	text
-
-      	.concealed.	text
-      	|concealed|	text
-
-      .a.	.b.	.c.	.d.
-      |a|	|b|	|c|	|d|]])
-
-    -- Conceal settings.
-    feed_command('set conceallevel=2')
-    feed_command('set concealcursor=nc')
-    feed_command('syntax match test /|/ conceal')
-    -- Start test.
-    feed_command('/^start:')
-    feed('ztj')
-    expect_pos(2, 1)
-    -- We should end up in the same column when running these commands on the
-    -- two lines.
-    feed('ft')
-    expect_pos(2, 17)
-    feed('$')
-    expect_pos(2, 20)
-    feed('0j')
-    expect_pos(3, 1)
-    feed('ft')
-    expect_pos(3, 17)
-    feed('$')
-    expect_pos(3, 20)
-    feed('j0j')
-    expect_pos(5, 8)
-    -- Same for next test block.
-    feed('ft')
-    expect_pos(5, 25)
-    feed('$')
-    expect_pos(5, 28)
-    feed('0j')
-    expect_pos(6, 8)
-    feed('ft')
-    expect_pos(6, 25)
-    feed('$')
-    expect_pos(6, 28)
-    feed('0j0j')
-    expect_pos(8, 1)
-    -- And check W with multiple tabs and conceals in a line.
-    feed('W')
-    expect_pos(8, 9)
-    feed('W')
-    expect_pos(8, 17)
-    feed('W')
-    expect_pos(8, 25)
-    feed('$')
-    expect_pos(8, 27)
-    feed('0j')
-    expect_pos(9, 1)
-    feed('W')
-    expect_pos(9, 9)
-    feed('W')
-    expect_pos(9, 17)
-    feed('W')
-    expect_pos(9, 25)
-    feed('$')
-    expect_pos(9, 26)
-    feed_command('set lbr')
-    feed('$')
-    expect_pos(9, 26)
-    feed_command('set list listchars=tab:>-')
-    feed('0')
-    expect_pos(9, 1)
-    feed('W')
-    expect_pos(9, 9)
-    feed('W')
-    expect_pos(9, 17)
-    feed('W')
-    expect_pos(9, 25)
-    feed('$')
-    expect_pos(9, 26)
-  end)
-end)
diff --git a/test/functional/legacy/conceal_spec.lua b/test/functional/legacy/conceal_spec.lua
new file mode 100644
index 0000000000..429cf9dc03
--- /dev/null
+++ b/test/functional/legacy/conceal_spec.lua
@@ -0,0 +1,554 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local exec = helpers.exec
+local feed = helpers.feed
+
+local expect_pos = function(row, col)
+  return helpers.eq({row, col}, helpers.eval('[screenrow(), screencol()]'))
+end
+
+describe('Conceal', function()
+  before_each(function()
+    clear()
+    command('set nohlsearch')
+  end)
+
+  -- oldtest: Test_conceal_two_windows()
+  it('works', function()
+    local screen = Screen.new(75, 12)
+    screen:set_default_attr_ids({
+      [0] = {bold = true, foreground = Screen.colors.Blue},  -- NonText
+      [1] = {bold = true, reverse = true},  -- StatusLine
+      [2] = {reverse = true},  -- StatusLineNC, IncSearch
+      [3] = {bold = true},  -- ModeMsg
+    })
+    screen:attach()
+    exec([[
+      let lines = ["one one one one one", "two |hidden| here", "three |hidden| three"]
+      call setline(1, lines)
+      syntax match test /|hidden|/ conceal
+      set conceallevel=2
+      set concealcursor=
+      exe "normal /here\r"
+      new
+      call setline(1, lines)
+      call setline(4, "Second window")
+      syntax match test /|hidden|/ conceal
+      set conceallevel=2
+      set concealcursor=nc
+      exe "normal /here\r"
+    ]])
+
+    -- Check that cursor line is concealed
+    screen:expect([[
+      one one one one one                                                        |
+      two  ^here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      /here                                                                      |
+    ]])
+
+    -- Check that with concealed text vertical cursor movement is correct.
+    feed('k')
+    screen:expect([[
+      one one one o^ne one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      /here                                                                      |
+    ]])
+
+    -- Check that with cursor line is not concealed
+    feed('j')
+    command('set concealcursor=')
+    screen:expect([[
+      one one one one one                                                        |
+      two |hidden| ^here                                                          |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      /here                                                                      |
+    ]])
+
+    -- Check that with cursor line is not concealed when moving cursor down
+    feed('j')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three |hidden^| three                                                       |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      /here                                                                      |
+    ]])
+
+    -- Check that with cursor line is not concealed when switching windows
+    feed('')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| ^here                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      /here                                                                      |
+    ]])
+
+    -- Check that with cursor line is only concealed in Normal mode
+    command('set concealcursor=n')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two  ^here                                                                  |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      /here                                                                      |
+    ]])
+    feed('a')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| h^ere                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      {3:-- INSERT --}                                                               |
+    ]])
+    feed('/e')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| h{2:e}re                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      /e^                                                                         |
+    ]])
+    feed('v')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| ^here                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      {3:-- VISUAL --}                                                               |
+    ]])
+    feed('')
+
+    -- Check that with cursor line is only concealed in Insert mode
+    command('set concealcursor=i')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| ^here                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+                                                                                 |
+    ]])
+    feed('a')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two  h^ere                                                                  |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      {3:-- INSERT --}                                                               |
+    ]])
+    feed('/e')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| h{2:e}re                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      /e^                                                                         |
+    ]])
+    feed('v')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| ^here                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      {3:-- VISUAL --}                                                               |
+    ]])
+    feed('')
+
+    -- Check that with cursor line is only concealed in Visual mode
+    command('set concealcursor=v')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| ^here                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+                                                                                 |
+    ]])
+    feed('a')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| h^ere                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      {3:-- INSERT --}                                                               |
+    ]])
+    feed('/e')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| h{2:e}re                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      /e^                                                                         |
+    ]])
+    feed('v')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two  ^here                                                                  |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      {3:-- VISUAL --}                                                               |
+    ]])
+    feed('')
+
+    -- Check moving the cursor while in insert mode.
+    command('set concealcursor=')
+    feed('a')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two |hidden| h^ere                                                          |
+      three  three                                                               |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      {3:-- INSERT --}                                                               |
+    ]])
+    feed('')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two  here                                                                  |
+      three |hidden|^ three                                                       |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+      {3:-- INSERT --}                                                               |
+    ]])
+    feed('')
+
+    -- Check the "o" command
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two  here                                                                  |
+      three |hidden^| three                                                       |
+      {0:~                                                                          }|
+      {1:[No Name] [+]                                                              }|
+                                                                                 |
+    ]])
+    feed('o')
+    screen:expect([[
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      Second window                                                              |
+      {0:~                                                                          }|
+      {2:[No Name] [+]                                                              }|
+      one one one one one                                                        |
+      two  here                                                                  |
+      three  three                                                               |
+      ^                                                                           |
+      {1:[No Name] [+]                                                              }|
+      {3:-- INSERT --}                                                               |
+    ]])
+    feed('')
+  end)
+
+  -- oldtest: Test_conceal_with_cursorcolumn()
+  it('CursorColumn and ColorColumn on wrapped line', function()
+    local screen = Screen.new(40, 10)
+    screen:set_default_attr_ids({
+      [0] = {bold = true, foreground = Screen.colors.Blue},  -- NonText
+      [1] = {background = Screen.colors.Grey90},  -- CursorColumn
+      [2] = {background = Screen.colors.LightRed},  -- ColorColumn
+    })
+    screen:attach()
+    -- Check that cursorcolumn and colorcolumn don't get broken in presence of
+    -- wrapped lines containing concealed text
+    -- luacheck: push ignore 613 (trailing whitespace in a string)
+    exec([[
+      let lines = ["one one one |hidden| one one one one one one one one",
+            \ "two two two two |hidden| here two two",
+            \ "three |hidden| three three three three three three three three"]
+      call setline(1, lines)
+      set wrap linebreak
+      set showbreak=\ >>>\ 
+      syntax match test /|hidden|/ conceal
+      set conceallevel=2
+      set concealcursor=
+      exe "normal /here\r"
+      set cursorcolumn
+      set colorcolumn=50
+    ]])
+    -- luacheck: pop
+
+    screen:expect([[
+      one one one  one one one {1:o}ne            |
+      {0: >>> }one {2:o}ne one one                    |
+      two two two two |hidden| ^here two two   |
+      three  three three three {1:t}hree          |
+      {0: >>> }thre{2:e} three three three            |
+      {0:~                                       }|
+      {0:~                                       }|
+      {0:~                                       }|
+      {0:~                                       }|
+      /here                                   |
+    ]])
+
+    -- move cursor to the end of line (the cursor jumps to the next screen line)
+    feed('$')
+    screen:expect([[
+      one one one  one one one one            |
+      {0: >>> }one {2:o}ne one one                    |
+      two two two two |hidden| here two tw^o   |
+      three  three three three three          |
+      {0: >>> }thre{2:e} three three three            |
+      {0:~                                       }|
+      {0:~                                       }|
+      {0:~                                       }|
+      {0:~                                       }|
+      /here                                   |
+    ]])
+  end)
+
+  -- oldtest: Test_conceal_resize_term()
+  it('resize editor', function()
+    local screen = Screen.new(75, 6)
+    screen:set_default_attr_ids({
+      [0] = {bold = true, foreground = Screen.colors.Blue},  -- NonText
+      [1] = {foreground = Screen.colors.Blue},  -- Comment
+    })
+    screen:attach()
+    exec([[
+      call setline(1, '`one` `two` `three` `four` `five`, the backticks should be concealed')
+      setl cocu=n cole=3
+      syn region CommentCodeSpan matchgroup=Comment start=/`/ end=/`/ concealends
+      normal fb
+    ]])
+    screen:expect([[
+      one two three four five, the ^backticks should be concealed                 |
+      {0:~                                                                          }|
+      {0:~                                                                          }|
+      {0:~                                                                          }|
+      {0:~                                                                          }|
+                                                                                 |
+    ]])
+
+    screen:try_resize(75, 7)
+    screen:expect([[
+      one two three four five, the ^backticks should be concealed                 |
+      {0:~                                                                          }|
+      {0:~                                                                          }|
+      {0:~                                                                          }|
+      {0:~                                                                          }|
+      {0:~                                                                          }|
+                                                                                 |
+    ]])
+  end)
+
+  -- Tests for correct display (cursor column position) with +conceal and tabulators.
+  -- oldtest: Test_conceal_cursor_pos()
+  it('cursor and column position with conceal and tabulators', function()
+    exec([[
+      let l = ['start:', '.concealed.     text', "|concealed|\ttext"]
+      let l += ['', "\t.concealed.\ttext", "\t|concealed|\ttext", '']
+      let l += [".a.\t.b.\t.c.\t.d.", "|a|\t|b|\t|c|\t|d|"]
+      call append(0, l)
+      call cursor(1, 1)
+      " Conceal settings.
+      set conceallevel=2
+      set concealcursor=nc
+      syntax match test /|/ conceal
+    ]])
+    feed('ztj')
+    expect_pos(2, 1)
+    -- We should end up in the same column when running these commands on the
+    -- two lines.
+    feed('ft')
+    expect_pos(2, 17)
+    feed('$')
+    expect_pos(2, 20)
+    feed('0j')
+    expect_pos(3, 1)
+    feed('ft')
+    expect_pos(3, 17)
+    feed('$')
+    expect_pos(3, 20)
+    feed('j0j')
+    expect_pos(5, 8)
+    -- Same for next test block.
+    feed('ft')
+    expect_pos(5, 25)
+    feed('$')
+    expect_pos(5, 28)
+    feed('0j')
+    expect_pos(6, 8)
+    feed('ft')
+    expect_pos(6, 25)
+    feed('$')
+    expect_pos(6, 28)
+    feed('0j0j')
+    expect_pos(8, 1)
+    -- And check W with multiple tabs and conceals in a line.
+    feed('W')
+    expect_pos(8, 9)
+    feed('W')
+    expect_pos(8, 17)
+    feed('W')
+    expect_pos(8, 25)
+    feed('$')
+    expect_pos(8, 27)
+    feed('0j')
+    expect_pos(9, 1)
+    feed('W')
+    expect_pos(9, 9)
+    feed('W')
+    expect_pos(9, 17)
+    feed('W')
+    expect_pos(9, 25)
+    feed('$')
+    expect_pos(9, 26)
+    command('set lbr')
+    feed('$')
+    expect_pos(9, 26)
+    command('set list listchars=tab:>-')
+    feed('0')
+    expect_pos(9, 1)
+    feed('W')
+    expect_pos(9, 9)
+    feed('W')
+    expect_pos(9, 17)
+    feed('W')
+    expect_pos(9, 25)
+    feed('$')
+    expect_pos(9, 26)
+  end)
+end)
-- 
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')

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')

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 9e79f7433eb0e8c5ab9b7c84ac7670aac2f56671 Mon Sep 17 00:00:00 2001
From: Andreas Schneider 
Date: Fri, 21 Apr 2023 13:16:32 +0200
Subject: fix(usercmd): Fix buffer overflow in uc_list() (#23225)

fix(usercmd): fix buffer overflow in uc_list()

Build with: -Wp,-D_FORTIFY_SOURCE=3 -O1 and gcc 13.

*** buffer overflow detected ***: terminated

(gdb) bt
  #0  __pthread_kill_implementation (threadid=, signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
  #1  0x00007f3eb8b93c03 in __pthread_kill_internal (signo=6, threadid=) at pthread_kill.c:78
  #2  0x00007f3eb8b42aee in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
  #3  0x00007f3eb8b2b87f in __GI_abort () at abort.c:79
  #4  0x00007f3eb8b2c60f in __libc_message (fmt=fmt@entry=0x7f3eb8ca72e6 "*** %s ***: terminated\n") at ../sysdeps/posix/libc_fatal.c:150
  #5  0x00007f3eb8c27b29 in __GI___fortify_fail (msg=msg@entry=0x7f3eb8ca728c "buffer overflow detected") at fortify_fail.c:24
  #6  0x00007f3eb8c26364 in __GI___chk_fail () at chk_fail.c:28
  #7  0x00007f3eb8c25f45 in ___snprintf_chk (s=s@entry=0x55b8c7c096a5  "t' item", maxlen=maxlen@entry=1025, flag=flag@entry=2, slen=slen@entry=1020, format=format@entry=0x55b8c7b872a6 "%ldc") at snprintf_chk.c:29
  #8  0x000055b8c7aea59f in snprintf (__fmt=0x55b8c7b872a6 "%ldc", __n=1025, __s=0x55b8c7c096a5  "t' item") at /usr/include/bits/stdio2.h:54
  #9  uc_list (name=name@entry=0x55b8c8351788 "Explore", name_len=name_len@entry=7) at /usr/src/debug/neovim-0.9.0-1.fc38.x86_64/src/nvim/usercmd.c:534
  #10 0x000055b8c7aeb8a0 in ex_command (eap=0x7fffdc350e60) at /usr/src/debug/neovim-0.9.0-1.fc38.x86_64/src/nvim/usercmd.c:1009
  #11 0x000055b8c7972537 in execute_cmd0 (retv=retv@entry=0x7fffdc350e54, eap=eap@entry=0x7fffdc350e60, errormsg=errormsg@entry=0x7fffdc350e58, preview=preview@entry=false) at /usr/src/debug/neovim-0.9.0-1.fc38.x86_64/src/nvim/ex_docmd.c:1620
  #12 0x000055b8c7975c55 in do_one_cmd (cmdlinep=cmdlinep@entry=0x7fffdc3510b8, flags=flags@entry=0, cstack=cstack@entry=0x7fffdc351140, fgetline=fgetline@entry=0x55b8c79882b8 , cookie=cookie@entry=0x0) at /usr/src/debug/neovim-0.9.0-1.fc38.x86_64/src/nvim/ex_docmd.c:2279
  #13 0x000055b8c79767fe in do_cmdline (cmdline=, fgetline=0x55b8c79882b8 , cookie=0x0, flags=0) at /usr/src/debug/neovim-0.9.0-1.fc38.x86_64/src/nvim/ex_docmd.c:578
  #14 0x000055b8c7a17463 in nv_colon (cap=0x7fffdc351780) at /usr/src/debug/neovim-0.9.0-1.fc38.x86_64/src/nvim/normal.c:3228
  #15 0x000055b8c7a11b35 in normal_execute (state=0x7fffdc351700, key=) at /usr/src/debug/neovim-0.9.0-1.fc38.x86_64/src/nvim/normal.c:1196
  #16 0x000055b8c7ab0994 in state_enter (s=0x7fffdc351700) at /usr/src/debug/neovim-0.9.0-1.fc38.x86_64/src/nvim/state.c:99
  #17 0x000055b8c7a0ef68 in normal_enter (cmdwin=false, noexmode=false) at /usr/src/debug/neovim-0.9.0-1.fc38.x86_64/src/nvim/normal.c:497
  #18 0x000055b8c78a0640 in main (argc=, argv=) at /usr/src/debug/neovim-0.9.0-1.fc38.x86_64/src/nvim/main.c:641
---
 test/functional/ex_cmds/excmd_spec.lua | 5 +++++
 1 file changed, 5 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ex_cmds/excmd_spec.lua b/test/functional/ex_cmds/excmd_spec.lua
index b313d6428c..14cc2b8387 100644
--- a/test/functional/ex_cmds/excmd_spec.lua
+++ b/test/functional/ex_cmds/excmd_spec.lua
@@ -28,6 +28,11 @@ describe('Ex cmds', function()
     assert_alive()
   end)
 
+  it('listing long user command does not crash', function()
+    command('execute "command" repeat("T", 255) ":"')
+    command('command')
+  end)
+
   it(':def is an unknown command #23149', function()
     eq('Vim:E492: Not an editor command: def', pcall_err(command, 'def'))
     eq(1, funcs.exists(':d'))
-- 
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')

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')

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 d9f78b63361e00a7f623ebb5b869606ac653b180 Mon Sep 17 00:00:00 2001
From: T727 <74924917+T-727@users.noreply.github.com>
Date: Sat, 22 Apr 2023 13:04:05 +0300
Subject: docs(powershell): use tee.exe instead of Tee-Object

Problem: Tee-Object does not create a file if it does not receive input
for example when :grep does not find matches.
and so nvim tries to open a nonexistent errorfile causing an error.

Solution: use tee.exe instead of Tee-Object
---
 test/functional/ex_cmds/make_spec.lua | 4 +---
 test/functional/helpers.lua           | 4 ++--
 2 files changed, 3 insertions(+), 5 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ex_cmds/make_spec.lua b/test/functional/ex_cmds/make_spec.lua
index f42e21e4cb..8d903330b1 100644
--- a/test/functional/ex_cmds/make_spec.lua
+++ b/test/functional/ex_cmds/make_spec.lua
@@ -24,10 +24,8 @@ describe(':make', function()
     it('captures stderr & non zero exit code #14349', function ()
       nvim('set_option', 'makeprg', testprg('shell-test')..' foo')
       local out = eval('execute("make")')
-      -- Make program exit code correctly captured
-      matches('\nshell returned 3', out)
       -- Error message is captured in the file and printed in the footer
-      matches('\n.*%: Unknown first argument%: foo', out)
+      matches('[\r\n]+.*[\r\n]+Unknown first argument%: foo[\r\n]+%(1 of 1%)%: Unknown first argument%: foo', out)
     end)
 
     it('captures stderr & zero exit code #14349', function ()
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 2e373467d0..6e668b22b0 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -552,7 +552,7 @@ function module.set_shell_powershell(fake)
   end
   local shell = found and (is_os('win') and 'powershell' or 'pwsh') or module.testprg('pwsh-test')
   local cmd = 'Remove-Item -Force '..table.concat(is_os('win')
-    and {'alias:cat', 'alias:echo', 'alias:sleep', 'alias:sort'}
+    and {'alias:cat', 'alias:echo', 'alias:sleep', 'alias:sort', 'alias:tee'}
     or  {'alias:echo'}, ',')..';'
   module.exec([[
     let &shell = ']]..shell..[['
@@ -562,7 +562,7 @@ function module.set_shell_powershell(fake)
     let &shellcmdflag .= '$PSDefaultParameterValues[''Out-File:Encoding'']=''utf8'';'
     let &shellcmdflag .= ']]..cmd..[['
     let &shellredir = '2>&1 | %%{ "$_" } | Out-File %s; exit $LastExitCode'
-    let &shellpipe  = '2>&1 | %%{ "$_" } | Tee-Object %s; exit $LastExitCode'
+    let &shellpipe  = '2>&1 | %%{ "$_" } | tee %s; exit $LastExitCode'
   ]])
   return found
 end
-- 
cgit 


From 040d9da5c8f4d56e0482758223ea7bb04dc90cc0 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 23 Apr 2023 00:30:52 +0800
Subject: vim-patch:9.0.1476: lines put in non-current window are not displayed
 (#23265)

Problem:    Lines put in non-current window are not displayed. (Marius
            Gedminas)
Solution:   Don't increment the topline when inserting just above it.
            (closes vim/vim#12212)

https://github.com/vim/vim/commit/e7f05a8780426dc7af247419c6d02d5f1e896689

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/put_spec.lua   |  28 +++++++++
 test/functional/ui/popupmenu_spec.lua | 103 +++++++++++++++++-----------------
 2 files changed, 79 insertions(+), 52 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/put_spec.lua b/test/functional/legacy/put_spec.lua
index 3ddf65490e..e83fde774a 100644
--- a/test/functional/legacy/put_spec.lua
+++ b/test/functional/legacy/put_spec.lua
@@ -1,4 +1,5 @@
 local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
 local clear = helpers.clear
 local exec_lua = helpers.exec_lua
 local meths = helpers.meths
@@ -42,4 +43,31 @@ describe('put', function()
       bwipe!
     ]]
   end)
+
+  -- oldtest: Test_put_other_window()
+  it('above topline in buffer in two splits', function()
+    local screen = Screen.new(80, 10)
+    screen:attach()
+    source([[
+      40vsplit
+      0put ='some text at the top'
+      put ='  one more text'
+      put ='  two more text'
+      put ='  three more text'
+      put ='  four more text'
+    ]])
+
+    screen:expect([[
+      some text at the top                    │some text at the top                   |
+        one more text                         │  one more text                        |
+        two more text                         │  two more text                        |
+        three more text                       │  three more text                      |
+        ^four more text                        │  four more text                       |
+                                              │                                       |
+      ~                                       │~                                      |
+      ~                                       │~                                      |
+      [No Name] [+]                            [No Name] [+]                          |
+                                                                                      |
+    ]])
+  end)
 end)
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 944319c443..cfcf83ba42 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -1372,11 +1372,11 @@ describe('builtin popupmenu', function()
         U{n: qui            }{s: }eniam, quis nostrud                     |
         e{n: officia        }{s: }co laboris nisi ut aliquip ex           |
       {4:[No}{n: deserunt       }{s: }{4:                                        }|
-        L{n: mollit         }{s: }sit amet, consectetur                   |
-        a{n: anim           }{s: }sed do eiusmod tempor                   |
-        i{n: id             }{s: }re et dolore magna aliqua.              |
-        U{n: est            }{s: }eniam, quis nostrud                     |
-        e{n: laborum        }{c: }co laboris nisi ut aliquip ex           |
+      Est{n: mollit         }{s: }                                        |
+        L{n: anim           }{s: }sit amet, consectetur                   |
+        a{n: id             }{s: }sed do eiusmod tempor                   |
+        i{n: est            }{s: }re et dolore magna aliqua.              |
+        U{n: laborum        }{c: }eniam, quis nostrud                     |
       {3:[No}{s: Est            }{c: }{3:                                        }|
       {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
     ]])
@@ -1390,11 +1390,11 @@ describe('builtin popupmenu', function()
         U{n: qui            }{s: }eniam, quis nostrud                     |
         e{n: officia        }{s: }co laboris nisi ut aliquip ex           |
       {4:[No}{n: deserunt       }{s: }{4:                                        }|
-        U{n: mollit         }{s: }eniam, quis nostrud                     |
-        e{n: anim           }{s: }co laboris nisi ut aliquip ex           |
-        e{n: id             }{s: }at. Duis aute irure dolor in            |
-        r{n: est            }{s: }oluptate velit esse cillum              |
-        d{n: laborum        }{c: }ulla pariatur. Excepteur sint           |
+        i{n: mollit         }{s: }re et dolore magna aliqua.              |
+        U{n: anim           }{s: }eniam, quis nostrud                     |
+        e{n: id             }{s: }co laboris nisi ut aliquip ex           |
+        e{n: est            }{s: }at. Duis aute irure dolor in            |
+        r{n: laborum        }{c: }oluptate velit esse cillum              |
       {3:[No}{s: Est            }{c: }{3:                                        }|
       {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
     ]])
@@ -1408,11 +1408,11 @@ describe('builtin popupmenu', function()
         U{n: enim           }veniam, quis nostrud                     |
         e{n: exercitation   }mco laboris nisi ut aliquip ex           |
       {4:[No}{n: ex             }{4:                                         }|
-        U{n: ea             }veniam, quis nostrud                     |
-        e{n: esse           }mco laboris nisi ut aliquip ex           |
-        e{n: eu             }uat. Duis aute irure dolor in            |
-        r{s: est            }voluptate velit esse cillum              |
-        dolore eu fugiat nulla pariatur. Excepteur sint           |
+        i{n: ea             }ore et dolore magna aliqua.              |
+        U{n: esse           }veniam, quis nostrud                     |
+        e{n: eu             }mco laboris nisi ut aliquip ex           |
+        e{s: est            }uat. Duis aute irure dolor in            |
+        reprehenderit in voluptate velit esse cillum              |
       {3:[No Name] [+]                                               }|
       {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
     ]])
@@ -1426,11 +1426,11 @@ describe('builtin popupmenu', function()
         U{n: enim           }veniam, quis nostrud                     |
         e{n: exercitation   }mco laboris nisi ut aliquip ex           |
       {4:[No}{n: ex             }{4:                                         }|
-        L{n: ea             } sit amet, consectetur                   |
-        a{n: esse           } sed do eiusmod tempor                   |
-        i{n: eu             }ore et dolore magna aliqua.              |
-        U{s: est            }veniam, quis nostrud                     |
-        exercitation ullamco laboris nisi ut aliquip ex           |
+      Est{n: ea             }                                         |
+        L{n: esse           } sit amet, consectetur                   |
+        a{n: eu             } sed do eiusmod tempor                   |
+        i{s: est            }ore et dolore magna aliqua.              |
+        Ut enim ad minim veniam, quis nostrud                     |
       {3:[No Name] [+]                                               }|
       {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
     ]])
@@ -1444,11 +1444,11 @@ describe('builtin popupmenu', function()
         Ut enim ad minim veniam, quis nostrud                     |
         exercitation ullamco laboris nisi ut aliquip ex           |
       {4:[No Name] [+]                                               }|
+      Est es                                                      |
         Lorem ipsum dolor sit amet, consectetur                   |
         adipisicing elit, sed do eiusmod tempor                   |
         incididunt ut labore et dolore magna aliqua.              |
         Ut enim ad minim veniam, quis nostrud                     |
-        exercitation ullamco laboris nisi ut aliquip ex           |
       {3:[No Name] [+]                                               }|
       {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
     ]])
@@ -1462,11 +1462,11 @@ describe('builtin popupmenu', function()
         Ut enim ad minim veniam, quis nostrud                     |
         exercitation ullamco laboris nisi ut aliquip ex           |
       {4:[No Name] [+]                                               }|
+        incididunt ut labore et dolore magna aliqua.              |
         Ut enim ad minim veniam, quis nostrud                     |
         exercitation ullamco laboris nisi ut aliquip ex           |
         ea commodo consequat. Duis aute irure dolor in            |
         reprehenderit in voluptate velit esse cillum              |
-        dolore eu fugiat nulla pariatur. Excepteur sint           |
       {3:[No Name] [+]                                               }|
       {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
     ]])
@@ -1480,11 +1480,11 @@ describe('builtin popupmenu', function()
         U{n: enim           }veniam, quis nostrud                     |
         e{n: exercitation   }mco laboris nisi ut aliquip ex           |
       {4:[No}{n: ex             }{4:                                         }|
-        U{n: ea             }veniam, quis nostrud                     |
-        e{n: esse           }mco laboris nisi ut aliquip ex           |
-        e{n: eu             }uat. Duis aute irure dolor in            |
-        r{s: est            }voluptate velit esse cillum              |
-        dolore eu fugiat nulla pariatur. Excepteur sint           |
+        i{n: ea             }ore et dolore magna aliqua.              |
+        U{n: esse           }veniam, quis nostrud                     |
+        e{n: eu             }mco laboris nisi ut aliquip ex           |
+        e{s: est            }uat. Duis aute irure dolor in            |
+        reprehenderit in voluptate velit esse cillum              |
       {3:[No Name] [+]                                               }|
       {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
     ]])
@@ -1498,11 +1498,11 @@ describe('builtin popupmenu', function()
         U{n: enim           }veniam, quis nostrud                     |
         e{n: exercitation   }mco laboris nisi ut aliquip ex           |
       {4:[No}{n: ex             }{4:                                         }|
-        U{n: ea             }veniam, quis nostrud                     |
-        e{n: esse           }mco laboris nisi ut aliquip ex           |
-        e{s: eu             }uat. Duis aute irure dolor in            |
-        r{n: est            }voluptate velit esse cillum              |
-        dolore eu fugiat nulla pariatur. Excepteur sint           |
+        i{n: ea             }ore et dolore magna aliqua.              |
+        U{n: esse           }veniam, quis nostrud                     |
+        e{s: eu             }mco laboris nisi ut aliquip ex           |
+        e{n: est            }uat. Duis aute irure dolor in            |
+        reprehenderit in voluptate velit esse cillum              |
       {3:[No Name] [+]                                               }|
       {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65}           |
     ]])
@@ -1516,16 +1516,15 @@ describe('builtin popupmenu', function()
         U{n: enim           }veniam, quis nostrud                     |
         e{n: exercitation   }mco laboris nisi ut aliquip ex           |
       {4:[No}{n: ex             }{4:                                         }|
-        r{n: ea             }voluptate velit esse cillum              |
-        d{n: esse           }nulla pariatur. Excepteur sint           |
-        o{s: eu             }t non proident, sunt in culpa            |
-        q{n: est            }unt mollit anim id est                   |
-        laborum.                                                  |
+        e{n: ea             }uat. Duis aute irure dolor in            |
+        r{n: esse           }voluptate velit esse cillum              |
+        d{s: eu             }nulla pariatur. Excepteur sint           |
+        o{n: est            }t non proident, sunt in culpa            |
+        qui officia deserunt mollit anim id est                   |
       {3:[No Name] [+]                                               }|
       {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65}           |
     ]])
 
-
     funcs.complete(4, {'ea', 'eeeeeeeeeeeeeeeeee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'})
     screen:expect([[
       Est eu^                                                      |
@@ -1535,11 +1534,11 @@ describe('builtin popupmenu', function()
         {n: eo                 }iam, quis nostrud                     |
         {n: eu                 } laboris nisi ut aliquip ex           |
       {4:[N}{n: ey                 }{4:                                      }|
-        {n: eå                 }uptate velit esse cillum              |
-        {n: eä                 }la pariatur. Excepteur sint           |
-        {n: eö                 }on proident, sunt in culpa            |
+        {n: eå                 }. Duis aute irure dolor in            |
+        {n: eä                 }uptate velit esse cillum              |
+        {n: eö                 }la pariatur. Excepteur sint           |
+        occaecat cupidatat non proident, sunt in culpa            |
         qui officia deserunt mollit anim id est                   |
-        laborum.                                                  |
       {3:[No Name] [+]                                               }|
       {2:-- Keyword Local completion (^N^P) }{5:match 1 of 9}             |
     ]])
@@ -1553,11 +1552,11 @@ describe('builtin popupmenu', function()
         {n: eo             } veniam, quis nostrud                     |
         {n: eu             }amco laboris nisi ut aliquip ex           |
       {4:[N}{n: ey             }{4:                                          }|
-        {n: eå             } voluptate velit esse cillum              |
-        {n: eä             } nulla pariatur. Excepteur sint           |
-        {n: eö             }at non proident, sunt in culpa            |
+        {n: eå             }quat. Duis aute irure dolor in            |
+        {n: eä             } voluptate velit esse cillum              |
+        {n: eö             } nulla pariatur. Excepteur sint           |
+        occaecat cupidatat non proident, sunt in culpa            |
         qui officia deserunt mollit anim id est                   |
-        laborum.                                                  |
       {3:[No Name] [+]                                               }|
       {2:-- INSERT --}                                                |
     ]])
@@ -1571,11 +1570,11 @@ describe('builtin popupmenu', function()
         {n: eo             } veniam, quis nostrud                     |
         {n: eu             }amco laboris nisi ut aliquip ex           |
       {4:[N}{n: ey             }{4:                                          }|
-        {n: eå             } voluptate velit esse cillum              |
-        {n: eä             } nulla pariatur. Excepteur sint           |
-        {n: eö             }at non proident, sunt in culpa            |
+        {n: eå             }quat. Duis aute irure dolor in            |
+        {n: eä             } voluptate velit esse cillum              |
+        {n: eö             } nulla pariatur. Excepteur sint           |
+        occaecat cupidatat non proident, sunt in culpa            |
         qui officia deserunt mollit anim id est                   |
-        laborum.                                                  |
       {3:[No Name] [+]                                               }|
       {2:-- INSERT --}                                                |
     ]])
@@ -1589,11 +1588,11 @@ describe('builtin popupmenu', function()
         Ut enim ad minim veniam, quis nostrud                     |
         exercitation ullamco laboris nisi ut aliquip ex           |
       {4:[No Name] [+]                                               }|
+        ea commodo consequat. Duis aute irure dolor in            |
         reprehenderit in voluptate velit esse cillum              |
         dolore eu fugiat nulla pariatur. Excepteur sint           |
         occaecat cupidatat non proident, sunt in culpa            |
         qui officia deserunt mollit anim id est                   |
-        laborum.                                                  |
       {3:[No Name] [+]                                               }|
       {2:-- INSERT --}                                                |
     ]])
@@ -1607,11 +1606,11 @@ describe('builtin popupmenu', function()
         Ut enim ad minim veniam, quis nostrud                     |
         exercitation ullamco laboris nisi ut aliquip ex           |
       {4:[No Name] [+]                                               }|
+        ea commodo consequat. Duis aute irure dolor in            |
         reprehenderit in voluptate velit esse cillum              |
         dolore eu fugiat nulla pariatur. Excepteur sint           |
         occaecat cupidatat non proident, sunt in culpa            |
         qui officia deserunt mollit anim id est                   |
-        laborum.                                                  |
       {3:[No Name] [+]                                               }|
       {2:-- INSERT --}                                                |
     ]])
-- 
cgit 


From 540d6c595bc8e1b298dce51211b5d39e25e17d03 Mon Sep 17 00:00:00 2001
From: jdrouhard 
Date: Sat, 22 Apr 2023 17:08:28 -0500
Subject: test(lsp): fix unstable tests for semantic tokens

Add screen:expect() calls after insert() to make sure the screen has
been drawn before we assert the state of the semantic tokens table
---
 .../functional/plugin/lsp/semantic_tokens_spec.lua | 82 ++++++++++++++++++++++
 1 file changed, 82 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua
index ec4d20974d..d1ffb72ef5 100644
--- a/test/functional/plugin/lsp/semantic_tokens_spec.lua
+++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua
@@ -629,6 +629,26 @@ describe('semantic token highlighting', function()
             marked = true,
           },
         },
+        expected_screen = function()
+          screen:expect{grid=[[
+            char* {7:foo} = "\n"^;                       |
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+                                                    |
+          ]]}
+        end,
       },
       {
         it = 'clangd-15 on C++',
@@ -741,6 +761,26 @@ int main()
             marked = true,
           },
         },
+        expected_screen = function()
+          screen:expect{grid=[[
+            #include                      |
+            int {8:main}()                              |
+            {                                       |
+              #ifdef {5:__cplusplus}                    |
+              const int {7:x} = 1;                      |
+              {4:std}::{2:cout} << {2:x} << {4:std}::{3:endl};          |
+            {6:  #else}                                 |
+            {6:    comment}                             |
+            {6:  #endif}                                |
+            ^}                                       |
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+                                                    |
+          ]]}
+        end,
       },
       {
         it = 'sumneko_lua',
@@ -782,6 +822,26 @@ b = "as"]],
             marked = true,
           },
         },
+        expected_screen = function()
+          screen:expect{grid=[[
+            {6:-- comment}                              |
+            local {7:a} = 1                             |
+            {2:b} = "as^"                                |
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+                                                    |
+          ]]}
+        end,
       },
       {
         it = 'rust-analyzer',
@@ -892,6 +952,26 @@ b = "as"]],
             marked = true,
           },
         },
+        expected_screen = function()
+          screen:expect{grid=[[
+            pub fn {8:main}() {                         |
+              break rust;                           |
+              //{6:/ what?}                             |
+            }                                       |
+            ^                                        |
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+            {1:~                                       }|
+                                                    |
+          ]]}
+        end,
       },
     }) do
       it(test.it, function()
@@ -918,6 +998,8 @@ b = "as"]],
 
         insert(test.text)
 
+        test.expected_screen()
+
         local highlights = exec_lua([[
           local semantic_tokens = vim.lsp.semantic_tokens
           return semantic_tokens.__STHighlighter.active[bufnr].client_state[client_id].current_result.highlights
-- 
cgit 


From 3ac952d4e27f4e2454332a730310316fe13fd4a3 Mon Sep 17 00:00:00 2001
From: Dhruv Manilawala 
Date: Sun, 23 Apr 2023 06:53:25 +0530
Subject: fix(api): avoid assertion when autocmd group id is 0 (#23210)

---
 test/functional/api/autocmd_spec.lua | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/api/autocmd_spec.lua b/test/functional/api/autocmd_spec.lua
index b1e38e77a1..57390519de 100644
--- a/test/functional/api/autocmd_spec.lua
+++ b/test/functional/api/autocmd_spec.lua
@@ -39,6 +39,10 @@ describe('autocmd api', function()
       }))
       eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.create_autocmd,
         {'FileType', {}}, {}))
+      eq("Invalid 'group': 0", pcall_err(meths.create_autocmd, 'FileType', {
+        group = 0,
+        command = 'ls',
+      }))
     end)
 
     it('doesnt leak when you use ++once', function()
@@ -308,6 +312,9 @@ describe('autocmd api', function()
       eq("Invalid 'group': 'bogus'", pcall_err(meths.get_autocmds, {
         group = 'bogus',
       }))
+      eq("Invalid 'group': 0", pcall_err(meths.get_autocmds, {
+        group = 0,
+      }))
       eq("Invalid 'group': expected String or Integer, got Array", pcall_err(meths.get_autocmds, {
         group = {},
       }))
@@ -725,6 +732,9 @@ describe('autocmd api', function()
       eq("Invalid 'group': expected String or Integer, got Array", pcall_err(meths.exec_autocmds, 'FileType', {
         group = {},
       }))
+      eq("Invalid 'group': 0", pcall_err(meths.exec_autocmds, 'FileType', {
+        group = 0,
+      }))
       eq("Invalid 'buffer': expected Integer, got Array", pcall_err(meths.exec_autocmds, 'FileType', {
         buffer = {},
       }))
@@ -1049,6 +1059,12 @@ describe('autocmd api', function()
 
       eq(false, exec_lua[[return pcall(vim.api.nvim_del_augroup_by_id, -12342)]])
       eq('Vim:E367: No such group: "--Deleted--"', pcall_err(meths.del_augroup_by_id, -12312))
+
+      eq(false, exec_lua[[return pcall(vim.api.nvim_del_augroup_by_id, 0)]])
+      eq('Vim:E367: No such group: "[NULL]"', pcall_err(meths.del_augroup_by_id, 0))
+
+      eq(false, exec_lua[[return pcall(vim.api.nvim_del_augroup_by_id, 12342)]])
+      eq('Vim:E367: No such group: "[NULL]"', pcall_err(meths.del_augroup_by_id, 12312))
     end)
 
     it('groups work with once', function()
@@ -1224,6 +1240,7 @@ describe('autocmd api', function()
       eq("Invalid 'event' item: expected String, got Array", pcall_err(meths.clear_autocmds, {
         event = {'FileType', {}}
       }))
+      eq("Invalid 'group': 0", pcall_err(meths.clear_autocmds, {group = 0}))
     end)
 
     it('should clear based on event + pattern', function()
-- 
cgit 


From 1355861b926a05e411ba3d42fa85a2fe238aea8d Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 23 Apr 2023 17:44:08 +0800
Subject: fix(typval): don't treat v:null as truthy (#23281)

---
 test/functional/vimscript/special_vars_spec.lua | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/vimscript/special_vars_spec.lua b/test/functional/vimscript/special_vars_spec.lua
index 14ccbc3827..217f0b2c2b 100644
--- a/test/functional/vimscript/special_vars_spec.lua
+++ b/test/functional/vimscript/special_vars_spec.lua
@@ -130,6 +130,12 @@ describe('Special values', function()
     eq("v:false", eval('"" . v:false'))
   end)
 
+  it('work with ?? (falsy operator)', function()
+    eq(true, eval('v:true ?? 42'))
+    eq(42, eval('v:false ?? 42'))
+    eq(42, eval('v:null ?? 42'))
+  end)
+
   it('work with type()', function()
     eq(6, funcs.type(true))
     eq(6, funcs.type(false))
-- 
cgit 


From c1331a65dd12dd1128db5fb136a77218ef7376f1 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 24 Apr 2023 09:26:10 +0800
Subject: fix(pum): show right-click menu above cmdline area (#23298)

---
 test/functional/ui/popupmenu_spec.lua | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index cfcf83ba42..53ef60bc89 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -3259,16 +3259,16 @@ describe('builtin popupmenu', function()
       :let g:menustr = 'bar'          |
     ]])
     eq('bar', meths.get_var('menustr'))
-    feed('<20,1>')
+    feed('<20,2>')
     screen:expect([[
       ^popup menu test                 |
       {1:~                               }|
+      {1:~                               }|
       {1:~                  }{n: foo }{1:        }|
       {1:~                  }{n: bar }{1:        }|
-      {1:~                  }{n: baz }{1:        }|
-      :let g:menustr = 'bar'          |
+      :let g:menustr = 'b{n: baz }        |
     ]])
-    feed('<22,4>')
+    feed('<22,5>')
     screen:expect([[
       ^popup menu test                 |
       {1:~                               }|
@@ -3675,7 +3675,7 @@ describe('builtin popupmenu with ui/ext_multigrid', function()
       {n: foo }|
       {n: bar }|
       {n: baz }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 2, 19, false, 100}}})
+    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 2, 19, false, 250}}})
     meths.input_mouse('left', 'press', '', 4, 2, 2)
     screen:expect({grid=[[
     ## grid 1
@@ -3716,7 +3716,7 @@ describe('builtin popupmenu with ui/ext_multigrid', function()
       {n: foo }|
       {n: bar }|
       {n: baz }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}})
+    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
     meths.input_mouse('right', 'drag', '', 2, 3, 6)
     screen:expect({grid=[[
     ## grid 1
@@ -3738,7 +3738,7 @@ describe('builtin popupmenu with ui/ext_multigrid', function()
       {n: foo }|
       {n: bar }|
       {s: baz }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}})
+    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
     meths.input_mouse('right', 'release', '', 2, 1, 6)
     screen:expect({grid=[[
     ## grid 1
@@ -3780,7 +3780,7 @@ describe('builtin popupmenu with ui/ext_multigrid', function()
       {n: foo }|
       {n: bar }|
       {n: baz }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}})
+    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
     eq(true, screen.options.mousemoveevent)
     meths.input_mouse('move', '', '', 2, 3, 6)
     screen:expect({grid=[[
@@ -3803,7 +3803,7 @@ describe('builtin popupmenu with ui/ext_multigrid', function()
       {n: foo }|
       {n: bar }|
       {s: baz }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}})
+    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
     eq(true, screen.options.mousemoveevent)
     meths.input_mouse('left', 'press', '', 2, 2, 6)
     screen:expect({grid=[[
-- 
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')

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 a4b2400804355e99813f39a6b38d8f38667f8bdd Mon Sep 17 00:00:00 2001
From: luukvbaal 
Date: Tue, 25 Apr 2023 05:05:04 +0200
Subject: fix(statusline): also allow right click when 'mousemodel' is "popup*"
 (#23258)

Problem:    The 'statusline'-format ui elements do not receive right
            click events when "mousemodel" is "popup*"
Solution:   Do not draw popupmenu and handle click event instead.
---
 test/functional/ui/mouse_spec.lua        |  10 -
 test/functional/ui/statuscolumn_spec.lua |  82 ++++----
 test/functional/ui/statusline_spec.lua   | 348 ++++++++++++++++---------------
 3 files changed, 219 insertions(+), 221 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index f705678bd5..c7f6861c12 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1840,16 +1840,6 @@ describe('ui/mouse/input', function()
     eq({2, 9}, meths.win_get_cursor(0))
     eq('', funcs.getreg('"'))
 
-    -- Try clicking on the status line
-    funcs.setreg('"', '')
-    meths.win_set_cursor(0, {1, 9})
-    feed('vee')
-    meths.input_mouse('right', 'press', '', 0, 5, 1)
-    meths.input_mouse('right', 'release', '', 0, 5, 1)
-    feed('')
-    eq({1, 9}, meths.win_get_cursor(0))
-    eq('ran away', funcs.getreg('"'))
-
     -- Try clicking outside the window
     funcs.setreg('"', '')
     meths.win_set_cursor(0, {2, 1})
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index c4b055d289..3b41d3684a 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -9,6 +9,8 @@ local feed = helpers.feed
 local meths = helpers.meths
 local pcall_err = helpers.pcall_err
 
+local mousemodels = { "extend", "popup", "popup_setpos" }
+
 describe('statuscolumn', function()
   local screen
   before_each(function()
@@ -420,45 +422,47 @@ describe('statuscolumn', function()
     ]])
   end)
 
-  it("works with 'statuscolumn' clicks", function()
-    command('set mousemodel=extend')
-    command([[
-      function! MyClickFunc(minwid, clicks, button, mods)
-        let g:testvar = printf("%d %d %s %d", a:minwid, a:clicks, a:button, getmousepos().line)
-        if a:mods !=# '    '
-          let g:testvar ..= '(' .. a:mods .. ')'
-        endif
-      endfunction
-      set stc=%0@MyClickFunc@%=%l%T
-    ]])
-    meths.input_mouse('left', 'press', '', 0, 0, 0)
-    eq('0 1 l 4', eval("g:testvar"))
-    meths.input_mouse('left', 'press', '', 0, 0, 0)
-    eq('0 2 l 4', eval("g:testvar"))
-    meths.input_mouse('left', 'press', '', 0, 0, 0)
-    eq('0 3 l 4', eval("g:testvar"))
-    meths.input_mouse('left', 'press', '', 0, 0, 0)
-    eq('0 4 l 4', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 3, 0)
-    eq('0 1 r 7', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 3, 0)
-    eq('0 2 r 7', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 3, 0)
-    eq('0 3 r 7', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 3, 0)
-    eq('0 4 r 7', eval("g:testvar"))
-    command('set laststatus=2 winbar=%f')
-    command('let g:testvar=""')
-    -- Check that winbar click doesn't register as statuscolumn click
-    meths.input_mouse('right', 'press', '', 0, 0, 0)
-    eq('', eval("g:testvar"))
-    -- Check that statusline click doesn't register as statuscolumn click
-    meths.input_mouse('right', 'press', '', 0, 12, 0)
-    eq('', eval("g:testvar"))
-    -- Check that cmdline click doesn't register as statuscolumn click
-    meths.input_mouse('right', 'press', '', 0, 13, 0)
-    eq('', eval("g:testvar"))
-  end)
+  for _, model in ipairs(mousemodels) do
+    it("works with 'statuscolumn' clicks with mousemodel=" .. model, function()
+      command('set mousemodel=' .. model)
+      command([[
+        function! MyClickFunc(minwid, clicks, button, mods)
+          let g:testvar = printf("%d %d %s %d", a:minwid, a:clicks, a:button, getmousepos().line)
+          if a:mods !=# '    '
+            let g:testvar ..= '(' .. a:mods .. ')'
+          endif
+        endfunction
+        set stc=%0@MyClickFunc@%=%l%T
+      ]])
+      meths.input_mouse('left', 'press', '', 0, 0, 0)
+      eq('0 1 l 4', eval("g:testvar"))
+      meths.input_mouse('left', 'press', '', 0, 0, 0)
+      eq('0 2 l 4', eval("g:testvar"))
+      meths.input_mouse('left', 'press', '', 0, 0, 0)
+      eq('0 3 l 4', eval("g:testvar"))
+      meths.input_mouse('left', 'press', '', 0, 0, 0)
+      eq('0 4 l 4', eval("g:testvar"))
+      meths.input_mouse('right', 'press', '', 0, 3, 0)
+      eq('0 1 r 7', eval("g:testvar"))
+      meths.input_mouse('right', 'press', '', 0, 3, 0)
+      eq('0 2 r 7', eval("g:testvar"))
+      meths.input_mouse('right', 'press', '', 0, 3, 0)
+      eq('0 3 r 7', eval("g:testvar"))
+      meths.input_mouse('right', 'press', '', 0, 3, 0)
+      eq('0 4 r 7', eval("g:testvar"))
+      command('set laststatus=2 winbar=%f')
+      command('let g:testvar=""')
+      -- Check that winbar click doesn't register as statuscolumn click
+      meths.input_mouse('right', 'press', '', 0, 0, 0)
+      eq('', eval("g:testvar"))
+      -- Check that statusline click doesn't register as statuscolumn click
+      meths.input_mouse('right', 'press', '', 0, 12, 0)
+      eq('', eval("g:testvar"))
+      -- Check that cmdline click doesn't register as statuscolumn click
+      meths.input_mouse('right', 'press', '', 0, 13, 0)
+      eq('', eval("g:testvar"))
+    end)
+  end
 
   it('click labels do not leak memory', function()
     command([[
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
index c41d4983a7..5ea4eade4e 100644
--- a/test/functional/ui/statusline_spec.lua
+++ b/test/functional/ui/statusline_spec.lua
@@ -12,178 +12,182 @@ local exec_lua = helpers.exec_lua
 local eval = helpers.eval
 local sleep = helpers.sleep
 
-describe('statusline clicks', function()
-  local screen
-
-  before_each(function()
-    clear()
-    screen = Screen.new(40, 8)
-    screen:attach()
-    command('set laststatus=2 mousemodel=extend')
-    exec([=[
-      function! MyClickFunc(minwid, clicks, button, mods)
-        let g:testvar = printf("%d %d %s", a:minwid, a:clicks, a:button)
-        if a:mods !=# '    '
-          let g:testvar ..= '(' .. a:mods .. ')'
-        endif
-      endfunction
-    ]=])
-  end)
-
-  it('works', function()
-    meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
-    meths.input_mouse('left', 'press', '', 0, 6, 17)
-    eq('0 1 l', eval("g:testvar"))
-    meths.input_mouse('left', 'press', '', 0, 6, 17)
-    eq('0 2 l', eval("g:testvar"))
-    meths.input_mouse('left', 'press', '', 0, 6, 17)
-    eq('0 3 l', eval("g:testvar"))
-    meths.input_mouse('left', 'press', '', 0, 6, 17)
-    eq('0 4 l', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 6, 17)
-    eq('0 1 r', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 6, 17)
-    eq('0 2 r', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 6, 17)
-    eq('0 3 r', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 6, 17)
-    eq('0 4 r', eval("g:testvar"))
-  end)
-
-  it('works for winbar', function()
-    meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
-    meths.input_mouse('left', 'press', '', 0, 0, 17)
-    eq('0 1 l', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 0, 17)
-    eq('0 1 r', eval("g:testvar"))
-  end)
-
-  it('works for winbar in floating window', function()
-    meths.open_win(0, true, { width=30, height=4, relative='editor', row=1, col=5,
-                              border = "single" })
-    meths.set_option_value('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T',
-                           { scope = 'local' })
-    meths.input_mouse('left', 'press', '', 0, 2, 23)
-    eq('0 1 l', eval("g:testvar"))
-  end)
-
-  it('works when there are multiple windows', function()
-    command('split')
-    meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
-    meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
-    meths.input_mouse('left', 'press', '', 0, 0, 17)
-    eq('0 1 l', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 4, 17)
-    eq('0 1 r', eval("g:testvar"))
-    meths.input_mouse('middle', 'press', '', 0, 3, 17)
-    eq('0 1 m', eval("g:testvar"))
-    meths.input_mouse('left', 'press', '', 0, 6, 17)
-    eq('0 1 l', eval("g:testvar"))
-  end)
-
-  it('works with Lua function', function()
-    exec_lua([[
-      function clicky_func(minwid, clicks, button, mods)
-        vim.g.testvar = string.format("%d %d %s", minwid, clicks, button)
-      end
-    ]])
-    meths.set_option('statusline', 'Not clicky stuff %0@v:lua.clicky_func@Clicky stuff%T')
-    meths.input_mouse('left', 'press', '', 0, 6, 17)
-    eq('0 1 l', eval("g:testvar"))
-  end)
-
-  it('ignores unsupported click items', function()
-    command('tabnew | tabprevious')
-    meths.set_option('statusline', '%2TNot clicky stuff%T')
-    meths.input_mouse('left', 'press', '', 0, 6, 0)
-    eq(1, meths.get_current_tabpage().id)
-    meths.set_option('statusline', '%2XNot clicky stuff%X')
-    meths.input_mouse('left', 'press', '', 0, 6, 0)
-    eq(2, #meths.list_tabpages())
-  end)
-
-  it("right click works when statusline isn't focused #18994", function()
-    meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
-    meths.input_mouse('right', 'press', '', 0, 6, 17)
-    eq('0 1 r', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 6, 17)
-    eq('0 2 r', eval("g:testvar"))
-  end)
-
-  it("works with modifiers #18994", function()
-    meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
-    -- Note: alternate between left and right mouse buttons to avoid triggering multiclicks
-    meths.input_mouse('left', 'press', 'S', 0, 6, 17)
-    eq('0 1 l(s   )', eval("g:testvar"))
-    meths.input_mouse('right', 'press', 'S', 0, 6, 17)
-    eq('0 1 r(s   )', eval("g:testvar"))
-    meths.input_mouse('left', 'press', 'A', 0, 6, 17)
-    eq('0 1 l(  a )', eval("g:testvar"))
-    meths.input_mouse('right', 'press', 'A', 0, 6, 17)
-    eq('0 1 r(  a )', eval("g:testvar"))
-    meths.input_mouse('left', 'press', 'AS', 0, 6, 17)
-    eq('0 1 l(s a )', eval("g:testvar"))
-    meths.input_mouse('right', 'press', 'AS', 0, 6, 17)
-    eq('0 1 r(s a )', eval("g:testvar"))
-    meths.input_mouse('left', 'press', 'T', 0, 6, 17)
-    eq('0 1 l(   m)', eval("g:testvar"))
-    meths.input_mouse('right', 'press', 'T', 0, 6, 17)
-    eq('0 1 r(   m)', eval("g:testvar"))
-    meths.input_mouse('left', 'press', 'TS', 0, 6, 17)
-    eq('0 1 l(s  m)', eval("g:testvar"))
-    meths.input_mouse('right', 'press', 'TS', 0, 6, 17)
-    eq('0 1 r(s  m)', eval("g:testvar"))
-    meths.input_mouse('left', 'press', 'C', 0, 6, 17)
-    eq('0 1 l( c  )', eval("g:testvar"))
-    --  is for tag jump
-  end)
-
-  it("works for global statusline with vertical splits #19186", function()
-    command('set laststatus=3')
-    meths.set_option('statusline', '%0@MyClickFunc@Clicky stuff%T %= %0@MyClickFunc@Clicky stuff%T')
-    command('vsplit')
-    screen:expect([[
-      ^                    │                   |
-      ~                   │~                  |
-      ~                   │~                  |
-      ~                   │~                  |
-      ~                   │~                  |
-      ~                   │~                  |
-      Clicky stuff                Clicky stuff|
-                                              |
-    ]])
-
-    -- clickable area on the right
-    meths.input_mouse('left', 'press', '', 0, 6, 35)
-    eq('0 1 l', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 6, 35)
-    eq('0 1 r', eval("g:testvar"))
-
-    -- clickable area on the left
-    meths.input_mouse('left', 'press', '', 0, 6, 5)
-    eq('0 1 l', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 6, 5)
-    eq('0 1 r', eval("g:testvar"))
-  end)
-
-  it('no memory leak with zero-width click labels', function()
-    command([[
-      let &stl = '%@Test@%T%@MyClickFunc@%=%T%@Test@'
-    ]])
-    meths.input_mouse('left', 'press', '', 0, 6, 0)
-    eq('0 1 l', eval("g:testvar"))
-    meths.input_mouse('right', 'press', '', 0, 6, 39)
-    eq('0 1 r', eval("g:testvar"))
-  end)
-
-  it('no memory leak with truncated click labels', function()
-    command([[
-      let &stl = '%@MyClickFunc@foo%X' .. repeat('a', 40) .. '% is for tag jump
+      end)
+
+      it("works for global statusline with vertical splits #19186", function()
+        command('set laststatus=3')
+        meths.set_option('statusline', '%0@MyClickFunc@Clicky stuff%T %= %0@MyClickFunc@Clicky stuff%T')
+        command('vsplit')
+        screen:expect([[
+        ^                    │                   |
+        ~                   │~                  |
+        ~                   │~                  |
+        ~                   │~                  |
+        ~                   │~                  |
+        ~                   │~                  |
+        Clicky stuff                Clicky stuff|
+                                                |
+        ]])
+
+        -- clickable area on the right
+        meths.input_mouse('left', 'press', '', 0, 6, 35)
+        eq('0 1 l', eval("g:testvar"))
+        meths.input_mouse('right', 'press', '', 0, 6, 35)
+        eq('0 1 r', eval("g:testvar"))
+
+        -- clickable area on the left
+        meths.input_mouse('left', 'press', '', 0, 6, 5)
+        eq('0 1 l', eval("g:testvar"))
+        meths.input_mouse('right', 'press', '', 0, 6, 5)
+        eq('0 1 r', eval("g:testvar"))
+      end)
+
+      it('no memory leak with zero-width click labels', function()
+        command([[
+        let &stl = '%@Test@%T%@MyClickFunc@%=%T%@Test@'
+        ]])
+        meths.input_mouse('left', 'press', '', 0, 6, 0)
+        eq('0 1 l', eval("g:testvar"))
+        meths.input_mouse('right', 'press', '', 0, 6, 39)
+        eq('0 1 r', eval("g:testvar"))
+      end)
+
+      it('no memory leak with truncated click labels', function()
+        command([[
+        let &stl = '%@MyClickFunc@foo%X' .. repeat('a', 40) .. '%
Date: Tue, 25 Apr 2023 23:19:00 +0800
Subject: vim-patch:9.0.0875: using freed memory when executing delfunc at more
 prompt (#23314)

Problem:    Using freed memory when executing delfunc at the more prompt.
Solution:   Check function list not changed in another place. (closes vim/vim#11437)

https://github.com/vim/vim/commit/398a26f7fcd58fbc6e2329f892edbb7479a971bb

Co-authored-by: Bram Moolenaar 
---
 test/functional/vimscript/eval_spec.lua | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua
index b411b1e379..b3f2c1bfeb 100644
--- a/test/functional/vimscript/eval_spec.lua
+++ b/test/functional/vimscript/eval_spec.lua
@@ -191,11 +191,10 @@ describe('listing functions using :function', function()
    endfunction]]):format(num), exec_capture(('function %s'):format(num)))
   end)
 
-  -- FIXME: If the same function is deleted, the crash still happens. #20790
   it('does not crash if another function is deleted while listing', function()
     local screen = Screen.new(80, 24)
     screen:attach()
-    matches('Vim%(function%):E454: function list was modified', pcall_err(exec_lua, [=[
+    matches('Vim%(function%):E454: Function list was modified$', pcall_err(exec_lua, [=[
       vim.cmd([[
         func Func1()
         endfunc
@@ -219,6 +218,34 @@ describe('listing functions using :function', function()
     ]=]))
     assert_alive()
   end)
+
+  it('does not crash if the same function is deleted while listing', function()
+    local screen = Screen.new(80, 24)
+    screen:attach()
+    matches('Vim%(function%):E454: Function list was modified$', pcall_err(exec_lua, [=[
+      vim.cmd([[
+        func Func1()
+        endfunc
+        func Func2()
+        endfunc
+        func Func3()
+        endfunc
+      ]])
+
+      local ns = vim.api.nvim_create_namespace('test')
+
+      vim.ui_attach(ns, { ext_messages = true }, function(event, _, content)
+        if event == 'msg_show' and content[1][2] == 'function Func1()'  then
+          vim.cmd('delfunc Func2')
+        end
+      end)
+
+      vim.cmd('function')
+
+      vim.ui_detach(ns)
+    ]=]))
+    assert_alive()
+  end)
 end)
 
 it('no double-free in garbage collection #16287', function()
-- 
cgit 


From a35bca21125980d407bdb830e7c52d95a629de76 Mon Sep 17 00:00:00 2001
From: Munif Tanjim 
Date: Sun, 23 Apr 2023 18:42:03 +0600
Subject: test: scheduled callback shouldn't trigger ModeChanged repeatedly

---
 test/functional/autocmd/modechanged_spec.lua | 39 +++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/autocmd/modechanged_spec.lua b/test/functional/autocmd/modechanged_spec.lua
index be5a291ac9..69a722a0e9 100644
--- a/test/functional/autocmd/modechanged_spec.lua
+++ b/test/functional/autocmd/modechanged_spec.lua
@@ -1,17 +1,19 @@
 local helpers = require('test.functional.helpers')(after_each)
 local clear, eval, eq = helpers.clear, helpers.eval, helpers.eq
 local feed, command = helpers.feed, helpers.command
+local exec_lua = helpers.exec_lua
 
 describe('ModeChanged', function()
   before_each(function()
     clear()
+  end)
+
+  it('picks up terminal mode changes', function()
     command('let g:count = 0')
     command('au ModeChanged * let g:event = copy(v:event)')
     command('au ModeChanged * let g:count += 1')
-  end)
 
-  it('picks up terminal mode changes', function()
-    command("term")
+    command('term')
     feed('i')
     eq({
       old_mode = 'nt',
@@ -28,4 +30,35 @@ describe('ModeChanged', function()
     -- v:event is cleared after the autocommand is done
     eq({}, eval('v:event'))
   end)
+
+  it('does not repeatedly trigger for scheduled callback', function()
+    exec_lua([[
+      vim.g.s_count = 0
+      vim.g.s_mode = ""
+      vim.g.t_count = 0
+      vim.g.t_mode = ""
+      vim.api.nvim_create_autocmd("ModeChanged", {
+        callback = function()
+          vim.g.s_count = vim.g.s_count + 1
+          vim.g.s_mode = vim.api.nvim_get_mode().mode
+          vim.schedule(function()
+            vim.g.t_count = vim.g.t_count + 1
+            vim.g.t_mode = vim.api.nvim_get_mode().mode
+          end)
+        end,
+      })
+    ]])
+
+    feed('d')
+    eq(1, eval('g:s_count'))
+    eq('no', eval('g:s_mode'))
+    eq(1, eval('g:t_count'))
+    eq('no', eval('g:t_mode'))
+
+    feed('')
+    eq(2, eval('g:s_count'))
+    eq('n', eval('g:s_mode'))
+    eq(2, eval('g:t_count'))
+    eq('n', eval('g:t_mode'))
+  end)
 end)
-- 
cgit 


From 1fc468aed2809a92769fbdfd6c422c2b9b12a233 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Thu, 27 Apr 2023 09:07:30 +0800
Subject: vim-patch:9.0.1491: wrong scrolling with ls=0 and :botright split
 (#23333)

Problem:    Wrong scrolling with ls=0 and :botright split.
Solution:   Add statusline before calling frame_new_height(). (closes vim/vim#12299)

https://github.com/vim/vim/commit/fbf2071ac9ef08302a1df86c15f3d4ddbe871243
---
 test/functional/legacy/window_cmd_spec.lua | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/window_cmd_spec.lua b/test/functional/legacy/window_cmd_spec.lua
index c7b5878b92..3a51f7a23f 100644
--- a/test/functional/legacy/window_cmd_spec.lua
+++ b/test/functional/legacy/window_cmd_spec.lua
@@ -3,8 +3,37 @@ local Screen = require('test.functional.ui.screen')
 local clear = helpers.clear
 local exec = helpers.exec
 local exec_lua = helpers.exec_lua
+local command = helpers.command
 local feed = helpers.feed
 
+-- oldtest: Test_window_cmd_ls0_split_scrolling()
+it('scrolling with laststatus=0 and :botright split', function()
+  clear('--cmd', 'set ruler')
+  local screen = Screen.new(40, 10)
+  screen:set_default_attr_ids({
+    [1] = {reverse = true},  -- StatusLineNC
+  })
+  screen:attach()
+  exec([[
+    set laststatus=0
+    call setline(1, range(1, 100))
+    normal! G
+  ]])
+  command('botright split')
+  screen:expect([[
+    97                                      |
+    98                                      |
+    99                                      |
+    100                                     |
+    {1:[No Name] [+]         100,1          Bot}|
+    97                                      |
+    98                                      |
+    99                                      |
+    ^100                                     |
+                          100,1         Bot |
+  ]])
+end)
+
 describe('splitkeep', function()
   local screen
 
-- 
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/autocmd/tabnewentered_spec.lua |  4 ++--
 test/functional/editor/fold_spec.lua           | 22 +++++++++---------
 test/functional/editor/put_spec.lua            |  2 ++
 test/functional/lua/secure_spec.lua            | 12 +++-------
 test/functional/plugin/shada_spec.lua          |  4 ++++
 test/functional/ui/inccommand_spec.lua         | 31 ++++++++++++++------------
 test/functional/ui/output_spec.lua             |  2 ++
 test/functional/vimscript/environ_spec.lua     |  2 ++
 test/functional/vimscript/executable_spec.lua  |  6 +++++
 9 files changed, 49 insertions(+), 36 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/autocmd/tabnewentered_spec.lua b/test/functional/autocmd/tabnewentered_spec.lua
index b186aa1f50..f3443f317d 100644
--- a/test/functional/autocmd/tabnewentered_spec.lua
+++ b/test/functional/autocmd/tabnewentered_spec.lua
@@ -21,9 +21,9 @@ describe('TabNewEntered', function()
     end)
     describe('with FILE as ', function()
       it('matches when opening a new tab for FILE', function()
+        clear()
         nvim('command', 'au! TabNewEntered Xtest-tabnewentered echom "tabnewentered:match"')
-        eq('tabnewentered:4:4\ntabnewentered:match',
-          nvim('exec', 'tabnew Xtest-tabnewentered', true))
+        eq('tabnewentered:match', nvim('exec', 'tabnew Xtest-tabnewentered', true))
      end)
     end)
     describe('with CTRL-W T', function()
diff --git a/test/functional/editor/fold_spec.lua b/test/functional/editor/fold_spec.lua
index 3115c20410..0ed9d1ba80 100644
--- a/test/functional/editor/fold_spec.lua
+++ b/test/functional/editor/fold_spec.lua
@@ -58,11 +58,11 @@ describe('Folds', function()
   describe('adjusting folds after :move', function()
     local function manually_fold_indent()
       -- setting foldmethod twice is a trick to get vim to set the folds for me
-      command('set foldmethod=indent')
-      command('set foldmethod=manual')
+      command('setlocal foldmethod=indent')
+      command('setlocal foldmethod=manual')
       -- Ensure that all folds will get closed (makes it easier to test the
       -- length of folds).
-      command('set foldminlines=0')
+      command('setlocal foldminlines=0')
       -- Start with all folds open (so :move ranges aren't affected by closed
       -- folds).
       command('%foldopen!')
@@ -83,7 +83,7 @@ describe('Folds', function()
       command(move_command)
       local after_move_folds = get_folds()
       -- Doesn't change anything, but does call foldUpdateAll()
-      command('set foldminlines=0')
+      command('setlocal foldminlines=0')
       eq(after_move_folds, get_folds())
       -- Set up the buffer with insert_string for the manual fold testing.
       command('enew!')
@@ -279,7 +279,7 @@ a]], '13m7')
     	a
     	a
     ]])
-    command('set foldmethod=indent')
+    command('setlocal foldmethod=indent')
     command('2')
     command('%foldopen')
     command('read ' .. tempfname)
@@ -317,7 +317,7 @@ a]], '13m7')
     	a
     	a
     ]])
-    command('set foldmethod=indent')
+    command('setlocal foldmethod=indent')
     command('3,5d')
     eq(5, funcs.foldclosedend(1))
   end)
@@ -333,7 +333,7 @@ a]], '13m7')
 
     }}}
     ]])
-    command('set foldmethod=marker')
+    command('setlocal foldmethod=marker')
     command('3,5d')
     command('%foldclose')
     eq(2, funcs.foldclosedend(1))
@@ -372,7 +372,7 @@ a]], '13m7')
     a
     a
     ]])
-    command('set foldmethod=expr foldexpr=TestFoldExpr(v:lnum)')
+    command('setlocal foldmethod=expr foldexpr=TestFoldExpr(v:lnum)')
     command('2')
     command('foldopen')
     command('read ' .. tempfname)
@@ -386,7 +386,7 @@ a]], '13m7')
   end)
 
   it('no folds remain if :delete makes buffer empty #19671', function()
-    command('set foldmethod=manual')
+    command('setlocal foldmethod=manual')
     funcs.setline(1, {'foo', 'bar', 'baz'})
     command('2,3fold')
     command('%delete')
@@ -394,7 +394,7 @@ a]], '13m7')
   end)
 
   it('multibyte fold markers work #20438', function()
-    command('set foldmethod=marker foldmarker=«,» commentstring=/*%s*/')
+    command('setlocal foldmethod=marker foldmarker=«,» commentstring=/*%s*/')
     insert([[
       bbbbb
       bbbbb
@@ -412,7 +412,7 @@ a]], '13m7')
     a
     b
     ]])
-    command('set foldmethod=indent shiftwidth=2')
+    command('setlocal foldmethod=indent shiftwidth=2')
     feed('gg0jI  ') -- indent both lines using visual blockwise mode
     eq(1, funcs.foldlevel(1))
     eq(1, funcs.foldlevel(2))
diff --git a/test/functional/editor/put_spec.lua b/test/functional/editor/put_spec.lua
index fb55b71e43..47068470bb 100644
--- a/test/functional/editor/put_spec.lua
+++ b/test/functional/editor/put_spec.lua
@@ -902,6 +902,8 @@ describe('put command', function()
           end
         end
       end, unchanged=(not should_ring)}
+      screen.bell = false
+      screen.visualbell = false
     end
 
     it('should not ring the bell with gp at end of line', function()
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)
 
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index 93cf6d2b77..f6145a5809 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -2150,6 +2150,7 @@ describe('plugin/shada.vim', function()
 
   teardown(function()
     os.remove(fname)
+    os.remove(fname .. '.tst')
     os.remove(fname_tmp)
   end)
 
@@ -2419,6 +2420,9 @@ describe('plugin/shada.vim', function()
 
   it('event SourceCmd', function()
     reset(fname)
+    finally(function()
+      nvim_command('set shadafile=NONE')  -- Avoid writing shada file on exit
+    end)
     wshada('\004\000\006\146\000\196\002ab')
     wshada_tmp('\004\001\006\146\000\196\002bc')
     eq(0, exc_exec('source ' .. fname))
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 96634be327..a67db78cbe 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -745,10 +745,11 @@ describe(":substitute, 'inccommand' preserves undo", function()
 end)
 
 describe(":substitute, inccommand=split", function()
-  local screen = Screen.new(30,15)
+  local screen
 
   before_each(function()
     clear()
+    screen = Screen.new(30,15)
     common_setup(screen, "split", default_text .. default_text)
   end)
 
@@ -1413,10 +1414,11 @@ describe(":substitute, inccommand=split", function()
 end)
 
 describe("inccommand=nosplit", function()
-  local screen = Screen.new(20,10)
+  local screen
 
   before_each(function()
     clear()
+    screen = Screen.new(20,10)
     common_setup(screen, "nosplit", default_text .. default_text)
   end)
 
@@ -1644,11 +1646,12 @@ describe("inccommand=nosplit", function()
 end)
 
 describe(":substitute, 'inccommand' with a failing expression", function()
-  local screen = Screen.new(20,10)
+  local screen
   local cases = { "", "split", "nosplit" }
 
   local function refresh(case)
     clear()
+    screen = Screen.new(20,10)
     common_setup(screen, case, default_text)
   end
 
@@ -2127,9 +2130,10 @@ describe("'inccommand' with 'gdefault'", function()
 end)
 
 describe(":substitute", function()
-  local screen = Screen.new(30,15)
+  local screen
   before_each(function()
     clear()
+    screen = Screen.new(30,15)
   end)
 
   it("inccommand=split, highlights multiline substitutions", function()
@@ -2335,8 +2339,7 @@ describe(":substitute", function()
     ]])
   end)
 
-  it("inccommand=split, substitutions of different length",
-    function()
+  it("inccommand=split, substitutions of different length", function()
     common_setup(screen, "split", "T T123 T2T TTT T090804\nx")
 
     feed(":%s/T\\([0-9]\\+\\)/\\1\\1/g")
@@ -2872,8 +2875,8 @@ it(':substitute with inccommand during :terminal activity', function()
     return
   end
   retry(2, 40000, function()
-    local screen = Screen.new(30,15)
     clear()
+    local screen = Screen.new(30,15)
 
     command("set cmdwinheight=3")
     feed(([[:terminal "%s" REP 5000 xxx]]):format(testprg('shell-test')))
@@ -2893,8 +2896,8 @@ it(':substitute with inccommand during :terminal activity', function()
 end)
 
 it(':substitute with inccommand, timer-induced :redraw #9777', function()
-  local screen = Screen.new(30,12)
   clear()
+  local screen = Screen.new(30,12)
   command('set cmdwinheight=3')
   command('call timer_start(10, {-> execute("redraw")}, {"repeat":-1})')
   command('call timer_start(10, {-> execute("redrawstatus")}, {"repeat":-1})')
@@ -2920,8 +2923,8 @@ it(':substitute with inccommand, timer-induced :redraw #9777', function()
 end)
 
 it(':substitute with inccommand, allows :redraw before first separator is typed #18857', function()
-  local screen = Screen.new(30,6)
   clear()
+  local screen = Screen.new(30,6)
   common_setup(screen, 'split', 'foo bar baz\nbar baz fox\nbar foo baz')
   command('hi! link NormalFloat CursorLine')
   local float_buf = meths.create_buf(false, true)
@@ -2950,8 +2953,8 @@ it(':substitute with inccommand, allows :redraw before first separator is typed
 end)
 
 it(':substitute with inccommand, does not crash if range contains invalid marks', function()
-  local screen = Screen.new(30, 6)
   clear()
+  local screen = Screen.new(30, 6)
   common_setup(screen, 'split', 'test')
   feed([[:'a,'bs]])
   screen:expect([[
@@ -2976,8 +2979,8 @@ it(':substitute with inccommand, does not crash if range contains invalid marks'
 end)
 
 it(':substitute with inccommand, no unnecessary redraw if preview is not shown', function()
-  local screen = Screen.new(60, 6)
   clear()
+  local screen = Screen.new(60, 6)
   common_setup(screen, 'split', 'test')
   feed(':ls')
   screen:expect([[
@@ -3029,8 +3032,8 @@ it(':substitute with inccommand, no unnecessary redraw if preview is not shown',
 end)
 
 it(":substitute doesn't crash with inccommand, if undo is empty #12932", function()
-  local screen = Screen.new(10,5)
   clear()
+  local screen = Screen.new(10,5)
   command('set undolevels=-1')
   common_setup(screen, 'split', 'test')
   feed(':%s/test')
@@ -3049,8 +3052,8 @@ it(":substitute doesn't crash with inccommand, if undo is empty #12932", functio
 end)
 
 it(':substitute with inccommand works properly if undo is not synced #20029', function()
-  local screen = Screen.new(30, 6)
   clear()
+  local screen = Screen.new(30, 6)
   common_setup(screen, 'nosplit', 'foo\nbar\nbaz')
   meths.set_keymap('x', '', '``>obbbbb asdfV`lljj')
@@ -3086,8 +3089,8 @@ it(':substitute with inccommand works properly if undo is not synced #20029', fu
 end)
 
 it('long :%s/ with inccommand does not collapse cmdline', function()
-  local screen = Screen.new(10,5)
   clear()
+  local screen = Screen.new(10,5)
   common_setup(screen)
   command('set inccommand=nosplit')
   feed(':%s/AAAAAAA', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 954431d689..0dd1f0325c 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -15,6 +15,8 @@ local set_shell_powershell = helpers.set_shell_powershell
 local skip = helpers.skip
 local is_os = helpers.is_os
 
+clear()  -- for has_powershell()
+
 describe("shell command :!", function()
   local screen
   before_each(function()
diff --git a/test/functional/vimscript/environ_spec.lua b/test/functional/vimscript/environ_spec.lua
index 9e19568249..52218d3cc9 100644
--- a/test/functional/vimscript/environ_spec.lua
+++ b/test/functional/vimscript/environ_spec.lua
@@ -26,6 +26,8 @@ end)
 describe('empty $HOME', function()
   local original_home = os.getenv('HOME')
 
+  before_each(clear)
+
   -- recover $HOME after each test
   after_each(function()
     if original_home ~= nil then
diff --git a/test/functional/vimscript/executable_spec.lua b/test/functional/vimscript/executable_spec.lua
index 43e4a29e1a..2b8e3f6218 100644
--- a/test/functional/vimscript/executable_spec.lua
+++ b/test/functional/vimscript/executable_spec.lua
@@ -137,12 +137,16 @@ describe('executable() (Windows)', function()
   end)
 
   it('system([…]), jobstart([…]) use $PATHEXT #9569', function()
+    -- Empty $PATHEXT defaults to ".com;.exe;.bat;.cmd".
+    clear({env={PATHEXT=''}})
     -- Invoking `cmdscript` should find/execute `cmdscript.cmd`.
     eq('much success\n', call('system', {'test/functional/fixtures/cmdscript'}))
     assert(0 < call('jobstart', {'test/functional/fixtures/cmdscript'}))
   end)
 
   it('full path with extension', function()
+    -- Empty $PATHEXT defaults to ".com;.exe;.bat;.cmd".
+    clear({env={PATHEXT=''}})
     -- Some executable we can expect in the test env.
     local exe = 'printargs-test'
     local exedir = eval("fnamemodify(v:progpath, ':h')")
@@ -153,6 +157,8 @@ describe('executable() (Windows)', function()
   end)
 
   it('full path without extension', function()
+    -- Empty $PATHEXT defaults to ".com;.exe;.bat;.cmd".
+    clear({env={PATHEXT=''}})
     -- Some executable we can expect in the test env.
     local exe = 'printargs-test'
     local exedir = eval("fnamemodify(v:progpath, ':h')")
-- 
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')

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 a3dfe1bc89a518442503189ca074ee8ab4b8b0d4 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Thu, 27 Apr 2023 20:19:21 +0800
Subject: fix(pum): position properly with ext_multigrid (#23336)

---
 test/functional/ui/mouse_spec.lua     |   12 +
 test/functional/ui/popupmenu_spec.lua | 5853 +++++++++++++++++++--------------
 2 files changed, 3316 insertions(+), 2549 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index c7f6861c12..d9b9cf9f1b 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1849,5 +1849,17 @@ describe('ui/mouse/input', function()
     feed('')
     eq(2, funcs.winnr())
     eq('', funcs.getreg('"'))
+
+    -- Test for right click in visual mode inside the selection with vertical splits
+    command('wincmd t')
+    command('rightbelow vsplit')
+    funcs.setreg('"', '')
+    meths.win_set_cursor(0, {1, 9})
+    feed('vee')
+    meths.input_mouse('right', 'press', '', 0, 0, 52)
+    meths.input_mouse('right', 'release', '', 0, 0, 52)
+    feed('')
+    eq({1, 9}, meths.win_get_cursor(0))
+    eq('ran away', funcs.getreg('"'))
   end)
 end)
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 53ef60bc89..c5e0c10a81 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -1023,1869 +1023,11 @@ describe('ui/ext_popupmenu', function()
   end)
 end)
 
+describe("builtin popupmenu 'pumblend'", function()
+  before_each(clear)
 
-describe('builtin popupmenu', function()
-  local screen
-  before_each(function()
-    clear()
-    screen = Screen.new(32, 20)
-    screen:attach()
-    screen:set_default_attr_ids({
-      -- popup selected item / scrollbar track
-      ['s'] = {background = Screen.colors.WebGray},
-      -- popup non-selected item
-      ['n'] = {background = Screen.colors.LightMagenta},
-      -- popup scrollbar knob
-      ['c'] = {background = Screen.colors.Grey0},
-      [1] = {bold = true, foreground = Screen.colors.Blue},
-      [2] = {bold = true},
-      [3] = {reverse = true},
-      [4] = {bold = true, reverse = true},
-      [5] = {bold = true, foreground = Screen.colors.SeaGreen},
-      [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
-      [7] = {background = Screen.colors.Yellow},  -- Search
-      [8] = {foreground = Screen.colors.Red},
-    })
-  end)
-
-  it('with preview-window above', function()
-    feed(':ped4+')
-    feed('iaa bb cc dd ee ff gg hh ii jj')
-    feed('')
-    screen:expect([[
-      aa bb cc dd ee ff gg hh ii jj   |
-      aa                              |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {3:[No Name] [Preview][+]          }|
-      aa bb cc dd ee ff gg hh ii jj   |
-      aa^                              |
-      {s:aa             }{c: }{1:                }|
-      {n:bb             }{c: }{1:                }|
-      {n:cc             }{c: }{1:                }|
-      {n:dd             }{c: }{1:                }|
-      {n:ee             }{c: }{1:                }|
-      {n:ff             }{c: }{1:                }|
-      {n:gg             }{s: }{1:                }|
-      {n:hh             }{s: }{4:                }|
-      {2:-- }{5:match 1 of 10}                |
-    ]])
-  end)
-
-  it('with preview-window below', function()
-    feed(':ped4+r')
-    feed('iaa bb cc dd ee ff gg hh ii jj')
-    feed('')
-    screen:expect([[
-      aa bb cc dd ee ff gg hh ii jj   |
-      aa^                              |
-      {s:aa             }{c: }{1:                }|
-      {n:bb             }{c: }{1:                }|
-      {n:cc             }{c: }{1:                }|
-      {n:dd             }{c: }{1:                }|
-      {n:ee             }{c: }{1:                }|
-      {n:ff             }{c: }{1:                }|
-      {n:gg             }{s: }{1:                }|
-      {n:hh             }{s: }{4:                }|
-      aa bb cc dd ee ff gg hh ii jj   |
-      aa                              |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {3:[No Name] [Preview][+]          }|
-      {2:-- }{5:match 1 of 10}                |
-      ]])
-  end)
-
-  it('with preview-window above and tall and inverted', function()
-    feed(':ped8+')
-    feed('iaabbccddee')
-    feed('ffgghhiijj')
-    feed('kkllmmnnoo')
-    feed('')
-    screen:expect([[
-      aa                              |
-      bb                              |
-      cc                              |
-      dd                              |
-      {s:aa             }{c: }{3:ew][+]          }|
-      {n:bb             }{c: }                |
-      {n:cc             }{c: }                |
-      {n:dd             }{c: }                |
-      {n:ee             }{c: }                |
-      {n:ff             }{c: }                |
-      {n:gg             }{c: }                |
-      {n:hh             }{c: }                |
-      {n:ii             }{c: }                |
-      {n:jj             }{c: }                |
-      {n:kk             }{c: }                |
-      {n:ll             }{s: }                |
-      {n:mm             }{s: }                |
-      aa^                              |
-      {4:[No Name] [+]                   }|
-      {2:-- }{5:match 1 of 15}                |
-    ]])
-  end)
-
-  it('with preview-window above and short and inverted', function()
-    feed(':ped4+')
-    feed('iaabbccddee')
-    feed('ffgghhiijj')
-    feed('')
-    screen:expect([[
-      aa                              |
-      bb                              |
-      cc                              |
-      dd                              |
-      ee                              |
-      ff                              |
-      gg                              |
-      hh                              |
-      {s:aa             }{c: }{3:ew][+]          }|
-      {n:bb             }{c: }                |
-      {n:cc             }{c: }                |
-      {n:dd             }{c: }                |
-      {n:ee             }{c: }                |
-      {n:ff             }{c: }                |
-      {n:gg             }{c: }                |
-      {n:hh             }{c: }                |
-      {n:ii             }{s: }                |
-      aa^                              |
-      {4:[No Name] [+]                   }|
-      {2:-- }{5:match 1 of 10}                |
-    ]])
-  end)
-
-  it('with preview-window below and inverted', function()
-    feed(':ped4+r')
-    feed('iaabbccddee')
-    feed('ffgghhiijj')
-    feed('')
-    screen:expect([[
-      {s:aa             }{c: }                |
-      {n:bb             }{c: }                |
-      {n:cc             }{c: }                |
-      {n:dd             }{c: }                |
-      {n:ee             }{c: }                |
-      {n:ff             }{c: }                |
-      {n:gg             }{s: }                |
-      {n:hh             }{s: }                |
-      aa^                              |
-      {4:[No Name] [+]                   }|
-      aa                              |
-      bb                              |
-      cc                              |
-      dd                              |
-      ee                              |
-      ff                              |
-      gg                              |
-      hh                              |
-      {3:[No Name] [Preview][+]          }|
-      {2:-- }{5:match 1 of 10}                |
-    ]])
-  end)
-
-  -- oldtest: Test_pum_with_preview_win()
-  it('preview window opened during completion', function()
-    exec([[
-      funct Omni_test(findstart, base)
-        if a:findstart
-          return col(".") - 1
-        endif
-        return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}]
-      endfunc
-      set omnifunc=Omni_test
-      set completeopt+=longest
-    ]])
-    feed('Gi')
-    screen:expect([[
-      ^                                |
-      {n:one            }{1:                 }|
-      {n:two            }{1:                 }|
-      {n:three          }{1:                 }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {2:-- }{8:Back at original}             |
-    ]])
-    feed('')
-    screen:expect([[
-      1info                           |
-                                      |
-      {1:~                               }|
-      {3:[Scratch] [Preview]             }|
-      one^                             |
-      {s:one            }{1:                 }|
-      {n:two            }{1:                 }|
-      {n:three          }{1:                 }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {4:[No Name] [+]                   }|
-      {2:-- }{5:match 1 of 3}                 |
-    ]])
-  end)
-
-  it('with vsplits', function()
-    insert('aaa aab aac\n')
-    feed(':vsplit')
-    screen:expect([[
-      aaa aab aac         │aaa aab aac|
-      ^                    │           |
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {4:[No Name] [+]        }{3:')
-    screen:expect([[
-      aaa aab aac         │aaa aab aac|
-      bbb aaa^             │bbb aaa    |
-      {1:~  }{s: aaa            }{1: }│{1:~          }|
-      {1:~  }{n: aab            }{1: }│{1:~          }|
-      {1:~  }{n: aac            }{1: }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {1:~                   }│{1:~          }|
-      {4:[No Name] [+]        }{3:oc a')
-    screen:expect([[
-      aaa aab aac│aaa aab aac         |
-      bbb aaa    │bbb aaa             |
-      c aaa      │c aaa^               |
-      {1:~          }│{1:~}{s: aaa            }{1:   }|
-      {1:~          }│{1:~}{n: aab            }{1:   }|
-      {1:~          }│{1:~}{n: aac            }{1:   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {1:~          }│{1:~                   }|
-      {3:')
-    screen:expect([[
-      Est ^                                                        |
-        L{n: sunt           }{s: }sit amet, consectetur                   |
-        a{n: in             }{s: }sed do eiusmod tempor                   |
-        i{n: culpa          }{s: }re et dolore magna aliqua.              |
-        U{n: qui            }{s: }eniam, quis nostrud                     |
-        e{n: officia        }{s: }co laboris nisi ut aliquip ex           |
-      {4:[No}{n: deserunt       }{s: }{4:                                        }|
-      Est{n: mollit         }{s: }                                        |
-        L{n: anim           }{s: }sit amet, consectetur                   |
-        a{n: id             }{s: }sed do eiusmod tempor                   |
-        i{n: est            }{s: }re et dolore magna aliqua.              |
-        U{n: laborum        }{c: }eniam, quis nostrud                     |
-      {3:[No}{s: Est            }{c: }{3:                                        }|
-      {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
-    ]])
-
-    meths.input_mouse('wheel', 'down', '', 0, 9, 40)
-    screen:expect([[
-      Est ^                                                        |
-        L{n: sunt           }{s: }sit amet, consectetur                   |
-        a{n: in             }{s: }sed do eiusmod tempor                   |
-        i{n: culpa          }{s: }re et dolore magna aliqua.              |
-        U{n: qui            }{s: }eniam, quis nostrud                     |
-        e{n: officia        }{s: }co laboris nisi ut aliquip ex           |
-      {4:[No}{n: deserunt       }{s: }{4:                                        }|
-        i{n: mollit         }{s: }re et dolore magna aliqua.              |
-        U{n: anim           }{s: }eniam, quis nostrud                     |
-        e{n: id             }{s: }co laboris nisi ut aliquip ex           |
-        e{n: est            }{s: }at. Duis aute irure dolor in            |
-        r{n: laborum        }{c: }oluptate velit esse cillum              |
-      {3:[No}{s: Est            }{c: }{3:                                        }|
-      {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
-    ]])
-
-    feed('e')
-    screen:expect([[
-      Est e^                                                       |
-        L{n: elit           } sit amet, consectetur                   |
-        a{n: eiusmod        } sed do eiusmod tempor                   |
-        i{n: et             }ore et dolore magna aliqua.              |
-        U{n: enim           }veniam, quis nostrud                     |
-        e{n: exercitation   }mco laboris nisi ut aliquip ex           |
-      {4:[No}{n: ex             }{4:                                         }|
-        i{n: ea             }ore et dolore magna aliqua.              |
-        U{n: esse           }veniam, quis nostrud                     |
-        e{n: eu             }mco laboris nisi ut aliquip ex           |
-        e{s: est            }uat. Duis aute irure dolor in            |
-        reprehenderit in voluptate velit esse cillum              |
-      {3:[No Name] [+]                                               }|
-      {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
-    ]])
-
-    meths.input_mouse('wheel', 'up', '', 0, 9, 40)
-    screen:expect([[
-      Est e^                                                       |
-        L{n: elit           } sit amet, consectetur                   |
-        a{n: eiusmod        } sed do eiusmod tempor                   |
-        i{n: et             }ore et dolore magna aliqua.              |
-        U{n: enim           }veniam, quis nostrud                     |
-        e{n: exercitation   }mco laboris nisi ut aliquip ex           |
-      {4:[No}{n: ex             }{4:                                         }|
-      Est{n: ea             }                                         |
-        L{n: esse           } sit amet, consectetur                   |
-        a{n: eu             } sed do eiusmod tempor                   |
-        i{s: est            }ore et dolore magna aliqua.              |
-        Ut enim ad minim veniam, quis nostrud                     |
-      {3:[No Name] [+]                                               }|
-      {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
-    ]])
-
-    feed('s')
-    screen:expect([[
-      Est es^                                                      |
-        L{n: esse           } sit amet, consectetur                   |
-        a{s: est            } sed do eiusmod tempor                   |
-        incididunt ut labore et dolore magna aliqua.              |
-        Ut enim ad minim veniam, quis nostrud                     |
-        exercitation ullamco laboris nisi ut aliquip ex           |
-      {4:[No Name] [+]                                               }|
-      Est es                                                      |
-        Lorem ipsum dolor sit amet, consectetur                   |
-        adipisicing elit, sed do eiusmod tempor                   |
-        incididunt ut labore et dolore magna aliqua.              |
-        Ut enim ad minim veniam, quis nostrud                     |
-      {3:[No Name] [+]                                               }|
-      {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
-    ]])
-
-    meths.input_mouse('wheel', 'down', '', 0, 9, 40)
-    screen:expect([[
-      Est es^                                                      |
-        L{n: esse           } sit amet, consectetur                   |
-        a{s: est            } sed do eiusmod tempor                   |
-        incididunt ut labore et dolore magna aliqua.              |
-        Ut enim ad minim veniam, quis nostrud                     |
-        exercitation ullamco laboris nisi ut aliquip ex           |
-      {4:[No Name] [+]                                               }|
-        incididunt ut labore et dolore magna aliqua.              |
-        Ut enim ad minim veniam, quis nostrud                     |
-        exercitation ullamco laboris nisi ut aliquip ex           |
-        ea commodo consequat. Duis aute irure dolor in            |
-        reprehenderit in voluptate velit esse cillum              |
-      {3:[No Name] [+]                                               }|
-      {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
-    ]])
-
-    feed('')
-    screen:expect([[
-      Est e^                                                       |
-        L{n: elit           } sit amet, consectetur                   |
-        a{n: eiusmod        } sed do eiusmod tempor                   |
-        i{n: et             }ore et dolore magna aliqua.              |
-        U{n: enim           }veniam, quis nostrud                     |
-        e{n: exercitation   }mco laboris nisi ut aliquip ex           |
-      {4:[No}{n: ex             }{4:                                         }|
-        i{n: ea             }ore et dolore magna aliqua.              |
-        U{n: esse           }veniam, quis nostrud                     |
-        e{n: eu             }mco laboris nisi ut aliquip ex           |
-        e{s: est            }uat. Duis aute irure dolor in            |
-        reprehenderit in voluptate velit esse cillum              |
-      {3:[No Name] [+]                                               }|
-      {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
-    ]])
-
-    feed('')
-    screen:expect([[
-      Est eu^                                                      |
-        L{n: elit           } sit amet, consectetur                   |
-        a{n: eiusmod        } sed do eiusmod tempor                   |
-        i{n: et             }ore et dolore magna aliqua.              |
-        U{n: enim           }veniam, quis nostrud                     |
-        e{n: exercitation   }mco laboris nisi ut aliquip ex           |
-      {4:[No}{n: ex             }{4:                                         }|
-        i{n: ea             }ore et dolore magna aliqua.              |
-        U{n: esse           }veniam, quis nostrud                     |
-        e{s: eu             }mco laboris nisi ut aliquip ex           |
-        e{n: est            }uat. Duis aute irure dolor in            |
-        reprehenderit in voluptate velit esse cillum              |
-      {3:[No Name] [+]                                               }|
-      {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65}           |
-    ]])
-
-    meths.input_mouse('wheel', 'down', '', 0, 9, 40)
-    screen:expect([[
-      Est eu^                                                      |
-        L{n: elit           } sit amet, consectetur                   |
-        a{n: eiusmod        } sed do eiusmod tempor                   |
-        i{n: et             }ore et dolore magna aliqua.              |
-        U{n: enim           }veniam, quis nostrud                     |
-        e{n: exercitation   }mco laboris nisi ut aliquip ex           |
-      {4:[No}{n: ex             }{4:                                         }|
-        e{n: ea             }uat. Duis aute irure dolor in            |
-        r{n: esse           }voluptate velit esse cillum              |
-        d{s: eu             }nulla pariatur. Excepteur sint           |
-        o{n: est            }t non proident, sunt in culpa            |
-        qui officia deserunt mollit anim id est                   |
-      {3:[No Name] [+]                                               }|
-      {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65}           |
-    ]])
-
-    funcs.complete(4, {'ea', 'eeeeeeeeeeeeeeeeee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'})
-    screen:expect([[
-      Est eu^                                                      |
-        {s: ea                 }t amet, consectetur                   |
-        {n: eeeeeeeeeeeeeeeeee }d do eiusmod tempor                   |
-        {n: ei                 } et dolore magna aliqua.              |
-        {n: eo                 }iam, quis nostrud                     |
-        {n: eu                 } laboris nisi ut aliquip ex           |
-      {4:[N}{n: ey                 }{4:                                      }|
-        {n: eå                 }. Duis aute irure dolor in            |
-        {n: eä                 }uptate velit esse cillum              |
-        {n: eö                 }la pariatur. Excepteur sint           |
-        occaecat cupidatat non proident, sunt in culpa            |
-        qui officia deserunt mollit anim id est                   |
-      {3:[No Name] [+]                                               }|
-      {2:-- Keyword Local completion (^N^P) }{5:match 1 of 9}             |
-    ]])
-
-    funcs.complete(4, {'ea', 'eee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'})
-    screen:expect([[
-      Est eu^                                                      |
-        {s: ea             }r sit amet, consectetur                   |
-        {n: eee            }, sed do eiusmod tempor                   |
-        {n: ei             }bore et dolore magna aliqua.              |
-        {n: eo             } veniam, quis nostrud                     |
-        {n: eu             }amco laboris nisi ut aliquip ex           |
-      {4:[N}{n: ey             }{4:                                          }|
-        {n: eå             }quat. Duis aute irure dolor in            |
-        {n: eä             } voluptate velit esse cillum              |
-        {n: eö             } nulla pariatur. Excepteur sint           |
-        occaecat cupidatat non proident, sunt in culpa            |
-        qui officia deserunt mollit anim id est                   |
-      {3:[No Name] [+]                                               }|
-      {2:-- INSERT --}                                                |
-    ]])
-
-    feed('')
-    screen:expect([[
-      Esteee^                                                      |
-        {n: ea             }r sit amet, consectetur                   |
-        {s: eee            }, sed do eiusmod tempor                   |
-        {n: ei             }bore et dolore magna aliqua.              |
-        {n: eo             } veniam, quis nostrud                     |
-        {n: eu             }amco laboris nisi ut aliquip ex           |
-      {4:[N}{n: ey             }{4:                                          }|
-        {n: eå             }quat. Duis aute irure dolor in            |
-        {n: eä             } voluptate velit esse cillum              |
-        {n: eö             } nulla pariatur. Excepteur sint           |
-        occaecat cupidatat non proident, sunt in culpa            |
-        qui officia deserunt mollit anim id est                   |
-      {3:[No Name] [+]                                               }|
-      {2:-- INSERT --}                                                |
-    ]])
-
-    funcs.complete(6, {'foo', 'bar'})
-    screen:expect([[
-      Esteee^                                                      |
-        Lo{s: foo            }sit amet, consectetur                   |
-        ad{n: bar            }sed do eiusmod tempor                   |
-        incididunt ut labore et dolore magna aliqua.              |
-        Ut enim ad minim veniam, quis nostrud                     |
-        exercitation ullamco laboris nisi ut aliquip ex           |
-      {4:[No Name] [+]                                               }|
-        ea commodo consequat. Duis aute irure dolor in            |
-        reprehenderit in voluptate velit esse cillum              |
-        dolore eu fugiat nulla pariatur. Excepteur sint           |
-        occaecat cupidatat non proident, sunt in culpa            |
-        qui officia deserunt mollit anim id est                   |
-      {3:[No Name] [+]                                               }|
-      {2:-- INSERT --}                                                |
-    ]])
-
-    feed('')
-    screen:expect([[
-      Esteefoo^                                                    |
-        Lorem ipsum dolor sit amet, consectetur                   |
-        adipisicing elit, sed do eiusmod tempor                   |
-        incididunt ut labore et dolore magna aliqua.              |
-        Ut enim ad minim veniam, quis nostrud                     |
-        exercitation ullamco laboris nisi ut aliquip ex           |
-      {4:[No Name] [+]                                               }|
-        ea commodo consequat. Duis aute irure dolor in            |
-        reprehenderit in voluptate velit esse cillum              |
-        dolore eu fugiat nulla pariatur. Excepteur sint           |
-        occaecat cupidatat non proident, sunt in culpa            |
-        qui officia deserunt mollit anim id est                   |
-      {3:[No Name] [+]                                               }|
-      {2:-- INSERT --}                                                |
-    ]])
-  end)
-
-  it('can be moved due to wrap or resize', function()
-    feed('isome long prefix before the ')
-    command("set completeopt+=noinsert,noselect")
-    command("set linebreak")
-    funcs.complete(29, {'word', 'choice', 'text', 'thing'})
-    screen:expect([[
-      some long prefix before the ^    |
-      {1:~                        }{n: word  }|
-      {1:~                        }{n: choice}|
-      {1:~                        }{n: text  }|
-      {1:~                        }{n: thing }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {2:-- INSERT --}                    |
-    ]])
-
-    feed('')
-    screen:expect([[
-      some long prefix before the     |
-      thing^                           |
-      {n:word           }{1:                 }|
-      {n:choice         }{1:                 }|
-      {n:text           }{1:                 }|
-      {s:thing          }{1:                 }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {2:-- INSERT --}                    |
-    ]])
-
-    feed('')
-    screen:expect([[
-      some long prefix before the text|
-      {1:^~                        }{n: word  }|
-      {1:~                        }{n: choice}|
-      {1:~                        }{s: text  }|
-      {1:~                        }{n: thing }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {2:-- INSERT --}                    |
-    ]])
-
-    screen:try_resize(30,8)
-    screen:expect([[
-      some long prefix before the   |
-      text^                          |
-      {n:word           }{1:               }|
-      {n:choice         }{1:               }|
-      {s:text           }{1:               }|
-      {n:thing          }{1:               }|
-      {1:~                             }|
-      {2:-- INSERT --}                  |
-    ]])
-
-    screen:try_resize(50,8)
-    screen:expect([[
-      some long prefix before the text^                  |
-      {1:~                          }{n: word           }{1:       }|
-      {1:~                          }{n: choice         }{1:       }|
-      {1:~                          }{s: text           }{1:       }|
-      {1:~                          }{n: thing          }{1:       }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {2:-- INSERT --}                                      |
-    ]])
-
-    screen:try_resize(25,10)
-    screen:expect([[
-      some long prefix before  |
-      the text^                 |
-      {1:~  }{n: word           }{1:      }|
-      {1:~  }{n: choice         }{1:      }|
-      {1:~  }{s: text           }{1:      }|
-      {1:~  }{n: thing          }{1:      }|
-      {1:~                        }|
-      {1:~                        }|
-      {1:~                        }|
-      {2:-- INSERT --}             |
-    ]])
-
-    screen:try_resize(12,5)
-    screen:expect([[
-      some long   |
-      prefix      |
-      bef{n: word  }  |
-      tex{n: }^        |
-      {2:-- INSERT -} |
-    ]])
-
-    -- can't draw the pum, but check we don't crash
-    screen:try_resize(12,2)
-    screen:expect([[
-      text^        |
-      {2:-- INSERT -} |
-    ]])
-
-    -- but state is preserved, pum reappears
-    screen:try_resize(20,8)
-    screen:expect([[
-      some long prefix    |
-      before the text^     |
-      {1:~         }{n: word    }{1: }|
-      {1:~         }{n: choice  }{1: }|
-      {1:~         }{s: text    }{1: }|
-      {1:~         }{n: thing   }{1: }|
-      {1:~                   }|
-      {2:-- INSERT --}        |
-    ]])
-  end)
-
-  it('with VimResized autocmd', function()
-    feed('isome long prefix before the ')
-    command("set completeopt+=noinsert,noselect")
-    command("autocmd VimResized * redraw!")
-    command("set linebreak")
-    funcs.complete(29, {'word', 'choice', 'text', 'thing'})
-    screen:expect([[
-      some long prefix before the ^    |
-      {1:~                        }{n: word  }|
-      {1:~                        }{n: choice}|
-      {1:~                        }{n: text  }|
-      {1:~                        }{n: thing }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {2:-- INSERT --}                    |
-    ]])
-
-    screen:try_resize(16,10)
-    screen:expect([[
-      some long       |
-      prefix before   |
-      the ^            |
-      {1:~  }{n: word        }|
-      {1:~  }{n: choice      }|
-      {1:~  }{n: text        }|
-      {1:~  }{n: thing       }|
-      {1:~               }|
-      {1:~               }|
-      {2:-- INSERT --}    |
-    ]])
-  end)
-
-  it('with rightleft window', function()
-    command("set rl wildoptions+=pum")
-    feed('isome rightleft ')
-    screen:expect([[
-                      ^  tfelthgir emos|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {2:-- INSERT --}                    |
-    ]])
-
-    command("set completeopt+=noinsert,noselect")
-    funcs.complete(16, {'word', 'choice', 'text', 'thing'})
-    screen:expect([[
-                      ^  tfelthgir emos|
-      {1:  }{n:           drow}{1:              ~}|
-      {1:  }{n:         eciohc}{1:              ~}|
-      {1:  }{n:           txet}{1:              ~}|
-      {1:  }{n:          gniht}{1:              ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {2:-- INSERT --}                    |
-    ]])
-
-    feed('')
-    screen:expect([[
-                  ^ drow tfelthgir emos|
-      {1:  }{s:           drow}{1:              ~}|
-      {1:  }{n:         eciohc}{1:              ~}|
-      {1:  }{n:           txet}{1:              ~}|
-      {1:  }{n:          gniht}{1:              ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {2:-- INSERT --}                    |
-    ]])
-
-    feed('')
-    screen:expect([[
-                  ^ drow tfelthgir emos|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {2:-- INSERT --}                    |
-    ]])
-
-    -- not rightleft on the cmdline
-    feed(':sign ')
-    screen:expect{grid=[[
-                   drow tfelthgir emos|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      :sign ^                          |
-    ]]}
-
-    feed('')
-    screen:expect{grid=[[
-                   drow tfelthgir emos|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:                               ~}|
-      {1:     }{s: define         }{1:          ~}|
-      {1:     }{n: jump           }{1:          ~}|
-      {1:     }{n: list           }{1:          ~}|
-      {1:     }{n: place          }{1:          ~}|
-      {1:     }{n: undefine       }{1:          ~}|
-      {1:     }{n: unplace        }{1:          ~}|
-      :sign define^                    |
-    ]]}
-  end)
-
-  it('with multiline messages', function()
-    screen:try_resize(40,8)
-    feed('ixx')
-    command('imap  echoerr "very"\\|echoerr "much"\\|echoerr "error"')
-    funcs.complete(1, {'word', 'choice', 'text', 'thing'})
-    screen:expect([[
-      xx                                      |
-      word^                                    |
-      {s:word           }{1:                         }|
-      {n:choice         }{1:                         }|
-      {n:text           }{1:                         }|
-      {n:thing          }{1:                         }|
-      {1:~                                       }|
-      {2:-- INSERT --}                            |
-    ]])
-
-    feed('')
-    screen:expect([[
-      xx                                      |
-      word                                    |
-      {s:word           }{1:                         }|
-      {4:                                        }|
-      {6:very}                                    |
-      {6:much}                                    |
-      {6:error}                                   |
-      {5:Press ENTER or type command to continue}^ |
-    ]])
-
-    feed('')
-    screen:expect([[
-      xx                                      |
-      word^                                    |
-      {s:word           }{1:                         }|
-      {n:choice         }{1:                         }|
-      {n:text           }{1:                         }|
-      {n:thing          }{1:                         }|
-      {1:~                                       }|
-      {2:-- INSERT --}                            |
-    ]])
-
-    feed('')
-    screen:expect([[
-      xx                                      |
-      choice^                                  |
-      {n:word           }{1:                         }|
-      {s:choice         }{1:                         }|
-      {n:text           }{1:                         }|
-      {n:thing          }{1:                         }|
-      {1:~                                       }|
-      {2:-- INSERT --}                            |
-    ]])
-
-    command("split")
-    screen:expect([[
-      xx                                      |
-      choice^                                  |
-      {n:word           }{1:                         }|
-      {s:choice         }{4:                         }|
-      {n:text           }                         |
-      {n:thing          }                         |
-      {3:[No Name] [+]                           }|
-      {2:-- INSERT --}                            |
-    ]])
-
-    meths.input_mouse('wheel', 'down', '', 0, 6, 15)
-    screen:expect{grid=[[
-      xx                                      |
-      choice^                                  |
-      {n:word           }{1:                         }|
-      {s:choice         }{4:                         }|
-      {n:text           }                         |
-      {n:thing          }{1:                         }|
-      {3:[No Name] [+]                           }|
-      {2:-- INSERT --}                            |
-    ]], unchanged=true}
-  end)
-
-  it('with kind, menu and abbr attributes', function()
-    screen:try_resize(40,8)
-    feed('ixx ')
-    funcs.complete(4, {{word='wordey', kind= 'x', menu='extrainfo'}, 'thing', {word='secret', abbr='sneaky', menu='bar'}})
-    screen:expect([[
-      xx wordey^                               |
-      {1:~ }{s: wordey x extrainfo }{1:                  }|
-      {1:~ }{n: thing              }{1:                  }|
-      {1:~ }{n: sneaky   bar       }{1:                  }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {2:-- INSERT --}                            |
-    ]])
-
-    feed('')
-    screen:expect([[
-      xx ^                                     |
-      {1:~ }{n: wordey x extrainfo }{1:                  }|
-      {1:~ }{n: thing              }{1:                  }|
-      {1:~ }{n: sneaky   bar       }{1:                  }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {2:-- INSERT --}                            |
-    ]])
-
-    feed('')
-    screen:expect([[
-      xx secret^                               |
-      {1:~ }{n: wordey x extrainfo }{1:                  }|
-      {1:~ }{n: thing              }{1:                  }|
-      {1:~ }{s: sneaky   bar       }{1:                  }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {2:-- INSERT --}                            |
-    ]])
-
-    feed('')
-    screen:expect([[
-      xx secre^t                               |
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-                                              |
-    ]])
-  end)
-
-  it('wildoptions=pum', function()
-    screen:try_resize(32,10)
-    command('set wildmenu')
-    command('set wildoptions=pum')
-    command('set shellslash')
-    command("cd test/functional/fixtures/wildpum")
-
-    feed(':sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :sign ^                          |
-    ]])
-
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{s: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign define^                    |
-    ]])
-
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{s: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign list^                      |
-    ]])
-
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{s: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign place^                     |
-    ]])
-
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{s: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign list^                      |
-    ]])
-
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{s: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign jump^                      |
-    ]])
-
-    -- pressing  should end completion and go back to the original match
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :sign ^                          |
-    ]])
-
-    -- pressing  should select the current match and end completion
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :sign unplace^                   |
-    ]])
-
-    -- showing popup menu in different columns in the cmdline
-    feed('sign define ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~           }{s: culhl=         }{1:    }|
-      {1:~           }{n: icon=          }{1:    }|
-      {1:~           }{n: linehl=        }{1:    }|
-      {1:~           }{n: numhl=         }{1:    }|
-      {1:~           }{n: text=          }{1:    }|
-      {1:~           }{n: texthl=        }{1:    }|
-      :sign define culhl=^             |
-    ]])
-
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                  }{s: culhl=     }{1: }|
-      {1:~                  }{n: icon=      }{1: }|
-      {1:~                  }{n: linehl=    }{1: }|
-      {1:~                  }{n: numhl=     }{1: }|
-      {1:~                  }{n: text=      }{1: }|
-      {1:~                  }{n: texthl=    }{1: }|
-      :sign define culhl= culhl=^      |
-    ]])
-
-    feed('e Xdi')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~      }{s: XdirA/         }{1:         }|
-      {1:~      }{n: XfileA         }{1:         }|
-      :e Xdir/XdirA/^                  |
-    ]])
-
-    -- Pressing  on a directory name should go into that directory
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~            }{s: XdirB/         }{1:   }|
-      {1:~            }{n: XfileB         }{1:   }|
-      :e Xdir/XdirA/XdirB/^            |
-    ]])
-
-    -- Pressing  on a directory name should go to the parent directory
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~      }{s: XdirA/         }{1:         }|
-      {1:~      }{n: XfileA         }{1:         }|
-      :e Xdir/XdirA/^                  |
-    ]])
-
-    -- Pressing  when the popup menu is displayed should list all the
-    -- matches and remove the popup menu
-    feed(':sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {4:                                }|
-      :sign define jump list place und|
-      efine unplace^                   |
-    ]])
-
-    -- Pressing  after that should move the cursor
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {4:                                }|
-      :sign define jump list place und|
-      efine unplac^e                   |
-    ]])
-    feed('')
-
-    -- Pressing  when the popup menu is displayed should remove the popup
-    -- menu
-    feed('sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {4:                                }|
-      :sign define                    |
-      define                          |
-      :sign define^                    |
-    ]])
-
-    -- Pressing  should open the popup menu with the last entry selected
-    feed(':sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{s: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign undefine^                  |
-    ]])
-
-    -- Pressing  should close the popup menu and cancel the cmd line
-    feed(':sign ')
-    screen:expect([[
-      ^                                |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-                                      |
-    ]])
-
-    -- Typing a character when the popup is open, should close the popup
-    feed(':sign x')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :sign definex^                   |
-    ]])
-
-    -- When the popup is open, entering the cmdline window should close the popup
-    feed('sign ')
-    screen:expect([[
-                                      |
-      {3:[No Name]                       }|
-      {1::}sign define                    |
-      {1::}sign define^                    |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {4:[Command Line]                  }|
-      :sign define                    |
-    ]])
-    feed(':q')
-
-    -- After the last popup menu item,  should show the original string
-    feed(':sign u')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign u^                         |
-    ]])
-
-    -- Use the popup menu for the command name
-    feed('bu')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {s: bufdo          }{1:                }|
-      {n: buffer         }{1:                }|
-      {n: buffers        }{1:                }|
-      {n: bunload        }{1:                }|
-      :bufdo^                          |
-    ]])
-
-    -- Pressing  should remove the popup menu and erase the last character
-    feed('sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :sign defin^                     |
-    ]])
-
-    -- Pressing  should remove the popup menu and erase the previous word
-    feed('sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :sign ^                          |
-    ]])
-
-    -- Pressing  should remove the popup menu and erase the entire line
-    feed('sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :^                               |
-    ]])
-
-    -- Using  to cancel the popup menu and then pressing  should recall
-    -- the cmdline from history
-    feed('sign xyz:sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :sign xyz^                       |
-    ]])
-
-    feed('')
-
-    -- Check "list" still works
-    command('set wildmode=longest,list')
-    feed(':cn')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {4:                                }|
-      :cn                             |
-      cnewer       cnoreabbrev        |
-      cnext        cnoremap           |
-      cnfile       cnoremenu          |
-      :cn^                             |
-    ]])
-    feed('s')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {4:                                }|
-      :cn                             |
-      cnewer       cnoreabbrev        |
-      cnext        cnoremap           |
-      cnfile       cnoremenu          |
-      :cns^                            |
-    ]])
-
-    feed('')
-    command('set wildmode=full')
-
-    -- Tests a directory name contained full-width characters.
-    feed(':e あいう/')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~        }{s: 123            }{1:       }|
-      {1:~        }{n: abc            }{1:       }|
-      {1:~        }{n: xyz            }{1:       }|
-      :e あいう/123^                   |
-    ]])
-    feed('')
-
-    -- Pressing  should scroll the menu downward
-    feed(':sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{s: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign undefine^                  |
-    ]])
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{s: unplace        }{1:           }|
-      :sign unplace^                   |
-    ]])
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign ^                          |
-    ]])
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{s: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign define^                    |
-    ]])
-    feed('sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{s: unplace        }{1:           }|
-      :sign unplace^                   |
-    ]])
-
-    -- Pressing  should scroll the menu upward
-    feed('sign ')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign ^                          |
-    ]])
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{s: unplace        }{1:           }|
-      :sign unplace^                   |
-    ]])
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{n: define         }{1:           }|
-      {1:~    }{s: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign jump^                      |
-    ]])
-    feed('')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~    }{s: define         }{1:           }|
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign define^                    |
-    ]])
-
-    feed('')
-
-    -- check positioning with multibyte char in pattern
-    command("e långfile1")
-    command("sp långfile2")
-    feed(':b lå')
-    screen:expect([[
-                                      |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {4:långfile2                       }|
-                                      |
-      {1:~                               }|
-      {1:~ }{s: långfile1      }{1:              }|
-      {3:lå}{n: långfile2      }{3:              }|
-      :b långfile1^                    |
-    ]])
-
-    -- check doesn't crash on screen resize
-    screen:try_resize(20,6)
-    screen:expect([[
-                          |
-      {1:~                   }|
-      {4:långfile2           }|
-        {s: långfile1      }  |
-      {3:lå}{n: långfile2      }{3:  }|
-      :b långfile1^        |
-    ]])
-
-    screen:try_resize(50,15)
-    screen:expect([[
-                                                        |
-      {1:~                                                 }|
-      {4:långfile2                                         }|
-                                                        |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~ }{s: långfile1      }{1:                                }|
-      {3:lå}{n: långfile2      }{3:                                }|
-      :b långfile1^                                      |
-    ]])
-
-    -- position is calculated correctly with "longest"
-    feed('')
-    command('set wildmode=longest:full,full')
-    feed(':b lå')
-    screen:expect([[
-                                                        |
-      {1:~                                                 }|
-      {4:långfile2                                         }|
-                                                        |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~ }{n: långfile1      }{1:                                }|
-      {3:lå}{n: långfile2      }{3:                                }|
-      :b långfile^                                       |
-    ]])
-
-    feed('')
-    command("close")
-    command('set wildmode=full')
-
-    -- special case: when patterns ends with "/", show menu items aligned
-    -- after the "/"
-    feed(':e compdir/')
-    screen:expect([[
-                                                        |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~         }{s: file1          }{1:                        }|
-      {1:~         }{n: file2          }{1:                        }|
-      :e compdir/file1^                                  |
-    ]])
-  end)
-
-  it('wildoptions=pum with scrolled messages', function()
-    screen:try_resize(40,10)
-    command('set wildmenu')
-    command('set wildoptions=pum')
-
-    feed(':echoerr "fail"|echoerr "error"')
-    screen:expect{grid=[[
-                                              |
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {4:                                        }|
-      {6:fail}                                    |
-      {6:error}                                   |
-      {5:Press ENTER or type command to continue}^ |
-    ]]}
-
-    feed(':sign ')
-    screen:expect{grid=[[
-                                              |
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~    }{s: define         }{1:                   }|
-      {1:~    }{n: jump           }{1:                   }|
-      {1:~    }{n: list           }{1:                   }|
-      {4:     }{n: place          }{4:                   }|
-      {6:fail} {n: undefine       }                   |
-      {6:error}{n: unplace        }                   |
-      :sign define^                            |
-    ]]}
-
-    feed('d')
-    screen:expect{grid=[[
-                                              |
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {1:~                                       }|
-      {4:                                        }|
-      {6:fail}                                    |
-      {6:error}                                   |
-      :sign defined^                           |
-    ]]}
-  end)
-
-  it('wildoptions=pum and wildmode=longest,full #11622', function()
-    screen:try_resize(30,8)
-    command('set wildmenu')
-    command('set wildoptions=pum')
-    command('set wildmode=longest,full')
-
-    -- With 'wildmode' set to 'longest,full', completing a match should display
-    -- the longest match, the wildmenu should not be displayed.
-    feed(':sign u')
-    screen:expect{grid=[[
-                                    |
-      {1:~                             }|
-      {1:~                             }|
-      {1:~                             }|
-      {1:~                             }|
-      {1:~                             }|
-      {1:~                             }|
-      :sign un^                      |
-    ]]}
-    eq(0, funcs.wildmenumode())
-
-    -- pressing  should display the wildmenu
-    feed('')
-    screen:expect{grid=[[
-                                    |
-      {1:~                             }|
-      {1:~                             }|
-      {1:~                             }|
-      {1:~                             }|
-      {1:~    }{s: undefine       }{1:         }|
-      {1:~    }{n: unplace        }{1:         }|
-      :sign undefine^                |
-    ]]}
-    eq(1, funcs.wildmenumode())
-
-    -- pressing  second time should select the next entry in the menu
-    feed('')
-    screen:expect{grid=[[
-                                    |
-      {1:~                             }|
-      {1:~                             }|
-      {1:~                             }|
-      {1:~                             }|
-      {1:~    }{n: undefine       }{1:         }|
-      {1:~    }{s: unplace        }{1:         }|
-      :sign unplace^                 |
-    ]]}
-  end)
-
-  it('wildoptions=pum with a wrapped line in buffer vim-patch:8.2.4655', function()
-    screen:try_resize(32, 10)
-    meths.buf_set_lines(0, 0, -1, true, { ('a'):rep(100) })
-    command('set wildoptions+=pum')
-    feed('$')
-    feed(':sign ')
-    screen:expect([[
-      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
-      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
-      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
-      aaaa {s: define         }           |
-      {1:~    }{n: jump           }{1:           }|
-      {1:~    }{n: list           }{1:           }|
-      {1:~    }{n: place          }{1:           }|
-      {1:~    }{n: undefine       }{1:           }|
-      {1:~    }{n: unplace        }{1:           }|
-      :sign define^                    |
-    ]])
-  end)
-
-  -- oldtest: Test_wildmenu_pum_clear_entries()
-  it('wildoptions=pum when using Ctrl-E as wildchar vim-patch:9.0.1030', function()
-    screen:try_resize(30, 10)
-    exec([[
-      set wildoptions=pum
-      set wildchar=
-    ]])
-    feed(':sign ')
-    screen:expect([[
-                                    |
-      {1:~                             }|
-      {1:~                             }|
-      {1:~    }{s: define         }{1:         }|
-      {1:~    }{n: jump           }{1:         }|
-      {1:~    }{n: list           }{1:         }|
-      {1:~    }{n: place          }{1:         }|
-      {1:~    }{n: undefine       }{1:         }|
-      {1:~    }{n: unplace        }{1:         }|
-      :sign define^                  |
-    ]])
-    assert_alive()
-  end)
-
-  it("'pumblend' RGB-color", function()
-    screen:try_resize(60,14)
+  it('RGB-color', function()
+    local screen = Screen.new(60, 14)
     screen:set_default_attr_ids({
       [1] = {background = Screen.colors.Yellow},
       [2] = {bold = true, reverse = true},
@@ -2933,6 +1075,7 @@ describe('builtin popupmenu', function()
       [44] = {foreground = tonumber('0x3f3f3f'), background = tonumber('0x7f5d7f')},
       [45] = {background = Screen.colors.WebGray, blend=0},
     })
+    screen:attach()
     command('syntax on')
     command('set mouse=a')
     command('set pumblend=10')
@@ -3081,10 +1224,8 @@ describe('builtin popupmenu', function()
     ]])
   end)
 
-  it("'pumblend' 256-color (non-RGB)", function()
-    screen:detach()
-    screen = Screen.new(60, 8)
-    screen:attach({rgb=false, ext_popupmenu=false})
+  it('256-color (non-RGB)', function()
+    local screen = Screen.new(60, 8)
     screen:set_default_attr_ids({
       [1] = {foreground = Screen.colors.Grey0, background = tonumber('0x000007')},
       [2] = {foreground = tonumber('0x000055'), background = tonumber('0x000007')},
@@ -3097,6 +1238,7 @@ describe('builtin popupmenu', function()
       [9] = {bold = true},
       [10] = {foreground = tonumber('0x000002')},
     })
+    screen:attach({rgb=false})
     command('set notermguicolors pumblend=10')
     insert([[
       Lorem ipsum dolor sit amet, consectetur
@@ -3117,713 +1259,3326 @@ describe('builtin popupmenu', function()
       {9:-- Keyword Local completion (^N^P) }{10:match 1 of 3}             |
     ]])
   end)
+end)
 
-  it("'pumheight'", function()
-    screen:try_resize(32,8)
-    feed('isome long prefix before the ')
-    command("set completeopt+=noinsert,noselect")
-    command("set linebreak")
-    command("set pumheight=2")
-    funcs.complete(29, {'word', 'choice', 'text', 'thing'})
-    screen:expect([[
-      some long prefix before the ^    |
-      {1:~                       }{n: word  }{c: }|
-      {1:~                       }{n: choice}{s: }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {2:-- INSERT --}                    |
-    ]])
-  end)
+describe('builtin popupmenu', function()
+  before_each(clear)
 
-  it("'pumwidth'", function()
-    screen:try_resize(32,8)
-    feed('isome long prefix before the ')
-    command("set completeopt+=noinsert,noselect")
-    command("set linebreak")
-    command("set pumwidth=8")
-    funcs.complete(29, {'word', 'choice', 'text', 'thing'})
-    screen:expect([[
-      some long prefix before the ^    |
-      {1:~                        }{n: word  }|
-      {1:~                        }{n: choice}|
-      {1:~                        }{n: text  }|
-      {1:~                        }{n: thing }|
-      {1:~                               }|
-      {1:~                               }|
-      {2:-- INSERT --}                    |
-    ]])
-  end)
+  local function with_ext_multigrid(multigrid)
+    local screen
+    before_each(function()
+      screen = Screen.new(32, 20)
+      screen:set_default_attr_ids({
+        -- popup selected item / scrollbar track
+        ['s'] = {background = Screen.colors.WebGray},
+        -- popup non-selected item
+        ['n'] = {background = Screen.colors.LightMagenta},
+        -- popup scrollbar knob
+        ['c'] = {background = Screen.colors.Grey0},
+        [1] = {bold = true, foreground = Screen.colors.Blue},
+        [2] = {bold = true},
+        [3] = {reverse = true},
+        [4] = {bold = true, reverse = true},
+        [5] = {bold = true, foreground = Screen.colors.SeaGreen},
+        [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+        [7] = {background = Screen.colors.Yellow},  -- Search
+        [8] = {foreground = Screen.colors.Red},
+      })
+      screen:attach({ext_multigrid=multigrid})
+    end)
 
-  it('does not crash when displayed in the last column with rightleft (#12032)', function()
-    local col = 30
-    local items = {'word', 'choice', 'text', 'thing'}
-    local max_len = 0
-    for _, v in ipairs(items) do
-      max_len = max_len < #v and #v or max_len
-    end
-    screen:try_resize(col, 8)
-    command('set rightleft')
-    command('call setline(1, repeat(" ", &columns - '..max_len..'))')
-    feed('$i')
-    funcs.complete(col - max_len, items)
-    feed('')
-    assert_alive()
-  end)
+    it('with preview-window above', function()
+      feed(':ped4+')
+      feed('iaa bb cc dd ee ff gg hh ii jj')
+      feed('')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          {3:[No Name] [Preview][+]          }|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {4:[No Name] [+]                   }|
+          [3:--------------------------------]|
+        ## grid 2
+          aa bb cc dd ee ff gg hh ii jj   |
+          aa^                              |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          {2:-- }{5:match 1 of 10}                |
+        ## grid 4
+          aa bb cc dd ee ff gg hh ii jj   |
+          aa                              |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 5
+          {s:aa             }{c: }|
+          {n:bb             }{c: }|
+          {n:cc             }{c: }|
+          {n:dd             }{c: }|
+          {n:ee             }{c: }|
+          {n:ff             }{c: }|
+          {n:gg             }{s: }|
+          {n:hh             }{s: }|
+        ]], float_pos={
+          [5] = {{id = -1}, "NW", 2, 2, 0, false, 100};
+        }}
+      else
+        screen:expect([[
+          aa bb cc dd ee ff gg hh ii jj   |
+          aa                              |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {3:[No Name] [Preview][+]          }|
+          aa bb cc dd ee ff gg hh ii jj   |
+          aa^                              |
+          {s:aa             }{c: }{1:                }|
+          {n:bb             }{c: }{1:                }|
+          {n:cc             }{c: }{1:                }|
+          {n:dd             }{c: }{1:                }|
+          {n:ee             }{c: }{1:                }|
+          {n:ff             }{c: }{1:                }|
+          {n:gg             }{s: }{1:                }|
+          {n:hh             }{s: }{4:                }|
+          {2:-- }{5:match 1 of 10}                |
+        ]])
+      end
+    end)
 
-  it('truncates double-width character correctly when there is no scrollbar', function()
-    screen:try_resize(32,8)
-    command('set completeopt+=menuone,noselect')
-    feed('i' .. string.rep(' ', 13))
-    funcs.complete(14, {'哦哦哦哦哦哦哦哦哦哦'})
-    screen:expect([[
-                   ^                   |
-      {1:~           }{n: 哦哦哦哦哦哦哦哦哦>}|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {2:-- INSERT --}                    |
-    ]])
-  end)
+    it('with preview-window below', function()
+      feed(':ped4+r')
+      feed('iaa bb cc dd ee ff gg hh ii jj')
+      feed('')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {4:[No Name] [+]                   }|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          {3:[No Name] [Preview][+]          }|
+          [3:--------------------------------]|
+        ## grid 2
+          aa bb cc dd ee ff gg hh ii jj   |
+          aa^                              |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          {2:-- }{5:match 1 of 10}                |
+        ## grid 4
+          aa bb cc dd ee ff gg hh ii jj   |
+          aa                              |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 5
+          {s:aa             }{c: }|
+          {n:bb             }{c: }|
+          {n:cc             }{c: }|
+          {n:dd             }{c: }|
+          {n:ee             }{c: }|
+          {n:ff             }{c: }|
+          {n:gg             }{s: }|
+          {n:hh             }{s: }|
+        ]], float_pos={
+          [5] = {{id = -1}, "NW", 2, 2, 0, false, 100};
+        }}
+      else
+        screen:expect([[
+          aa bb cc dd ee ff gg hh ii jj   |
+          aa^                              |
+          {s:aa             }{c: }{1:                }|
+          {n:bb             }{c: }{1:                }|
+          {n:cc             }{c: }{1:                }|
+          {n:dd             }{c: }{1:                }|
+          {n:ee             }{c: }{1:                }|
+          {n:ff             }{c: }{1:                }|
+          {n:gg             }{s: }{1:                }|
+          {n:hh             }{s: }{4:                }|
+          aa bb cc dd ee ff gg hh ii jj   |
+          aa                              |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {3:[No Name] [Preview][+]          }|
+          {2:-- }{5:match 1 of 10}                |
+        ]])
+      end
+    end)
 
-  it('truncates double-width character correctly when there is scrollbar', function()
-    screen:try_resize(32,8)
-    command('set completeopt+=noselect')
-    command('set pumheight=4')
-    feed('i' .. string.rep(' ', 12))
-    local items = {}
-    for _ = 1, 8 do
-      table.insert(items, {word = '哦哦哦哦哦哦哦哦哦哦', equal = 1, dup = 1})
-    end
-    funcs.complete(13, items)
-    screen:expect([[
-                  ^                    |
-      {1:~          }{n: 哦哦哦哦哦哦哦哦哦>}{c: }|
-      {1:~          }{n: 哦哦哦哦哦哦哦哦哦>}{c: }|
-      {1:~          }{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
-      {1:~          }{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
-      {1:~                               }|
-      {1:~                               }|
-      {2:-- INSERT --}                    |
-    ]])
-  end)
+    it('with preview-window above and tall and inverted', function()
+      feed(':ped8+')
+      feed('iaabbccddee')
+      feed('ffgghhiijj')
+      feed('kkllmmnnoo')
+      feed('')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          {3:[No Name] [Preview][+]          }|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {4:[No Name] [+]                   }|
+          [3:--------------------------------]|
+        ## grid 2
+          dd                              |
+          ee                              |
+          ff                              |
+          gg                              |
+          hh                              |
+          ii                              |
+          jj                              |
+          kk                              |
+          ll                              |
+          mm                              |
+          nn                              |
+          oo                              |
+          aa^                              |
+        ## grid 3
+          {2:-- }{5:match 1 of 15}                |
+        ## grid 4
+          aa                              |
+          bb                              |
+          cc                              |
+          dd                              |
+        ## grid 5
+          {s:aa             }{c: }|
+          {n:bb             }{c: }|
+          {n:cc             }{c: }|
+          {n:dd             }{c: }|
+          {n:ee             }{c: }|
+          {n:ff             }{c: }|
+          {n:gg             }{c: }|
+          {n:hh             }{c: }|
+          {n:ii             }{c: }|
+          {n:jj             }{c: }|
+          {n:kk             }{c: }|
+          {n:ll             }{s: }|
+          {n:mm             }{s: }|
+        ]], float_pos={
+          [5] = {{id = -1}, "SW", 2, 12, 0, false, 100};
+        }}
+      else
+        screen:expect([[
+          aa                              |
+          bb                              |
+          cc                              |
+          dd                              |
+          {s:aa             }{c: }{3:ew][+]          }|
+          {n:bb             }{c: }                |
+          {n:cc             }{c: }                |
+          {n:dd             }{c: }                |
+          {n:ee             }{c: }                |
+          {n:ff             }{c: }                |
+          {n:gg             }{c: }                |
+          {n:hh             }{c: }                |
+          {n:ii             }{c: }                |
+          {n:jj             }{c: }                |
+          {n:kk             }{c: }                |
+          {n:ll             }{s: }                |
+          {n:mm             }{s: }                |
+          aa^                              |
+          {4:[No Name] [+]                   }|
+          {2:-- }{5:match 1 of 15}                |
+        ]])
+      end
+    end)
 
-  it('supports mousemodel=popup', function()
-    screen:try_resize(32, 6)
-    exec([[
-      call setline(1, 'popup menu test')
-      set mouse=a mousemodel=popup
+    it('with preview-window above and short and inverted', function()
+      feed(':ped4+')
+      feed('iaabbccddee')
+      feed('ffgghhiijj')
+      feed('')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          {3:[No Name] [Preview][+]          }|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {4:[No Name] [+]                   }|
+          [3:--------------------------------]|
+        ## grid 2
+          cc                              |
+          dd                              |
+          ee                              |
+          ff                              |
+          gg                              |
+          hh                              |
+          ii                              |
+          jj                              |
+          aa^                              |
+        ## grid 3
+          {2:-- }{5:match 1 of 10}                |
+        ## grid 4
+          aa                              |
+          bb                              |
+          cc                              |
+          dd                              |
+          ee                              |
+          ff                              |
+          gg                              |
+          hh                              |
+        ## grid 5
+          {s:aa             }{c: }|
+          {n:bb             }{c: }|
+          {n:cc             }{c: }|
+          {n:dd             }{c: }|
+          {n:ee             }{c: }|
+          {n:ff             }{c: }|
+          {n:gg             }{c: }|
+          {n:hh             }{c: }|
+          {n:ii             }{s: }|
+        ]], float_pos={
+          [5] = {{id = -1}, "SW", 2, 8, 0, false, 100};
+        }}
+      else
+        screen:expect([[
+          aa                              |
+          bb                              |
+          cc                              |
+          dd                              |
+          ee                              |
+          ff                              |
+          gg                              |
+          hh                              |
+          {s:aa             }{c: }{3:ew][+]          }|
+          {n:bb             }{c: }                |
+          {n:cc             }{c: }                |
+          {n:dd             }{c: }                |
+          {n:ee             }{c: }                |
+          {n:ff             }{c: }                |
+          {n:gg             }{c: }                |
+          {n:hh             }{c: }                |
+          {n:ii             }{s: }                |
+          aa^                              |
+          {4:[No Name] [+]                   }|
+          {2:-- }{5:match 1 of 10}                |
+        ]])
+      end
+    end)
 
-      aunmenu PopUp
-      menu PopUp.foo :let g:menustr = 'foo'
-      menu PopUp.bar :let g:menustr = 'bar'
-      menu PopUp.baz :let g:menustr = 'baz'
-    ]])
-    feed('<4,0>')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~  }{n: foo }{1:                        }|
-      {1:~  }{n: bar }{1:                        }|
-      {1:~  }{n: baz }{1:                        }|
-      {1:~                               }|
-                                      |
-    ]])
-    feed('')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~  }{s: foo }{1:                        }|
-      {1:~  }{n: bar }{1:                        }|
-      {1:~  }{n: baz }{1:                        }|
-      {1:~                               }|
-                                      |
-    ]])
-    feed('')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~  }{n: foo }{1:                        }|
-      {1:~  }{s: bar }{1:                        }|
-      {1:~  }{n: baz }{1:                        }|
-      {1:~                               }|
-                                      |
-    ]])
-    feed('')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :let g:menustr = 'bar'          |
-    ]])
-    eq('bar', meths.get_var('menustr'))
-    feed('<20,2>')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                  }{n: foo }{1:        }|
-      {1:~                  }{n: bar }{1:        }|
-      :let g:menustr = 'b{n: baz }        |
-    ]])
-    feed('<22,5>')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :let g:menustr = 'baz'          |
-    ]])
-    eq('baz', meths.get_var('menustr'))
-    feed('<4,0>')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~  }{n: foo }{1:                        }|
-      {1:~  }{n: bar }{1:                        }|
-      {1:~  }{n: baz }{1:                        }|
-      {1:~                               }|
-      :let g:menustr = 'baz'          |
-    ]])
-    feed('<6,3>')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~  }{n: foo }{1:                        }|
-      {1:~  }{n: bar }{1:                        }|
-      {1:~  }{s: baz }{1:                        }|
-      {1:~                               }|
-      :let g:menustr = 'baz'          |
-    ]])
-    feed('<6,1>')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :let g:menustr = 'foo'          |
-    ]])
-    eq('foo', meths.get_var('menustr'))
-    eq(false, screen.options.mousemoveevent)
-    feed('<4,0>')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~  }{n: foo }{1:                        }|
-      {1:~  }{n: bar }{1:                        }|
-      {1:~  }{n: baz }{1:                        }|
-      {1:~                               }|
-      :let g:menustr = 'foo'          |
-    ]])
-    eq(true, screen.options.mousemoveevent)
-    feed('<6,3>')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~  }{n: foo }{1:                        }|
-      {1:~  }{n: bar }{1:                        }|
-      {1:~  }{s: baz }{1:                        }|
-      {1:~                               }|
-      :let g:menustr = 'foo'          |
-    ]])
-    eq(true, screen.options.mousemoveevent)
-    feed('<6,2>')
-    screen:expect([[
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :let g:menustr = 'bar'          |
-    ]])
-    eq(false, screen.options.mousemoveevent)
-    eq('bar', meths.get_var('menustr'))
-  end)
+    it('with preview-window below and inverted', function()
+      feed(':ped4+r')
+      feed('iaabbccddee')
+      feed('ffgghhiijj')
+      feed('')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {4:[No Name] [+]                   }|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          [4:--------------------------------]|
+          {3:[No Name] [Preview][+]          }|
+          [3:--------------------------------]|
+        ## grid 2
+          cc                              |
+          dd                              |
+          ee                              |
+          ff                              |
+          gg                              |
+          hh                              |
+          ii                              |
+          jj                              |
+          aa^                              |
+        ## grid 3
+          {2:-- }{5:match 1 of 10}                |
+        ## grid 4
+          aa                              |
+          bb                              |
+          cc                              |
+          dd                              |
+          ee                              |
+          ff                              |
+          gg                              |
+          hh                              |
+        ## grid 5
+          {s:aa             }{c: }|
+          {n:bb             }{c: }|
+          {n:cc             }{c: }|
+          {n:dd             }{c: }|
+          {n:ee             }{c: }|
+          {n:ff             }{c: }|
+          {n:gg             }{s: }|
+          {n:hh             }{s: }|
+        ]], float_pos={
+          [5] = {{id = -1}, "SW", 2, 8, 0, false, 100};
+        }}
+      else
+        screen:expect([[
+          {s:aa             }{c: }                |
+          {n:bb             }{c: }                |
+          {n:cc             }{c: }                |
+          {n:dd             }{c: }                |
+          {n:ee             }{c: }                |
+          {n:ff             }{c: }                |
+          {n:gg             }{s: }                |
+          {n:hh             }{s: }                |
+          aa^                              |
+          {4:[No Name] [+]                   }|
+          aa                              |
+          bb                              |
+          cc                              |
+          dd                              |
+          ee                              |
+          ff                              |
+          gg                              |
+          hh                              |
+          {3:[No Name] [Preview][+]          }|
+          {2:-- }{5:match 1 of 10}                |
+        ]])
+      end
+    end)
 
-  -- oldtest: Test_popup_command_dump()
-  it(':popup command', function()
-    exec([[
-      func ChangeMenu()
-        aunmenu PopUp.&Paste
-        nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"
-        echomsg 'changed'
-        return "\"
-      endfunc
-
-      let lines =<< trim END
-        one two three four five
-        and one two Xthree four five
-        one more two three four five
-      END
-      call setline(1, lines)
-
-      aunmenu *
-      source $VIMRUNTIME/menu.vim
-    ]])
-    feed('/X:popup PopUp')
-    screen:expect([[
-      one two three four five         |
-      and one two {7:^X}three four five    |
-      one more tw{n: Undo             }   |
-      {1:~          }{n:                  }{1:   }|
-      {1:~          }{n: Paste            }{1:   }|
-      {1:~          }{n:                  }{1:   }|
-      {1:~          }{n: Select Word      }{1:   }|
-      {1:~          }{n: Select Sentence  }{1:   }|
-      {1:~          }{n: Select Paragraph }{1:   }|
-      {1:~          }{n: Select Line      }{1:   }|
-      {1:~          }{n: Select Block     }{1:   }|
-      {1:~          }{n: Select All       }{1:   }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :popup PopUp                    |
-    ]])
+    if not multigrid then
+      -- oldtest: Test_pum_with_preview_win()
+      it('preview window opened during completion', function()
+        exec([[
+          funct Omni_test(findstart, base)
+            if a:findstart
+              return col(".") - 1
+            endif
+            return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}]
+          endfunc
+          set omnifunc=Omni_test
+          set completeopt+=longest
+        ]])
+        feed('Gi')
+        screen:expect([[
+          ^                                |
+          {n:one            }{1:                 }|
+          {n:two            }{1:                 }|
+          {n:three          }{1:                 }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {2:-- }{8:Back at original}             |
+        ]])
+        feed('')
+        screen:expect([[
+          1info                           |
+                                          |
+          {1:~                               }|
+          {3:[Scratch] [Preview]             }|
+          one^                             |
+          {s:one            }{1:                 }|
+          {n:two            }{1:                 }|
+          {n:three          }{1:                 }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {4:[No Name] [+]                   }|
+          {2:-- }{5:match 1 of 3}                 |
+        ]])
+      end)
+    end
 
-    -- go to the Paste entry in the menu
-    feed('jj')
-    screen:expect([[
-      one two three four five         |
-      and one two {7:^X}three four five    |
-      one more tw{n: Undo             }   |
-      {1:~          }{n:                  }{1:   }|
-      {1:~          }{s: Paste            }{1:   }|
-      {1:~          }{n:                  }{1:   }|
-      {1:~          }{n: Select Word      }{1:   }|
-      {1:~          }{n: Select Sentence  }{1:   }|
-      {1:~          }{n: Select Paragraph }{1:   }|
-      {1:~          }{n: Select Line      }{1:   }|
-      {1:~          }{n: Select Block     }{1:   }|
-      {1:~          }{n: Select All       }{1:   }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      :popup PopUp                    |
-    ]])
+    it('with vsplits', function()
+      screen:try_resize(32, 8)
+      insert('aaa aab aac\n')
+      feed(':vsplit')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [4:--------------------]│[2:-----------]|
+          [4:--------------------]│[2:-----------]|
+          [4:--------------------]│[2:-----------]|
+          [4:--------------------]│[2:-----------]|
+          [4:--------------------]│[2:-----------]|
+          [4:--------------------]│[2:-----------]|
+          {4:[No Name] [+]        }{3:')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [4:--------------------]│[2:-----------]|
+          [4:--------------------]│[2:-----------]|
+          [4:--------------------]│[2:-----------]|
+          [4:--------------------]│[2:-----------]|
+          [4:--------------------]│[2:-----------]|
+          [4:--------------------]│[2:-----------]|
+          {4:[No Name] [+]        }{3:oc a')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          {3:')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          {3:')
+        screen:expect([[
+          Est ^                                                        |
+            L{n: sunt           }{s: }sit amet, consectetur                   |
+            a{n: in             }{s: }sed do eiusmod tempor                   |
+            i{n: culpa          }{s: }re et dolore magna aliqua.              |
+            U{n: qui            }{s: }eniam, quis nostrud                     |
+            e{n: officia        }{s: }co laboris nisi ut aliquip ex           |
+          {4:[No}{n: deserunt       }{s: }{4:                                        }|
+          Est{n: mollit         }{s: }                                        |
+            L{n: anim           }{s: }sit amet, consectetur                   |
+            a{n: id             }{s: }sed do eiusmod tempor                   |
+            i{n: est            }{s: }re et dolore magna aliqua.              |
+            U{n: laborum        }{c: }eniam, quis nostrud                     |
+          {3:[No}{s: Est            }{c: }{3:                                        }|
+          {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
+        ]])
+
+        meths.input_mouse('wheel', 'down', '', 0, 9, 40)
+        screen:expect([[
+          Est ^                                                        |
+            L{n: sunt           }{s: }sit amet, consectetur                   |
+            a{n: in             }{s: }sed do eiusmod tempor                   |
+            i{n: culpa          }{s: }re et dolore magna aliqua.              |
+            U{n: qui            }{s: }eniam, quis nostrud                     |
+            e{n: officia        }{s: }co laboris nisi ut aliquip ex           |
+          {4:[No}{n: deserunt       }{s: }{4:                                        }|
+            i{n: mollit         }{s: }re et dolore magna aliqua.              |
+            U{n: anim           }{s: }eniam, quis nostrud                     |
+            e{n: id             }{s: }co laboris nisi ut aliquip ex           |
+            e{n: est            }{s: }at. Duis aute irure dolor in            |
+            r{n: laborum        }{c: }oluptate velit esse cillum              |
+          {3:[No}{s: Est            }{c: }{3:                                        }|
+          {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
+        ]])
+
+        feed('e')
+        screen:expect([[
+          Est e^                                                       |
+            L{n: elit           } sit amet, consectetur                   |
+            a{n: eiusmod        } sed do eiusmod tempor                   |
+            i{n: et             }ore et dolore magna aliqua.              |
+            U{n: enim           }veniam, quis nostrud                     |
+            e{n: exercitation   }mco laboris nisi ut aliquip ex           |
+          {4:[No}{n: ex             }{4:                                         }|
+            i{n: ea             }ore et dolore magna aliqua.              |
+            U{n: esse           }veniam, quis nostrud                     |
+            e{n: eu             }mco laboris nisi ut aliquip ex           |
+            e{s: est            }uat. Duis aute irure dolor in            |
+            reprehenderit in voluptate velit esse cillum              |
+          {3:[No Name] [+]                                               }|
+          {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
+        ]])
+
+        meths.input_mouse('wheel', 'up', '', 0, 9, 40)
+        screen:expect([[
+          Est e^                                                       |
+            L{n: elit           } sit amet, consectetur                   |
+            a{n: eiusmod        } sed do eiusmod tempor                   |
+            i{n: et             }ore et dolore magna aliqua.              |
+            U{n: enim           }veniam, quis nostrud                     |
+            e{n: exercitation   }mco laboris nisi ut aliquip ex           |
+          {4:[No}{n: ex             }{4:                                         }|
+          Est{n: ea             }                                         |
+            L{n: esse           } sit amet, consectetur                   |
+            a{n: eu             } sed do eiusmod tempor                   |
+            i{s: est            }ore et dolore magna aliqua.              |
+            Ut enim ad minim veniam, quis nostrud                     |
+          {3:[No Name] [+]                                               }|
+          {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
+        ]])
+
+        feed('s')
+        screen:expect([[
+          Est es^                                                      |
+            L{n: esse           } sit amet, consectetur                   |
+            a{s: est            } sed do eiusmod tempor                   |
+            incididunt ut labore et dolore magna aliqua.              |
+            Ut enim ad minim veniam, quis nostrud                     |
+            exercitation ullamco laboris nisi ut aliquip ex           |
+          {4:[No Name] [+]                                               }|
+          Est es                                                      |
+            Lorem ipsum dolor sit amet, consectetur                   |
+            adipisicing elit, sed do eiusmod tempor                   |
+            incididunt ut labore et dolore magna aliqua.              |
+            Ut enim ad minim veniam, quis nostrud                     |
+          {3:[No Name] [+]                                               }|
+          {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
+        ]])
+
+        meths.input_mouse('wheel', 'down', '', 0, 9, 40)
+        screen:expect([[
+          Est es^                                                      |
+            L{n: esse           } sit amet, consectetur                   |
+            a{s: est            } sed do eiusmod tempor                   |
+            incididunt ut labore et dolore magna aliqua.              |
+            Ut enim ad minim veniam, quis nostrud                     |
+            exercitation ullamco laboris nisi ut aliquip ex           |
+          {4:[No Name] [+]                                               }|
+            incididunt ut labore et dolore magna aliqua.              |
+            Ut enim ad minim veniam, quis nostrud                     |
+            exercitation ullamco laboris nisi ut aliquip ex           |
+            ea commodo consequat. Duis aute irure dolor in            |
+            reprehenderit in voluptate velit esse cillum              |
+          {3:[No Name] [+]                                               }|
+          {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
+        ]])
+
+        feed('')
+        screen:expect([[
+          Est e^                                                       |
+            L{n: elit           } sit amet, consectetur                   |
+            a{n: eiusmod        } sed do eiusmod tempor                   |
+            i{n: et             }ore et dolore magna aliqua.              |
+            U{n: enim           }veniam, quis nostrud                     |
+            e{n: exercitation   }mco laboris nisi ut aliquip ex           |
+          {4:[No}{n: ex             }{4:                                         }|
+            i{n: ea             }ore et dolore magna aliqua.              |
+            U{n: esse           }veniam, quis nostrud                     |
+            e{n: eu             }mco laboris nisi ut aliquip ex           |
+            e{s: est            }uat. Duis aute irure dolor in            |
+            reprehenderit in voluptate velit esse cillum              |
+          {3:[No Name] [+]                                               }|
+          {2:-- Keyword Local completion (^N^P) }{5:match 1 of 65}            |
+        ]])
+
+        feed('')
+        screen:expect([[
+          Est eu^                                                      |
+            L{n: elit           } sit amet, consectetur                   |
+            a{n: eiusmod        } sed do eiusmod tempor                   |
+            i{n: et             }ore et dolore magna aliqua.              |
+            U{n: enim           }veniam, quis nostrud                     |
+            e{n: exercitation   }mco laboris nisi ut aliquip ex           |
+          {4:[No}{n: ex             }{4:                                         }|
+            i{n: ea             }ore et dolore magna aliqua.              |
+            U{n: esse           }veniam, quis nostrud                     |
+            e{s: eu             }mco laboris nisi ut aliquip ex           |
+            e{n: est            }uat. Duis aute irure dolor in            |
+            reprehenderit in voluptate velit esse cillum              |
+          {3:[No Name] [+]                                               }|
+          {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65}           |
+        ]])
+
+        meths.input_mouse('wheel', 'down', '', 0, 9, 40)
+        screen:expect([[
+          Est eu^                                                      |
+            L{n: elit           } sit amet, consectetur                   |
+            a{n: eiusmod        } sed do eiusmod tempor                   |
+            i{n: et             }ore et dolore magna aliqua.              |
+            U{n: enim           }veniam, quis nostrud                     |
+            e{n: exercitation   }mco laboris nisi ut aliquip ex           |
+          {4:[No}{n: ex             }{4:                                         }|
+            e{n: ea             }uat. Duis aute irure dolor in            |
+            r{n: esse           }voluptate velit esse cillum              |
+            d{s: eu             }nulla pariatur. Excepteur sint           |
+            o{n: est            }t non proident, sunt in culpa            |
+            qui officia deserunt mollit anim id est                   |
+          {3:[No Name] [+]                                               }|
+          {2:-- Keyword Local completion (^N^P) }{5:match 22 of 65}           |
+        ]])
+
+        funcs.complete(4, {'ea', 'eeeeeeeeeeeeeeeeee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'})
+        screen:expect([[
+          Est eu^                                                      |
+            {s: ea                 }t amet, consectetur                   |
+            {n: eeeeeeeeeeeeeeeeee }d do eiusmod tempor                   |
+            {n: ei                 } et dolore magna aliqua.              |
+            {n: eo                 }iam, quis nostrud                     |
+            {n: eu                 } laboris nisi ut aliquip ex           |
+          {4:[N}{n: ey                 }{4:                                      }|
+            {n: eå                 }. Duis aute irure dolor in            |
+            {n: eä                 }uptate velit esse cillum              |
+            {n: eö                 }la pariatur. Excepteur sint           |
+            occaecat cupidatat non proident, sunt in culpa            |
+            qui officia deserunt mollit anim id est                   |
+          {3:[No Name] [+]                                               }|
+          {2:-- Keyword Local completion (^N^P) }{5:match 1 of 9}             |
+        ]])
+
+        funcs.complete(4, {'ea', 'eee', 'ei', 'eo', 'eu', 'ey', 'eå', 'eä', 'eö'})
+        screen:expect([[
+          Est eu^                                                      |
+            {s: ea             }r sit amet, consectetur                   |
+            {n: eee            }, sed do eiusmod tempor                   |
+            {n: ei             }bore et dolore magna aliqua.              |
+            {n: eo             } veniam, quis nostrud                     |
+            {n: eu             }amco laboris nisi ut aliquip ex           |
+          {4:[N}{n: ey             }{4:                                          }|
+            {n: eå             }quat. Duis aute irure dolor in            |
+            {n: eä             } voluptate velit esse cillum              |
+            {n: eö             } nulla pariatur. Excepteur sint           |
+            occaecat cupidatat non proident, sunt in culpa            |
+            qui officia deserunt mollit anim id est                   |
+          {3:[No Name] [+]                                               }|
+          {2:-- INSERT --}                                                |
+        ]])
+
+        feed('')
+        screen:expect([[
+          Esteee^                                                      |
+            {n: ea             }r sit amet, consectetur                   |
+            {s: eee            }, sed do eiusmod tempor                   |
+            {n: ei             }bore et dolore magna aliqua.              |
+            {n: eo             } veniam, quis nostrud                     |
+            {n: eu             }amco laboris nisi ut aliquip ex           |
+          {4:[N}{n: ey             }{4:                                          }|
+            {n: eå             }quat. Duis aute irure dolor in            |
+            {n: eä             } voluptate velit esse cillum              |
+            {n: eö             } nulla pariatur. Excepteur sint           |
+            occaecat cupidatat non proident, sunt in culpa            |
+            qui officia deserunt mollit anim id est                   |
+          {3:[No Name] [+]                                               }|
+          {2:-- INSERT --}                                                |
+        ]])
+
+        funcs.complete(6, {'foo', 'bar'})
+        screen:expect([[
+          Esteee^                                                      |
+            Lo{s: foo            }sit amet, consectetur                   |
+            ad{n: bar            }sed do eiusmod tempor                   |
+            incididunt ut labore et dolore magna aliqua.              |
+            Ut enim ad minim veniam, quis nostrud                     |
+            exercitation ullamco laboris nisi ut aliquip ex           |
+          {4:[No Name] [+]                                               }|
+            ea commodo consequat. Duis aute irure dolor in            |
+            reprehenderit in voluptate velit esse cillum              |
+            dolore eu fugiat nulla pariatur. Excepteur sint           |
+            occaecat cupidatat non proident, sunt in culpa            |
+            qui officia deserunt mollit anim id est                   |
+          {3:[No Name] [+]                                               }|
+          {2:-- INSERT --}                                                |
+        ]])
+
+        feed('')
+        screen:expect([[
+          Esteefoo^                                                    |
+            Lorem ipsum dolor sit amet, consectetur                   |
+            adipisicing elit, sed do eiusmod tempor                   |
+            incididunt ut labore et dolore magna aliqua.              |
+            Ut enim ad minim veniam, quis nostrud                     |
+            exercitation ullamco laboris nisi ut aliquip ex           |
+          {4:[No Name] [+]                                               }|
+            ea commodo consequat. Duis aute irure dolor in            |
+            reprehenderit in voluptate velit esse cillum              |
+            dolore eu fugiat nulla pariatur. Excepteur sint           |
+            occaecat cupidatat non proident, sunt in culpa            |
+            qui officia deserunt mollit anim id est                   |
+          {3:[No Name] [+]                                               }|
+          {2:-- INSERT --}                                                |
+        ]])
+      end)
+
+      it('can be moved due to wrap or resize', function()
+        feed('isome long prefix before the ')
+        command("set completeopt+=noinsert,noselect")
+        command("set linebreak")
+        funcs.complete(29, {'word', 'choice', 'text', 'thing'})
+        screen:expect([[
+          some long prefix before the ^    |
+          {1:~                        }{n: word  }|
+          {1:~                        }{n: choice}|
+          {1:~                        }{n: text  }|
+          {1:~                        }{n: thing }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {2:-- INSERT --}                    |
+        ]])
+
+        feed('')
+        screen:expect([[
+          some long prefix before the     |
+          thing^                           |
+          {n:word           }{1:                 }|
+          {n:choice         }{1:                 }|
+          {n:text           }{1:                 }|
+          {s:thing          }{1:                 }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {2:-- INSERT --}                    |
+        ]])
+
+        feed('')
+        screen:expect([[
+          some long prefix before the text|
+          {1:^~                        }{n: word  }|
+          {1:~                        }{n: choice}|
+          {1:~                        }{s: text  }|
+          {1:~                        }{n: thing }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {2:-- INSERT --}                    |
+        ]])
+
+        screen:try_resize(30,8)
+        screen:expect([[
+          some long prefix before the   |
+          text^                          |
+          {n:word           }{1:               }|
+          {n:choice         }{1:               }|
+          {s:text           }{1:               }|
+          {n:thing          }{1:               }|
+          {1:~                             }|
+          {2:-- INSERT --}                  |
+        ]])
+
+        screen:try_resize(50,8)
+        screen:expect([[
+          some long prefix before the text^                  |
+          {1:~                          }{n: word           }{1:       }|
+          {1:~                          }{n: choice         }{1:       }|
+          {1:~                          }{s: text           }{1:       }|
+          {1:~                          }{n: thing          }{1:       }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {2:-- INSERT --}                                      |
+        ]])
+
+        screen:try_resize(25,10)
+        screen:expect([[
+          some long prefix before  |
+          the text^                 |
+          {1:~  }{n: word           }{1:      }|
+          {1:~  }{n: choice         }{1:      }|
+          {1:~  }{s: text           }{1:      }|
+          {1:~  }{n: thing          }{1:      }|
+          {1:~                        }|
+          {1:~                        }|
+          {1:~                        }|
+          {2:-- INSERT --}             |
+        ]])
+
+        screen:try_resize(12,5)
+        screen:expect([[
+          some long   |
+          prefix      |
+          bef{n: word  }  |
+          tex{n: }^        |
+          {2:-- INSERT -} |
+        ]])
+
+        -- can't draw the pum, but check we don't crash
+        screen:try_resize(12,2)
+        screen:expect([[
+          text^        |
+          {2:-- INSERT -} |
+        ]])
+
+        -- but state is preserved, pum reappears
+        screen:try_resize(20,8)
+        screen:expect([[
+          some long prefix    |
+          before the text^     |
+          {1:~         }{n: word    }{1: }|
+          {1:~         }{n: choice  }{1: }|
+          {1:~         }{s: text    }{1: }|
+          {1:~         }{n: thing   }{1: }|
+          {1:~                   }|
+          {2:-- INSERT --}        |
+        ]])
+      end)
+
+      it('with VimResized autocmd', function()
+        feed('isome long prefix before the ')
+        command("set completeopt+=noinsert,noselect")
+        command("autocmd VimResized * redraw!")
+        command("set linebreak")
+        funcs.complete(29, {'word', 'choice', 'text', 'thing'})
+        screen:expect([[
+          some long prefix before the ^    |
+          {1:~                        }{n: word  }|
+          {1:~                        }{n: choice}|
+          {1:~                        }{n: text  }|
+          {1:~                        }{n: thing }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {2:-- INSERT --}                    |
+        ]])
+
+        screen:try_resize(16,10)
+        screen:expect([[
+          some long       |
+          prefix before   |
+          the ^            |
+          {1:~  }{n: word        }|
+          {1:~  }{n: choice      }|
+          {1:~  }{n: text        }|
+          {1:~  }{n: thing       }|
+          {1:~               }|
+          {1:~               }|
+          {2:-- INSERT --}    |
+        ]])
+      end)
+
+      it('with rightleft window', function()
+        command("set rl wildoptions+=pum")
+        feed('isome rightleft ')
+        screen:expect([[
+                          ^  tfelthgir emos|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {2:-- INSERT --}                    |
+        ]])
+
+        command("set completeopt+=noinsert,noselect")
+        funcs.complete(16, {'word', 'choice', 'text', 'thing'})
+        screen:expect([[
+                          ^  tfelthgir emos|
+          {1:  }{n:           drow}{1:              ~}|
+          {1:  }{n:         eciohc}{1:              ~}|
+          {1:  }{n:           txet}{1:              ~}|
+          {1:  }{n:          gniht}{1:              ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {2:-- INSERT --}                    |
+        ]])
+
+        feed('')
+        screen:expect([[
+                      ^ drow tfelthgir emos|
+          {1:  }{s:           drow}{1:              ~}|
+          {1:  }{n:         eciohc}{1:              ~}|
+          {1:  }{n:           txet}{1:              ~}|
+          {1:  }{n:          gniht}{1:              ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {2:-- INSERT --}                    |
+        ]])
+
+        feed('')
+        screen:expect([[
+                      ^ drow tfelthgir emos|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {2:-- INSERT --}                    |
+        ]])
+
+        -- not rightleft on the cmdline
+        feed(':sign ')
+        screen:expect{grid=[[
+                       drow tfelthgir emos|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          :sign ^                          |
+        ]]}
+
+        feed('')
+        screen:expect{grid=[[
+                       drow tfelthgir emos|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:                               ~}|
+          {1:     }{s: define         }{1:          ~}|
+          {1:     }{n: jump           }{1:          ~}|
+          {1:     }{n: list           }{1:          ~}|
+          {1:     }{n: place          }{1:          ~}|
+          {1:     }{n: undefine       }{1:          ~}|
+          {1:     }{n: unplace        }{1:          ~}|
+          :sign define^                    |
+        ]]}
+      end)
+    end
 
-    feed('')
+    it('with rightleft vsplits', function()
+      screen:try_resize(40, 8)
+      command('set rightleft')
+      command('rightbelow vsplit')
+      command("set completeopt+=noinsert,noselect")
+      feed('isome rightleft ')
+      funcs.complete(16, {'word', 'choice', 'text', 'thing'})
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          {3:[No Name] [+]       }{4:[No Name] [+]       }|
+          [3:----------------------------------------]|
+        ## grid 2
+               tfelthgir emos|
+          {1:                  ~}|
+          {1:                  ~}|
+          {1:                  ~}|
+          {1:                  ~}|
+          {1:                  ~}|
+        ## grid 3
+          {2:-- INSERT --}                            |
+        ## grid 4
+              ^  tfelthgir emos|
+          {1:                   ~}|
+          {1:                   ~}|
+          {1:                   ~}|
+          {1:                   ~}|
+          {1:                   ~}|
+        ## grid 5
+           {n:           drow}|
+           {n:         eciohc}|
+           {n:           txet}|
+           {n:          gniht}|
+        ]], float_pos={
+          [5] = {{id = -1}, "NW", 4, 1, -11, false, 100};
+        }}
+      else
+        screen:expect([[
+               tfelthgir emos│    ^  tfelthgir emos|
+          {1:          }{n:           drow}{1:              ~}|
+          {1:          }{n:         eciohc}{1:              ~}|
+          {1:          }{n:           txet}{1:              ~}|
+          {1:          }{n:          gniht}{1:              ~}|
+          {1:                  ~}│{1:                   ~}|
+          {3:[No Name] [+]       }{4:[No Name] [+]       }|
+          {2:-- INSERT --}                            |
+        ]])
+      end
+    end)
 
-    -- Set an  mapping to change a menu entry while it's displayed.
-    -- The text should not change but the command does.
-    -- Also verify that "changed" shows up, which means the mapping triggered.
-    command('nnoremap   ChangeMenu()')
-    feed('/X:popup PopUp')
-    screen:expect([[
-      one two three four five         |
-      and one two {7:^X}three four five    |
-      one more tw{n: Undo             }   |
-      {1:~          }{n:                  }{1:   }|
-      {1:~          }{n: Paste            }{1:   }|
-      {1:~          }{n:                  }{1:   }|
-      {1:~          }{n: Select Word      }{1:   }|
-      {1:~          }{n: Select Sentence  }{1:   }|
-      {1:~          }{n: Select Paragraph }{1:   }|
-      {1:~          }{n: Select Line      }{1:   }|
-      {1:~          }{n: Select Block     }{1:   }|
-      {1:~          }{n: Select All       }{1:   }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      changed                         |
-    ]])
+    if not multigrid then
+      it('with multiline messages', function()
+        screen:try_resize(40,8)
+        feed('ixx')
+        command('imap  echoerr "very"\\|echoerr "much"\\|echoerr "error"')
+        funcs.complete(1, {'word', 'choice', 'text', 'thing'})
+        screen:expect([[
+          xx                                      |
+          word^                                    |
+          {s:word           }{1:                         }|
+          {n:choice         }{1:                         }|
+          {n:text           }{1:                         }|
+          {n:thing          }{1:                         }|
+          {1:~                                       }|
+          {2:-- INSERT --}                            |
+        ]])
+
+        feed('')
+        screen:expect([[
+          xx                                      |
+          word                                    |
+          {s:word           }{1:                         }|
+          {4:                                        }|
+          {6:very}                                    |
+          {6:much}                                    |
+          {6:error}                                   |
+          {5:Press ENTER or type command to continue}^ |
+        ]])
+
+        feed('')
+        screen:expect([[
+          xx                                      |
+          word^                                    |
+          {s:word           }{1:                         }|
+          {n:choice         }{1:                         }|
+          {n:text           }{1:                         }|
+          {n:thing          }{1:                         }|
+          {1:~                                       }|
+          {2:-- INSERT --}                            |
+        ]])
+
+        feed('')
+        screen:expect([[
+          xx                                      |
+          choice^                                  |
+          {n:word           }{1:                         }|
+          {s:choice         }{1:                         }|
+          {n:text           }{1:                         }|
+          {n:thing          }{1:                         }|
+          {1:~                                       }|
+          {2:-- INSERT --}                            |
+        ]])
+
+        command("split")
+        screen:expect([[
+          xx                                      |
+          choice^                                  |
+          {n:word           }{1:                         }|
+          {s:choice         }{4:                         }|
+          {n:text           }                         |
+          {n:thing          }                         |
+          {3:[No Name] [+]                           }|
+          {2:-- INSERT --}                            |
+        ]])
+
+        meths.input_mouse('wheel', 'down', '', 0, 6, 15)
+        screen:expect{grid=[[
+          xx                                      |
+          choice^                                  |
+          {n:word           }{1:                         }|
+          {s:choice         }{4:                         }|
+          {n:text           }                         |
+          {n:thing          }{1:                         }|
+          {3:[No Name] [+]                           }|
+          {2:-- INSERT --}                            |
+        ]], unchanged=true}
+      end)
+
+      it('with kind, menu and abbr attributes', function()
+        screen:try_resize(40,8)
+        feed('ixx ')
+        funcs.complete(4, {{word='wordey', kind= 'x', menu='extrainfo'}, 'thing', {word='secret', abbr='sneaky', menu='bar'}})
+        screen:expect([[
+          xx wordey^                               |
+          {1:~ }{s: wordey x extrainfo }{1:                  }|
+          {1:~ }{n: thing              }{1:                  }|
+          {1:~ }{n: sneaky   bar       }{1:                  }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {2:-- INSERT --}                            |
+        ]])
+
+        feed('')
+        screen:expect([[
+          xx ^                                     |
+          {1:~ }{n: wordey x extrainfo }{1:                  }|
+          {1:~ }{n: thing              }{1:                  }|
+          {1:~ }{n: sneaky   bar       }{1:                  }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {2:-- INSERT --}                            |
+        ]])
+
+        feed('')
+        screen:expect([[
+          xx secret^                               |
+          {1:~ }{n: wordey x extrainfo }{1:                  }|
+          {1:~ }{n: thing              }{1:                  }|
+          {1:~ }{s: sneaky   bar       }{1:                  }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {2:-- INSERT --}                            |
+        ]])
+
+        feed('')
+        screen:expect([[
+          xx secre^t                               |
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+                                                  |
+        ]])
+      end)
+
+      it('wildoptions=pum', function()
+        screen:try_resize(32,10)
+        command('set wildmenu')
+        command('set wildoptions=pum')
+        command('set shellslash')
+        command("cd test/functional/fixtures/wildpum")
+
+        feed(':sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :sign ^                          |
+        ]])
+
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{s: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign define^                    |
+        ]])
+
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{s: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign list^                      |
+        ]])
+
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{s: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign place^                     |
+        ]])
+
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{s: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign list^                      |
+        ]])
+
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{s: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign jump^                      |
+        ]])
+
+        -- pressing  should end completion and go back to the original match
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :sign ^                          |
+        ]])
+
+        -- pressing  should select the current match and end completion
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :sign unplace^                   |
+        ]])
+
+        -- showing popup menu in different columns in the cmdline
+        feed('sign define ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~           }{s: culhl=         }{1:    }|
+          {1:~           }{n: icon=          }{1:    }|
+          {1:~           }{n: linehl=        }{1:    }|
+          {1:~           }{n: numhl=         }{1:    }|
+          {1:~           }{n: text=          }{1:    }|
+          {1:~           }{n: texthl=        }{1:    }|
+          :sign define culhl=^             |
+        ]])
+
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                  }{s: culhl=     }{1: }|
+          {1:~                  }{n: icon=      }{1: }|
+          {1:~                  }{n: linehl=    }{1: }|
+          {1:~                  }{n: numhl=     }{1: }|
+          {1:~                  }{n: text=      }{1: }|
+          {1:~                  }{n: texthl=    }{1: }|
+          :sign define culhl= culhl=^      |
+        ]])
+
+        feed('e Xdi')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~      }{s: XdirA/         }{1:         }|
+          {1:~      }{n: XfileA         }{1:         }|
+          :e Xdir/XdirA/^                  |
+        ]])
+
+        -- Pressing  on a directory name should go into that directory
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~            }{s: XdirB/         }{1:   }|
+          {1:~            }{n: XfileB         }{1:   }|
+          :e Xdir/XdirA/XdirB/^            |
+        ]])
+
+        -- Pressing  on a directory name should go to the parent directory
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~      }{s: XdirA/         }{1:         }|
+          {1:~      }{n: XfileA         }{1:         }|
+          :e Xdir/XdirA/^                  |
+        ]])
+
+        -- Pressing  when the popup menu is displayed should list all the
+        -- matches and remove the popup menu
+        feed(':sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {4:                                }|
+          :sign define jump list place und|
+          efine unplace^                   |
+        ]])
+
+        -- Pressing  after that should move the cursor
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {4:                                }|
+          :sign define jump list place und|
+          efine unplac^e                   |
+        ]])
+        feed('')
+
+        -- Pressing  when the popup menu is displayed should remove the popup
+        -- menu
+        feed('sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {4:                                }|
+          :sign define                    |
+          define                          |
+          :sign define^                    |
+        ]])
+
+        -- Pressing  should open the popup menu with the last entry selected
+        feed(':sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{s: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign undefine^                  |
+        ]])
+
+        -- Pressing  should close the popup menu and cancel the cmd line
+        feed(':sign ')
+        screen:expect([[
+          ^                                |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+                                          |
+        ]])
+
+        -- Typing a character when the popup is open, should close the popup
+        feed(':sign x')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :sign definex^                   |
+        ]])
+
+        -- When the popup is open, entering the cmdline window should close the popup
+        feed('sign ')
+        screen:expect([[
+                                          |
+          {3:[No Name]                       }|
+          {1::}sign define                    |
+          {1::}sign define^                    |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {4:[Command Line]                  }|
+          :sign define                    |
+        ]])
+        feed(':q')
+
+        -- After the last popup menu item,  should show the original string
+        feed(':sign u')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign u^                         |
+        ]])
+
+        -- Use the popup menu for the command name
+        feed('bu')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {s: bufdo          }{1:                }|
+          {n: buffer         }{1:                }|
+          {n: buffers        }{1:                }|
+          {n: bunload        }{1:                }|
+          :bufdo^                          |
+        ]])
+
+        -- Pressing  should remove the popup menu and erase the last character
+        feed('sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :sign defin^                     |
+        ]])
+
+        -- Pressing  should remove the popup menu and erase the previous word
+        feed('sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :sign ^                          |
+        ]])
+
+        -- Pressing  should remove the popup menu and erase the entire line
+        feed('sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :^                               |
+        ]])
+
+        -- Using  to cancel the popup menu and then pressing  should recall
+        -- the cmdline from history
+        feed('sign xyz:sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :sign xyz^                       |
+        ]])
+
+        feed('')
+
+        -- Check "list" still works
+        command('set wildmode=longest,list')
+        feed(':cn')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {4:                                }|
+          :cn                             |
+          cnewer       cnoreabbrev        |
+          cnext        cnoremap           |
+          cnfile       cnoremenu          |
+          :cn^                             |
+        ]])
+        feed('s')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {4:                                }|
+          :cn                             |
+          cnewer       cnoreabbrev        |
+          cnext        cnoremap           |
+          cnfile       cnoremenu          |
+          :cns^                            |
+        ]])
+
+        feed('')
+        command('set wildmode=full')
+
+        -- Tests a directory name contained full-width characters.
+        feed(':e あいう/')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~        }{s: 123            }{1:       }|
+          {1:~        }{n: abc            }{1:       }|
+          {1:~        }{n: xyz            }{1:       }|
+          :e あいう/123^                   |
+        ]])
+        feed('')
+
+        -- Pressing  should scroll the menu downward
+        feed(':sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{s: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign undefine^                  |
+        ]])
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{s: unplace        }{1:           }|
+          :sign unplace^                   |
+        ]])
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign ^                          |
+        ]])
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{s: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign define^                    |
+        ]])
+        feed('sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{s: unplace        }{1:           }|
+          :sign unplace^                   |
+        ]])
+
+        -- Pressing  should scroll the menu upward
+        feed('sign ')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign ^                          |
+        ]])
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{s: unplace        }{1:           }|
+          :sign unplace^                   |
+        ]])
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{n: define         }{1:           }|
+          {1:~    }{s: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign jump^                      |
+        ]])
+        feed('')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~    }{s: define         }{1:           }|
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign define^                    |
+        ]])
+
+        feed('')
+
+        -- check positioning with multibyte char in pattern
+        command("e långfile1")
+        command("sp långfile2")
+        feed(':b lå')
+        screen:expect([[
+                                          |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {4:långfile2                       }|
+                                          |
+          {1:~                               }|
+          {1:~ }{s: långfile1      }{1:              }|
+          {3:lå}{n: långfile2      }{3:              }|
+          :b långfile1^                    |
+        ]])
+
+        -- check doesn't crash on screen resize
+        screen:try_resize(20,6)
+        screen:expect([[
+                              |
+          {1:~                   }|
+          {4:långfile2           }|
+            {s: långfile1      }  |
+          {3:lå}{n: långfile2      }{3:  }|
+          :b långfile1^        |
+        ]])
+
+        screen:try_resize(50,15)
+        screen:expect([[
+                                                            |
+          {1:~                                                 }|
+          {4:långfile2                                         }|
+                                                            |
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~ }{s: långfile1      }{1:                                }|
+          {3:lå}{n: långfile2      }{3:                                }|
+          :b långfile1^                                      |
+        ]])
+
+        -- position is calculated correctly with "longest"
+        feed('')
+        command('set wildmode=longest:full,full')
+        feed(':b lå')
+        screen:expect([[
+                                                            |
+          {1:~                                                 }|
+          {4:långfile2                                         }|
+                                                            |
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~ }{n: långfile1      }{1:                                }|
+          {3:lå}{n: långfile2      }{3:                                }|
+          :b långfile^                                       |
+        ]])
+
+        feed('')
+        command("close")
+        command('set wildmode=full')
+
+        -- special case: when patterns ends with "/", show menu items aligned
+        -- after the "/"
+        feed(':e compdir/')
+        screen:expect([[
+                                                            |
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~                                                 }|
+          {1:~         }{s: file1          }{1:                        }|
+          {1:~         }{n: file2          }{1:                        }|
+          :e compdir/file1^                                  |
+        ]])
+      end)
+
+      it('wildoptions=pum with scrolled messages', function()
+        screen:try_resize(40,10)
+        command('set wildmenu')
+        command('set wildoptions=pum')
+
+        feed(':echoerr "fail"|echoerr "error"')
+        screen:expect{grid=[[
+                                                  |
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {4:                                        }|
+          {6:fail}                                    |
+          {6:error}                                   |
+          {5:Press ENTER or type command to continue}^ |
+        ]]}
+
+        feed(':sign ')
+        screen:expect{grid=[[
+                                                  |
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~    }{s: define         }{1:                   }|
+          {1:~    }{n: jump           }{1:                   }|
+          {1:~    }{n: list           }{1:                   }|
+          {4:     }{n: place          }{4:                   }|
+          {6:fail} {n: undefine       }                   |
+          {6:error}{n: unplace        }                   |
+          :sign define^                            |
+        ]]}
+
+        feed('d')
+        screen:expect{grid=[[
+                                                  |
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {1:~                                       }|
+          {4:                                        }|
+          {6:fail}                                    |
+          {6:error}                                   |
+          :sign defined^                           |
+        ]]}
+      end)
+
+      it('wildoptions=pum and wildmode=longest,full #11622', function()
+        screen:try_resize(30,8)
+        command('set wildmenu')
+        command('set wildoptions=pum')
+        command('set wildmode=longest,full')
+
+        -- With 'wildmode' set to 'longest,full', completing a match should display
+        -- the longest match, the wildmenu should not be displayed.
+        feed(':sign u')
+        screen:expect{grid=[[
+                                        |
+          {1:~                             }|
+          {1:~                             }|
+          {1:~                             }|
+          {1:~                             }|
+          {1:~                             }|
+          {1:~                             }|
+          :sign un^                      |
+        ]]}
+        eq(0, funcs.wildmenumode())
+
+        -- pressing  should display the wildmenu
+        feed('')
+        screen:expect{grid=[[
+                                        |
+          {1:~                             }|
+          {1:~                             }|
+          {1:~                             }|
+          {1:~                             }|
+          {1:~    }{s: undefine       }{1:         }|
+          {1:~    }{n: unplace        }{1:         }|
+          :sign undefine^                |
+        ]]}
+        eq(1, funcs.wildmenumode())
+
+        -- pressing  second time should select the next entry in the menu
+        feed('')
+        screen:expect{grid=[[
+                                        |
+          {1:~                             }|
+          {1:~                             }|
+          {1:~                             }|
+          {1:~                             }|
+          {1:~    }{n: undefine       }{1:         }|
+          {1:~    }{s: unplace        }{1:         }|
+          :sign unplace^                 |
+        ]]}
+      end)
+
+      it('wildoptions=pum with a wrapped line in buffer vim-patch:8.2.4655', function()
+        screen:try_resize(32, 10)
+        meths.buf_set_lines(0, 0, -1, true, { ('a'):rep(100) })
+        command('set wildoptions+=pum')
+        feed('$')
+        feed(':sign ')
+        screen:expect([[
+          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+          aaaa {s: define         }           |
+          {1:~    }{n: jump           }{1:           }|
+          {1:~    }{n: list           }{1:           }|
+          {1:~    }{n: place          }{1:           }|
+          {1:~    }{n: undefine       }{1:           }|
+          {1:~    }{n: unplace        }{1:           }|
+          :sign define^                    |
+        ]])
+      end)
+
+      -- oldtest: Test_wildmenu_pum_clear_entries()
+      it('wildoptions=pum when using Ctrl-E as wildchar vim-patch:9.0.1030', function()
+        screen:try_resize(30, 10)
+        exec([[
+          set wildoptions=pum
+          set wildchar=
+        ]])
+        feed(':sign ')
+        screen:expect([[
+                                        |
+          {1:~                             }|
+          {1:~                             }|
+          {1:~    }{s: define         }{1:         }|
+          {1:~    }{n: jump           }{1:         }|
+          {1:~    }{n: list           }{1:         }|
+          {1:~    }{n: place          }{1:         }|
+          {1:~    }{n: undefine       }{1:         }|
+          {1:~    }{n: unplace        }{1:         }|
+          :sign define^                  |
+        ]])
+        assert_alive()
+      end)
+    end
 
-    -- Select the Paste entry, executes the changed menu item.
-    feed('jj')
-    screen:expect([[
-      one two three four five         |
-      and one two {7:^X}three four five    |
-      one more two three four five    |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      pasted                          |
-    ]])
-  end)
+    it("'pumheight'", function()
+      screen:try_resize(32,8)
+      feed('isome long prefix before the ')
+      command("set completeopt+=noinsert,noselect")
+      command("set linebreak")
+      command("set pumheight=2")
+      funcs.complete(29, {'word', 'choice', 'text', 'thing'})
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          some long prefix before the ^    |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          {2:-- INSERT --}                    |
+        ## grid 4
+          {n: word  }{c: }|
+          {n: choice}{s: }|
+        ]], float_pos={
+          [4] = {{id = -1}, "NW", 2, 1, 24, false, 100};
+        }}
+      else
+        screen:expect([[
+          some long prefix before the ^    |
+          {1:~                       }{n: word  }{c: }|
+          {1:~                       }{n: choice}{s: }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {2:-- INSERT --}                    |
+        ]])
+      end
+    end)
 
-  describe('"kind" and "menu"', function()
-    before_each(function()
-      screen:try_resize(30, 8)
-      exec([[
-        func CompleteFunc( findstart, base )
-          if a:findstart
-            return 0
-          endif
-          return {
-                \ 'words': [
-                \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', },
-                \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', },
-                \ { 'word': 'aword3', 'menu': 'extra text 3', 'kind': 'W', },
-                \]}
-        endfunc
-        set completeopt=menu
-        set completefunc=CompleteFunc
-      ]])
+    it("'pumwidth'", function()
+      screen:try_resize(32,8)
+      feed('isome long prefix before the ')
+      command("set completeopt+=noinsert,noselect")
+      command("set linebreak")
+      command("set pumwidth=8")
+      funcs.complete(29, {'word', 'choice', 'text', 'thing'})
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          some long prefix before the ^    |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          {2:-- INSERT --}                    |
+        ## grid 4
+          {n: word  }|
+          {n: choice}|
+          {n: text  }|
+          {n: thing }|
+        ]], float_pos={
+          [4] = {{id = -1}, "NW", 2, 1, 25, false, 100};
+        }}
+      else
+        screen:expect([[
+          some long prefix before the ^    |
+          {1:~                        }{n: word  }|
+          {1:~                        }{n: choice}|
+          {1:~                        }{n: text  }|
+          {1:~                        }{n: thing }|
+          {1:~                               }|
+          {1:~                               }|
+          {2:-- INSERT --}                    |
+        ]])
+      end
     end)
 
-    -- oldtest: Test_pum_highlights_default()
-    it('default highlight groups', function()
-      feed('iaw')
-      screen:expect([[
-        aword1^                        |
-        {s:aword1 W extra text 1 }{1:        }|
-        {n:aword2 W extra text 2 }{1:        }|
-        {n:aword3 W extra text 3 }{1:        }|
-        {1:~                             }|
-        {1:~                             }|
-        {1:~                             }|
-        {2:-- }{5:match 1 of 3}               |
-      ]])
+    it('does not crash when displayed in the last column with rightleft #12032', function()
+      local col = 30
+      local items = {'word', 'choice', 'text', 'thing'}
+      local max_len = 0
+      for _, v in ipairs(items) do
+        max_len = max_len < #v and #v or max_len
+      end
+      screen:try_resize(col, 8)
+      command('set rightleft')
+      command('call setline(1, repeat(" ", &columns - '..max_len..'))')
+      feed('$i')
+      funcs.complete(col - max_len, items)
+      feed('')
+      assert_alive()
     end)
 
-    -- oldtest: Test_pum_highlights_custom()
-    it('custom highlight groups', function()
-      exec([[
-        hi PmenuKind      guifg=Red guibg=Magenta
-        hi PmenuKindSel   guifg=Red guibg=Grey
-        hi PmenuExtra     guifg=White guibg=Magenta
-        hi PmenuExtraSel  guifg=Black guibg=Grey
-      ]])
-      local attrs = screen:get_default_attr_ids()
-      attrs.kn = {foreground = Screen.colors.Red, background = Screen.colors.Magenta}
-      attrs.ks = {foreground = Screen.colors.Red, background = Screen.colors.Grey}
-      attrs.xn = {foreground = Screen.colors.White, background = Screen.colors.Magenta}
-      attrs.xs = {foreground = Screen.colors.Black, background = Screen.colors.Grey}
-      feed('iaw')
-      screen:expect([[
-        aword1^                        |
-        {s:aword1 }{ks:W }{xs:extra text 1 }{1:        }|
-        {n:aword2 }{kn:W }{xn:extra text 2 }{1:        }|
-        {n:aword3 }{kn:W }{xn:extra text 3 }{1:        }|
-        {1:~                             }|
-        {1:~                             }|
-        {1:~                             }|
-        {2:-- }{5:match 1 of 3}               |
-      ]], attrs)
+    it('truncates double-width character correctly without scrollbar', function()
+      screen:try_resize(32, 8)
+      command('set completeopt+=menuone,noselect')
+      feed('i' .. string.rep(' ', 13))
+      funcs.complete(14, {'哦哦哦哦哦哦哦哦哦哦'})
+      if multigrid then
+        screen:expect({grid=[[
+          ## grid 1
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [3:--------------------------------]|
+          ## grid 2
+                         ^                   |
+            {1:~                               }|
+            {1:~                               }|
+            {1:~                               }|
+            {1:~                               }|
+            {1:~                               }|
+            {1:~                               }|
+          ## grid 3
+            {2:-- INSERT --}                    |
+          ## grid 4
+            {n: 哦哦哦哦哦哦哦哦哦>}|
+        ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 12, false, 100}}})
+      else
+        screen:expect([[
+                       ^                   |
+          {1:~           }{n: 哦哦哦哦哦哦哦哦哦>}|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {2:-- INSERT --}                    |
+        ]])
+      end
     end)
-  end)
-end)
 
-describe('builtin popupmenu with ui/ext_multigrid', function()
-  local screen
-  before_each(function()
-    clear()
-    screen = Screen.new(32, 20)
-    screen:attach({ext_multigrid=true})
-    screen:set_default_attr_ids({
-      -- popup selected item / scrollbar track
-      ['s'] = {background = Screen.colors.WebGray},
-      -- popup non-selected item
-      ['n'] = {background = Screen.colors.LightMagenta},
-      -- popup scrollbar knob
-      ['c'] = {background = Screen.colors.Grey0},
-      [1] = {bold = true, foreground = Screen.colors.Blue},
-      [2] = {bold = true},
-      [3] = {reverse = true},
-      [4] = {bold = true, reverse = true},
-      [5] = {bold = true, foreground = Screen.colors.SeaGreen},
-      [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
-    })
-  end)
+    it('truncates double-width character correctly with scrollbar', function()
+      screen:try_resize(32,8)
+      command('set completeopt+=noselect')
+      command('set pumheight=4')
+      feed('i' .. string.rep(' ', 12))
+      local items = {}
+      for _ = 1, 8 do
+        table.insert(items, {word = '哦哦哦哦哦哦哦哦哦哦', equal = 1, dup = 1})
+      end
+      funcs.complete(13, items)
+      if multigrid then
+        screen:expect({grid=[[
+          ## grid 1
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [2:--------------------------------]|
+            [3:--------------------------------]|
+          ## grid 2
+                        ^                    |
+            {1:~                               }|
+            {1:~                               }|
+            {1:~                               }|
+            {1:~                               }|
+            {1:~                               }|
+            {1:~                               }|
+          ## grid 3
+            {2:-- INSERT --}                    |
+          ## grid 4
+            {n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+            {n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+            {n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+            {n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+        ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 11, false, 100}}})
+      else
+        screen:expect([[
+                      ^                    |
+          {1:~          }{n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+          {1:~          }{n: 哦哦哦哦哦哦哦哦哦>}{c: }|
+          {1:~          }{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+          {1:~          }{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
+          {1:~                               }|
+          {1:~                               }|
+          {2:-- INSERT --}                    |
+        ]])
+      end
+    end)
 
-  it('truncates double-width character correctly when there is no scrollbar', function()
-    screen:try_resize(32,8)
-    command('set completeopt+=menuone,noselect')
-    feed('i' .. string.rep(' ', 13))
-    funcs.complete(14, {'哦哦哦哦哦哦哦哦哦哦'})
-    screen:expect({grid=[[
-      ## grid 1
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [3:--------------------------------]|
-      ## grid 2
-                     ^                   |
-        {1:~                               }|
-        {1:~                               }|
-        {1:~                               }|
-        {1:~                               }|
-        {1:~                               }|
-        {1:~                               }|
-      ## grid 3
-        {2:-- INSERT --}                    |
-      ## grid 4
-        {n: 哦哦哦哦哦哦哦哦哦>}|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 12, false, 100}}})
-  end)
+    it('supports mousemodel=popup', function()
+      screen:try_resize(32, 6)
+      exec([[
+        call setline(1, 'popup menu test')
+        set mouse=a mousemodel=popup
+
+        aunmenu PopUp
+        menu PopUp.foo :let g:menustr = 'foo'
+        menu PopUp.bar :let g:menustr = 'bar'
+        menu PopUp.baz :let g:menustr = 'baz'
+      ]])
 
-  it('truncates double-width character correctly when there is scrollbar', function()
-    screen:try_resize(32,8)
-    command('set completeopt+=noselect')
-    command('set pumheight=4')
-    feed('i' .. string.rep(' ', 12))
-    local items = {}
-    for _ = 1, 8 do
-      table.insert(items, {word = '哦哦哦哦哦哦哦哦哦哦', equal = 1, dup = 1})
+      if multigrid then
+        meths.input_mouse('right', 'press', '', 2, 0, 4)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+                                          |
+        ## grid 4
+          {n: foo }|
+          {n: bar }|
+          {n: baz }|
+        ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
+      else
+        feed('<4,0>')
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~  }{n: foo }{1:                        }|
+          {1:~  }{n: bar }{1:                        }|
+          {1:~  }{n: baz }{1:                        }|
+          {1:~                               }|
+                                          |
+        ]])
+      end
+      feed('')
+      if multigrid then
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+                                          |
+        ## grid 4
+          {s: foo }|
+          {n: bar }|
+          {n: baz }|
+        ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
+      else
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~  }{s: foo }{1:                        }|
+          {1:~  }{n: bar }{1:                        }|
+          {1:~  }{n: baz }{1:                        }|
+          {1:~                               }|
+                                          |
+        ]])
+      end
+      feed('')
+      if multigrid then
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+                                          |
+        ## grid 4
+          {n: foo }|
+          {s: bar }|
+          {n: baz }|
+        ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
+      else
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~  }{n: foo }{1:                        }|
+          {1:~  }{s: bar }{1:                        }|
+          {1:~  }{n: baz }{1:                        }|
+          {1:~                               }|
+                                          |
+        ]])
+      end
+      feed('')
+      if multigrid then
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'bar'          |
+        ]]})
+      else
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :let g:menustr = 'bar'          |
+        ]])
+      end
+      eq('bar', meths.get_var('menustr'))
+
+      if multigrid then
+        meths.input_mouse('right', 'press', '', 2, 2, 20)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'bar'          |
+        ## grid 4
+          {n: foo }|
+          {n: bar }|
+          {n: baz }|
+        ]], float_pos={[4] = {{id = -1}, 'NW', 2, 3, 19, false, 250}}})
+      else
+        feed('<20,2>')
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                  }{n: foo }{1:        }|
+          {1:~                  }{n: bar }{1:        }|
+          :let g:menustr = 'b{n: baz }        |
+        ]])
+      end
+      if multigrid then
+        meths.input_mouse('left', 'press', '', 4, 2, 2)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'baz'          |
+        ]]})
+      else
+        feed('<22,5>')
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :let g:menustr = 'baz'          |
+        ]])
+      end
+      eq('baz', meths.get_var('menustr'))
+
+      if multigrid then
+        meths.input_mouse('right', 'press', '', 2, 0, 4)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'baz'          |
+        ## grid 4
+          {n: foo }|
+          {n: bar }|
+          {n: baz }|
+        ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
+      else
+        feed('<4,0>')
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~  }{n: foo }{1:                        }|
+          {1:~  }{n: bar }{1:                        }|
+          {1:~  }{n: baz }{1:                        }|
+          {1:~                               }|
+          :let g:menustr = 'baz'          |
+        ]])
+      end
+      if multigrid then
+        meths.input_mouse('right', 'drag', '', 2, 3, 6)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'baz'          |
+        ## grid 4
+          {n: foo }|
+          {n: bar }|
+          {s: baz }|
+        ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
+      else
+        feed('<6,3>')
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~  }{n: foo }{1:                        }|
+          {1:~  }{n: bar }{1:                        }|
+          {1:~  }{s: baz }{1:                        }|
+          {1:~                               }|
+          :let g:menustr = 'baz'          |
+        ]])
+      end
+      if multigrid then
+        meths.input_mouse('right', 'release', '', 2, 1, 6)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'foo'          |
+        ]]})
+      else
+        feed('<6,1>')
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :let g:menustr = 'foo'          |
+        ]])
+      end
+      eq('foo', meths.get_var('menustr'))
+
+      eq(false, screen.options.mousemoveevent)
+      if multigrid then
+        meths.input_mouse('right', 'press', '', 2, 0, 4)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'foo'          |
+        ## grid 4
+          {n: foo }|
+          {n: bar }|
+          {n: baz }|
+        ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
+      else
+        feed('<4,0>')
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~  }{n: foo }{1:                        }|
+          {1:~  }{n: bar }{1:                        }|
+          {1:~  }{n: baz }{1:                        }|
+          {1:~                               }|
+          :let g:menustr = 'foo'          |
+        ]])
+      end
+      eq(true, screen.options.mousemoveevent)
+      if multigrid then
+        meths.input_mouse('move', '', '', 2, 3, 6)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'foo'          |
+        ## grid 4
+          {n: foo }|
+          {n: bar }|
+          {s: baz }|
+        ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
+      else
+        feed('<6,3>')
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~  }{n: foo }{1:                        }|
+          {1:~  }{n: bar }{1:                        }|
+          {1:~  }{s: baz }{1:                        }|
+          {1:~                               }|
+          :let g:menustr = 'foo'          |
+        ]])
+      end
+      eq(true, screen.options.mousemoveevent)
+      if multigrid then
+        meths.input_mouse('left', 'press', '', 2, 2, 6)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'bar'          |
+        ]]})
+      else
+        feed('<6,2>')
+        screen:expect([[
+          ^popup menu test                 |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :let g:menustr = 'bar'          |
+        ]])
+      end
+      eq(false, screen.options.mousemoveevent)
+      eq('bar', meths.get_var('menustr'))
+
+      command('set laststatus=0 | botright split')
+      if multigrid then
+        meths.input_mouse('right', 'press', '', 5, 1, 20)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {3:[No Name] [+]                   }|
+          [5:--------------------------------]|
+          [5:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          popup menu test                 |
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'bar'          |
+        ## grid 4
+          {n: foo }|
+          {n: bar }|
+          {n: baz }|
+        ## grid 5
+          ^popup menu test                 |
+          {1:~                               }|
+        ]], float_pos={[4] = {{id = -1}, "SW", 5, 1, 19, false, 250}}})
+      else
+        feed('<20,4>')
+        screen:expect([[
+          popup menu test                 |
+          {1:~                  }{n: foo }{1:        }|
+          {3:[No Name] [+]      }{n: bar }{3:        }|
+          ^popup menu test    {n: baz }        |
+          {1:~                               }|
+          :let g:menustr = 'bar'          |
+        ]])
+      end
+      if multigrid then
+        meths.input_mouse('left', 'press', '', 4, 2, 2)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {3:[No Name] [+]                   }|
+          [5:--------------------------------]|
+          [5:--------------------------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          popup menu test                 |
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'baz'          |
+        ## grid 5
+          ^popup menu test                 |
+          {1:~                               }|
+        ]]})
+      else
+        feed('<22,3>')
+        screen:expect([[
+          popup menu test                 |
+          {1:~                               }|
+          {3:[No Name] [+]                   }|
+          ^popup menu test                 |
+          {1:~                               }|
+          :let g:menustr = 'baz'          |
+        ]])
+      end
+      eq('baz', meths.get_var('menustr'))
+
+      command('set winwidth=1 | rightbelow vsplit')
+      if multigrid then
+        meths.input_mouse('right', 'press', '', 6, 1, 14)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {3:[No Name] [+]                   }|
+          [5:---------------]│[6:----------------]|
+          [5:---------------]│[6:----------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          popup menu test                 |
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'baz'          |
+        ## grid 4
+          {n: foo}|
+          {n: bar}|
+          {n: baz}|
+        ## grid 5
+          popup menu test|
+          {1:~              }|
+        ## grid 6
+          ^popup menu test |
+          {1:~               }|
+        ]], float_pos={[4] = {{id = -1}, "SW", 6, 1, 12, false, 250}}})
+      else
+        feed('<30,4>')
+        screen:expect([[
+          popup menu test                 |
+          {1:~                           }{n: foo}|
+          {3:[No Name] [+]               }{n: bar}|
+          popup menu test│^popup menu t{n: baz}|
+          {1:~              }│{1:~               }|
+          :let g:menustr = 'baz'          |
+        ]])
+      end
+      if multigrid then
+        meths.input_mouse('left', 'press', '', 4, 0, 2)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {3:[No Name] [+]                   }|
+          [5:---------------]│[6:----------------]|
+          [5:---------------]│[6:----------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          popup menu test                 |
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'foo'          |
+        ## grid 5
+          popup menu test|
+          {1:~              }|
+        ## grid 6
+          ^popup menu test |
+          {1:~               }|
+        ]]})
+      else
+        feed('<31,1>')
+        screen:expect([[
+          popup menu test                 |
+          {1:~                               }|
+          {3:[No Name] [+]                   }|
+          popup menu test│^popup menu test |
+          {1:~              }│{1:~               }|
+          :let g:menustr = 'foo'          |
+        ]])
+      end
+      eq('foo', meths.get_var('menustr'))
+    end)
+
+    if not multigrid then
+      -- oldtest: Test_popup_command_dump()
+      it(':popup command', function()
+        exec([[
+          func ChangeMenu()
+            aunmenu PopUp.&Paste
+            nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"
+            echomsg 'changed'
+            return "\"
+          endfunc
+
+          let lines =<< trim END
+            one two three four five
+            and one two Xthree four five
+            one more two three four five
+          END
+          call setline(1, lines)
+
+          aunmenu *
+          source $VIMRUNTIME/menu.vim
+        ]])
+        feed('/X:popup PopUp')
+        screen:expect([[
+          one two three four five         |
+          and one two {7:^X}three four five    |
+          one more tw{n: Undo             }   |
+          {1:~          }{n:                  }{1:   }|
+          {1:~          }{n: Paste            }{1:   }|
+          {1:~          }{n:                  }{1:   }|
+          {1:~          }{n: Select Word      }{1:   }|
+          {1:~          }{n: Select Sentence  }{1:   }|
+          {1:~          }{n: Select Paragraph }{1:   }|
+          {1:~          }{n: Select Line      }{1:   }|
+          {1:~          }{n: Select Block     }{1:   }|
+          {1:~          }{n: Select All       }{1:   }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :popup PopUp                    |
+        ]])
+
+        -- go to the Paste entry in the menu
+        feed('jj')
+        screen:expect([[
+          one two three four five         |
+          and one two {7:^X}three four five    |
+          one more tw{n: Undo             }   |
+          {1:~          }{n:                  }{1:   }|
+          {1:~          }{s: Paste            }{1:   }|
+          {1:~          }{n:                  }{1:   }|
+          {1:~          }{n: Select Word      }{1:   }|
+          {1:~          }{n: Select Sentence  }{1:   }|
+          {1:~          }{n: Select Paragraph }{1:   }|
+          {1:~          }{n: Select Line      }{1:   }|
+          {1:~          }{n: Select Block     }{1:   }|
+          {1:~          }{n: Select All       }{1:   }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :popup PopUp                    |
+        ]])
+
+        -- Select a word
+        feed('j')
+        screen:expect([[
+          one two three four five         |
+          and one two {7:^X}three four five    |
+          one more tw{n: Undo             }   |
+          {1:~          }{n:                  }{1:   }|
+          {1:~          }{n: Paste            }{1:   }|
+          {1:~          }{n:                  }{1:   }|
+          {1:~          }{s: Select Word      }{1:   }|
+          {1:~          }{n: Select Sentence  }{1:   }|
+          {1:~          }{n: Select Paragraph }{1:   }|
+          {1:~          }{n: Select Line      }{1:   }|
+          {1:~          }{n: Select Block     }{1:   }|
+          {1:~          }{n: Select All       }{1:   }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :popup PopUp                    |
+        ]])
+
+        feed('')
+
+        -- Set an  mapping to change a menu entry while it's displayed.
+        -- The text should not change but the command does.
+        -- Also verify that "changed" shows up, which means the mapping triggered.
+        command('nnoremap   ChangeMenu()')
+        feed('/X:popup PopUp')
+        screen:expect([[
+          one two three four five         |
+          and one two {7:^X}three four five    |
+          one more tw{n: Undo             }   |
+          {1:~          }{n:                  }{1:   }|
+          {1:~          }{n: Paste            }{1:   }|
+          {1:~          }{n:                  }{1:   }|
+          {1:~          }{n: Select Word      }{1:   }|
+          {1:~          }{n: Select Sentence  }{1:   }|
+          {1:~          }{n: Select Paragraph }{1:   }|
+          {1:~          }{n: Select Line      }{1:   }|
+          {1:~          }{n: Select Block     }{1:   }|
+          {1:~          }{n: Select All       }{1:   }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          changed                         |
+        ]])
+
+        -- Select the Paste entry, executes the changed menu item.
+        feed('jj')
+        screen:expect([[
+          one two three four five         |
+          and one two {7:^X}three four five    |
+          one more two three four five    |
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          pasted                          |
+        ]])
+      end)
+
+      describe('"kind" and "menu"', function()
+        before_each(function()
+          screen:try_resize(30, 8)
+          exec([[
+            func CompleteFunc( findstart, base )
+              if a:findstart
+                return 0
+              endif
+              return {
+                    \ 'words': [
+                    \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', },
+                    \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', },
+                    \ { 'word': 'aword3', 'menu': 'extra text 3', 'kind': 'W', },
+                    \]}
+            endfunc
+            set completeopt=menu
+            set completefunc=CompleteFunc
+          ]])
+        end)
+
+        -- oldtest: Test_pum_highlights_default()
+        it('default highlight groups', function()
+          feed('iaw')
+          screen:expect([[
+            aword1^                        |
+            {s:aword1 W extra text 1 }{1:        }|
+            {n:aword2 W extra text 2 }{1:        }|
+            {n:aword3 W extra text 3 }{1:        }|
+            {1:~                             }|
+            {1:~                             }|
+            {1:~                             }|
+            {2:-- }{5:match 1 of 3}               |
+          ]])
+        end)
+
+        -- oldtest: Test_pum_highlights_custom()
+        it('custom highlight groups', function()
+          exec([[
+            hi PmenuKind      guifg=Red guibg=Magenta
+            hi PmenuKindSel   guifg=Red guibg=Grey
+            hi PmenuExtra     guifg=White guibg=Magenta
+            hi PmenuExtraSel  guifg=Black guibg=Grey
+          ]])
+          local attrs = screen:get_default_attr_ids()
+          attrs.kn = {foreground = Screen.colors.Red, background = Screen.colors.Magenta}
+          attrs.ks = {foreground = Screen.colors.Red, background = Screen.colors.Grey}
+          attrs.xn = {foreground = Screen.colors.White, background = Screen.colors.Magenta}
+          attrs.xs = {foreground = Screen.colors.Black, background = Screen.colors.Grey}
+          feed('iaw')
+          screen:expect([[
+            aword1^                        |
+            {s:aword1 }{ks:W }{xs:extra text 1 }{1:        }|
+            {n:aword2 }{kn:W }{xn:extra text 2 }{1:        }|
+            {n:aword3 }{kn:W }{xn:extra text 3 }{1:        }|
+            {1:~                             }|
+            {1:~                             }|
+            {1:~                             }|
+            {2:-- }{5:match 1 of 3}               |
+          ]], attrs)
+        end)
+      end)
     end
-    funcs.complete(13, items)
-    screen:expect({grid=[[
-      ## grid 1
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [2:--------------------------------]|
-        [3:--------------------------------]|
-      ## grid 2
-                    ^                    |
-        {1:~                               }|
-        {1:~                               }|
-        {1:~                               }|
-        {1:~                               }|
-        {1:~                               }|
-        {1:~                               }|
-      ## grid 3
-        {2:-- INSERT --}                    |
-      ## grid 4
-        {n: 哦哦哦哦哦哦哦哦哦>}{c: }|
-        {n: 哦哦哦哦哦哦哦哦哦>}{c: }|
-        {n: 哦哦哦哦哦哦哦哦哦>}{s: }|
-        {n: 哦哦哦哦哦哦哦哦哦>}{s: }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 11, false, 100}}})
-  end)
+  end
 
-  it('supports mousemodel=popup', function()
-    screen:try_resize(32, 6)
-    exec([[
-      call setline(1, 'popup menu test')
-      set mouse=a mousemodel=popup
+  describe('with ext_multigrid', function()
+    with_ext_multigrid(true)
+  end)
 
-      aunmenu PopUp
-      menu PopUp.foo :let g:menustr = 'foo'
-      menu PopUp.bar :let g:menustr = 'bar'
-      menu PopUp.baz :let g:menustr = 'baz'
-    ]])
-    meths.input_mouse('right', 'press', '', 2, 1, 20)
-    screen:expect({grid=[[
-    ## grid 1
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [3:--------------------------------]|
-    ## grid 2
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-    ## grid 3
-                                      |
-    ## grid 4
-      {n: foo }|
-      {n: bar }|
-      {n: baz }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 2, 19, false, 250}}})
-    meths.input_mouse('left', 'press', '', 4, 2, 2)
-    screen:expect({grid=[[
-    ## grid 1
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [3:--------------------------------]|
-    ## grid 2
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-    ## grid 3
-      :let g:menustr = 'baz'          |
-    ]]})
-    eq('baz', meths.get_var('menustr'))
-    meths.input_mouse('right', 'press', '', 2, 0, 4)
-    screen:expect({grid=[[
-    ## grid 1
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [3:--------------------------------]|
-    ## grid 2
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-    ## grid 3
-      :let g:menustr = 'baz'          |
-    ## grid 4
-      {n: foo }|
-      {n: bar }|
-      {n: baz }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
-    meths.input_mouse('right', 'drag', '', 2, 3, 6)
-    screen:expect({grid=[[
-    ## grid 1
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [3:--------------------------------]|
-    ## grid 2
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-    ## grid 3
-      :let g:menustr = 'baz'          |
-    ## grid 4
-      {n: foo }|
-      {n: bar }|
-      {s: baz }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
-    meths.input_mouse('right', 'release', '', 2, 1, 6)
-    screen:expect({grid=[[
-    ## grid 1
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [3:--------------------------------]|
-    ## grid 2
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-    ## grid 3
-      :let g:menustr = 'foo'          |
-    ]]})
-    eq('foo', meths.get_var('menustr'))
-    eq(false, screen.options.mousemoveevent)
-    meths.input_mouse('right', 'press', '', 2, 0, 4)
-    screen:expect({grid=[[
-    ## grid 1
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [3:--------------------------------]|
-    ## grid 2
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-    ## grid 3
-      :let g:menustr = 'foo'          |
-    ## grid 4
-      {n: foo }|
-      {n: bar }|
-      {n: baz }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
-    eq(true, screen.options.mousemoveevent)
-    meths.input_mouse('move', '', '', 2, 3, 6)
-    screen:expect({grid=[[
-    ## grid 1
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [3:--------------------------------]|
-    ## grid 2
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-    ## grid 3
-      :let g:menustr = 'foo'          |
-    ## grid 4
-      {n: foo }|
-      {n: bar }|
-      {s: baz }|
-    ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 250}}})
-    eq(true, screen.options.mousemoveevent)
-    meths.input_mouse('left', 'press', '', 2, 2, 6)
-    screen:expect({grid=[[
-    ## grid 1
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [2:--------------------------------]|
-      [3:--------------------------------]|
-    ## grid 2
-      ^popup menu test                 |
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-      {1:~                               }|
-    ## grid 3
-      :let g:menustr = 'bar'          |
-    ]]})
-    eq(false, screen.options.mousemoveevent)
-    eq('bar', meths.get_var('menustr'))
+  describe('without ext_multigrid', function()
+    with_ext_multigrid(false)
   end)
 end)
-- 
cgit 


From eb4676c67f5dd54bcda473783315901a3444b40b Mon Sep 17 00:00:00 2001
From: Lewis Russell 
Date: Thu, 27 Apr 2023 17:30:22 +0100
Subject: fix: disallow removing extmarks in on_lines callbacks (#23219)

fix(extmarks): disallow removing extmarks in on_lines callbacks

decor_redraw_start (which runs before decor_providers_invoke_lines) gets
references for the extmarks on a specific line. If these extmarks are
deleted in on_lines callbacks then this results in a heap-use-after-free
error.

Fixes #22801
---
 test/functional/ui/decorations_spec.lua | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 80e5b6230e..5792c9703d 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -122,7 +122,7 @@ describe('decorations providers', function()
     ]]}
     check_trace {
       { "start", 5 };
-      { "buf", 1 };
+      { "buf", 1, 5 };
       { "win", 1000, 1, 0, 8 };
       { "line", 1000, 1, 6 };
       { "end", 5 };
@@ -565,6 +565,23 @@ describe('decorations providers', function()
                                               |
     ]])
   end)
+
+  it('does not allow removing extmarks during on_line callbacks', function()
+    exec_lua([[
+      eok = true
+    ]])
+    setup_provider([[
+      local function on_do(kind, winid, bufnr, topline, botline_guess)
+        if kind == 'line' then
+          api.nvim_buf_set_extmark(bufnr, ns1, 1, -1, { sign_text = 'X' })
+          eok = pcall(api.nvim_buf_clear_namespace, bufnr, ns1, 0, -1)
+        end
+      end
+    ]])
+    exec_lua([[
+      assert(eok == false)
+    ]])
+  end)
 end)
 
 describe('extmark decorations', function()
-- 
cgit 


From 1cb60405548e79f1ec63921540e1c3ebb3ddcc01 Mon Sep 17 00:00:00 2001
From: ii14 <59243201+ii14@users.noreply.github.com>
Date: Thu, 27 Apr 2023 19:25:08 +0200
Subject: perf(events): store autocommands in flat vectors (#23256)

Instead of nested linked lists, store autocommands in a flat, contiguous
kvec_t, with one kvec_t per event type. Previously patterns were stored
in each node of the outer linked list, so they can be matched only once
on repeating patterns. They are now reference counted and referenced in
each autocommand, and matching is skipped if the pattern repeats. Speeds
up creation and deletion, execution is not affected.

Co-authored-by: ii14 
---
 test/functional/autocmd/autocmd_spec.lua | 18 ++++++++++++++
 test/functional/autocmd/show_spec.lua    | 41 ++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index fb5bab445c..82c7f9502f 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -611,4 +611,22 @@ describe('autocmd', function()
       eq(4, #meths.get_autocmds { event = "BufReadCmd", group = "TestingPatterns" })
     end)
   end)
+
+  it('no use-after-free when adding autocommands from a callback', function()
+    exec_lua [[
+      vim.cmd "autocmd! TabNew"
+      vim.g.count = 0
+      vim.api.nvim_create_autocmd('TabNew', {
+        callback = function()
+          vim.g.count = vim.g.count + 1
+          for _ = 1, 100 do
+            vim.cmd "autocmd TabNew * let g:count += 1"
+          end
+          return true
+        end,
+      })
+      vim.cmd "tabnew"
+    ]]
+    eq(1, eval('g:count'))  -- Added autocommands should not be executed
+  end)
 end)
diff --git a/test/functional/autocmd/show_spec.lua b/test/functional/autocmd/show_spec.lua
index 505bed834b..9e0a5b819a 100644
--- a/test/functional/autocmd/show_spec.lua
+++ b/test/functional/autocmd/show_spec.lua
@@ -180,4 +180,45 @@ describe(":autocmd", function()
       test_3  User
           B         echo "B3"]]), funcs.execute('autocmd test_3 * B'))
   end)
+
+  it('should skip consecutive patterns', function()
+    exec([[
+      autocmd! BufEnter
+      augroup test_1
+        autocmd BufEnter A echo 'A'
+        autocmd BufEnter A echo 'B'
+        autocmd BufEnter A echo 'C'
+        autocmd BufEnter B echo 'D'
+        autocmd BufEnter B echo 'E'
+        autocmd BufEnter B echo 'F'
+      augroup END
+      augroup test_2
+        autocmd BufEnter C echo 'A'
+        autocmd BufEnter C echo 'B'
+        autocmd BufEnter C echo 'C'
+        autocmd BufEnter D echo 'D'
+        autocmd BufEnter D echo 'E'
+        autocmd BufEnter D echo 'F'
+      augroup END
+
+      let g:output = execute('autocmd BufEnter')
+    ]])
+    eq(dedent([[
+
+      --- Autocommands ---
+      test_1  BufEnter
+          A         echo 'A'
+                    echo 'B'
+                    echo 'C'
+          B         echo 'D'
+                    echo 'E'
+                    echo 'F'
+      test_2  BufEnter
+          C         echo 'A'
+                    echo 'B'
+                    echo 'C'
+          D         echo 'D'
+                    echo 'E'
+                    echo 'F']]), eval('g:output'))
+  end)
 end)
-- 
cgit 


From 774a32e5fe732a43b229ab25e24dffa36ac29aa4 Mon Sep 17 00:00:00 2001
From: ii14 
Date: Thu, 27 Apr 2023 22:03:17 +0200
Subject: fix(events): null dereference in autocmd functions

---
 test/functional/autocmd/autocmd_spec.lua | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index 82c7f9502f..da8c7b5ee0 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -629,4 +629,20 @@ describe('autocmd', function()
     ]]
     eq(1, eval('g:count'))  -- Added autocommands should not be executed
   end)
+
+  it('no crash when clearing a group inside a callback #23355', function()
+    exec_lua [[
+      vim.cmd "autocmd! TabNew"
+      local group = vim.api.nvim_create_augroup('Test', {})
+      local id
+      id = vim.api.nvim_create_autocmd('TabNew', {
+        group = group,
+        callback = function()
+          vim.api.nvim_del_autocmd(id)
+          vim.api.nvim_create_augroup('Test', { clear = true })
+        end,
+      })
+      vim.cmd "tabnew"
+    ]]
+  end)
 end)
-- 
cgit 


From fbaa2787736173e417a93b958a9ca61e888e567d Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Thu, 27 Apr 2023 23:40:39 +0800
Subject: fix(pum): make :popup position correctly with float border

---
 test/functional/ui/float_spec.lua | 123 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 120 insertions(+), 3 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index e2fe0a2df5..28c16642f1 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -9,6 +9,7 @@ local eval = helpers.eval
 local eq = helpers.eq
 local neq = helpers.neq
 local expect = helpers.expect
+local exec = helpers.exec
 local exec_lua = helpers.exec_lua
 local insert = helpers.insert
 local meths = helpers.meths
@@ -2123,7 +2124,7 @@ describe('float window', function()
           {5:║}{1:^         }{5:║}|
           {5:╚═════════╝}|
         ]], float_pos={
-          [5] = { { id = 1002 }, "NW", 1, 0, 5, true }
+          [5] = { { id = 1002 }, "NW", 1, 0, 5, true };
         }, win_viewport={
           [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
           [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 0, linecount = 3, sum_scroll_delta = 0};
@@ -2181,8 +2182,8 @@ describe('float window', function()
           {1: abb            }|
           {13: acc            }|
         ]], float_pos={
-          [5] = { { id = 1002 }, "NW", 1, 0, 5, true, 50 },
-          [6] = { { id = -1 }, "NW", 5, 4, 0, false, 100 }
+          [5] = { { id = 1002 }, "NW", 1, 0, 5, true, 50 };
+          [6] = { { id = -1 }, "NW", 5, 4, 0, false, 100 };
         }, win_viewport={
           [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1, sum_scroll_delta = 0};
           [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3, linecount=3, sum_scroll_delta = 0};
@@ -2201,6 +2202,122 @@ describe('float window', function()
           {3:-- }{8:match 1 of 4}                         |
         ]]}
       end
+
+      feed ''
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [3:----------------------------------------]|
+        ## grid 2
+                                                  |
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+        ## grid 3
+                                                  |
+        ## grid 5
+          {5:╔═════════╗}|
+          {5:║}{1:aaa aab  }{5:║}|
+          {5:║}{1:abb acc  }{5:║}|
+          {5:║}{1:ac^c      }{5:║}|
+          {5:╚═════════╝}|
+        ]], float_pos={
+          [5] = { { id = 1002 }, "NW", 1, 0, 5, true };
+        }, win_viewport={
+          [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+          [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 2, linecount = 3, sum_scroll_delta = 0};
+        }}
+      else
+        screen:expect{grid=[[
+               {5:╔═════════╗}                        |
+          {0:~    }{5:║}{1:aaa aab  }{5:║}{0:                        }|
+          {0:~    }{5:║}{1:abb acc  }{5:║}{0:                        }|
+          {0:~    }{5:║}{1:ac^c      }{5:║}{0:                        }|
+          {0:~    }{5:╚═════════╝}{0:                        }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+                                                  |
+        ]]}
+      end
+
+      exec([[
+        nnoremenu Test.foo :
+        nnoremenu Test.bar :
+        nnoremenu Test.baz :
+      ]])
+      feed ':popup Test'
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [2:----------------------------------------]|
+          [3:----------------------------------------]|
+        ## grid 2
+                                                  |
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+          {0:~                                       }|
+        ## grid 3
+          :popup Test                             |
+        ## grid 5
+          {5:╔═════════╗}|
+          {5:║}{1:aaa aab  }{5:║}|
+          {5:║}{1:abb acc  }{5:║}|
+          {5:║}{1:ac^c      }{5:║}|
+          {5:╚═════════╝}|
+        ## grid 6
+          {1: foo }|
+          {1: bar }|
+          {1: baz }|
+        ]], float_pos={
+          [5] = { { id = 1002 }, "NW", 1, 0, 5, true };
+          [6] = { { id = -1 }, "NW", 5, 4, 2, false, 250 };
+        }, win_viewport={
+          [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
+          [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 2, linecount = 3, sum_scroll_delta = 0};
+        }}
+      else
+        screen:expect{grid=[[
+               {5:╔═════════╗}                        |
+          {0:~    }{5:║}{1:aaa aab  }{5:║}{0:                        }|
+          {0:~    }{5:║}{1:abb acc  }{5:║}{0:                        }|
+          {0:~    }{5:║}{1:ac^c      }{5:║}{0:                        }|
+          {0:~    }{5:╚═}{1: foo }{5:═══╝}{0:                        }|
+          {0:~      }{1: bar }{0:                            }|
+          {0:~      }{1: baz }{0:                            }|
+          {0:~                                       }|
+          {0:~                                       }|
+          :popup Test                             |
+        ]]}
+      end
     end)
 
     it('show ruler of current floating window', function()
-- 
cgit 


From aca226d728418e791b897a908631d52aa24157fe Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Fri, 28 Apr 2023 05:50:08 +0800
Subject: vim-patch:9.0.1493: popup menu position wrong in window with toolbar

Problem:    Popup menu position wrong in window with toolbar.
Solution:   Take the window toolbar into account when positioning the popup
            menu. (closes vim/vim#12308)

https://github.com/vim/vim/commit/4e1ca0d9a6c6d66987da67155e97f83f286ffbcc

Fixed in the previous commit. Test only.
---
 test/functional/ui/popupmenu_spec.lua | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index c5e0c10a81..0b71e12b6f 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -4508,6 +4508,34 @@ describe('builtin popupmenu', function()
           {1:~                               }|
           pasted                          |
         ]])
+
+        -- Add a window toolbar to the window and check the :popup menu position.
+        command('setlocal winbar=TEST')
+        feed('/X:popup PopUp')
+        screen:expect([[
+          {2:TEST                            }|
+          one two three four five         |
+          and one two {7:^X}three four five    |
+          one more tw{n: Undo             }   |
+          {1:~          }{n:                  }{1:   }|
+          {1:~          }{n: Paste            }{1:   }|
+          {1:~          }{n:                  }{1:   }|
+          {1:~          }{n: Select Word      }{1:   }|
+          {1:~          }{n: Select Sentence  }{1:   }|
+          {1:~          }{n: Select Paragraph }{1:   }|
+          {1:~          }{n: Select Line      }{1:   }|
+          {1:~          }{n: Select Block     }{1:   }|
+          {1:~          }{n: Select All       }{1:   }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          {1:~                               }|
+          :popup PopUp                    |
+        ]])
+
+        feed('')
       end)
 
       describe('"kind" and "menu"', 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')

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 19a793545f15bb7e0bac2fc8f705c600e8f9c9bb Mon Sep 17 00:00:00 2001
From: Lewis Russell 
Date: Sun, 30 Apr 2023 16:11:38 +0100
Subject: fix(treesitter): redraw added/removed injections properly (#23287)

When injections are added or removed make sure to:
- invoke 'changedtree' callbacks for when new trees are added.
- invoke 'changedtree' callbacks for when trees are invalidated
- redraw regions when languagetree children are removed
---
 test/functional/treesitter/highlight_spec.lua | 82 +++++++++++++++++++++++----
 1 file changed, 72 insertions(+), 10 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index 4e1efec404..dc303c564f 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -11,7 +11,7 @@ local eq = helpers.eq
 
 before_each(clear)
 
-local hl_query = [[
+local hl_query_c = [[
   (ERROR) @error
 
   "if" @keyword
@@ -47,7 +47,7 @@ local hl_query = [[
   (comment) @comment
 ]]
 
-local hl_text = [[
+local hl_text_c = [[
 /// Schedule Lua callback on main loop's event queue
 static int nlua_schedule(lua_State *const lstate)
 {
@@ -64,7 +64,7 @@ static int nlua_schedule(lua_State *const lstate)
   return 0;
 }]]
 
-local test_text = [[
+local test_text_c = [[
 void ui_refresh(void)
 {
   int width = INT_MAX, height = INT_MAX;
@@ -85,7 +85,7 @@ void ui_refresh(void)
   }
 }]]
 
-describe('treesitter highlighting', function()
+describe('treesitter highlighting (C)', function()
   local screen
 
   before_each(function()
@@ -105,13 +105,13 @@ describe('treesitter highlighting', function()
       [11] = {foreground = Screen.colors.Cyan4};
     }
 
-    exec_lua([[ hl_query = ... ]], hl_query)
+    exec_lua([[ hl_query = ... ]], hl_query_c)
     command [[ hi link @error ErrorMsg ]]
     command [[ hi link @warning WarningMsg ]]
   end)
 
   it('is updated with edits', function()
-    insert(hl_text)
+    insert(hl_text_c)
     screen:expect{grid=[[
       /// Schedule Lua callback on main loop's event queue             |
       static int nlua_schedule(lua_State *const lstate)                |
@@ -274,7 +274,7 @@ describe('treesitter highlighting', function()
   end)
 
   it('is updated with :sort', function()
-    insert(test_text)
+    insert(test_text_c)
     exec_lua [[
       local parser = vim.treesitter.get_parser(0, "c")
       test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query}})
@@ -351,7 +351,7 @@ describe('treesitter highlighting', function()
       [1] = {bold = true, foreground = Screen.colors.SeaGreen4};
     }
 
-    insert(test_text)
+    insert(test_text_c)
 
     screen:expect{ grid= [[
       int width = INT_MAX, height = INT_MAX;                         |
@@ -510,7 +510,7 @@ describe('treesitter highlighting', function()
   end)
 
   it("supports highlighting with custom highlight groups", function()
-    insert(hl_text)
+    insert(hl_text_c)
 
     exec_lua [[
       local parser = vim.treesitter.get_parser(0, "c")
@@ -692,7 +692,7 @@ describe('treesitter highlighting', function()
   end)
 
   it("supports conceal attribute", function()
-    insert(hl_text)
+    insert(hl_text_c)
 
     -- conceal can be empty or a single cchar.
     exec_lua [=[
@@ -753,3 +753,65 @@ describe('treesitter highlighting', function()
     eq(nil, get_hl"@total.nonsense.but.a.lot.of.dots")
   end)
 end)
+
+describe('treesitter highlighting (help)', function()
+  local screen
+
+  before_each(function()
+    screen = Screen.new(40, 6)
+    screen:attach()
+    screen:set_default_attr_ids {
+      [1] = {foreground = Screen.colors.Blue1};
+      [2] = {bold = true, foreground = Screen.colors.Blue1};
+      [3] = {bold = true, foreground = Screen.colors.Brown};
+      [4] = {foreground = Screen.colors.Cyan4};
+      [5] = {foreground = Screen.colors.Magenta1};
+    }
+  end)
+
+  it("correctly redraws added/removed injections", function()
+    insert[[
+    >ruby
+      -- comment
+      local this_is = 'actually_lua'
+    <
+    ]]
+
+    exec_lua [[
+      vim.bo.filetype = 'help'
+      vim.treesitter.start()
+    ]]
+
+    screen:expect{grid=[[
+      {1:>ruby}                                   |
+      {1:  -- comment}                            |
+      {1:  local this_is = 'actually_lua'}        |
+      <                                       |
+      ^                                        |
+                                              |
+    ]]}
+
+    helpers.curbufmeths.set_text(0, 1, 0, 5, {'lua'})
+
+    screen:expect{grid=[[
+      {1:>lua}                                    |
+      {1:  -- comment}                            |
+      {1:  }{3:local}{1: }{4:this_is}{1: }{3:=}{1: }{5:'actually_lua'}        |
+      <                                       |
+      ^                                        |
+                                              |
+    ]]}
+
+    helpers.curbufmeths.set_text(0, 1, 0, 4, {'ruby'})
+
+    screen:expect{grid=[[
+      {1:>ruby}                                   |
+      {1:  -- comment}                            |
+      {1:  local this_is = 'actually_lua'}        |
+      <                                       |
+      ^                                        |
+                                              |
+    ]]}
+  end)
+
+end)
-- 
cgit 


From a803bff89c89cc63e549a3c791fa07d91d1106c8 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 1 May 2023 12:30:55 +0800
Subject: fix(spell): extmark with spell=false should disable spell (#23400)

---
 test/functional/ui/decorations_spec.lua | 117 ++++++++++++++++-----------
 test/functional/ui/spell_spec.lua       | 139 ++++++++++++++++++++++++++------
 2 files changed, 187 insertions(+), 69 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 5792c9703d..f531878bc6 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -8,6 +8,7 @@ local exec_lua = helpers.exec_lua
 local exec = helpers.exec
 local expect_events = helpers.expect_events
 local meths = helpers.meths
+local curbufmeths = helpers.curbufmeths
 local command = helpers.command
 
 describe('decorations providers', function()
@@ -31,8 +32,9 @@ describe('decorations providers', function()
       [12] = {foreground = tonumber('0x990000')};
       [13] = {background = Screen.colors.LightBlue};
       [14] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue};
-      [15] = {special = Screen.colors.Blue1, undercurl = true},
+      [15] = {special = Screen.colors.Blue, undercurl = true},
       [16] = {special = Screen.colors.Red, undercurl = true},
+      [17] = {foreground = Screen.colors.Red},
     }
   end)
 
@@ -201,14 +203,14 @@ describe('decorations providers', function()
     feed "gg0"
 
     screen:expect{grid=[[
-    ^I am well written text.                 |
-    {15:i} am not capitalized.                   |
-    I am a {16:speling} {16:mistakke}.                |
-                                            |
-    {1:~                                       }|
-    {1:~                                       }|
-    {1:~                                       }|
-                                            |
+      ^I am well written text.                 |
+      {15:i} am not capitalized.                   |
+      I am a {16:speling} {16:mistakke}.                |
+                                              |
+      {1:~                                       }|
+      {1:~                                       }|
+      {1:~                                       }|
+                                              |
     ]]}
 
     feed "]s"
@@ -216,14 +218,14 @@ describe('decorations providers', function()
       { "spell", 1000, 1, 1, 0, 1, -1 };
     }
     screen:expect{grid=[[
-    I am well written text.                 |
-    {15:^i} am not capitalized.                   |
-    I am a {16:speling} {16:mistakke}.                |
-                                            |
-    {1:~                                       }|
-    {1:~                                       }|
-    {1:~                                       }|
-                                            |
+      I am well written text.                 |
+      {15:^i} am not capitalized.                   |
+      I am a {16:speling} {16:mistakke}.                |
+                                              |
+      {1:~                                       }|
+      {1:~                                       }|
+      {1:~                                       }|
+                                              |
     ]]}
 
     feed "]s"
@@ -231,43 +233,68 @@ describe('decorations providers', function()
       { "spell", 1000, 1, 2, 7, 2, -1 };
     }
     screen:expect{grid=[[
-    I am well written text.                 |
-    {15:i} am not capitalized.                   |
-    I am a {16:^speling} {16:mistakke}.                |
-                                            |
-    {1:~                                       }|
-    {1:~                                       }|
-    {1:~                                       }|
-                                            |
+      I am well written text.                 |
+      {15:i} am not capitalized.                   |
+      I am a {16:^speling} {16:mistakke}.                |
+                                              |
+      {1:~                                       }|
+      {1:~                                       }|
+      {1:~                                       }|
+                                              |
     ]]}
 
-    -- spell=false with lower priority doesn't disable spell
+    -- spell=false with higher priority does disable spell
     local ns = meths.create_namespace "spell"
-    local id = helpers.curbufmeths.set_extmark(ns, 0, 0, { priority = 30, end_row = 2, end_col = 23, spell = false })
+    local id = curbufmeths.set_extmark(ns, 0, 0, { priority = 30, end_row = 2, end_col = 23, spell = false })
 
     screen:expect{grid=[[
-    I am well written text.                 |
-    i am not capitalized.                   |
-    I am a ^speling mistakke.                |
-                                            |
-    {1:~                                       }|
-    {1:~                                       }|
-    {1:~                                       }|
-                                            |
+      I am well written text.                 |
+      i am not capitalized.                   |
+      I am a ^speling mistakke.                |
+                                              |
+      {1:~                                       }|
+      {1:~                                       }|
+      {1:~                                       }|
+                                              |
     ]]}
 
-    -- spell=false with higher priority does disable spell
-    helpers.curbufmeths.set_extmark(ns, 0, 0, { id = id, priority = 10, end_row = 2, end_col = 23, spell = false })
+    feed "]s"
+    screen:expect{grid=[[
+      I am well written text.                 |
+      i am not capitalized.                   |
+      I am a ^speling mistakke.                |
+                                              |
+      {1:~                                       }|
+      {1:~                                       }|
+      {1:~                                       }|
+      {17:search hit BOTTOM, continuing at TOP}    |
+    ]]}
+    command('echo ""')
+
+    -- spell=false with lower priority doesn't disable spell
+    curbufmeths.set_extmark(ns, 0, 0, { id = id, priority = 10, end_row = 2, end_col = 23, spell = false })
+
+    screen:expect{grid=[[
+      I am well written text.                 |
+      {15:i} am not capitalized.                   |
+      I am a {16:^speling} {16:mistakke}.                |
+                                              |
+      {1:~                                       }|
+      {1:~                                       }|
+      {1:~                                       }|
+                                              |
+    ]]}
 
+    feed "]s"
     screen:expect{grid=[[
-    I am well written text.                 |
-    {15:i} am not capitalized.                   |
-    I am a {16:^speling} {16:mistakke}.                |
-                                            |
-    {1:~                                       }|
-    {1:~                                       }|
-    {1:~                                       }|
-                                            |
+      I am well written text.                 |
+      {15:i} am not capitalized.                   |
+      I am a {16:speling} {16:^mistakke}.                |
+                                              |
+      {1:~                                       }|
+      {1:~                                       }|
+      {1:~                                       }|
+                                              |
     ]]}
 
   end)
diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index 361f83d1ce..15819aef40 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -6,6 +6,8 @@ local clear = helpers.clear
 local feed = helpers.feed
 local insert = helpers.insert
 local command = helpers.command
+local meths = helpers.meths
+local curbufmeths = helpers.curbufmeths
 local is_os = helpers.is_os
 
 describe("'spell'", function()
@@ -18,11 +20,13 @@ describe("'spell'", function()
     screen:set_default_attr_ids( {
       [0] = {bold=true, foreground=Screen.colors.Blue},
       [1] = {special = Screen.colors.Red, undercurl = true},
-      [2] = {special = Screen.colors.Blue1, undercurl = true},
+      [2] = {special = Screen.colors.Blue, undercurl = true},
       [3] = {foreground = tonumber('0x6a0dad')},
       [4] = {foreground = Screen.colors.Magenta},
       [5] = {bold = true, foreground = Screen.colors.SeaGreen},
       [6] = {foreground = Screen.colors.Red},
+      [7] = {foreground = Screen.colors.Blue},
+      [8] = {foreground = Screen.colors.Blue, special = Screen.colors.Red, undercurl = true},
     })
   end)
 
@@ -74,19 +78,57 @@ describe("'spell'", function()
     ]])
   end)
 
-  it('"noplainbuffer" and syntax #20385', function()
+  it('extmarks, "noplainbuffer" and syntax #20385 #23398', function()
     command('set filetype=c')
     command('syntax on')
     command('set spell')
     insert([[
       #include 
-      bool func(void);]])
+      bool func(void);
+      // I am a speling mistakke]])
+    feed('ge')
     screen:expect([[
       {3:#include }{4:}                                                            |
-      {5:bool} func({5:void})^;                                                                |
+      {5:bool} func({5:void});                                                                |
+      {7:// I am a }{8:spelin^g}{7: }{8:mistakke}                                                      |
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
+    feed(']s')
+    screen:expect([[
+      {3:#include }{4:}                                                            |
+      {5:bool} func({5:void});                                                                |
+      {7:// I am a }{8:speling}{7: }{8:^mistakke}                                                      |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
+    feed(']s')
+    screen:expect([[
+      {3:#include }{4:}                                                            |
+      {5:bool} func({5:void});                                                                |
+      {7:// I am a }{8:^speling}{7: }{8:mistakke}                                                      |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {6:search hit BOTTOM, continuing at TOP}                                            |
+    ]])
+    command('echo ""')
+    local ns = meths.create_namespace("spell")
+    -- extmark with spell=true enables spell
+    local id = curbufmeths.set_extmark(ns, 1, 4, { end_row = 1, end_col = 10, spell = true })
+    screen:expect([[
+      {3:#include }{4:}                                                            |
+      {5:bool} {1:func}({5:void});                                                                |
+      {7:// I am a }{8:^speling}{7: }{8:mistakke}                                                      |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
                                                                                       |
@@ -94,73 +136,122 @@ describe("'spell'", function()
     feed('[s')
     screen:expect([[
       {3:#include }{4:}                                                            |
-      {5:bool} func({5:void})^;                                                                |
+      {5:bool} {1:^func}({5:void});                                                                |
+      {7:// I am a }{8:speling}{7: }{8:mistakke}                                                      |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
       {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
+    curbufmeths.del_extmark(ns, id)
+    -- extmark with spell=false disables spell
+    id = curbufmeths.set_extmark(ns, 2, 18, { end_row = 2, end_col = 26, spell = false })
+    screen:expect([[
+      {3:#include }{4:}                                                            |
+      {5:bool} ^func({5:void});                                                                |
+      {7:// I am a }{8:speling}{7: mistakke}                                                      |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
+    feed('[s')
+    screen:expect([[
+      {3:#include }{4:}                                                            |
+      {5:bool} func({5:void});                                                                |
+      {7:// I am a }{8:^speling}{7: mistakke}                                                      |
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
       {6:search hit TOP, continuing at BOTTOM}                                            |
     ]])
+    command('echo ""')
+    curbufmeths.del_extmark(ns, id)
+    screen:expect([[
+      {3:#include }{4:}                                                            |
+      {5:bool} func({5:void});                                                                |
+      {7:// I am a }{8:^speling}{7: }{8:mistakke}                                                      |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
+    feed(']s')
+    screen:expect([[
+      {3:#include }{4:}                                                            |
+      {5:bool} func({5:void});                                                                |
+      {7:// I am a }{8:speling}{7: }{8:^mistakke}                                                      |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
     -- "noplainbuffer" shouldn't change spellchecking behavior with syntax enabled
     command('set spelloptions+=noplainbuffer')
     screen:expect_unchanged()
-    feed(']s')
+    feed('[s')
     screen:expect([[
       {3:#include }{4:}                                                            |
-      {5:bool} func({5:void})^;                                                                |
-      {0:~                                                                               }|
+      {5:bool} func({5:void});                                                                |
+      {7:// I am a }{8:^speling}{7: }{8:mistakke}                                                      |
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
-      {6:search hit BOTTOM, continuing at TOP}                                            |
+                                                                                      |
     ]])
     -- no spellchecking with "noplainbuffer" and syntax disabled
     command('syntax off')
     screen:expect([[
       #include                                                             |
-      bool func(void)^;                                                                |
+      bool func(void);                                                                |
+      // I am a ^speling mistakke                                                      |
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
-      {0:~                                                                               }|
-      {6:search hit BOTTOM, continuing at TOP}                                            |
+                                                                                      |
     ]])
-    feed('[s')
+    feed(']s')
     screen:expect([[
       #include                                                             |
-      bool func(void)^;                                                                |
+      bool func(void);                                                                |
+      // I am a ^speling mistakke                                                      |
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
-      {0:~                                                                               }|
-      {6:search hit TOP, continuing at BOTTOM}                                            |
+      {6:search hit BOTTOM, continuing at TOP}                                            |
     ]])
+    command('echo ""')
     -- everything is spellchecked without "noplainbuffer" with syntax disabled
     command('set spelloptions&')
     screen:expect([[
       #include <{1:stdbool}.h>                                                            |
-      {1:bool} {1:func}(void)^;                                                                |
-      {0:~                                                                               }|
+      {1:bool} {1:func}(void);                                                                |
+      // I am a {1:^speling} {1:mistakke}                                                      |
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
-      {6:search hit TOP, continuing at BOTTOM}                                            |
+                                                                                      |
     ]])
-    feed(']s')
+    feed('[s')
     screen:expect([[
-      #include <{1:^stdbool}.h>                                                            |
-      {1:bool} {1:func}(void);                                                                |
-      {0:~                                                                               }|
+      #include <{1:stdbool}.h>                                                            |
+      {1:bool} {1:^func}(void);                                                                |
+      // I am a {1:speling} {1:mistakke}                                                      |
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
       {0:~                                                                               }|
-      {6:search hit BOTTOM, continuing at TOP}                                            |
+                                                                                      |
     ]])
   end)
+
 end)
-- 
cgit 


From 0f1b511f2302324684c3ed9ff586f51c2129694d Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 1 May 2023 12:20:07 +0800
Subject: fix(tui): redraw on SIGWINCH even if size didn't change

---
 test/functional/terminal/tui_spec.lua | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 069fbad803..f366c8a6d9 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -1565,6 +1565,29 @@ describe('TUI', function()
       {5:-- TERMINAL --}                                    |
     ]])
   end)
+
+  it('redraws on SIGWINCH even if terminal size is unchanged #23411', function()
+    child_session:request('nvim_echo', {{'foo'}}, false, {})
+    screen:expect([[
+      {1: }                                                 |
+      {4:~                                                 }|
+      {4:~                                                 }|
+      {4:~                                                 }|
+      {5:[No Name]                                         }|
+      foo                                               |
+      {3:-- TERMINAL --}                                    |
+    ]])
+    exec_lua([[vim.loop.kill(vim.fn.jobpid(vim.bo.channel), 'sigwinch')]])
+    screen:expect([[
+      {1: }                                                 |
+      {4:~                                                 }|
+      {4:~                                                 }|
+      {4:~                                                 }|
+      {5:[No Name]                                         }|
+                                                        |
+      {3:-- TERMINAL --}                                    |
+    ]])
+  end)
 end)
 
 describe('TUI', function()
-- 
cgit 


From 03e8b5fc91f9b4b0535f79a8d725e1551aec6795 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Tue, 2 May 2023 10:00:34 +0800
Subject: fix(float): make bufpos work properly with resized parent grid

---
 test/functional/ui/multigrid_spec.lua | 103 ++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 2525314b8e..7b2bf30642 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -37,6 +37,8 @@ describe('ext_multigrid', function()
       [18] = {bold = true, foreground = Screen.colors.Magenta},
       [19] = {foreground = Screen.colors.Brown},
       [20] = {background = Screen.colors.LightGrey},
+      [21] = {background = Screen.colors.LightMagenta},
+      [22] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue},
     })
   end)
 
@@ -1060,6 +1062,107 @@ describe('ext_multigrid', function()
                                                              |
       ]]}
     end)
+
+    it('anchored float window "bufpos"', function()
+      insert(('c'):rep(1111))
+      screen:expect{grid=[[
+      ## grid 1
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        {11:[No Name] [+]                                        }|
+        [3:-----------------------------------------------------]|
+      ## grid 2
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccc^c                             |
+        {1:~                                                           }|
+      ## grid 3
+                                                             |
+      ]]}
+      local float_buf = meths.create_buf(false, false)
+      meths.open_win(float_buf, false, {
+        relative = 'win',
+        win = curwin(),
+        bufpos = {0, 1018},
+        anchor = 'SE',
+        width = 5,
+        height = 5,
+      })
+      screen:expect{grid=[[
+      ## grid 1
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        {11:[No Name] [+]                                        }|
+        [3:-----------------------------------------------------]|
+      ## grid 2
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc|
+        cccccccccccccccccccccccccccccc^c                             |
+        {1:~                                                           }|
+      ## grid 3
+                                                             |
+      ## grid 4
+        {21:     }|
+        {22:~    }|
+        {22:~    }|
+        {22:~    }|
+        {22:~    }|
+      ]], float_pos={
+        [4] = {{id = 1001}, "SE", 2, 16, 58, true, 50};
+      }}
+    end)
   end)
 
   it('multiline messages scroll over windows', function()
-- 
cgit 


From 37b73cf14b118ca1583da2a3e89611222bd3e020 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Tue, 2 May 2023 10:36:41 +0800
Subject: fix(drawline): make cursorlineopt=screenline work with resized grid

---
 test/functional/ui/multigrid_spec.lua | 47 +++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 7b2bf30642..9663997a71 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -39,6 +39,7 @@ describe('ext_multigrid', function()
       [20] = {background = Screen.colors.LightGrey},
       [21] = {background = Screen.colors.LightMagenta},
       [22] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue},
+      [23] = {background = Screen.colors.Grey90},
     })
   end)
 
@@ -930,7 +931,7 @@ describe('ext_multigrid', function()
     end)
 
     it('wraps with grid width', function()
-      insert(('b'):rep(80).."\n")
+      insert(('b'):rep(160).."\n")
       screen:expect{grid=[[
       ## grid 1
         [2:-----------------------------------------------------]|
@@ -949,7 +950,8 @@ describe('ext_multigrid', function()
         [3:-----------------------------------------------------]|
       ## grid 2
         bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
-        bbbbbbbbbbbbbbbbbbbb                                        |
+        bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+        bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb                    |
         ^                                                            |
         {1:~                                                           }|
         {1:~                                                           }|
@@ -967,6 +969,47 @@ describe('ext_multigrid', function()
         {1:~                                                           }|
         {1:~                                                           }|
         {1:~                                                           }|
+      ## grid 3
+                                                             |
+      ]]}
+      feed('2gk')
+      command('setlocal cursorline cursorlineopt=screenline')
+      screen:expect{grid=[[
+      ## grid 1
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        {11:[No Name] [+]                                        }|
+        [3:-----------------------------------------------------]|
+      ## grid 2
+        bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb|
+        {23:^bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb}|
+        bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb                    |
+                                                                    |
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
         {1:~                                                           }|
       ## grid 3
                                                              |
-- 
cgit 


From 088cdf69e3faf5cf6c9ef743379638127e6e7c0b Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Tue, 2 May 2023 11:09:27 +0800
Subject: fix(normal): make "g$" work properly with resized grid

---
 test/functional/ui/multigrid_spec.lua | 88 ++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 9663997a71..6b6d6ad1d2 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -887,7 +887,6 @@ describe('ext_multigrid', function()
 
     it('gets written till grid width', function()
       insert(('a'):rep(60).."\n")
-
       screen:expect{grid=[[
       ## grid 1
         [2:-----------------------------------------------------]|
@@ -930,6 +929,93 @@ describe('ext_multigrid', function()
       ]]}
     end)
 
+    it('"g$" works correctly with double-width characters and no wrapping', function()
+      command('set nowrap')
+      insert(('a'):rep(58) .. ('哦'):rep(3))
+      feed('0')
+      screen:expect{grid=[[
+      ## grid 1
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        {11:[No Name] [+]                                        }|
+        [3:-----------------------------------------------------]|
+      ## grid 2
+        ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa哦|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+      ## grid 3
+                                                             |
+      ]]}
+      feed('g$')
+      screen:expect{grid=[[
+      ## grid 1
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        {11:[No Name] [+]                                        }|
+        [3:-----------------------------------------------------]|
+      ## grid 2
+        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^哦|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+      ## grid 3
+                                                             |
+      ]]}
+    end)
+
     it('wraps with grid width', function()
       insert(('b'):rep(160).."\n")
       screen:expect{grid=[[
-- 
cgit 


From 7c1921e9d69e008781c9fb16c11e843f7bd9099a Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Tue, 2 May 2023 15:25:41 +0800
Subject: fix(mouse): fix popup_setpos position check with ext_multigrid
 (#23436)

---
 test/functional/ui/multigrid_spec.lua | 396 +++++++++++++++++++++++++++++++++-
 1 file changed, 395 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 6b6d6ad1d2..558b9e3e16 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -2235,7 +2235,7 @@ describe('ext_multigrid', function()
       {1:~                         }|
     ]]}
 
-    meths.input_mouse('left', 'press', '', 1,8, 26)
+    meths.input_mouse('left', 'press', '', 1, 8, 26)
     poke_eventloop()
     meths.input_mouse('left', 'drag', '', 1, 6, 30)
     screen:expect{grid=[[
@@ -2276,6 +2276,400 @@ describe('ext_multigrid', function()
       {1:~                             }|
       {1:~                             }|
     ]]}
+
+    command('aunmenu PopUp | vmenu PopUp.Copy y')
+
+    funcs.setreg('"', '')
+    meths.input_mouse('left', 'press', '2', 2, 1, 6)
+    screen:expect{grid=[[
+    ## grid 1
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {12:[No Name] [+]                                        }|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  }{11:[No Name] [+]         }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be {20:clicke}^d         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+      {7:-- VISUAL --}                                         |
+    ## grid 4
+      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmo          |
+      {1:~                                                                               }|
+    ## grid 5
+      some text                     |
+      to be {20:clicked}                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ]]}
+    meths.input_mouse('right', 'press', '', 2, 1, 6)
+    meths.input_mouse('right', 'release', '', 2, 1, 6)
+    screen:expect{grid=[[
+    ## grid 1
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {12:[No Name] [+]                                        }|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  }{11:[No Name] [+]         }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be {20:clicke}^d         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+      {7:-- VISUAL --}                                         |
+    ## grid 4
+      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmo          |
+      {1:~                                                                               }|
+    ## grid 5
+      some text                     |
+      to be {20:clicked}                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ## grid 6
+      {21: Copy }|
+    ]], float_pos={
+      [6] = {{id = -1}, "NW", 2, 2, 5, false, 250};
+    }}
+    feed('')
+    screen:expect{grid=[[
+    ## grid 1
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {12:[No Name] [+]                                        }|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  }{11:[No Name] [+]         }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be ^clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+                                                           |
+    ## grid 4
+      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmo          |
+      {1:~                                                                               }|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ]]}
+    eq('clicked', funcs.getreg('"'))
+
+    funcs.setreg('"', '')
+    meths.input_mouse('left', 'press', '2', 4, 0, 64)
+    screen:expect{grid=[[
+    ## grid 1
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+      {7:-- VISUAL --}                                         |
+    ## grid 4
+      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do {20:eiusm}^o          |
+      {1:~                                                                               }|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ]]}
+    meths.input_mouse('right', 'press', '', 4, 0, 64)
+    meths.input_mouse('right', 'release', '', 4, 0, 64)
+    -- FIXME: popup menu position is strange
+    -- screen:expect{}
+    feed('')
+    screen:expect{grid=[[
+    ## grid 1
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+                                                           |
+    ## grid 4
+      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do ^eiusmo          |
+      {1:~                                                                               }|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ]]}
+    eq('eiusmo', funcs.getreg('"'))
+
+    command('wincmd J')
+    screen:try_resize_grid(4, 7, 10)
+    screen:expect{grid=[[
+    ## grid 1
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+                                                           |
+    ## grid 4
+      Lorem i|
+      psum do|
+      lor sit|
+       amet, |
+      consect|
+      etur ad|
+      ipiscin|
+      g elit,|
+       sed do|
+       ^eiusmo|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ]]}
+
+    funcs.setreg('"', '')
+    meths.input_mouse('left', 'press', '2', 4, 9, 1)
+    screen:expect{grid=[[
+    ## grid 1
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+      {7:-- VISUAL --}                                         |
+    ## grid 4
+      Lorem i|
+      psum do|
+      lor sit|
+       amet, |
+      consect|
+      etur ad|
+      ipiscin|
+      g elit,|
+       sed do|
+       {20:eiusm}^o|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ]]}
+    meths.input_mouse('right', 'press', '', 4, 9, 1)
+    meths.input_mouse('right', 'release', '', 4, 9, 1)
+    screen:expect{grid=[[
+    ## grid 1
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+      {7:-- VISUAL --}                                         |
+    ## grid 4
+      Lorem i|
+      psum do|
+      lor sit|
+       amet, |
+      consect|
+      etur ad|
+      ipiscin|
+      g elit,|
+       sed do|
+       {20:eiusm}^o|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ## grid 6
+      {21: Copy }|
+    ]], float_pos={
+      [6] = {{id = -1}, "SW", 4, 9, 0, false, 250};
+    }}
+    feed('')
+    screen:expect{grid=[[
+    ## grid 1
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+                                                           |
+    ## grid 4
+      Lorem i|
+      psum do|
+      lor sit|
+       amet, |
+      consect|
+      etur ad|
+      ipiscin|
+      g elit,|
+       sed do|
+       ^eiusmo|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ]]}
+    eq('eiusmo', funcs.getreg('"'))
   end)
 
   it('supports mouse drag with mouse=a', function()
-- 
cgit 


From be11f80d018797b514ed7d01cde2e4c8f88cc8d2 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 26 Apr 2023 01:55:00 +0200
Subject: vim-patch:9.0.0640: cannot scroll by screen line if a line wraps

Problem:    Cannot scroll by screen line if a line wraps.
Solution:   Add the 'smoothscroll' option.  Only works for CTRL-E and CTRL-Y
            so far.

https://github.com/vim/vim/commit/f6196f424474e2a9c160f2a995fc2691f82b58f9

vim-patch:9.0.0641: missing part of the new option code

Problem:    Missing part of the new option code.
Solution:   Add missing WV_SMS.

https://github.com/vim/vim/commit/bbbda8fd81f6d720962b67ae885825bad9be4456

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 111 +++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)
 create mode 100644 test/functional/legacy/scroll_opt_spec.lua

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
new file mode 100644
index 0000000000..0d0e9640a7
--- /dev/null
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -0,0 +1,111 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('smoothscroll', function()
+  local screen
+
+  before_each(function()
+    screen = Screen.new(40, 12)
+    screen:attach()
+  end)
+
+  -- oldtest: Test_smoothscroll_CtrlE_CtrlY()
+  it('works with  and ', function()
+    exec([[
+      call setline(1, [ 'line one', 'word '->repeat(20), 'line three', 'long word '->repeat(7), 'line', 'line', 'line', ])
+      set smoothscroll
+      :5
+    ]])
+    local s0 = [[
+      line one                                |
+      word word word word word word word word |
+      word word word word word word word word |
+      word word word word                     |
+      line three                              |
+      long word long word long word long word |
+      long word long word long word           |
+      ^line                                    |
+      line                                    |
+      line                                    |
+      ~                                       |
+                                              |
+    ]]
+    local s1 = [[
+      word word word word word word word word |
+      word word word word word word word word |
+      word word word word                     |
+      line three                              |
+      long word long word long word long word |
+      long word long word long word           |
+      ^line                                    |
+      line                                    |
+      line                                    |
+      ~                                       |
+      ~                                       |
+                                              |
+    ]]
+    local s2 = [[
+      word word word word word word word word |
+      word word word word                     |
+      line three                              |
+      long word long word long word long word |
+      long word long word long word           |
+      ^line                                    |
+      line                                    |
+      line                                    |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+                                              |
+    ]]
+    local s3 = [[
+      word word word word                     |
+      line three                              |
+      long word long word long word long word |
+      long word long word long word           |
+      ^line                                    |
+      line                                    |
+      line                                    |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+                                              |
+    ]]
+    local s4 = [[
+      line three                              |
+      long word long word long word long word |
+      long word long word long word           |
+      ^line                                    |
+      line                                    |
+      line                                    |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+                                              |
+    ]]
+    feed('')
+    screen:expect(s1)
+    feed('')
+    screen:expect(s2)
+    feed('')
+    screen:expect(s3)
+    feed('')
+    screen:expect(s4)
+    feed('')
+    screen:expect(s3)
+    feed('')
+    screen:expect(s2)
+    feed('')
+    screen:expect(s1)
+    feed('')
+    screen:expect(s0)
+  end)
+end)
-- 
cgit 


From 69af5e8782e601fe9c1e39adf49ce16728719a73 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 26 Apr 2023 04:00:38 +0200
Subject: vim-patch:9.0.0645: CTRL-Y does not stop at line 1

Problem:    CTRL-Y does not stop at line 1. (John Marriott)
Solution:   Stop at line 1 when 'smoothscroll' is not set. (closes vim/vim#11261)

https://github.com/vim/vim/commit/8df9748edb2ac8bd025e34e06194ac210667c97a

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 13 +++++++++++++
 1 file changed, 13 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 0d0e9640a7..14dbe0caf9 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -14,6 +14,19 @@ describe('smoothscroll', function()
     screen:attach()
   end)
 
+  -- oldtest: Test_CtrlE_CtrlY_stop_at_end()
+  it('disabled does not break  and  stop at end', function()
+    exec([[
+      enew
+      call setline(1, ['one', 'two'])
+      set number
+    ]])
+    feed('')
+    screen:expect({any = "  1 ^one"})
+    feed('')
+    screen:expect({any = "  2 ^two"})
+  end)
+
   -- oldtest: Test_smoothscroll_CtrlE_CtrlY()
   it('works with  and ', function()
     exec([[
-- 
cgit 


From d6050e9bda7f8b080c577100ae94e017dc146c88 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 26 Apr 2023 04:32:50 +0200
Subject: vim-patch:9.0.0646: with 'smoothscroll' CTRL-E is wrong when
 'foldmethod' set

Problem:    with 'smoothscroll' set CTRL-E does not work properly when
            'foldmethod' is set to "indent". (Yee Cheng Chin)
Solution:   Merge the code for scroling with folds and 'smoothscroll'.
            (closes vim/vim#11262)

https://github.com/vim/vim/commit/6b2d4ff7148e0b416ba745d20d061e6f7bb53ee7

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 80 ++++++++++++++++++++++++------
 1 file changed, 66 insertions(+), 14 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 14dbe0caf9..20976089e2 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -31,11 +31,10 @@ describe('smoothscroll', function()
   it('works with  and ', function()
     exec([[
       call setline(1, [ 'line one', 'word '->repeat(20), 'line three', 'long word '->repeat(7), 'line', 'line', 'line', ])
-      set smoothscroll
+      set smoothscroll scrolloff=5
       :5
     ]])
-    local s0 = [[
-      line one                                |
+    local s1 = [[
       word word word word word word word word |
       word word word word word word word word |
       word word word word                     |
@@ -45,11 +44,11 @@ describe('smoothscroll', function()
       ^line                                    |
       line                                    |
       line                                    |
+      ~                                       |
       ~                                       |
                                               |
     ]]
-    local s1 = [[
-      word word word word word word word word |
+    local s2 = [[
       word word word word word word word word |
       word word word word                     |
       line three                              |
@@ -59,11 +58,11 @@ describe('smoothscroll', function()
       line                                    |
       line                                    |
       ~                                       |
+      ~                                       |
       ~                                       |
                                               |
     ]]
-    local s2 = [[
-      word word word word word word word word |
+    local s3 = [[
       word word word word                     |
       line three                              |
       long word long word long word long word |
@@ -73,37 +72,80 @@ describe('smoothscroll', function()
       line                                    |
       ~                                       |
       ~                                       |
+      ~                                       |
       ~                                       |
                                               |
     ]]
-    local s3 = [[
-      word word word word                     |
+    local s4 = [[
       line three                              |
       long word long word long word long word |
       long word long word long word           |
-      ^line                                    |
       line                                    |
       line                                    |
+      ^line                                    |
+      ~                                       |
       ~                                       |
       ~                                       |
       ~                                       |
       ~                                       |
                                               |
     ]]
-    local s4 = [[
+    local s5 = [[
+      word word word word                     |
       line three                              |
       long word long word long word long word |
       long word long word long word           |
+      line                                    |
+      line                                    |
       ^line                                    |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+                                              |
+    ]]
+    local s6 = [[
+      word word word word word word word word |
+      word word word word                     |
+      line three                              |
+      long word long word long word long word |
+      long word long word long word           |
       line                                    |
       line                                    |
+      ^line                                    |
       ~                                       |
       ~                                       |
       ~                                       |
+                                              |
+    ]]
+    local s7 = [[
+      word word word word word word word word |
+      word word word word word word word word |
+      word word word word                     |
+      line three                              |
+      long word long word long word long word |
+      long word long word long word           |
+      line                                    |
+      line                                    |
+      ^line                                    |
       ~                                       |
       ~                                       |
                                               |
     ]]
+    local s8 = [[
+      line one                                |
+      word word word word word word word word |
+      word word word word word word word word |
+      word word word word                     |
+      line three                              |
+      long word long word long word long word |
+      long word long word long word           |
+      line                                    |
+      line                                    |
+      ^line                                    |
+      ~                                       |
+                                              |
+    ]]
     feed('')
     screen:expect(s1)
     feed('')
@@ -113,12 +155,22 @@ describe('smoothscroll', function()
     feed('')
     screen:expect(s4)
     feed('')
-    screen:expect(s3)
+    screen:expect(s5)
     feed('')
-    screen:expect(s2)
+    screen:expect(s6)
     feed('')
+    screen:expect(s7)
+    feed('')
+    screen:expect(s8)
+    exec('set foldmethod=indent')
+    -- move the cursor so we can reuse the same dumps
+    feed('5G')
     screen:expect(s1)
+    feed('')
+    screen:expect(s2)
+    feed('7G')
+    screen:expect(s7)
     feed('')
-    screen:expect(s0)
+    screen:expect(s8)
   end)
 end)
-- 
cgit 


From a43b28a34c568eb3e280e75a81424f80f0ed980b Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 26 Apr 2023 13:11:33 +0200
Subject: vim-patch:9.0.0649: no indication the first line is broken for
 'smoothscroll'

Problem:    No indication when the first line is broken for 'smoothscroll'.
Solution:   Show "<<<" in the first line.

https://github.com/vim/vim/commit/406b5d89e18742ac6e6256ffc72fb70a27f0148b

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 20976089e2..ddbeca1a30 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -49,7 +49,7 @@ describe('smoothscroll', function()
                                               |
     ]]
     local s2 = [[
-      word word word word word word word word |
+      <<
Date: Thu, 27 Apr 2023 04:54:50 +0200
Subject: vim-patch:9.0.0652: 'smoothscroll' not tested with 'number' and "n"
 in 'cpo'

Problem:    'smoothscroll' not tested with 'number' and "n" in 'cpo'.
Solution:   Add tests, fix uncovered problem.

https://github.com/vim/vim/commit/b6aab8f44beb8c5d99393abdc2c9faab085c72aa

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 99 ++++++++++++++++++++++++++++++
 test/functional/ui/highlight_spec.lua      |  2 +-
 test/functional/ui/popupmenu_spec.lua      |  2 +-
 3 files changed, 101 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index ddbeca1a30..8d2eade1a8 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -173,4 +173,103 @@ describe('smoothscroll', function()
     feed('')
     screen:expect(s8)
   end)
+
+  -- oldtest: Test_smoothscroll_number()
+  it("works 'number' and 'cpo'+=n", function()
+    exec([[
+      call setline(1, [ 'one ' .. 'word '->repeat(20), 'two ' .. 'long word '->repeat(7), 'line', 'line', 'line', ])
+      set smoothscroll scrolloff=5
+      set number cpo+=n
+      :3
+    ]])
+    screen:expect([[
+        1 one word word word word word word wo|
+      rd word word word word word word word wo|
+      rd word word word word word             |
+        2 two long word long word long word lo|
+      ng word long word long word long word   |
+        3 ^line                                |
+        4 line                                |
+        5 line                                |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+                                              |
+    ]])
+    feed('')
+    screen:expect([[
+      <<')
+    screen:expect([[
+      <<')
+    screen:expect([[
+      <<< rd word word word word word word wor|
+          d word word word word word word     |
+        2 two long word long word long word lo|
+          ng word long word long word long wor|
+          d                                   |
+        3 ^line                                |
+        4 line                                |
+        5 line                                |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+                                              |
+    ]])
+    feed('')
+    screen:expect([[
+        1 one word word word word word word wo|
+          rd word word word word word word wor|
+          d word word word word word word     |
+        2 two long word long word long word lo|
+          ng word long word long word long wor|
+          d                                   |
+        3 ^line                                |
+        4 line                                |
+        5 line                                |
+      ~                                       |
+      ~                                       |
+                                              |
+    ]])
+  end)
 end)
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 89b503141b..01895003ae 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -704,7 +704,7 @@ describe("'listchars' highlight", function()
     feed_command('set listchars=eol:¬,precedes:< list')
     feed('90ia')
     screen:expect([[
-      {0:<}aaaaaaaaaaaaaaaaaaa|
+      {0:<<<}aaaaaaaaaaaaaaaaa|
       aaaaaaaaaaaaaaaaaaaa|
       aaaaaaaaaaaaaaaaaaaa|
       aaaaaaaaa^a{0:¬}         |
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 0b71e12b6f..6c26c8ea39 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -2396,7 +2396,7 @@ describe('builtin popupmenu', function()
         -- can't draw the pum, but check we don't crash
         screen:try_resize(12,2)
         screen:expect([[
-          text^        |
+          {1:<<<}t^        |
           {2:-- INSERT -} |
         ]])
 
-- 
cgit 


From 8e4a4629cab3377ba6fd5e291cf5f17fb4ff8a5c Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 26 Apr 2023 16:54:23 +0200
Subject: vim-patch:9.0.0671: negative topline using CTRL-Y with 'smoothscroll'
 and 'diff'

Problem:    Negative topline using CTRL-Y with 'smoothscroll' and 'diff'.
            (Ernie Rael)
Solution:   Only use 'smoothscroll' when 'wrap' is set.

https://github.com/vim/vim/commit/1a58e1d97cfc72e501cbf63ad75f46f1bb4c8da2

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 8d2eade1a8..90417d93f3 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -272,4 +272,33 @@ describe('smoothscroll', function()
                                               |
     ]])
   end)
+
+  -- oldtest: Test_smoothscroll_diff_mode()
+  it("works with diff mode", function()
+    screen:try_resize(40, 8)
+    exec([[
+      let text = 'just some text here'
+      call setline(1, text)
+      set smoothscroll
+      diffthis
+      new
+      call setline(1, text)
+      set smoothscroll
+      diffthis
+    ]])
+    screen:expect([[
+      - ^just some text here                   |
+      ~                                       |
+      ~                                       |
+      [No Name] [+]                           |
+      - just some text here                   |
+      ~                                       |
+      [No Name] [+]                           |
+                                              |
+    ]])
+    feed('')
+    screen:expect_unchanged()
+    feed('')
+    screen:expect_unchanged()
+  end)
 end)
-- 
cgit 


From 3a1973debceca29e65c4f7c83d025cb3314ebaf2 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 26 Apr 2023 17:08:35 +0200
Subject: vim-patch:9.0.0672: line partly shows with 'smoothscroll' and
 'scrolloff' zero

Problem:    Cursor line only partly shows with 'smoothscroll' and 'scrolloff'
            zero.
Solution:   Do not use 'smoothscroll' when adjusting the bottom of the window.
            (closes vim/vim#11269)

https://github.com/vim/vim/commit/9bab7a024393200bb2c03b3abddfda86436990a7

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 90417d93f3..c63401cb02 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -301,4 +301,30 @@ describe('smoothscroll', function()
     feed('')
     screen:expect_unchanged()
   end)
+
+  -- oldtest: Test_smoothscroll_wrap_scrolloff_zero()
+  it("works with zero 'scrolloff'", function()
+    screen:try_resize(40, 8)
+    exec([[
+      call setline(1, ['Line' .. (' with some text'->repeat(7))]->repeat(7))
+      set smoothscroll scrolloff=0
+      :3
+    ]])
+    screen:expect([[
+      <<j')
+    screen:expect_unchanged()
+    feed('G')
+    screen:expect_unchanged()
+  end)
 end)
-- 
cgit 


From d95697d6d4533e84bbb9d262b355ee9f71bd7452 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 26 Apr 2023 17:23:42 +0200
Subject: vim-patch:9.0.0673: first line wong with 'smoothscroll' and
 'scrolloff' zero

Problem:    First line not scrolled properly with 'smoothscroll' and
            'scrolloff' zero and using "k".
Solution:   Make sure the cursor position is visible.

https://github.com/vim/vim/commit/46b54747c5d252c584571a321231bad9330018ec

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index c63401cb02..fb4990ff00 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -307,7 +307,7 @@ describe('smoothscroll', function()
     screen:try_resize(40, 8)
     exec([[
       call setline(1, ['Line' .. (' with some text'->repeat(7))]->repeat(7))
-      set smoothscroll scrolloff=0
+      set smoothscroll scrolloff=0 display=
       :3
     ]])
     screen:expect([[
@@ -322,9 +322,22 @@ describe('smoothscroll', function()
     ]])
     feed('j')
     screen:expect_unchanged()
+    -- moving cursor down - whole bottom line shows
     feed('j')
     screen:expect_unchanged()
     feed('G')
     screen:expect_unchanged()
+    -- moving cursor up - whole top line shows
+    feed('2k')
+    screen:expect([[
+      ^Line with some text with some text with |
+      some text with some text with some text |
+      with some text with some text           |
+      Line with some text with some text with |
+      some text with some text with some text |
+      with some text with some text           |
+      @                                       |
+                                              |
+    ]])
   end)
 end)
-- 
cgit 


From f3de7f44685c8ec99c1f5c7a624a668044c5aa19 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 26 Apr 2023 21:56:31 +0200
Subject: vim-patch:9.0.0701: with 'smoothscroll' cursor position not adjusted
 in long line

Problem:    With 'smoothscroll' the cursor position s not adjusted in a long
            line.
Solution:   Move the cursor further up or down in the line.

https://github.com/vim/vim/commit/8cf3459878198c5bb4a96f3c63214b2beccce341

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 56 ++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index fb4990ff00..5c7c9cd55a 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -340,4 +340,60 @@ describe('smoothscroll', function()
                                               |
     ]])
   end)
+
+  -- oldtest: Test_smoothscroll_wrap_long_line()
+  it("adjusts the cursor position in a long line", function()
+    screen:try_resize(40, 6)
+    exec([[
+      call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(30))])
+      set smoothscroll scrolloff=0
+      normal 3G10|zt
+    ]])
+    -- scrolling up, cursor moves screen line down
+    screen:expect([[
+      Line with^ lots of text with lots of text|
+       with lots of text with lots of text wit|
+      h lots of text with lots of text with lo|
+      ts of text with lots of text with lots o|
+      f text with lots of text with lots of te|
+                                              |
+    ]])
+    feed('')
+    screen:expect([[
+      <<')
+    screen:expect([[
+      <<< lots ^of text with lots of text with |
+      lots of text with lots of text with lots|
+       of text with lots of text with lots of |
+      text with lots of text with lots of text|
+       with lots of text with lots of text wit|
+                                              |
+    ]])
+    -- scrolling down, cursor moves screen line up
+    feed('5')
+    screen:expect([[
+      <<')
+    screen:expect([[
+      Line with lots of text with lots of text|
+       with lots of text with lots of text wit|
+      h lots of text with lots of text with lo|
+      ts of text with lots of text with lots o|
+      f text wi^th lots of text with lots of te|
+                                              |
+    ]])
+  end)
 end)
-- 
cgit 


From 36c98b47a3526dc61d149f951f8b8e3a677c26eb Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 26 Apr 2023 22:15:25 +0200
Subject: vim-patch:9.0.0707: with 'smoothscroll' cursor position not adjusted
 in long line

Problem:    With 'smoothscroll' and 'scrolloff' non-zero the cursor position
            is not properly adjusted in a long line.
Solution:   Move the cursor further up or down in the line.

https://github.com/vim/vim/commit/118c235112854f34182d968613d7fe98be3b290b

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 42 ++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 5c7c9cd55a..be7d324908 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -395,5 +395,47 @@ describe('smoothscroll', function()
       f text wi^th lots of text with lots of te|
                                               |
     ]])
+    -- 'scrolloff' set to 1, scrolling up, cursor moves screen line down
+    exec('set scrolloff=1')
+    feed('10|')
+    screen:expect([[
+      <<gjgj')
+    screen:expect([[
+      <<')
+    screen:expect([[
+      <<gjgj')
+    screen:expect([[
+      <<
Date: Wed, 26 Apr 2023 22:32:38 +0200
Subject: vim-patch:9.0.0734: cursor position invalid when scrolling with
 'smoothscroll'

Problem:    Cursor position invalid when scrolling with 'smoothscroll' set.
            (Ernie Rael)
Solution:   Add w_valid_skipcol and clear flags when it changes.  Adjust
            w_skipcol after moving the cursor.

https://github.com/vim/vim/commit/2fbabd238a94022c99506e920186a5b6cdf15426

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 34 ++++++++++++++++++++++++------
 1 file changed, 28 insertions(+), 6 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index be7d324908..a5660ae4d2 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -428,14 +428,36 @@ describe('smoothscroll', function()
                                               |
     ]])
     -- 'scrolloff' set to 2, scrolling down, cursor moves screen line up
-    feed('gjgj')
+    feed('gj')
+    screen:expect_unchanged()
+  end)
+
+  -- oldtest: Test_smoothscroll_one_long_line()
+  it("scrolls correctly when moving the cursor", function()
+    screen:try_resize(40, 6)
+    exec([[
+      call setline(1, 'with lots of text '->repeat(7))
+      set smoothscroll scrolloff=0
+    ]])
+    local s1 = [[
+      ^with lots of text with lots of text with|
+       lots of text with lots of text with lot|
+      s of text with lots of text with lots of|
+       text                                   |
+      ~                                       |
+                                              |
+    ]]
+    screen:expect(s1)
+    feed('')
     screen:expect([[
-      <<
Date: Thu, 27 Apr 2023 00:57:48 +0200
Subject: vim-patch:9.0.0757: line number not visisble with 'smoothscroll',
 'nu' and 'rnu'

Problem:    Line number not visisble with 'smoothscroll', 'nu' and 'rnu'.
Solution:   Put the ">>>" after the line number instead of on top.

https://github.com/vim/vim/commit/eb4de629315f2682d8b314462d02422ec98d751a

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index a5660ae4d2..5e54470bd4 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -181,6 +181,12 @@ describe('smoothscroll', function()
       set smoothscroll scrolloff=5
       set number cpo+=n
       :3
+      func g:DoRel()
+        set number relativenumber scrolloff=0
+        :%del
+        call setline(1, [ 'one', 'very long text '->repeat(12), 'three', ])
+        exe "normal 2Gzt\"
+      endfunc
     ]])
     screen:expect([[
         1 one word word word word word word wo|
@@ -271,6 +277,21 @@ describe('smoothscroll', function()
       ~                                       |
                                               |
     ]])
+    exec('call DoRel()')
+    screen:expect([[
+      2<<
Date: Thu, 27 Apr 2023 02:54:51 +0200
Subject: vim-patch:9.0.0758: "precedes" from 'listchars' overwritten by <<<

Problem:    "precedes" from 'listchars' overwritten by <<< for 'smoothscroll'.
Solution:   Keep the "precedes" character.

https://github.com/vim/vim/commit/13cdde39520220bb856cba16626327c706752b51

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 32 ++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 5e54470bd4..b5a571d8b5 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -294,6 +294,38 @@ describe('smoothscroll', function()
     ]])
   end)
 
+  -- oldtest: Test_smoothscroll_list()
+  it("works with list mode", function()
+    screen:try_resize(40, 8)
+    exec([[
+      set smoothscroll scrolloff=0
+      set list
+      call setline(1, [ 'one', 'very long text '->repeat(12), 'three', ])
+      exe "normal 2Gzt\"
+    ]])
+    screen:expect([[
+      <<
Date: Thu, 27 Apr 2023 03:15:46 +0200
Subject: vim-patch:9.0.0760: display test for 'listchars' "precedes" fails

Problem:    Display test for 'listchars' "precedes" fails.
Solution:   Correct the expected result.

https://github.com/vim/vim/commit/297164cb7972beff35e375ccac4fbad8196ccbd7

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/highlight_spec.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 01895003ae..89b503141b 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -704,7 +704,7 @@ describe("'listchars' highlight", function()
     feed_command('set listchars=eol:¬,precedes:< list')
     feed('90ia')
     screen:expect([[
-      {0:<<<}aaaaaaaaaaaaaaaaa|
+      {0:<}aaaaaaaaaaaaaaaaaaa|
       aaaaaaaaaaaaaaaaaaaa|
       aaaaaaaaaaaaaaaaaaaa|
       aaaaaaaaa^a{0:¬}         |
-- 
cgit 


From 88d13d2778a4fab3fdcc2bf4c1adf631b38ea3ce Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Thu, 27 Apr 2023 03:36:31 +0200
Subject: vim-patch:9.0.0807: with 'smoothscroll' typing "0" may not go to the
 first column

Problem:    With 'smoothscroll' typing "0" may not go to the first column.
Solution:   Recompute w_cline_height when needed.  Do not scroll up when it
            would move the cursor.

https://github.com/vim/vim/commit/d5337efece7c68e9b4ce864532ea49b02453b674

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index b5a571d8b5..42d8f31d3c 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -482,7 +482,14 @@ describe('smoothscroll', function()
     ]])
     -- 'scrolloff' set to 2, scrolling down, cursor moves screen line up
     feed('gj')
-    screen:expect_unchanged()
+    screen:expect([[
+      <<
Date: Thu, 27 Apr 2023 17:51:47 +0200
Subject: vim-patch:9.0.0893: 'smoothscroll' cursor calculations wrong when
 'number' is set

Problem:    'smoothscroll' cursor calculations wrong when 'number' is set.
Solution:   Correct the code that computes the width. (closes vim/vim#11492)

https://github.com/vim/vim/commit/01ee52bab6041450095c53f9469b1b266a7e3d4d

Co-authored-by: Yee Cheng Chin 
---
 test/functional/legacy/scroll_opt_spec.lua | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 42d8f31d3c..8f0286771a 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -279,8 +279,8 @@ describe('smoothscroll', function()
     ]])
     exec('call DoRel()')
     screen:expect([[
-      2<<
Date: Thu, 27 Apr 2023 18:20:34 +0200
Subject: vim-patch:9.0.0898: with 'smoothscroll' cursor is one screen line too
 far down

Problem:    With 'smoothscroll' cursor is one screen line too far down. (Ernie
            Rael)
Solution:   Add a test that currently has the wrong result so that a fix can
            be made. (issue vim/vim#11436)

https://github.com/vim/vim/commit/75ac25b4967cdcdfdf2d6c086a6e2308868c280a

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 8f0286771a..2f88221032 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -520,4 +520,34 @@ describe('smoothscroll', function()
     feed('0')
     screen:expect(s1)
   end)
+
+  -- oldtest: Test_smoothscroll_long_line_showbreak()
+  it("cursor is not one screen line too far down", function()
+    screen:try_resize(40, 6)
+    exec([[
+      " a line that spans four screen lines
+      call setline(1, 'with lots of text in one line '->repeat(6))
+      set smoothscroll scrolloff=0 showbreak=+++\ 
+    ]])
+    local s1 = [[
+      ^with lots of text in one line with lots |
+      +++ of text in one line with lots of tex|
+      +++ t in one line with lots of text in o|
+      +++ ne line with lots of text in one lin|
+      +++ e with lots of text in one line     |
+                                              |
+    ]]
+    screen:expect(s1)
+    feed('')
+    screen:expect([[
+      +++ of text in one line with lots of tex|
+      +++ ^t in one line with lots of text in o|
+      +++ ne line with lots of text in one lin|
+      +++ e with lots of text in one line     |
+      ~                                       |
+                                              |
+    ]])
+    feed('0')
+    screen:expect(s1)
+  end)
 end)
-- 
cgit 


From 3621604029119a8806da006eb0468cf65e23b980 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Thu, 27 Apr 2023 18:35:25 +0200
Subject: vim-patch:9.0.0900: cursor moves too far with 'smoothscroll'

Problem:    Cursor moves too far with 'smoothscroll'.
Solution:   Only move as far as really needed. (Yee Cheng Chin, closes vim/vim#11504)

https://github.com/vim/vim/commit/81ba26e9de24ca6b1c05b6ec03e53b21793f1a4b

Co-authored-by: Yee Cheng Chin 
---
 test/functional/legacy/scroll_opt_spec.lua | 32 ++++++++++++++++++++----------
 1 file changed, 21 insertions(+), 11 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 2f88221032..a05470418f 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -279,8 +279,8 @@ describe('smoothscroll', function()
     ]])
     exec('call DoRel()')
     screen:expect([[
-      2<<>> marker - no need to show whole line
+    feed('2gj3l2k')
+    screen:expect([[
+      <<<^h some text with some text           |
+      Line with some text with some text with |
+      some text with some text with some text |
+      with some text with some text           |
+      Line with some text with some text with |
+      some text with some text with some text |
+      with some text with some text           |
+                                              |
+    ]])
+    -- moving cursor up where the >>> marker is - whole top line shows
+    feed('2j02k')
     screen:expect([[
       ^Line with some text with some text with |
       some text with some text with some text |
@@ -524,11 +536,9 @@ describe('smoothscroll', function()
   -- oldtest: Test_smoothscroll_long_line_showbreak()
   it("cursor is not one screen line too far down", function()
     screen:try_resize(40, 6)
-    exec([[
-      " a line that spans four screen lines
-      call setline(1, 'with lots of text in one line '->repeat(6))
-      set smoothscroll scrolloff=0 showbreak=+++\ 
-    ]])
+    -- a line that spans four screen lines
+    exec("call setline(1, 'with lots of text in one line '->repeat(6))")
+    exec('set smoothscroll scrolloff=0 showbreak=+++\\ ')
     local s1 = [[
       ^with lots of text in one line with lots |
       +++ of text in one line with lots of tex|
@@ -540,8 +550,8 @@ describe('smoothscroll', function()
     screen:expect(s1)
     feed('')
     screen:expect([[
-      +++ of text in one line with lots of tex|
-      +++ ^t in one line with lots of text in o|
+      +++ ^of text in one line with lots of tex|
+      +++ t in one line with lots of text in o|
       +++ ne line with lots of text in one lin|
       +++ e with lots of text in one line     |
       ~                                       |
-- 
cgit 


From 46646a9bb81b72d5579beade64006d6f3dc64d19 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Thu, 27 Apr 2023 19:40:00 +0200
Subject: vim-patch:9.0.0908: with 'smoothscroll' cursor may end up in wrong
 position

Problem:    With 'smoothscroll' cursor may end up in wrong position.
Solution:   Correct the computation of screen lines. (Yee Cheng Chin,
            closes vim/vim#11502)

https://github.com/vim/vim/commit/361895d2a15b4b0bbbb4c009261eab5b3d69ebf1

Co-authored-by: Yee Cheng Chin 
---
 test/functional/legacy/scroll_opt_spec.lua | 41 +++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index a05470418f..6c8ca2cf97 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -410,7 +410,7 @@ describe('smoothscroll', function()
   it("adjusts the cursor position in a long line", function()
     screen:try_resize(40, 6)
     exec([[
-      call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(30))])
+      call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(30)) .. ' end', 'four'])
       set smoothscroll scrolloff=0
       normal 3G10|zt
     ]])
@@ -502,6 +502,45 @@ describe('smoothscroll', function()
       ith lots of text with lots of text with |
                                               |
     ]])
+    -- 'scrolloff' set to 0, move cursor down one line. Cursor should move properly,
+    -- and since this is a really long line, it will be put on top of the screen.
+    exec('set scrolloff=0')
+    feed('0j')
+    screen:expect([[
+      ^four                                    |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+      ~                                       |
+                                              |
+    ]])
+    -- Repeat the step and move the cursor down again.
+    -- This time, use a shorter long line that is barely long enough to span more
+    -- than one window. Note that the cursor is at the bottom this time because
+    -- Vim prefers to do so if we are scrolling a few lines only.
+    exec("call setline(1, ['one', 'two', 'Line' .. (' with lots of text'->repeat(10)) .. ' end', 'four'])")
+    feed('3Gztj')
+    screen:expect([[
+      <<j')
+    screen:expect([[
+      <<
Date: Fri, 28 Apr 2023 12:36:11 +0200
Subject: vim-patch:9.0.1000: with 'smoothscroll' skipcol may be reset
 unnecessarily

Problem:    With 'smoothscroll' skipcol may be reset unnecessarily.
Solution:   Check the line does actually fit in the window.

https://github.com/vim/vim/commit/b21b8e9ed081a6ef6b6745fe65d219b3ac046c3b

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 6c8ca2cf97..31d851f571 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -494,14 +494,7 @@ describe('smoothscroll', function()
     ]])
     -- 'scrolloff' set to 2, scrolling down, cursor moves screen line up
     feed('gj')
-    screen:expect([[
-      <<
Date: Fri, 28 Apr 2023 13:34:07 +0200
Subject: vim-patch:9.0.1121: cursor positioning and display problems with
 'smoothscroll'

Problem:    Cursor positioning and display problems with 'smoothscroll' and
            using "zt", "zb" or "zz".
Solution:   Adjust computations and conditions. (Yee Cheng Chin,
            closes vim/vim#11764)

https://github.com/vim/vim/commit/db4d88c2adfe8f8122341ac9d6cae27ef78451c8

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 31d851f571..e58b95ecc1 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -499,6 +499,34 @@ describe('smoothscroll', function()
     -- and since this is a really long line, it will be put on top of the screen.
     exec('set scrolloff=0')
     feed('0j')
+    screen:expect([[
+      <<
Date: Fri, 28 Apr 2023 16:22:42 +0200
Subject: vim-patch:9.0.1247: divide by zero with 'smoothscroll' set and a
 narrow window

Problem:    Divide by zero with 'smoothscroll' set and a narrow window.
Solution:   Bail out when the window is too narrow.

https://github.com/vim/vim/commit/870219c58c0804bdc55419b2e455c06ac715a835

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/scroll_opt_spec.lua | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index e58b95ecc1..f9dc9e81ca 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -620,4 +620,30 @@ describe('smoothscroll', function()
     feed('0')
     screen:expect(s1)
   end)
+
+  -- oldtest: Test_smoothscroll_zero_width()
+  it("does not divide by zero with a narrow window", function()
+    screen:try_resize(12, 2)
+    screen:set_default_attr_ids({
+      [1] = {foreground = Screen.colors.Brown},
+      [2] = {foreground = Screen.colors.Blue1, bold = true},
+    })
+    exec([[
+      call setline(1, ['a'->repeat(100)])
+      set wrap smoothscroll number laststatus=0
+      wincmd v
+      wincmd v
+      wincmd v
+      wincmd v
+    ]])
+    screen:expect([[
+      {1:  1^ }│{1: }│{1: }│{1: }│{1: }|
+                  |
+    ]])
+    feed('llllllllllo')
+    screen:expect([[
+      {2:<<<}{1: }aa^aaaaaa|
+                  |
+    ]])
+  end)
 end)
-- 
cgit 


From f78130b2d84a950ed7a13a5cbd946cba6c5c68f7 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Sat, 29 Apr 2023 23:02:29 +0200
Subject: test: 'smoothscroll' works with virt_lines above and below

---
 test/functional/legacy/scroll_opt_spec.lua | 73 ++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index f9dc9e81ca..253b20df5c 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -646,4 +646,77 @@ describe('smoothscroll', function()
                   |
     ]])
   end)
+
+  it("works with virt_lines above and below", function()
+    screen:try_resize(55, 7)
+    exec([=[
+      call setline(1, ['Line' .. (' with some text'->repeat(7))]->repeat(3))
+      set smoothscroll
+      let ns = nvim_create_namespace('')
+      call nvim_buf_set_extmark(0, ns, 0, 0, {'virt_lines':[[['virt_below1']]]})
+      call nvim_buf_set_extmark(0, ns, 1, 0, {'virt_lines':[[['virt_above1']]],'virt_lines_above':1})
+      call nvim_buf_set_extmark(0, ns, 1, 0, {'virt_lines':[[['virt_below2']]]})
+      call nvim_buf_set_extmark(0, ns, 2, 0, {'virt_lines':[[['virt_above2']]],'virt_lines_above':1})
+      norm ggL
+    ]=])
+    screen:expect([[
+      Line with some text with some text with some text with |
+      some text with some text with some text with some text |
+      virt_below1                                            |
+      virt_above1                                            |
+      ^Line with some text with some text with some text with |
+      some text with some text with some text with some text |
+                                                             |
+    ]])
+    feed('')
+    screen:expect([[
+      <<')
+    screen:expect([[
+      virt_below1                                            |
+      virt_above1                                            |
+      ^Line with some text with some text with some text with |
+      some text with some text with some text with some text |
+      virt_below2                                            |
+      virt_above2                                            |
+                                                             |
+    ]])
+    feed('')
+    screen:expect([[
+      virt_above1                                            |
+      ^Line with some text with some text with some text with |
+      some text with some text with some text with some text |
+      virt_below2                                            |
+      virt_above2                                            |
+      Line with some text with some text with some text wi@@@|
+                                                             |
+    ]])
+    feed('')
+    screen:expect([[
+      ^Line with some text with some text with some text with |
+      some text with some text with some text with some text |
+      virt_below2                                            |
+      virt_above2                                            |
+      Line with some text with some text with some text with |
+      some text with some text with some text with some text |
+                                                             |
+    ]])
+    feed('')
+    screen:expect([[
+      <<
Date: Sun, 30 Apr 2023 22:04:35 +0200
Subject: vim-patch:9.0.1502: no test for deleting the end of a long wrapped
 line

Problem:    No test for deleting the end of a long wrapped line.
Solution:   Add a test to check the right text is displayed. (Luuk van Baal,
            closes vim/vim#12318)

https://github.com/vim/vim/commit/5b10a140983c16140d69a214494c4b8af8b34763

Co-authored-by: Luuk van Baal 
---
 test/functional/legacy/display_spec.lua | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index f9b78f5dcd..4952a5c4fe 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -194,4 +194,51 @@ describe('display', function()
   it('display "lastline" works correctly with multibyte fillchar', function()
     run_test_display_lastline(true)
   end)
+
+  -- oldtest: Test_display_long_lastline
+  it('display "lastline" shows correct text when end of wrapped line is deleted', function()
+    local screen = Screen.new(35, 14)
+    screen:attach()
+    exec([[
+      set display=lastline scrolloff=5
+      call setline(1, [
+        \'aaaaa'->repeat(100),
+        \'bbbbb '->repeat(7) .. 'ccccc '->repeat(7) .. 'ddddd '->repeat(7)
+      \])
+    ]])
+    feed('482|')
+    screen:expect([[
+      <<
Date: Mon, 1 May 2023 14:42:30 +0200
Subject: test: 'smoothscroll' <<< marker shows with tabline, winbar and splits

---
 test/functional/legacy/scroll_opt_spec.lua | 55 ++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 253b20df5c..b00ff0bc7a 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -719,4 +719,59 @@ describe('smoothscroll', function()
                                                              |
     ]])
   end)
+
+  it('<<< marker shows with tabline, winbar and splits', function()
+    screen:try_resize(40, 12)
+    exec([[
+      call setline(1, ['Line' .. (' with some text'->repeat(7))]->repeat(7))
+      set smoothscroll scrolloff=0
+      norm sj
+    ]])
+    screen:expect([[
+      <<')
+    screen:expect([[
+       2+ [No Name]                           |
+      <<k')
+    screen:expect([[
+       2+ [No Name]                           |
+      winbar                                  |
+      <<
Date: Tue, 2 May 2023 23:55:14 +0800
Subject: fix(pum): fix missing rightmost column with 'rightleft' (#23445)

---
 test/functional/ui/popupmenu_spec.lua | 225 +++++++++++++++++++++++++++++++---
 1 file changed, 208 insertions(+), 17 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 6c26c8ea39..4c0ecd9c4e 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -5,6 +5,7 @@ local clear, feed = helpers.clear, helpers.feed
 local source = helpers.source
 local insert = helpers.insert
 local meths = helpers.meths
+local async_meths = helpers.async_meths
 local command = helpers.command
 local funcs = helpers.funcs
 local eq = helpers.eq
@@ -1978,6 +1979,54 @@ describe('builtin popupmenu', function()
           {2:-- }{5:match 1 of 4}                 |
         ]])
       end
+
+      feed('\n')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          [4:-----------]│[2:--------------------]|
+          {3:')
         screen:expect([[
                       ^ drow tfelthgir emos|
-          {1:  }{s:           drow}{1:              ~}|
-          {1:  }{n:         eciohc}{1:              ~}|
-          {1:  }{n:           txet}{1:              ~}|
-          {1:  }{n:          gniht}{1:              ~}|
+          {1:  }{s:           drow }{1:             ~}|
+          {1:  }{n:         eciohc }{1:             ~}|
+          {1:  }{n:           txet }{1:             ~}|
+          {1:  }{n:          gniht }{1:             ~}|
           {1:                               ~}|
           {1:                               ~}|
           {1:                               ~}|
@@ -2643,25 +2692,167 @@ describe('builtin popupmenu', function()
           {1:                   ~}|
           {1:                   ~}|
         ## grid 5
-           {n:           drow}|
-           {n:         eciohc}|
-           {n:           txet}|
-           {n:          gniht}|
+          {n:           drow }|
+          {n:         eciohc }|
+          {n:           txet }|
+          {n:          gniht }|
         ]], float_pos={
-          [5] = {{id = -1}, "NW", 4, 1, -11, false, 100};
+          [5] = {{id = -1}, "NW", 4, 1, -10, false, 100};
         }}
       else
         screen:expect([[
                tfelthgir emos│    ^  tfelthgir emos|
-          {1:          }{n:           drow}{1:              ~}|
-          {1:          }{n:         eciohc}{1:              ~}|
-          {1:          }{n:           txet}{1:              ~}|
-          {1:          }{n:          gniht}{1:              ~}|
+          {1:          }{n:           drow }{1:             ~}|
+          {1:          }{n:         eciohc }{1:             ~}|
+          {1:          }{n:           txet }{1:             ~}|
+          {1:          }{n:          gniht }{1:             ~}|
           {1:                  ~}│{1:                   ~}|
           {3:[No Name] [+]       }{4:[No Name] [+]       }|
           {2:-- INSERT --}                            |
         ]])
       end
+      feed('')
+      funcs.complete(1, {'word', 'choice', 'text', 'thing'})
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          {3:[No Name] [+]       }{4:[No Name] [+]       }|
+          [3:----------------------------------------]|
+        ## grid 2
+               tfelthgir emos|
+                             |
+          {1:                  ~}|
+          {1:                  ~}|
+          {1:                  ~}|
+          {1:                  ~}|
+        ## grid 3
+          {2:-- INSERT --}                            |
+        ## grid 4
+                tfelthgir emos|
+                             ^ |
+          {1:                   ~}|
+          {1:                   ~}|
+          {1:                   ~}|
+          {1:                   ~}|
+        ## grid 5
+          {n:           drow}|
+          {n:         eciohc}|
+          {n:           txet}|
+          {n:          gniht}|
+        ]], float_pos={
+          [5] = {{id = -1}, "NW", 4, 2, 5, false, 100};
+        }}
+      else
+        screen:expect([[
+               tfelthgir emos│      tfelthgir emos|
+                             │                   ^ |
+          {1:                  ~}│{1:     }{n:           drow}|
+          {1:                  ~}│{1:     }{n:         eciohc}|
+          {1:                  ~}│{1:     }{n:           txet}|
+          {1:                  ~}│{1:     }{n:          gniht}|
+          {3:[No Name] [+]       }{4:[No Name] [+]       }|
+          {2:-- INSERT --}                            |
+        ]])
+      end
+      feed('')
+      async_meths.call_function('input', {'', '', 'sign'})
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          {3:[No Name] [+]       }{4:[No Name] [+]       }|
+          [3:----------------------------------------]|
+        ## grid 2
+               tfelthgir emos|
+                             |
+          {1:                  ~}|
+          {1:                  ~}|
+          {1:                  ~}|
+          {1:                  ~}|
+        ## grid 3
+          ^                                        |
+        ## grid 4
+                tfelthgir emos|
+                              |
+          {1:                   ~}|
+          {1:                   ~}|
+          {1:                   ~}|
+          {1:                   ~}|
+        ]]}
+      else
+        screen:expect([[
+               tfelthgir emos│      tfelthgir emos|
+                             │                    |
+          {1:                  ~}│{1:                   ~}|
+          {1:                  ~}│{1:                   ~}|
+          {1:                  ~}│{1:                   ~}|
+          {1:                  ~}│{1:                   ~}|
+          {3:[No Name] [+]       }{4:[No Name] [+]       }|
+          ^                                        |
+        ]])
+      end
+      command('set wildoptions+=pum')
+      feed('')
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          [2:-------------------]│[4:--------------------]|
+          {3:[No Name] [+]       }{4:[No Name] [+]       }|
+          [3:----------------------------------------]|
+        ## grid 2
+               tfelthgir emos|
+                             |
+          {1:                  ~}|
+          {1:                  ~}|
+          {1:                  ~}|
+          {1:                  ~}|
+        ## grid 3
+          define^                                  |
+        ## grid 4
+                tfelthgir emos|
+                              |
+          {1:                   ~}|
+          {1:                   ~}|
+          {1:                   ~}|
+          {1:                   ~}|
+        ## grid 5
+          {s:define         }|
+          {n:jump           }|
+          {n:list           }|
+          {n:place          }|
+          {n:undefine       }|
+          {n:unplace        }|
+        ]], float_pos={
+          [5] = {{id = -1}, "SW", 1, 7, 0, false, 250};
+        }}
+      else
+        screen:expect([[
+               tfelthgir emos│      tfelthgir emos|
+          {s:define         }    │                    |
+          {n:jump           }{1:   ~}│{1:                   ~}|
+          {n:list           }{1:   ~}│{1:                   ~}|
+          {n:place          }{1:   ~}│{1:                   ~}|
+          {n:undefine       }{1:   ~}│{1:                   ~}|
+          {n:unplace        }{3:     }{4:[No Name] [+]       }|
+          define^                                  |
+        ]])
+      end
     end)
 
     if not multigrid then
-- 
cgit 


From 8bc973c6f59c6b90917dafc025303e69835167a3 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 3 May 2023 01:13:03 +0800
Subject: fix(pum): fix missing scrollbar with 'rightleft' (#23448)

---
 test/functional/ui/popupmenu_spec.lua | 79 +++++++++--------------------------
 1 file changed, 20 insertions(+), 59 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 4c0ecd9c4e..61b815dbf6 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -2658,10 +2658,11 @@ describe('builtin popupmenu', function()
     end
 
     it('with rightleft vsplits', function()
-      screen:try_resize(40, 8)
+      screen:try_resize(40, 6)
       command('set rightleft')
       command('rightbelow vsplit')
-      command("set completeopt+=noinsert,noselect")
+      command('set completeopt+=noinsert,noselect')
+      command('set pumheight=2')
       feed('isome rightleft ')
       funcs.complete(16, {'word', 'choice', 'text', 'thing'})
       if multigrid then
@@ -2671,8 +2672,6 @@ describe('builtin popupmenu', function()
           [2:-------------------]│[4:--------------------]|
           [2:-------------------]│[4:--------------------]|
           [2:-------------------]│[4:--------------------]|
-          [2:-------------------]│[4:--------------------]|
-          [2:-------------------]│[4:--------------------]|
           {3:[No Name] [+]       }{4:[No Name] [+]       }|
           [3:----------------------------------------]|
         ## grid 2
@@ -2680,8 +2679,6 @@ describe('builtin popupmenu', function()
           {1:                  ~}|
           {1:                  ~}|
           {1:                  ~}|
-          {1:                  ~}|
-          {1:                  ~}|
         ## grid 3
           {2:-- INSERT --}                            |
         ## grid 4
@@ -2689,23 +2686,17 @@ describe('builtin popupmenu', function()
           {1:                   ~}|
           {1:                   ~}|
           {1:                   ~}|
-          {1:                   ~}|
-          {1:                   ~}|
         ## grid 5
-          {n:           drow }|
-          {n:         eciohc }|
-          {n:           txet }|
-          {n:          gniht }|
+          {c: }{n:           drow }|
+          {s: }{n:         eciohc }|
         ]], float_pos={
-          [5] = {{id = -1}, "NW", 4, 1, -10, false, 100};
+          [5] = {{id = -1}, "NW", 4, 1, -11, false, 100};
         }}
       else
         screen:expect([[
                tfelthgir emos│    ^  tfelthgir emos|
-          {1:          }{n:           drow }{1:             ~}|
-          {1:          }{n:         eciohc }{1:             ~}|
-          {1:          }{n:           txet }{1:             ~}|
-          {1:          }{n:          gniht }{1:             ~}|
+          {1:         }{c: }{n:           drow }{1:             ~}|
+          {1:         }{s: }{n:         eciohc }{1:             ~}|
           {1:                  ~}│{1:                   ~}|
           {3:[No Name] [+]       }{4:[No Name] [+]       }|
           {2:-- INSERT --}                            |
@@ -2720,8 +2711,6 @@ describe('builtin popupmenu', function()
           [2:-------------------]│[4:--------------------]|
           [2:-------------------]│[4:--------------------]|
           [2:-------------------]│[4:--------------------]|
-          [2:-------------------]│[4:--------------------]|
-          [2:-------------------]│[4:--------------------]|
           {3:[No Name] [+]       }{4:[No Name] [+]       }|
           [3:----------------------------------------]|
         ## grid 2
@@ -2729,8 +2718,6 @@ describe('builtin popupmenu', function()
                              |
           {1:                  ~}|
           {1:                  ~}|
-          {1:                  ~}|
-          {1:                  ~}|
         ## grid 3
           {2:-- INSERT --}                            |
         ## grid 4
@@ -2738,24 +2725,18 @@ describe('builtin popupmenu', function()
                              ^ |
           {1:                   ~}|
           {1:                   ~}|
-          {1:                   ~}|
-          {1:                   ~}|
         ## grid 5
-          {n:           drow}|
-          {n:         eciohc}|
-          {n:           txet}|
-          {n:          gniht}|
+          {c: }{n:           drow}|
+          {s: }{n:         eciohc}|
         ]], float_pos={
-          [5] = {{id = -1}, "NW", 4, 2, 5, false, 100};
+          [5] = {{id = -1}, "NW", 4, 2, 4, false, 100};
         }}
       else
         screen:expect([[
                tfelthgir emos│      tfelthgir emos|
                              │                   ^ |
-          {1:                  ~}│{1:     }{n:           drow}|
-          {1:                  ~}│{1:     }{n:         eciohc}|
-          {1:                  ~}│{1:     }{n:           txet}|
-          {1:                  ~}│{1:     }{n:          gniht}|
+          {1:                  ~}│{1:    }{c: }{n:           drow}|
+          {1:                  ~}│{1:    }{s: }{n:         eciohc}|
           {3:[No Name] [+]       }{4:[No Name] [+]       }|
           {2:-- INSERT --}                            |
         ]])
@@ -2769,8 +2750,6 @@ describe('builtin popupmenu', function()
           [2:-------------------]│[4:--------------------]|
           [2:-------------------]│[4:--------------------]|
           [2:-------------------]│[4:--------------------]|
-          [2:-------------------]│[4:--------------------]|
-          [2:-------------------]│[4:--------------------]|
           {3:[No Name] [+]       }{4:[No Name] [+]       }|
           [3:----------------------------------------]|
         ## grid 2
@@ -2778,8 +2757,6 @@ describe('builtin popupmenu', function()
                              |
           {1:                  ~}|
           {1:                  ~}|
-          {1:                  ~}|
-          {1:                  ~}|
         ## grid 3
           ^                                        |
         ## grid 4
@@ -2787,8 +2764,6 @@ describe('builtin popupmenu', function()
                               |
           {1:                   ~}|
           {1:                   ~}|
-          {1:                   ~}|
-          {1:                   ~}|
         ]]}
       else
         screen:expect([[
@@ -2796,8 +2771,6 @@ describe('builtin popupmenu', function()
                              │                    |
           {1:                  ~}│{1:                   ~}|
           {1:                  ~}│{1:                   ~}|
-          {1:                  ~}│{1:                   ~}|
-          {1:                  ~}│{1:                   ~}|
           {3:[No Name] [+]       }{4:[No Name] [+]       }|
           ^                                        |
         ]])
@@ -2811,8 +2784,6 @@ describe('builtin popupmenu', function()
           [2:-------------------]│[4:--------------------]|
           [2:-------------------]│[4:--------------------]|
           [2:-------------------]│[4:--------------------]|
-          [2:-------------------]│[4:--------------------]|
-          [2:-------------------]│[4:--------------------]|
           {3:[No Name] [+]       }{4:[No Name] [+]       }|
           [3:----------------------------------------]|
         ## grid 2
@@ -2820,8 +2791,6 @@ describe('builtin popupmenu', function()
                              |
           {1:                  ~}|
           {1:                  ~}|
-          {1:                  ~}|
-          {1:                  ~}|
         ## grid 3
           define^                                  |
         ## grid 4
@@ -2829,27 +2798,19 @@ describe('builtin popupmenu', function()
                               |
           {1:                   ~}|
           {1:                   ~}|
-          {1:                   ~}|
-          {1:                   ~}|
         ## grid 5
-          {s:define         }|
-          {n:jump           }|
-          {n:list           }|
-          {n:place          }|
-          {n:undefine       }|
-          {n:unplace        }|
+          {s:define         }{c: }|
+          {n:jump           }{s: }|
         ]], float_pos={
-          [5] = {{id = -1}, "SW", 1, 7, 0, false, 250};
+          [5] = {{id = -1}, "SW", 1, 5, 0, false, 250};
         }}
       else
         screen:expect([[
                tfelthgir emos│      tfelthgir emos|
-          {s:define         }    │                    |
-          {n:jump           }{1:   ~}│{1:                   ~}|
-          {n:list           }{1:   ~}│{1:                   ~}|
-          {n:place          }{1:   ~}│{1:                   ~}|
-          {n:undefine       }{1:   ~}│{1:                   ~}|
-          {n:unplace        }{3:     }{4:[No Name] [+]       }|
+                             │                    |
+          {1:                  ~}│{1:                   ~}|
+          {s:define         }{c: }{1:  ~}│{1:                   ~}|
+          {n:jump           }{s: }{3:    }{4:[No Name] [+]       }|
           define^                                  |
         ]])
       end
-- 
cgit 


From 540941ef8320e2005fe65e6776fc1068f18543c6 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 3 May 2023 06:17:53 +0800
Subject: fix(pum): don't position too far with resized parent grid (#23442)

---
 test/functional/ui/multigrid_spec.lua | 378 +++++++++++++++++++++++++++++++++-
 1 file changed, 376 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 558b9e3e16..4c04bcb54e 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -40,6 +40,7 @@ describe('ext_multigrid', function()
       [21] = {background = Screen.colors.LightMagenta},
       [22] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue},
       [23] = {background = Screen.colors.Grey90},
+      [24] = {background = Screen.colors.Grey},
     })
   end)
 
@@ -1292,6 +1293,154 @@ describe('ext_multigrid', function()
         [4] = {{id = 1001}, "SE", 2, 16, 58, true, 50};
       }}
     end)
+
+    it('completion popup position', function()
+      insert(('\n'):rep(14) .. ('foo bar '):rep(7))
+      feed('A')
+      screen:expect{grid=[[
+      ## grid 1
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        {11:[No Name] [+]                                        }|
+        [3:-----------------------------------------------------]|
+      ## grid 2
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+        foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo^ |
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+        {1:~                                                           }|
+      ## grid 3
+        {7:-- Keyword Local completion (^N^P) }{15:match 1 of 2}      |
+      ## grid 4
+        {24: foo}|
+        {21: bar}|
+      ]], float_pos={
+        [4] = {{id = -1}, "NW", 2, 15, 55, false, 100};
+      }}
+      feed('')
+
+      command('setlocal rightleft')
+      feed('o')
+      screen:expect{grid=[[
+      ## grid 1
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        {11:[No Name] [+]                                        }|
+        [3:-----------------------------------------------------]|
+      ## grid 2
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+             rab oof rab oof rab oof rab oof rab oof rab oof rab oof|
+                                                                ^ oof|
+        {1:                                                           ~}|
+        {1:                                                           ~}|
+        {1:                                                           ~}|
+        {1:                                                           ~}|
+      ## grid 3
+        {7:-- Keyword Local completion (^N^P) }{15:match 1 of 2}      |
+      ## grid 4
+        {24:            oof}|
+        {21:            rab}|
+      ]], float_pos={
+        [4] = {{id = -1}, "NW", 2, 16, 45, false, 100};
+      }}
+      feed('')
+
+      command('set wildoptions+=pum')
+      feed(':sign un')
+      screen:expect{grid=[[
+      ## grid 1
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        [2:-----------------------------------------------------]|
+        {11:[No Name] [+]                                        }|
+        [3:-----------------------------------------------------]|
+      ## grid 2
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+                                                                    |
+             rab oof rab oof rab oof rab oof rab oof rab oof rab oof|
+                                                                    |
+        {1:                                                           ~}|
+        {1:                                                           ~}|
+        {1:                                                           ~}|
+        {1:                                                           ~}|
+      ## grid 3
+        :sign undefine^                                       |
+      ## grid 4
+        {24: undefine       }|
+        {21: unplace        }|
+      ]], float_pos={
+        [4] = {{id = -1}, "SW", 1, 13, 5, false, 250};
+      }}
+    end)
   end)
 
   it('multiline messages scroll over windows', function()
@@ -2446,8 +2595,48 @@ describe('ext_multigrid', function()
     ]]}
     meths.input_mouse('right', 'press', '', 4, 0, 64)
     meths.input_mouse('right', 'release', '', 4, 0, 64)
-    -- FIXME: popup menu position is strange
-    -- screen:expect{}
+    screen:expect{grid=[[
+    ## grid 1
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+      {7:-- VISUAL --}                                         |
+    ## grid 4
+      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do {20:eiusm}^o          |
+      {1:~                                                                               }|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ## grid 6
+      {21: Copy }|
+    ]], float_pos={
+      [6] = {{id = -1}, "NW", 4, 1, 63, false, 250};
+    }}
     feed('')
     screen:expect{grid=[[
     ## grid 1
@@ -2670,6 +2859,191 @@ describe('ext_multigrid', function()
       {1:~                             }|
     ]]}
     eq('eiusmo', funcs.getreg('"'))
+
+    screen:try_resize_grid(4, 7, 11)
+    screen:expect{grid=[[
+    ## grid 1
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+                                                           |
+    ## grid 4
+      ^Lorem i|
+      psum do|
+      lor sit|
+       amet, |
+      consect|
+      etur ad|
+      ipiscin|
+      g elit,|
+       sed do|
+       eiusmo|
+      {1:~      }|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ]]}
+
+    funcs.setreg('"', '')
+    meths.input_mouse('left', 'press', '2', 4, 9, 1)
+    screen:expect{grid=[[
+    ## grid 1
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+      {7:-- VISUAL --}                                         |
+    ## grid 4
+      Lorem i|
+      psum do|
+      lor sit|
+       amet, |
+      consect|
+      etur ad|
+      ipiscin|
+      g elit,|
+       sed do|
+       {20:eiusm}^o|
+      {1:~      }|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ]]}
+    meths.input_mouse('right', 'press', '', 4, 9, 1)
+    meths.input_mouse('right', 'release', '', 4, 9, 1)
+    screen:expect{grid=[[
+    ## grid 1
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+      {7:-- VISUAL --}                                         |
+    ## grid 4
+      Lorem i|
+      psum do|
+      lor sit|
+       amet, |
+      consect|
+      etur ad|
+      ipiscin|
+      g elit,|
+       sed do|
+       {20:eiusm}^o|
+      {1:~      }|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ## grid 6
+      {21: Copy }|
+    ]], float_pos={
+      [6] = {{id = -1}, "NW", 4, 10, 0, false, 250};
+    }}
+    feed('')
+    screen:expect{grid=[[
+    ## grid 1
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      [5:------------------------------]│[2:----------------------]|
+      {12:[No Name] [+]                  [No Name] [+]         }|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      [4:-----------------------------------------------------]|
+      {11:[No Name] [+]                                        }|
+      [3:-----------------------------------------------------]|
+    ## grid 2
+      some text             |
+      to be clicked         |
+      {1:~                     }|
+      {1:~                     }|
+      {1:~                     }|
+    ## grid 3
+                                                           |
+    ## grid 4
+      Lorem i|
+      psum do|
+      lor sit|
+       amet, |
+      consect|
+      etur ad|
+      ipiscin|
+      g elit,|
+       sed do|
+       ^eiusmo|
+      {1:~      }|
+    ## grid 5
+      some text                     |
+      to be clicked                 |
+      {1:~                             }|
+      {1:~                             }|
+      {1:~                             }|
+    ]]}
+    eq('eiusmo', funcs.getreg('"'))
   end)
 
   it('supports mouse drag with mouse=a', function()
-- 
cgit 


From 62ecb05957f43b140e7dd874e1f84e3a6fa99838 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 3 May 2023 07:21:09 +0800
Subject: vim-patch:9.0.1506: line number not displayed when using
 'smoothscroll' (#23453)

Problem:    Line number not displayed when using 'smoothscroll'.
Solution:   Adjust condition for showing the line number. (closes vim/vim#12333)

https://github.com/vim/vim/commit/88bb3e0a48f160134bdea98cd2b8bd3af86f9d6f
---
 test/functional/legacy/display_spec.lua    |  2 +-
 test/functional/legacy/scroll_opt_spec.lua | 48 ++++++++++++++++++++++++++++++
 test/functional/ui/diff_spec.lua           |  2 ++
 3 files changed, 51 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index 4952a5c4fe..f1cd8d1aac 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -195,7 +195,7 @@ describe('display', function()
     run_test_display_lastline(true)
   end)
 
-  -- oldtest: Test_display_long_lastline
+  -- oldtest: Test_display_long_lastline()
   it('display "lastline" shows correct text when end of wrapped line is deleted', function()
     local screen = Screen.new(35, 14)
     screen:attach()
diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index b00ff0bc7a..8af23d2c26 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -179,6 +179,7 @@ describe('smoothscroll', function()
     exec([[
       call setline(1, [ 'one ' .. 'word '->repeat(20), 'two ' .. 'long word '->repeat(7), 'line', 'line', 'line', ])
       set smoothscroll scrolloff=5
+      set splitkeep=topline
       set number cpo+=n
       :3
       func g:DoRel()
@@ -277,6 +278,53 @@ describe('smoothscroll', function()
       ~                                       |
                                               |
     ]])
+    exec('botright split')
+    feed('gg')
+    screen:expect([[
+        1 one word word word word word word wo|
+          rd word word word word word word wor|
+          d word word word word word word     |
+        2 two long word long word long word@@@|
+      [No Name] [+]                           |
+        1 ^one word word word word word word wo|
+          rd word word word word word word wor|
+          d word word word word word word     |
+        2 two long word long word long word lo|
+          ng word long word long word long @@@|
+      [No Name] [+]                           |
+                                              |
+    ]])
+    feed('')
+    screen:expect([[
+        1 one word word word word word word wo|
+          rd word word word word word word wor|
+          d word word word word word word     |
+        2 two long word long word long word@@@|
+      [No Name] [+]                           |
+      <<< rd word word word word word word wor|
+          d word word word word word word^     |
+        2 two long word long word long word lo|
+          ng word long word long word long wor|
+          d                                   |
+      [No Name] [+]                           |
+                                              |
+    ]])
+    feed('')
+    screen:expect([[
+        1 one word word word word word word wo|
+          rd word word word word word word wor|
+          d word word word word word word     |
+        2 two long word long word long word@@@|
+      [No Name] [+]                           |
+      <<< d word word word word word word^     |
+        2 two long word long word long word lo|
+          ng word long word long word long wor|
+          d                                   |
+        3 line                                |
+      [No Name] [+]                           |
+                                              |
+    ]])
+    exec('close')
     exec('call DoRel()')
     screen:expect([[
       2<<<^ong text very long text very long te|
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index dbdf3823ec..0f551e3044 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -1325,6 +1325,7 @@ it('win_update redraws lines properly', function()
   ]]}
 end)
 
+-- oldtest: Test_diff_rnu()
 it('diff updates line numbers below filler lines', function()
   clear()
   local screen = Screen.new(40, 14)
@@ -1401,6 +1402,7 @@ it('diff updates line numbers below filler lines', function()
   ]])
 end)
 
+-- oldtest: Test_diff_with_scroll_and_change()
 it('Align the filler lines when changing text in diff mode', function()
   clear()
   local screen = Screen.new(40, 20)
-- 
cgit 


From 1975062d3cd9775a6bdecbf471aa5f8b281692b1 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 3 May 2023 07:54:17 +0800
Subject: vim-patch:9.0.0662: concealed characters do not work correctly
 (#23454)

Problem:    Concealed characters do not work correctly.
Solution:   Subtract boguscols instead of adding them. (closes vim/vim#11273)

https://github.com/vim/vim/commit/75008661821eee6989476908feaf64a9dea03e05

Code change is N/A as Nvim has a draw_col variable instead.

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/conceal_spec.lua | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/conceal_spec.lua b/test/functional/legacy/conceal_spec.lua
index 429cf9dc03..6aaa93f886 100644
--- a/test/functional/legacy/conceal_spec.lua
+++ b/test/functional/legacy/conceal_spec.lua
@@ -474,6 +474,39 @@ describe('Conceal', function()
     ]])
   end)
 
+  -- oldtest: Test_conceal_linebreak()
+  it('with linebreak', function()
+    local screen = Screen.new(75, 8)
+    screen:set_default_attr_ids({
+      [0] = {bold = true, foreground = Screen.colors.Blue},  -- NonText
+    })
+    screen:attach()
+    exec([[
+      let &wrap = v:true
+      let &conceallevel = 2
+      let &concealcursor = 'nc'
+      let &linebreak = v:true
+      let &showbreak = '+ '
+      let line = 'a`a`a`a`'
+          \ .. 'a'->repeat(&columns - 15)
+          \ .. ' b`b`'
+          \ .. 'b'->repeat(&columns - 10)
+          \ .. ' cccccc'
+      eval ['x'->repeat(&columns), '', line]->setline(1)
+      syntax region CodeSpan matchgroup=Delimiter start=/\z(`\+\)/ end=/\z1/ concealends
+    ]])
+    screen:expect([[
+      ^xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
+                                                                                 |
+      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa           |
+      {0:+ }bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb      |
+      {0:+ }cccccc                                                                   |
+      {0:~                                                                          }|
+      {0:~                                                                          }|
+                                                                                 |
+    ]])
+  end)
+
   -- Tests for correct display (cursor column position) with +conceal and tabulators.
   -- oldtest: Test_conceal_cursor_pos()
   it('cursor and column position with conceal and tabulators', function()
-- 
cgit 


From dc394b9641f92a5014147da58f5e14fd1681ec0f Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 3 May 2023 10:29:19 +0800
Subject: fix(mouse): fix popup menu position check with winbar (#23456)

---
 test/functional/ui/mouse_spec.lua     | 11 ++++++
 test/functional/ui/popupmenu_spec.lua | 73 +++++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index d9b9cf9f1b..2c0a00c74f 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1861,5 +1861,16 @@ describe('ui/mouse/input', function()
     feed('')
     eq({1, 9}, meths.win_get_cursor(0))
     eq('ran away', funcs.getreg('"'))
+
+    -- Test for right click inside visual selection at bottom of window with winbar
+    command('setlocal winbar=WINBAR')
+    feed('2yyP')
+    funcs.setreg('"', '')
+    feed('G$vbb')
+    meths.input_mouse('right', 'press', '', 0, 4, 61)
+    meths.input_mouse('right', 'release', '', 0, 4, 61)
+    feed('')
+    eq({4, 20}, meths.win_get_cursor(0))
+    eq('the moon', funcs.getreg('"'))
   end)
 end)
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 61b815dbf6..76038472bd 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -4509,6 +4509,79 @@ describe('builtin popupmenu', function()
         ]])
       end
       eq('foo', meths.get_var('menustr'))
+
+      command('setlocal winbar=WINBAR')
+      if multigrid then
+        meths.input_mouse('right', 'press', '', 6, 1, 14)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {3:[No Name] [+]                   }|
+          [5:---------------]│[6:----------------]|
+          [5:---------------]│[6:----------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          popup menu test                 |
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'foo'          |
+        ## grid 4
+          {n: foo}|
+          {n: bar}|
+          {n: baz}|
+        ## grid 5
+          popup menu test|
+          {1:~              }|
+        ## grid 6
+          {2:WINBAR          }|
+          ^popup menu test |
+        ]], float_pos={[4] = {{id = -1}, "SW", 6, 1, 12, false, 250}}})
+      else
+        feed('<30,4>')
+        screen:expect([[
+          popup menu test                 |
+          {1:~                           }{n: foo}|
+          {3:[No Name] [+]               }{n: bar}|
+          popup menu test│{2:WINBAR      }{n: baz}|
+          {1:~              }│^popup menu test |
+          :let g:menustr = 'foo'          |
+        ]])
+      end
+      if multigrid then
+        meths.input_mouse('left', 'press', '', 4, 1, 2)
+        screen:expect({grid=[[
+        ## grid 1
+          [2:--------------------------------]|
+          [2:--------------------------------]|
+          {3:[No Name] [+]                   }|
+          [5:---------------]│[6:----------------]|
+          [5:---------------]│[6:----------------]|
+          [3:--------------------------------]|
+        ## grid 2
+          popup menu test                 |
+          {1:~                               }|
+        ## grid 3
+          :let g:menustr = 'bar'          |
+        ## grid 5
+          popup menu test|
+          {1:~              }|
+        ## grid 6
+          {2:WINBAR          }|
+          ^popup menu test |
+        ]]})
+      else
+        feed('<31,2>')
+        screen:expect([[
+          popup menu test                 |
+          {1:~                               }|
+          {3:[No Name] [+]                   }|
+          popup menu test│{2:WINBAR          }|
+          {1:~              }│^popup menu test |
+          :let g:menustr = 'bar'          |
+        ]])
+      end
+      eq('bar', meths.get_var('menustr'))
     end)
 
     if not multigrid then
-- 
cgit 


From 197827321a39168dbaa143c9f7b4f5db668f893c Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Mon, 1 May 2023 20:08:25 +0200
Subject: fix(tui): grid_clear properly clears the screen

Problem:    When setting a shell size smaller than the containing
            terminal window through `:winsize` or `:set lines/columns`
            the screen is not properly cleared.
Solution:   Clear the tui dimensions rather than the grid dimensions.
---
 test/functional/terminal/api_spec.lua |  8 ++++----
 test/functional/terminal/tui_spec.lua | 13 +++++++++++++
 2 files changed, 17 insertions(+), 4 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/terminal/api_spec.lua b/test/functional/terminal/api_spec.lua
index 724791343d..93641fc576 100644
--- a/test/functional/terminal/api_spec.lua
+++ b/test/functional/terminal/api_spec.lua
@@ -66,10 +66,10 @@ describe('api', function()
 
     screen:expect([[
       [tui] insert-mode                                 |
-      [socket 1] this is more t{4:                         }|
-      han 25 columns           {4:                         }|
-      [socket 2] input{1: }        {4:                         }|
-      {4:~                                                 }|
+      [socket 1] this is more t                         |
+      han 25 columns                                    |
+      [socket 2] input{1: }                                 |
+      {4:~                        }                         |
       {3:-- INSERT --}                                      |
       {3:-- TERMINAL --}                                    |
     ]])
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 069fbad803..5fd3467949 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -2422,6 +2422,19 @@ describe("TUI as a client", function()
       {3:-- TERMINAL --}                                    |
     ]]}
 
+    -- grid smaller than containing terminal window is cleared properly
+    feed_data(":call setline(1,['a'->repeat(&columns)]->repeat(&lines))\n")
+    feed_data("0:set lines=2\n")
+    screen_server:expect{grid=[[
+      {1:a}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+      {5:[No Name] [+]                                     }|
+                                                        |
+                                                        |
+                                                        |
+                                                        |
+      {3:-- TERMINAL --}                                    |
+    ]]}
+
     feed_data(":q!\n")
 
     server_super:close()
-- 
cgit 


From 75119fcc86e055895af824f7fdbba2f42c1cbbe8 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Fri, 5 May 2023 07:02:43 +0800
Subject: vim-patch:8.2.3135: Vim9: builtin function arguments not checked at
 compile time

Problem:    Vim9: builtin function arguments not checked at compile time.
Solution:   Add more type checks. (Yegappan Lakshmanan, closes vim/vim#8539)

https://github.com/vim/vim/commit/5b73992d8f82be7ac4b6f46c17f53ffb9640e5fa

Co-authored-by: Yegappan Lakshmanan 
---
 test/functional/editor/mode_insert_spec.lua  |  2 +-
 test/functional/legacy/edit_spec.lua         |  2 +-
 test/functional/legacy/eval_spec.lua         |  6 +++---
 test/functional/options/defaults_spec.lua    |  4 ++--
 test/functional/vimscript/execute_spec.lua   | 10 +++++-----
 test/functional/vimscript/input_spec.lua     | 30 ++++++++++++++--------------
 test/functional/vimscript/writefile_spec.lua |  6 +++---
 7 files changed, 30 insertions(+), 30 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua
index 6f16b4e685..12f450520a 100644
--- a/test/functional/editor/mode_insert_spec.lua
+++ b/test/functional/editor/mode_insert_spec.lua
@@ -86,7 +86,7 @@ describe('insert-mode', function()
         {0:~                                                           }|
         {4:                                                            }|
         ={2:{}}                                                         |
-        {5:E731: using Dictionary as a String}                          |
+        {5:E731: Using a Dictionary as a String}                        |
         {6:Press ENTER or type command to continue}^                     |
       ]])
       feed('')
diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua
index a0d8ca63a2..186bf395cc 100644
--- a/test/functional/legacy/edit_spec.lua
+++ b/test/functional/legacy/edit_spec.lua
@@ -95,7 +95,7 @@ describe('edit', function()
       {0:~                                                           }|
       {4:                                                            }|
       ={2:{}}                                                         |
-      {5:E731: using Dictionary as a String}                          |
+      {5:E731: Using a Dictionary as a String}                        |
       {6:Press ENTER or type command to continue}^                     |
     ]])
 
diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua
index b5e45a86c1..fc1343bb89 100644
--- a/test/functional/legacy/eval_spec.lua
+++ b/test/functional/legacy/eval_spec.lua
@@ -613,15 +613,15 @@ describe('eval', function()
       Executing call setreg(1, 2, 3, 4)
       Vim(call):E118: Too many arguments for function: setreg
       Executing call setreg([], 2)
-      Vim(call):E730: using List as a String
+      Vim(call):E730: Using a List as a String
       Executing call setreg(1, 2, [])
-      Vim(call):E730: using List as a String
+      Vim(call):E730: Using a List as a String
       Executing call setreg("/", ["1", "2"])
       Vim(call):E883: search pattern and expression register may not contain two or more lines
       Executing call setreg("=", ["1", "2"])
       Vim(call):E883: search pattern and expression register may not contain two or more lines
       Executing call setreg(1, ["", "", [], ""])
-      Vim(call):E730: using List as a String]])
+      Vim(call):E730: Using a List as a String]])
   end)
 
   it('function name not starting with a capital', function()
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index 4242b6e493..fcf313785a 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -892,8 +892,8 @@ describe('stdpath()', function()
     end)
 
     it('on non-strings', function()
-      eq('Vim(call):E731: using Dictionary as a String', exc_exec('call stdpath({"eris": 23})'))
-      eq('Vim(call):E730: using List as a String', exc_exec('call stdpath([23])'))
+      eq('Vim(call):E731: Using a Dictionary as a String', exc_exec('call stdpath({"eris": 23})'))
+      eq('Vim(call):E730: Using a List as a String', exc_exec('call stdpath([23])'))
     end)
   end)
 end)
diff --git a/test/functional/vimscript/execute_spec.lua b/test/functional/vimscript/execute_spec.lua
index 5fe3d787cb..b9893a5150 100644
--- a/test/functional/vimscript/execute_spec.lua
+++ b/test/functional/vimscript/execute_spec.lua
@@ -95,15 +95,15 @@ describe('execute()', function()
     ret = exc_exec('call execute(0.0)')
     eq('Vim(call):E806: using Float as a String', ret)
     ret = exc_exec('call execute(v:_null_dict)')
-    eq('Vim(call):E731: using Dictionary as a String', ret)
+    eq('Vim(call):E731: Using a Dictionary as a String', ret)
     ret = exc_exec('call execute(function("tr"))')
-    eq('Vim(call):E729: using Funcref as a String', ret)
+    eq('Vim(call):E729: Using a Funcref as a String', ret)
     ret = exc_exec('call execute(["echo 42", 0.0, "echo 44"])')
     eq('Vim:E806: using Float as a String', ret)
     ret = exc_exec('call execute(["echo 42", v:_null_dict, "echo 44"])')
-    eq('Vim:E731: using Dictionary as a String', ret)
+    eq('Vim:E731: Using a Dictionary as a String', ret)
     ret = exc_exec('call execute(["echo 42", function("tr"), "echo 44"])')
-    eq('Vim:E729: using Funcref as a String', ret)
+    eq('Vim:E729: Using a Funcref as a String', ret)
   end)
 
   it('captures output with highlights', function()
@@ -325,7 +325,7 @@ describe('execute()', function()
       eq('Vim(call):E806: using Float as a String', ret)
 
       ret = exc_exec('call execute(v:_null_dict, "silent")')
-      eq('Vim(call):E731: using Dictionary as a String', ret)
+      eq('Vim(call):E731: Using a Dictionary as a String', ret)
 
       ret = exc_exec('call execute("echo add(1, 1)", "")')
       eq('Vim(echo):E897: List or Blob required', ret)
diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua
index f50b39c2c5..d1643a799a 100644
--- a/test/functional/vimscript/input_spec.lua
+++ b/test/functional/vimscript/input_spec.lua
@@ -222,17 +222,17 @@ describe('input()', function()
     eq('DEF2', meths.get_var('var'))
   end)
   it('errors out on invalid inputs', function()
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call input([])'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call input("", [])'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call input("", "", [])'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call input({"prompt": []})'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call input({"default": []})'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call input({"completion": []})'))
     eq('Vim(call):E5050: {opts} must be the only argument',
        exc_exec('call input({}, "default")'))
@@ -418,17 +418,17 @@ describe('inputdialog()', function()
     eq('DEF2', meths.get_var('var'))
   end)
   it('errors out on invalid inputs', function()
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call inputdialog([])'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call inputdialog("", [])'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call inputdialog("", "", [])'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call inputdialog({"prompt": []})'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call inputdialog({"default": []})'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        exc_exec('call inputdialog({"completion": []})'))
     eq('Vim(call):E5050: {opts} must be the only argument',
        exc_exec('call inputdialog({}, "default")'))
@@ -512,13 +512,13 @@ describe('confirm()', function()
       eq(1, meths.get_var('a'))
     end
 
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        pcall_err(command, 'call confirm([])'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        pcall_err(command, 'call confirm("Are you sure?", [])'))
     eq('Vim(call):E745: Using a List as a Number',
        pcall_err(command, 'call confirm("Are you sure?", "&Yes\n&No\n", [])'))
-    eq('Vim(call):E730: using List as a String',
+    eq('Vim(call):E730: Using a List as a String',
        pcall_err(command, 'call confirm("Are you sure?", "&Yes\n&No\n", 0, [])'))
   end)
 
diff --git a/test/functional/vimscript/writefile_spec.lua b/test/functional/vimscript/writefile_spec.lua
index c816efd37b..3cd1052968 100644
--- a/test/functional/vimscript/writefile_spec.lua
+++ b/test/functional/vimscript/writefile_spec.lua
@@ -147,11 +147,11 @@ describe('writefile()', function()
     for _, args in ipairs({'[], %s, "b"', '[], "' .. fname .. '", %s'}) do
       eq('Vim(call):E806: using Float as a String',
          pcall_err(command, ('call writefile(%s)'):format(args:format('0.0'))))
-      eq('Vim(call):E730: using List as a String',
+      eq('Vim(call):E730: Using a List as a String',
          pcall_err(command, ('call writefile(%s)'):format(args:format('[]'))))
-      eq('Vim(call):E731: using Dictionary as a String',
+      eq('Vim(call):E731: Using a Dictionary as a String',
          pcall_err(command, ('call writefile(%s)'):format(args:format('{}'))))
-      eq('Vim(call):E729: using Funcref as a String',
+      eq('Vim(call):E729: Using a Funcref as a String',
          pcall_err(command, ('call writefile(%s)'):format(args:format('function("tr")'))))
     end
     eq('Vim(call):E5060: Unknown flag: «»',
-- 
cgit 


From b8d5586d5b0d1e2d25533ee398d16bb2e8412820 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Fri, 5 May 2023 08:18:36 +0800
Subject: refactor: using a different error number for 'mousescroll'

Because E548 is linked to 'guicursor' in help.
---
 test/functional/options/mousescroll_spec.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/options/mousescroll_spec.lua b/test/functional/options/mousescroll_spec.lua
index 5bff45a836..38a9692792 100644
--- a/test/functional/options/mousescroll_spec.lua
+++ b/test/functional/options/mousescroll_spec.lua
@@ -20,7 +20,7 @@ end
 
 describe("'mousescroll'", function()
   local invalid_arg = 'Vim(set):E474: Invalid argument: mousescroll='
-  local digit_expected = 'Vim(set):E548: digit expected: mousescroll='
+  local digit_expected = 'Vim(set):E5080: Digit expected: mousescroll='
 
   local function should_fail(val, errorstr)
     eq(errorstr..val, exc_exec('set mousescroll='..val))
-- 
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/ex_cmds/highlight_spec.lua       | 2 +-
 test/functional/legacy/eval_spec.lua             | 4 ++--
 test/functional/legacy/glob2regpat_spec.lua      | 2 +-
 test/functional/lua/commands_spec.lua            | 2 +-
 test/functional/ui/cmdline_highlight_spec.lua    | 4 ++--
 test/functional/ui/mouse_spec.lua                | 2 +-
 test/functional/vimscript/execute_spec.lua       | 6 +++---
 test/functional/vimscript/map_functions_spec.lua | 4 ++--
 test/functional/vimscript/null_spec.lua          | 4 ++--
 test/functional/vimscript/writefile_spec.lua     | 2 +-
 10 files changed, 16 insertions(+), 16 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ex_cmds/highlight_spec.lua b/test/functional/ex_cmds/highlight_spec.lua
index 45764e6719..958dd99226 100644
--- a/test/functional/ex_cmds/highlight_spec.lua
+++ b/test/functional/ex_cmds/highlight_spec.lua
@@ -24,7 +24,7 @@ describe(':highlight', function()
   end)
 
   it('invalid group name', function()
-    eq('Vim(highlight):E411: highlight group not found: foo',
+    eq('Vim(highlight):E411: Highlight group not found: foo',
        exc_exec("highlight foo"))
   end)
 
diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua
index fc1343bb89..c531c59fd1 100644
--- a/test/functional/legacy/eval_spec.lua
+++ b/test/functional/legacy/eval_spec.lua
@@ -617,9 +617,9 @@ describe('eval', function()
       Executing call setreg(1, 2, [])
       Vim(call):E730: Using a List as a String
       Executing call setreg("/", ["1", "2"])
-      Vim(call):E883: search pattern and expression register may not contain two or more lines
+      Vim(call):E883: Search pattern and expression register may not contain two or more lines
       Executing call setreg("=", ["1", "2"])
-      Vim(call):E883: search pattern and expression register may not contain two or more lines
+      Vim(call):E883: Search pattern and expression register may not contain two or more lines
       Executing call setreg(1, ["", "", [], ""])
       Vim(call):E730: Using a List as a String]])
   end)
diff --git a/test/functional/legacy/glob2regpat_spec.lua b/test/functional/legacy/glob2regpat_spec.lua
index 029d95206e..c442c628c2 100644
--- a/test/functional/legacy/glob2regpat_spec.lua
+++ b/test/functional/legacy/glob2regpat_spec.lua
@@ -8,7 +8,7 @@ describe('glob2regpat()', function()
   before_each(clear)
 
   it('handles invalid input', function()
-    eq('Vim(call):E806: using Float as a String',
+    eq('Vim(call):E806: Using Float as a String',
        exc_exec('call glob2regpat(1.33)'))
   end)
   it('returns ^$ for empty input', function()
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)
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
index 783246c6e4..636f571641 100644
--- a/test/functional/ui/cmdline_highlight_spec.lua
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -854,11 +854,11 @@ describe('Ex commands coloring', function()
       :#                                      |
       {ERR:Error detected while processing :}       |
       {ERR:E605: Exception not caught: 42}          |
-      {ERR:E749: empty buffer}                      |
+      {ERR:E749: Empty buffer}                      |
       {PE:Press ENTER or type command to continue}^ |
     ]])
     feed('')
-    eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: empty buffer',
+    eq('Error detected while processing :\nE605: Exception not caught: 42\nE749: Empty buffer',
        exec_capture('messages'))
   end)
   it('errors out when failing to get callback', function()
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index 2c0a00c74f..e55804e29f 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -790,7 +790,7 @@ describe('ui/mouse/input', function()
     feed('<0,0>')
     screen:expect([[
       {6:E433: No tags file}       |
-      {6:E426: tag not found: test}|
+      {6:E426: Tag not found: test}|
       {6:ing}                      |
       {7:Press ENTER or type comma}|
       {7:nd to continue}^           |
diff --git a/test/functional/vimscript/execute_spec.lua b/test/functional/vimscript/execute_spec.lua
index b9893a5150..bf86f1623e 100644
--- a/test/functional/vimscript/execute_spec.lua
+++ b/test/functional/vimscript/execute_spec.lua
@@ -93,13 +93,13 @@ describe('execute()', function()
   it('captures errors', function()
     local ret
     ret = exc_exec('call execute(0.0)')
-    eq('Vim(call):E806: using Float as a String', ret)
+    eq('Vim(call):E806: Using Float as a String', ret)
     ret = exc_exec('call execute(v:_null_dict)')
     eq('Vim(call):E731: Using a Dictionary as a String', ret)
     ret = exc_exec('call execute(function("tr"))')
     eq('Vim(call):E729: Using a Funcref as a String', ret)
     ret = exc_exec('call execute(["echo 42", 0.0, "echo 44"])')
-    eq('Vim:E806: using Float as a String', ret)
+    eq('Vim:E806: Using Float as a String', ret)
     ret = exc_exec('call execute(["echo 42", v:_null_dict, "echo 44"])')
     eq('Vim:E731: Using a Dictionary as a String', ret)
     ret = exc_exec('call execute(["echo 42", function("tr"), "echo 44"])')
@@ -322,7 +322,7 @@ describe('execute()', function()
     it('propagates errors for "" and "silent"', function()
       local ret
       ret = exc_exec('call execute(0.0, "")')
-      eq('Vim(call):E806: using Float as a String', ret)
+      eq('Vim(call):E806: Using Float as a String', ret)
 
       ret = exc_exec('call execute(v:_null_dict, "silent")')
       eq('Vim(call):E731: Using a Dictionary as a String', ret)
diff --git a/test/functional/vimscript/map_functions_spec.lua b/test/functional/vimscript/map_functions_spec.lua
index ba1b4d7a76..2c8fe69428 100644
--- a/test/functional/vimscript/map_functions_spec.lua
+++ b/test/functional/vimscript/map_functions_spec.lua
@@ -246,9 +246,9 @@ describe('mapset()', function()
   end)
 
   it('does not leak memory if lhs is missing', function()
-    eq('Vim:E460: entries missing in mapset() dict argument',
+    eq('Vim:E460: Entries missing in mapset() dict argument',
        pcall_err(exec_lua, [[vim.fn.mapset('n', false, {rhs = 'foo'})]]))
-    eq('Vim:E460: entries missing in mapset() dict argument',
+    eq('Vim:E460: Entries missing in mapset() dict argument',
        pcall_err(exec_lua, [[vim.fn.mapset('n', false, {callback = function() end})]]))
   end)
 end)
diff --git a/test/functional/vimscript/null_spec.lua b/test/functional/vimscript/null_spec.lua
index 1153baac46..4ba5dd6b45 100644
--- a/test/functional/vimscript/null_spec.lua
+++ b/test/functional/vimscript/null_spec.lua
@@ -65,7 +65,7 @@ describe('NULL', function()
 
     -- Correct behaviour
     null_expr_test('can be indexed with error message for empty list', 'L[0]',
-                   'E684: list index out of range: 0', nil)
+                   'E684: List index out of range: 0', nil)
     null_expr_test('can be splice-indexed', 'L[:]', 0, {})
     null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0)
     null_test('is accepted by :for', 'for x in L|throw x|endfor', 0)
@@ -80,7 +80,7 @@ describe('NULL', function()
     null_expr_test('can be copied', 'copy(L)', 0, {})
     null_expr_test('can be deepcopied', 'deepcopy(L)', 0, {})
     null_expr_test('does not crash when indexed', 'L[1]',
-                        'E684: list index out of range: 1', nil)
+                        'E684: List index out of range: 1', nil)
     null_expr_test('does not crash call()', 'call("arglistid", L)', 0, 0)
     null_expr_test('does not crash col()', 'col(L)', 0, 0)
     null_expr_test('does not crash virtcol()', 'virtcol(L)', 0, 0)
diff --git a/test/functional/vimscript/writefile_spec.lua b/test/functional/vimscript/writefile_spec.lua
index 3cd1052968..da06671fe5 100644
--- a/test/functional/vimscript/writefile_spec.lua
+++ b/test/functional/vimscript/writefile_spec.lua
@@ -145,7 +145,7 @@ describe('writefile()', function()
          pcall_err(command, ('call writefile(%s, "%s", "b")'):format(arg, fname)))
     end
     for _, args in ipairs({'[], %s, "b"', '[], "' .. fname .. '", %s'}) do
-      eq('Vim(call):E806: using Float as a String',
+      eq('Vim(call):E806: Using Float as a String',
          pcall_err(command, ('call writefile(%s)'):format(args:format('0.0'))))
       eq('Vim(call):E730: Using a List as a String',
          pcall_err(command, ('call writefile(%s)'):format(args:format('[]'))))
-- 
cgit 


From bdaaf2e8e113f8c32c70f83b60e0bf3f648357c1 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Fri, 5 May 2023 09:00:35 +0800
Subject: vim-patch:9.0.0250: slightly inconsistent error messages

Problem:    Slightly inconsistent error messages.
Solution:   Make it "Using a Float". (closes vim/vim#10959)

https://github.com/vim/vim/commit/dde77a7c4d72622284dc5fb72557bde42c314fa6

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/glob2regpat_spec.lua  | 2 +-
 test/functional/vimscript/execute_spec.lua   | 6 +++---
 test/functional/vimscript/writefile_spec.lua | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/glob2regpat_spec.lua b/test/functional/legacy/glob2regpat_spec.lua
index c442c628c2..1771f12f85 100644
--- a/test/functional/legacy/glob2regpat_spec.lua
+++ b/test/functional/legacy/glob2regpat_spec.lua
@@ -8,7 +8,7 @@ describe('glob2regpat()', function()
   before_each(clear)
 
   it('handles invalid input', function()
-    eq('Vim(call):E806: Using Float as a String',
+    eq('Vim(call):E806: Using a Float as a String',
        exc_exec('call glob2regpat(1.33)'))
   end)
   it('returns ^$ for empty input', function()
diff --git a/test/functional/vimscript/execute_spec.lua b/test/functional/vimscript/execute_spec.lua
index bf86f1623e..17edf5c93e 100644
--- a/test/functional/vimscript/execute_spec.lua
+++ b/test/functional/vimscript/execute_spec.lua
@@ -93,13 +93,13 @@ describe('execute()', function()
   it('captures errors', function()
     local ret
     ret = exc_exec('call execute(0.0)')
-    eq('Vim(call):E806: Using Float as a String', ret)
+    eq('Vim(call):E806: Using a Float as a String', ret)
     ret = exc_exec('call execute(v:_null_dict)')
     eq('Vim(call):E731: Using a Dictionary as a String', ret)
     ret = exc_exec('call execute(function("tr"))')
     eq('Vim(call):E729: Using a Funcref as a String', ret)
     ret = exc_exec('call execute(["echo 42", 0.0, "echo 44"])')
-    eq('Vim:E806: Using Float as a String', ret)
+    eq('Vim:E806: Using a Float as a String', ret)
     ret = exc_exec('call execute(["echo 42", v:_null_dict, "echo 44"])')
     eq('Vim:E731: Using a Dictionary as a String', ret)
     ret = exc_exec('call execute(["echo 42", function("tr"), "echo 44"])')
@@ -322,7 +322,7 @@ describe('execute()', function()
     it('propagates errors for "" and "silent"', function()
       local ret
       ret = exc_exec('call execute(0.0, "")')
-      eq('Vim(call):E806: Using Float as a String', ret)
+      eq('Vim(call):E806: Using a Float as a String', ret)
 
       ret = exc_exec('call execute(v:_null_dict, "silent")')
       eq('Vim(call):E731: Using a Dictionary as a String', ret)
diff --git a/test/functional/vimscript/writefile_spec.lua b/test/functional/vimscript/writefile_spec.lua
index da06671fe5..521a4eb2b1 100644
--- a/test/functional/vimscript/writefile_spec.lua
+++ b/test/functional/vimscript/writefile_spec.lua
@@ -145,7 +145,7 @@ describe('writefile()', function()
          pcall_err(command, ('call writefile(%s, "%s", "b")'):format(arg, fname)))
     end
     for _, args in ipairs({'[], %s, "b"', '[], "' .. fname .. '", %s'}) do
-      eq('Vim(call):E806: Using Float as a String',
+      eq('Vim(call):E806: Using a Float as a String',
          pcall_err(command, ('call writefile(%s)'):format(args:format('0.0'))))
       eq('Vim(call):E730: Using a List as a String',
          pcall_err(command, ('call writefile(%s)'):format(args:format('[]'))))
-- 
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/ex_cmds/excmd_spec.lua | 16 ++++++++++------
 test/functional/lua/commands_spec.lua  |  2 +-
 test/functional/ui/inccommand_spec.lua |  2 +-
 3 files changed, 12 insertions(+), 8 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ex_cmds/excmd_spec.lua b/test/functional/ex_cmds/excmd_spec.lua
index 14cc2b8387..a92329ede5 100644
--- a/test/functional/ex_cmds/excmd_spec.lua
+++ b/test/functional/ex_cmds/excmd_spec.lua
@@ -11,20 +11,24 @@ describe('Ex cmds', function()
     clear()
   end)
 
+  local function check_excmd_err(cmd, err)
+    eq(err .. ': ' .. cmd, pcall_err(command, cmd))
+  end
+
   it('handle integer overflow from user-input #5555', function()
     command(':9999999999999999999999999999999999999999')
     command(':later 9999999999999999999999999999999999999999')
     command(':echo expand("#<9999999999999999999999999999999999999999")')
     command(':lockvar 9999999999999999999999999999999999999999')
     command(':winsize 9999999999999999999999999999999999999999 9999999999999999999999999999999999999999')
-    eq('Vim(tabnext):E475: Invalid argument: 9999999999999999999999999999999999999999',
-      pcall_err(command, ':tabnext 9999999999999999999999999999999999999999'))
-    eq('Vim(Next):E939: Positive count required',
-      pcall_err(command, ':N 9999999999999999999999999999999999999999'))
+    check_excmd_err(':tabnext 9999999999999999999999999999999999999999',
+                    'Vim(tabnext):E475: Invalid argument: 9999999999999999999999999999999999999999')
+    check_excmd_err(':N 9999999999999999999999999999999999999999',
+                    'Vim(Next):E939: Positive count required')
+    check_excmd_err(':bdelete 9999999999999999999999999999999999999999',
+                    'Vim(bdelete):E939: Positive count required')
     eq('Vim(menu):E329: No menu "9999999999999999999999999999999999999999"',
       pcall_err(command, ':menu 9999999999999999999999999999999999999999'))
-    eq('Vim(bdelete):E939: Positive count required',
-      pcall_err(command, ':bdelete 9999999999999999999999999999999999999999'))
     assert_alive()
   end)
 
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)
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index a67db78cbe..28f489783b 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -1720,7 +1720,7 @@ describe("'inccommand' and :cnoremap", function()
 
   local function refresh(case, visual)
     clear()
-    screen = visual and Screen.new(50,10) or nil
+    screen = visual and Screen.new(80,10) or nil
     common_setup(screen, case, default_text)
   end
 
-- 
cgit 


From 3a1e17e3a1767b4ff8a082150f7f9d6bda50cc8f Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Fri, 5 May 2023 19:03:08 +0800
Subject: test: add tests for executing commands with backwards range

---
 test/functional/api/vim_spec.lua           | 6 ++++++
 test/functional/vimscript/execute_spec.lua | 9 +++++++++
 2 files changed, 15 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index af6fbf092a..c81b6e90cc 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -361,6 +361,12 @@ describe('API', function()
       eq('', eval('v:errmsg'))  -- v:errmsg was not updated.
       eq('', eval('v:exception'))
     end)
+
+    it('gives E493 instead of prompting on backwards range', function()
+      command('split')
+      eq('Vim(windo):E493: Backwards range given: 2,1windo echo',
+         pcall_err(command, '2,1windo echo'))
+    end)
   end)
 
   describe('nvim_command_output', function()
diff --git a/test/functional/vimscript/execute_spec.lua b/test/functional/vimscript/execute_spec.lua
index 17edf5c93e..a9a4ad4811 100644
--- a/test/functional/vimscript/execute_spec.lua
+++ b/test/functional/vimscript/execute_spec.lua
@@ -4,6 +4,7 @@ local eval = helpers.eval
 local clear = helpers.clear
 local source = helpers.source
 local exc_exec = helpers.exc_exec
+local pcall_err = helpers.pcall_err
 local funcs = helpers.funcs
 local Screen = require('test.functional.ui.screen')
 local command = helpers.command
@@ -284,6 +285,14 @@ describe('execute()', function()
       eq('42', eval('g:mes'))
     end)
 
+    it('gives E493 instead of prompting on backwards range for ""', function()
+      command('split')
+      eq('Vim(windo):E493: Backwards range given: 2,1windo echo',
+         pcall_err(funcs.execute, '2,1windo echo', ''))
+      eq('Vim(windo):E493: Backwards range given: 2,1windo echo',
+         pcall_err(funcs.execute, {'2,1windo echo'}, ''))
+    end)
+
     it('captures but does not display output for "silent"', function()
       local screen = Screen.new(40, 5)
       screen:attach()
-- 
cgit 


From c8ebb04e92c9646d83110f4b45f1d1dfd5316561 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Fri, 5 May 2023 18:15:44 +0200
Subject: fix(health): replace healthFoo with DiagnosticFoo (#23475)

This replaces the custom `health{Error,Warning,Success}` highlight
groups with `Diagnostic{Error,Warning,Ok}`, which are defined by
default. Removes the link for `healthHelp`, which was no longer
actually used after #20879.
---
 test/functional/plugin/health_spec.lua | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index 926e12ec32..488a213a9e 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -130,8 +130,8 @@ describe('health.vim', function()
       local screen = Screen.new(50, 12)
       screen:attach()
       screen:set_default_attr_ids({
-        Ok = { foreground = Screen.colors.Grey3, background = 6291200 },
-        Error = { foreground = Screen.colors.Grey100, background = Screen.colors.Red },
+        Ok = { foreground = Screen.colors.LightGreen },
+        Error = { foreground = Screen.colors.Red },
         Heading = { foreground = tonumber('0x6a0dad') },
         Bar = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGrey },
       })
-- 
cgit 


From 22205f36a6213f51f211a67444b335f916a2fa9f Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sat, 6 May 2023 07:46:07 +0800
Subject: fix(api): don't change title when setting buffer in a window (#23492)

---
 test/functional/ui/screen_basic_spec.lua | 47 ++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 439021ad87..6b05bd01c2 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
 local Screen = require('test.functional.ui.screen')
 local spawn, set_session, clear = helpers.spawn, helpers.set_session, helpers.clear
 local feed, command = helpers.feed, helpers.command
+local curwin = helpers.curwin
 local insert = helpers.insert
 local eq = helpers.eq
 local eval = helpers.eval
@@ -189,6 +190,52 @@ local function screen_tests(linegrid)
           eq(expected, screen.title)
         end)
       end)
+
+      it('setting the buffer of another window using RPC', function()
+        local oldwin = curwin().id
+        command('split')
+        meths.win_set_buf(oldwin, buf2)
+        command('redraw!')
+        screen:expect(function()
+          eq(expected, screen.title)
+        end)
+      end)
+
+      it('setting the buffer of another window using Lua callback', function()
+        local oldwin = curwin().id
+        command('split')
+        exec_lua(string.format([[
+          vim.schedule(function()
+            vim.api.nvim_win_set_buf(%d, %d)
+          end)
+        ]], oldwin, buf2))
+        command('redraw!')
+        screen:expect(function()
+          eq(expected, screen.title)
+        end)
+      end)
+
+      it('creating a floating window using RPC', function()
+        meths.open_win(buf2, false, {
+          relative = 'editor', width = 5, height = 5, row = 0, col = 0,
+        })
+        command('redraw!')
+        screen:expect(function()
+          eq(expected, screen.title)
+        end)
+      end)
+
+      it('creating a floating window using Lua callback', function()
+        exec_lua(string.format([[
+          vim.api.nvim_open_win(%d, false, {
+            relative = 'editor', width = 5, height = 5, row = 0, col = 0,
+          })
+        ]], buf2))
+        command('redraw!')
+        screen:expect(function()
+          eq(expected, screen.title)
+        end)
+      end)
     end)
   end)
 
-- 
cgit 


From 3b2bd8d69e6c0a173562778fae6ece67d9adf52c Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Sat, 6 May 2023 17:33:42 +0200
Subject: vim-patch:9.0.1512: inserting lines when scrolling with
 'smoothscroll' set

Problem:    Inserting lines when scrolling with 'smoothscroll' set.
Solution:   Adjust line height computation for w_skipcol. (Luuk van Baal,
            closes vim/vim#12350)

https://github.com/vim/vim/commit/c8502f9b880b6d23baa4f9d28b60e1ceb442e35f
---
 test/functional/legacy/scroll_opt_spec.lua | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 8af23d2c26..c3c99b506b 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -695,6 +695,30 @@ describe('smoothscroll', function()
     ]])
   end)
 
+  -- oldtest: Test_smoothscroll_ins_lines()
+  it("this was unnecessarily inserting lines", function()
+    screen:try_resize(40, 6)
+    exec([=[
+      set wrap smoothscroll scrolloff=0 conceallevel=2 concealcursor=nc
+      call setline(1, [
+        \'line one' .. 'with lots of text in one line '->repeat(2),
+        \'line two',
+        \'line three',
+        \'line four',
+        \'line five'
+      \])
+    ]=])
+    feed('gjgk')
+    screen:expect([[
+      <<
Date: Sat, 6 May 2023 19:24:45 +0200
Subject: vim-patch:9.0.1513: text scrolls unnecessarily when splitting

Problem:    Text scrolls unnecessarily when splitting and 'splitkeep' is not
            "cursor".
Solution:   Avoid resetting w_skipcol. (Luuk van Baal, closes vim/vim#12334)

https://github.com/vim/vim/commit/b926bf47d61360a4ec5e4867714a08d70fd49965
---
 test/functional/legacy/window_cmd_spec.lua | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/window_cmd_spec.lua b/test/functional/legacy/window_cmd_spec.lua
index 3a51f7a23f..373a9c7163 100644
--- a/test/functional/legacy/window_cmd_spec.lua
+++ b/test/functional/legacy/window_cmd_spec.lua
@@ -254,4 +254,29 @@ describe('splitkeep', function()
                                                            |
     ]])
   end)
+
+  -- oldtest: Test_splitkeep_skipcol()
+  it('skipcol is not reset unnecessarily and is copied to new window', function()
+    screen:try_resize(40, 12)
+    exec([[
+      set splitkeep=topline smoothscroll splitbelow scrolloff=0
+      call setline(1, 'with lots of text in one line '->repeat(6))
+      norm 2
+      wincmd s
+    ]])
+    screen:expect([[
+      <<
Date: Sun, 7 May 2023 07:57:29 +0800
Subject: vim-patch:9.0.1518: search stats not always visible when searching
 backwards (#23517)

Problem:    Search stats not always visible when searching backwards.
Solution:   Do not display the top/bot message on top of the search stats.
            (Christian Brabandt, closes vim/vim#12322, closes vim/vim#12222)

https://github.com/vim/vim/commit/34a6a3617b5b6ce11372439f14762caddc4b0cea

Co-authored-by: Christian Brabandt 
---
 test/functional/legacy/search_stat_spec.lua | 56 ++++++++++++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/search_stat_spec.lua b/test/functional/legacy/search_stat_spec.lua
index 06e0b2320a..bd5ab68e5c 100644
--- a/test/functional/legacy/search_stat_spec.lua
+++ b/test/functional/legacy/search_stat_spec.lua
@@ -10,8 +10,9 @@ describe('search stat', function()
     screen:set_default_attr_ids({
       [1] = {bold = true, foreground = Screen.colors.Blue},  -- NonText
       [2] = {background = Screen.colors.Yellow},  -- Search
-      [3] = {foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey},  -- Folded
+      [3] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},  -- Folded
       [4] = {reverse = true},  -- IncSearch, TabLineFill
+      [5] = {foreground = Screen.colors.Red},  -- WarningMsg
     })
     screen:attach()
   end)
@@ -183,4 +184,57 @@ describe('search stat', function()
       /abc^                          |
     ]])
   end)
+
+  -- oldtest: Test_search_stat_backwards()
+  it('when searching backwards', function()
+    screen:try_resize(60, 10)
+    exec([[
+      set shm-=S
+      call setline(1, ['test', ''])
+    ]])
+
+    feed('*')
+    screen:expect([[
+      {2:^test}                                                        |
+                                                                  |
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      /\                                            [1/1]  |
+    ]])
+
+    feed('N')
+    screen:expect([[
+      {2:^test}                                                        |
+                                                                  |
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      ?\                                            [1/1]  |
+    ]])
+
+    command('set shm+=S')
+    feed('N')
+    -- shows "Search Hit Bottom.."
+    screen:expect([[
+      {2:^test}                                                        |
+                                                                  |
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {1:~                                                           }|
+      {5:search hit TOP, continuing at BOTTOM}                        |
+    ]])
+  end)
 end)
-- 
cgit 


From a2b9117ca8f8abe8d4c9e2d1bacb73b1902a4e1f Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 7 May 2023 08:12:42 +0800
Subject: vim-patch:8.2.1978: making a mapping work in all modes is complicated

Problem:    Making a mapping work in all modes is complicated.
Solution:   Add the  special key. (Yegappan Lakshmanan, closes vim/vim#7282,
            closes 4784, based on patch by Bjorn Linse)

https://github.com/vim/vim/commit/957cf67d50516ba98716f59c9e1cb6412ec1535d

Change docs to match Vim if it's wording is better.
Change error numbers to match Vim.

Co-authored-by: Bram Moolenaar 
---
 test/functional/ex_cmds/cmd_map_spec.lua | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ex_cmds/cmd_map_spec.lua b/test/functional/ex_cmds/cmd_map_spec.lua
index 919d167712..a0aec7fdd0 100644
--- a/test/functional/ex_cmds/cmd_map_spec.lua
+++ b/test/functional/ex_cmds/cmd_map_spec.lua
@@ -90,7 +90,7 @@ describe('mappings with ', function()
       {1:~                                                                }|
       {1:~                                                                }|
       {1:~                                                                }|
-      {2:E5521:  mapping must end with  before second }      |
+      {2:E1136:  mapping must end with  before second }      |
     ]])
 
     command('noremap  let x = 3')
@@ -103,7 +103,7 @@ describe('mappings with ', function()
       {1:~                                                                }|
       {1:~                                                                }|
       {1:~                                                                }|
-      {2:E5520:  mapping must end with }                          |
+      {2:E1135:  mapping must end with }                          |
     ]])
     eq(0, eval('x'))
   end)
-- 
cgit 


From 29c228dc1087676af5b72f4145ab146cff75156e Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 7 May 2023 08:33:06 +0800
Subject: vim-patch:8.2.3887: E1135 is used for two different errors

Problem:    E1135 is used for two different errors.
Solution:   Renumber one error.

https://github.com/vim/vim/commit/806da5176e9e9ab011d927c4ca33a8dde1769539

Co-authored-by: Bram Moolenaar 
---
 test/functional/ex_cmds/cmd_map_spec.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ex_cmds/cmd_map_spec.lua b/test/functional/ex_cmds/cmd_map_spec.lua
index a0aec7fdd0..12867179bd 100644
--- a/test/functional/ex_cmds/cmd_map_spec.lua
+++ b/test/functional/ex_cmds/cmd_map_spec.lua
@@ -103,7 +103,7 @@ describe('mappings with ', function()
       {1:~                                                                }|
       {1:~                                                                }|
       {1:~                                                                }|
-      {2:E1135:  mapping must end with }                          |
+      {2:E1255:  mapping must end with }                          |
     ]])
     eq(0, eval('x'))
   end)
-- 
cgit 


From 3001d86aea184f8b015c1bfffd2db42c946f8a84 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 8 May 2023 15:22:58 +0800
Subject: test: add more tests for :Man section extraction

---
 test/functional/plugin/man_spec.lua | 32 ++++++++++++++++++++++++--------
 1 file changed, 24 insertions(+), 8 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index 9730bf4bf6..d5c1a78fc8 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -20,10 +20,10 @@ local function get_search_history(name)
     local man = require('runtime.lua.man')
     local res = {}
     man.find_path = function(sect, name)
-      table.insert(res, name)
+      table.insert(res, {sect, name})
       return nil
     end
-    local ok, rv = pcall(man.open_page, 0, {tab = 0}, args)
+    local ok, rv = pcall(man.open_page, -1, {tab = 0}, args)
     assert(not ok)
     assert(rv and rv:match('no manual entry'))
     return res
@@ -196,16 +196,32 @@ describe(':Man', function()
 
   it('tries variants with spaces, underscores #22503', function()
     eq({
-       'NAME WITH SPACES',
-       'NAME_WITH_SPACES',
+       {'', 'NAME WITH SPACES'},
+       {'', 'NAME_WITH_SPACES'},
       }, get_search_history('NAME WITH SPACES'))
     eq({
-       'some other man',
-       'some_other_man',
+       {'3', 'some other man'},
+       {'3', 'some_other_man'},
       }, get_search_history('3 some other man'))
     eq({
-       'other_man',
-       'other_man',
+       {'3x', 'some other man'},
+       {'3x', 'some_other_man'},
+      }, get_search_history('3X some other man'))
+    eq({
+       {'3tcl', 'some other man'},
+       {'3tcl', 'some_other_man'},
+      }, get_search_history('3tcl some other man'))
+    eq({
+       {'n', 'some other man'},
+       {'n', 'some_other_man'},
+      }, get_search_history('n some other man'))
+    eq({
+       {'', '123some other man'},
+       {'', '123some_other_man'},
+      }, get_search_history('123some other man'))
+    eq({
+       {'1', 'other_man'},
+       {'1', 'other_man'},
       }, get_search_history('other_man(1)'))
   end)
 end)
-- 
cgit 


From 4ecf6fdfd857b52c0bab9a8dbfc760364ac2677b Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 8 May 2023 16:25:03 +0800
Subject: fix(statusline): bail out properly on negative row (#23535)

---
 test/functional/ui/winbar_spec.lua | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua
index 970f9c3d76..3b79f4328d 100644
--- a/test/functional/ui/winbar_spec.lua
+++ b/test/functional/ui/winbar_spec.lua
@@ -713,3 +713,26 @@ describe('local winbar with tabs', function()
     ]]}
   end)
 end)
+
+it('winbar works properly when redrawing is postponed #23534', function()
+  clear({args = {
+    '-c', 'set laststatus=2 lazyredraw',
+    '-c', 'setlocal statusline=(statusline) winbar=(winbar)',
+    '-c', 'call nvim_input(":")',
+  }})
+  local screen = Screen.new(60, 6)
+  screen:attach()
+  screen:set_default_attr_ids({
+    [0] = {foreground = Screen.colors.Blue, bold = true},
+    [1] = {bold = true},
+    [2] = {bold = true, reverse = true},
+  })
+  screen:expect([[
+    {1:(winbar)                                                    }|
+    ^                                                            |
+    {0:~                                                           }|
+    {0:~                                                           }|
+    {2:(statusline)                                                }|
+                                                                |
+  ]])
+end)
-- 
cgit 


From 44fc2a6d7e642d5b02c2fc7de11f478401a51bb2 Mon Sep 17 00:00:00 2001
From: luukvbaal 
Date: Tue, 9 May 2023 01:44:31 +0200
Subject: vim-patch:9.0.1525: 'smoothscroll' does not always work properly
 (#23544)

Problem:    'smoothscroll' does not always work properly.
Solution:   Do not reset w_skipcol after it was intentionally set.  (Luuk van
            Baal, closes vim/vim#12360, closes vim/vim#12199, closes vim/vim#12323)

https://github.com/vim/vim/commit/3ce8c389155fc1257082cdb0cef7801b49f6aaf9
---
 test/functional/legacy/scroll_opt_spec.lua | 69 ++++++++++++++++++++++++++++--
 1 file changed, 65 insertions(+), 4 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index c3c99b506b..869763be3c 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -548,11 +548,11 @@ describe('smoothscroll', function()
     exec('set scrolloff=0')
     feed('0j')
     screen:expect([[
-      <<repeat(&lines * &columns),
+        \(('_')->repeat(&columns - 2) .. 'xxx')->repeat(2)
+      \])
+      autocmd CursorMoved * eval [line('w0'), line('w$')]
+      call search('xxx')
+    ]=])
+    screen:expect([[
+      <<<_____________________________________|
+      ________________________________________|
+      ______________________________________^xx|
+      x______________________________________x|
+      xx                                      |
+                                              |
+    ]])
+  end)
+
+  -- oldtest: Test_smoothscroll_eob()
+  it("does not scroll halfway at end of buffer", function()
+    screen:try_resize(40, 10)
+    exec([[
+      set smoothscroll
+      call setline(1, ['']->repeat(100))
+      norm G
+    ]])
+    -- does not scroll halfway when scrolling to end of buffer
+    screen:expect([[
+                                              |
+                                              |
+                                              |
+                                              |
+                                              |
+                                              |
+                                              |
+                                              |
+      ^                                        |
+                                              |
+    ]])
+    exec("call setline(92, 'a'->repeat(100))")
+    feed('G')
+    -- cursor is not placed below window
+    screen:expect([[
+      <<
Date: Tue, 9 May 2023 11:12:54 -0500
Subject: fix(lsp): fix relative patterns for `workspace/didChangeWatchedFiles`
 (#23548)

---
 test/functional/plugin/lsp_spec.lua | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 5ba0706208..fc7b2dafb8 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -3855,7 +3855,7 @@ describe('LSP', function()
     end)
 
     it('correctly registers and unregisters', function()
-      local root_dir = 'some_dir'
+      local root_dir = '/some_dir'
       exec_lua(create_server_definition)
       local result = exec_lua([[
         local root_dir = ...
@@ -4009,10 +4009,9 @@ describe('LSP', function()
         local watchers = {}
         local max_kind = protocol.WatchKind.Create + protocol.WatchKind.Change + protocol.WatchKind.Delete
         for i = 0, max_kind do
-          local j = i
           table.insert(watchers, {
             globPattern = {
-              baseUri = vim.uri_from_fname('/dir'..tostring(i)),
+              baseUri = vim.uri_from_fname('/dir'),
               pattern = 'watch'..tostring(i),
             },
             kind = i,
@@ -4031,7 +4030,7 @@ describe('LSP', function()
         }, { client_id = client_id })
 
         for i = 0, max_kind do
-          local filename = 'watch'..tostring(i)
+          local filename = '/dir/watch' .. tostring(i)
           send_event(filename, vim._watch.FileChangeType.Created)
           send_event(filename, vim._watch.FileChangeType.Changed)
           send_event(filename, vim._watch.FileChangeType.Deleted)
@@ -4045,7 +4044,8 @@ describe('LSP', function()
 
       local function watched_uri(fname)
         return exec_lua([[
-            return vim.uri_from_fname(...)
+            local fname = ...
+            return vim.uri_from_fname('/dir/' .. fname)
           ]], fname)
       end
 
-- 
cgit 


From 36baaf7c1aa0bbc9c80f4512bb1384839c8851ff Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 10 May 2023 00:14:54 +0800
Subject: test: move most title tests to a separate file (#23557)

This avoids running title tests twice unnecessarily.
---
 test/functional/ui/screen_basic_spec.lua | 121 +--------------------------
 test/functional/ui/title_spec.lua        | 138 +++++++++++++++++++++++++++++++
 2 files changed, 139 insertions(+), 120 deletions(-)
 create mode 100644 test/functional/ui/title_spec.lua

(limited to 'test/functional')

diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index 6b05bd01c2..e1ae76badf 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -2,12 +2,10 @@ local helpers = require('test.functional.helpers')(after_each)
 local Screen = require('test.functional.ui.screen')
 local spawn, set_session, clear = helpers.spawn, helpers.set_session, helpers.clear
 local feed, command = helpers.feed, helpers.command
-local curwin = helpers.curwin
 local insert = helpers.insert
 local eq = helpers.eq
 local eval = helpers.eval
-local funcs, meths, exec_lua = helpers.funcs, helpers.meths, helpers.exec_lua
-local is_os = helpers.is_os
+local funcs, meths = helpers.funcs, helpers.meths
 
 describe('screen', function()
   local screen
@@ -120,123 +118,6 @@ local function screen_tests(linegrid)
         eq(expected, screen.title)
       end)
     end)
-
-    it('has correct default title with unnamed file', function()
-      local expected = '[No Name] - NVIM'
-      command('set title')
-      screen:expect(function()
-        eq(expected, screen.title)
-      end)
-    end)
-
-    it('has correct default title with named file', function()
-      local expected = (is_os('win') and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM')
-      command('set title')
-      command(is_os('win') and 'file C:\\mydir\\myfile' or 'file /mydir/myfile')
-      screen:expect(function()
-        eq(expected, screen.title)
-      end)
-    end)
-
-    describe('is not changed by', function()
-      local file1 = is_os('win') and 'C:\\mydir\\myfile1' or '/mydir/myfile1'
-      local file2 = is_os('win') and 'C:\\mydir\\myfile2' or '/mydir/myfile2'
-      local expected = (is_os('win') and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM')
-      local buf2
-
-      before_each(function()
-        command('edit '..file1)
-        buf2 = funcs.bufadd(file2)
-        command('set title')
-      end)
-
-      it('calling setbufvar() to set an option in a hidden buffer from i_CTRL-R', function()
-        command([[inoremap  =setbufvar(]]..buf2..[[, '&autoindent', 1) ? '' : '']])
-        feed('i')
-        command('redraw!')
-        screen:expect(function()
-          eq(expected, screen.title)
-        end)
-      end)
-
-      it('an RPC call to nvim_buf_set_option in a hidden buffer', function()
-        meths.buf_set_option(buf2, 'autoindent', true)
-        command('redraw!')
-        screen:expect(function()
-          eq(expected, screen.title)
-        end)
-      end)
-
-      it('a Lua callback calling nvim_buf_set_option in a hidden buffer', function()
-        exec_lua(string.format([[
-          vim.schedule(function()
-            vim.api.nvim_buf_set_option(%d, 'autoindent', true)
-          end)
-        ]], buf2))
-        command('redraw!')
-        screen:expect(function()
-          eq(expected, screen.title)
-        end)
-      end)
-
-      it('a Lua callback calling nvim_buf_call in a hidden buffer', function()
-        exec_lua(string.format([[
-          vim.schedule(function()
-            vim.api.nvim_buf_call(%d, function() end)
-          end)
-        ]], buf2))
-        command('redraw!')
-        screen:expect(function()
-          eq(expected, screen.title)
-        end)
-      end)
-
-      it('setting the buffer of another window using RPC', function()
-        local oldwin = curwin().id
-        command('split')
-        meths.win_set_buf(oldwin, buf2)
-        command('redraw!')
-        screen:expect(function()
-          eq(expected, screen.title)
-        end)
-      end)
-
-      it('setting the buffer of another window using Lua callback', function()
-        local oldwin = curwin().id
-        command('split')
-        exec_lua(string.format([[
-          vim.schedule(function()
-            vim.api.nvim_win_set_buf(%d, %d)
-          end)
-        ]], oldwin, buf2))
-        command('redraw!')
-        screen:expect(function()
-          eq(expected, screen.title)
-        end)
-      end)
-
-      it('creating a floating window using RPC', function()
-        meths.open_win(buf2, false, {
-          relative = 'editor', width = 5, height = 5, row = 0, col = 0,
-        })
-        command('redraw!')
-        screen:expect(function()
-          eq(expected, screen.title)
-        end)
-      end)
-
-      it('creating a floating window using Lua callback', function()
-        exec_lua(string.format([[
-          vim.api.nvim_open_win(%d, false, {
-            relative = 'editor', width = 5, height = 5, row = 0, col = 0,
-          })
-        ]], buf2))
-        command('redraw!')
-        screen:expect(function()
-          eq(expected, screen.title)
-        end)
-      end)
-    end)
   end)
 
   describe(':set icon', function()
diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua
new file mode 100644
index 0000000000..75ead49f74
--- /dev/null
+++ b/test/functional/ui/title_spec.lua
@@ -0,0 +1,138 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local command = helpers.command
+local curwin = helpers.curwin
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local feed = helpers.feed
+local funcs = helpers.funcs
+local meths = helpers.meths
+local is_os = helpers.is_os
+
+describe('title', function()
+  local screen
+
+  before_each(function()
+    clear()
+    screen = Screen.new()
+    screen:attach()
+  end)
+
+  it('has correct default title with unnamed file', function()
+    local expected = '[No Name] - NVIM'
+    command('set title')
+    screen:expect(function()
+      eq(expected, screen.title)
+    end)
+  end)
+
+  it('has correct default title with named file', function()
+    local expected = (is_os('win') and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM')
+    command('set title')
+    command(is_os('win') and 'file C:\\mydir\\myfile' or 'file /mydir/myfile')
+    screen:expect(function()
+      eq(expected, screen.title)
+    end)
+  end)
+
+  describe('is not changed by', function()
+    local file1 = is_os('win') and 'C:\\mydir\\myfile1' or '/mydir/myfile1'
+    local file2 = is_os('win') and 'C:\\mydir\\myfile2' or '/mydir/myfile2'
+    local expected = (is_os('win') and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM')
+    local buf2
+
+    before_each(function()
+      command('edit '..file1)
+      buf2 = funcs.bufadd(file2)
+      command('set title')
+    end)
+
+    it('calling setbufvar() to set an option in a hidden buffer from i_CTRL-R', function()
+      command([[inoremap  =setbufvar(]]..buf2..[[, '&autoindent', 1) ? '' : '']])
+      feed('i')
+      command('redraw!')
+      screen:expect(function()
+        eq(expected, screen.title)
+      end)
+    end)
+
+    it('an RPC call to nvim_buf_set_option in a hidden buffer', function()
+      meths.buf_set_option(buf2, 'autoindent', true)
+      command('redraw!')
+      screen:expect(function()
+        eq(expected, screen.title)
+      end)
+    end)
+
+    it('a Lua callback calling nvim_buf_set_option in a hidden buffer', function()
+      exec_lua(string.format([[
+        vim.schedule(function()
+          vim.api.nvim_buf_set_option(%d, 'autoindent', true)
+        end)
+      ]], buf2))
+      command('redraw!')
+      screen:expect(function()
+        eq(expected, screen.title)
+      end)
+    end)
+
+    it('a Lua callback calling nvim_buf_call in a hidden buffer', function()
+      exec_lua(string.format([[
+        vim.schedule(function()
+          vim.api.nvim_buf_call(%d, function() end)
+        end)
+      ]], buf2))
+      command('redraw!')
+      screen:expect(function()
+        eq(expected, screen.title)
+      end)
+    end)
+
+    it('setting the buffer of another window using RPC', function()
+      local oldwin = curwin().id
+      command('split')
+      meths.win_set_buf(oldwin, buf2)
+      command('redraw!')
+      screen:expect(function()
+        eq(expected, screen.title)
+      end)
+    end)
+
+    it('setting the buffer of another window using Lua callback', function()
+      local oldwin = curwin().id
+      command('split')
+      exec_lua(string.format([[
+        vim.schedule(function()
+          vim.api.nvim_win_set_buf(%d, %d)
+        end)
+      ]], oldwin, buf2))
+      command('redraw!')
+      screen:expect(function()
+        eq(expected, screen.title)
+      end)
+    end)
+
+    it('creating a floating window using RPC', function()
+      meths.open_win(buf2, false, {
+        relative = 'editor', width = 5, height = 5, row = 0, col = 0,
+      })
+      command('redraw!')
+      screen:expect(function()
+        eq(expected, screen.title)
+      end)
+    end)
+
+    it('creating a floating window using Lua callback', function()
+      exec_lua(string.format([[
+        vim.api.nvim_open_win(%d, false, {
+          relative = 'editor', width = 5, height = 5, row = 0, col = 0,
+        })
+      ]], buf2))
+      command('redraw!')
+      screen:expect(function()
+        eq(expected, screen.title)
+      end)
+    end)
+  end)
+end)
-- 
cgit 


From 1caad791b4655c412c35279003641e5c4d9ed28d Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Tue, 9 May 2023 17:09:43 +0200
Subject: vim-patch:9.0.1530: cursor moves to wrong line when 'foldmethod' is
 "diff"

Problem:    Cursor moves to wrong line when 'foldmethod' is "diff". (Rick
            Howe)
Solution:   Adjust logic for scrolling. (Luuk van Baal, closes vim/vim#12364,
            closes vim/vim#12218)

https://github.com/vim/vim/commit/aa6ba308a1498dc8da04d1d30ec0470018bf782a
---
 test/functional/legacy/normal_spec.lua | 41 ++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 test/functional/legacy/normal_spec.lua

(limited to 'test/functional')

diff --git a/test/functional/legacy/normal_spec.lua b/test/functional/legacy/normal_spec.lua
new file mode 100644
index 0000000000..ba875460f5
--- /dev/null
+++ b/test/functional/legacy/normal_spec.lua
@@ -0,0 +1,41 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+
+before_each(clear)
+
+describe('normal', function()
+  -- oldtest: Test_normal_j_below_botline()
+  it([["j" does not skip lines when scrolling below botline and 'foldmethod' is not "manual"]], function()
+    local screen = Screen.new(40, 19)
+    screen:attach()
+    screen:set_default_attr_ids({{foreground = Screen.colors.Brown}})
+    exec([[
+      set number foldmethod=diff scrolloff=0
+      call setline(1, map(range(1, 9), 'repeat(v:val, 200)'))
+      norm Lj
+    ]])
+    screen:expect([[
+      {1:  2 }222222222222222222222222222222222222|
+      {1:    }222222222222222222222222222222222222|
+      {1:    }222222222222222222222222222222222222|
+      {1:    }222222222222222222222222222222222222|
+      {1:    }222222222222222222222222222222222222|
+      {1:    }22222222222222222222                |
+      {1:  3 }333333333333333333333333333333333333|
+      {1:    }333333333333333333333333333333333333|
+      {1:    }333333333333333333333333333333333333|
+      {1:    }333333333333333333333333333333333333|
+      {1:    }333333333333333333333333333333333333|
+      {1:    }33333333333333333333                |
+      {1:  4 }^444444444444444444444444444444444444|
+      {1:    }444444444444444444444444444444444444|
+      {1:    }444444444444444444444444444444444444|
+      {1:    }444444444444444444444444444444444444|
+      {1:    }444444444444444444444444444444444444|
+      {1:    }44444444444444444444                |
+                                              |
+    ]])
+  end)
+end)
-- 
cgit 


From d5780e133a030d3ae4a4985264412bdca06746d7 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Tue, 9 May 2023 22:41:02 +0200
Subject: vim-patch:9.0.1533: test for 'smoothscroll' is ineffective

Problem:    Test for 'smoothscroll' is ineffective.
Solution:   Change the order of testing "zb" and "zt". (Luuk van Baal,
            closes vim/vim#12366)

https://github.com/vim/vim/commit/6f37e530d3e2d58ff055723047bf91d91af2632c
---
 test/functional/legacy/scroll_opt_spec.lua | 29 +++++++++++------------------
 1 file changed, 11 insertions(+), 18 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 869763be3c..e567d238b2 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -556,13 +556,13 @@ describe('smoothscroll', function()
                                               |
     ]])
     -- Test zt/zz/zb that they work properly when a long line is above it
-    feed('zb')
+    feed('zt')
     screen:expect([[
-      <<repeat(10)) .. ' end', 'four'])")
     feed('3Gztj')
-    screen:expect([[
-      <<
Date: Wed, 10 May 2023 17:42:14 +0800
Subject: fix(redo): make redo of Lua mappings in op-pending mode work (#23566)

---
 test/functional/api/keymap_spec.lua | 45 +++++++++++++++++++++++--------------
 1 file changed, 28 insertions(+), 17 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index f2817ff627..e239717d3a 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -813,19 +813,18 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
   it('can make lua mappings', function()
     eq(0, exec_lua [[
       GlobalCount = 0
-      vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+      vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
       return GlobalCount
     ]])
 
     feed('asdf\n')
 
     eq(1, exec_lua[[return GlobalCount]])
-
   end)
 
   it (':map command shows lua mapping correctly', function()
     exec_lua [[
-      vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
+      vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end })
     ]]
     assert.truthy(
       string.match(
@@ -837,7 +836,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
 
   it ('mapcheck() returns lua mapping correctly', function()
     exec_lua [[
-      vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
+      vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() print('jkl;') end })
     ]]
     assert.truthy(string.match(funcs.mapcheck('asdf', 'n'),
                   "^"))
@@ -871,7 +870,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
 
   it('can make lua expr mappings replacing keycodes', function()
     exec_lua [[
-      vim.api.nvim_set_keymap ('n', 'aa', '', {callback = function() return 'πfoo' end, expr = true, replace_keycodes = true })
+      vim.api.nvim_set_keymap('n', 'aa', '', {callback = function() return 'πfoo' end, expr = true, replace_keycodes = true })
     ]]
 
     feed('aa')
@@ -881,7 +880,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
 
   it('can make lua expr mappings without replacing keycodes', function()
     exec_lua [[
-      vim.api.nvim_set_keymap ('i', 'aa', '', {callback = function() return '' end, expr = true })
+      vim.api.nvim_set_keymap('i', 'aa', '', {callback = function() return '' end, expr = true })
     ]]
 
     feed('iaa')
@@ -891,7 +890,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
 
   it('lua expr mapping returning nil is equivalent to returning an empty string', function()
     exec_lua [[
-      vim.api.nvim_set_keymap ('i', 'aa', '', {callback = function() return nil end, expr = true })
+      vim.api.nvim_set_keymap('i', 'aa', '', {callback = function() return nil end, expr = true })
     ]]
 
     feed('iaa')
@@ -902,17 +901,29 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
   it('does not reset pum in lua mapping', function()
     eq(0, exec_lua [[
       VisibleCount = 0
-      vim.api.nvim_set_keymap ('i', '', '', {callback = function() VisibleCount = VisibleCount + vim.fn.pumvisible() end})
+      vim.api.nvim_set_keymap('i', '', '', {callback = function() VisibleCount = VisibleCount + vim.fn.pumvisible() end})
       return VisibleCount
     ]])
     feed('i')
     eq(2, exec_lua[[return VisibleCount]])
   end)
 
+  it('redo of lua mappings in op-pending mode work', function()
+    eq(0, exec_lua [[
+      OpCount = 0
+      vim.api.nvim_set_keymap('o', '', '', {callback = function() OpCount = OpCount + 1 end})
+      return OpCount
+    ]])
+    feed('d')
+    eq(1, exec_lua[[return OpCount]])
+    feed('.')
+    eq(2, exec_lua[[return OpCount]])
+  end)
+
   it('can overwrite lua mappings', function()
     eq(0, exec_lua [[
       GlobalCount = 0
-      vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+      vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
       return GlobalCount
     ]])
 
@@ -921,7 +932,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
     eq(1, exec_lua[[return GlobalCount]])
 
     exec_lua [[
-      vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end })
+      vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end })
     ]]
 
     feed('asdf\n')
@@ -932,7 +943,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
   it('can unmap lua mappings', function()
     eq(0, exec_lua [[
       GlobalCount = 0
-      vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+      vim.api.nvim_set_keymap('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
       return GlobalCount
     ]])
 
@@ -1078,7 +1089,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
   it('can make lua mappings', function()
     eq(0, exec_lua [[
       GlobalCount = 0
-      vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+      vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
       return GlobalCount
     ]])
 
@@ -1089,7 +1100,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
 
   it('can make lua expr mappings replacing keycodes', function()
     exec_lua [[
-      vim.api.nvim_buf_set_keymap (0, 'n', 'aa', '', {callback = function() return 'πfoo' end, expr = true, replace_keycodes = true })
+      vim.api.nvim_buf_set_keymap(0, 'n', 'aa', '', {callback = function() return 'πfoo' end, expr = true, replace_keycodes = true })
     ]]
 
     feed('aa')
@@ -1099,7 +1110,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
 
   it('can make lua expr mappings without replacing keycodes', function()
     exec_lua [[
-      vim.api.nvim_buf_set_keymap (0, 'i', 'aa', '', {callback = function() return '' end, expr = true })
+      vim.api.nvim_buf_set_keymap(0, 'i', 'aa', '', {callback = function() return '' end, expr = true })
     ]]
 
     feed('iaa')
@@ -1111,7 +1122,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
   it('can overwrite lua mappings', function()
     eq(0, exec_lua [[
       GlobalCount = 0
-      vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+      vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
       return GlobalCount
     ]])
 
@@ -1120,7 +1131,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
     eq(1, exec_lua[[return GlobalCount]])
 
     exec_lua [[
-      vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end })
+      vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end })
     ]]
 
     feed('asdf\n')
@@ -1131,7 +1142,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
   it('can unmap lua mappings', function()
     eq(0, exec_lua [[
       GlobalCount = 0
-      vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+      vim.api.nvim_buf_set_keymap(0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
       return GlobalCount
     ]])
 
-- 
cgit 


From 03ca36d1f8d027c95edd46f3127284e9a3577990 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 10 May 2023 23:46:50 +0800
Subject: fix(highlight): apply 'winblend' to NormalNC (#23555)

---
 test/functional/ui/float_spec.lua | 63 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 4 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 28c16642f1..46a079d9ff 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -8079,10 +8079,13 @@ describe('float window', function()
         [6] = {foreground = tonumber('0x332533'), background = tonumber('0xfff1ff')},
         [7] = {background = tonumber('0xffcfff'), bold = true, foreground = tonumber('0x0000d8')},
         [8] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1},
-        [9] = {background = Screen.colors.LightMagenta, blend=30},
-        [10] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta, blend=0},
-        [11] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta, blend=80},
-        [12] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1, blend=30},
+        [9] = {background = Screen.colors.LightMagenta, blend = 30},
+        [10] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta, blend = 0},
+        [11] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta, blend = 80},
+        [12] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1, blend = 30},
+        [13] = {background = Screen.colors.LightGray, blend = 30},
+        [14] = {foreground = Screen.colors.Grey0, background = Screen.colors.Grey88},
+        [15] = {foreground = tonumber('0x939393'), background = Screen.colors.Grey88},
       })
       insert([[
         Lorem ipsum dolor sit amet, consectetur
@@ -8184,6 +8187,58 @@ describe('float window', function()
         ]])
       end
 
+      -- Check that 'winblend' works with NormalNC highlight
+      meths.set_option_value('winhighlight', 'NormalNC:Visual', {win = win})
+      if multigrid then
+        screen:expect{grid=[[
+        ## grid 1
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [2:--------------------------------------------------]|
+          [3:--------------------------------------------------]|
+        ## grid 2
+          Ut enim ad minim veniam, quis nostrud             |
+          exercitation ullamco laboris nisi ut aliquip ex   |
+          ea commodo consequat. Duis aute irure dolor in    |
+          reprehenderit in voluptate velit esse cillum      |
+          dolore eu fugiat nulla pariatur. Excepteur sint   |
+          occaecat cupidatat non proident, sunt in culpa    |
+          qui officia deserunt mollit anim id est           |
+          laborum^.                                          |
+        ## grid 3
+                                                            |
+        ## grid 5
+          {13:test           }|
+          {13:               }|
+          {13:popup    text  }|
+        ]], float_pos={
+          [5] = {{id = 1002}, "NW", 1, 2, 5, true, 50};
+        }}
+      else
+        screen:expect([[
+          Ut enim ad minim veniam, quis nostrud             |
+          exercitation ullamco laboris nisi ut aliquip ex   |
+          ea co{14:test}{15:o consequat}. Duis aute irure dolor in    |
+          repre{15:henderit in vol}uptate velit esse cillum      |
+          dolor{14:popup}{15:fugi}{14:text}{15:ul}la pariatur. Excepteur sint   |
+          occaecat cupidatat non proident, sunt in culpa    |
+          qui officia deserunt mollit anim id est           |
+          laborum^.                                          |
+                                                            |
+        ]])
+      end
+
+      -- Also test with global NormalNC highlight
+      meths.set_option_value('winhighlight', '', {win = win})
+      command('hi link NormalNC Visual')
+      screen:expect_unchanged(true)
+      command('hi clear NormalNC')
+
       command('hi SpecialRegion guifg=Red blend=0')
       meths.buf_add_highlight(buf, -1, "SpecialRegion", 2, 0, -1)
       if multigrid then
-- 
cgit 


From 15c684b358b0165d0874ba08ab6ac0976c86cc0f Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Thu, 11 May 2023 20:29:09 +0200
Subject: vim-patch:9.0.1542: line not fully displayed if it doesn't fit in the
 screen

Problem:    Line not fully displayed if it doesn't fit in the screen.
Solution:   Do not reset s_skipcol if not needed. (Luuk van Baal,
            closes vim/vim#12376)

https://github.com/vim/vim/commit/6c018680be0ec25d42614a93be1ea08df29a9e2a
---
 test/functional/legacy/display_spec.lua | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index f1cd8d1aac..a698bed9f7 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -196,7 +196,7 @@ describe('display', function()
   end)
 
   -- oldtest: Test_display_long_lastline()
-  it('display "lastline" shows correct text when end of wrapped line is deleted', function()
+  it('"lastline" shows correct text when end of wrapped line is deleted', function()
     local screen = Screen.new(35, 14)
     screen:attach()
     exec([[
@@ -241,4 +241,24 @@ describe('display', function()
                                          |
     ]])
   end)
+
+  -- oldtest: Test_display_cursor_long_line()
+  it("correctly shows line that doesn't fit in the window", function()
+    local screen = Screen.new(75, 8)
+    screen:attach()
+    exec([[
+      call setline(1, ['a', 'bbbbb '->repeat(100), 'c'])
+      norm $j
+    ]])
+    screen:expect([[
+      <<
Date: Thu, 11 May 2023 20:37:49 +0200
Subject: vim-patch:9.0.1543: display errors when making topline shorter

Problem:    Display errors when making topline shorter and 'smoothscroll' is
            set.
Solution:   Reset w_skipcol when the topline becomes shorter than its current
            value. (Luuk van Baal, closes vim/vim#12367)

https://github.com/vim/vim/commit/5d01f86d99bc3a3fd92d4f4e9338a9e78e9ebe16
---
 test/functional/legacy/display_spec.lua    | 51 ++++++++++++++++++++++++++----
 test/functional/legacy/scroll_opt_spec.lua |  3 ++
 2 files changed, 48 insertions(+), 6 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index a698bed9f7..f59eac7674 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -200,13 +200,13 @@ describe('display', function()
     local screen = Screen.new(35, 14)
     screen:attach()
     exec([[
-      set display=lastline scrolloff=5
+      set display=lastline smoothscroll scrolloff=0
       call setline(1, [
-        \'aaaaa'->repeat(100),
+        \'aaaaa'->repeat(500),
         \'bbbbb '->repeat(7) .. 'ccccc '->repeat(7) .. 'ddddd '->repeat(7)
       \])
     ]])
-    feed('482|')
+    feed('736|')
     screen:expect([[
       <<repeat(10)) .. ' end', 'four'])")
+    -- Currently visible lines were replaced, test that the lines and cursor
+    -- are correctly displayed.
+    screen:expect_unchanged()
     feed('3Gztj')
     screen:expect_unchanged()
     -- Repeat the step but this time start it when the line is smooth-scrolled by
-- 
cgit 


From 5825d2f6cabc852dcbf5367d631b7c6cf4516d68 Mon Sep 17 00:00:00 2001
From: luukvbaal 
Date: Fri, 12 May 2023 02:17:38 +0200
Subject: test(scroll_opt): fix typo in porting oldtest (#23593)

---
 test/functional/legacy/display_spec.lua | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index f59eac7674..feb2662100 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -202,7 +202,7 @@ describe('display', function()
     exec([[
       set display=lastline smoothscroll scrolloff=0
       call setline(1, [
-        \'aaaaa'->repeat(500),
+        \'aaaaa'->repeat(150),
         \'bbbbb '->repeat(7) .. 'ccccc '->repeat(7) .. 'ddddd '->repeat(7)
       \])
     ]])
@@ -220,7 +220,7 @@ describe('display', function()
       aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
-      ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+      ^aaaaaaaaaaaaaaa                    |
                                          |
     ]])
     -- The correct part of the last line is moved into view.
-- 
cgit 


From ecd6d679a020ff97156de2fd3c443a77a671ac3d Mon Sep 17 00:00:00 2001
From: dundargoc <33953936+dundargoc@users.noreply.github.com>
Date: Sun, 14 May 2023 14:29:18 +0200
Subject: test: skip flaky test on Windows

---
 test/functional/terminal/buffer_spec.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'test/functional')

diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index b983ea89d5..fa587e9364 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -281,6 +281,7 @@ describe(':terminal buffer', function()
   end)
 
   it('requires bang (!) to close a running job #15402', function()
+    skip(is_os('win'), "Test freezes the CI and makes it time out")
     eq('Vim(wqall):E948: Job still running', exc_exec('wqall'))
     for _, cmd in ipairs({ 'bdelete', '%bdelete', 'bwipeout', 'bunload' }) do
       matches('^Vim%('..cmd:gsub('%%', '')..'%):E89: term://.*tty%-test.* will be killed %(add %! to override%)$',
-- 
cgit 


From 9ff59517cbf309d31f979a49b7dc82b237ecfcc4 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Sat, 13 May 2023 12:56:21 +0200
Subject: fix(treesitter): update c queries

---
 test/functional/treesitter/parser_spec.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 9afce0b3a0..60042ab2fd 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -483,7 +483,7 @@ end]]
     return list
     ]]
 
-    eq({ 'any-of?', 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list)
+    eq({ 'any-of?', 'contains?', 'eq?', 'has-ancestor?', 'has-parent?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list)
   end)
 
 
-- 
cgit 


From 5887ecab6ddd294f43ff3f2372149ce8c5f8dc7f Mon Sep 17 00:00:00 2001
From: luukvbaal 
Date: Tue, 16 May 2023 01:56:06 +0200
Subject: vim-patch:9.0.1561: display wrong when moving cursor to above the top
 line (#23644)

Problem:    Display wrong when moving cursor to above the top line and
            'smoothscroll' is set.
Solution:   Call adjust_skipcol() in more places and make it work better.
            (Luuk van Baal, closes vim/vim#12395)

https://github.com/vim/vim/commit/798fa76dbf737f855e47b10bf326453866b429ab
---
 test/functional/legacy/display_spec.lua | 55 ++++++++++++++++++++++++++++-----
 1 file changed, 47 insertions(+), 8 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua
index feb2662100..482b88eae8 100644
--- a/test/functional/legacy/display_spec.lua
+++ b/test/functional/legacy/display_spec.lua
@@ -286,17 +286,56 @@ describe('display', function()
     local screen = Screen.new(75, 8)
     screen:attach()
     exec([[
-      call setline(1, ['a', 'bbbbb '->repeat(100), 'c'])
+      call setline(1, ['a', 'b ' .. 'bbbbb'->repeat(150), 'c'])
       norm $j
     ]])
     screen:expect([[
-      <<
Date: Tue, 16 May 2023 16:41:47 +0100
Subject: fix(treesitter): correctly calculate bytes for text sources (#23655)

Fixes #20419
---
 test/functional/treesitter/parser_spec.lua | 56 +++++++++++++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index 60042ab2fd..14de07639b 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -486,7 +486,6 @@ end]]
     eq({ 'any-of?', 'contains?', 'eq?', 'has-ancestor?', 'has-parent?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list)
   end)
 
-
   it('allows to set simple ranges', function()
     insert(test_text)
 
@@ -528,6 +527,7 @@ end]]
 
     eq(range_tbl, { { { 0, 0, 0, 17, 1, 508 } } })
   end)
+
   it("allows to set complex ranges", function()
     insert(test_text)
 
@@ -992,4 +992,58 @@ int x = INT_MAX;
     }, run_query())
 
   end)
+
+  it('handles ranges when source is a multiline string (#20419)', function()
+    local source = [==[
+      vim.cmd[[
+        set number
+        set cmdheight=2
+        set lastsatus=2
+      ]]
+
+      set query = [[;; query
+        ((function_call
+          name: [
+            (identifier) @_cdef_identifier
+            (_ _ (identifier) @_cdef_identifier)
+          ]
+          arguments: (arguments (string content: _ @injection.content)))
+          (#set! injection.language "c")
+          (#eq? @_cdef_identifier "cdef"))
+      ]]
+    ]==]
+
+    local r = exec_lua([[
+      local parser = vim.treesitter.get_string_parser(..., 'lua')
+      parser:parse()
+      local ranges = {}
+      parser:for_each_tree(function(tstree, tree)
+        ranges[tree:lang()] = { tstree:root():range(true) }
+      end)
+      return ranges
+    ]], source)
+
+    eq({
+      lua = { 0, 6, 6, 16, 4, 438 },
+      query = { 6, 20, 113, 15, 6, 431 },
+      vim = { 1, 0, 16, 4, 6, 89 }
+    }, r)
+
+    -- The above ranges are provided directly from treesitter, however query directives may mutate
+    -- the ranges but only provide a Range4. Strip the byte entries from the ranges and make sure
+    -- add_bytes() produces the same result.
+
+    local rb = exec_lua([[
+      local r, source = ...
+      local add_bytes = require('vim.treesitter._range').add_bytes
+      for lang, range in pairs(r) do
+        r[lang] = {range[1], range[2], range[4], range[5]}
+        r[lang] = add_bytes(source, r[lang])
+      end
+      return r
+    ]], r, source)
+
+    eq(rb, r)
+
+  end)
 end)
-- 
cgit 


From c9f47fca8b896ecb304294cce675fedac9ab926c Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 17 May 2023 21:06:27 +0800
Subject: fix(messages): ensure msg_grid is at top at more prompt (#23584)

---
 test/functional/terminal/tui_spec.lua | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index b69867af89..352009a1b1 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -112,7 +112,7 @@ describe('TUI', function()
     child_session:request("nvim_exec", [[
     set more
     func! ManyErr()
-      for i in range(10)
+      for i in range(20)
         echoerr "FAIL ".i
       endfor
     endfunc
@@ -128,7 +128,35 @@ describe('TUI', function()
       {3:-- TERMINAL --}                                    |
     ]]}
 
-    feed_data('d')
+    screen:try_resize(50,10)
+    screen:expect{grid=[[
+      :call ManyErr()                                   |
+      {8:Error detected while processing function ManyErr:} |
+      {11:line    2:}                                        |
+      {8:FAIL 0}                                            |
+      {8:FAIL 1}                                            |
+      {8:FAIL 2}                                            |
+                                                        |
+                                                        |
+      {10:-- More --}{1: }                                       |
+      {3:-- TERMINAL --}                                    |
+    ]]}
+
+    feed_data('j')
+    screen:expect{grid=[[
+      {8:Error detected while processing function ManyErr:} |
+      {11:line    2:}                                        |
+      {8:FAIL 0}                                            |
+      {8:FAIL 1}                                            |
+      {8:FAIL 2}                                            |
+      {8:FAIL 3}                                            |
+      {8:FAIL 4}                                            |
+      {8:FAIL 5}                                            |
+      {10:-- More --}{1: }                                       |
+      {3:-- TERMINAL --}                                    |
+    ]]}
+
+    screen:try_resize(50,7)
     screen:expect{grid=[[
       {8:FAIL 1}                                            |
       {8:FAIL 2}                                            |
-- 
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')

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 02ef104d5bcd40c048e8011e0106f30389034674 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Fri, 19 May 2023 16:14:41 +0200
Subject: vim-patch:9.0.1564: display moves up and down with 'incsearch' and
 'smoothscroll'

Problem:    Display moves up and down with 'incsearch' and 'smoothscroll'.
Solution:   Do not check if w_skipcol changed. (Luuk van Baal, closes vim/vim#12410,
            closes vim/vim#12409)

https://github.com/vim/vim/commit/0222c2d103ad9298bec4dc8864cd80b4e7559db1
---
 test/functional/legacy/scroll_opt_spec.lua | 35 +++++++++++++++++++++++++++---
 1 file changed, 32 insertions(+), 3 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 838ada4006..056262939b 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -422,12 +422,41 @@ describe('smoothscroll', function()
                                               |
     ]])
     feed('j')
-    screen:expect_unchanged()
+    screen:expect([[
+      Line with some text with some text with |
+      some text with some text with some text |
+      with some text with some text           |
+      ^Line with some text with some text with |
+      some text with some text with some text |
+      with some text with some text           |
+      @                                       |
+                                              |
+    ]])
     -- moving cursor down - whole bottom line shows
     feed('j')
-    screen:expect_unchanged()
+    screen:expect([[
+      <<>> marker - no need to show whole line
     feed('2gj3l2k')
     screen:expect([[
-- 
cgit 


From cf0f83ebf0d74b11c1ffdc4d1066555f312a91ec Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Fri, 19 May 2023 18:42:54 +0200
Subject: vim-patch:9.0.1568: with 'smoothscroll' cursor may move below botline

Problem:    With 'smoothscroll' cursor may move below botline.
Solution:   Call redraw_later() if needed,  Compute cursor row with adjusted
            condition. (Luuk van Baal, closes vim/vim#12415)

https://github.com/vim/vim/commit/d49f646bf56b29d44bbb16e79bc877b59aab38ac
---
 test/functional/legacy/scroll_opt_spec.lua | 102 +++++++++++++++++++----------
 1 file changed, 68 insertions(+), 34 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua
index 056262939b..cd4c2fda8b 100644
--- a/test/functional/legacy/scroll_opt_spec.lua
+++ b/test/functional/legacy/scroll_opt_spec.lua
@@ -422,42 +422,15 @@ describe('smoothscroll', function()
                                               |
     ]])
     feed('j')
-    screen:expect([[
-      Line with some text with some text with |
-      some text with some text with some text |
-      with some text with some text           |
-      ^Line with some text with some text with |
-      some text with some text with some text |
-      with some text with some text           |
-      @                                       |
-                                              |
-    ]])
+    screen:expect_unchanged()
     -- moving cursor down - whole bottom line shows
     feed('j')
-    screen:expect([[
-      <<>> marker - no need to show whole line
+    screen:expect_unchanged()
+    feed('4G')
+    screen:expect_unchanged()
+    -- moving cursor up right after the <<< marker - no need to show whole line
     feed('2gj3l2k')
     screen:expect([[
       <<<^h some text with some text           |
@@ -469,7 +442,7 @@ describe('smoothscroll', function()
       with some text with some text           |
                                               |
     ]])
-    -- moving cursor up where the >>> marker is - whole top line shows
+    -- moving cursor up where the <<< marker is - whole top line shows
     feed('2j02k')
     screen:expect([[
       ^Line with some text with some text with |
@@ -805,6 +778,67 @@ describe('smoothscroll', function()
     ]])
   end)
 
+  -- oldtest: Test_smoothscroll_incsearch()
+  it("does not reset skipcol when doing incremental search on the same word", function()
+    screen:try_resize(40, 8)
+    screen:set_default_attr_ids({
+      [1] = {foreground = Screen.colors.Brown},
+      [2] = {foreground = Screen.colors.Blue1, bold = true},
+      [3] = {background = Screen.colors.Yellow1},
+      [4] = {reverse = true},
+    })
+    exec([[
+      set smoothscroll number scrolloff=0 incsearch
+      call setline(1, repeat([''], 20))
+      call setline(11, repeat('a', 100))
+      call setline(14, 'bbbb')
+    ]])
+    feed('/b')
+    screen:expect([[
+      {2:<<<}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaa        |
+      {1: 12 }                                    |
+      {1: 13 }                                    |
+      {1: 14 }{4:b}{3:bbb}                                |
+      {1: 15 }                                    |
+      {1: 16 }                                    |
+      {1: 17 }                                    |
+      /b^                                      |
+    ]])
+    feed('b')
+    screen:expect([[
+      {2:<<<}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaa        |
+      {1: 12 }                                    |
+      {1: 13 }                                    |
+      {1: 14 }{4:bb}{3:bb}                                |
+      {1: 15 }                                    |
+      {1: 16 }                                    |
+      {1: 17 }                                    |
+      /bb^                                     |
+    ]])
+    feed('b')
+    screen:expect([[
+      {2:<<<}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaa        |
+      {1: 12 }                                    |
+      {1: 13 }                                    |
+      {1: 14 }{4:bbb}b                                |
+      {1: 15 }                                    |
+      {1: 16 }                                    |
+      {1: 17 }                                    |
+      /bbb^                                    |
+    ]])
+    feed('b')
+    screen:expect([[
+      {2:<<<}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaa        |
+      {1: 12 }                                    |
+      {1: 13 }                                    |
+      {1: 14 }{4:bbbb}                                |
+      {1: 15 }                                    |
+      {1: 16 }                                    |
+      {1: 17 }                                    |
+      /bbbb^                                   |
+    ]])
+  end)
+
   it("works with virt_lines above and below", function()
     screen:try_resize(55, 7)
     exec([=[
-- 
cgit 


From 073035a030f5ef8ae9b9ca51552f887944c52eaa Mon Sep 17 00:00:00 2001
From: Jon Huhn 
Date: Sat, 20 May 2023 00:45:39 -0500
Subject: fix(lsp): don't register didChangeWatchedFiles when capability not
 set (#23689)

Some LSP servers (tailwindcss, rome) are known to request registration
for `workspace/didChangeWatchedFiles` even when the corresponding client
capability does not advertise support. This change adds an extra check
in the `client/registerCapability` handler not to start a watch unless
the client capability is set appropriately.
---
 test/functional/plugin/lsp_spec.lua | 84 +++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index fc7b2dafb8..506bc1333b 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -3778,6 +3778,13 @@ describe('LSP', function()
           name = 'watchfiles-test',
           cmd = server.cmd,
           root_dir = root_dir,
+          capabilities = {
+            workspace = {
+              didChangeWatchedFiles = {
+                dynamicRegistration = true,
+              },
+            },
+          },
         })
 
         local expected_messages = 2 -- initialize, initialized
@@ -3865,6 +3872,13 @@ describe('LSP', function()
           name = 'watchfiles-test',
           cmd = server.cmd,
           root_dir = root_dir,
+          capabilities = {
+            workspace = {
+              didChangeWatchedFiles = {
+                dynamicRegistration = true,
+              },
+            },
+          },
         })
 
         local expected_messages = 2 -- initialize, initialized
@@ -3982,6 +3996,13 @@ describe('LSP', function()
           name = 'watchfiles-test',
           cmd = server.cmd,
           root_dir = root_dir,
+          capabilities = {
+            workspace = {
+              didChangeWatchedFiles = {
+                dynamicRegistration = true,
+              },
+            },
+          },
         })
 
         local expected_messages = 2 -- initialize, initialized
@@ -4116,6 +4137,13 @@ describe('LSP', function()
           name = 'watchfiles-test',
           cmd = server.cmd,
           root_dir = root_dir,
+          capabilities = {
+            workspace = {
+              didChangeWatchedFiles = {
+                dynamicRegistration = true,
+              },
+            },
+          },
         })
 
         local expected_messages = 2 -- initialize, initialized
@@ -4186,5 +4214,61 @@ describe('LSP', function()
         },
       }, result[3].params)
     end)
+
+    it("ignores registrations by servers when the client doesn't advertise support", function()
+      exec_lua(create_server_definition)
+      local result = exec_lua([[
+        local server = _create_server()
+        local client_id = vim.lsp.start({
+          name = 'watchfiles-test',
+          cmd = server.cmd,
+          root_dir = 'some_dir',
+          capabilities = {
+            workspace = {
+              didChangeWatchedFiles = {
+                dynamicRegistration = false,
+              },
+            },
+          },
+        })
+
+        local watching = false
+        require('vim.lsp._watchfiles')._watchfunc = function(_, _, callback)
+          -- Since the registration is ignored, this should not execute and `watching` should stay false
+          watching = true
+          return function() end
+        end
+
+        vim.lsp.handlers['client/registerCapability'](nil, {
+          registrations = {
+            {
+              id = 'watchfiles-test-kind',
+              method = 'workspace/didChangeWatchedFiles',
+              registerOptions = {
+                watchers = {
+                  {
+                    globPattern = '**/*',
+                  },
+                },
+              },
+            },
+          },
+        }, { client_id = client_id })
+
+        -- Ensure no errors occur when unregistering something that was never really registered.
+        vim.lsp.handlers['client/unregisterCapability'](nil, {
+          unregisterations = {
+            {
+              id = 'watchfiles-test-kind',
+              method = 'workspace/didChangeWatchedFiles',
+            },
+          },
+        }, { client_id = client_id })
+
+        return watching
+      ]])
+
+      eq(false, result)
+    end)
   end)
 end)
-- 
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')

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/api/buffer_spec.lua                | 24 +++---
 test/functional/api/extmark_spec.lua               |  4 +-
 test/functional/api/highlight_spec.lua             |  4 +-
 test/functional/api/vim_spec.lua                   | 88 ++++++++++------------
 test/functional/api/window_spec.lua                | 26 +++----
 test/functional/autocmd/autocmd_spec.lua           |  2 +-
 test/functional/autocmd/cursorhold_spec.lua        |  6 +-
 test/functional/autocmd/termxx_spec.lua            | 14 ++--
 test/functional/core/spellfile_spec.lua            | 20 ++---
 test/functional/core/startup_spec.lua              |  6 +-
 test/functional/editor/K_spec.lua                  |  2 +-
 test/functional/editor/completion_spec.lua         |  2 +-
 test/functional/editor/mode_cmdline_spec.lua       |  2 +-
 test/functional/ex_cmds/append_spec.lua            |  3 +-
 test/functional/ex_cmds/ls_spec.lua                |  2 +-
 test/functional/ex_cmds/make_spec.lua              |  4 +-
 test/functional/ex_cmds/map_spec.lua               |  2 +-
 test/functional/ex_cmds/mksession_spec.lua         | 14 ++--
 test/functional/ex_cmds/source_spec.lua            |  2 +-
 test/functional/ex_cmds/verbose_spec.lua           |  4 +-
 test/functional/ex_cmds/write_spec.lua             |  8 +-
 test/functional/legacy/012_directory_spec.lua      | 13 ++--
 test/functional/legacy/autocmd_option_spec.lua     | 12 +--
 test/functional/legacy/buffer_spec.lua             |  2 +-
 test/functional/legacy/cmdline_spec.lua            | 14 ++--
 test/functional/legacy/filechanged_spec.lua        |  4 +-
 test/functional/legacy/messages_spec.lua           |  6 +-
 test/functional/legacy/vimscript_spec.lua          |  2 +-
 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 +++++++--------
 test/functional/options/defaults_spec.lua          | 64 ++++++++--------
 test/functional/options/num_options_spec.lua       | 22 +++---
 test/functional/plugin/editorconfig_spec.lua       |  3 +-
 .../plugin/lsp/incremental_sync_spec.lua           |  2 +-
 test/functional/plugin/lsp_spec.lua                | 20 ++---
 test/functional/plugin/shada_spec.lua              | 30 ++++----
 test/functional/provider/perl_spec.lua             |  4 +-
 test/functional/provider/ruby_spec.lua             |  3 +-
 test/functional/shada/buffers_spec.lua             |  8 +-
 test/functional/shada/history_spec.lua             |  8 +-
 test/functional/shada/shada_spec.lua               | 34 ++++-----
 test/functional/terminal/buffer_spec.lua           |  2 +-
 test/functional/terminal/edit_spec.lua             |  6 +-
 test/functional/terminal/ex_terminal_spec.lua      | 10 +--
 test/functional/terminal/mouse_spec.lua            |  4 +-
 test/functional/terminal/scrollback_spec.lua       | 46 +++++------
 test/functional/terminal/tui_spec.lua              | 10 +--
 test/functional/terminal/window_split_tab_spec.lua |  4 +-
 test/functional/ui/cmdline_highlight_spec.lua      |  2 +-
 test/functional/ui/cursor_spec.lua                 |  8 +-
 test/functional/ui/decorations_spec.lua            |  6 +-
 test/functional/ui/float_spec.lua                  | 52 ++++++-------
 test/functional/ui/fold_spec.lua                   |  4 +-
 test/functional/ui/inccommand_spec.lua             | 23 +++---
 test/functional/ui/inccommand_user_spec.lua        |  2 +-
 test/functional/ui/messages_spec.lua               |  2 +-
 test/functional/ui/mouse_spec.lua                  | 26 +++----
 test/functional/ui/multigrid_spec.lua              |  6 +-
 test/functional/ui/quickfix_spec.lua               |  2 +-
 test/functional/ui/screen_basic_spec.lua           | 10 +--
 test/functional/ui/statusline_spec.lua             | 56 +++++++-------
 test/functional/ui/title_spec.lua                  |  8 +-
 test/functional/ui/wildmode_spec.lua               | 20 ++---
 test/functional/ui/winbar_spec.lua                 |  8 +-
 test/functional/vimscript/api_functions_spec.lua   |  4 +-
 test/functional/vimscript/buf_functions_spec.lua   | 22 +++---
 test/functional/vimscript/input_spec.lua           |  4 +-
 test/functional/vimscript/json_functions_spec.lua  |  2 +-
 test/functional/vimscript/system_spec.lua          |  4 +-
 75 files changed, 460 insertions(+), 481 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index d454765edb..df9092fa14 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -630,19 +630,19 @@ describe('api/buf', function()
       eq('Index out of bounds', pcall_err(get_offset, 6))
       eq('Index out of bounds', pcall_err(get_offset, -1))
 
-      curbufmeths.set_option('eol', false)
-      curbufmeths.set_option('fixeol', false)
+      meths.set_option_value('eol', false, {buf=0})
+      meths.set_option_value('fixeol', false, {buf=0})
       eq(28, get_offset(5))
 
       -- fileformat is ignored
-      curbufmeths.set_option('fileformat', 'dos')
+      meths.set_option_value('fileformat', 'dos', {buf=0})
       eq(0, get_offset(0))
       eq(6, get_offset(1))
       eq(15, get_offset(2))
       eq(16, get_offset(3))
       eq(24, get_offset(4))
       eq(28, get_offset(5))
-      curbufmeths.set_option('eol', true)
+      meths.set_option_value('eol', true, {buf=0})
       eq(29, get_offset(5))
 
       command("set hidden")
@@ -697,23 +697,23 @@ describe('api/buf', function()
     end)
   end)
 
-  describe('nvim_buf_get_option, nvim_buf_set_option', function()
+  describe('nvim_get_option_value, nvim_set_option_value', function()
     it('works', function()
-      eq(8, curbuf('get_option', 'shiftwidth'))
-      curbuf('set_option', 'shiftwidth', 4)
-      eq(4, curbuf('get_option', 'shiftwidth'))
+      eq(8, nvim('get_option_value', 'shiftwidth', {buf = 0}))
+      nvim('set_option_value', 'shiftwidth', 4, {buf=0})
+      eq(4, nvim('get_option_value', 'shiftwidth', {buf = 0}))
       -- global-local option
-      curbuf('set_option', 'define', 'test')
-      eq('test', curbuf('get_option', 'define'))
+      nvim('set_option_value', 'define', 'test', {buf = 0})
+      eq('test', nvim('get_option_value', 'define', {buf = 0}))
       -- Doesn't change the global value
-      eq([[^\s*#\s*define]], nvim('get_option', 'define'))
+      eq([[^\s*#\s*define]], nvim('get_option_value', 'define', {scope='global'}))
     end)
 
     it('returns values for unset local options', function()
       -- 'undolevels' is only set to its "unset" value when a new buffer is
       -- created
       command('enew')
-      eq(-123456, curbuf('get_option', 'undolevels'))
+      eq(-123456, nvim('get_option_value', 'undolevels', {buf=0}))
     end)
   end)
 
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index e30ffc92b6..0960e910f1 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -1401,7 +1401,7 @@ describe('API/extmarks', function()
 
   it('in read-only buffer', function()
     command("view! runtime/doc/help.txt")
-    eq(true, curbufmeths.get_option('ro'))
+    eq(true, meths.get_option_value('ro', {buf=0}))
     local id = set_extmark(ns, 0, 0, 2)
     eq({{id, 0, 2}}, get_extmarks(ns,0, -1))
   end)
@@ -1474,7 +1474,7 @@ describe('API/extmarks', function()
   it('in prompt buffer', function()
     feed('dd')
     local id = set_extmark(ns, marks[1], 0, 0, {})
-    curbufmeths.set_option('buftype', 'prompt')
+    meths.set_option_value('buftype', 'prompt', {buf = 0})
     feed('i')
     eq({{id, 0, 2}}, get_extmarks(ns, 0, -1))
   end)
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index a6e9f9a42b..1601184e1b 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -155,9 +155,9 @@ describe('API: highlight',function()
 
   it("nvim_buf_add_highlight to other buffer doesn't crash if undo is disabled #12873", function()
     command('vsplit file')
-    local err, _ = pcall(meths.buf_set_option, 1, 'undofile', false)
+    local err, _ = pcall(meths.set_option_value, 'undofile', false, { buf = 1 })
     eq(true, err)
-    err, _ = pcall(meths.buf_set_option, 1, 'undolevels', -1)
+    err, _ = pcall(meths.set_option_value, 'undolevels', -1, { buf = 1 })
     eq(true, err)
     err, _ = pcall(meths.buf_add_highlight, 1, -1, 'Question', 0, 0, -1)
     eq(true, err)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index c81b6e90cc..5b8b52a559 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -1051,7 +1051,7 @@ describe('API', function()
         line 3
         ]])
       eq({0,4,1,0}, funcs.getpos('.'))  -- Cursor follows the paste.
-      eq(false, nvim('get_option', 'paste'))
+      eq(false, nvim('get_option_value', 'paste', {}))
       command('%delete _')
       -- Without final "\n".
       nvim('paste', 'line 1\nline 2\nline 3', true, -1)
@@ -1091,7 +1091,7 @@ describe('API', function()
       nvim('paste', 'line 1\r\n\r\rline 2\nline 3\rline 4\r', true, -1)
       expect('line 1\n\n\nline 2\nline 3\nline 4\n')
       eq({0,7,1,0}, funcs.getpos('.'))
-      eq(false, nvim('get_option', 'paste'))
+      eq(false, nvim('get_option_value', 'paste', {}))
     end)
     it('Replace-mode', function()
       -- Within single line
@@ -1382,44 +1382,38 @@ describe('API', function()
     end)
   end)
 
-  describe('nvim_get_option, nvim_set_option', function()
+  describe('nvim_get_option_value, nvim_set_option_value', function()
     it('works', function()
-      ok(nvim('get_option', 'equalalways'))
-      nvim('set_option', 'equalalways', false)
-      ok(not nvim('get_option', 'equalalways'))
+      ok(nvim('get_option_value', 'equalalways', {}))
+      nvim('set_option_value', 'equalalways', false, {})
+      ok(not nvim('get_option_value', 'equalalways', {}))
     end)
 
     it('works to get global value of local options', function()
-      eq(false, nvim('get_option', 'lisp'))
-      eq(8, nvim('get_option', 'shiftwidth'))
+      eq(false, nvim('get_option_value', 'lisp', {}))
+      eq(8, nvim('get_option_value', 'shiftwidth', {}))
     end)
 
     it('works to set global value of local options', function()
-      nvim('set_option', 'lisp', true)
-      eq(true, nvim('get_option', 'lisp'))
-      eq(false, helpers.curbuf('get_option', 'lisp'))
+      nvim('set_option_value', 'lisp', true, {scope='global'})
+      eq(true, nvim('get_option_value', 'lisp', {scope='global'}))
+      eq(false, nvim('get_option_value', 'lisp', {buf=0}))
       eq(nil, nvim('command_output', 'setglobal lisp?'):match('nolisp'))
       eq('nolisp', nvim('command_output', 'setlocal lisp?'):match('nolisp'))
-      nvim('set_option', 'shiftwidth', 20)
+      nvim('set_option_value', 'shiftwidth', 20, {scope='global'})
       eq('20', nvim('command_output', 'setglobal shiftwidth?'):match('%d+'))
       eq('8', nvim('command_output', 'setlocal shiftwidth?'):match('%d+'))
     end)
 
-    it('most window-local options have no global value', function()
-      local status, err = pcall(nvim, 'get_option', 'foldcolumn')
-      eq(false, status)
-      ok(err:match('Invalid option name') ~= nil)
-    end)
-
     it('updates where the option was last set from', function()
-      nvim('set_option', 'equalalways', false)
+      nvim('set_option_value', 'equalalways', false, {})
       local status, rv = pcall(nvim, 'command_output',
         'verbose set equalalways?')
       eq(true, status)
       ok(nil ~= string.find(rv, 'noequalalways\n'..
         '\tLast set from API client %(channel id %d+%)'))
 
-      nvim('exec_lua', 'vim.api.nvim_set_option("equalalways", true)', {})
+      nvim('exec_lua', 'vim.api.nvim_set_option_value("equalalways", true, {})', {})
       status, rv = pcall(nvim, 'command_output',
         'verbose set equalalways?')
       eq(true, status)
@@ -1499,7 +1493,6 @@ describe('API', function()
     end)
 
     it('set window options', function()
-      -- Same as to nvim_win_set_option
       nvim('set_option_value', 'colorcolumn', '4,3', {win=0})
       eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'}))
       command("set modified hidden")
@@ -1508,7 +1501,6 @@ describe('API', function()
     end)
 
     it('set local window options', function()
-      -- Different to nvim_win_set_option
       nvim('set_option_value', 'colorcolumn', '4,3', {win=0, scope='local'})
       eq('4,3', nvim('get_option_value', 'colorcolumn', {win = 0, scope = 'local'}))
       command("set modified hidden")
@@ -1519,11 +1511,11 @@ describe('API', function()
     it('get buffer or window-local options', function()
       nvim('command', 'new')
       local buf = nvim('get_current_buf').id
-      nvim('buf_set_option', buf, 'tagfunc', 'foobar')
+      nvim('set_option_value', 'tagfunc', 'foobar', {buf=buf})
       eq('foobar', nvim('get_option_value', 'tagfunc', {buf = buf}))
 
       local win = nvim('get_current_win').id
-      nvim('win_set_option', win, 'number', true)
+      nvim('set_option_value', 'number', true, {win=win})
       eq(true, nvim('get_option_value', 'number', {win = win}))
     end)
 
@@ -2215,7 +2207,7 @@ describe('API', function()
     it('stream=job :terminal channel', function()
       command(':terminal')
       eq({id=1}, meths.get_current_buf())
-      eq(3, meths.buf_get_option(1, 'channel'))
+      eq(3, meths.get_option_value('channel', {buf=1}))
 
       local info = {
         stream='job',
@@ -2368,45 +2360,45 @@ describe('API', function()
     end)
 
     it('returns nothing with empty &runtimepath', function()
-      meths.set_option('runtimepath', '')
+      meths.set_option_value('runtimepath', '', {})
       eq({}, meths.list_runtime_paths())
     end)
     it('returns single runtimepath', function()
-      meths.set_option('runtimepath', 'a')
+      meths.set_option_value('runtimepath', 'a', {})
       eq({'a'}, meths.list_runtime_paths())
     end)
     it('returns two runtimepaths', function()
-      meths.set_option('runtimepath', 'a,b')
+      meths.set_option_value('runtimepath', 'a,b', {})
       eq({'a', 'b'}, meths.list_runtime_paths())
     end)
     it('returns empty strings when appropriate', function()
-      meths.set_option('runtimepath', 'a,,b')
+      meths.set_option_value('runtimepath', 'a,,b', {})
       eq({'a', '', 'b'}, meths.list_runtime_paths())
-      meths.set_option('runtimepath', ',a,b')
+      meths.set_option_value('runtimepath', ',a,b', {})
       eq({'', 'a', 'b'}, meths.list_runtime_paths())
       -- Trailing "," is ignored. Use ",," if you really really want CWD.
-      meths.set_option('runtimepath', 'a,b,')
+      meths.set_option_value('runtimepath', 'a,b,', {})
       eq({'a', 'b'}, meths.list_runtime_paths())
-      meths.set_option('runtimepath', 'a,b,,')
+      meths.set_option_value('runtimepath', 'a,b,,', {})
       eq({'a', 'b', ''}, meths.list_runtime_paths())
     end)
     it('truncates too long paths', function()
       local long_path = ('/a'):rep(8192)
-      meths.set_option('runtimepath', long_path)
+      meths.set_option_value('runtimepath', long_path, {})
       local paths_list = meths.list_runtime_paths()
       eq({}, paths_list)
     end)
   end)
 
   it('can throw exceptions', function()
-    local status, err = pcall(nvim, 'get_option', 'invalid-option')
+    local status, err = pcall(nvim, 'get_option_value', 'invalid-option', {})
     eq(false, status)
-    ok(err:match('Invalid option name') ~= nil)
+    ok(err:match("Invalid 'option': 'invalid%-option'") ~= nil)
   end)
 
   it('does not truncate error message <1 MB #5984', function()
     local very_long_name = 'A'..('x'):rep(10000)..'Z'
-    local status, err = pcall(nvim, 'get_option', very_long_name)
+    local status, err = pcall(nvim, 'get_option_value', very_long_name, {})
     eq(false, status)
     eq(very_long_name, err:match('Ax+Z?'))
   end)
@@ -2419,7 +2411,7 @@ describe('API', function()
 
   describe('nvim_parse_expression', function()
     before_each(function()
-      meths.set_option('isident', '')
+      meths.set_option_value('isident', '', {})
     end)
 
     local function simplify_east_api_node(line, east_api_node)
@@ -2704,9 +2696,9 @@ describe('API', function()
     end)
 
     it('can change buftype before visiting', function()
-      meths.set_option("hidden", false)
+      meths.set_option_value("hidden", false, {})
       eq({id=2}, meths.create_buf(true, false))
-      meths.buf_set_option(2, "buftype", "nofile")
+      meths.set_option_value("buftype", "nofile", {buf=2})
       meths.buf_set_lines(2, 0, -1, true, {"test text"})
       command("split | buffer 2")
       eq({id=2}, meths.get_current_buf())
@@ -2749,10 +2741,10 @@ describe('API', function()
       local edited_buf = 2
       meths.buf_set_lines(edited_buf, 0, -1, true, {"some text"})
       for _,b in ipairs(scratch_bufs) do
-        eq('nofile', meths.buf_get_option(b, 'buftype'))
-        eq('hide', meths.buf_get_option(b, 'bufhidden'))
-        eq(false, meths.buf_get_option(b, 'swapfile'))
-        eq(false, meths.buf_get_option(b, 'modeline'))
+        eq('nofile', meths.get_option_value('buftype', {buf=b}))
+        eq('hide', meths.get_option_value('bufhidden', {buf=b}))
+        eq(false, meths.get_option_value('swapfile', {buf=b}))
+        eq(false, meths.get_option_value('modeline', {buf=b}))
       end
 
       --
@@ -2765,10 +2757,10 @@ describe('API', function()
         {1:~                   }|
                             |
       ]])
-      eq('nofile', meths.buf_get_option(edited_buf, 'buftype'))
-      eq('hide', meths.buf_get_option(edited_buf, 'bufhidden'))
-      eq(false, meths.buf_get_option(edited_buf, 'swapfile'))
-      eq(false, meths.buf_get_option(edited_buf, 'modeline'))
+      eq('nofile', meths.get_option_value('buftype', {buf=edited_buf}))
+      eq('hide', meths.get_option_value('bufhidden', {buf=edited_buf}))
+      eq(false, meths.get_option_value('swapfile', {buf=edited_buf}))
+      eq(false, meths.get_option_value('modeline', {buf=edited_buf}))
 
       -- Scratch buffer can be wiped without error.
       command('bwipe')
@@ -2899,7 +2891,7 @@ describe('API', function()
     it('should have information about global options', function()
       -- precondition: the option was changed from its default
       -- in test setup.
-      eq(false, meths.get_option'showcmd')
+      eq(false, meths.get_option_value('showcmd', {}))
 
       eq({
         allows_duplicates = true,
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index ecab6a4713..660fa4731e 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -363,22 +363,22 @@ describe('API/win', function()
     end)
   end)
 
-  describe('nvim_win_get_option, nvim_win_set_option', function()
+  describe('nvim_get_option_value, nvim_set_option_value', function()
     it('works', function()
-      curwin('set_option', 'colorcolumn', '4,3')
-      eq('4,3', curwin('get_option', 'colorcolumn'))
+      nvim('set_option_value', 'colorcolumn', '4,3', {win=0})
+      eq('4,3', nvim('get_option_value', 'colorcolumn', {win = 0}))
       command("set modified hidden")
       command("enew") -- edit new buffer, window option is preserved
-      eq('4,3', curwin('get_option', 'colorcolumn'))
+      eq('4,3', nvim('get_option_value', 'colorcolumn', {win = 0}))
 
       -- global-local option
-      curwin('set_option', 'statusline', 'window-status')
-      eq('window-status', curwin('get_option', 'statusline'))
-      eq('', nvim('get_option', 'statusline'))
+      nvim('set_option_value', 'statusline', 'window-status', {win=0})
+      eq('window-status', nvim('get_option_value', 'statusline', {win=0}))
+      eq('', nvim('get_option_value', 'statusline', {scope='global'}))
       command("set modified")
       command("enew") -- global-local: not preserved in new buffer
       -- confirm local value was not copied
-      eq('', curwin('get_option', 'statusline'))
+      eq('', nvim('get_option_value', 'statusline', {win = 0}))
       eq('', eval('&l:statusline'))
     end)
 
@@ -386,16 +386,16 @@ describe('API/win', function()
       nvim('command', 'tabnew')
       local tab1 = unpack(nvim('list_tabpages'))
       local win1 = unpack(tabpage('list_wins', tab1))
-      window('set_option', win1, 'statusline', 'window-status')
+      nvim('set_option_value', 'statusline', 'window-status', {win=win1.id})
       nvim('command', 'split')
       nvim('command', 'wincmd J')
       nvim('command', 'wincmd j')
-      eq('window-status', window('get_option', win1, 'statusline'))
+      eq('window-status', nvim('get_option_value', 'statusline', {win = win1.id}))
       assert_alive()
     end)
 
     it('returns values for unset local options', function()
-      eq(-1, curwin('get_option', 'scrolloff'))
+      eq(-1, nvim('get_option_value', 'scrolloff', {win=0, scope='local'}))
     end)
   end)
 
@@ -568,11 +568,11 @@ describe('API/win', function()
     it('deletes the buffer when bufhidden=wipe', function()
       local oldwin = meths.get_current_win()
       local oldbuf = meths.get_current_buf()
-      local buf = meths.create_buf(true, false)
+      local buf = meths.create_buf(true, false).id
       local newwin = meths.open_win(buf, true, {
         relative='win', row=3, col=3, width=12, height=3
       })
-      meths.buf_set_option(buf, 'bufhidden', 'wipe')
+      meths.set_option_value('bufhidden', 'wipe', {buf=buf})
       meths.win_hide(newwin)
       eq({oldwin}, meths.list_wins())
       eq({oldbuf}, meths.list_bufs())
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index da8c7b5ee0..63a487c8bc 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -141,7 +141,7 @@ describe('autocmd', function()
   describe('BufLeave autocommand', function()
     it('can wipe out the buffer created by :edit which triggered autocmd',
     function()
-      meths.set_option('hidden', true)
+      meths.set_option_value('hidden', true, {})
       curbufmeths.set_lines(0, 1, false, {
         'start of test file xx',
         'end of test file xx'})
diff --git a/test/functional/autocmd/cursorhold_spec.lua b/test/functional/autocmd/cursorhold_spec.lua
index b04bd5233a..e6bcb19682 100644
--- a/test/functional/autocmd/cursorhold_spec.lua
+++ b/test/functional/autocmd/cursorhold_spec.lua
@@ -26,7 +26,7 @@ describe('CursorHold', function()
       -- if testing with small 'updatetime' fails, double its value and test again
       retry(10, nil, function()
         ut = ut * 2
-        meths.set_option('updatetime', ut)
+        meths.set_option_value('updatetime', ut, {})
         feed('0')  -- reset did_cursorhold
         meths.set_var('cursorhold', 0)
         sleep(ut / 4)
@@ -51,12 +51,12 @@ describe('CursorHold', function()
   end)
 
   it("reducing 'updatetime' while waiting for CursorHold #20241", function()
-    meths.set_option('updatetime', 10000)
+    meths.set_option_value('updatetime', 10000, {})
     feed('0')  -- reset did_cursorhold
     meths.set_var('cursorhold', 0)
     sleep(50)
     eq(0, meths.get_var('cursorhold'))
-    meths.set_option('updatetime', 20)
+    meths.set_option_value('updatetime', 20, {})
     sleep(10)
     eq(1, meths.get_var('cursorhold'))
   end)
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
index a9980dda04..9ec1469c03 100644
--- a/test/functional/autocmd/termxx_spec.lua
+++ b/test/functional/autocmd/termxx_spec.lua
@@ -16,14 +16,14 @@ local is_os = helpers.is_os
 describe('autocmd TermClose', function()
   before_each(function()
     clear()
-    nvim('set_option', 'shell', testprg('shell-test'))
+    nvim('set_option_value', 'shell', testprg('shell-test'), {})
     command('set shellcmdflag=EXE shellredir= shellpipe= shellquote= shellxquote=')
   end)
 
 
   local function test_termclose_delete_own_buf()
     -- The terminal process needs to keep running so that TermClose isn't triggered immediately.
-    nvim('set_option', 'shell', string.format('"%s" INTERACT', testprg('shell-test')))
+    nvim('set_option_value', 'shell', string.format('"%s" INTERACT', testprg('shell-test')), {})
     command('autocmd TermClose * bdelete!')
     command('terminal')
     matches('^TermClose Autocommands for "%*": Vim%(bdelete%):E937: Attempt to delete a buffer that is in use: term://',
@@ -51,7 +51,7 @@ describe('autocmd TermClose', function()
 
   it('triggers when long-running terminal job gets stopped', function()
     skip(is_os('win'))
-    nvim('set_option', 'shell', is_os('win') and 'cmd.exe' or 'sh')
+    nvim('set_option_value', 'shell', is_os('win') and 'cmd.exe' or 'sh', {})
     command('autocmd TermClose * let g:test_termclose = 23')
     command('terminal')
     command('call jobstop(b:terminal_job_id)')
@@ -60,8 +60,8 @@ describe('autocmd TermClose', function()
 
   it('kills job trapping SIGTERM', function()
     skip(is_os('win'))
-    nvim('set_option', 'shell', 'sh')
-    nvim('set_option', 'shellcmdflag', '-c')
+    nvim('set_option_value', 'shell', 'sh', {})
+    nvim('set_option_value', 'shellcmdflag', '-c', {})
     command([[ let g:test_job = jobstart('trap "" TERM && echo 1 && sleep 60', { ]]
       .. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]]
       .. [[ 'on_exit': {-> execute('let g:test_job_exited = 1')}}) ]])
@@ -80,8 +80,8 @@ describe('autocmd TermClose', function()
 
   it('kills PTY job trapping SIGHUP and SIGTERM', function()
     skip(is_os('win'))
-    nvim('set_option', 'shell', 'sh')
-    nvim('set_option', 'shellcmdflag', '-c')
+    nvim('set_option_value', 'shell', 'sh', {})
+    nvim('set_option_value', 'shellcmdflag', '-c', {})
     command([[ let g:test_job = jobstart('trap "" HUP TERM && echo 1 && sleep 60', { ]]
       .. [[ 'pty': 1,]]
       .. [[ 'on_stdout': {-> execute('let g:test_job_started = 1')}, ]]
diff --git a/test/functional/core/spellfile_spec.lua b/test/functional/core/spellfile_spec.lua
index 378899eece..e3a59085cf 100644
--- a/test/functional/core/spellfile_spec.lua
+++ b/test/functional/core/spellfile_spec.lua
@@ -24,7 +24,7 @@ describe('spellfile', function()
   --                   │       ┌ Spell file version (#VIMSPELLVERSION)
   local spellheader = 'VIMspell\050'
   it('errors out when prefcond section is truncated', function()
-    meths.set_option('runtimepath', testdir)
+    meths.set_option_value('runtimepath', testdir, {})
     write_file(testdir .. '/spell/en.ascii.spl',
     --                         ┌ Section identifier (#SN_PREFCOND)
     --                         │   ┌ Section flags (#SNF_REQUIRED or zero)
@@ -34,12 +34,12 @@ describe('spellfile', function()
     --             │       ┌ Condition length (1 byte)
     --             │       │   ┌ Condition regex (missing!)
                .. '\000\001\001')
-    meths.set_option('spelllang', 'en')
+    meths.set_option_value('spelllang', 'en', {})
     eq('Vim(set):E758: Truncated spell file',
        exc_exec('set spell'))
   end)
   it('errors out when prefcond regexp contains NUL byte', function()
-    meths.set_option('runtimepath', testdir)
+    meths.set_option_value('runtimepath', testdir, {})
     write_file(testdir .. '/spell/en.ascii.spl',
     --                         ┌ Section identifier (#SN_PREFCOND)
     --                         │   ┌ Section flags (#SNF_REQUIRED or zero)
@@ -54,12 +54,12 @@ describe('spellfile', function()
     --             │               ┌ KWORDTREE tree length (4 bytes)
     --             │               │               ┌ PREFIXTREE tree length
                .. '\000\000\000\000\000\000\000\000\000\000\000\000')
-    meths.set_option('spelllang', 'en')
+    meths.set_option_value('spelllang', 'en', {})
     eq('Vim(set):E759: Format error in spell file',
        exc_exec('set spell'))
   end)
   it('errors out when region contains NUL byte', function()
-    meths.set_option('runtimepath', testdir)
+    meths.set_option_value('runtimepath', testdir, {})
     write_file(testdir .. '/spell/en.ascii.spl',
     --                         ┌ Section identifier (#SN_REGION)
     --                         │   ┌ Section flags (#SNF_REQUIRED or zero)
@@ -71,12 +71,12 @@ describe('spellfile', function()
     --             │               ┌ KWORDTREE tree length (4 bytes)
     --             │               │               ┌ PREFIXTREE tree length
                .. '\000\000\000\000\000\000\000\000\000\000\000\000')
-    meths.set_option('spelllang', 'en')
+    meths.set_option_value('spelllang', 'en', {})
     eq('Vim(set):E759: Format error in spell file',
        exc_exec('set spell'))
   end)
   it('errors out when SAL section contains NUL byte', function()
-    meths.set_option('runtimepath', testdir)
+    meths.set_option_value('runtimepath', testdir, {})
     write_file(testdir .. '/spell/en.ascii.spl',
     --                         ┌ Section identifier (#SN_SAL)
     --                         │   ┌ Section flags (#SNF_REQUIRED or zero)
@@ -95,15 +95,15 @@ describe('spellfile', function()
     --             │               ┌ KWORDTREE tree length (4 bytes)
     --             │               │               ┌ PREFIXTREE tree length
                .. '\000\000\000\000\000\000\000\000\000\000\000\000')
-    meths.set_option('spelllang', 'en')
+    meths.set_option_value('spelllang', 'en', {})
     eq('Vim(set):E759: Format error in spell file',
        exc_exec('set spell'))
   end)
   it('errors out when spell header contains NUL bytes', function()
-    meths.set_option('runtimepath', testdir)
+    meths.set_option_value('runtimepath', testdir, {})
     write_file(testdir .. '/spell/en.ascii.spl',
                spellheader:sub(1, -3) .. '\000\000')
-    meths.set_option('spelllang', 'en')
+    meths.set_option_value('spelllang', 'en', {})
     eq('Vim(set):E757: This does not look like a spell file',
        exc_exec('set spell'))
   end)
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index b8a3c1dcd5..fe1b8e1c4e 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -40,9 +40,9 @@ end)
 describe('startup', function()
   it('--clean', function()
     clear()
-    ok(string.find(alter_slashes(meths.get_option('runtimepath')), funcs.stdpath('config'), 1, true) ~= nil)
+    ok(string.find(alter_slashes(meths.get_option_value('runtimepath', {})), funcs.stdpath('config'), 1, true) ~= nil)
     clear('--clean')
-    ok(string.find(alter_slashes(meths.get_option('runtimepath')), funcs.stdpath('config'), 1, true) == nil)
+    ok(string.find(alter_slashes(meths.get_option_value('runtimepath', {})), funcs.stdpath('config'), 1, true) == nil)
   end)
 
   it('--startuptime', function()
@@ -589,7 +589,7 @@ describe('startup', function()
     ]]
     eq({'ordinary', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
 
-    local rtp = meths.get_option'rtp'
+    local rtp = meths.get_option_value('rtp', {})
     ok(startswith(rtp, 'test/functional/fixtures/nvim,test/functional/fixtures/pack/*/start/*,test/functional/fixtures/start/*,test/functional/fixtures,test/functional/fixtures/middle,'),
       'startswith(…)', 'rtp='..rtp)
   end)
diff --git a/test/functional/editor/K_spec.lua b/test/functional/editor/K_spec.lua
index 3b5580540f..b964fb3467 100644
--- a/test/functional/editor/K_spec.lua
+++ b/test/functional/editor/K_spec.lua
@@ -59,7 +59,7 @@ describe('K', function()
   end)
 
   it('empty string falls back to :help #19298', function()
-    meths.set_option('keywordprg', '')
+    meths.set_option_value('keywordprg', '', {})
     meths.buf_set_lines(0, 0, -1, true, {'doesnotexist'})
     feed('K')
     eq('E149: Sorry, no help for doesnotexist', meths.get_vvar('errmsg'))
diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua
index 22857efe5b..dcd7ef720f 100644
--- a/test/functional/editor/completion_spec.lua
+++ b/test/functional/editor/completion_spec.lua
@@ -988,7 +988,7 @@ describe('completion', function()
           return ''
         endfunction
       ]])
-      meths.set_option('completeopt', 'menuone,noselect')
+      meths.set_option_value('completeopt', 'menuone,noselect', {})
       meths.set_var('_complist', {{
         word=0,
         abbr=1,
diff --git a/test/functional/editor/mode_cmdline_spec.lua b/test/functional/editor/mode_cmdline_spec.lua
index 50cc5e17ee..fcd75ae3b6 100644
--- a/test/functional/editor/mode_cmdline_spec.lua
+++ b/test/functional/editor/mode_cmdline_spec.lua
@@ -55,7 +55,7 @@ describe('cmdline', function()
     it('correctly clears end of the history', function()
       -- Regression test: check absence of the memory leak when clearing end of
       -- the history using ex_getln.c/clr_history().
-      meths.set_option('history', 1)
+      meths.set_option_value('history', 1, {})
       eq(1, funcs.histadd(':', 'foo'))
       eq(1, funcs.histdel(':'))
       eq('', funcs.histget(':', -1))
diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua
index fadb5c9b42..e3a39384a6 100644
--- a/test/functional/ex_cmds/append_spec.lua
+++ b/test/functional/ex_cmds/append_spec.lua
@@ -8,6 +8,7 @@ local clear = helpers.clear
 local funcs = helpers.funcs
 local command = helpers.command
 local curbufmeths = helpers.curbufmeths
+local meths = helpers.meths
 local Screen = require('test.functional.ui.screen')
 
 local cmdtest = function(cmd, prep, ret1)
@@ -42,7 +43,7 @@ local cmdtest = function(cmd, prep, ret1)
       eq(hisline, funcs.histget(':', -2))
       eq(cmd, funcs.histget(':'))
       -- Test that command-line window was launched
-      eq('nofile', curbufmeths.get_option('buftype'))
+      eq('nofile', meths.get_option_value('buftype', {buf=0}))
       eq('n', funcs.mode(1))
       feed('')
       eq('c', funcs.mode(1))
diff --git a/test/functional/ex_cmds/ls_spec.lua b/test/functional/ex_cmds/ls_spec.lua
index 2583d80269..d02af21731 100644
--- a/test/functional/ex_cmds/ls_spec.lua
+++ b/test/functional/ex_cmds/ls_spec.lua
@@ -14,7 +14,7 @@ describe(':ls', function()
   end)
 
   it('R, F for :terminal buffers', function()
-    nvim('set_option', 'shell', string.format('"%s" INTERACT', testprg('shell-test')))
+    nvim('set_option_value', 'shell', string.format('"%s" INTERACT', testprg('shell-test')), {})
 
     command('edit foo')
     command('set hidden')
diff --git a/test/functional/ex_cmds/make_spec.lua b/test/functional/ex_cmds/make_spec.lua
index 8d903330b1..d82f59ddf9 100644
--- a/test/functional/ex_cmds/make_spec.lua
+++ b/test/functional/ex_cmds/make_spec.lua
@@ -22,14 +22,14 @@ describe(':make', function()
     end)
 
     it('captures stderr & non zero exit code #14349', function ()
-      nvim('set_option', 'makeprg', testprg('shell-test')..' foo')
+      nvim('set_option_value', 'makeprg', testprg('shell-test')..' foo', {})
       local out = eval('execute("make")')
       -- Error message is captured in the file and printed in the footer
       matches('[\r\n]+.*[\r\n]+Unknown first argument%: foo[\r\n]+%(1 of 1%)%: Unknown first argument%: foo', out)
     end)
 
     it('captures stderr & zero exit code #14349', function ()
-      nvim('set_option', 'makeprg', testprg('shell-test'))
+      nvim('set_option_value', 'makeprg', testprg('shell-test'), {})
       local out = eval('execute("make")')
       -- Ensure there are no "shell returned X" messages between
       -- command and last line (indicating zero exit)
diff --git a/test/functional/ex_cmds/map_spec.lua b/test/functional/ex_cmds/map_spec.lua
index a197b81cc5..a580e88b93 100644
--- a/test/functional/ex_cmds/map_spec.lua
+++ b/test/functional/ex_cmds/map_spec.lua
@@ -18,7 +18,7 @@ describe(':*map', function()
   it('are not affected by &isident', function()
     meths.set_var('counter', 0)
     command('nnoremap  :let counter+=1')
-    meths.set_option('isident', ('%u'):format(('>'):byte()))
+    meths.set_option_value('isident', ('%u'):format(('>'):byte()), {})
     command('nnoremap  :let counter+=1')
     -- &isident used to disable keycode parsing here as well
     feed('\24\25')
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
index d70ccb5b39..f51e7c62cb 100644
--- a/test/functional/ex_cmds/mksession_spec.lua
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -81,13 +81,13 @@ describe(':mksession', function()
       local buf_count = #meths.list_bufs()
       eq(2, buf_count)
 
-      eq('terminal', meths.buf_get_option(0, 'buftype'))
+      eq('terminal', meths.get_option_value('buftype', { buf = 0 }))
 
       test_terminal_session_disabled(2)
 
       -- no terminal should be set. As a side effect we end up with a blank buffer
-      eq('', meths.buf_get_option(meths.list_bufs()[1], 'buftype'))
-      eq('', meths.buf_get_option(meths.list_bufs()[2], 'buftype'))
+      eq('', meths.get_option_value('buftype', { buf = meths.list_bufs()[1] }))
+      eq('', meths.get_option_value('buftype', { buf = meths.list_bufs()[2] }))
     end
   )
 
@@ -112,7 +112,7 @@ describe(':mksession', function()
 
   it('do not restore :terminal if not set in sessionoptions, only buffer #13078', function()
     command('terminal')
-    eq('terminal', meths.buf_get_option(0, 'buftype'))
+    eq('terminal', meths.get_option_value('buftype', { buf = 0 }))
 
     local buf_count = #meths.list_bufs()
     eq(1, buf_count)
@@ -120,7 +120,7 @@ describe(':mksession', function()
     test_terminal_session_disabled(1)
 
     -- no terminal should be set
-    eq('', meths.buf_get_option(0, 'buftype'))
+    eq('', meths.get_option_value('buftype', { buf = 0 }))
   end)
 
   it('restores tab-local working directories', function()
@@ -249,7 +249,7 @@ describe(':mksession', function()
       style = 'minimal',
     }
     meths.open_win(buf, false, config)
-    local cmdheight = meths.get_option('cmdheight')
+    local cmdheight = meths.get_option_value('cmdheight', {})
     command('mksession ' .. session_file)
 
     -- Create a new test instance of Nvim.
@@ -262,7 +262,7 @@ describe(':mksession', function()
     -- window was not restored.
     eq(1, funcs.winnr('$'))
     -- The command-line height should remain the same as it was.
-    eq(cmdheight, meths.get_option('cmdheight'))
+    eq(cmdheight, meths.get_option_value('cmdheight', {}))
 
     os.remove(tmpfile)
   end)
diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
index 41045f5cb4..02f5bff021 100644
--- a/test/functional/ex_cmds/source_spec.lua
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -48,7 +48,7 @@ describe(':source', function()
       pending("'shellslash' only works on Windows")
       return
     end
-    meths.set_option('shellslash', false)
+    meths.set_option_value('shellslash', false, {})
     mkdir('Xshellslash')
 
     write_file([[Xshellslash/Xstack.vim]], [[
diff --git a/test/functional/ex_cmds/verbose_spec.lua b/test/functional/ex_cmds/verbose_spec.lua
index def09e2f9e..50077e9e0c 100644
--- a/test/functional/ex_cmds/verbose_spec.lua
+++ b/test/functional/ex_cmds/verbose_spec.lua
@@ -18,7 +18,7 @@ local function last_set_tests(cmd)
     script_location = table.concat{current_dir, helpers.get_pathsep(), script_file}
 
     write_file(script_file, [[
-vim.api.nvim_set_option('hlsearch', false)
+vim.api.nvim_set_option_value('hlsearch', false, {})
 vim.bo.expandtab = true
 vim.opt.number = true
 vim.api.nvim_set_keymap('n', 'key1', ':echo "test"', {noremap = true})
@@ -160,7 +160,7 @@ describe('lua verbose:', function()
     clear()
     script_file = 'test_luafile.lua'
     write_file(script_file, [[
-    vim.api.nvim_set_option('hlsearch', false)
+    vim.api.nvim_set_option_value('hlsearch', false, {})
     ]])
     exec(':source '..script_file)
   end)
diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua
index 126646f21a..0b8ce93b09 100644
--- a/test/functional/ex_cmds/write_spec.lua
+++ b/test/functional/ex_cmds/write_spec.lua
@@ -129,18 +129,18 @@ describe(':write', function()
       eq(('Vim(write):E17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'),
         pcall_err(command, 'write .'))
     end
-    meths.set_option('writeany', true)
+    meths.set_option_value('writeany', true, {})
     -- Message from buf_write
     eq(('Vim(write):E502: "." is a directory'), pcall_err(command, 'write .'))
     funcs.mkdir(fname_bak)
-    meths.set_option('backupdir', '.')
-    meths.set_option('backup', true)
+    meths.set_option_value('backupdir', '.', {})
+    meths.set_option_value('backup', true, {})
     write_file(fname, 'content0')
     command('edit ' .. fname)
     funcs.setline(1, 'TTY')
     eq('Vim(write):E510: Can\'t make backup file (add ! to override)',
        pcall_err(command, 'write'))
-    meths.set_option('backup', false)
+    meths.set_option_value('backup', false, {})
     funcs.setfperm(fname, 'r--------')
     eq('Vim(write):E505: "Xtest-functional-ex_cmds-write" is read-only (add ! to override)',
        pcall_err(command, 'write'))
diff --git a/test/functional/legacy/012_directory_spec.lua b/test/functional/legacy/012_directory_spec.lua
index 050e3855fe..f44ba10f7f 100644
--- a/test/functional/legacy/012_directory_spec.lua
+++ b/test/functional/legacy/012_directory_spec.lua
@@ -15,7 +15,6 @@ local clear = helpers.clear
 local insert = helpers.insert
 local command = helpers.command
 local write_file = helpers.write_file
-local curbufmeths = helpers.curbufmeths
 local expect_exit = helpers.expect_exit
 local mkdir = helpers.mkdir
 
@@ -58,9 +57,9 @@ describe("'directory' option", function()
       line 3 Abcdefghij
       end of testfile]])
 
-    meths.set_option('swapfile', true)
-    curbufmeths.set_option('swapfile', true)
-    meths.set_option('directory', '.')
+    meths.set_option_value('swapfile', true, {})
+    meths.set_option_value('swapfile', true, {buf=0})
+    meths.set_option_value('directory', '.', {})
 
     -- sanity check: files should not exist yet.
     eq(nil, luv.fs_stat('.Xtest1.swp'))
@@ -72,7 +71,7 @@ describe("'directory' option", function()
     -- reading the output from :!ls.
     neq(nil, luv.fs_stat('.Xtest1.swp'))
 
-    meths.set_option('directory', './Xtest2,.')
+    meths.set_option_value('directory', './Xtest2,.', {})
     command('edit Xtest1')
     poke_eventloop()
 
@@ -81,10 +80,10 @@ describe("'directory' option", function()
 
     eq({ "Xtest1.swp", "Xtest3" }, ls_dir_sorted("Xtest2"))
 
-    meths.set_option('directory', 'Xtest.je')
+    meths.set_option_value('directory', 'Xtest.je', {})
     command('bdelete')
     command('edit Xtest2/Xtest3')
-    eq(true, curbufmeths.get_option('swapfile'))
+    eq(true, meths.get_option_value('swapfile', {buf=0}))
     poke_eventloop()
 
     eq({ "Xtest3" }, ls_dir_sorted("Xtest2"))
diff --git a/test/functional/legacy/autocmd_option_spec.lua b/test/functional/legacy/autocmd_option_spec.lua
index e00b468c16..8f17f509f5 100644
--- a/test/functional/legacy/autocmd_option_spec.lua
+++ b/test/functional/legacy/autocmd_option_spec.lua
@@ -631,24 +631,24 @@ describe('au OptionSet', function()
       it('should trigger if a boolean option be set globally', function()
         set_hook('autochdir')
 
-        nvim.set_option('autochdir', true)
-        eq(true, nvim.get_option('autochdir'))
+        nvim.set_option_value('autochdir', true, {scope='global'})
+        eq(true, nvim.get_option_value('autochdir', {scope='global'}))
         expected_combination({'autochdir', 0, '', 0, 1, 'global', 'setglobal'})
       end)
 
       it('should trigger if a number option be set globally', function()
         set_hook('cmdheight')
 
-        nvim.set_option('cmdheight', 5)
-        eq(5, nvim.get_option('cmdheight'))
+        nvim.set_option_value('cmdheight', 5, {scope='global'})
+        eq(5, nvim.get_option_value('cmdheight', {scope='global'}))
         expected_combination({'cmdheight', 1, '', 1, 5, 'global', 'setglobal'})
       end)
 
       it('should trigger if a string option be set globally', function()
         set_hook('ambiwidth')
 
-        nvim.set_option('ambiwidth', 'double')
-        eq('double', nvim.get_option('ambiwidth'))
+        nvim.set_option_value('ambiwidth', 'double', {scope='global'})
+        eq('double', nvim.get_option_value('ambiwidth', {scope='global'}))
         expected_combination({'ambiwidth', 'single', '', 'single', 'double', 'global', 'setglobal'})
       end)
     end)
diff --git a/test/functional/legacy/buffer_spec.lua b/test/functional/legacy/buffer_spec.lua
index acaa9a51f1..1e8909f0d0 100644
--- a/test/functional/legacy/buffer_spec.lua
+++ b/test/functional/legacy/buffer_spec.lua
@@ -10,7 +10,7 @@ describe('buffer', function()
   before_each(function()
     clear()
     meths.ui_attach(80, 24, {})
-    meths.set_option('hidden', false)
+    meths.set_option_value('hidden', false, {})
   end)
 
   it('deleting a modified buffer with :confirm', function()
diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua
index f7df6ae8d7..3cbff2a01b 100644
--- a/test/functional/legacy/cmdline_spec.lua
+++ b/test/functional/legacy/cmdline_spec.lua
@@ -225,9 +225,9 @@ describe('cmdline', function()
       [3] = {reverse = true},  -- TabLineFill
     })
     screen:attach()
-    meths.set_option('laststatus', 2)
-    meths.set_option('showtabline', 2)
-    meths.set_option('cmdheight', 1)
+    meths.set_option_value('laststatus', 2, {})
+    meths.set_option_value('showtabline', 2, {})
+    meths.set_option_value('cmdheight', 1, {})
     screen:expect([[
       {2: [No Name] }{3:                                                 }|
       ^                                                            |
@@ -247,10 +247,10 @@ describe('cmdline', function()
       [0] = {bold = true, foreground = Screen.colors.Blue},  -- NonText
     }
     screen:attach()
-    meths.set_option('ruler', true)
-    meths.set_option('rulerformat', 'longish')
-    meths.set_option('laststatus', 0)
-    meths.set_option('winwidth', 1)
+    meths.set_option_value('ruler', true, {})
+    meths.set_option_value('rulerformat', 'longish', {})
+    meths.set_option_value('laststatus', 0, {})
+    meths.set_option_value('winwidth', 1, {})
     feed [[v|p]]
     screen:expect [[
                         │^ |
diff --git a/test/functional/legacy/filechanged_spec.lua b/test/functional/legacy/filechanged_spec.lua
index cea1d6ac30..c8e772f597 100644
--- a/test/functional/legacy/filechanged_spec.lua
+++ b/test/functional/legacy/filechanged_spec.lua
@@ -12,8 +12,8 @@ describe('file changed dialog', function()
   before_each(function()
     clear()
     meths.ui_attach(80, 24, {})
-    meths.set_option('autoread', false)
-    meths.set_option('fsync', true)
+    meths.set_option_value('autoread', false, {})
+    meths.set_option_value('fsync', true, {})
   end)
 
   it('works', function()
diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua
index 71a53c8381..794676153c 100644
--- a/test/functional/legacy/messages_spec.lua
+++ b/test/functional/legacy/messages_spec.lua
@@ -361,9 +361,9 @@ describe('messages', function()
       screen:attach()
 
       command('cd '..nvim_dir)
-      meths.set_option('shell', './shell-test')
-      meths.set_option('shellcmdflag', 'REP 20')
-      meths.set_option('shellxquote', '')  -- win: avoid extra quotes
+      meths.set_option_value('shell', './shell-test', {})
+      meths.set_option_value('shellcmdflag', 'REP 20', {})
+      meths.set_option_value('shellxquote', '', {})  -- win: avoid extra quotes
 
       -- display a page and go back, results in exactly the same view
       feed([[:4 verbose echo system('foo')]])
diff --git a/test/functional/legacy/vimscript_spec.lua b/test/functional/legacy/vimscript_spec.lua
index f59a87f824..16a1080396 100644
--- a/test/functional/legacy/vimscript_spec.lua
+++ b/test/functional/legacy/vimscript_spec.lua
@@ -12,7 +12,7 @@ describe('Vim script', function()
   it('Error when if/for/while/try/function is nested too deep',function()
     local screen = Screen.new(80, 24)
     screen:attach()
-    meths.set_option('laststatus', 2)
+    meths.set_option_value('laststatus', 2, {})
     exec([[
       " Deep nesting of if ... endif
       func Test1()
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)
 
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index fcf313785a..3690b7e97c 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -202,8 +202,8 @@ describe('startup defaults', function()
     clear{args={}, args_rm={'-i'}, env=env}
     -- Default 'shadafile' is empty.
     -- This means use the default location. :help shada-file-name
-    eq('', meths.get_option('shadafile'))
-    eq('', meths.get_option('viminfofile'))
+    eq('', meths.get_option_value('shadafile', {}))
+    eq('', meths.get_option_value('viminfofile', {}))
     -- Check that shada data (such as v:oldfiles) is saved/restored.
     command('edit Xtest-foo')
     command('write')
@@ -227,13 +227,13 @@ describe('startup defaults', function()
       args_rm={'runtimepath'},
     }
     -- Defaults to &runtimepath.
-    eq(meths.get_option('runtimepath'), meths.get_option('packpath'))
+    eq(meths.get_option_value('runtimepath', {}), meths.get_option_value('packpath', {}))
 
     -- Does not follow modifications to runtimepath.
     meths.command('set runtimepath+=foo')
-    neq(meths.get_option('runtimepath'), meths.get_option('packpath'))
+    neq(meths.get_option_value('runtimepath', {}), meths.get_option_value('packpath', {}))
     meths.command('set packpath+=foo')
-    eq(meths.get_option('runtimepath'), meths.get_option('packpath'))
+    eq(meths.get_option_value('runtimepath', {}), meths.get_option_value('packpath', {}))
   end)
 
   it('v:progpath is set to the absolute path', function()
@@ -318,10 +318,10 @@ describe('XDG defaults', function()
         USER=nil,
       }})
 
-      eq('.', meths.get_option('backupdir'))
-      eq('.', meths.get_option('viewdir'))
-      eq('.', meths.get_option('directory'))
-      eq('.', meths.get_option('undodir'))
+      eq('.', meths.get_option_value('backupdir', {}))
+      eq('.', meths.get_option_value('viewdir', {}))
+      eq('.', meths.get_option_value('directory', {}))
+      eq('.', meths.get_option_value('undodir', {}))
       ok((funcs.tempname()):len() > 4)
     end)
   end)
@@ -383,7 +383,7 @@ describe('XDG defaults', function()
           .. ',' .. root_path .. ('/b'):rep(2048) .. '/nvim/after'
           .. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim/after'
           .. ',' .. root_path .. ('/x'):rep(4096) .. '/nvim/after'
-      ):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
+      ):gsub('\\', '/')), (meths.get_option_value('runtimepath', {})):gsub('\\', '/'))
       meths.command('set runtimepath&')
       meths.command('set backupdir&')
       meths.command('set directory&')
@@ -407,15 +407,15 @@ describe('XDG defaults', function()
           .. ',' .. root_path .. ('/b'):rep(2048) .. '/nvim/after'
           .. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim/after'
           .. ',' .. root_path .. ('/x'):rep(4096) .. '/nvim/after'
-      ):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
+      ):gsub('\\', '/')), (meths.get_option_value('runtimepath', {})):gsub('\\', '/'))
       eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. state_dir .. '/backup//',
-         (meths.get_option('backupdir'):gsub('\\', '/')))
+         (meths.get_option_value('backupdir', {}):gsub('\\', '/')))
       eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/swap//',
-         (meths.get_option('directory')):gsub('\\', '/'))
+         (meths.get_option_value('directory', {})):gsub('\\', '/'))
       eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/undo//',
-         (meths.get_option('undodir')):gsub('\\', '/'))
+         (meths.get_option_value('undodir', {})):gsub('\\', '/'))
       eq(root_path .. ('/X'):rep(4096) .. '/'  ..  state_dir .. '/view//',
-         (meths.get_option('viewdir')):gsub('\\', '/'))
+         (meths.get_option_value('viewdir', {})):gsub('\\', '/'))
     end)
   end)
 
@@ -450,7 +450,7 @@ describe('XDG defaults', function()
           .. ',$XDG_CONFIG_HOME/' .. data_dir .. '/site/after'
           .. ',$XDG_DATA_DIRS/nvim/after'
           .. ',$XDG_DATA_HOME/nvim/after'
-      ):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
+      ):gsub('\\', '/')), (meths.get_option_value('runtimepath', {})):gsub('\\', '/'))
       meths.command('set runtimepath&')
       meths.command('set backupdir&')
       meths.command('set directory&')
@@ -466,15 +466,15 @@ describe('XDG defaults', function()
           .. ',$XDG_CONFIG_HOME/' .. data_dir .. '/site/after'
           .. ',$XDG_DATA_DIRS/nvim/after'
           .. ',$XDG_DATA_HOME/nvim/after'
-      ):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
+      ):gsub('\\', '/')), (meths.get_option_value('runtimepath', {})):gsub('\\', '/'))
       eq(('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
-          meths.get_option('backupdir'):gsub('\\', '/'))
+          meths.get_option_value('backupdir', {}):gsub('\\', '/'))
       eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
-          meths.get_option('directory'):gsub('\\', '/'))
+          meths.get_option_value('directory', {}):gsub('\\', '/'))
       eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
-          meths.get_option('undodir'):gsub('\\', '/'))
+          meths.get_option_value('undodir', {}):gsub('\\', '/'))
       eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
-          meths.get_option('viewdir'):gsub('\\', '/'))
+          meths.get_option_value('viewdir', {}):gsub('\\', '/'))
       meths.command('set all&')
       eq(('$XDG_DATA_HOME/nvim'
           .. ',$XDG_DATA_DIRS/nvim'
@@ -486,15 +486,15 @@ describe('XDG defaults', function()
           .. ',$XDG_CONFIG_HOME/' .. data_dir .. '/site/after'
           .. ',$XDG_DATA_DIRS/nvim/after'
           .. ',$XDG_DATA_HOME/nvim/after'
-      ):gsub('\\', '/'), (meths.get_option('runtimepath')):gsub('\\', '/'))
+      ):gsub('\\', '/'), (meths.get_option_value('runtimepath', {})):gsub('\\', '/'))
       eq(('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'),
-          meths.get_option('backupdir'):gsub('\\', '/'))
+          meths.get_option_value('backupdir', {}):gsub('\\', '/'))
       eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'),
-          meths.get_option('directory'):gsub('\\', '/'))
+          meths.get_option_value('directory', {}):gsub('\\', '/'))
       eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'),
-          meths.get_option('undodir'):gsub('\\', '/'))
+          meths.get_option_value('undodir', {}):gsub('\\', '/'))
       eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'),
-          meths.get_option('viewdir'):gsub('\\', '/'))
+          meths.get_option_value('viewdir', {}):gsub('\\', '/'))
       eq(nil, (funcs.tempname()):match('XDG_RUNTIME_DIR'))
     end)
   end)
@@ -529,7 +529,7 @@ describe('XDG defaults', function()
           .. ',-\\,-\\,-' .. path_sep .. 'nvim' .. path_sep .. 'after'
           .. ',\\,-\\,-\\,' .. path_sep .. 'nvim' .. path_sep .. 'after'
           .. ',\\, \\, \\,' .. path_sep .. 'nvim' .. path_sep .. 'after'
-      ), meths.get_option('runtimepath'))
+      ), meths.get_option_value('runtimepath', {}))
       meths.command('set runtimepath&')
       meths.command('set backupdir&')
       meths.command('set directory&')
@@ -549,15 +549,15 @@ describe('XDG defaults', function()
           .. ',-\\,-\\,-' .. path_sep ..'nvim' .. path_sep ..'after'
           .. ',\\,-\\,-\\,' .. path_sep ..'nvim' .. path_sep ..'after'
           .. ',\\, \\, \\,' .. path_sep ..'nvim' .. path_sep ..'after'
-      ), meths.get_option('runtimepath'))
+      ), meths.get_option_value('runtimepath', {}))
       eq('.,\\,=\\,=\\,' .. path_sep .. state_dir .. '' .. path_sep ..'backup' .. (path_sep):rep(2),
-          meths.get_option('backupdir'))
+          meths.get_option_value('backupdir', {}))
       eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'swap' .. (path_sep):rep(2),
-          meths.get_option('directory'))
+          meths.get_option_value('directory', {}))
       eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'undo' .. (path_sep):rep(2),
-          meths.get_option('undodir'))
+          meths.get_option_value('undodir', {}))
       eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'view' .. (path_sep):rep(2),
-          meths.get_option('viewdir'))
+          meths.get_option_value('viewdir', {}))
     end)
   end)
 end)
diff --git a/test/functional/options/num_options_spec.lua b/test/functional/options/num_options_spec.lua
index f343e2da75..16a53c75e6 100644
--- a/test/functional/options/num_options_spec.lua
+++ b/test/functional/options/num_options_spec.lua
@@ -11,7 +11,7 @@ local function should_fail(opt, value, errmsg)
   feed_command('setlocal ' .. opt .. '=' .. value)
   eq(errmsg, eval("v:errmsg"):match("E%d*"))
   feed_command('let v:errmsg = ""')
-  local status, err = pcall(meths.set_option, opt, value)
+  local status, err = pcall(meths.set_option_value, opt, value, {})
   eq(status, false)
   eq(errmsg, err:match("E%d*"))
   eq('', eval("v:errmsg"))
@@ -20,8 +20,8 @@ end
 local function should_succeed(opt, value)
   feed_command('setglobal ' .. opt .. '=' .. value)
   feed_command('setlocal ' .. opt .. '=' .. value)
-  meths.set_option(opt, value)
-  eq(value, meths.get_option(opt))
+  meths.set_option_value(opt, value, {})
+  eq(value, meths.get_option_value(opt, {}))
   eq('', eval("v:errmsg"))
 end
 
@@ -29,12 +29,12 @@ describe(':setlocal', function()
   before_each(clear)
 
   it('setlocal sets only local value', function()
-    eq(0, meths.get_option('iminsert'))
+    eq(0, meths.get_option_value('iminsert', {scope='global'}))
     feed_command('setlocal iminsert=1')
-    eq(0, meths.get_option('iminsert'))
-    eq(-1, meths.get_option('imsearch'))
+    eq(0, meths.get_option_value('iminsert', {scope='global'}))
+    eq(-1, meths.get_option_value('imsearch', {scope='global'}))
     feed_command('setlocal imsearch=1')
-    eq(-1, meths.get_option('imsearch'))
+    eq(-1, meths.get_option_value('imsearch', {scope='global'}))
   end)
 end)
 
@@ -77,8 +77,8 @@ describe(':set validation', function()
 
     -- If smaller than 1 this one is set to 'lines'-1
     feed_command('setglobal window=-10')
-    meths.set_option('window', -10)
-    eq(23, meths.get_option('window'))
+    meths.set_option_value('window', -10, {})
+    eq(23, meths.get_option_value('window', {}))
     eq('', eval("v:errmsg"))
 
     -- 'scrolloff' and 'sidescrolloff' can have a -1 value when
@@ -112,8 +112,8 @@ describe(':set validation', function()
     local function setto(value)
       feed_command('setglobal maxcombine=' .. value)
       feed_command('setlocal maxcombine=' .. value)
-      meths.set_option('maxcombine', value)
-      eq(6, meths.get_option('maxcombine'))
+      meths.set_option_value('maxcombine', value, {})
+      eq(6, meths.get_option_value('maxcombine', {}))
       eq('', eval("v:errmsg"))
     end
     setto(0)
diff --git a/test/functional/plugin/editorconfig_spec.lua b/test/functional/plugin/editorconfig_spec.lua
index e6a2550aba..4ad9903032 100644
--- a/test/functional/plugin/editorconfig_spec.lua
+++ b/test/functional/plugin/editorconfig_spec.lua
@@ -3,7 +3,6 @@ local clear = helpers.clear
 local command = helpers.command
 local eq = helpers.eq
 local pathsep = helpers.get_pathsep()
-local curbufmeths = helpers.curbufmeths
 local funcs = helpers.funcs
 local meths = helpers.meths
 
@@ -13,7 +12,7 @@ local function test_case(name, expected)
   local filename = testdir .. pathsep .. name
   command('edit ' .. filename)
   for opt, val in pairs(expected) do
-    eq(val, curbufmeths.get_option(opt), name)
+    eq(val, meths.get_option_value(opt, {buf=0}), name)
   end
 end
 
diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua
index 4985da9cd7..1dca464d74 100644
--- a/test/functional/plugin/lsp/incremental_sync_spec.lua
+++ b/test/functional/plugin/lsp/incremental_sync_spec.lua
@@ -21,7 +21,7 @@ before_each(function ()
     --   ["mac"] = '\r',
     -- }
 
-    -- local line_ending = format_line_ending[vim.api.nvim_buf_get_option(0, 'fileformat')]
+    -- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {buf=0})]
 
 
     function test_register(bufnr, id, offset_encoding, line_ending)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 506bc1333b..b906ae265f 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -33,7 +33,9 @@ local test_rpc_server = lsp_helpers.test_rpc_server
 
 local function get_buf_option(name, bufnr)
     bufnr = bufnr or "BUFFER"
-    return exec_lua(string.format("return vim.api.nvim_buf_get_option(%s, '%s')", bufnr, name))
+    return exec_lua(
+      string.format("return vim.api.nvim_get_option_value('%s', { buf = %s })", name, bufnr)
+    )
 end
 
 -- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837
@@ -356,8 +358,8 @@ describe('LSP', function()
             vim.api.nvim_command('filetype plugin on')
             BUFFER_1 = vim.api.nvim_create_buf(false, true)
             BUFFER_2 = vim.api.nvim_create_buf(false, true)
-            vim.api.nvim_buf_set_option(BUFFER_1, 'filetype', 'man')
-            vim.api.nvim_buf_set_option(BUFFER_2, 'filetype', 'xml')
+            vim.api.nvim_set_option_value('filetype', 'man', { buf = BUFFER_1 })
+            vim.api.nvim_set_option_value('filetype', 'xml', { buf = BUFFER_2 })
           ]]
 
           -- Sanity check to ensure that some values are set after setting filetype.
@@ -394,9 +396,9 @@ describe('LSP', function()
           client = _client
           exec_lua [[
             BUFFER = vim.api.nvim_create_buf(false, true)
-            vim.api.nvim_buf_set_option(BUFFER, 'tagfunc', 'tfu')
-            vim.api.nvim_buf_set_option(BUFFER, 'omnifunc', 'ofu')
-            vim.api.nvim_buf_set_option(BUFFER, 'formatexpr', 'fex')
+            vim.api.nvim_set_option_value('tagfunc', 'tfu', { buf = BUFFER })
+            vim.api.nvim_set_option_value('omnifunc', 'ofu', { buf = BUFFER })
+            vim.api.nvim_set_option_value('formatexpr', 'fex', { buf = BUFFER })
             lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
           ]]
         end;
@@ -1166,7 +1168,7 @@ describe('LSP', function()
               "testing";
               "123";
             })
-            vim.api.nvim_buf_set_option(BUFFER, 'eol', false)
+            vim.bo[BUFFER].eol = false
           ]]
         end;
         on_init = function(_client)
@@ -2929,8 +2931,8 @@ describe('LSP', function()
   describe('lsp.util.get_effective_tabstop', function()
     local function test_tabstop(tabsize, shiftwidth)
       exec_lua(string.format([[
-        vim.api.nvim_buf_set_option(0, 'shiftwidth', %d)
-        vim.api.nvim_buf_set_option(0, 'tabstop', 2)
+        vim.bo.shiftwidth = %d
+        vim.bo.tabstop = 2
       ]], shiftwidth))
       eq(tabsize, exec_lua('return vim.lsp.util.get_effective_tabstop()'))
     end
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index f6145a5809..43222f1904 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -2181,8 +2181,8 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "a"',
     }, nvim_eval('getline(1, "$")'))
-    eq(false, curbuf('get_option', 'modified'))
-    eq('shada', curbuf('get_option', 'filetype'))
+    eq(false, nvim('get_option_value', 'modified', {buf=0}))
+    eq('shada', nvim('get_option_value', 'filetype', {buf=0}))
     nvim_command('edit ' .. fname_tmp)
     eq({
       'History entry with timestamp ' .. epoch .. ':',
@@ -2191,8 +2191,8 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "b"',
     }, nvim_eval('getline(1, "$")'))
-    eq(false, curbuf('get_option', 'modified'))
-    eq('shada', curbuf('get_option', 'filetype'))
+    eq(false, nvim('get_option_value', 'modified', {buf=0}))
+    eq('shada', nvim('get_option_value', 'filetype', {buf=0}))
     eq('++opt not supported', exc_exec('edit ++enc=latin1 ' .. fname))
     neq({
       'History entry with timestamp ' .. epoch .. ':',
@@ -2201,7 +2201,7 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "a"',
     }, nvim_eval('getline(1, "$")'))
-    neq(true, curbuf('get_option', 'modified'))
+    neq(true, nvim('get_option_value', 'modified', {buf=0}))
   end)
 
   it('event FileReadCmd', function()
@@ -2217,8 +2217,8 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "a"',
     }, nvim_eval('getline(1, "$")'))
-    eq(true, curbuf('get_option', 'modified'))
-    neq('shada', curbuf('get_option', 'filetype'))
+    eq(true, nvim('get_option_value', 'modified', {buf=0}))
+    neq('shada', nvim('get_option_value', 'filetype', {buf=0}))
     nvim_command('1,$read ' .. fname_tmp)
     eq({
       '',
@@ -2233,9 +2233,9 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "b"',
     }, nvim_eval('getline(1, "$")'))
-    eq(true, curbuf('get_option', 'modified'))
-    neq('shada', curbuf('get_option', 'filetype'))
-    curbuf('set_option', 'modified', false)
+    eq(true, nvim('get_option_value', 'modified', {buf=0}))
+    neq('shada', nvim('get_option_value', 'filetype', {buf=0}))
+    nvim('set_option_value', 'modified', false, {buf=0})
     eq('++opt not supported', exc_exec('$read ++enc=latin1 ' .. fname))
     eq({
       '',
@@ -2250,7 +2250,7 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "b"',
     }, nvim_eval('getline(1, "$")'))
-    neq(true, curbuf('get_option', 'modified'))
+    neq(true, nvim('get_option_value', 'modified', {buf=0}))
   end)
 
   it('event BufWriteCmd', function()
@@ -2517,10 +2517,10 @@ describe('ftplugin/shada.vim', function()
   it('sets options correctly', function()
     nvim_command('filetype plugin indent on')
     nvim_command('setlocal filetype=shada')
-    eq(true, curbuf('get_option', 'expandtab'))
-    eq(2, curbuf('get_option', 'tabstop'))
-    eq(2, curbuf('get_option', 'softtabstop'))
-    eq(2, curbuf('get_option', 'shiftwidth'))
+    eq(true, nvim('get_option_value', 'expandtab', {buf=0}))
+    eq(2, nvim('get_option_value', 'tabstop', {buf=0}))
+    eq(2, nvim('get_option_value', 'softtabstop', {buf=0}))
+    eq(2, nvim('get_option_value', 'shiftwidth', {buf=0}))
   end)
 
   it('sets indentkeys correctly', function()
diff --git a/test/functional/provider/perl_spec.lua b/test/functional/provider/perl_spec.lua
index 5ab807e90d..bc7261895d 100644
--- a/test/functional/provider/perl_spec.lua
+++ b/test/functional/provider/perl_spec.lua
@@ -5,7 +5,7 @@ local command = helpers.command
 local write_file = helpers.write_file
 local eval = helpers.eval
 local retry = helpers.retry
-local curbufmeths = helpers.curbufmeths
+local meths = helpers.meths
 local insert = helpers.insert
 local expect = helpers.expect
 local feed = helpers.feed
@@ -45,7 +45,7 @@ describe('legacy perl provider', function()
     -- :perldo 1; doesn't change $_,
     -- the buffer should not be changed
     command('normal :perldo 1;')
-    eq(false, curbufmeths.get_option('modified'))
+    eq(false, meths.get_option_value('modified', {buf=0}))
     -- insert some text
     insert('abc\ndef\nghi')
     expect([[
diff --git a/test/functional/provider/ruby_spec.lua b/test/functional/provider/ruby_spec.lua
index fba96100fc..40ace28c4e 100644
--- a/test/functional/provider/ruby_spec.lua
+++ b/test/functional/provider/ruby_spec.lua
@@ -3,7 +3,6 @@ local helpers = require('test.functional.helpers')(after_each)
 local assert_alive = helpers.assert_alive
 local clear = helpers.clear
 local command = helpers.command
-local curbufmeths = helpers.curbufmeths
 local eq = helpers.eq
 local exc_exec = helpers.exc_exec
 local expect = helpers.expect
@@ -98,7 +97,7 @@ describe(':rubydo command', function()
 
   it('does not modify the buffer if no changes are made', function()
     command('normal :rubydo 42')
-    eq(false, curbufmeths.get_option('modified'))
+    eq(false, meths.get_option_value('modified', {buf=0}))
   end)
 end)
 
diff --git a/test/functional/shada/buffers_spec.lua b/test/functional/shada/buffers_spec.lua
index 26a4569fce..2740eeeca6 100644
--- a/test/functional/shada/buffers_spec.lua
+++ b/test/functional/shada/buffers_spec.lua
@@ -1,7 +1,7 @@
 -- shada buffer list saving/reading support
 local helpers = require('test.functional.helpers')(after_each)
-local nvim_command, funcs, eq, curbufmeths =
-  helpers.command, helpers.funcs, helpers.eq, helpers.curbufmeths
+local nvim_command, funcs, eq, curbufmeths, meths =
+  helpers.command, helpers.funcs, helpers.eq, helpers.curbufmeths, helpers.meths
 local expect_exit = helpers.expect_exit
 
 local shada_helpers = require('test.functional.shada.helpers')
@@ -48,7 +48,7 @@ describe('shada support code', function()
     reset('set shada+=%')
     nvim_command('edit ' .. testfilename)
     nvim_command('edit ' .. testfilename_2)
-    curbufmeths.set_option('buflisted', false)
+    meths.set_option_value('buflisted', false, {buf=0})
     expect_exit(nvim_command, 'qall')
     reset('set shada+=%')
     eq(2, funcs.bufnr('$'))
@@ -60,7 +60,7 @@ describe('shada support code', function()
     reset('set shada+=%')
     nvim_command('edit ' .. testfilename)
     nvim_command('edit ' .. testfilename_2)
-    curbufmeths.set_option('buftype', 'quickfix')
+    meths.set_option_value('buftype', 'quickfix', {buf=0})
     expect_exit(nvim_command, 'qall')
     reset('set shada+=%')
     eq(2, funcs.bufnr('$'))
diff --git a/test/functional/shada/history_spec.lua b/test/functional/shada/history_spec.lua
index aa4106ad63..433db3171e 100644
--- a/test/functional/shada/history_spec.lua
+++ b/test/functional/shada/history_spec.lua
@@ -106,13 +106,13 @@ describe('ShaDa support code', function()
   end)
 
   it('dumps and loads last search pattern with offset', function()
-    meths.set_option('wrapscan', false)
+    meths.set_option_value('wrapscan', false, {})
     funcs.setline('.', {'foo', 'bar--'})
     nvim_feed('gg0/a/e+1\n')
     eq({0, 2, 3, 0}, funcs.getpos('.'))
     nvim_command('wshada')
     reset()
-    meths.set_option('wrapscan', false)
+    meths.set_option_value('wrapscan', false, {})
     funcs.setline('.', {'foo', 'bar--'})
     nvim_feed('gg0n')
     eq({0, 2, 3, 0}, funcs.getpos('.'))
@@ -121,13 +121,13 @@ describe('ShaDa support code', function()
 
   it('dumps and loads last search pattern with offset and backward direction',
   function()
-    meths.set_option('wrapscan', false)
+    meths.set_option_value('wrapscan', false, {})
     funcs.setline('.', {'foo', 'bar--'})
     nvim_feed('G$?a?e+1\n')
     eq({0, 2, 3, 0}, funcs.getpos('.'))
     nvim_command('wshada')
     reset()
-    meths.set_option('wrapscan', false)
+    meths.set_option_value('wrapscan', false, {})
     funcs.setline('.', {'foo', 'bar--'})
     nvim_feed('G$n')
     eq({0, 2, 3, 0}, funcs.getpos('.'))
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index cc21d08620..3a3238eb34 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -196,30 +196,30 @@ describe('ShaDa support code', function()
   end)
 
   it('is able to set &shada after &viminfo', function()
-    meths.set_option('viminfo', '\'10')
-    eq('\'10', meths.get_option('viminfo'))
-    eq('\'10', meths.get_option('shada'))
-    meths.set_option('shada', '')
-    eq('', meths.get_option('viminfo'))
-    eq('', meths.get_option('shada'))
+    meths.set_option_value('viminfo', '\'10', {})
+    eq('\'10', meths.get_option_value('viminfo', {}))
+    eq('\'10', meths.get_option_value('shada', {}))
+    meths.set_option_value('shada', '', {})
+    eq('', meths.get_option_value('viminfo', {}))
+    eq('', meths.get_option_value('shada', {}))
   end)
 
   it('is able to set all& after setting &shada', function()
-    meths.set_option('shada', '\'10')
-    eq('\'10', meths.get_option('viminfo'))
-    eq('\'10', meths.get_option('shada'))
+    meths.set_option_value('shada', '\'10', {})
+    eq('\'10', meths.get_option_value('viminfo', {}))
+    eq('\'10', meths.get_option_value('shada', {}))
     nvim_command('set all&')
-    eq('!,\'100,<50,s10,h', meths.get_option('viminfo'))
-    eq('!,\'100,<50,s10,h', meths.get_option('shada'))
+    eq('!,\'100,<50,s10,h', meths.get_option_value('viminfo', {}))
+    eq('!,\'100,<50,s10,h', meths.get_option_value('shada', {}))
   end)
 
   it('is able to set &shada after &viminfo using :set', function()
     nvim_command('set viminfo=\'10')
-    eq('\'10', meths.get_option('viminfo'))
-    eq('\'10', meths.get_option('shada'))
+    eq('\'10', meths.get_option_value('viminfo', {}))
+    eq('\'10', meths.get_option_value('shada', {}))
     nvim_command('set shada=')
-    eq('', meths.get_option('viminfo'))
-    eq('', meths.get_option('shada'))
+    eq('', meths.get_option_value('viminfo', {}))
+    eq('', meths.get_option_value('shada', {}))
   end)
 
   it('setting &shada gives proper error message on missing number', function()
@@ -237,12 +237,12 @@ describe('ShaDa support code', function()
     funcs.mkdir(dirname, '', 0)
     eq(0, funcs.filewritable(dirname))
     reset{shadafile=dirshada, args={'--cmd', 'set shada='}}
-    meths.set_option('shada', '\'10')
+    meths.set_option_value('shada', '\'10', {})
     eq('Vim(wshada):E886: System error while opening ShaDa file '
        .. 'Xtest-functional-shada-shada.d/main.shada for reading to merge '
        .. 'before writing it: permission denied',
        exc_exec('wshada'))
-    meths.set_option('shada', '')
+    meths.set_option_value('shada', '', {})
   end)
 end)
 
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index fa587e9364..4ce354b9a9 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -197,7 +197,7 @@ describe(':terminal buffer', function()
 
   it('handles loss of focus gracefully', function()
     -- Change the statusline to avoid printing the file name, which varies.
-    nvim('set_option', 'statusline', '==========')
+    nvim('set_option_value', 'statusline', '==========', {})
     feed_command('set laststatus=0')
 
     -- Save the buffer number of the terminal for later testing.
diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua
index 80287bb3d0..db5dba7374 100644
--- a/test/functional/terminal/edit_spec.lua
+++ b/test/functional/terminal/edit_spec.lua
@@ -21,8 +21,8 @@ describe(':edit term://*', function()
 
   before_each(function()
     clear()
-    meths.set_option('shell', testprg('shell-test'))
-    meths.set_option('shellcmdflag', 'EXE')
+    meths.set_option_value('shell', testprg('shell-test'), {})
+    meths.set_option_value('shellcmdflag', 'EXE', {})
   end)
 
   it('runs TermOpen event', function()
@@ -40,7 +40,7 @@ describe(':edit term://*', function()
     local columns, lines = 20, 4
     local scr = get_screen(columns, lines)
     local rep = 97
-    meths.set_option('shellcmdflag', 'REP ' .. rep)
+    meths.set_option_value('shellcmdflag', 'REP ' .. rep, {})
     command('set shellxquote=')  -- win: avoid extra quotes
     local sb = 10
     command('autocmd TermOpen * :setlocal scrollback='..tostring(sb)
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 6b7e93a864..28751a3504 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -133,8 +133,8 @@ describe(':terminal (with fake shell)', function()
     screen = Screen.new(50, 4)
     screen:attach({rgb=false})
     -- shell-test.c is a fake shell that prints its arguments and exits.
-    nvim('set_option', 'shell', testprg('shell-test'))
-    nvim('set_option', 'shellcmdflag', 'EXE')
+    nvim('set_option_value', 'shell', testprg('shell-test'), {})
+    nvim('set_option_value', 'shellcmdflag', 'EXE', {})
   end)
 
   -- Invokes `:terminal {cmd}` using a fake shell (shell-test.c) which prints
@@ -157,7 +157,7 @@ describe(':terminal (with fake shell)', function()
   end)
 
   it("with no argument, and 'shell' is set to empty string", function()
-    nvim('set_option', 'shell', '')
+    nvim('set_option_value', 'shell', '', {})
     terminal_with_fake_shell()
     screen:expect([[
       ^                                                  |
@@ -169,7 +169,7 @@ describe(':terminal (with fake shell)', function()
 
   it("with no argument, but 'shell' has arguments, acts like termopen()", function()
     skip(is_os('win'))
-    nvim('set_option', 'shell', testprg('shell-test')..' -t jeff')
+    nvim('set_option_value', 'shell', testprg('shell-test')..' -t jeff', {})
     terminal_with_fake_shell()
     screen:expect([[
       ^jeff $                                            |
@@ -193,7 +193,7 @@ describe(':terminal (with fake shell)', function()
 
   it("executes a given command through the shell, when 'shell' has arguments", function()
     skip(is_os('win'))
-    nvim('set_option', 'shell', testprg('shell-test')..' -t jeff')
+    nvim('set_option_value', 'shell', testprg('shell-test')..' -t jeff', {})
     command('set shellxquote=')   -- win: avoid extra quotes
     terminal_with_fake_shell('echo hi')
     screen:expect([[
diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua
index ac76217023..a2e9ffa1d7 100644
--- a/test/functional/terminal/mouse_spec.lua
+++ b/test/functional/terminal/mouse_spec.lua
@@ -11,7 +11,7 @@ describe(':terminal mouse', function()
 
   before_each(function()
     clear()
-    nvim('set_option', 'statusline', '==========')
+    nvim('set_option_value', 'statusline', '==========', {})
     command('highlight StatusLine cterm=NONE')
     command('highlight StatusLineNC cterm=NONE')
     command('highlight VertSplit cterm=NONE')
@@ -352,7 +352,7 @@ describe(':terminal mouse', function()
       end)
 
       it('handles terminal size when switching buffers', function()
-        nvim('set_option', 'hidden', true)
+        nvim('set_option_value', 'hidden', true, {})
         feed('')
         screen:expect([[
           {7: 27 }line                 │line30                  |
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index 5d967e0340..48a9fa7171 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -8,7 +8,7 @@ local command = helpers.command
 local matches = helpers.matches
 local poke_eventloop = helpers.poke_eventloop
 local retry = helpers.retry
-local curbufmeths = helpers.curbufmeths
+local meths = helpers.meths
 local nvim = helpers.nvim
 local feed_data = thelpers.feed_data
 local pcall_err = helpers.pcall_err
@@ -381,8 +381,8 @@ describe("'scrollback' option", function()
 
   local function set_fake_shell()
     -- shell-test.c is a fake shell that prints its arguments and exits.
-    nvim('set_option', 'shell', testprg('shell-test'))
-    nvim('set_option', 'shellcmdflag', 'EXE')
+    nvim('set_option_value', 'shell', testprg('shell-test'), {})
+    nvim('set_option_value', 'shellcmdflag', 'EXE', {})
   end
 
   local function expect_lines(expected, epsilon)
@@ -401,7 +401,7 @@ describe("'scrollback' option", function()
       screen = thelpers.screen_setup(nil, "['sh']", 30)
     end
 
-    curbufmeths.set_option('scrollback', 0)
+    meths.set_option_value('scrollback', 0, {buf = 0})
     feed_data(('%s REP 31 line%s'):format(testprg('shell-test'), is_os('win') and '\r' or '\n'))
     screen:expect{any='30: line                      '}
     retry(nil, nil, function() expect_lines(7) end)
@@ -417,7 +417,7 @@ describe("'scrollback' option", function()
       screen = thelpers.screen_setup(nil, "['sh']", 30)
     end
 
-    curbufmeths.set_option('scrollback', 200)
+    meths.set_option_value('scrollback', 200, {buf=0})
 
     -- Wait for prompt.
     screen:expect{any='%$'}
@@ -426,10 +426,10 @@ describe("'scrollback' option", function()
     screen:expect{any='30: line                      '}
 
     retry(nil, nil, function() expect_lines(33, 2) end)
-    curbufmeths.set_option('scrollback', 10)
+    meths.set_option_value('scrollback', 10, {buf=0})
     poke_eventloop()
     retry(nil, nil, function() expect_lines(16) end)
-    curbufmeths.set_option('scrollback', 10000)
+    meths.set_option_value('scrollback', 10000, {buf=0})
     retry(nil, nil, function() expect_lines(16) end)
     -- Terminal job data is received asynchronously, may happen before the
     -- 'scrollback' option is synchronized with the internal sb_buffer.
@@ -484,18 +484,18 @@ describe("'scrollback' option", function()
       ]])
     local term_height = 6  -- Actual terminal screen height, not the scrollback
     -- Initial
-    local scrollback = curbufmeths.get_option('scrollback')
+    local scrollback = meths.get_option_value('scrollback', {buf=0})
     eq(scrollback + term_height, eval('line("$")'))
     -- Reduction
     scrollback = scrollback - 2
-    curbufmeths.set_option('scrollback', scrollback)
+    meths.set_option_value('scrollback', scrollback, {buf=0})
     eq(scrollback + term_height, eval('line("$")'))
   end)
 
   it('defaults to 10000 in :terminal buffers', function()
     set_fake_shell()
     command('terminal')
-    eq(10000, curbufmeths.get_option('scrollback'))
+    eq(10000, meths.get_option_value('scrollback', {buf=0}))
   end)
 
   it('error if set to invalid value', function()
@@ -507,7 +507,7 @@ describe("'scrollback' option", function()
 
   it('defaults to -1 on normal buffers', function()
     command('new')
-    eq(-1, curbufmeths.get_option('scrollback'))
+    eq(-1, meths.get_option_value('scrollback', {buf=0}))
   end)
 
   it(':setlocal in a :terminal buffer', function()
@@ -516,45 +516,45 @@ describe("'scrollback' option", function()
     -- _Global_ scrollback=-1 defaults :terminal to 10_000.
     command('setglobal scrollback=-1')
     command('terminal')
-    eq(10000, curbufmeths.get_option('scrollback'))
+    eq(10000, meths.get_option_value('scrollback', {buf=0}))
 
     -- _Local_ scrollback=-1 in :terminal forces the _maximum_.
     command('setlocal scrollback=-1')
     retry(nil, nil, function()  -- Fixup happens on refresh, not immediately.
-      eq(100000, curbufmeths.get_option('scrollback'))
+      eq(100000, meths.get_option_value('scrollback', {buf=0}))
     end)
 
     -- _Local_ scrollback=-1 during TermOpen forces the maximum. #9605
     command('setglobal scrollback=-1')
     command('autocmd TermOpen * setlocal scrollback=-1')
     command('terminal')
-    eq(100000, curbufmeths.get_option('scrollback'))
+    eq(100000, meths.get_option_value('scrollback', {buf=0}))
   end)
 
   it(':setlocal in a normal buffer', function()
     command('new')
     -- :setlocal to -1.
     command('setlocal scrollback=-1')
-    eq(-1, curbufmeths.get_option('scrollback'))
+    eq(-1, meths.get_option_value('scrollback', {buf=0}))
     -- :setlocal to anything except -1. Currently, this just has no effect.
     command('setlocal scrollback=42')
-    eq(42, curbufmeths.get_option('scrollback'))
+    eq(42, meths.get_option_value('scrollback', {buf=0}))
   end)
 
   it(':set updates local value and global default', function()
     set_fake_shell()
     command('set scrollback=42')                  -- set global value
-    eq(42, curbufmeths.get_option('scrollback'))
+    eq(42, meths.get_option_value('scrollback', {buf=0}))
     command('terminal')
-    eq(42, curbufmeths.get_option('scrollback'))  -- inherits global default
+    eq(42, meths.get_option_value('scrollback', {buf=0})) -- inherits global default
     command('setlocal scrollback=99')
-    eq(99, curbufmeths.get_option('scrollback'))
+    eq(99, meths.get_option_value('scrollback', {buf=0}))
     command('set scrollback<')                    -- reset to global default
-    eq(42, curbufmeths.get_option('scrollback'))
+    eq(42, meths.get_option_value('scrollback', {buf=0}))
     command('setglobal scrollback=734')           -- new global default
-    eq(42, curbufmeths.get_option('scrollback'))  -- local value did not change
+    eq(42, meths.get_option_value('scrollback', {buf=0})) -- local value did not change
     command('terminal')
-    eq(734, curbufmeths.get_option('scrollback'))
+    eq(734, meths.get_option_value('scrollback', {buf=0}))
   end)
 
 end)
@@ -578,7 +578,7 @@ describe("pending scrollback line handling", function()
       local api = vim.api
       local buf = api.nvim_create_buf(true, true)
       local chan = api.nvim_open_term(buf, {})
-      api.nvim_win_set_option(0, "number", true)
+      vim.wo.number = true
       api.nvim_chan_send(chan, ("a\n"):rep(11) .. "a")
       api.nvim_win_set_buf(0, buf)
     ]]
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 352009a1b1..3cfd222336 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -1458,9 +1458,9 @@ describe('TUI', function()
 
   it('allows grid to assume wider ambiguous-width characters than host terminal #19686', function()
     child_session:request('nvim_buf_set_lines', 0, 0, -1, true, { ('℃'):rep(60), ('℃'):rep(60) })
-    child_session:request('nvim_win_set_option', 0, 'cursorline', true)
-    child_session:request('nvim_win_set_option', 0, 'list', true)
-    child_session:request('nvim_win_set_option', 0, 'listchars', 'eol:$')
+    child_session:request('nvim_set_option_value', 'cursorline', true, {win=0})
+    child_session:request('nvim_set_option_value', 'list', true, {win=0})
+    child_session:request('nvim_set_option_value', 'listchars', 'eol:$', {win=0})
     feed_data('gg')
     local singlewidth_screen = [[
       {13:℃}{12:℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃℃}|
@@ -1483,9 +1483,9 @@ describe('TUI', function()
       {3:-- TERMINAL --}                                    |
     ]]
     screen:expect(singlewidth_screen)
-    child_session:request('nvim_set_option', 'ambiwidth', 'double')
+    child_session:request('nvim_set_option_value', 'ambiwidth', 'double', {})
     screen:expect(doublewidth_screen)
-    child_session:request('nvim_set_option', 'ambiwidth', 'single')
+    child_session:request('nvim_set_option_value', 'ambiwidth', 'single', {})
     screen:expect(singlewidth_screen)
     child_session:request('nvim_call_function', 'setcellwidths', {{{0x2103, 0x2103, 2}}})
     screen:expect(doublewidth_screen)
diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua
index 1d77e1e92e..3e1520e5fd 100644
--- a/test/functional/terminal/window_split_tab_spec.lua
+++ b/test/functional/terminal/window_split_tab_spec.lua
@@ -19,7 +19,7 @@ describe(':terminal', function()
     clear()
     -- set the statusline to a constant value because of variables like pid
     -- and current directory and to improve visibility of splits
-    meths.set_option('statusline', '==========')
+    meths.set_option_value('statusline', '==========', {})
     command('highlight StatusLine cterm=NONE')
     command('highlight StatusLineNC cterm=NONE')
     command('highlight VertSplit cterm=NONE')
@@ -71,7 +71,7 @@ describe(':terminal', function()
   end)
 
   it('does not change size if updated when not visible in any window #19665', function()
-    local channel = meths.buf_get_option(0, 'channel')
+    local channel = meths.get_option_value('channel', { buf = 0 })
     command('enew')
     sleep(100)
     meths.chan_send(channel, 'foo')
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
index 636f571641..17e6855ee4 100644
--- a/test/functional/ui/cmdline_highlight_spec.lua
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -178,7 +178,7 @@ end
 describe('Command-line coloring', function()
   it('works', function()
     set_color_cb('RainBowParens')
-    meths.set_option('more', false)
+    meths.set_option_value('more', false, {})
     start_prompt()
     screen:expect([[
                                               |
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 7e28caea04..01475a189d 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -265,8 +265,8 @@ describe('ui/cursor', function()
     }
 
     -- Another cursor style.
-    meths.set_option('guicursor', 'n-v-c:ver35-blinkwait171-blinkoff172-blinkon173'
-      ..',ve:hor35,o:ver50,i-ci:block,r-cr:hor90,sm:ver42')
+    meths.set_option_value('guicursor', 'n-v-c:ver35-blinkwait171-blinkoff172-blinkon173'
+      ..',ve:hor35,o:ver50,i-ci:block,r-cr:hor90,sm:ver42', {})
     screen:expect(function()
       local named = {}
       for _, m in ipairs(screen._mode_info) do
@@ -288,7 +288,7 @@ describe('ui/cursor', function()
     end)
 
     -- If there is no setting for guicursor, it becomes the default setting.
-    meths.set_option('guicursor', 'n:ver35-blinkwait171-blinkoff172-blinkon173-Cursor/lCursor')
+    meths.set_option_value('guicursor', 'n:ver35-blinkwait171-blinkoff172-blinkon173-Cursor/lCursor', {})
     screen:expect(function()
       for _,m in ipairs(screen._mode_info) do
         if m.name ~= 'normal' then
@@ -304,7 +304,7 @@ describe('ui/cursor', function()
   end)
 
   it("empty 'guicursor' sets cursor_shape=block in all modes", function()
-    meths.set_option('guicursor', '')
+    meths.set_option_value('guicursor', '', {})
     screen:expect(function()
       -- Empty 'guicursor' sets enabled=false.
       eq(false, screen._cursor_style_enabled)
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index f531878bc6..324362a865 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1910,7 +1910,7 @@ describe('decorations: signs', function()
     }
 
     ns = meths.create_namespace 'test'
-    meths.win_set_option(0, 'signcolumn', 'auto:9')
+    meths.set_option_value('signcolumn', 'auto:9', {win = 0})
   end)
 
   local example_text = [[
@@ -2222,7 +2222,7 @@ l5
     ]]}
 
     -- Check truncation works too
-    meths.win_set_option(0, 'signcolumn', 'auto')
+    meths.set_option_value('signcolumn', 'auto', {win = 0})
 
     screen:expect{grid=[[
       S5^l1                |
@@ -2233,7 +2233,7 @@ l5
 
   it('does not set signcolumn for signs without text', function()
     screen:try_resize(20, 3)
-    meths.win_set_option(0, 'signcolumn', 'auto')
+    meths.set_option_value('signcolumn', 'auto', {win = 0})
     insert(example_text)
     feed 'gg'
     meths.buf_set_extmark(0, ns, 0, -1, {number_hl_group='Error'})
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 46a079d9ff..19ad340dd5 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -105,7 +105,7 @@ describe('float window', function()
 
   it('opened with correct height', function()
     local height = exec_lua([[
-      vim.api.nvim_set_option("winheight", 20)
+      vim.go.winheight = 20
       local bufnr = vim.api.nvim_create_buf(false, true)
 
       local opts = {
@@ -127,7 +127,7 @@ describe('float window', function()
 
   it('opened with correct width', function()
     local width = exec_lua([[
-      vim.api.nvim_set_option("winwidth", 20)
+      vim.go.winwidth = 20
       local bufnr = vim.api.nvim_create_buf(false, true)
 
       local opts = {
@@ -427,36 +427,36 @@ describe('float window', function()
   it("no segfault when setting minimal style after clearing local 'fillchars' #19510", function()
     local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1}
     local float_win = meths.open_win(0, true, float_opts)
-    meths.win_set_option(float_win, 'fillchars', NIL)
+    meths.set_option_value('fillchars', NIL, {win=float_win.id})
     float_opts.style = 'minimal'
     meths.win_set_config(float_win, float_opts)
     assert_alive()
-  end)
+    end)
 
-  it("should re-apply 'style' when present", function()
+    it("should re-apply 'style' when present", function()
     local float_opts = {style = 'minimal', relative = 'editor', row = 1, col = 1, width = 1, height = 1}
     local float_win = meths.open_win(0, true, float_opts)
-    meths.win_set_option(float_win, 'number', true)
+    meths.set_option_value('number', true, { win = float_win })
     float_opts.row = 2
     meths.win_set_config(float_win, float_opts)
-    eq(false, meths.win_get_option(float_win, 'number'))
+    eq(false, meths.get_option_value('number', { win = float_win }))
   end)
 
   it("should not re-apply 'style' when missing", function()
     local float_opts = {style = 'minimal', relative = 'editor', row = 1, col = 1, width = 1, height = 1}
     local float_win = meths.open_win(0, true, float_opts)
-    meths.win_set_option(float_win, 'number', true)
+    meths.set_option_value('number', true, { win = float_win })
     float_opts.row = 2
     float_opts.style = nil
     meths.win_set_config(float_win, float_opts)
-    eq(true, meths.win_get_option(float_win, 'number'))
+    eq(true, meths.get_option_value('number', { win = float_win }))
   end)
 
   it("'scroll' is computed correctly when opening float with splitkeep=screen #20684", function()
-    meths.set_option('splitkeep', 'screen')
+    meths.set_option_value('splitkeep', 'screen', {})
     local float_opts = {relative = 'editor', row = 1, col = 1, width = 10, height = 10}
     local float_win = meths.open_win(0, true, float_opts)
-    eq(5, meths.win_get_option(float_win, 'scroll'))
+    eq(5, meths.get_option_value('scroll', {win=float_win.id}))
   end)
 
   describe('with only one tabpage,', function()
@@ -4553,8 +4553,8 @@ describe('float window', function()
     describe('and completion', function()
       before_each(function()
         local buf = meths.create_buf(false,false)
-        local win = meths.open_win(buf, true, {relative='editor', width=12, height=4, row=2, col=5})
-        meths.win_set_option(win , 'winhl', 'Normal:ErrorMsg')
+        local win = meths.open_win(buf, true, {relative='editor', width=12, height=4, row=2, col=5}).id
+        meths.set_option_value('winhl', 'Normal:ErrorMsg', {win=win})
         if multigrid then
           screen:expect{grid=[[
           ## grid 1
@@ -7823,7 +7823,7 @@ describe('float window', function()
       local buf = meths.create_buf(false,false)
       meths.buf_set_lines(buf, 0, -1, true, {'foo', 'bar', 'baz'})
       local float_win = meths.open_win(buf, false, {relative='editor', width=20, height=4, row=1, col=5})
-      meths.win_set_option(float_win, 'winbar', 'floaty bar')
+      meths.set_option_value('winbar', 'floaty bar', {win=float_win.id})
       if multigrid then
         screen:expect{grid=[[
         ## grid 1
@@ -8144,7 +8144,7 @@ describe('float window', function()
         ]])
       end
 
-      meths.win_set_option(win, "winblend", 30)
+      meths.set_option_value("winblend", 30, {win=win.id})
       if multigrid then
         screen:expect{grid=[[
         ## grid 1
@@ -8452,7 +8452,7 @@ describe('float window', function()
       -- at least. Also check invisible EndOfBuffer region blends correctly.
       meths.buf_set_lines(buf, 0, -1, true, {" x x  x   xx", "  x x  x   x"})
       win = meths.open_win(buf, false, {relative='editor', width=12, height=3, row=0, col=11, style='minimal'})
-      meths.win_set_option(win, 'winblend', 30)
+      meths.set_option_value('winblend', 30, {win=win.id})
       screen:set_default_attr_ids({
         [1] = {foreground = tonumber('0xb282b2'), background = tonumber('0xffcfff')},
         [2] = {foreground = Screen.colors.Grey0, background = tonumber('0xffcfff')},
@@ -8694,7 +8694,7 @@ describe('float window', function()
     it("correctly orders multiple opened floats (current last)", function()
       local buf = meths.create_buf(false,false)
       local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5})
-      meths.win_set_option(win, "winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg")
+      meths.set_option_value("winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg", {win=win.id})
 
       if multigrid then
         screen:expect{grid=[[
@@ -8739,10 +8739,10 @@ describe('float window', function()
       exec_lua [[
         local buf = vim.api.nvim_create_buf(false,false)
         local win = vim.api.nvim_open_win(buf, false, {relative='editor', width=16, height=2, row=3, col=8})
-        vim.api.nvim_win_set_option(win, "winhl", "EndOfBuffer:Normal")
+        vim.wo[win].winhl = "EndOfBuffer:Normal"
         buf = vim.api.nvim_create_buf(false,false)
         win = vim.api.nvim_open_win(buf, true, {relative='editor', width=12, height=2, row=4, col=10})
-        vim.api.nvim_win_set_option(win, "winhl", "Normal:Search,EndOfBuffer:Search")
+        vim.wo[win].winhl = "Normal:Search,EndOfBuffer:Search"
       ]]
 
       if multigrid then
@@ -8799,7 +8799,7 @@ describe('float window', function()
     it("correctly orders multiple opened floats (non-current last)", function()
       local buf = meths.create_buf(false,false)
       local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5})
-      meths.win_set_option(win, "winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg")
+      meths.set_option_value("winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg", {win=win.id})
 
       if multigrid then
         screen:expect{grid=[[
@@ -8844,10 +8844,10 @@ describe('float window', function()
       exec_lua [[
         local buf = vim.api.nvim_create_buf(false,false)
         local win = vim.api.nvim_open_win(buf, true, {relative='editor', width=12, height=2, row=4, col=10})
-        vim.api.nvim_win_set_option(win, "winhl", "Normal:Search,EndOfBuffer:Search")
+        vim.wo[win].winhl = "Normal:Search,EndOfBuffer:Search"
         buf = vim.api.nvim_create_buf(false,false)
         win = vim.api.nvim_open_win(buf, false, {relative='editor', width=16, height=2, row=3, col=8})
-        vim.api.nvim_win_set_option(win, "winhl", "EndOfBuffer:Normal")
+        vim.wo[win].winhl = "EndOfBuffer:Normal"
       ]]
 
       if multigrid then
@@ -8904,11 +8904,11 @@ describe('float window', function()
     it('can use z-index', function()
       local buf = meths.create_buf(false,false)
       local win1 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=1, col=5, zindex=30})
-      meths.win_set_option(win1, "winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg")
+      meths.set_option_value("winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg", {win=win1.id})
       local win2 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=2, col=6, zindex=50})
-      meths.win_set_option(win2, "winhl", "Normal:Search,EndOfBuffer:Search")
+      meths.set_option_value("winhl", "Normal:Search,EndOfBuffer:Search", {win=win2.id})
       local win3 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=3, col=7, zindex=40})
-      meths.win_set_option(win3, "winhl", "Normal:Question,EndOfBuffer:Question")
+      meths.set_option_value("winhl", "Normal:Question,EndOfBuffer:Question", {win=win3.id})
 
       if multigrid then
         screen:expect{grid=[[
@@ -8967,7 +8967,7 @@ describe('float window', function()
     it('can use winbar', function()
       local buf = meths.create_buf(false,false)
       local win1 = meths.open_win(buf, false, {relative='editor', width=15, height=3, row=1, col=5})
-      meths.win_set_option(win1, 'winbar', 'floaty bar')
+      meths.set_option_value('winbar', 'floaty bar', {win=win1.id})
 
       if multigrid then
         screen:expect{grid=[[
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index a99b77f707..7a0495f93c 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -967,8 +967,8 @@ describe("folded lines", function()
 
     it("works with multibyte text", function()
       -- Currently the only allowed value of 'maxcombine'
-      eq(6, meths.get_option('maxcombine'))
-      eq(true, meths.get_option('arabicshape'))
+      eq(6, meths.get_option_value('maxcombine', {}))
+      eq(true, meths.get_option_value('arabicshape', {}))
       insert([[
         å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢͟ العَرَبِيَّة
         möre text]])
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 28f489783b..23b200bd24 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -2,7 +2,6 @@ local helpers = require('test.functional.helpers')(after_each)
 local Screen = require('test.functional.ui.screen')
 local clear = helpers.clear
 local command = helpers.command
-local curbufmeths = helpers.curbufmeths
 local eq = helpers.eq
 local eval = helpers.eval
 local feed_command = helpers.feed_command
@@ -178,8 +177,8 @@ describe(":substitute, 'inccommand' preserves", function()
       feed_command("set inccommand=" .. case)
       insert("as")
       feed(":%s/as/glork/")
-      eq(meths.get_option('undolevels'), 139)
-      eq(curbufmeths.get_option('undolevels'), 34)
+      eq(meths.get_option_value('undolevels', {scope='global'}), 139)
+      eq(meths.get_option_value('undolevels', {buf=0}), 34)
     end)
   end
 
@@ -1192,7 +1191,7 @@ describe(":substitute, inccommand=split", function()
 
   it("deactivates if 'redrawtime' is exceeded #5602", function()
     -- prevent redraws from 'incsearch'
-    meths.set_option('incsearch', false)
+    meths.set_option_value('incsearch', false, {})
     -- Assert that 'inccommand' is ENABLED initially.
     eq("split", eval("&inccommand"))
     -- Set 'redrawtime' to minimal value, to ensure timeout is triggered.
@@ -2465,16 +2464,14 @@ describe(":substitute", function()
   end)
 
   it("inccommand=split, contraction of two subsequent NL chars", function()
-    -- luacheck: push ignore 611
     local text = [[
       AAA AA
-      
+
       BBB BB
-      
+
       CCC CC
-      
+
 ]]
-    -- luacheck: pop
 
     -- This used to crash, but more than 20 highlight entries are required
     -- to reproduce it (so that the marktree has multiple nodes)
@@ -2501,16 +2498,14 @@ describe(":substitute", function()
   end)
 
   it("inccommand=nosplit, contraction of two subsequent NL chars", function()
-    -- luacheck: push ignore 611
     local text = [[
       AAA AA
-      
+
       BBB BB
-      
+
       CCC CC
-      
+
 ]]
-    -- luacheck: pop
 
     common_setup(screen, "nosplit", string.rep(text,10))
     feed(":%s/\\n\\n//g")
diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua
index 43e9b94feb..6329ece40a 100644
--- a/test/functional/ui/inccommand_user_spec.lua
+++ b/test/functional/ui/inccommand_user_spec.lua
@@ -391,7 +391,7 @@ describe("'inccommand' for user commands", function()
       vim.api.nvim_create_user_command('Replace', function() end, {
         nargs = '*',
         preview = function()
-          vim.api.nvim_set_option('inccommand', 'split')
+          vim.api.nvim_set_option_value('inccommand', 'split', {})
           return 2
         end,
       })
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 1a7fe26d26..46a42e5beb 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -1273,7 +1273,7 @@ vimComment     xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1  excludenl contains=@vim
       {1:~                                                           }|
                                                                   |
     ]])
-    eq(1, meths.get_option('cmdheight'))
+    eq(1, meths.get_option_value('cmdheight', {}))
   end)
 end)
 
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index e55804e29f..d8739e1c31 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -11,8 +11,8 @@ describe('ui/mouse/input', function()
 
   before_each(function()
     clear()
-    meths.set_option('mouse', 'a')
-    meths.set_option('list', true)
+    meths.set_option_value('mouse', 'a', {})
+    meths.set_option_value('list', true, {})
     -- NB: this is weird, but mostly irrelevant to the test
     -- So I didn't bother to change it
     command('set listchars=eol:$')
@@ -64,7 +64,7 @@ describe('ui/mouse/input', function()
   end)
 
   it("in external ui works with unset 'mouse'", function()
-    meths.set_option('mouse', '')
+    meths.set_option_value('mouse', '', {})
     feed('<2,1>')
     screen:expect{grid=[[
       testing                  |
@@ -379,7 +379,7 @@ describe('ui/mouse/input', function()
     end)
 
     it('left click in default tabline (position 24) closes tab', function()
-      meths.set_option('hidden', true)
+      meths.set_option_value('hidden', true, {})
       feed_command('%delete')
       insert('this is foo')
       feed_command('silent file foo | tabnew | file bar')
@@ -402,7 +402,7 @@ describe('ui/mouse/input', function()
     end)
 
     it('double click in default tabline (position 4) opens new tab', function()
-      meths.set_option('hidden', true)
+      meths.set_option_value('hidden', true, {})
       feed_command('%delete')
       insert('this is foo')
       feed_command('silent file foo | tabnew | file bar')
@@ -437,8 +437,8 @@ describe('ui/mouse/input', function()
             return call('Test', a:000 + [2])
           endfunction
         ]])
-        meths.set_option('tabline', '%@Test@test%X-%5@Test2@test2')
-        meths.set_option('showtabline', 2)
+        meths.set_option_value('tabline', '%@Test@test%X-%5@Test2@test2', {})
+        meths.set_option_value('showtabline', 2, {})
         screen:expect([[
           {fill:test-test2               }|
           testing                  |
@@ -786,7 +786,7 @@ describe('ui/mouse/input', function()
   end)
 
   it('ctrl + left click will search for a tag', function()
-    meths.set_option('tags', './non-existent-tags-file')
+    meths.set_option_value('tags', './non-existent-tags-file', {})
     feed('<0,0>')
     screen:expect([[
       {6:E433: No tags file}       |
@@ -1577,9 +1577,9 @@ describe('ui/mouse/input', function()
   end)
 
   it('getmousepos works correctly', function()
-    local winwidth = meths.get_option('winwidth')
+    local winwidth = meths.get_option_value('winwidth', {})
     -- Set winwidth=1 so that window sizes don't change.
-    meths.set_option('winwidth', 1)
+    meths.set_option_value('winwidth', 1, {})
     command('tabedit')
     local tabpage = meths.get_current_tabpage()
     insert('hello')
@@ -1597,8 +1597,8 @@ describe('ui/mouse/input', function()
     }
     local float = meths.open_win(meths.get_current_buf(), false, opts)
     command('redraw')
-    local lines = meths.get_option('lines')
-    local columns = meths.get_option('columns')
+    local lines = meths.get_option_value('lines', {})
+    local columns = meths.get_option_value('columns', {})
 
     -- Test that screenrow and screencol are set properly for all positions.
     for row = 0, lines - 1 do
@@ -1696,7 +1696,7 @@ describe('ui/mouse/input', function()
 
     -- Restore state and release mouse.
     command('tabclose!')
-    meths.set_option('winwidth', winwidth)
+    meths.set_option_value('winwidth', winwidth, {})
     meths.input_mouse('left', 'release', '', 0, 0, 0)
   end)
 
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 4c04bcb54e..8918c46de6 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -3555,7 +3555,7 @@ describe('ext_multigrid', function()
   end)
 
   it('with winbar dragging statusline with mouse works correctly', function()
-    meths.set_option('winbar', 'Set Up The Bars')
+    meths.set_option_value('winbar', 'Set Up The Bars', {})
     command('split')
     screen:expect([[
     ## grid 1
@@ -3695,7 +3695,7 @@ describe('ext_multigrid', function()
       {1:~                                                    }|
       {1:~                                                    }|
     ]])
-    eq(3, meths.get_option('cmdheight'))
+    eq(3, meths.get_option_value('cmdheight', {}))
 
     meths.input_mouse('left', 'drag', '', 1, 12, 10)
     screen:expect([[
@@ -3730,6 +3730,6 @@ describe('ext_multigrid', function()
       {1:~                                                    }|
       {1:~                                                    }|
     ]])
-    eq(1, meths.get_option('cmdheight'))
+    eq(1, meths.get_option_value('cmdheight', {}))
   end)
 end)
diff --git a/test/functional/ui/quickfix_spec.lua b/test/functional/ui/quickfix_spec.lua
index b0d89ee3b6..df43871e60 100644
--- a/test/functional/ui/quickfix_spec.lua
+++ b/test/functional/ui/quickfix_spec.lua
@@ -27,7 +27,7 @@ describe('quickfix selection highlight', function()
       [12] = {foreground = Screen.colors.Brown, background = Screen.colors.Fuchsia},
     })
 
-    meths.set_option('errorformat', '%m %l')
+    meths.set_option_value('errorformat', '%m %l', {})
     command('syntax on')
     command('highlight Search guibg=Green')
 
diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index e1ae76badf..b31e40d4ab 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -828,7 +828,7 @@ local function screen_tests(linegrid)
       command([[autocmd VimResized * redrawtabline]])
       command([[autocmd VimResized * lua vim.api.nvim_echo({ { 'Hello' } }, false, {})]])
       command([[autocmd VimResized * let g:echospace = v:echospace]])
-      meths.set_option('showtabline', 2)
+      meths.set_option_value('showtabline', 2, {})
       screen:expect([[
         {2: + [No Name] }{3:            }|
         resiz^e                   |
@@ -1056,8 +1056,8 @@ it('CTRL-F or CTRL-B scrolls a page after UI attach/resize #20605', function()
   clear()
   local screen = Screen.new(100, 100)
   screen:attach()
-  eq(100, meths.get_option('lines'))
-  eq(99, meths.get_option('window'))
+  eq(100, meths.get_option_value('lines', {}))
+  eq(99, meths.get_option_value('window', {}))
   eq(99, meths.win_get_height(0))
   feed('1000o')
   eq(903, funcs.line('w0'))
@@ -1071,8 +1071,8 @@ it('CTRL-F or CTRL-B scrolls a page after UI attach/resize #20605', function()
   eq(903, funcs.line('w0'))
   feed('G')
   screen:try_resize(50, 50)
-  eq(50, meths.get_option('lines'))
-  eq(49, meths.get_option('window'))
+  eq(50, meths.get_option_value('lines', {}))
+  eq(49, meths.get_option_value('window', {}))
   eq(49, meths.win_get_height(0))
   eq(953, funcs.line('w0'))
   feed('')
diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua
index 5ea4eade4e..5afa912be6 100644
--- a/test/functional/ui/statusline_spec.lua
+++ b/test/functional/ui/statusline_spec.lua
@@ -34,7 +34,7 @@ for _, model in ipairs(mousemodels) do
       end)
 
       it('works', function()
-        meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+        meths.set_option_value('statusline',  'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
         meths.input_mouse('left', 'press', '', 0, 6, 17)
         eq('0 1 l', eval("g:testvar"))
         meths.input_mouse('left', 'press', '', 0, 6, 17)
@@ -54,7 +54,7 @@ for _, model in ipairs(mousemodels) do
       end)
 
       it('works for winbar', function()
-        meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+        meths.set_option_value('winbar',  'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
         meths.input_mouse('left', 'press', '', 0, 0, 17)
         eq('0 1 l', eval("g:testvar"))
         meths.input_mouse('right', 'press', '', 0, 0, 17)
@@ -72,8 +72,8 @@ for _, model in ipairs(mousemodels) do
 
       it('works when there are multiple windows', function()
         command('split')
-        meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
-        meths.set_option('winbar', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+        meths.set_option_value('statusline',  'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
+        meths.set_option_value('winbar',  'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
         meths.input_mouse('left', 'press', '', 0, 0, 17)
         eq('0 1 l', eval("g:testvar"))
         meths.input_mouse('right', 'press', '', 0, 4, 17)
@@ -90,23 +90,23 @@ for _, model in ipairs(mousemodels) do
           vim.g.testvar = string.format("%d %d %s", minwid, clicks, button)
         end
         ]])
-        meths.set_option('statusline', 'Not clicky stuff %0@v:lua.clicky_func@Clicky stuff%T')
+        meths.set_option_value('statusline',  'Not clicky stuff %0@v:lua.clicky_func@Clicky stuff%T', {})
         meths.input_mouse('left', 'press', '', 0, 6, 17)
         eq('0 1 l', eval("g:testvar"))
       end)
 
       it('ignores unsupported click items', function()
         command('tabnew | tabprevious')
-        meths.set_option('statusline', '%2TNot clicky stuff%T')
+        meths.set_option_value('statusline',  '%2TNot clicky stuff%T', {})
         meths.input_mouse('left', 'press', '', 0, 6, 0)
         eq(1, meths.get_current_tabpage().id)
-        meths.set_option('statusline', '%2XNot clicky stuff%X')
+        meths.set_option_value('statusline',  '%2XNot clicky stuff%X', {})
         meths.input_mouse('left', 'press', '', 0, 6, 0)
         eq(2, #meths.list_tabpages())
       end)
 
       it("right click works when statusline isn't focused #18994", function()
-        meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+        meths.set_option_value('statusline',  'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
         meths.input_mouse('right', 'press', '', 0, 6, 17)
         eq('0 1 r', eval("g:testvar"))
         meths.input_mouse('right', 'press', '', 0, 6, 17)
@@ -114,7 +114,7 @@ for _, model in ipairs(mousemodels) do
       end)
 
       it("works with modifiers #18994", function()
-        meths.set_option('statusline', 'Not clicky stuff %0@MyClickFunc@Clicky stuff%T')
+        meths.set_option_value('statusline',  'Not clicky stuff %0@MyClickFunc@Clicky stuff%T', {})
         -- Note: alternate between left and right mouse buttons to avoid triggering multiclicks
         meths.input_mouse('left', 'press', 'S', 0, 6, 17)
         eq('0 1 l(s   )', eval("g:testvar"))
@@ -143,7 +143,7 @@ for _, model in ipairs(mousemodels) do
 
       it("works for global statusline with vertical splits #19186", function()
         command('set laststatus=3')
-        meths.set_option('statusline', '%0@MyClickFunc@Clicky stuff%T %= %0@MyClickFunc@Clicky stuff%T')
+        meths.set_option_value('statusline',  '%0@MyClickFunc@Clicky stuff%T %= %0@MyClickFunc@Clicky stuff%T', {})
         command('vsplit')
         screen:expect([[
         ^                    │                   |
@@ -394,38 +394,38 @@ describe('global statusline', function()
   end)
 
   it('win_move_statusline() can reduce cmdheight to 1', function()
-    eq(1, meths.get_option('cmdheight'))
+    eq(1, meths.get_option_value('cmdheight', {}))
     funcs.win_move_statusline(0, -1)
-    eq(2, meths.get_option('cmdheight'))
+    eq(2, meths.get_option_value('cmdheight', {}))
     funcs.win_move_statusline(0, -1)
-    eq(3, meths.get_option('cmdheight'))
+    eq(3, meths.get_option_value('cmdheight', {}))
     funcs.win_move_statusline(0, 1)
-    eq(2, meths.get_option('cmdheight'))
+    eq(2, meths.get_option_value('cmdheight', {}))
     funcs.win_move_statusline(0, 1)
-    eq(1, meths.get_option('cmdheight'))
+    eq(1, meths.get_option_value('cmdheight', {}))
   end)
 
   it('mouse dragging can reduce cmdheight to 1', function()
     command('set mouse=a')
     meths.input_mouse('left', 'press', '', 0, 14, 10)
-    eq(1, meths.get_option('cmdheight'))
+    eq(1, meths.get_option_value('cmdheight', {}))
     meths.input_mouse('left', 'drag', '', 0, 13, 10)
-    eq(2, meths.get_option('cmdheight'))
+    eq(2, meths.get_option_value('cmdheight', {}))
     meths.input_mouse('left', 'drag', '', 0, 12, 10)
-    eq(3, meths.get_option('cmdheight'))
+    eq(3, meths.get_option_value('cmdheight', {}))
     meths.input_mouse('left', 'drag', '', 0, 13, 10)
-    eq(2, meths.get_option('cmdheight'))
+    eq(2, meths.get_option_value('cmdheight', {}))
     meths.input_mouse('left', 'drag', '', 0, 14, 10)
-    eq(1, meths.get_option('cmdheight'))
+    eq(1, meths.get_option_value('cmdheight', {}))
     meths.input_mouse('left', 'drag', '', 0, 15, 10)
-    eq(1, meths.get_option('cmdheight'))
+    eq(1, meths.get_option_value('cmdheight', {}))
     meths.input_mouse('left', 'drag', '', 0, 14, 10)
-    eq(1, meths.get_option('cmdheight'))
+    eq(1, meths.get_option_value('cmdheight', {}))
   end)
 
   it('cmdline row is correct after setting cmdheight #20514', function()
     command('botright split test/functional/fixtures/bigfile.txt')
-    meths.set_option('cmdheight', 1)
+    meths.set_option_value('cmdheight', 1, {})
     feed('L')
     screen:expect([[
                                                                   |
@@ -464,7 +464,7 @@ describe('global statusline', function()
       {2:test/functional/fixtures/bigfile.txt      8,1             0%}|
                                                                   |
     ]])
-    meths.set_option('showtabline', 2)
+    meths.set_option_value('showtabline', 2, {})
     screen:expect([[
       {3: }{5:2}{3: t/f/f/bigfile.txt }{4:                                       }|
                                                                   |
@@ -483,7 +483,7 @@ describe('global statusline', function()
       {2:test/functional/fixtures/bigfile.txt      8,1             0%}|
                                                                   |
     ]])
-    meths.set_option('cmdheight', 0)
+    meths.set_option_value('cmdheight', 0, {})
     screen:expect([[
       {3: }{5:2}{3: t/f/f/bigfile.txt }{4:                                       }|
                                                                   |
@@ -502,7 +502,7 @@ describe('global statusline', function()
       ^0007;;Cc;0;BN;;;;;N;BELL;;;;                       |
       {2:test/functional/fixtures/bigfile.txt      8,1             0%}|
     ]])
-    meths.set_option('cmdheight', 1)
+    meths.set_option_value('cmdheight', 1, {})
     screen:expect([[
       {3: }{5:2}{3: t/f/f/bigfile.txt }{4:                                       }|
                                                                   |
@@ -526,8 +526,8 @@ end)
 
 it('statusline does not crash if it has Arabic characters #19447', function()
   clear()
-  meths.set_option('statusline', 'غً')
-  meths.set_option('laststatus', 2)
+  meths.set_option_value('statusline', 'غً', {})
+  meths.set_option_value('laststatus', 2, {})
   command('redraw!')
   assert_alive()
 end)
diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua
index 75ead49f74..2247d2e80f 100644
--- a/test/functional/ui/title_spec.lua
+++ b/test/functional/ui/title_spec.lua
@@ -57,18 +57,18 @@ describe('title', function()
       end)
     end)
 
-    it('an RPC call to nvim_buf_set_option in a hidden buffer', function()
-      meths.buf_set_option(buf2, 'autoindent', true)
+    it('an RPC call to nvim_set_option_value in a hidden buffer', function()
+      meths.set_option_value('autoindent', true, { buf = buf2 })
       command('redraw!')
       screen:expect(function()
         eq(expected, screen.title)
       end)
     end)
 
-    it('a Lua callback calling nvim_buf_set_option in a hidden buffer', function()
+    it('a Lua callback calling nvim_set_option_value in a hidden buffer', function()
       exec_lua(string.format([[
         vim.schedule(function()
-          vim.api.nvim_buf_set_option(%d, 'autoindent', true)
+          vim.api.nvim_set_option_value('autoindent', true, { buf = %d })
         end)
       ]], buf2))
       command('redraw!')
diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua
index 50466c9473..0355c57b5a 100644
--- a/test/functional/ui/wildmode_spec.lua
+++ b/test/functional/ui/wildmode_spec.lua
@@ -367,12 +367,12 @@ describe("'wildmenu'", function()
     }
 
     -- Wildcharm? where we are going we aint't no need no wildcharm.
-    eq(0, meths.get_option'wildcharm')
+    eq(0, meths.get_option_value('wildcharm', {}))
     -- Don't mess the defaults yet (neovim is about backwards compatibility)
-    eq(9, meths.get_option'wildchar')
+    eq(9, meths.get_option_value('wildchar', {}))
     -- Lol what is cnoremap? Some say it can define mappings.
     command 'set wildchar=0'
-    eq(0, meths.get_option'wildchar')
+    eq(0, meths.get_option_value('wildchar', {}))
 
     command 'cnoremap  '
     feed(':syntax ')
@@ -481,9 +481,9 @@ describe('command line completion', function()
   end)
 
   it('does not leak memory with  with wildmenu and only one match #19874', function()
-    meths.set_option('wildmenu', true)
-    meths.set_option('wildmode', 'full')
-    meths.set_option('wildoptions', 'pum')
+    meths.set_option_value('wildmenu', true, {})
+    meths.set_option_value('wildmode', 'full', {})
+    meths.set_option_value('wildoptions', 'pum', {})
 
     feed(':sign unpla')
     screen:expect([[
@@ -505,8 +505,8 @@ describe('command line completion', function()
   end)
 
   it('does not show matches with  without wildmenu with wildmode=full', function()
-    meths.set_option('wildmenu', false)
-    meths.set_option('wildmode', 'full')
+    meths.set_option_value('wildmenu', false, {})
+    meths.set_option_value('wildmode', 'full', {})
 
     feed(':sign ')
     screen:expect([[
@@ -519,8 +519,8 @@ describe('command line completion', function()
   end)
 
   it('shows matches with  without wildmenu with wildmode=list', function()
-    meths.set_option('wildmenu', false)
-    meths.set_option('wildmode', 'list')
+    meths.set_option_value('wildmenu', false, {})
+    meths.set_option_value('wildmode', 'list', {})
 
     feed(':sign ')
     screen:expect([[
diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua
index 3b79f4328d..78bbcd3a63 100644
--- a/test/functional/ui/winbar_spec.lua
+++ b/test/functional/ui/winbar_spec.lua
@@ -31,7 +31,7 @@ describe('winbar', function()
       [10] = {background = Screen.colors.LightGrey, underline = true},
       [11] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta},
     })
-    meths.set_option('winbar', 'Set Up The Bars')
+    meths.set_option_value('winbar', 'Set Up The Bars', {})
   end)
 
   it('works', function()
@@ -206,7 +206,7 @@ describe('winbar', function()
     insert [[
       just some
       random text]]
-    meths.set_option('winbar', 'Hello, I am a ruler: %l,%c')
+    meths.set_option_value('winbar', 'Hello, I am a ruler: %l,%c', {})
     screen:expect{grid=[[
       {1:Hello, I am a ruler: 2,11                                   }|
       just some                                                   |
@@ -450,7 +450,7 @@ describe('winbar', function()
                                                                   |
                                                                   |
     ]])
-    eq(3, meths.get_option('cmdheight'))
+    eq(3, meths.get_option_value('cmdheight', {}))
 
     meths.input_mouse('left', 'drag', '', 1, 11, 10)
     screen:expect([[
@@ -468,7 +468,7 @@ describe('winbar', function()
       {2:[No Name]                                                   }|
                                                                   |
     ]])
-    eq(1, meths.get_option('cmdheight'))
+    eq(1, meths.get_option_value('cmdheight', {}))
   end)
 
   it('properly equalizes window height for window-local value', function()
diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua
index dc591c3e0d..3404b06a55 100644
--- a/test/functional/vimscript/api_functions_spec.lua
+++ b/test/functional/vimscript/api_functions_spec.lua
@@ -32,8 +32,8 @@ describe('eval-API', function()
     local err = exc_exec('call nvim_get_current_buf("foo")')
     eq('Vim(call):E118: Too many arguments for function: nvim_get_current_buf', err)
 
-    err = exc_exec('call nvim_set_option("hlsearch")')
-    eq('Vim(call):E119: Not enough arguments for function: nvim_set_option', err)
+    err = exc_exec('call nvim_set_option_value("hlsearch")')
+    eq('Vim(call):E119: Not enough arguments for function: nvim_set_option_value', err)
 
     err = exc_exec('call nvim_buf_set_lines(1, 0, -1, [], ["list"])')
     eq('Vim(call):E5555: API call: Wrong type for argument 4 when calling nvim_buf_set_lines, expecting Boolean', err)
diff --git a/test/functional/vimscript/buf_functions_spec.lua b/test/functional/vimscript/buf_functions_spec.lua
index 7a54f479e0..2d6d4b8e04 100644
--- a/test/functional/vimscript/buf_functions_spec.lua
+++ b/test/functional/vimscript/buf_functions_spec.lua
@@ -9,7 +9,6 @@ local meths = helpers.meths
 local command = helpers.command
 local exc_exec = helpers.exc_exec
 local bufmeths = helpers.bufmeths
-local winmeths = helpers.winmeths
 local curbufmeths = helpers.curbufmeths
 local curwinmeths = helpers.curwinmeths
 local curtabmeths = helpers.curtabmeths
@@ -189,7 +188,7 @@ describe('getbufline() function', function()
     eq({}, funcs.getbufline(1, -1, 9999))
   end)
   it('returns expected lines', function()
-    meths.set_option('hidden', true)
+    meths.set_option_value('hidden', true, {})
     command('file ' .. fname)
     curbufmeths.set_lines(0, 1, false, {'foo\0', '\0bar', 'baz'})
     command('edit ' .. fname2)
@@ -269,24 +268,25 @@ describe('setbufvar() function', function()
   end)
   it('may set options, including window-local and global values', function()
     local buf1 = meths.get_current_buf()
-    eq(false, curwinmeths.get_option('number'))
+    eq(false, meths.get_option_value('number', {win=0}))
     command('split')
     command('new')
     eq(2, bufmeths.get_number(curwinmeths.get_buf()))
     funcs.setbufvar(1, '&number', true)
     local windows = curtabmeths.list_wins()
-    eq(false, winmeths.get_option(windows[1], 'number'))
-    eq(true, winmeths.get_option(windows[2], 'number'))
-    eq(false, winmeths.get_option(windows[3], 'number'))
-    eq(false, winmeths.get_option(meths.get_current_win(), 'number'))
+    eq(false, meths.get_option_value('number', {win=windows[1].id}))
+    eq(true, meths.get_option_value('number', {win=windows[2].id}))
+    eq(false, meths.get_option_value('number', {win=windows[3].id}))
+    eq(false, meths.get_option_value('number', {win=meths.get_current_win().id}))
 
-    eq(true, meths.get_option('hidden'))
+
+    eq(true, meths.get_option_value('hidden', {}))
     funcs.setbufvar(1, '&hidden', 0)
-    eq(false, meths.get_option('hidden'))
+    eq(false, meths.get_option_value('hidden', {}))
 
-    eq(false, bufmeths.get_option(buf1, 'autoindent'))
+    eq(false, meths.get_option_value('autoindent', {buf=buf1.id}))
     funcs.setbufvar(1, '&autoindent', true)
-    eq(true, bufmeths.get_option(buf1, 'autoindent'))
+    eq(true, meths.get_option_value('autoindent', {buf=buf1.id}))
     eq('Vim(call):E355: Unknown option: xxx',
        exc_exec('call setbufvar(1, "&xxx", 0)'))
   end)
diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua
index d1643a799a..bd9f7e5381 100644
--- a/test/functional/vimscript/input_spec.lua
+++ b/test/functional/vimscript/input_spec.lua
@@ -452,8 +452,8 @@ end)
 describe('confirm()', function()
   -- oldtest: Test_confirm()
   it('works', function()
-    meths.set_option('more', false)  -- Avoid hit-enter prompt
-    meths.set_option('laststatus', 2)
+    meths.set_option_value('more', false, {})  -- Avoid hit-enter prompt
+    meths.set_option_value('laststatus', 2, {})
     -- screen:expect() calls are needed to avoid feeding input too early
     screen:expect({any = '%[No Name%]'})
 
diff --git a/test/functional/vimscript/json_functions_spec.lua b/test/functional/vimscript/json_functions_spec.lua
index 70d0934756..a9dab8431c 100644
--- a/test/functional/vimscript/json_functions_spec.lua
+++ b/test/functional/vimscript/json_functions_spec.lua
@@ -754,7 +754,7 @@ describe('json_encode() function', function()
   end)
 
   it('ignores improper values in &isprint', function()
-    meths.set_option('isprint', '1')
+    meths.set_option_value('isprint', '1', {})
     eq(1, eval('"\1" =~# "\\\\p"'))
     eq('"\\u0001"', funcs.json_encode('\1'))
   end)
diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua
index 130d5d81fa..762e8877ce 100644
--- a/test/functional/vimscript/system_spec.lua
+++ b/test/functional/vimscript/system_spec.lua
@@ -210,8 +210,8 @@ describe('system()', function()
     end)
 
     it('prints verbose information', function()
-      nvim('set_option', 'shell', 'fake_shell')
-      nvim('set_option', 'shellcmdflag', 'cmdflag')
+      nvim('set_option_value', 'shell', 'fake_shell', {})
+      nvim('set_option_value', 'shellcmdflag', 'cmdflag', {})
 
       screen:try_resize(72, 14)
       feed(':4verbose echo system("echo hi")')
-- 
cgit 


From 60f69014a801891d084542cf98ba2aa0d476164a Mon Sep 17 00:00:00 2001
From: luukvbaal 
Date: Sun, 21 May 2023 13:00:37 +0200
Subject: fix(redraw): multibyte characters are wrapped at the end of a line
 (#23696)

Problem:    Multibyte characters may be wrapped at the end of a line
            when 'statuscolumn' and 'spell' are set.
Solution:   Update line pointerdiff "v" before fetching the line pointer
            after evaluating 'statuscolumn'.
---
 test/functional/ui/statuscolumn_spec.lua | 12 ++++++++++++
 1 file changed, 12 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index 3b41d3684a..3d68246ba9 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -674,4 +674,16 @@ describe('statuscolumn', function()
     ]])
     eq(2, eval('g:stcnr'))
   end)
+
+  it('does not wrap multibyte characters at the end of a line', function()
+    screen:try_resize(33, 4)
+    command([[set spell stc=%l\ ]])
+    command('call setline(8, "This is a line that contains ᶏ multibyte character.")')
+    screen:expect([[
+      8  ^This is a line that contains ᶏ|
+          multibyte character.         |
+      9  aaaaa                         |
+                                       |
+    ]])
+  end)
 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/api/buffer_spec.lua                | 14 ++++----
 test/functional/api/extmark_spec.lua               |  4 +--
 test/functional/api/vim_spec.lua                   |  4 +--
 test/functional/api/window_spec.lua                |  6 ++--
 test/functional/ex_cmds/append_spec.lua            |  2 +-
 test/functional/ex_cmds/mksession_spec.lua         |  6 ++--
 test/functional/legacy/012_directory_spec.lua      |  4 +--
 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 ++--
 .../plugin/lsp/incremental_sync_spec.lua           |  2 +-
 test/functional/plugin/shada_spec.lua              | 30 ++++++++---------
 test/functional/provider/perl_spec.lua             |  2 +-
 test/functional/provider/ruby_spec.lua             |  2 +-
 test/functional/shada/buffers_spec.lua             |  4 +--
 test/functional/terminal/scrollback_spec.lua       | 38 +++++++++++-----------
 test/functional/terminal/tui_spec.lua              |  4 +--
 test/functional/terminal/window_split_tab_spec.lua |  2 +-
 test/functional/ui/decorations_spec.lua            |  6 ++--
 test/functional/vimscript/buf_functions_spec.lua   |  2 +-
 22 files changed, 76 insertions(+), 76 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index df9092fa14..bf9e952319 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -630,19 +630,19 @@ describe('api/buf', function()
       eq('Index out of bounds', pcall_err(get_offset, 6))
       eq('Index out of bounds', pcall_err(get_offset, -1))
 
-      meths.set_option_value('eol', false, {buf=0})
-      meths.set_option_value('fixeol', false, {buf=0})
+      meths.set_option_value('eol', false, {})
+      meths.set_option_value('fixeol', false, {})
       eq(28, get_offset(5))
 
       -- fileformat is ignored
-      meths.set_option_value('fileformat', 'dos', {buf=0})
+      meths.set_option_value('fileformat', 'dos', {})
       eq(0, get_offset(0))
       eq(6, get_offset(1))
       eq(15, get_offset(2))
       eq(16, get_offset(3))
       eq(24, get_offset(4))
       eq(28, get_offset(5))
-      meths.set_option_value('eol', true, {buf=0})
+      meths.set_option_value('eol', true, {})
       eq(29, get_offset(5))
 
       command("set hidden")
@@ -699,9 +699,9 @@ describe('api/buf', function()
 
   describe('nvim_get_option_value, nvim_set_option_value', function()
     it('works', function()
-      eq(8, nvim('get_option_value', 'shiftwidth', {buf = 0}))
-      nvim('set_option_value', 'shiftwidth', 4, {buf=0})
-      eq(4, nvim('get_option_value', 'shiftwidth', {buf = 0}))
+      eq(8, nvim('get_option_value', 'shiftwidth', {}))
+      nvim('set_option_value', 'shiftwidth', 4, {})
+      eq(4, nvim('get_option_value', 'shiftwidth', {}))
       -- global-local option
       nvim('set_option_value', 'define', 'test', {buf = 0})
       eq('test', nvim('get_option_value', 'define', {buf = 0}))
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index 0960e910f1..675c8332de 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -1401,7 +1401,7 @@ describe('API/extmarks', function()
 
   it('in read-only buffer', function()
     command("view! runtime/doc/help.txt")
-    eq(true, meths.get_option_value('ro', {buf=0}))
+    eq(true, meths.get_option_value('ro', {}))
     local id = set_extmark(ns, 0, 0, 2)
     eq({{id, 0, 2}}, get_extmarks(ns,0, -1))
   end)
@@ -1474,7 +1474,7 @@ describe('API/extmarks', function()
   it('in prompt buffer', function()
     feed('dd')
     local id = set_extmark(ns, marks[1], 0, 0, {})
-    meths.set_option_value('buftype', 'prompt', {buf = 0})
+    meths.set_option_value('buftype', 'prompt', {})
     feed('i')
     eq({{id, 0, 2}}, get_extmarks(ns, 0, -1))
   end)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 5b8b52a559..040c26e058 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -1397,7 +1397,7 @@ describe('API', function()
     it('works to set global value of local options', function()
       nvim('set_option_value', 'lisp', true, {scope='global'})
       eq(true, nvim('get_option_value', 'lisp', {scope='global'}))
-      eq(false, nvim('get_option_value', 'lisp', {buf=0}))
+      eq(false, nvim('get_option_value', 'lisp', {}))
       eq(nil, nvim('command_output', 'setglobal lisp?'):match('nolisp'))
       eq('nolisp', nvim('command_output', 'setlocal lisp?'):match('nolisp'))
       nvim('set_option_value', 'shiftwidth', 20, {scope='global'})
@@ -1493,7 +1493,7 @@ describe('API', function()
     end)
 
     it('set window options', function()
-      nvim('set_option_value', 'colorcolumn', '4,3', {win=0})
+      nvim('set_option_value', 'colorcolumn', '4,3', {})
       eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'}))
       command("set modified hidden")
       command("enew") -- edit new buffer, window option is preserved
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 660fa4731e..a6d1807961 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -365,11 +365,11 @@ describe('API/win', function()
 
   describe('nvim_get_option_value, nvim_set_option_value', function()
     it('works', function()
-      nvim('set_option_value', 'colorcolumn', '4,3', {win=0})
-      eq('4,3', nvim('get_option_value', 'colorcolumn', {win = 0}))
+      nvim('set_option_value', 'colorcolumn', '4,3', {})
+      eq('4,3', nvim('get_option_value', 'colorcolumn', {}))
       command("set modified hidden")
       command("enew") -- edit new buffer, window option is preserved
-      eq('4,3', nvim('get_option_value', 'colorcolumn', {win = 0}))
+      eq('4,3', nvim('get_option_value', 'colorcolumn', {}))
 
       -- global-local option
       nvim('set_option_value', 'statusline', 'window-status', {win=0})
diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua
index e3a39384a6..4134eed87e 100644
--- a/test/functional/ex_cmds/append_spec.lua
+++ b/test/functional/ex_cmds/append_spec.lua
@@ -43,7 +43,7 @@ local cmdtest = function(cmd, prep, ret1)
       eq(hisline, funcs.histget(':', -2))
       eq(cmd, funcs.histget(':'))
       -- Test that command-line window was launched
-      eq('nofile', meths.get_option_value('buftype', {buf=0}))
+      eq('nofile', meths.get_option_value('buftype', {}))
       eq('n', funcs.mode(1))
       feed('')
       eq('c', funcs.mode(1))
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
index f51e7c62cb..7522d4a99c 100644
--- a/test/functional/ex_cmds/mksession_spec.lua
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -81,7 +81,7 @@ describe(':mksession', function()
       local buf_count = #meths.list_bufs()
       eq(2, buf_count)
 
-      eq('terminal', meths.get_option_value('buftype', { buf = 0 }))
+      eq('terminal', meths.get_option_value('buftype', {}))
 
       test_terminal_session_disabled(2)
 
@@ -112,7 +112,7 @@ describe(':mksession', function()
 
   it('do not restore :terminal if not set in sessionoptions, only buffer #13078', function()
     command('terminal')
-    eq('terminal', meths.get_option_value('buftype', { buf = 0 }))
+    eq('terminal', meths.get_option_value('buftype', {}))
 
     local buf_count = #meths.list_bufs()
     eq(1, buf_count)
@@ -120,7 +120,7 @@ describe(':mksession', function()
     test_terminal_session_disabled(1)
 
     -- no terminal should be set
-    eq('', meths.get_option_value('buftype', { buf = 0 }))
+    eq('', meths.get_option_value('buftype', {}))
   end)
 
   it('restores tab-local working directories', function()
diff --git a/test/functional/legacy/012_directory_spec.lua b/test/functional/legacy/012_directory_spec.lua
index f44ba10f7f..25d0dcb81e 100644
--- a/test/functional/legacy/012_directory_spec.lua
+++ b/test/functional/legacy/012_directory_spec.lua
@@ -58,7 +58,7 @@ describe("'directory' option", function()
       end of testfile]])
 
     meths.set_option_value('swapfile', true, {})
-    meths.set_option_value('swapfile', true, {buf=0})
+    meths.set_option_value('swapfile', true, {})
     meths.set_option_value('directory', '.', {})
 
     -- sanity check: files should not exist yet.
@@ -83,7 +83,7 @@ describe("'directory' option", function()
     meths.set_option_value('directory', 'Xtest.je', {})
     command('bdelete')
     command('edit Xtest2/Xtest3')
-    eq(true, meths.get_option_value('swapfile', {buf=0}))
+    eq(true, meths.get_option_value('swapfile', {}))
     poke_eventloop()
 
     eq({ "Xtest3" }, ls_dir_sorted("Xtest2"))
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 [[
diff --git a/test/functional/plugin/lsp/incremental_sync_spec.lua b/test/functional/plugin/lsp/incremental_sync_spec.lua
index 1dca464d74..724b3efb97 100644
--- a/test/functional/plugin/lsp/incremental_sync_spec.lua
+++ b/test/functional/plugin/lsp/incremental_sync_spec.lua
@@ -21,7 +21,7 @@ before_each(function ()
     --   ["mac"] = '\r',
     -- }
 
-    -- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {buf=0})]
+    -- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})]
 
 
     function test_register(bufnr, id, offset_encoding, line_ending)
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index 43222f1904..8d37100607 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -2181,8 +2181,8 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "a"',
     }, nvim_eval('getline(1, "$")'))
-    eq(false, nvim('get_option_value', 'modified', {buf=0}))
-    eq('shada', nvim('get_option_value', 'filetype', {buf=0}))
+    eq(false, nvim('get_option_value', 'modified', {}))
+    eq('shada', nvim('get_option_value', 'filetype', {}))
     nvim_command('edit ' .. fname_tmp)
     eq({
       'History entry with timestamp ' .. epoch .. ':',
@@ -2191,8 +2191,8 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "b"',
     }, nvim_eval('getline(1, "$")'))
-    eq(false, nvim('get_option_value', 'modified', {buf=0}))
-    eq('shada', nvim('get_option_value', 'filetype', {buf=0}))
+    eq(false, nvim('get_option_value', 'modified', {}))
+    eq('shada', nvim('get_option_value', 'filetype', {}))
     eq('++opt not supported', exc_exec('edit ++enc=latin1 ' .. fname))
     neq({
       'History entry with timestamp ' .. epoch .. ':',
@@ -2201,7 +2201,7 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "a"',
     }, nvim_eval('getline(1, "$")'))
-    neq(true, nvim('get_option_value', 'modified', {buf=0}))
+    neq(true, nvim('get_option_value', 'modified', {}))
   end)
 
   it('event FileReadCmd', function()
@@ -2217,8 +2217,8 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "a"',
     }, nvim_eval('getline(1, "$")'))
-    eq(true, nvim('get_option_value', 'modified', {buf=0}))
-    neq('shada', nvim('get_option_value', 'filetype', {buf=0}))
+    eq(true, nvim('get_option_value', 'modified', {}))
+    neq('shada', nvim('get_option_value', 'filetype', {}))
     nvim_command('1,$read ' .. fname_tmp)
     eq({
       '',
@@ -2233,9 +2233,9 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "b"',
     }, nvim_eval('getline(1, "$")'))
-    eq(true, nvim('get_option_value', 'modified', {buf=0}))
-    neq('shada', nvim('get_option_value', 'filetype', {buf=0}))
-    nvim('set_option_value', 'modified', false, {buf=0})
+    eq(true, nvim('get_option_value', 'modified', {}))
+    neq('shada', nvim('get_option_value', 'filetype', {}))
+    nvim('set_option_value', 'modified', false, {})
     eq('++opt not supported', exc_exec('$read ++enc=latin1 ' .. fname))
     eq({
       '',
@@ -2250,7 +2250,7 @@ describe('plugin/shada.vim', function()
       '  - contents      "ab"',
       '  -               "b"',
     }, nvim_eval('getline(1, "$")'))
-    neq(true, nvim('get_option_value', 'modified', {buf=0}))
+    neq(true, nvim('get_option_value', 'modified', {}))
   end)
 
   it('event BufWriteCmd', function()
@@ -2517,10 +2517,10 @@ describe('ftplugin/shada.vim', function()
   it('sets options correctly', function()
     nvim_command('filetype plugin indent on')
     nvim_command('setlocal filetype=shada')
-    eq(true, nvim('get_option_value', 'expandtab', {buf=0}))
-    eq(2, nvim('get_option_value', 'tabstop', {buf=0}))
-    eq(2, nvim('get_option_value', 'softtabstop', {buf=0}))
-    eq(2, nvim('get_option_value', 'shiftwidth', {buf=0}))
+    eq(true, nvim('get_option_value', 'expandtab', {}))
+    eq(2, nvim('get_option_value', 'tabstop', {}))
+    eq(2, nvim('get_option_value', 'softtabstop', {}))
+    eq(2, nvim('get_option_value', 'shiftwidth', {}))
   end)
 
   it('sets indentkeys correctly', function()
diff --git a/test/functional/provider/perl_spec.lua b/test/functional/provider/perl_spec.lua
index bc7261895d..8049f0f3e2 100644
--- a/test/functional/provider/perl_spec.lua
+++ b/test/functional/provider/perl_spec.lua
@@ -45,7 +45,7 @@ describe('legacy perl provider', function()
     -- :perldo 1; doesn't change $_,
     -- the buffer should not be changed
     command('normal :perldo 1;')
-    eq(false, meths.get_option_value('modified', {buf=0}))
+    eq(false, meths.get_option_value('modified', {}))
     -- insert some text
     insert('abc\ndef\nghi')
     expect([[
diff --git a/test/functional/provider/ruby_spec.lua b/test/functional/provider/ruby_spec.lua
index 40ace28c4e..d3b967dfbe 100644
--- a/test/functional/provider/ruby_spec.lua
+++ b/test/functional/provider/ruby_spec.lua
@@ -97,7 +97,7 @@ describe(':rubydo command', function()
 
   it('does not modify the buffer if no changes are made', function()
     command('normal :rubydo 42')
-    eq(false, meths.get_option_value('modified', {buf=0}))
+    eq(false, meths.get_option_value('modified', {}))
   end)
 end)
 
diff --git a/test/functional/shada/buffers_spec.lua b/test/functional/shada/buffers_spec.lua
index 2740eeeca6..b1c4ded541 100644
--- a/test/functional/shada/buffers_spec.lua
+++ b/test/functional/shada/buffers_spec.lua
@@ -48,7 +48,7 @@ describe('shada support code', function()
     reset('set shada+=%')
     nvim_command('edit ' .. testfilename)
     nvim_command('edit ' .. testfilename_2)
-    meths.set_option_value('buflisted', false, {buf=0})
+    meths.set_option_value('buflisted', false, {})
     expect_exit(nvim_command, 'qall')
     reset('set shada+=%')
     eq(2, funcs.bufnr('$'))
@@ -60,7 +60,7 @@ describe('shada support code', function()
     reset('set shada+=%')
     nvim_command('edit ' .. testfilename)
     nvim_command('edit ' .. testfilename_2)
-    meths.set_option_value('buftype', 'quickfix', {buf=0})
+    meths.set_option_value('buftype', 'quickfix', {})
     expect_exit(nvim_command, 'qall')
     reset('set shada+=%')
     eq(2, funcs.bufnr('$'))
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index 48a9fa7171..5d3e55d898 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -401,7 +401,7 @@ describe("'scrollback' option", function()
       screen = thelpers.screen_setup(nil, "['sh']", 30)
     end
 
-    meths.set_option_value('scrollback', 0, {buf = 0})
+    meths.set_option_value('scrollback', 0, {})
     feed_data(('%s REP 31 line%s'):format(testprg('shell-test'), is_os('win') and '\r' or '\n'))
     screen:expect{any='30: line                      '}
     retry(nil, nil, function() expect_lines(7) end)
@@ -417,7 +417,7 @@ describe("'scrollback' option", function()
       screen = thelpers.screen_setup(nil, "['sh']", 30)
     end
 
-    meths.set_option_value('scrollback', 200, {buf=0})
+    meths.set_option_value('scrollback', 200, {})
 
     -- Wait for prompt.
     screen:expect{any='%$'}
@@ -426,10 +426,10 @@ describe("'scrollback' option", function()
     screen:expect{any='30: line                      '}
 
     retry(nil, nil, function() expect_lines(33, 2) end)
-    meths.set_option_value('scrollback', 10, {buf=0})
+    meths.set_option_value('scrollback', 10, {})
     poke_eventloop()
     retry(nil, nil, function() expect_lines(16) end)
-    meths.set_option_value('scrollback', 10000, {buf=0})
+    meths.set_option_value('scrollback', 10000, {})
     retry(nil, nil, function() expect_lines(16) end)
     -- Terminal job data is received asynchronously, may happen before the
     -- 'scrollback' option is synchronized with the internal sb_buffer.
@@ -484,18 +484,18 @@ describe("'scrollback' option", function()
       ]])
     local term_height = 6  -- Actual terminal screen height, not the scrollback
     -- Initial
-    local scrollback = meths.get_option_value('scrollback', {buf=0})
+    local scrollback = meths.get_option_value('scrollback', {})
     eq(scrollback + term_height, eval('line("$")'))
     -- Reduction
     scrollback = scrollback - 2
-    meths.set_option_value('scrollback', scrollback, {buf=0})
+    meths.set_option_value('scrollback', scrollback, {})
     eq(scrollback + term_height, eval('line("$")'))
   end)
 
   it('defaults to 10000 in :terminal buffers', function()
     set_fake_shell()
     command('terminal')
-    eq(10000, meths.get_option_value('scrollback', {buf=0}))
+    eq(10000, meths.get_option_value('scrollback', {}))
   end)
 
   it('error if set to invalid value', function()
@@ -507,7 +507,7 @@ describe("'scrollback' option", function()
 
   it('defaults to -1 on normal buffers', function()
     command('new')
-    eq(-1, meths.get_option_value('scrollback', {buf=0}))
+    eq(-1, meths.get_option_value('scrollback', {}))
   end)
 
   it(':setlocal in a :terminal buffer', function()
@@ -516,45 +516,45 @@ describe("'scrollback' option", function()
     -- _Global_ scrollback=-1 defaults :terminal to 10_000.
     command('setglobal scrollback=-1')
     command('terminal')
-    eq(10000, meths.get_option_value('scrollback', {buf=0}))
+    eq(10000, meths.get_option_value('scrollback', {}))
 
     -- _Local_ scrollback=-1 in :terminal forces the _maximum_.
     command('setlocal scrollback=-1')
     retry(nil, nil, function()  -- Fixup happens on refresh, not immediately.
-      eq(100000, meths.get_option_value('scrollback', {buf=0}))
+      eq(100000, meths.get_option_value('scrollback', {}))
     end)
 
     -- _Local_ scrollback=-1 during TermOpen forces the maximum. #9605
     command('setglobal scrollback=-1')
     command('autocmd TermOpen * setlocal scrollback=-1')
     command('terminal')
-    eq(100000, meths.get_option_value('scrollback', {buf=0}))
+    eq(100000, meths.get_option_value('scrollback', {}))
   end)
 
   it(':setlocal in a normal buffer', function()
     command('new')
     -- :setlocal to -1.
     command('setlocal scrollback=-1')
-    eq(-1, meths.get_option_value('scrollback', {buf=0}))
+    eq(-1, meths.get_option_value('scrollback', {}))
     -- :setlocal to anything except -1. Currently, this just has no effect.
     command('setlocal scrollback=42')
-    eq(42, meths.get_option_value('scrollback', {buf=0}))
+    eq(42, meths.get_option_value('scrollback', {}))
   end)
 
   it(':set updates local value and global default', function()
     set_fake_shell()
     command('set scrollback=42')                  -- set global value
-    eq(42, meths.get_option_value('scrollback', {buf=0}))
+    eq(42, meths.get_option_value('scrollback', {}))
     command('terminal')
-    eq(42, meths.get_option_value('scrollback', {buf=0})) -- inherits global default
+    eq(42, meths.get_option_value('scrollback', {})) -- inherits global default
     command('setlocal scrollback=99')
-    eq(99, meths.get_option_value('scrollback', {buf=0}))
+    eq(99, meths.get_option_value('scrollback', {}))
     command('set scrollback<')                    -- reset to global default
-    eq(42, meths.get_option_value('scrollback', {buf=0}))
+    eq(42, meths.get_option_value('scrollback', {}))
     command('setglobal scrollback=734')           -- new global default
-    eq(42, meths.get_option_value('scrollback', {buf=0})) -- local value did not change
+    eq(42, meths.get_option_value('scrollback', {})) -- local value did not change
     command('terminal')
-    eq(734, meths.get_option_value('scrollback', {buf=0}))
+    eq(734, meths.get_option_value('scrollback', {}))
   end)
 
 end)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 3cfd222336..1b65c1cddc 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -1458,8 +1458,8 @@ describe('TUI', function()
 
   it('allows grid to assume wider ambiguous-width characters than host terminal #19686', function()
     child_session:request('nvim_buf_set_lines', 0, 0, -1, true, { ('℃'):rep(60), ('℃'):rep(60) })
-    child_session:request('nvim_set_option_value', 'cursorline', true, {win=0})
-    child_session:request('nvim_set_option_value', 'list', true, {win=0})
+    child_session:request('nvim_set_option_value', 'cursorline', true, {})
+    child_session:request('nvim_set_option_value', 'list', true, {})
     child_session:request('nvim_set_option_value', 'listchars', 'eol:$', {win=0})
     feed_data('gg')
     local singlewidth_screen = [[
diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua
index 3e1520e5fd..da14531fa2 100644
--- a/test/functional/terminal/window_split_tab_spec.lua
+++ b/test/functional/terminal/window_split_tab_spec.lua
@@ -71,7 +71,7 @@ describe(':terminal', function()
   end)
 
   it('does not change size if updated when not visible in any window #19665', function()
-    local channel = meths.get_option_value('channel', { buf = 0 })
+    local channel = meths.get_option_value('channel', {})
     command('enew')
     sleep(100)
     meths.chan_send(channel, 'foo')
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 324362a865..ccf1810ee1 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1910,7 +1910,7 @@ describe('decorations: signs', function()
     }
 
     ns = meths.create_namespace 'test'
-    meths.set_option_value('signcolumn', 'auto:9', {win = 0})
+    meths.set_option_value('signcolumn', 'auto:9', {})
   end)
 
   local example_text = [[
@@ -2222,7 +2222,7 @@ l5
     ]]}
 
     -- Check truncation works too
-    meths.set_option_value('signcolumn', 'auto', {win = 0})
+    meths.set_option_value('signcolumn', 'auto', {})
 
     screen:expect{grid=[[
       S5^l1                |
@@ -2233,7 +2233,7 @@ l5
 
   it('does not set signcolumn for signs without text', function()
     screen:try_resize(20, 3)
-    meths.set_option_value('signcolumn', 'auto', {win = 0})
+    meths.set_option_value('signcolumn', 'auto', {})
     insert(example_text)
     feed 'gg'
     meths.buf_set_extmark(0, ns, 0, -1, {number_hl_group='Error'})
diff --git a/test/functional/vimscript/buf_functions_spec.lua b/test/functional/vimscript/buf_functions_spec.lua
index 2d6d4b8e04..2a5720fbd7 100644
--- a/test/functional/vimscript/buf_functions_spec.lua
+++ b/test/functional/vimscript/buf_functions_spec.lua
@@ -268,7 +268,7 @@ describe('setbufvar() function', function()
   end)
   it('may set options, including window-local and global values', function()
     local buf1 = meths.get_current_buf()
-    eq(false, meths.get_option_value('number', {win=0}))
+    eq(false, meths.get_option_value('number', {}))
     command('split')
     command('new')
     eq(2, bufmeths.get_number(curwinmeths.get_buf()))
-- 
cgit 


From b7708eac24c22a96676176c68569d6859a9f793f Mon Sep 17 00:00:00 2001
From: Null Chilly <56817415+nullchilly@users.noreply.github.com>
Date: Mon, 22 May 2023 15:49:01 +0700
Subject: fix(api): nvim_get_hl should return default flag

---
 test/functional/api/highlight_spec.lua | 5 +++++
 1 file changed, 5 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua
index 1601184e1b..d3a79327ae 100644
--- a/test/functional/api/highlight_spec.lua
+++ b/test/functional/api/highlight_spec.lua
@@ -596,4 +596,9 @@ describe('API: get highlight', function()
     eq({}, data["@foobar.hubbabubba"])
     eq(nil, data["@foobar"])
   end)
+
+  it('should return default flag', function()
+    meths.set_hl(0, 'Tried', { fg = "#00ff00", default = true })
+    eq({ fg = tonumber('00ff00', 16), default = true }, meths.get_hl(0, { name = 'Tried' }))
+  end)
 end)
-- 
cgit 


From b11a8c1b5d3985479351b34f2078d490cbf59e90 Mon Sep 17 00:00:00 2001
From: luukvbaal 
Date: Mon, 22 May 2023 11:07:55 +0200
Subject: fix(highlight): remove unnecessary assignment to char_attr for
 'spell' (#23713)

---
 test/functional/ui/spell_spec.lua | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index 15819aef40..0f553d4a9b 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -254,4 +254,19 @@ describe("'spell'", function()
     ]])
   end)
 
+  it('and syntax does not clear extmark highlighting at the start of a word', function()
+    screen:try_resize(43, 3)
+    command([[
+      set spell
+      syntax match Constant "^.*$"
+      call setline(1, "This is some text without any spell errors.")
+    ]])
+    local ns = meths.create_namespace("spell")
+    curbufmeths.set_extmark(ns, 0, 0, { hl_group = 'WarningMsg', end_col = 43 })
+    screen:expect([[
+      {6:^This is some text without any spell errors.}|
+      {0:~                                          }|
+                                                 |
+    ]])
+  end)
 end)
-- 
cgit 


From cb34d0ddd086141d6afcb9c48eae180abbeffecc Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 22 May 2023 18:22:47 +0800
Subject: fix(redraw): overwrite double-width char with virt_text properly
 (#23708)

---
 test/functional/ui/decorations_spec.lua | 76 +++++++++++++++++++++++++++++++--
 1 file changed, 72 insertions(+), 4 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index ccf1810ee1..e31361e74c 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -704,14 +704,14 @@ end]]
     -- can "float" beyond end of line
     meths.buf_set_extmark(0, ns, 5, 28, { virt_text={{'loopy', 'ErrorMsg'}}, virt_text_pos='overlay'})
     -- bound check: right edge of window
-    meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork '}, {'bork bork bork', 'ErrorMsg'}}, virt_text_pos='overlay'})
+    meths.buf_set_extmark(0, ns, 2, 26, { virt_text={{'bork bork bork'}, {(' bork'):rep(10), 'ErrorMsg'}}, virt_text_pos='overlay'})
     -- empty virt_text should not change anything
     meths.buf_set_extmark(0, ns, 6, 16, { virt_text={{''}}, virt_text_pos='overlay'})
 
     screen:expect{grid=[[
       ^for _,item in ipairs(items) do                    |
       {2:|}   local text, hl_id_cell, count = unpack(item)  |
-      {2:|}   if hl_id_cell ~= nil tbork bork bork {4:bork bork}|
+      {2:|}   if hl_id_cell ~= nil tbork bork bork{4: bork bork}|
       {2:|}   {1:|}   hl_id = hl_id_cell                        |
       {2:|}   end                                           |
       {2:|}   for _ = 1, (count or 1) {4:loopy}                 |
@@ -726,7 +726,6 @@ end]]
                                                         |
     ]]}
 
-
     -- handles broken lines
     screen:try_resize(22, 25)
     screen:expect{grid=[[
@@ -736,7 +735,7 @@ end]]
       cell, count = unpack(i|
       tem)                  |
       {2:|}   if hl_id_cell ~= n|
-      il tbork bork bork {4:bor}|
+      il tbork bork bork{4: bor}|
       {2:|}   {1:|}   hl_id = hl_id_|
       cell                  |
       {2:|}   end               |
@@ -756,6 +755,75 @@ end]]
       {1:~                     }|
                             |
     ]]}
+
+    -- truncating in the middle of a char leaves a space
+    meths.buf_set_lines(0, 0, 1, true, {'for _,item in ipairs(items) do  -- 古古古'})
+    meths.buf_set_lines(0, 10, 12, true, {'    end  -- ??????????', 'end  -- ?古古古古?古古'})
+    meths.buf_set_extmark(0, ns, 0, 35, { virt_text={{'A', 'ErrorMsg'}, {'AA'}}, virt_text_pos='overlay'})
+    meths.buf_set_extmark(0, ns, 10, 19, { virt_text={{'口口口', 'ErrorMsg'}}, virt_text_pos='overlay'})
+    meths.buf_set_extmark(0, ns, 11, 21, { virt_text={{'口口口', 'ErrorMsg'}}, virt_text_pos='overlay'})
+    meths.buf_set_extmark(0, ns, 11, 8, { virt_text={{'口口', 'ErrorMsg'}}, virt_text_pos='overlay'})
+    screen:expect{grid=[[
+      ^for _,item in ipairs(i|
+      tems) do  -- {4:A}AA 古   |
+      {2:|}   local text, hl_id_|
+      cell, count = unpack(i|
+      tem)                  |
+      {2:|}   if hl_id_cell ~= n|
+      il tbork bork bork{4: bor}|
+      {2:|}   {1:|}   hl_id = hl_id_|
+      cell                  |
+      {2:|}   end               |
+      {2:|}   for _ = 1, (count |
+      or 1) {4:loopy}           |
+      {2:|}   {1:|}   local cell = l|
+      ine[colpos]           |
+      {2:|}   {1:|}   cell.text = te|
+      xt                    |
+      {2:|}   {1:|}   cell.hl_id = h|
+      l_id                  |
+      {2:|}   {1:|}   cofoo{3:bar}{4:!!}olpo|
+      s+1                   |
+          end  -- ???????{4:口 }|
+      end  -- {4:口口} 古古{4:口口 }|
+      {1:~                     }|
+      {1:~                     }|
+                            |
+    ]]}
+
+    screen:try_resize(82, 13)
+    screen:expect{grid=[[
+      ^for _,item in ipairs(items) do  -- {4:A}AA 古                                         |
+      {2:|}   local text, hl_id_cell, count = unpack(item)                                  |
+      {2:|}   if hl_id_cell ~= nil tbork bork bork{4: bork bork bork bork bork bork bork bork b}|
+      {2:|}   {1:|}   hl_id = hl_id_cell                                                        |
+      {2:|}   end                                                                           |
+      {2:|}   for _ = 1, (count or 1) {4:loopy}                                                 |
+      {2:|}   {1:|}   local cell = line[colpos]                                                 |
+      {2:|}   {1:|}   cell.text = text                                                          |
+      {2:|}   {1:|}   cell.hl_id = hl_id                                                        |
+      {2:|}   {1:|}   cofoo{3:bar}{4:!!}olpos+1                                                         |
+          end  -- ???????{4:口口口}                                                         |
+      end  -- {4:口口} 古古{4:口口口}                                                           |
+                                                                                        |
+    ]]}
+
+    meths.buf_clear_namespace(0, ns, 0, -1)
+    screen:expect{grid=[[
+      ^for _,item in ipairs(items) do  -- 古古古                                         |
+          local text, hl_id_cell, count = unpack(item)                                  |
+          if hl_id_cell ~= nil then                                                     |
+              hl_id = hl_id_cell                                                        |
+          end                                                                           |
+          for _ = 1, (count or 1) do                                                    |
+              local cell = line[colpos]                                                 |
+              cell.text = text                                                          |
+              cell.hl_id = hl_id                                                        |
+              colpos = colpos+1                                                         |
+          end  -- ??????????                                                            |
+      end  -- ?古古古古?古古                                                            |
+                                                                                        |
+    ]]}
   end)
 
   it('can have virtual text of overlay position and styling', function()
-- 
cgit 


From efa9b299a7cb68909e9bcd290e4d12bcb6d0bb03 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Sun, 19 Mar 2023 16:31:08 +1100
Subject: feat(ui): inline virtual text

vim-patch:9.0.0067: cannot show virtual text

Problem:    Cannot show virtual text.
Solution:   Initial changes for virtual text support, using text properties.

https://github.com/vim/vim/commit/7f9969c559b51446632ac7e8f76cde07e7d0078d

vim-patch:9.0.0116: virtual text not displayed if 'signcolumn' is "yes"

Problem:    Virtual text not displayed if 'signcolumn' is "yes".
Solution:   Set c_extra and c_final to NUL.
https://github.com/vim/vim/commit/711483cd1381a4ed848d783ae0a6792d5b04447b

Co-authored-by: bfredl 
---
 test/functional/ui/decorations_spec.lua | 79 +++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index ccf1810ee1..80dfebd33e 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -645,6 +645,7 @@ describe('extmark decorations', function()
       [25] = {background = Screen.colors.LightRed};
       [26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey};
       [27] = {background = Screen.colors.Plum1};
+      [28] = {foreground = Screen.colors.SlateBlue};
     }
 
     ns = meths.create_namespace 'test'
@@ -1166,6 +1167,84 @@ end]]
     screen:expect_unchanged(true)
   end)
 
+  it('can have virtual text of inline position', function()
+    insert(example_text)
+    feed 'gg'
+    screen:expect{grid=[[
+      ^for _,item in ipairs(items) do                    |
+          local text, hl_id_cell, count = unpack(item)  |
+          if hl_id_cell ~= nil then                     |
+              hl_id = hl_id_cell                        |
+          end                                           |
+          for _ = 1, (count or 1) do                    |
+              local cell = line[colpos]                 |
+              cell.text = text                          |
+              cell.hl_id = hl_id                        |
+              colpos = colpos+1                         |
+          end                                           |
+      end                                               |
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+    ]]}
+
+    meths.buf_set_extmark(0, ns, 1, 14, {virt_text={{': ', 'Special'}, {'string', 'Type'}}, virt_text_pos='inline'})
+    screen:expect{grid=[[
+      ^for _,item in ipairs(items) do                    |
+          local text{28:: }{3:string}, hl_id_cell, count = unpack|
+      (item)                                            |
+          if hl_id_cell ~= nil then                     |
+              hl_id = hl_id_cell                        |
+          end                                           |
+          for _ = 1, (count or 1) do                    |
+              local cell = line[colpos]                 |
+              cell.text = text                          |
+              cell.hl_id = hl_id                        |
+              colpos = colpos+1                         |
+          end                                           |
+      end                                               |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+
+    screen:try_resize(55, 15)
+    screen:expect{grid=[[
+      ^for _,item in ipairs(items) do                         |
+          local text{28:: }{3:string}, hl_id_cell, count = unpack(item|
+      )                                                      |
+          if hl_id_cell ~= nil then                          |
+              hl_id = hl_id_cell                             |
+          end                                                |
+          for _ = 1, (count or 1) do                         |
+              local cell = line[colpos]                      |
+              cell.text = text                               |
+              cell.hl_id = hl_id                             |
+              colpos = colpos+1                              |
+          end                                                |
+      end                                                    |
+      {1:~                                                      }|
+                                                             |
+    ]]}
+
+    screen:try_resize(56, 15)
+    screen:expect{grid=[[
+      ^for _,item in ipairs(items) do                          |
+          local text{28:: }{3:string}, hl_id_cell, count = unpack(item)|
+          if hl_id_cell ~= nil then                           |
+              hl_id = hl_id_cell                              |
+          end                                                 |
+          for _ = 1, (count or 1) do                          |
+              local cell = line[colpos]                       |
+              cell.text = text                                |
+              cell.hl_id = hl_id                              |
+              colpos = colpos+1                               |
+          end                                                 |
+      end                                                     |
+      {1:~                                                       }|
+      {1:~                                                       }|
+                                                              |
+    ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From a38d7f99845d6ef566b2885737b892c660749d5e Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Sun, 19 Mar 2023 17:37:28 +1100
Subject: fix(ui): fix cursor position with multiple inline virtual text

vim-patch9.0.0121: cannot put virtual text after or below a line

Problem:    Cannot put virtual text after or below a line.
Solution:   Add "text_align" and "text_wrap" arguments.

https://github.com/vim/vim/commit/b7963df98f9dbbb824713acad2f47c9989fcf8f3

This only patches the fix, not the whole thing.
---
 test/functional/ui/decorations_spec.lua | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 80dfebd33e..d029a66301 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1245,6 +1245,33 @@ end]]
                                                               |
     ]]}
   end)
+
+  it('cursor positions are correct with multiple inline virtual text', function()
+    insert('12345678')
+    meths.buf_set_extmark(0, ns, 0, 4,
+        { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' })
+    meths.buf_set_extmark(0, ns, 0, 4,
+        { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' })
+    feed '^'
+    feed '4l'
+        screen:expect { grid = [[
+      1234{28: virtual text  virtual text }^5678              |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From 389f5ca39d278173dc0446dc339f7ac1ff573329 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Sun, 19 Mar 2023 18:50:45 +1100
Subject: fix(ui): adjust the cursor when inserting virtual text

Credit to: Jesse Bakker

https://github.com/neovim/neovim/pull/20130#issuecomment-1369652743

Co-authored-by: Jesse Bakker 
---
 test/functional/ui/decorations_spec.lua | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index d029a66301..94267e35c4 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1272,6 +1272,32 @@ end]]
                                                         |
       ]]}
   end)
+
+  it('adjusts cursor location correctly when inserting around inline virtual text', function()
+        insert('12345678')
+        feed '$'
+        meths.buf_set_extmark(0, ns, 0, 4,
+            { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' })
+
+        screen:expect { grid = [[
+      1234{28: virtual text }567^8                            |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]
+        }
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From 0c7fa3bdcc3761cc851ea0ac37bf692b990044cc Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Sun, 19 Mar 2023 20:31:52 +1100
Subject: fix(ui): fix multi-byte characters highlight in virtual text

This also fixes insert cursor position around virtual text

vim-patch:9.0.0132: multi-byte characters in virtual text not handled correctly

Problem:    Multi-byte characters in virtual text not handled correctly.
Solution:   Count screen cells instead of bytes.

https://github.com/vim/vim/commit/09ff4b54fb86a64390ba9c609853c6410ea6197c
---
 test/functional/ui/decorations_spec.lua | 84 ++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 7 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 94267e35c4..6e4b19c856 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1254,7 +1254,7 @@ end]]
         { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' })
     feed '^'
     feed '4l'
-        screen:expect { grid = [[
+    screen:expect { grid = [[
       1234{28: virtual text  virtual text }^5678              |
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1274,12 +1274,12 @@ end]]
   end)
 
   it('adjusts cursor location correctly when inserting around inline virtual text', function()
-        insert('12345678')
-        feed '$'
-        meths.buf_set_extmark(0, ns, 0, 4,
+    insert('12345678')
+    feed '$'
+    meths.buf_set_extmark(0, ns, 0, 4,
             { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' })
 
-        screen:expect { grid = [[
+    screen:expect { grid = [[
       1234{28: virtual text }567^8                            |
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1295,8 +1295,78 @@ end]]
       {1:~                                                 }|
       {1:~                                                 }|
                                                         |
-      ]]
-        }
+      ]]}
+  end)
+
+  it('has correct highlighting with multi-byte characters in inline virtual text', function()
+    insert('12345678')
+    meths.buf_set_extmark(0, ns, 0, 4,
+            { virt_text = { { 'múlti-byté chñröcters 修补', 'Special' } }, virt_text_pos = 'inline' })
+
+    screen:expect { grid = [[
+      1234{28:múlti-byté chñröcters 修补}567^8                |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
+
+  it('has correct cursor position when inserting around virtual text', function()
+    insert('12345678')
+    meths.buf_set_extmark(0, ns, 0, 4,
+            { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
+    feed '^'
+    feed '3l'
+    feed 'a'
+    screen:expect { grid = [[
+      1234{28:^virtual text}5678                              |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {24:-- INSERT --}                                      |
+      ]]}
+    feed ''
+    feed '^'
+    feed '4l'
+    feed 'i'
+    screen:expect { grid = [[
+      1234{28:^virtual text}5678                              |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {24:-- INSERT --}                                      |
+      ]]}
   end)
 end)
 
-- 
cgit 


From 8eaf3c4f8c2ee4dc5a6e12bb809058ad263dbb65 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Sun, 26 Mar 2023 00:10:28 +1100
Subject: vim-patch:9.0.0143: cursor positioned after virtual text in empty
 line

Problem:    Cursor positioned after virtual text in empty line.
Solution:   Keep cursor in the first column. (closes vim/vim#10786)

https://github.com/vim/vim/commit/afd2aa79eda3fe69f2e7c87d0b9b4bca874f386a
---
 test/functional/ui/decorations_spec.lua | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 6e4b19c856..a2b0138da3 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1368,6 +1368,28 @@ end]]
       {24:-- INSERT --}                                      |
       ]]}
   end)
+
+  it('has correct cursor position with virtual text on an empty line', function()
+    meths.buf_set_extmark(0, ns, 0, 0,
+            { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
+    screen:expect { grid = [[
+      {28:^virtual text}                                      |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From 43c2eaada220d5e7d44fa9086655b00ee3e5fbb5 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Sun, 26 Mar 2023 14:49:09 +1100
Subject: vim-patch:9.0.0179: cursor pos wrong with wrapping virtual text in
 empty line

Problem:    Cursor position wrong with wrapping virtual text in empty line.
Solution:   Adjust handling of an empty line. (closes vim/vim#10875)

https://github.com/vim/vim/commit/49a90792d950c51608d0459ef8699fe921070718

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/decorations_spec.lua | 86 +++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index a2b0138da3..635666c941 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1390,6 +1390,92 @@ end]]
                                                         |
       ]]}
   end)
+
+  it('text is drawn correctly when inserting a wrapping virtual text on an empty line', function()
+    feed('o')
+    insert([[aaaaaaa
+
+bbbbbbb]])
+    meths.buf_set_extmark(0, ns, 0, 0,
+            { virt_text = { { string.rep('X', 51), 'Special' } }, virt_text_pos = 'inline' })
+    meths.buf_set_extmark(0, ns, 2, 0,
+            { virt_text = { { string.rep('X', 50), 'Special' } }, virt_text_pos = 'inline' })
+    feed('gg0')
+    screen:expect { grid = [[
+      {28:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {28:X}                                                 |
+      aaaaaaa                                           |
+      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      bbbbbbb                                           |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('j')
+    screen:expect { grid = [[
+      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {28:X}                                                 |
+      ^aaaaaaa                                           |
+      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      bbbbbbb                                           |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('j')
+    screen:expect { grid = [[
+      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {28:X}                                                 |
+      aaaaaaa                                           |
+      {28:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      bbbbbbb                                           |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('j')
+    screen:expect { grid = [[
+      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {28:X}                                                 |
+      aaaaaaa                                           |
+      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      ^bbbbbbb                                           |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From dee3af2122d5072d351551ef023d2c177334b332 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Sun, 26 Mar 2023 16:09:09 +1100
Subject: vim-patch:9.0.0178: cursor position wrong with virtual text before
 Tab

Problem:    Cursor position wrong with virtual text before Tab.
Solution:   Use the byte length, not the cell with, to compare the column.
            Correct tab size after text prop. (closes vim/vim#10866)

https://github.com/vim/vim/commit/e428fa04a758cc87ea580c856a796e58e407504b

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/decorations_spec.lua | 105 ++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 635666c941..91284e3a2f 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1476,6 +1476,111 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('cursor position is correct with virtual text attatched to hard tabs', function()
+    command('set noexpandtab')
+    feed('i')
+    feed('')
+    feed('')
+    feed('test')
+    feed('')
+    meths.buf_set_extmark(0, ns, 0, 1,
+            { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
+    feed('0')
+    screen:expect { grid = [[
+             ^ {28:virtual text}    test                      |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('l')
+    screen:expect { grid = [[
+              {28:virtual text}   ^ test                      |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('l')
+    screen:expect { grid = [[
+              {28:virtual text}    ^test                      |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('l')
+    screen:expect { grid = [[
+              {28:virtual text}    t^est                      |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('l')
+    screen:expect { grid = [[
+              {28:virtual text}    te^st                      |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From e12b5882af97126a9525a74a0955cc9e0f9114a9 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Sun, 26 Mar 2023 17:40:07 +1100
Subject: vim-patch:9.0.0183: extra space after virtual text when 'linebreak'
 is set

Problem:    Extra space after virtual text when 'linebreak' is set.
Solution:   Do not count virtual text when getting linebreak value.
            (closes vim/vim#10884)

https://github.com/vim/vim/commit/52de3a8d3943520bbd4e5e40a4c43fcc7182dac0

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/decorations_spec.lua | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 91284e3a2f..4ed9d5a044 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1581,6 +1581,31 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('has correct cursor position with virtual text on an empty line', function()
+    command('set linebreak')
+    insert('one twoword')
+    feed('0')
+    meths.buf_set_extmark(0, ns, 0, 3,
+            { virt_text = { { ': virtual text', 'Special' } }, virt_text_pos = 'inline' })
+    screen:expect { grid = [[
+      ^one{28:: virtual text} twoword                         |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From c5bf838f8aa51709f8d7ee81cf2b2a6479c77ad7 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Mon, 27 Mar 2023 01:25:37 +1100
Subject: fix(ui): fix visual and search highlighting interfering with virtual
 text

vim-patch:9.0.0193: search and match highlgith interfere with virtual text

Problem:    Search and match highlgith interfere with virtual text highlight.
            (Ben Jackson)
Solution:   Check for match highlight after text properties.  Reset and
            restore search highlight when showing virtual text.
            (closes vim/vim#10892)

https://github.com/vim/vim/commit/e38fc86180fd3f6b372648eea6adc3f623fea302

vim-patch:9.0.0452: Visual highlighting extends into virtual text prop

Problem:    Visual highlighting extends into virtual text prop.
Solution:   Do not highlight what isn't actually selected.  Fix ordering of
            stored text props.

https://github.com/vim/vim/commit/6eda17d881c9b2880ccb2a4d11951939a58f233d

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/decorations_spec.lua | 92 ++++++++++++++++++++++++++++++++-
 1 file changed, 91 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 4ed9d5a044..fa492dfcac 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -646,6 +646,8 @@ describe('extmark decorations', function()
       [26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey};
       [27] = {background = Screen.colors.Plum1};
       [28] = {foreground = Screen.colors.SlateBlue};
+      [29] = {background = Screen.colors.Yellow1};
+      [30] = {reverse = true};
     }
 
     ns = meths.create_namespace 'test'
@@ -1582,7 +1584,7 @@ bbbbbbb]])
       ]]}
   end)
 
-  it('has correct cursor position with virtual text on an empty line', function()
+  it('cursor position is correct with virtual text on an empty line', function()
     command('set linebreak')
     insert('one twoword')
     feed('0')
@@ -1606,6 +1608,94 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('search highlight is correct with virtual text attatched to', function()
+    insert('foo foo foo foo')
+    feed('0')
+    meths.buf_set_extmark(0, ns, 0, 8,
+            { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
+    screen:expect { grid = [[
+      ^foo foo {28:virtual text}foo foo                       |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('/foo')
+    screen:expect { grid = [[
+      {29:foo} {30:foo} {28:virtual text}{29:foo} {29:foo}                       |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      /foo^                                              |
+      ]]}
+  end)
+
+  it('visual select highlight is correct with virtual text attatched to', function()
+    insert('foo foo foo foo')
+    feed('0')
+    meths.buf_set_extmark(0, ns, 0, 8,
+            { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
+    feed('8l')
+    screen:expect { grid = [[
+      foo foo {28:virtual text}^foo foo                       |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('v')
+    feed('2h')
+    screen:expect { grid = [[
+      foo fo^o{18: }{28:virtual text}{18:f}oo foo                       |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {24:-- VISUAL --}                                      |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From be273c3a23cf65665e843cfb13fd5319657cc5c2 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Tue, 28 Mar 2023 01:23:21 +1100
Subject: vim-patch:9.0.0205: cursor in wrong position when inserting after
 virtual text

Problem:    Cursor in wrong position when inserting after virtual text. (Ben
            Jackson)
Solution:   Put the cursor after the virtual text, where the text will be
            inserted. (closes vim/vim#10914)

https://github.com/vim/vim/commit/28c9f895716cfa8f1220bc41b72a534c0e10cabe

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/decorations_spec.lua | 47 ++++++++++++++++++++++++++++++++-
 1 file changed, 46 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index fa492dfcac..de3f7e7a5b 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1652,11 +1652,12 @@ bbbbbbb]])
       ]]}
   end)
 
+    feed('8l')
   it('visual select highlight is correct with virtual text attatched to', function()
     insert('foo foo foo foo')
     feed('0')
     meths.buf_set_extmark(0, ns, 0, 8,
-            { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
+      { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
     feed('8l')
     screen:expect { grid = [[
       foo foo {28:virtual text}^foo foo                       |
@@ -1696,6 +1697,50 @@ bbbbbbb]])
       {24:-- VISUAL --}                                      |
       ]]}
   end)
+
+  it('cursor position is correct when inserting around a virtual text with right gravity set to false', function()
+    insert('foo foo foo foo')
+    meths.buf_set_extmark(0, ns, 0, 8,
+      { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+    feed('0')
+    feed('8l')
+    screen:expect { grid = [[
+      foo foo {28:virtual text}^foo foo                       |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('i')
+    screen:expect { grid = [[
+      foo foo {28:virtual text}^foo foo                       |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {24:-- INSERT --}                                      |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From 1936285d98f62a1357abf928b10c824cf9e3ff41 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Mon, 3 Apr 2023 01:05:08 +1000
Subject: fix(ui): fixes incorrect rendering when virtual text is not visable
 and nowrap

---
 test/functional/ui/decorations_spec.lua | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index de3f7e7a5b..68c0e5eaca 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1741,6 +1741,33 @@ bbbbbbb]])
       {24:-- INSERT --}                                      |
       ]]}
   end)
+
+  it('no wrap is rendered correctly with multiple virtual text, where one is hidden', function()
+    insert('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz')
+    command("set nowrap")
+    meths.buf_set_extmark(0, ns, 0, 50,
+      { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+    meths.buf_set_extmark(0, ns, 0, 2,
+      { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+    feed('$')
+    screen:expect { grid = [[
+      opqrstuvwxyzabcdefghijklmnopqrstuvwx{28:virtual text}y^z|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From 7423d3479d95e875e2d261d6e404ad19a631e530 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Mon, 3 Apr 2023 01:43:06 +1000
Subject: vim-patch:9.0.0716: with 'nowrap' virtual text "after" does not
 scroll left

Problem:    With 'nowrap' virtual text "after" does not scroll left.
Solution:   Skip part of the virtual text that is left of the window.
            (closes vim/vim#11320)  Fix going beyond the last column of the window.

https://github.com/vim/vim/commit/cd105417a53fcf97c0935f3468201ef11516c9f1

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/decorations_spec.lua | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 68c0e5eaca..ba3f73c229 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1742,7 +1742,7 @@ bbbbbbb]])
       ]]}
   end)
 
-  it('no wrap is rendered correctly with multiple virtual text, where one is hidden', function()
+  it('draws correctly with no wrap multiple virtual text, where one is hidden', function()
     insert('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz')
     command("set nowrap")
     meths.buf_set_extmark(0, ns, 0, 50,
@@ -1768,6 +1768,31 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('draws correctly with no wrap and a long virtual text', function()
+    insert('abcdefghi')
+    command("set nowrap")
+    meths.buf_set_extmark(0, ns, 0, 2,
+      { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+    feed('$')
+    screen:expect { grid = [[
+      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From 5d7afb2e9f222c32dd18c9c2bca49cab8bf751bc Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Wed, 12 Apr 2023 18:21:46 +1000
Subject: fix(ui): fix tabs not being spaced properly after virtual text with
 no wrap

also fixes incorrect skipping of multibyte characters
---
 test/functional/ui/decorations_spec.lua | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index ba3f73c229..9be8c23ba4 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1793,6 +1793,31 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('tabs are the correct length with no wrap following virtual text', function()
+    command('set nowrap')
+    feed('itesta')
+    meths.buf_set_extmark(0, ns, 0, 0,
+      { virt_text = { { string.rep('a', 55), 'Special' } }, virt_text_pos = 'inline' })
+    feed('gg$')
+    screen:expect { grid = [[
+      {28:aaaaaaaaaaaaaaaaaaaaaaaaa}test     ^a               |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From ecf225df574a48a4bbddf4978972b2b97184e92c Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Mon, 3 Apr 2023 20:46:50 +1000
Subject: vim-patch:9.0.0944: 'cursorline' causes virtual text highlight to
 continue

Problem:    'cursorline' causes virtual text highlight to continue.
Solution:   Save and restore line_attr. (closes vim/vim#11588)

https://github.com/vim/vim/commit/6ac16f0c0fe923098b9df5ac430f1923045f16ea

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/decorations_spec.lua | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 9be8c23ba4..77748eecb3 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1818,6 +1818,31 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('highlighting does not extend when no wrap is enabled with a long virtual text', function()
+    insert('abcdef')
+    command("set nowrap")
+    meths.buf_set_extmark(0, ns, 0, 3,
+      { virt_text = { { string.rep('X', 50), 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+    feed('$')
+    screen:expect { grid = [[
+      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}de^f|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From 332b70d2ed310084fe382affddbef3126c12751c Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Mon, 3 Apr 2023 23:12:56 +1000
Subject: fix(ui): fix incorrect highlighting when virtual text wraps with
 number

---
 test/functional/ui/decorations_spec.lua | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 77748eecb3..2d0f3e7a17 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1843,6 +1843,33 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('highlighting is correct when virtual text wraps with number', function()
+    insert([[
+    test
+    test]])
+    command('set number')
+    meths.buf_set_extmark(0, ns, 0, 1,
+      { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+    feed('gg0')
+    screen:expect { grid = [[
+      {2:  1 }^t{28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {2:    }{28:XXXXXXXXXX}est                                 |
+      {2:  2 }test                                          |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From 75f350aac6cd952341d7ce88e64b0d6ed2aa694d Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Wed, 5 Apr 2023 00:29:05 +1000
Subject: fix(ui): fix incorrect highlighting when virtual text next to match

---
 test/functional/ui/decorations_spec.lua | 53 +++++++++++++++++++++++++++++----
 1 file changed, 48 insertions(+), 5 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 2d0f3e7a17..292743e21a 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1746,9 +1746,9 @@ bbbbbbb]])
     insert('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz')
     command("set nowrap")
     meths.buf_set_extmark(0, ns, 0, 50,
-      { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+      { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
     meths.buf_set_extmark(0, ns, 0, 2,
-      { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+      { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
     feed('$')
     screen:expect { grid = [[
       opqrstuvwxyzabcdefghijklmnopqrstuvwx{28:virtual text}y^z|
@@ -1773,7 +1773,7 @@ bbbbbbb]])
     insert('abcdefghi')
     command("set nowrap")
     meths.buf_set_extmark(0, ns, 0, 2,
-      { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+      { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' })
     feed('$')
     screen:expect { grid = [[
       {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i|
@@ -1823,7 +1823,7 @@ bbbbbbb]])
     insert('abcdef')
     command("set nowrap")
     meths.buf_set_extmark(0, ns, 0, 3,
-      { virt_text = { { string.rep('X', 50), 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+      { virt_text = { { string.rep('X', 50), 'Special' } }, virt_text_pos = 'inline' })
     feed('$')
     screen:expect { grid = [[
       {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}de^f|
@@ -1850,7 +1850,7 @@ bbbbbbb]])
     test]])
     command('set number')
     meths.buf_set_extmark(0, ns, 0, 1,
-      { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+      { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' })
     feed('gg0')
     screen:expect { grid = [[
       {2:  1 }^t{28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
@@ -1870,6 +1870,49 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('highlighting is correct when virtual text is proceeded with a match', function()
+    insert([[test]])
+    meths.buf_set_extmark(0, ns, 0, 2,
+      { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
+    feed('gg0')
+    command('match ErrorMsg /e/')
+    screen:expect { grid = [[
+      ^t{4:e}{28:virtual text}st                                  |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+    command('match ErrorMsg /s/')
+    screen:expect { grid = [[
+      ^te{28:virtual text}{4:s}t                                  |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From 5547b16c40f92fbc75ad1b9a7b3dd1f5ff50cbb2 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Mon, 3 Apr 2023 22:13:15 +1000
Subject: vim-patch:9.0.1067: in diff mode virtual text is highlighted
 incorrectly

Problem:    In diff mode virtual text is highlighted incorrectly. (Rick Howe)
Solution:   Do not use diff attributes for virtual text. (closes vim/vim#11714)

https://github.com/vim/vim/commit/d097af77797f030e0f29f9bbc298358a5addb2a5

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/decorations_spec.lua | 43 +++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 292743e21a..4579fad53f 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -648,6 +648,9 @@ describe('extmark decorations', function()
       [28] = {foreground = Screen.colors.SlateBlue};
       [29] = {background = Screen.colors.Yellow1};
       [30] = {reverse = true};
+      [31] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.LightMagenta};
+      [32] = {bold = true, reverse = true};
+      [33] = {background = Screen.colors.Red1, bold = true}
     }
 
     ns = meths.create_namespace 'test'
@@ -1913,6 +1916,46 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('in diff mode virtual text is highlighted correct', function()
+    insert([[
+    9000
+    0009
+    0009
+    9000
+    0009
+    ]])
+    command("set diff")
+    meths.buf_set_extmark(0, ns, 0, 1,
+      { virt_text = { { 'test', 'Special' } }, virt_text_pos = 'inline', right_gravity = false })
+    command("vnew")
+    insert([[
+    000
+    000
+    000
+    000
+    000
+    ]])
+    command("set diff")
+    feed('gg0')
+    screen:expect { grid = [[
+      {27:^000                      }│{33:9}{31:test}{27:000                }|
+      {27:000                      }│{27:000}{33:9}{27:                    }|
+      {27:000                      }│{27:000}{33:9}{27:                    }|
+      {27:000                      }│{33:9}{27:000                    }|
+      {27:000                      }│{27:000}{33:9}{27:                    }|
+                               │                        |
+      {1:~                        }│{1:~                       }|
+      {1:~                        }│{1:~                       }|
+      {1:~                        }│{1:~                       }|
+      {1:~                        }│{1:~                       }|
+      {1:~                        }│{1:~                       }|
+      {1:~                        }│{1:~                       }|
+      {1:~                        }│{1:~                       }|
+      {32:[No Name] [+]             }{30:[No Name] [+]           }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From 34d862942c3387eaa9d2bba963d931d384031b90 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Wed, 19 Apr 2023 19:02:33 +1000
Subject: fix(ui): fix virtual text not displaying when two overlapping inlines
 (nowrap)

---
 test/functional/ui/decorations_spec.lua | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 4579fad53f..68a5bb5f9a 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1956,6 +1956,33 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('correctly draws when there are multiple overlapping virtual texts on the same line with nowrap', function()
+    command('set nowrap')
+    insert('a')
+    meths.buf_set_extmark(0, ns, 0, 0,
+      { virt_text = { { string.rep('a', 55), 'Special' } }, virt_text_pos = 'inline' })
+    meths.buf_set_extmark(0, ns, 0, 0,
+      { virt_text = { { string.rep('b', 55), 'Special' } }, virt_text_pos = 'inline' })
+    feed('$')
+    screen:expect { grid = [[
+      {28:bbbbbbbbbbbbbbbbbbbbbbbbb}^a                        |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From a37c99048359c27bbb7e1997c2ec318bb2cba787 Mon Sep 17 00:00:00 2001
From: Ibby <33922797+SleepySwords@users.noreply.github.com>
Date: Thu, 20 Apr 2023 02:15:49 +1000
Subject: fix(ui): fix overflowing nowrap virtual text not displaying if tab
 follows

---
 test/functional/ui/decorations_spec.lua | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 68a5bb5f9a..f67c4be419 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1983,6 +1983,38 @@ bbbbbbb]])
                                                         |
       ]]}
   end)
+
+  it('correctly draws when overflowing virtual text is followed by tab with no wrap', function()
+    command('set nowrap')
+    feed('itest')
+    meths.buf_set_extmark(
+      0,
+      ns,
+      0,
+      0,
+      { virt_text = { { string.rep('a', 60), 'Special' } }, virt_text_pos = 'inline' }
+    )
+    feed('0')
+    screen:expect({
+      grid = [[
+      {28:aaaaaaaaaaaaaaaaaaaaaa}   ^ test                    |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]],
+    })
+  end)
 end)
 
 describe('decorations: virtual lines', function()
-- 
cgit 


From a78fd18ed92d7474d10b5640dcf7a15728d2e03a Mon Sep 17 00:00:00 2001
From: bfredl 
Date: Tue, 9 May 2023 14:26:03 +0200
Subject: fix(extmark): fix cursor position with both left and right gravity
 inline text

---
 test/functional/ui/decorations_spec.lua | 43 +++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index f67c4be419..e8847258f4 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -1745,6 +1745,49 @@ bbbbbbb]])
       ]]}
   end)
 
+  it('cursor position is correct when inserting around virtual texts with both left and right gravity ', function()
+    insert('foo foo foo foo')
+    meths.buf_set_extmark(0, ns, 0, 8, { virt_text = {{ '>>', 'Special' }}, virt_text_pos = 'inline', right_gravity = false })
+    meths.buf_set_extmark(0, ns, 0, 8, { virt_text = {{ '<<', 'Special' }}, virt_text_pos = 'inline', right_gravity = true })
+    feed('08l')
+    screen:expect{ grid = [[
+      foo foo {28:>><<}^foo foo                               |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+      ]]}
+
+    feed('i')
+    screen:expect { grid = [[
+      foo foo {28:>>^<<}foo foo                               |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {24:-- INSERT --}                                      |
+      ]]}
+  end)
+
   it('draws correctly with no wrap multiple virtual text, where one is hidden', function()
     insert('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz')
     command("set nowrap")
-- 
cgit 


From c5528e7fd852939a5719ecc35edde89b41275a15 Mon Sep 17 00:00:00 2001
From: bfredl 
Date: Mon, 22 May 2023 12:15:41 +0200
Subject: fix(test): clean up inline virtual text tests a little

---
 test/functional/ui/decorations_spec.lua | 429 ++++++++++----------------------
 1 file changed, 137 insertions(+), 292 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index e8847258f4..4418729859 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -611,6 +611,20 @@ describe('decorations providers', function()
   end)
 end)
 
+local example_text = [[
+for _,item in ipairs(items) do
+    local text, hl_id_cell, count = unpack(item)
+    if hl_id_cell ~= nil then
+        hl_id = hl_id_cell
+    end
+    for _ = 1, (count or 1) do
+        local cell = line[colpos]
+        cell.text = text
+        cell.hl_id = hl_id
+        colpos = colpos+1
+    end
+end]]
+
 describe('extmark decorations', function()
   local screen, ns
   before_each( function()
@@ -645,31 +659,11 @@ describe('extmark decorations', function()
       [25] = {background = Screen.colors.LightRed};
       [26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey};
       [27] = {background = Screen.colors.Plum1};
-      [28] = {foreground = Screen.colors.SlateBlue};
-      [29] = {background = Screen.colors.Yellow1};
-      [30] = {reverse = true};
-      [31] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.LightMagenta};
-      [32] = {bold = true, reverse = true};
-      [33] = {background = Screen.colors.Red1, bold = true}
     }
 
     ns = meths.create_namespace 'test'
   end)
 
-  local example_text = [[
-for _,item in ipairs(items) do
-    local text, hl_id_cell, count = unpack(item)
-    if hl_id_cell ~= nil then
-        hl_id = hl_id_cell
-    end
-    for _ = 1, (count or 1) do
-        local cell = line[colpos]
-        cell.text = text
-        cell.hl_id = hl_id
-        colpos = colpos+1
-    end
-end]]
-
   it('empty virtual text at eol should not break colorcolumn #17860', function()
     insert(example_text)
     feed('gg')
@@ -1171,8 +1165,38 @@ end]]
     meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 20 })
     screen:expect_unchanged(true)
   end)
+end)
+
 
-  it('can have virtual text of inline position', function()
+describe('decorations: inline virtual text', function()
+  local screen, ns
+  before_each( function()
+    clear()
+    screen = Screen.new(50, 10)
+    screen:attach()
+    screen:set_default_attr_ids {
+      [1] = {bold=true, foreground=Screen.colors.Blue};
+      [2] = {foreground = Screen.colors.Brown};
+      [3] = {bold = true, foreground = Screen.colors.SeaGreen};
+      [4] = {background = Screen.colors.Red1, foreground = Screen.colors.Gray100};
+      [5] = {background = Screen.colors.Red1, bold = true};
+      [6] = {foreground = Screen.colors.DarkCyan};
+      [7] = {background = Screen.colors.LightGrey};
+      [8] = {bold = true};
+      [9] = {background = Screen.colors.Plum1};
+      [10] = {foreground = Screen.colors.SlateBlue};
+      [11] = {blend = 30, background = Screen.colors.Red1};
+      [12] = {background = Screen.colors.Yellow1};
+      [13] = {reverse = true};
+      [14] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.LightMagenta};
+      [15] = {bold = true, reverse = true};
+    }
+
+    ns = meths.create_namespace 'test'
+  end)
+
+
+  it('works', function()
     insert(example_text)
     feed 'gg'
     screen:expect{grid=[[
@@ -1185,18 +1209,13 @@ end]]
               local cell = line[colpos]                 |
               cell.text = text                          |
               cell.hl_id = hl_id                        |
-              colpos = colpos+1                         |
-          end                                           |
-      end                                               |
-      {1:~                                                 }|
-      {1:~                                                 }|
                                                         |
     ]]}
 
     meths.buf_set_extmark(0, ns, 1, 14, {virt_text={{': ', 'Special'}, {'string', 'Type'}}, virt_text_pos='inline'})
     screen:expect{grid=[[
       ^for _,item in ipairs(items) do                    |
-          local text{28:: }{3:string}, hl_id_cell, count = unpack|
+          local text{10:: }{3:string}, hl_id_cell, count = unpack|
       (item)                                            |
           if hl_id_cell ~= nil then                     |
               hl_id = hl_id_cell                        |
@@ -1204,18 +1223,13 @@ end]]
           for _ = 1, (count or 1) do                    |
               local cell = line[colpos]                 |
               cell.text = text                          |
-              cell.hl_id = hl_id                        |
-              colpos = colpos+1                         |
-          end                                           |
-      end                                               |
-      {1:~                                                 }|
                                                         |
     ]]}
 
-    screen:try_resize(55, 15)
+    screen:try_resize(55, 10)
     screen:expect{grid=[[
       ^for _,item in ipairs(items) do                         |
-          local text{28:: }{3:string}, hl_id_cell, count = unpack(item|
+          local text{10:: }{3:string}, hl_id_cell, count = unpack(item|
       )                                                      |
           if hl_id_cell ~= nil then                          |
               hl_id = hl_id_cell                             |
@@ -1223,18 +1237,13 @@ end]]
           for _ = 1, (count or 1) do                         |
               local cell = line[colpos]                      |
               cell.text = text                               |
-              cell.hl_id = hl_id                             |
-              colpos = colpos+1                              |
-          end                                                |
-      end                                                    |
-      {1:~                                                      }|
                                                              |
     ]]}
 
-    screen:try_resize(56, 15)
+    screen:try_resize(56, 10)
     screen:expect{grid=[[
       ^for _,item in ipairs(items) do                          |
-          local text{28:: }{3:string}, hl_id_cell, count = unpack(item)|
+          local text{10:: }{3:string}, hl_id_cell, count = unpack(item)|
           if hl_id_cell ~= nil then                           |
               hl_id = hl_id_cell                              |
           end                                                 |
@@ -1242,11 +1251,6 @@ end]]
               local cell = line[colpos]                       |
               cell.text = text                                |
               cell.hl_id = hl_id                              |
-              colpos = colpos+1                               |
-          end                                                 |
-      end                                                     |
-      {1:~                                                       }|
-      {1:~                                                       }|
                                                               |
     ]]}
   end)
@@ -1260,12 +1264,7 @@ end]]
     feed '^'
     feed '4l'
     screen:expect { grid = [[
-      1234{28: virtual text  virtual text }^5678              |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      1234{10: virtual text  virtual text }^5678              |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1285,12 +1284,7 @@ end]]
             { virt_text = { { ' virtual text ', 'Special' } }, virt_text_pos = 'inline' })
 
     screen:expect { grid = [[
-      1234{28: virtual text }567^8                            |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      1234{10: virtual text }567^8                            |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1303,18 +1297,13 @@ end]]
       ]]}
   end)
 
-  it('has correct highlighting with multi-byte characters in inline virtual text', function()
+  it('has correct highlighting with multi-byte characters', function()
     insert('12345678')
     meths.buf_set_extmark(0, ns, 0, 4,
             { virt_text = { { 'múlti-byté chñröcters 修补', 'Special' } }, virt_text_pos = 'inline' })
 
     screen:expect { grid = [[
-      1234{28:múlti-byté chñröcters 修补}567^8                |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      1234{10:múlti-byté chñröcters 修补}567^8                |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1335,7 +1324,7 @@ end]]
     feed '3l'
     feed 'a'
     screen:expect { grid = [[
-      1234{28:^virtual text}5678                              |
+      1234{10:^virtual text}5678                              |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1344,23 +1333,26 @@ end]]
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
+      {8:-- INSERT --}                                      |
+      ]]}
+    feed ''
+    screen:expect{grid=[[
+      123^4{10:virtual text}5678                              |
+      {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
-      {24:-- INSERT --}                                      |
-      ]]}
-    feed ''
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+    ]]}
     feed '^'
     feed '4l'
     feed 'i'
     screen:expect { grid = [[
-      1234{28:^virtual text}5678                              |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      1234{10:^virtual text}5678                              |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1369,8 +1361,7 @@ end]]
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
-      {1:~                                                 }|
-      {24:-- INSERT --}                                      |
+      {8:-- INSERT --}                                      |
       ]]}
   end)
 
@@ -1378,12 +1369,7 @@ end]]
     meths.buf_set_extmark(0, ns, 0, 0,
             { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
     screen:expect { grid = [[
-      {28:^virtual text}                                      |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      {10:^virtual text}                                      |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1407,82 +1393,62 @@ bbbbbbb]])
             { virt_text = { { string.rep('X', 50), 'Special' } }, virt_text_pos = 'inline' })
     feed('gg0')
     screen:expect { grid = [[
-      {28:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
-      {28:X}                                                 |
+      {10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {10:X}                                                 |
       aaaaaaa                                           |
-      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
       bbbbbbb                                           |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
       {1:~                                                 }|
                                                         |
       ]]}
 
     feed('j')
     screen:expect { grid = [[
-      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
-      {28:X}                                                 |
+      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {10:X}                                                 |
       ^aaaaaaa                                           |
-      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
       bbbbbbb                                           |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
       {1:~                                                 }|
                                                         |
       ]]}
 
     feed('j')
     screen:expect { grid = [[
-      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
-      {28:X}                                                 |
+      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {10:X}                                                 |
       aaaaaaa                                           |
-      {28:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {10:^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
       bbbbbbb                                           |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
       {1:~                                                 }|
                                                         |
       ]]}
 
     feed('j')
     screen:expect { grid = [[
-      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
-      {28:X}                                                 |
+      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {10:X}                                                 |
       aaaaaaa                                           |
-      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
       ^bbbbbbb                                           |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
       {1:~                                                 }|
                                                         |
       ]]}
   end)
 
-  it('cursor position is correct with virtual text attatched to hard tabs', function()
+  it('cursor position is correct with virtual text attached to hard tabs', function()
     command('set noexpandtab')
     feed('i')
     feed('')
@@ -1493,12 +1459,7 @@ bbbbbbb]])
             { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
     feed('0')
     screen:expect { grid = [[
-             ^ {28:virtual text}    test                      |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+             ^ {10:virtual text}    test                      |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1512,12 +1473,7 @@ bbbbbbb]])
 
     feed('l')
     screen:expect { grid = [[
-              {28:virtual text}   ^ test                      |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+              {10:virtual text}   ^ test                      |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1531,12 +1487,7 @@ bbbbbbb]])
 
     feed('l')
     screen:expect { grid = [[
-              {28:virtual text}    ^test                      |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+              {10:virtual text}    ^test                      |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1550,12 +1501,7 @@ bbbbbbb]])
 
     feed('l')
     screen:expect { grid = [[
-              {28:virtual text}    t^est                      |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+              {10:virtual text}    t^est                      |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1569,12 +1515,7 @@ bbbbbbb]])
 
     feed('l')
     screen:expect { grid = [[
-              {28:virtual text}    te^st                      |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+              {10:virtual text}    te^st                      |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1594,12 +1535,7 @@ bbbbbbb]])
     meths.buf_set_extmark(0, ns, 0, 3,
             { virt_text = { { ': virtual text', 'Special' } }, virt_text_pos = 'inline' })
     screen:expect { grid = [[
-      ^one{28:: virtual text} twoword                         |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      ^one{10:: virtual text} twoword                         |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1612,18 +1548,13 @@ bbbbbbb]])
       ]]}
   end)
 
-  it('search highlight is correct with virtual text attatched to', function()
+  it('search highlight is correct', function()
     insert('foo foo foo foo')
     feed('0')
     meths.buf_set_extmark(0, ns, 0, 8,
             { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
     screen:expect { grid = [[
-      ^foo foo {28:virtual text}foo foo                       |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      ^foo foo {10:virtual text}foo foo                       |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1637,12 +1568,7 @@ bbbbbbb]])
 
     feed('/foo')
     screen:expect { grid = [[
-      {29:foo} {30:foo} {28:virtual text}{29:foo} {29:foo}                       |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      {12:foo} {13:foo} {10:virtual text}{12:foo} {12:foo}                       |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1655,20 +1581,14 @@ bbbbbbb]])
       ]]}
   end)
 
-    feed('8l')
-  it('visual select highlight is correct with virtual text attatched to', function()
+  it('visual select highlight is correct', function()
     insert('foo foo foo foo')
     feed('0')
     meths.buf_set_extmark(0, ns, 0, 8,
       { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
     feed('8l')
     screen:expect { grid = [[
-      foo foo {28:virtual text}^foo foo                       |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      foo foo {10:virtual text}^foo foo                       |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1683,10 +1603,7 @@ bbbbbbb]])
     feed('v')
     feed('2h')
     screen:expect { grid = [[
-      foo fo^o{18: }{28:virtual text}{18:f}oo foo                       |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      foo fo^o{7: }{10:virtual text}{7:f}oo foo                       |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1695,9 +1612,7 @@ bbbbbbb]])
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {24:-- VISUAL --}                                      |
+      {8:-- VISUAL --}                                      |
       ]]}
   end)
 
@@ -1708,12 +1623,7 @@ bbbbbbb]])
     feed('0')
     feed('8l')
     screen:expect { grid = [[
-      foo foo {28:virtual text}^foo foo                       |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      foo foo {10:virtual text}^foo foo                       |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1727,12 +1637,7 @@ bbbbbbb]])
 
     feed('i')
     screen:expect { grid = [[
-      foo foo {28:virtual text}^foo foo                       |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      foo foo {10:virtual text}^foo foo                       |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1741,7 +1646,7 @@ bbbbbbb]])
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
-      {24:-- INSERT --}                                      |
+      {8:-- INSERT --}                                      |
       ]]}
   end)
 
@@ -1751,12 +1656,7 @@ bbbbbbb]])
     meths.buf_set_extmark(0, ns, 0, 8, { virt_text = {{ '<<', 'Special' }}, virt_text_pos = 'inline', right_gravity = true })
     feed('08l')
     screen:expect{ grid = [[
-      foo foo {28:>><<}^foo foo                               |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      foo foo {10:>><<}^foo foo                               |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1770,10 +1670,7 @@ bbbbbbb]])
 
     feed('i')
     screen:expect { grid = [[
-      foo foo {28:>>^<<}foo foo                               |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      foo foo {10:>>^<<}foo foo                               |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1782,9 +1679,7 @@ bbbbbbb]])
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {24:-- INSERT --}                                      |
+      {8:-- INSERT --}                                      |
       ]]}
   end)
 
@@ -1797,12 +1692,7 @@ bbbbbbb]])
       { virt_text = { { 'virtual text', 'Special' } }, virt_text_pos = 'inline' })
     feed('$')
     screen:expect { grid = [[
-      opqrstuvwxyzabcdefghijklmnopqrstuvwx{28:virtual text}y^z|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      opqrstuvwxyzabcdefghijklmnopqrstuvwx{10:virtual text}y^z|
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1822,12 +1712,7 @@ bbbbbbb]])
       { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' })
     feed('$')
     screen:expect { grid = [[
-      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}cdefgh^i|
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1847,12 +1732,7 @@ bbbbbbb]])
       { virt_text = { { string.rep('a', 55), 'Special' } }, virt_text_pos = 'inline' })
     feed('gg$')
     screen:expect { grid = [[
-      {28:aaaaaaaaaaaaaaaaaaaaaaaaa}test     ^a               |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      {10:aaaaaaaaaaaaaaaaaaaaaaaaa}test     ^a               |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1872,12 +1752,7 @@ bbbbbbb]])
       { virt_text = { { string.rep('X', 50), 'Special' } }, virt_text_pos = 'inline' })
     feed('$')
     screen:expect { grid = [[
-      {28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}de^f|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      {10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}de^f|
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1899,19 +1774,14 @@ bbbbbbb]])
       { virt_text = { { string.rep('X', 55), 'Special' } }, virt_text_pos = 'inline' })
     feed('gg0')
     screen:expect { grid = [[
-      {2:  1 }^t{28:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
-      {2:    }{28:XXXXXXXXXX}est                                 |
+      {2:  1 }^t{10:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX}|
+      {2:    }{10:XXXXXXXXXX}est                                 |
       {2:  2 }test                                          |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
       {1:~                                                 }|
                                                         |
       ]]}
@@ -1924,12 +1794,7 @@ bbbbbbb]])
     feed('gg0')
     command('match ErrorMsg /e/')
     screen:expect { grid = [[
-      ^t{4:e}{28:virtual text}st                                  |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      ^t{4:e}{10:virtual text}st                                  |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1942,12 +1807,7 @@ bbbbbbb]])
       ]]}
     command('match ErrorMsg /s/')
     screen:expect { grid = [[
-      ^te{28:virtual text}{4:s}t                                  |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      ^te{10:virtual text}{4:s}t                                  |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -1960,7 +1820,7 @@ bbbbbbb]])
       ]]}
   end)
 
-  it('in diff mode virtual text is highlighted correct', function()
+  it('in diff mode is highlighted correct', function()
     insert([[
     9000
     0009
@@ -1982,20 +1842,15 @@ bbbbbbb]])
     command("set diff")
     feed('gg0')
     screen:expect { grid = [[
-      {27:^000                      }│{33:9}{31:test}{27:000                }|
-      {27:000                      }│{27:000}{33:9}{27:                    }|
-      {27:000                      }│{27:000}{33:9}{27:                    }|
-      {27:000                      }│{33:9}{27:000                    }|
-      {27:000                      }│{27:000}{33:9}{27:                    }|
+      {9:^000                      }│{5:9}{14:test}{9:000                }|
+      {9:000                      }│{9:000}{5:9}{9:                    }|
+      {9:000                      }│{9:000}{5:9}{9:                    }|
+      {9:000                      }│{5:9}{9:000                    }|
+      {9:000                      }│{9:000}{5:9}{9:                    }|
                                │                        |
       {1:~                        }│{1:~                       }|
       {1:~                        }│{1:~                       }|
-      {1:~                        }│{1:~                       }|
-      {1:~                        }│{1:~                       }|
-      {1:~                        }│{1:~                       }|
-      {1:~                        }│{1:~                       }|
-      {1:~                        }│{1:~                       }|
-      {32:[No Name] [+]             }{30:[No Name] [+]           }|
+      {15:[No Name] [+]             }{13:[No Name] [+]           }|
                                                         |
       ]]}
   end)
@@ -2009,12 +1864,7 @@ bbbbbbb]])
       { virt_text = { { string.rep('b', 55), 'Special' } }, virt_text_pos = 'inline' })
     feed('$')
     screen:expect { grid = [[
-      {28:bbbbbbbbbbbbbbbbbbbbbbbbb}^a                        |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      {10:bbbbbbbbbbbbbbbbbbbbbbbbb}^a                        |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -2040,12 +1890,7 @@ bbbbbbb]])
     feed('0')
     screen:expect({
       grid = [[
-      {28:aaaaaaaaaaaaaaaaaaaaaa}   ^ test                    |
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
-      {1:~                                                 }|
+      {10:aaaaaaaaaaaaaaaaaaaaaa}   ^ test                    |
       {1:~                                                 }|
       {1:~                                                 }|
       {1:~                                                 }|
@@ -2081,7 +1926,7 @@ describe('decorations: virtual lines', function()
     ns = meths.create_namespace 'test'
   end)
 
-  local example_text = [[
+  local example_text2 = [[
 if (h->n_buckets < new_n_buckets) { // expand
   khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t));
   h->keys = new_keys;
@@ -2092,7 +1937,7 @@ if (h->n_buckets < new_n_buckets) { // expand
 }]]
 
   it('works with one line', function()
-    insert(example_text)
+    insert(example_text2)
     feed 'gg'
     meths.buf_set_extmark(0, ns, 1, 33, {
       virt_lines={ {{">> ", "NonText"}, {"krealloc", "Identifier"}, {": change the size of an allocation"}}};
@@ -2201,7 +2046,7 @@ if (h->n_buckets < new_n_buckets) { // expand
   end)
 
   it('works with text at the beginning of the buffer', function()
-    insert(example_text)
+    insert(example_text2)
     feed 'gg'
 
     screen:expect{grid=[[
@@ -2262,7 +2107,7 @@ if (h->n_buckets < new_n_buckets) { // expand
   end)
 
   it('works with text at the end of the buffer', function()
-    insert(example_text)
+    insert(example_text2)
     feed 'G'
 
     screen:expect{grid=[[
@@ -2381,7 +2226,7 @@ if (h->n_buckets < new_n_buckets) { // expand
   end)
 
   it('works beyond end of the buffer with virt_lines_above', function()
-    insert(example_text)
+    insert(example_text2)
     feed 'G'
 
     screen:expect{grid=[[
@@ -2652,7 +2497,7 @@ if (h->n_buckets < new_n_buckets) { // expand
   end)
 
   it('works with sign and numbercolumns', function()
-    insert(example_text)
+    insert(example_text2)
     feed 'gg'
     command 'set number signcolumn=yes'
     screen:expect{grid=[[
@@ -2718,7 +2563,7 @@ if (h->n_buckets < new_n_buckets) { // expand
 
 
   it('works with hard tabs', function()
-    insert(example_text)
+    insert(example_text2)
     feed 'gg'
     meths.buf_set_extmark(0, ns, 1, 0, {
       virt_lines={ {{">>", "NonText"}, {"\tvery\ttabby", "Identifier"}, {"text\twith\ttabs"}}};
@@ -2805,7 +2650,7 @@ describe('decorations: signs', function()
     meths.set_option_value('signcolumn', 'auto:9', {})
   end)
 
-  local example_text = [[
+  local example_test3 = [[
 l1
 l2
 l3
@@ -2814,7 +2659,7 @@ l5
 ]]
 
   it('can add a single sign (no end row)', function()
-    insert(example_text)
+    insert(example_test3)
     feed 'gg'
 
     meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S'})
@@ -2835,7 +2680,7 @@ l5
   end)
 
   it('can add a single sign (with end row)', function()
-    insert(example_text)
+    insert(example_test3)
     feed 'gg'
 
     meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row=1})
@@ -2857,7 +2702,7 @@ l5
 
   it('can add multiple signs (single extmark)', function()
     pending('TODO(lewis6991): Support ranged signs')
-    insert(example_text)
+    insert(example_test3)
     feed 'gg'
 
     meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row = 2})
@@ -2879,7 +2724,7 @@ l5
 
   it('can add multiple signs (multiple extmarks)', function()
     pending('TODO(lewis6991): Support ranged signs')
-    insert(example_text)
+    insert(example_test3)
     feed'gg'
 
     meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1'})
@@ -2901,7 +2746,7 @@ l5
   end)
 
   it('can add multiple signs (multiple extmarks) 2', function()
-    insert(example_text)
+    insert(example_test3)
     feed 'gg'
 
     meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1'})
@@ -2941,7 +2786,7 @@ l5
   it('can add multiple signs (multiple extmarks) 3', function()
     pending('TODO(lewis6991): Support ranged signs')
 
-    insert(example_text)
+    insert(example_test3)
     feed 'gg'
 
     meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1', end_row=2})
@@ -2962,7 +2807,7 @@ l5
   end)
 
   it('can add multiple signs (multiple extmarks) 4', function()
-    insert(example_text)
+    insert(example_test3)
     feed 'gg'
 
     meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1', end_row=0})
@@ -2983,7 +2828,7 @@ l5
   end)
 
   it('works with old signs', function()
-    insert(example_text)
+    insert(example_test3)
     feed 'gg'
 
     helpers.command('sign define Oldsign text=x')
@@ -3010,7 +2855,7 @@ l5
 
   it('works with old signs (with range)', function()
     pending('TODO(lewis6991): Support ranged signs')
-    insert(example_text)
+    insert(example_test3)
     feed 'gg'
 
     helpers.command('sign define Oldsign text=x')
@@ -3039,7 +2884,7 @@ l5
   it('can add a ranged sign (with start out of view)', function()
     pending('TODO(lewis6991): Support ranged signs')
 
-    insert(example_text)
+    insert(example_test3)
     command 'set signcolumn=yes:2'
     feed 'gg'
     feed '2'
@@ -3096,7 +2941,7 @@ l5
 
   it('works with priority #19716', function()
     screen:try_resize(20, 3)
-    insert(example_text)
+    insert(example_test3)
     feed 'gg'
 
     helpers.command('sign define Oldsign text=O3')
@@ -3126,7 +2971,7 @@ l5
   it('does not set signcolumn for signs without text', function()
     screen:try_resize(20, 3)
     meths.set_option_value('signcolumn', 'auto', {})
-    insert(example_text)
+    insert(example_test3)
     feed 'gg'
     meths.buf_set_extmark(0, ns, 0, -1, {number_hl_group='Error'})
     screen:expect{grid=[[
-- 
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')

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 c855eee919f2d4edc9b9fa91b277454290fbabfe Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Wed, 24 May 2023 10:04:49 +0200
Subject: feat(term): enable reflow by default (#21124)

libvterm v0.3 supports reflow of terminal buffer when Nvim is resized
Since v0.3 is now a required dependency, enable it by default to find
(and fix) possible issues.

Note: Neovim's scrollback buffer does not support reflow (yet), so lines
vanishing into the buffer due to a too small window will be restored
without reflow.
---
 test/functional/terminal/window_spec.lua | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/terminal/window_spec.lua b/test/functional/terminal/window_spec.lua
index 80e9d78400..f90e4f7e9d 100644
--- a/test/functional/terminal/window_spec.lua
+++ b/test/functional/terminal/window_spec.lua
@@ -64,7 +64,7 @@ describe(':terminal window', function()
         {7:       1 }tty ready                                |
         {7:       2 }rows: 6, cols: 48                        |
         {7:       3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO|
-        {7:       4 }WXYZrows: 6, cols: 41                    |
+        {7:       4 }PQRSTUVWXYZrows: 6, cols: 41             |
         {7:       5 }{1: }                                        |
         {7:       6 }                                         |
         {3:-- TERMINAL --}                                    |
@@ -74,7 +74,7 @@ describe(':terminal window', function()
         {7:       1 }tty ready                                |
         {7:       2 }rows: 6, cols: 48                        |
         {7:       3 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO|
-        {7:       4 }WXYZrows: 6, cols: 41                    |
+        {7:       4 }PQRSTUVWXYZrows: 6, cols: 41             |
         {7:       5 } abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMN|
         {7:       6 }OPQRSTUVWXYZ{1: }                            |
         {3:-- TERMINAL --}                                    |
-- 
cgit 


From 678548a2b44601db73cc7d049467abd2b433baae Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 24 May 2023 21:25:39 +0800
Subject: fix(folds): show Folded highlight in Visual selection (#23741)

Note: CursorLine highlight is now combined with Folded.
---
 test/functional/ui/fold_spec.lua         | 65 +++++++++++++++++++++++++++++---
 test/functional/ui/statuscolumn_spec.lua | 18 +++++----
 2 files changed, 69 insertions(+), 14 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 7a0495f93c..2afe27ecc7 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -42,7 +42,9 @@ describe("folded lines", function()
         [9] = {bold = true, foreground = Screen.colors.Brown},
         [10] = {background = Screen.colors.LightGrey, underline = true},
         [11] = {bold=true},
-        [12] = {background = Screen.colors.Grey90},
+        [12] = {background = Screen.colors.Grey90, underline = true},
+        [13] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey, underline = true},
+        [14] = {background = Screen.colors.LightGray},
       })
     end)
 
@@ -86,9 +88,10 @@ describe("folded lines", function()
       end
     end)
 
-    it("highlights with CursorLineFold when 'cursorline' is set", function()
+    it("foldcolumn highlighted with CursorLineFold when 'cursorline' is set", function()
       command("set number cursorline foldcolumn=2")
       command("hi link CursorLineFold Search")
+      command("hi! CursorLine gui=underline guibg=Grey90")
       insert(content1)
       feed("ggzf3jj")
       if multigrid then
@@ -138,7 +141,7 @@ describe("folded lines", function()
           [2:---------------------------------------------]|
           [3:---------------------------------------------]|
         ## grid 2
-          {6:+ }{9:  1 }{12:^+--  4 lines: This is a················}|
+          {6:+ }{9:  1 }{13:^+--  4 lines: This is a················}|
           {7:  }{8:  5 }in his cave.                           |
           {7:  }{8:  6 }                                       |
           {1:~                                            }|
@@ -150,7 +153,7 @@ describe("folded lines", function()
         ]])
       else
         screen:expect([[
-          {6:+ }{9:  1 }{12:^+--  4 lines: This is a················}|
+          {6:+ }{9:  1 }{13:^+--  4 lines: This is a················}|
           {7:  }{8:  5 }in his cave.                           |
           {7:  }{8:  6 }                                       |
           {1:~                                            }|
@@ -179,7 +182,7 @@ describe("folded lines", function()
           [2:---------------------------------------------]|
           [3:---------------------------------------------]|
         ## grid 2
-          {7:+ }{8:  1 }{12:^+--  4 lines: This is a················}|
+          {7:+ }{8:  1 }{13:^+--  4 lines: This is a················}|
           {7:  }{8:  5 }in his cave.                           |
           {7:  }{8:  6 }                                       |
           {1:~                                            }|
@@ -191,7 +194,7 @@ describe("folded lines", function()
         ]])
       else
         screen:expect([[
-          {7:+ }{8:  1 }{12:^+--  4 lines: This is a················}|
+          {7:+ }{8:  1 }{13:^+--  4 lines: This is a················}|
           {7:  }{8:  5 }in his cave.                           |
           {7:  }{8:  6 }                                       |
           {1:~                                            }|
@@ -2013,6 +2016,56 @@ describe("folded lines", function()
         ]])
       end
     end)
+
+    it('Folded highlight does not disappear in Visual selection #19691', function()
+      insert([[
+        " foo
+        " {{{1
+        set nocp
+        " }}}1
+        " bar
+        " {{{1
+        set foldmethod=marker
+        " }}}1
+        " baz]])
+      feed('gg')
+      command('source')
+      feed('G3l')
+      if multigrid then
+        screen:expect([[
+        ## grid 1
+          [2:---------------------------------------------]|
+          [2:---------------------------------------------]|
+          [2:---------------------------------------------]|
+          [2:---------------------------------------------]|
+          [2:---------------------------------------------]|
+          [2:---------------------------------------------]|
+          [2:---------------------------------------------]|
+          [3:---------------------------------------------]|
+        ## grid 2
+          {14:" fo}o                                        |
+          {5:+--  3 lines: "······························}|
+          {14:" ba}r                                        |
+          {5:+--  3 lines: "······························}|
+          {14:" b}^az                                        |
+          {1:~                                            }|
+          {1:~                                            }|
+        ## grid 3
+          {11:-- VISUAL BLOCK --}                           |
+        ]])
+      else
+        screen:expect([[
+          {14:" fo}o                                        |
+          {5:+--  3 lines: "······························}|
+          {14:" ba}r                                        |
+          {5:+--  3 lines: "······························}|
+          {14:" b}^az                                        |
+          {1:~                                            }|
+          {1:~                                            }|
+          {11:-- VISUAL BLOCK --}                           |
+        ]])
+      end
+    end)
   end
 
   describe("with ext_multigrid", function()
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index 3d68246ba9..f349b182c9 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -196,8 +196,10 @@ describe('statuscolumn', function()
       [2] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGrey},
       [3] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},
       [4] = {bold = true, foreground = Screen.colors.Brown},
-      [5] = {background = Screen.colors.Grey90},
+      [5] = {background = Screen.colors.Grey90, underline = true},
+      [6] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey, underline = true},
     })
+    command('hi! CursorLine gui=underline guibg=Grey90')
     screen:expect([[
       {1: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {1:  │ }a                                                |
@@ -214,7 +216,7 @@ describe('statuscolumn', function()
       {1:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{0:@@@}|
                                                            |
     ]])
-    command("set stc=%C%s%=%l│\\ ")
+    command([[set stc=%C%s%=%l│\ ]])
     screen:expect_unchanged()
     command('set signcolumn=auto:2 foldcolumn=auto')
     command('sign define piet1 text=>> texthl=LineNr')
@@ -268,7 +270,7 @@ describe('statuscolumn', function()
       {2: }{1:  │}{2:    }{1: }aaaaaa                                      |
       {2: }{1: 7│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {2: }{1:  │}{2:    }{1: }aaaaaa                                      |
-      {2:+}{4: 8│}{2:    }{4: }{5:^+--  1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+      {2:+}{4: 8│}{2:    }{4: }{6:^+--  1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
       {2: }{1: 9│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {2: }{1:  │}{2:    }{1: }aaaaaa                                      |
       {2: }{1:10│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
@@ -286,7 +288,7 @@ describe('statuscolumn', function()
       {2: }{1: 6│}{2:    }{1: }aaaaaa                                      |
       {2: }{1: 7│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {2: }{1: 7│}{2:    }{1: }aaaaaa                                      |
-      {2:+}{4: 8│}{2:    }{4: }{5:^+--  1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+      {2:+}{4: 8│}{2:    }{4: }{6:^+--  1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
       {2: }{1: 9│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {2: }{1: 9│}{2:    }{1: }aaaaaa                                      |
       {2: }{1:10│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
@@ -304,7 +306,7 @@ describe('statuscolumn', function()
       {2: }{1: 2│}{2:    }{1: }aaaaaa                                      |
       {2: }{1: 1│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {2: }{1: 1│}{2:    }{1: }aaaaaa                                      |
-      {2:+}{4: 0│}{2:    }{4: }{5:^+--  1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+      {2:+}{4: 0│}{2:    }{4: }{6:^+--  1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
       {2: }{1: 1│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {2: }{1: 1│}{2:    }{1: }aaaaaa                                      |
       {2: }{1: 2│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
@@ -321,7 +323,7 @@ describe('statuscolumn', function()
       {2: }{1:  │}{2:    }{1: }aaaaaa                                      |
       {2: }{1: 1│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {2: }{1:  │}{2:    }{1: }aaaaaa                                      |
-      {2:+}{4: 0│}{2:    }{4: }{5:^+--  1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+      {2:+}{4: 0│}{2:    }{4: }{6:^+--  1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
       {2: }{1: 1│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {2: }{1:  │}{2:    }{1: }aaaaaa                                      |
       {2: }{1: 2│}{2:    }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
@@ -346,7 +348,7 @@ describe('statuscolumn', function()
       {2: }{1:  │}{2:                  }{1: }aaaaaaaaaaaaaaaaaaaa          |
       {2: }{1: 1│}{2:                  }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {2: }{1:  │}{2:                  }{1: }aaaaaaaaaaaaaaaaaaaa          |
-      {2:+}{4: 0│}{2:                  }{4: }{5:^+--  1 line: aaaaaaaaaaaaaaaaa}|
+      {2:+}{4: 0│}{2:                  }{4: }{6:^+--  1 line: aaaaaaaaaaaaaaaaa}|
       {2: }{1: 1│}{2:                  }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {2: }{1:  │}{2:                  }{1: }aaaaaaaaaaaaaaaaaaaa          |
       {2: }{1: 2│}{2:                  }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
@@ -372,7 +374,7 @@ describe('statuscolumn', function()
       {1:wrapped 1 6}aaaaaaaa                                  |
       {1:buffer  0 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {1:wrapped 1 7}aaaaaaaa                                  |
-      {4:buffer  0 8}{5:^+--  1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
+      {4:buffer  0 8}{6:^+--  1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}|
       {1:buffer  0 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {1:wrapped 1 9}aaaaaaaa                                  |
                                                            |
-- 
cgit 


From bff67c9fbe8c174dae8952a565a110930dc4fc58 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 24 May 2023 19:50:01 +0200
Subject: vim-patch:9.0.0175: spell checking for capital not working with
 trailing space

Problem:    Spell checking for capital not working with trailing space.
Solution:   Do not calculate cap_col at the end of the line. (Christian
            Brabandt, closes vim/vim#10870, issue vim/vim#10838)

https://github.com/vim/vim/commit/afa23d1b99692e3c726eb694933ab348b442a1e4

Co-authored-by: Christian Brabandt 
---
 test/functional/ui/spell_spec.lua | 83 ++++++++++++++++++++++++++-------------
 1 file changed, 55 insertions(+), 28 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index 0f553d4a9b..c5c4ec3b99 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -3,9 +3,9 @@
 local helpers = require('test.functional.helpers')(after_each)
 local Screen = require('test.functional.ui.screen')
 local clear = helpers.clear
+local exec = helpers.exec
 local feed = helpers.feed
 local insert = helpers.insert
-local command = helpers.command
 local meths = helpers.meths
 local curbufmeths = helpers.curbufmeths
 local is_os = helpers.is_os
@@ -32,7 +32,7 @@ describe("'spell'", function()
 
   it('joins long lines #7937', function()
     if is_os('openbsd') then pending('FIXME #12104', function() end) return end
-    command('set spell')
+    exec('set spell')
     insert([[
     Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
     tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
@@ -57,31 +57,58 @@ describe("'spell'", function()
 
   -- oldtest: Test_spell_screendump()
   it('has correct highlight at start of line', function()
-    insert([[
-    "This is some text without any spell errors.  Everything",
-    "should just be black, nothing wrong here.",
-    "",
-    "This line has a sepll error. and missing caps.",
-    "And and this is the the duplication.",
-    "with missing caps here.",
+    exec([=[
+      call setline(1, [
+        \"This is some text without any spell errors.  Everything",
+        \"should just be black, nothing wrong here.",
+        \"",
+        \"This line has a sepll error. and missing caps.",
+        \"And and this is the the duplication.",
+        \"with missing caps here.",
+      \])
+      set spell spelllang=en_nz
+    ]=])
+    screen:expect([[
+      ^This is some text without any spell errors.  Everything                         |
+      should just be black, nothing wrong here.                                       |
+                                                                                      |
+      This line has a {1:sepll} error. {2:and} missing caps.                                  |
+      {1:And and} this is {1:the the} duplication.                                            |
+      {2:with} missing caps here.                                                         |
+      {0:~                                                                               }|
+                                                                                      |
     ]])
-    command('set spell spelllang=en_nz')
+  end)
+
+  -- oldtest: Test_spell_screendump_spellcap()
+  it('has correct highlight at start of line with trailing space', function()
+    exec([=[
+      call setline(1, [
+        \"   This line has a sepll error. and missing caps and trailing spaces.   ",
+        \"another missing cap here.",
+        \"",
+        \"and here.",
+        \"    ",
+        \"and here."
+      \])
+      set spell spelllang=en
+    ]=])
     screen:expect([[
-    "This is some text without any spell errors.  Everything",                      |
-    "should just be black, nothing wrong here.",                                    |
-    "",                                                                             |
-    "This line has a {1:sepll} error. {2:and} missing caps.",                               |
-    "{1:And and} this is {1:the the} duplication.",                                         |
-    "with missing caps here.",                                                      |
-    ^                                                                                |
-                                                                                    |
+      ^   This line has a {1:sepll} error. {2:and} missing caps and trailing spaces.           |
+      {2:another} missing cap here.                                                       |
+                                                                                      |
+      {2:and} here.                                                                       |
+                                                                                      |
+      {2:and} here.                                                                       |
+      {0:~                                                                               }|
+                                                                                      |
     ]])
   end)
 
   it('extmarks, "noplainbuffer" and syntax #20385 #23398', function()
-    command('set filetype=c')
-    command('syntax on')
-    command('set spell')
+    exec('set filetype=c')
+    exec('syntax on')
+    exec('set spell')
     insert([[
       #include 
       bool func(void);
@@ -119,7 +146,7 @@ describe("'spell'", function()
       {0:~                                                                               }|
       {6:search hit BOTTOM, continuing at TOP}                                            |
     ]])
-    command('echo ""')
+    exec('echo ""')
     local ns = meths.create_namespace("spell")
     -- extmark with spell=true enables spell
     local id = curbufmeths.set_extmark(ns, 1, 4, { end_row = 1, end_col = 10, spell = true })
@@ -168,7 +195,7 @@ describe("'spell'", function()
       {0:~                                                                               }|
       {6:search hit TOP, continuing at BOTTOM}                                            |
     ]])
-    command('echo ""')
+    exec('echo ""')
     curbufmeths.del_extmark(ns, id)
     screen:expect([[
       {3:#include }{4:}                                                            |
@@ -192,7 +219,7 @@ describe("'spell'", function()
                                                                                       |
     ]])
     -- "noplainbuffer" shouldn't change spellchecking behavior with syntax enabled
-    command('set spelloptions+=noplainbuffer')
+    exec('set spelloptions+=noplainbuffer')
     screen:expect_unchanged()
     feed('[s')
     screen:expect([[
@@ -206,7 +233,7 @@ describe("'spell'", function()
                                                                                       |
     ]])
     -- no spellchecking with "noplainbuffer" and syntax disabled
-    command('syntax off')
+    exec('syntax off')
     screen:expect([[
       #include                                                             |
       bool func(void);                                                                |
@@ -228,9 +255,9 @@ describe("'spell'", function()
       {0:~                                                                               }|
       {6:search hit BOTTOM, continuing at TOP}                                            |
     ]])
-    command('echo ""')
+    exec('echo ""')
     -- everything is spellchecked without "noplainbuffer" with syntax disabled
-    command('set spelloptions&')
+    exec('set spelloptions&')
     screen:expect([[
       #include <{1:stdbool}.h>                                                            |
       {1:bool} {1:func}(void);                                                                |
@@ -256,7 +283,7 @@ describe("'spell'", function()
 
   it('and syntax does not clear extmark highlighting at the start of a word', function()
     screen:try_resize(43, 3)
-    command([[
+    exec([[
       set spell
       syntax match Constant "^.*$"
       call setline(1, "This is some text without any spell errors.")
-- 
cgit 


From ad7cded1f3f40912d962796d6965dac17ecb97f0 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 24 May 2023 20:13:11 +0200
Subject: vim-patch:9.0.0590: after exiting Insert mode spelling not checked in
 next line

Problem:    After exiting Insert mode spelling is not checked in the next
            line.
Solution:   When spelling is enabled redraw the next line after exiting Insert
            mode in case the spell highlight needs updating.

https://github.com/vim/vim/commit/ee09fcc9b6cf24e02899461809da9a5148208ea5

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/spell_spec.lua | 12 ++++++++++++
 1 file changed, 12 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index c5c4ec3b99..5cfb85e431 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -103,6 +103,18 @@ describe("'spell'", function()
       {0:~                                                                               }|
                                                                                       |
     ]])
+    -- After adding word missing Cap in next line is updated
+    feed('3GANot')
+    screen:expect([[
+         This line has a {1:sepll} error. {2:and} missing caps and trailing spaces.           |
+      {2:another} missing cap here.                                                       |
+      No^t                                                                             |
+      and here.                                                                       |
+                                                                                      |
+      {2:and} here.                                                                       |
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
   end)
 
   it('extmarks, "noplainbuffer" and syntax #20385 #23398', function()
-- 
cgit 


From d2dc7cfa5b930a1ff68426f3d47809508ac7d392 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 24 May 2023 20:26:03 +0200
Subject: vim-patch:9.0.0608: with spelling, deleting a full stop does not
 update next line

Problem:    With spell checking, deleting a full stop at the end of a line
            does not update SpellCap at the start of the next line.
Solution:   Update the next line when characters have been deleted.  Also when
            using undo.

https://github.com/vim/vim/commit/26f09ea54b2c60abf21df42c60bdfc60eca17b0d

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/spell_spec.lua | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index 5cfb85e431..800043b169 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -115,6 +115,30 @@ describe("'spell'", function()
       {0:~                                                                               }|
                                                                                       |
     ]])
+    -- Deleting a full stop removes missing Cap in next line
+    feed('5Gddk$x')
+    screen:expect([[
+         This line has a {1:sepll} error. {2:and} missing caps and trailing spaces.           |
+      {2:another} missing cap here.                                                       |
+      Not                                                                             |
+      and her^e                                                                        |
+      and here.                                                                       |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
+    -- Undo also updates the next line (go to command line to remove message)
+    feed('u:')
+    screen:expect([[
+         This line has a {1:sepll} error. {2:and} missing caps and trailing spaces.           |
+      {2:another} missing cap here.                                                       |
+      Not                                                                             |
+      and here^.                                                                       |
+      {2:and} here.                                                                       |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
   end)
 
   it('extmarks, "noplainbuffer" and syntax #20385 #23398', function()
-- 
cgit 


From 50efdd6ccf1891392c048b92da5e5d123a30ff26 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 24 May 2023 20:41:58 +0200
Subject: vim-patch:9.0.0664: bad redrawing with spell checking, using "C" and
 "$" in 'cpo'

Problem:    Bad redrawing with spell checking, using "C" and "$" in 'cpo'.
Solution:   Do not redraw the next line when "$" is in 'cpo'. (closes vim/vim#11285)

https://github.com/vim/vim/commit/f3ef026c9897f1d2e3fba47166a4771d507dae91

Co-authored-by: Bram Moolenaar 
---
 test/functional/ui/spell_spec.lua | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index 800043b169..7f11b06f78 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -27,6 +27,7 @@ describe("'spell'", function()
       [6] = {foreground = Screen.colors.Red},
       [7] = {foreground = Screen.colors.Blue},
       [8] = {foreground = Screen.colors.Blue, special = Screen.colors.Red, undercurl = true},
+      [9] = {bold = true},
     })
   end)
 
@@ -141,6 +142,40 @@ describe("'spell'", function()
     ]])
   end)
 
+  -- oldtest: Test_spell_compatible()
+  it([[redraws properly when using "C" and "$" is in 'cpo']], function()
+    exec([=[
+      call setline(1, [
+        \ "test "->repeat(20),
+        \ "",
+        \ "end",
+      \ ])
+      set spell cpo+=$
+    ]=])
+    feed('51|C')
+    screen:expect([[
+      {2:test} test test test test test test test test test ^test test test test test test |
+      test test test test$                                                            |
+                                                                                      |
+      {2:end}                                                                             |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {9:-- INSERT --}                                                                    |
+    ]])
+    feed('x')
+    screen:expect([[
+      {2:test} test test test test test test test test test x^est test test test test test |
+      test test test test$                                                            |
+                                                                                      |
+      {2:end}                                                                             |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {9:-- INSERT --}                                                                    |
+    ]])
+  end)
+
   it('extmarks, "noplainbuffer" and syntax #20385 #23398', function()
     exec('set filetype=c')
     exec('syntax on')
-- 
cgit 


From ee986ee0449b828ca64bf7d4c69624596aab8319 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Thu, 25 May 2023 22:14:12 +0800
Subject: fix(folds): combined Folded and Visual highlights (#23752)

Also combine high-priority CursorLine with Folded.
---
 test/functional/ui/decorations_spec.lua  | 39 ++++++++++++++++++++++++++++++--
 test/functional/ui/fold_spec.lua         | 37 ++++++++++++++++++++++--------
 test/functional/ui/statuscolumn_spec.lua |  6 ++---
 3 files changed, 67 insertions(+), 15 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index e430865df6..b301ed8353 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -10,6 +10,7 @@ local expect_events = helpers.expect_events
 local meths = helpers.meths
 local curbufmeths = helpers.curbufmeths
 local command = helpers.command
+local assert_alive = helpers.assert_alive
 
 describe('decorations providers', function()
   local screen
@@ -80,7 +81,7 @@ describe('decorations providers', function()
       local ns2 = api.nvim_create_namespace "ns2"
       api.nvim_set_decoration_provider(ns2, {})
     ]])
-    helpers.assert_alive()
+    assert_alive()
   end)
 
   it('leave a trace', function()
@@ -1092,7 +1093,7 @@ describe('extmark decorations', function()
       {1:~                                                 }|
                                                         |
     ]]}
-    helpers.assert_alive()
+    assert_alive()
   end)
 
   it('conceal #19007', function()
@@ -1258,6 +1259,9 @@ describe('decorations: inline virtual text', function()
       [13] = {reverse = true};
       [14] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.LightMagenta};
       [15] = {bold = true, reverse = true};
+      [16] = {foreground = Screen.colors.Red};
+      [17] = {background = Screen.colors.LightGrey, foreground = Screen.colors.DarkBlue};
+      [18] = {background = Screen.colors.LightGrey, foreground = Screen.colors.Red};
     }
 
     ns = meths.create_namespace 'test'
@@ -1971,6 +1975,37 @@ bbbbbbb]])
       ]],
     })
   end)
+
+  it('does not crash at column 0 when folded in a wide window', function()
+    screen:try_resize(82, 4)
+    command('hi! CursorLine guibg=NONE guifg=Red gui=NONE')
+    command('set cursorline')
+    insert([[
+      aaaaa
+      bbbbb
+      ccccc]])
+    meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'foo'}}, virt_text_pos = 'inline' })
+    screen:expect{grid=[[
+      fooaaaaa                                                                          |
+      bbbbb                                                                             |
+      {16:cccc^c                                                                             }|
+                                                                                        |
+    ]]}
+    command('1,2fold')
+    screen:expect{grid=[[
+      {17:+--  2 lines: aaaaa·······························································}|
+      {16:cccc^c                                                                             }|
+      {1:~                                                                                 }|
+                                                                                        |
+    ]]}
+    feed('k')
+    screen:expect{grid=[[
+      {18:^+--  2 lines: aaaaa·······························································}|
+      ccccc                                                                             |
+      {1:~                                                                                 }|
+                                                                                        |
+    ]]}
+  end)
 end)
 
 describe('decorations: virtual lines', function()
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 2afe27ecc7..520979a2c2 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -42,9 +42,10 @@ describe("folded lines", function()
         [9] = {bold = true, foreground = Screen.colors.Brown},
         [10] = {background = Screen.colors.LightGrey, underline = true},
         [11] = {bold=true},
-        [12] = {background = Screen.colors.Grey90, underline = true},
-        [13] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey, underline = true},
-        [14] = {background = Screen.colors.LightGray},
+        [12] = {foreground = Screen.colors.Red},
+        [13] = {foreground = Screen.colors.Red, background = Screen.colors.LightGrey},
+        [14] = {background = Screen.colors.Red},
+        [15] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Red},
       })
     end)
 
@@ -88,10 +89,9 @@ describe("folded lines", function()
       end
     end)
 
-    it("foldcolumn highlighted with CursorLineFold when 'cursorline' is set", function()
+    local function test_folded_cursorline()
       command("set number cursorline foldcolumn=2")
       command("hi link CursorLineFold Search")
-      command("hi! CursorLine gui=underline guibg=Grey90")
       insert(content1)
       feed("ggzf3jj")
       if multigrid then
@@ -239,6 +239,22 @@ describe("folded lines", function()
                                                        |
         ]])
       end
+    end
+
+    describe("when 'cursorline' is set", function()
+      it('with high-priority CursorLine', function()
+        command("hi! CursorLine guibg=NONE guifg=Red gui=NONE")
+        test_folded_cursorline()
+      end)
+
+      it('with low-priority CursorLine', function()
+        command("hi! CursorLine guibg=NONE guifg=NONE gui=underline")
+        local attrs = screen:get_default_attr_ids()
+        attrs[12] = {underline = true}
+        attrs[13] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey, underline = true}
+        screen:set_default_attr_ids(attrs)
+        test_folded_cursorline()
+      end)
     end)
 
     it("work with spell", function()
@@ -2017,7 +2033,8 @@ describe("folded lines", function()
       end
     end)
 
-    it('Folded highlight does not disappear in Visual selection #19691', function()
+    it('Folded and Visual highlights are combined #19691', function()
+      command('hi! Visual guibg=Red')
       insert([[
         " foo
         " {{{1
@@ -2044,9 +2061,9 @@ describe("folded lines", function()
           [3:---------------------------------------------]|
         ## grid 2
           {14:" fo}o                                        |
-          {5:+--  3 lines: "······························}|
+          {15:+-- }{5: 3 lines: "······························}|
           {14:" ba}r                                        |
-          {5:+--  3 lines: "······························}|
+          {15:+-- }{5: 3 lines: "······························}|
           {14:" b}^az                                        |
           {1:~                                            }|
           {1:~                                            }|
@@ -2056,9 +2073,9 @@ describe("folded lines", function()
       else
         screen:expect([[
           {14:" fo}o                                        |
-          {5:+--  3 lines: "······························}|
+          {15:+-- }{5: 3 lines: "······························}|
           {14:" ba}r                                        |
-          {5:+--  3 lines: "······························}|
+          {15:+-- }{5: 3 lines: "······························}|
           {14:" b}^az                                        |
           {1:~                                            }|
           {1:~                                            }|
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index f349b182c9..c218bd8fd6 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -196,10 +196,10 @@ describe('statuscolumn', function()
       [2] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGrey},
       [3] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey},
       [4] = {bold = true, foreground = Screen.colors.Brown},
-      [5] = {background = Screen.colors.Grey90, underline = true},
-      [6] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey, underline = true},
+      [5] = {foreground = Screen.colors.Red},
+      [6] = {foreground = Screen.colors.Red, background = Screen.colors.LightGrey},
     })
-    command('hi! CursorLine gui=underline guibg=Grey90')
+    command('hi! CursorLine guifg=Red guibg=NONE')
     screen:expect([[
       {1: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
       {1:  │ }a                                                |
-- 
cgit 


From 455bca1ba86a2524251fea6f79ef668c1e38f6aa Mon Sep 17 00:00:00 2001
From: bfredl 
Date: Wed, 24 May 2023 14:33:09 +0200
Subject: fix(drawline): combine extmark highligh with area hl correctly

fixes #23734

Get rid of the weird attr_pri dance which always seemed like a kludge:

    if (!attr_pri) {
      wlv.char_attr = hl_combine_attr(wlv.char_attr, extmark_attr);
    } else {
      wlv.char_attr = hl_combine_attr(extmark_attr, wlv.char_attr);
    }

Instead combine extmark attrs with (old-skool) syntax attrs in a consistent way and then combine that with attr_pri and the rest in an _unified_ code path

fixes #23722

Co-authored-by: luukvbaal 
Co-authored-by: zeertzjq 
---
 test/functional/ui/decorations_spec.lua | 49 ++++++++++++++++++++++++++++++++-
 test/functional/ui/highlight_spec.lua   | 35 +++++++++++++++++++++++
 2 files changed, 83 insertions(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index e430865df6..1e21d90be9 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -659,6 +659,8 @@ describe('extmark decorations', function()
       [25] = {background = Screen.colors.LightRed};
       [26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey};
       [27] = {background = Screen.colors.Plum1};
+      [28] = {underline = true, foreground = Screen.colors.SlateBlue};
+      [29] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.LightGray, underline = true};
     }
 
     ns = meths.create_namespace 'test'
@@ -1233,8 +1235,53 @@ describe('extmark decorations', function()
     meths.buf_set_extmark(0, ns, 0, 3, { end_col = 6, hl_group = 'TestBold', priority = 20 })
     screen:expect_unchanged(true)
   end)
-end)
 
+  it('highlights the beginning of a TAB char correctly', function()
+    screen:try_resize(50, 3)
+    meths.buf_set_lines(0, 0, -1, true, {'this is the\ttab'})
+    meths.buf_set_extmark(0, ns, 0, 11, { end_col = 15, hl_group = 'ErrorMsg' })
+    screen:expect{grid=[[
+      ^this is the{4:     tab}                               |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+
+    meths.buf_clear_namespace(0, ns, 0, -1)
+    meths.buf_set_extmark(0, ns, 0, 12, { end_col = 15, hl_group = 'ErrorMsg' })
+    screen:expect{grid=[[
+      ^this is the     {4:tab}                               |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+  end)
+
+  pending('highlight applies to a full Tab in visual block mode #23734', function()
+    screen:try_resize(50, 8)
+    meths.buf_set_lines(0, 0, -1, true, {'asdf', '\tasdf', '\tasdf', '\tasdf', 'asdf'})
+    meths.buf_set_extmark(0, ns, 0, 0, {end_row = 5, end_col = 0, hl_group = 'Underlined'})
+    screen:expect([[
+      {28:^asdf}                                              |
+      {28:        asdf}                                      |
+      {28:        asdf}                                      |
+      {28:        asdf}                                      |
+      {28:asdf}                                              |
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+    ]])
+    feed('Gll')
+    screen:expect([[
+      {29:asd}{28:f}                                              |
+      {29:   }{28:     asdf}                                      |
+      {29:   }{28:     asdf}                                      |
+      {29:   }{28:     asdf}                                      |
+      {29:as}{28:^df}                                              |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {24:-- VISUAL BLOCK --}                                |
+    ]])
+  end)
+end)
 
 describe('decorations: inline virtual text', function()
   local screen, ns
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 89b503141b..9a4be4573c 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -526,6 +526,41 @@ describe('highlight', function()
     })
 
   end)
+
+  it("'diff', syntax and extmark", function()
+    local screen = Screen.new(25,10)
+    screen:attach()
+    exec([[
+      new
+      call setline(1, ['', '01234 6789'])
+      windo diffthis
+      wincmd w
+      syn match WarningMsg "^.*$"
+      call nvim_buf_add_highlight(0, -1, 'ErrorMsg', 1, 2, 8)
+    ]])
+    screen:expect([[
+      {1:  }^                       |
+      {1:  }{2:01}{3:234 67}{2:89}{5:             }|
+      {4:~                        }|
+      {4:~                        }|
+      {7:[No Name] [+]            }|
+      {1:  }                       |
+      {1:  }{6:-----------------------}|
+      {4:~                        }|
+      {8:[No Name]                }|
+                               |
+    ]],{
+      [0] = {Screen.colors.WebGray, foreground = Screen.colors.DarkBlue},
+      [1] = {background = Screen.colors.Grey, foreground = Screen.colors.Blue4},
+      [2] = {foreground = Screen.colors.Red, background = Screen.colors.LightBlue},
+      [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.LightBlue},
+      [4] = {bold = true, foreground = Screen.colors.Blue},
+      [5] = {background = Screen.colors.LightBlue},
+      [6] = {bold = true, background = Screen.colors.LightCyan, foreground = Screen.colors.Blue1},
+      [7] = {reverse = true, bold = true},
+      [8] = {reverse = true},
+    })
+  end)
 end)
 
 describe("'listchars' highlight", function()
-- 
cgit 


From 43d66c0ebbe43f40a1f76e1635ccef6181c01317 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Thu, 11 May 2023 10:48:48 +0800
Subject: fix(ui-ext): send title to newly-attached UI

---
 test/functional/ui/screen_basic_spec.lua | 12 ++++++++++++
 1 file changed, 12 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua
index b31e40d4ab..67e3b774b4 100644
--- a/test/functional/ui/screen_basic_spec.lua
+++ b/test/functional/ui/screen_basic_spec.lua
@@ -117,6 +117,12 @@ local function screen_tests(linegrid)
       screen:expect(function()
         eq(expected, screen.title)
       end)
+      screen:detach()
+      screen.title = nil
+      screen:attach()
+      screen:expect(function()
+        eq(expected, screen.title)
+      end)
     end)
   end)
 
@@ -128,6 +134,12 @@ local function screen_tests(linegrid)
       screen:expect(function()
         eq(expected, screen.icon)
       end)
+      screen:detach()
+      screen.icon = nil
+      screen:attach()
+      screen:expect(function()
+        eq(expected, screen.icon)
+      end)
     end)
   end)
 
-- 
cgit 


From f733595e795cd2b819cb8fd18327cd51f47b2124 Mon Sep 17 00:00:00 2001
From: luukvbaal 
Date: Fri, 26 May 2023 02:08:18 +0200
Subject: vim-patch:9.0.1578: SpellCap highlight not always updated when needed
 (#23755)

Problem:    SpellCap highlight not always updated when needed.
Solution:   Handle updating line below closed fold and other situations where
            only part of the window is redrawn. (Luuk van Baal, closes vim/vim#12428,
            closes vim/vim#12420)

https://github.com/vim/vim/commit/2ac6497f0ef186f0e3ba67d7f0a485bfb612bb08
---
 test/functional/ui/spell_spec.lua | 42 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index 7f11b06f78..630d0d0948 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -28,6 +28,7 @@ describe("'spell'", function()
       [7] = {foreground = Screen.colors.Blue},
       [8] = {foreground = Screen.colors.Blue, special = Screen.colors.Red, undercurl = true},
       [9] = {bold = true},
+      [10] = {background = Screen.colors.LightGrey, foreground = Screen.colors.DarkBlue},
     })
   end)
 
@@ -82,7 +83,7 @@ describe("'spell'", function()
   end)
 
   -- oldtest: Test_spell_screendump_spellcap()
-  it('has correct highlight at start of line with trailing space', function()
+  it('SpellCap highlight at start of line', function()
     exec([=[
       call setline(1, [
         \"   This line has a sepll error. and missing caps and trailing spaces.   ",
@@ -117,7 +118,7 @@ describe("'spell'", function()
                                                                                       |
     ]])
     -- Deleting a full stop removes missing Cap in next line
-    feed('5Gddk$x')
+    feed('5Gddk$x')
     screen:expect([[
          This line has a {1:sepll} error. {2:and} missing caps and trailing spaces.           |
       {2:another} missing cap here.                                                       |
@@ -140,6 +141,43 @@ describe("'spell'", function()
       {0:~                                                                               }|
                                                                                       |
     ]])
+    -- Folding an empty line does not remove Cap in next line
+    feed('uzfk:')
+    screen:expect([[
+         This line has a {1:sepll} error. {2:and} missing caps and trailing spaces.           |
+      {2:another} missing cap here.                                                       |
+      Not                                                                             |
+      {10:^+--  2 lines: and here.·························································}|
+      {2:and} here.                                                                       |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
+    -- Folding the end of a sentence does not remove Cap in next line
+    -- and editing a line does not remove Cap in current line
+    feed('Jzfkk$x')
+    screen:expect([[
+         This line has a {1:sepll} error. {2:and} missing caps and trailing spaces.           |
+      {2:another} missing cap her^e                                                        |
+      {10:+--  2 lines: Not·······························································}|
+      {2:and} here.                                                                       |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
+    -- Cap is correctly applied in the first row of a window
+    feed('')
+    screen:expect([[
+      {2:another} missing cap her^e                                                        |
+      {10:+--  2 lines: Not·······························································}|
+      {2:and} here.                                                                       |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
   end)
 
   -- oldtest: Test_spell_compatible()
-- 
cgit 


From a6dd67f5b66c0ef646808422ceeac710ce144547 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Fri, 26 May 2023 10:41:19 +0800
Subject: fix(extmarks): fix virt_text_hide with 'nowrap' and multibyte
 (#23757)

---
 test/functional/ui/decorations_spec.lua | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index b301ed8353..767ec54a7b 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -825,6 +825,26 @@ describe('extmark decorations', function()
       end  -- ?古古古古?古古                                                            |
                                                                                         |
     ]]}
+
+    screen:try_resize(50, 2)
+    command('set nowrap')
+    meths.buf_set_lines(0, 12, 12, true, {'-- ' .. ('…'):rep(57)})
+    feed('G')
+    meths.buf_set_extmark(0, ns, 12, 123, { virt_text={{'!!!!!', 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide=true})
+    screen:expect{grid=[[
+      ^-- …………………………………………………………………………………………………………{4:!!!!!}……|
+                                                        |
+    ]]}
+    feed('40zl')
+    screen:expect{grid=[[
+      ^………{4:!!!!!}………………………………                              |
+                                                        |
+    ]]}
+    feed('10zl')
+    screen:expect{grid=[[
+      ^…………………………                                        |
+                                                        |
+    ]]}
   end)
 
   it('can have virtual text of overlay position and styling', function()
-- 
cgit 


From 510e1f131b56e0423342f597178459a63eb0b810 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sat, 27 May 2023 21:36:16 +0800
Subject: fix(extmarks): make right_align and win_col work on wrapped line
 (#23759)

---
 test/functional/ui/decorations_spec.lua | 115 +++++++++++++++++++++++++++-----
 1 file changed, 98 insertions(+), 17 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 3ed31033fa..b9080cbcf5 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -940,25 +940,30 @@ describe('extmark decorations', function()
     ]]}
   end)
 
-  it('can have virtual text of fixed win_col position', function()
+  it('can have virtual text of right_align and fixed win_col position', function()
     insert(example_text)
     feed 'gg'
     meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}},   virt_text_win_col=31, hl_mode='blend'})
+    meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'VERY', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'})
     meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}},   virt_text_win_col=31, hl_mode='blend'})
+    meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'MUCH', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'})
     meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'})
+    meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'ERROR', 'ErrorMsg'}}, virt_text_pos='right_align', hl_mode='blend'})
     meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'})
+    meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_pos='right_align', hl_mode='blend'})
     -- empty virt_text should not change anything
     meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_win_col=14, hl_mode='blend'})
+    meths.buf_set_extmark(0, ns, 8, 0, { virt_text={{''}}, virt_text_pos='right_align', hl_mode='blend'})
 
     screen:expect{grid=[[
       ^for _,item in ipairs(items) do                    |
-          local text, hl_id_cell, cou{4:Very} unpack(item)  |
-          if hl_id_cell ~= nil then  {4:Much}               |
-              hl_id = hl_id_cell     {4:Error}              |
+          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
+          if hl_id_cell ~= nil then  {4:Much}           {4:MUCH}|
+              hl_id = hl_id_cell     {4:Error}         {4:ERROR}|
           end                                           |
           for _ = 1, (count or 1) do                    |
               local cell = line[colpos]                 |
-          {1:-}   cell.text = text                          |
+          {1:-}   cell.text = text                         {1:-}|
               cell.hl_id = hl_id                        |
               colpos = colpos+1                         |
           end                                           |
@@ -971,14 +976,14 @@ describe('extmark decorations', function()
     feed '3G12|i'
     screen:expect{grid=[[
       for _,item in ipairs(items) do                    |
-          local text, hl_id_cell, cou{4:Very} unpack(item)  |
-          if hl_i                    {4:Much}               |
+          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
+          if hl_i                    {4:Much}           {4:MUCH}|
       ^d_cell ~= nil then                                |
-              hl_id = hl_id_cell     {4:Error}              |
+              hl_id = hl_id_cell     {4:Error}         {4:ERROR}|
           end                                           |
           for _ = 1, (count or 1) do                    |
               local cell = line[colpos]                 |
-          {1:-}   cell.text = text                          |
+          {1:-}   cell.text = text                         {1:-}|
               cell.hl_id = hl_id                        |
               colpos = colpos+1                         |
           end                                           |
@@ -990,13 +995,13 @@ describe('extmark decorations', function()
     feed 'u:'
     screen:expect{grid=[[
       for _,item in ipairs(items) do                    |
-          local text, hl_id_cell, cou{4:Very} unpack(item)  |
-          if hl_i^d_cell ~= nil then  {4:Much}               |
-              hl_id = hl_id_cell     {4:Error}              |
+          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
+          if hl_i^d_cell ~= nil then  {4:Much}           {4:MUCH}|
+              hl_id = hl_id_cell     {4:Error}         {4:ERROR}|
           end                                           |
           for _ = 1, (count or 1) do                    |
               local cell = line[colpos]                 |
-          {1:-}   cell.text = text                          |
+          {1:-}   cell.text = text                         {1:-}|
               cell.hl_id = hl_id                        |
               colpos = colpos+1                         |
           end                                           |
@@ -1009,14 +1014,14 @@ describe('extmark decorations', function()
     feed '8|i'
     screen:expect{grid=[[
       for _,item in ipairs(items) do                    |
-          local text, hl_id_cell, cou{4:Very} unpack(item)  |
+          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
           if                                            |
-      ^hl_id_cell ~= nil then         {4:Much}               |
-              hl_id = hl_id_cell     {4:Error}              |
+      ^hl_id_cell ~= nil then         {4:Much}           {4:MUCH}|
+              hl_id = hl_id_cell     {4:Error}         {4:ERROR}|
           end                                           |
           for _ = 1, (count or 1) do                    |
               local cell = line[colpos]                 |
-          {1:-}   cell.text = text                          |
+          {1:-}   cell.text = text                         {1:-}|
               cell.hl_id = hl_id                        |
               colpos = colpos+1                         |
           end                                           |
@@ -1024,6 +1029,82 @@ describe('extmark decorations', function()
       {1:~                                                 }|
                                                         |
     ]]}
+
+    feed 'jI-- ..........'
+    screen:expect{grid=[[
+      for _,item in ipairs(items) do                    |
+          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
+          if                                            |
+      hl_id_cell ~= nil then         {4:Much}           {4:MUCH}|
+              --^ -- -- -- -- -- -- --{4:Error}- -- hl_i{4:ERROR}|
+      l_id_cell                                         |
+          end                                           |
+          for _ = 1, (count or 1) do                    |
+              local cell = line[colpos]                 |
+          {1:-}   cell.text = text                         {1:-}|
+              cell.hl_id = hl_id                        |
+              colpos = colpos+1                         |
+          end                                           |
+      end                                               |
+                                                        |
+    ]]}
+
+    feed '.'
+    screen:expect{grid=[[
+      for _,item in ipairs(items) do                    |
+          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
+          if                                            |
+      hl_id_cell ~= nil then         {4:Much}           {4:MUCH}|
+              --^ -- -- -- -- -- -- -- -- -- -- -- hl_id |
+      = hl_id_cell                   {4:Error}         {4:ERROR}|
+          end                                           |
+          for _ = 1, (count or 1) do                    |
+              local cell = line[colpos]                 |
+          {1:-}   cell.text = text                         {1:-}|
+              cell.hl_id = hl_id                        |
+              colpos = colpos+1                         |
+          end                                           |
+      end                                               |
+                                                        |
+    ]]}
+
+    command 'set nowrap'
+    screen:expect{grid=[[
+      for _,item in ipairs(items) do                    |
+          local text, hl_id_cell, cou{4:Very} unpack(ite{4:VERY}|
+          if                                            |
+      hl_id_cell ~= nil then         {4:Much}           {4:MUCH}|
+              --^ -- -- -- -- -- -- --{4:Error}- -- -- h{4:ERROR}|
+          end                                           |
+          for _ = 1, (count or 1) do                    |
+              local cell = line[colpos]                 |
+          {1:-}   cell.text = text                         {1:-}|
+              cell.hl_id = hl_id                        |
+              colpos = colpos+1                         |
+          end                                           |
+      end                                               |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+
+    feed('8zl')
+    screen:expect{grid=[[
+      em in ipairs(items) do                            |
+      l text, hl_id_cell, count = unp{4:Very}item)      {4:VERY}|
+                                                        |
+      ll ~= nil then                 {4:Much}           {4:MUCH}|
+      --^ -- -- -- -- -- -- -- -- -- -{4:Error}hl_id = h{4:ERROR}|
+                                                        |
+      _ = 1, (count or 1) do                            |
+      local cell = line[colpos]                         |
+      cell{1:-}text = text                                 {1:-}|
+      cell.hl_id = hl_id                                |
+      colpos = colpos+1                                 |
+                                                        |
+                                                        |
+      {1:~                                                 }|
+                                                        |
+    ]]}
   end)
 
   it('can have virtual text which combines foreground and background groups', function()
-- 
cgit 


From e41b2e34b46a806b0fc59914263f8f4af9ac62f1 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 28 May 2023 11:09:25 +0800
Subject: test(extmarks): add test for virt_text_hide with 'smoothscroll'
 (#23791)

---
 test/functional/ui/decorations_spec.lua | 37 +++++++++++++++++++++++++++++----
 1 file changed, 33 insertions(+), 4 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index b9080cbcf5..0247582cdd 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -827,26 +827,55 @@ describe('extmark decorations', function()
       end  -- ?古古古古?古古                                                            |
                                                                                         |
     ]]}
+  end)
 
-    screen:try_resize(50, 2)
+  it('virt_text_hide hides overlay virtual text when extmark is off-screen', function()
+    screen:try_resize(50, 3)
     command('set nowrap')
-    meths.buf_set_lines(0, 12, 12, true, {'-- ' .. ('…'):rep(57)})
-    feed('G')
-    meths.buf_set_extmark(0, ns, 12, 123, { virt_text={{'!!!!!', 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide=true})
+    meths.buf_set_lines(0, 0, -1, true, {'-- ' .. ('…'):rep(57)})
+    meths.buf_set_extmark(0, ns, 0, 123, { virt_text={{'!!!!!', 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide=true})
     screen:expect{grid=[[
       ^-- …………………………………………………………………………………………………………{4:!!!!!}……|
+      {1:~                                                 }|
                                                         |
     ]]}
     feed('40zl')
     screen:expect{grid=[[
       ^………{4:!!!!!}………………………………                              |
+      {1:~                                                 }|
                                                         |
     ]]}
     feed('10zl')
     screen:expect{grid=[[
+      ^…………………………                                        |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+
+    command('set wrap smoothscroll')
+    screen:expect{grid=[[
+      -- …………………………………………………………………………………………………………{4:!!!!!}……|
       ^…………………………                                        |
                                                         |
     ]]}
+    feed('')
+    screen:expect{grid=[[
+      {1:<<<}………………^…                                        |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+    screen:try_resize(40, 3)
+    screen:expect{grid=[[
+      {1:<<<}{4:!!!!!}……………………………^…                    |
+      {1:~                                       }|
+                                              |
+    ]]}
+    feed('')
+    screen:expect{grid=[[
+      -- …………………………………………………………………………………………………|
+      ………{4:!!!!!}……………………………^…                    |
+                                              |
+    ]]}
   end)
 
   it('can have virtual text of overlay position and styling', function()
-- 
cgit 


From ddd92a70d2aab5247895e89abaaa79c62ba7dbb4 Mon Sep 17 00:00:00 2001
From: Folke Lemaitre 
Date: Sun, 28 May 2023 07:51:28 +0200
Subject: feat(lsp): initial support for dynamic capabilities (#23681)

- `client.dynamic_capabilities` is an object that tracks client register/unregister
- `client.supports_method` will additionally check if a dynamic capability supports the method, taking document filters into account. But only if the client enabled `dynamicRegistration` for the capability
- updated the default client capabilities to include dynamicRegistration for:
    - formatting
    - rangeFormatting
    - hover
    - codeAction
    - hover
    - rename
---
 test/functional/plugin/lsp_spec.lua | 90 +++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index b906ae265f..1a7a656d1d 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -3765,6 +3765,96 @@ describe('LSP', function()
     end)
   end)
 
+  describe('#dynamic vim.lsp._dynamic', function()
+    it('supports dynamic registration', function()
+      local root_dir = helpers.tmpname()
+      os.remove(root_dir)
+      mkdir(root_dir)
+      local tmpfile = root_dir .. '/dynamic.foo'
+      local file = io.open(tmpfile, 'w')
+      file:close()
+
+      exec_lua(create_server_definition)
+      local result = exec_lua([[
+        local root_dir, tmpfile = ...
+
+        local server = _create_server()
+        local client_id = vim.lsp.start({
+          name = 'dynamic-test',
+          cmd = server.cmd,
+          root_dir = root_dir,
+          capabilities = {
+            textDocument = {
+              formatting = {
+                dynamicRegistration = true,
+              },
+              rangeFormatting = {
+                dynamicRegistration = true,
+              },
+            },
+          },
+        })
+
+        local expected_messages = 2 -- initialize, initialized
+
+        vim.lsp.handlers['client/registerCapability'](nil, {
+          registrations = {
+            {
+              id = 'formatting',
+              method = 'textDocument/formatting',
+              registerOptions = {
+                documentSelector = {{
+                  pattern = root_dir .. '/*.foo',
+                }},
+              },
+            },
+          },
+        }, { client_id = client_id })
+
+        vim.lsp.handlers['client/registerCapability'](nil, {
+          registrations = {
+            {
+              id = 'range-formatting',
+              method = 'textDocument/rangeFormatting',
+            },
+          },
+        }, { client_id = client_id })
+
+        vim.lsp.handlers['client/registerCapability'](nil, {
+          registrations = {
+            {
+              id = 'completion',
+              method = 'textDocument/completion',
+            },
+          },
+        }, { client_id = client_id })
+
+        local result = {}
+        local function check(method, fname)
+          local bufnr = fname and vim.fn.bufadd(fname) or nil
+          local client = vim.lsp.get_client_by_id(client_id)
+          result[#result + 1] = {method = method, fname = fname, supported = client.supports_method(method, {bufnr = bufnr})}
+        end
+
+
+        check("textDocument/formatting")
+        check("textDocument/formatting", tmpfile)
+        check("textDocument/rangeFormatting")
+        check("textDocument/rangeFormatting", tmpfile)
+        check("textDocument/completion")
+
+        return result
+      ]], root_dir, tmpfile)
+
+      eq(5, #result)
+      eq({method = 'textDocument/formatting', supported = false}, result[1])
+      eq({method = 'textDocument/formatting', supported = true, fname = tmpfile}, result[2])
+      eq({method = 'textDocument/rangeFormatting', supported = true}, result[3])
+      eq({method = 'textDocument/rangeFormatting', supported = true, fname = tmpfile}, result[4])
+      eq({method = 'textDocument/completion', supported = false}, result[5])
+    end)
+  end)
+
   describe('vim.lsp._watchfiles', function()
     it('sends notifications when files change', function()
       local root_dir = helpers.tmpname()
-- 
cgit 


From f29acc507305a7f4323a3233dc3867dfbe00132b Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 28 May 2023 16:28:10 +0800
Subject: test(extmarks): add tests for #14201 #20004 #20885 (#23794)

---
 test/functional/ui/decorations_spec.lua | 74 +++++++++++++++++++++++++++++++--
 test/functional/ui/highlight_spec.lua   |  8 ++--
 2 files changed, 74 insertions(+), 8 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 0247582cdd..fa4286c3ad 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -8,6 +8,7 @@ local exec_lua = helpers.exec_lua
 local exec = helpers.exec
 local expect_events = helpers.expect_events
 local meths = helpers.meths
+local funcs = helpers.funcs
 local curbufmeths = helpers.curbufmeths
 local command = helpers.command
 local assert_alive = helpers.assert_alive
@@ -651,7 +652,7 @@ describe('extmark decorations', function()
       [16] = {blend = 30, background = Screen.colors.Red1, foreground = Screen.colors.Magenta1};
       [17] = {bold = true, foreground = Screen.colors.Brown, background = Screen.colors.LightGrey};
       [18] = {background = Screen.colors.LightGrey};
-      [19] = {foreground = Screen.colors.Cyan4, background = Screen.colors.LightGrey};
+      [19] = {foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGrey};
       [20] = {foreground = tonumber('0x180606'), background = tonumber('0xf13f3f')};
       [21] = {foreground = Screen.colors.Gray0, background = tonumber('0xf13f3f')};
       [22] = {foreground = tonumber('0xb20000'), background = tonumber('0xf13f3f')};
@@ -662,6 +663,9 @@ describe('extmark decorations', function()
       [27] = {background = Screen.colors.Plum1};
       [28] = {underline = true, foreground = Screen.colors.SlateBlue};
       [29] = {foreground = Screen.colors.SlateBlue, background = Screen.colors.LightGray, underline = true};
+      [30] = {foreground = Screen.colors.DarkCyan, background = Screen.colors.LightGray, underline = true};
+      [31] = {underline = true, foreground = Screen.colors.DarkCyan};
+      [32] = {underline = true};
     }
 
     ns = meths.create_namespace 'test'
@@ -1367,7 +1371,56 @@ describe('extmark decorations', function()
     screen:expect_unchanged(true)
   end)
 
-  it('highlights the beginning of a TAB char correctly', function()
+  it('highlight is combined with syntax and sign linehl #20004', function()
+    screen:try_resize(50, 3)
+    insert([[
+      function Func()
+      end]])
+    feed('gg')
+    command('set ft=lua')
+    command('syntax on')
+    meths.buf_set_extmark(0, ns, 0, 0, { end_col = 3, hl_mode = 'combine', hl_group = 'Visual' })
+    command('hi default MyLine gui=underline')
+    command('sign define CurrentLine linehl=MyLine')
+    funcs.sign_place(6, 'Test', 'CurrentLine', '', { lnum = 1 })
+    screen:expect{grid=[[
+      {30:^fun}{31:ction}{32: Func()                                   }|
+      {6:end}                                               |
+                                                        |
+    ]]}
+  end)
+
+  it('highlight works after TAB with sidescroll #14201', function()
+    screen:try_resize(50, 3)
+    command('set nowrap')
+    meths.buf_set_lines(0, 0, -1, true, {'\tword word word word'})
+    meths.buf_set_extmark(0, ns, 0, 1, { end_col = 3, hl_group = 'ErrorMsg' })
+    screen:expect{grid=[[
+             ^ {4:wo}rd word word word                       |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+    feed('7zl')
+    screen:expect{grid=[[
+       {4:^wo}rd word word word                              |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+    feed('zl')
+    screen:expect{grid=[[
+      {4:^wo}rd word word word                               |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+    feed('zl')
+    screen:expect{grid=[[
+      {4:^o}rd word word word                                |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+  end)
+
+  it('highlights the beginning of a TAB char correctly #23734', function()
     screen:try_resize(50, 3)
     meths.buf_set_lines(0, 0, -1, true, {'this is the\ttab'})
     meths.buf_set_extmark(0, ns, 0, 11, { end_col = 15, hl_group = 'ErrorMsg' })
@@ -1386,7 +1439,20 @@ describe('extmark decorations', function()
     ]]}
   end)
 
-  pending('highlight applies to a full Tab in visual block mode #23734', function()
+  it('highlight applies to a full TAB on line with matches #20885', function()
+    screen:try_resize(50, 3)
+    meths.buf_set_lines(0, 0, -1, true, {'\t-- match1', '        -- match2'})
+    funcs.matchadd('Underlined', 'match')
+    meths.buf_set_extmark(0, ns, 0, 0, { end_row = 1, end_col = 0, hl_group = 'Visual' })
+    meths.buf_set_extmark(0, ns, 1, 0, { end_row = 2, end_col = 0, hl_group = 'Visual' })
+    screen:expect{grid=[[
+      {18:       ^ -- }{29:match}{18:1}                                 |
+      {18:        -- }{29:match}{18:2}                                 |
+                                                        |
+    ]]}
+  end)
+
+  pending('highlight applies to a full TAB in visual block mode', function()
     screen:try_resize(50, 8)
     meths.buf_set_lines(0, 0, -1, true, {'asdf', '\tasdf', '\tasdf', '\tasdf', 'asdf'})
     meths.buf_set_extmark(0, ns, 0, 0, {end_row = 5, end_col = 0, hl_group = 'Underlined'})
@@ -2193,7 +2259,7 @@ describe('decorations: virtual lines', function()
     screen:attach()
     screen:set_default_attr_ids {
       [1] = {bold=true, foreground=Screen.colors.Blue};
-      [2] = {foreground = Screen.colors.Cyan4};
+      [2] = {foreground = Screen.colors.DarkCyan};
       [3] = {background = Screen.colors.Yellow1};
       [4] = {bold = true};
       [5] = {background = Screen.colors.Yellow, foreground = Screen.colors.Blue};
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 9a4be4573c..c68f4cf34c 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -426,7 +426,7 @@ describe('highlight', function()
       ^                         |
       {2:~                        }|
                                |
-    ]],{
+    ]], {
       [1] = {strikethrough = true},
       [2] = {bold = true, foreground = Screen.colors.Blue1},
     })
@@ -515,7 +515,7 @@ describe('highlight', function()
               {1:neovim} tabbed^    |
       {0:~                        }|
       {5:-- INSERT --}             |
-    ]],{
+    ]], {
       [0] = {bold=true, foreground=Screen.colors.Blue},
       [1] = {background = Screen.colors.Yellow, foreground = Screen.colors.Red,
              special = Screen.colors.Red},
@@ -527,7 +527,7 @@ describe('highlight', function()
 
   end)
 
-  it("'diff', syntax and extmark", function()
+  it("'diff', syntax and extmark #23722", function()
     local screen = Screen.new(25,10)
     screen:attach()
     exec([[
@@ -549,7 +549,7 @@ describe('highlight', function()
       {4:~                        }|
       {8:[No Name]                }|
                                |
-    ]],{
+    ]], {
       [0] = {Screen.colors.WebGray, foreground = Screen.colors.DarkBlue},
       [1] = {background = Screen.colors.Grey, foreground = Screen.colors.Blue4},
       [2] = {foreground = Screen.colors.Red, background = Screen.colors.LightBlue},
-- 
cgit 


From 4dd43e31db8fa23b5189e074cff94f1491035aac Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 28 May 2023 17:22:25 +0800
Subject: fix(extmarks): don't show virt lines for end mark (#23792)

---
 test/functional/ui/decorations_spec.lua | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index fa4286c3ad..4960a1d3ed 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -2978,6 +2978,30 @@ if (h->n_buckets < new_n_buckets) { // expand
     ]]}
   end)
 
+  it('does not show twice if end_row or end_col is specified #18622', function()
+    insert([[
+      aaa
+      bbb
+      ccc
+      ddd]])
+    meths.buf_set_extmark(0, ns, 0, 0, {end_row = 2, virt_lines = {{{'VIRT LINE 1', 'NonText'}}}})
+    meths.buf_set_extmark(0, ns, 3, 0, {end_col = 2, virt_lines = {{{'VIRT LINE 2', 'NonText'}}}})
+    screen:expect{grid=[[
+      aaa                                               |
+      {1:VIRT LINE 1}                                       |
+      bbb                                               |
+      ccc                                               |
+      dd^d                                               |
+      {1:VIRT LINE 2}                                       |
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+      {1:~                                                 }|
+                                                        |
+    ]]}
+  end)
+
 end)
 
 describe('decorations: signs', function()
-- 
cgit 


From 9c41a81dec15ced3f66723b8aa87c2438a099128 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 28 May 2023 17:29:44 +0800
Subject: fix(extmarks): fix virt_text_hide off-by-one hiding (#23795)

---
 test/functional/ui/decorations_spec.lua | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 4960a1d3ed..975da35355 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -837,9 +837,10 @@ describe('extmark decorations', function()
     screen:try_resize(50, 3)
     command('set nowrap')
     meths.buf_set_lines(0, 0, -1, true, {'-- ' .. ('…'):rep(57)})
+    meths.buf_set_extmark(0, ns, 0, 0, { virt_text={{'?????', 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide=true})
     meths.buf_set_extmark(0, ns, 0, 123, { virt_text={{'!!!!!', 'ErrorMsg'}}, virt_text_pos='overlay', virt_text_hide=true})
     screen:expect{grid=[[
-      ^-- …………………………………………………………………………………………………………{4:!!!!!}……|
+      {4:^?????}……………………………………………………………………………………………………{4:!!!!!}……|
       {1:~                                                 }|
                                                         |
     ]]}
@@ -849,7 +850,13 @@ describe('extmark decorations', function()
       {1:~                                                 }|
                                                         |
     ]]}
-    feed('10zl')
+    feed('3zl')
+    screen:expect{grid=[[
+      {4:^!!!!!}………………………………                                 |
+      {1:~                                                 }|
+                                                        |
+    ]]}
+    feed('7zl')
     screen:expect{grid=[[
       ^…………………………                                        |
       {1:~                                                 }|
@@ -858,7 +865,7 @@ describe('extmark decorations', function()
 
     command('set wrap smoothscroll')
     screen:expect{grid=[[
-      -- …………………………………………………………………………………………………………{4:!!!!!}……|
+      {4:?????}……………………………………………………………………………………………………{4:!!!!!}……|
       ^…………………………                                        |
                                                         |
     ]]}
@@ -876,7 +883,7 @@ describe('extmark decorations', function()
     ]]}
     feed('')
     screen:expect{grid=[[
-      -- …………………………………………………………………………………………………|
+      {4:?????}……………………………………………………………………………………………|
       ………{4:!!!!!}……………………………^…                    |
                                               |
     ]]}
-- 
cgit 


From 5a3752889c5b7e18d1041eb873ca2fa9ceb814bd Mon Sep 17 00:00:00 2001
From: Ghjuvan Lacambre 
Date: Sun, 28 May 2023 16:04:54 +0200
Subject: fix(NVIM_APPNAME): show error message if $NVIM_APPNAME is invalid

Closes https://github.com/neovim/neovim/issues/23056.
---
 test/functional/options/defaults_spec.lua | 5 +++++
 1 file changed, 5 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index 3690b7e97c..60edf219d9 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -14,6 +14,7 @@ local ok = helpers.ok
 local funcs = helpers.funcs
 local insert = helpers.insert
 local neq = helpers.neq
+local nvim_prog = helpers.nvim_prog
 local mkdir = helpers.mkdir
 local rmdir = helpers.rmdir
 local alter_slashes = helpers.alter_slashes
@@ -603,6 +604,10 @@ describe('stdpath()', function()
       eq(appname, funcs.fnamemodify(funcs.stdpath('data_dirs')[1], ':t'))
     end
     assert_alive()  -- Check for crash. #8393
+
+    --  Check that nvim rejects invalid APPNAMEs
+    local child = funcs.jobstart({ nvim_prog }, {env={NVIM_APPNAME='a/b\\c'}})
+    eq(1, funcs.jobwait({child}, 3000)[1])
   end)
 
   context('returns a String', function()
-- 
cgit 


From 9dd48f7832f4656af4a2579368641268bb6399e7 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Mon, 29 May 2023 08:44:52 +0800
Subject: fix(substitute): properly check if preview is needed (#23809)

---
 test/functional/ui/inccommand_user_spec.lua | 34 +++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua
index 6329ece40a..9cc6e095c5 100644
--- a/test/functional/ui/inccommand_user_spec.lua
+++ b/test/functional/ui/inccommand_user_spec.lua
@@ -401,6 +401,40 @@ describe("'inccommand' for user commands", function()
     feed('e')
     assert_alive()
   end)
+
+  it('no crash when adding highlight after :substitute #21495', function()
+    command('set inccommand=nosplit')
+    exec_lua([[
+      vim.api.nvim_create_user_command("Crash", function() end, {
+        preview = function(_, preview_ns, _)
+          vim.cmd("%s/text/cats/g")
+          vim.api.nvim_buf_add_highlight(0, preview_ns, "Search", 0, 0, -1)
+          return 1
+        end,
+      })
+    ]])
+    feed(':C')
+    screen:expect([[
+      {1:  cats on line 1}                        |
+        more cats on line 2                   |
+        oh no, even more cats                 |
+        will the cats ever stop               |
+        oh well                               |
+        did the cats stop                     |
+        why won't it stop                     |
+        make the cats stop                    |
+                                              |
+      {2:~                                       }|
+      {2:~                                       }|
+      {2:~                                       }|
+      {2:~                                       }|
+      {2:~                                       }|
+      {2:~                                       }|
+      {2:~                                       }|
+      :C^                                      |
+    ]])
+    assert_alive()
+  end)
 end)
 
 describe("'inccommand' with multiple buffers", function()
-- 
cgit 


From 55f6a1cab031ecc28c5a7f2558a0cac9df2145e1 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Tue, 30 May 2023 07:18:12 +0800
Subject: vim-patch:9.0.1588: Incsearch not triggered when pasting clipboard
 register (#23817)

Problem:    Incsearch not triggered when pasting clipboard register on the
            command line.
Solution:   Also set "literally" when using a clipboard register. (Ken Takata,
            closes vim/vim#12460)

https://github.com/vim/vim/commit/9cf6ab133227ac7e9169941752293bb7178d8e38

Co-authored-by: K.Takata 
---
 test/functional/autocmd/textyankpost_spec.lua    |  2 +-
 test/functional/provider/clipboard_spec.lua      |  2 +-
 test/functional/provider/provider_spec.lua       |  2 +-
 test/functional/ui/searchhl_spec.lua             | 30 ++++++++++++++++++++++++
 test/functional/vimscript/api_functions_spec.lua |  2 +-
 5 files changed, 34 insertions(+), 4 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/autocmd/textyankpost_spec.lua b/test/functional/autocmd/textyankpost_spec.lua
index 3898d59e58..1640916ad8 100644
--- a/test/functional/autocmd/textyankpost_spec.lua
+++ b/test/functional/autocmd/textyankpost_spec.lua
@@ -8,7 +8,7 @@ describe('TextYankPost', function()
     clear()
 
     -- emulate the clipboard so system clipboard isn't affected
-    command('let &rtp = "test/functional/fixtures,".&rtp')
+    command('set rtp^=test/functional/fixtures')
 
     command('let g:count = 0')
     command('autocmd TextYankPost * let g:event = copy(v:event)')
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index 2c5185a974..c8f1518283 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -301,7 +301,7 @@ end)
 
 describe('clipboard (with fake clipboard.vim)', function()
   local function reset(...)
-    clear('--cmd', 'let &rtp = "test/functional/fixtures,".&rtp', ...)
+    clear('--cmd', 'set rtp^=test/functional/fixtures', ...)
   end
 
   before_each(function()
diff --git a/test/functional/provider/provider_spec.lua b/test/functional/provider/provider_spec.lua
index 3895b8613f..b1c326d04c 100644
--- a/test/functional/provider/provider_spec.lua
+++ b/test/functional/provider/provider_spec.lua
@@ -7,7 +7,7 @@ local pcall_err = helpers.pcall_err
 
 describe('providers', function()
   before_each(function()
-    clear('--cmd', 'let &rtp = "test/functional/fixtures,".&rtp')
+    clear('--cmd', 'set rtp^=test/functional/fixtures')
   end)
 
   it('with #Call(), missing g:loaded_xx_provider', function()
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 3c8dceb8cb..1e42689200 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -512,6 +512,36 @@ describe('search highlighting', function()
       {1:~                   }│{1:~                  }|
       /file^                                   |
     ]])
+    feed('')
+
+    command('set rtp^=test/functional/fixtures')
+    -- incsearch works after c_CTRL-R inserts clipboard register
+
+    command('let @* = "first"')
+    feed('/*')
+    screen:expect([[
+      the {3:first} line      │the {2:first} line     |
+      in a little file    │in a little file   |
+      {1:~                   }│{1:~                  }|
+      {1:~                   }│{1:~                  }|
+      {1:~                   }│{1:~                  }|
+      {1:~                   }│{1:~                  }|
+      /first^                                  |
+    ]])
+    feed('')
+
+    command('let @+ = "little"')
+    feed('/+')
+    screen:expect([[
+      the first line      │the first line     |
+      in a {3:little} file    │in a {2:little} file   |
+      {1:~                   }│{1:~                  }|
+      {1:~                   }│{1:~                  }|
+      {1:~                   }│{1:~                  }|
+      {1:~                   }│{1:~                  }|
+      /little^                                 |
+    ]])
+    feed('')
   end)
 
   it('works with incsearch and offset', function()
diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua
index 3404b06a55..14678a966d 100644
--- a/test/functional/vimscript/api_functions_spec.lua
+++ b/test/functional/vimscript/api_functions_spec.lua
@@ -133,7 +133,7 @@ describe('eval-API', function()
     })
 
     command("set ft=vim")
-    command("let &rtp='build/runtime/,'.&rtp")
+    command("set rtp^=build/runtime/")
     command("syntax on")
     insert([[
       call bufnr('%')
-- 
cgit 


From 70da793c5eda9f3e533a137ac0c0e31db1df0324 Mon Sep 17 00:00:00 2001
From: luukvbaal 
Date: Tue, 30 May 2023 14:56:12 +0200
Subject: fix(statusline): corrupted screen with minwid sign item in
 'statuscolumn' (#23823)

---
 test/functional/ui/statuscolumn_spec.lua | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index c218bd8fd6..6624fb008d 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -424,6 +424,21 @@ describe('statuscolumn', function()
     ]])
   end)
 
+  it('does not corrupt the screen with minwid sign item', function()
+    screen:try_resize(screen._width, 3)
+    screen:set_default_attr_ids({
+      [0] = {foreground = Screen.colors.Brown},
+      [1] = {foreground = Screen.colors.Blue4, background = Screen.colors.Gray},
+    })
+    command([[set stc=%6s\ %l]])
+    exec_lua('vim.api.nvim_buf_set_extmark(0, ns, 7, 0, {sign_text = "𒀀"})')
+    screen:expect([[
+      {0:    𒀀  8}^aaaaa                                        |
+      {0:    }{1:  }{0: 9}aaaaa                                        |
+                                                           |
+    ]])
+  end)
+
   for _, model in ipairs(mousemodels) do
     it("works with 'statuscolumn' clicks with mousemodel=" .. model, function()
       command('set mousemodel=' .. model)
-- 
cgit 


From 58618d208acd3827c4e86668529edb619bb9b8dd Mon Sep 17 00:00:00 2001
From: jdrouhard 
Date: Tue, 30 May 2023 13:56:29 -0500
Subject: feat(lsp)!: promote LspRequest to a full autocmd and enrich with
 additional data (#23694)

BREAKING CHANGE: LspRequest is no longer a User autocmd but is now a
first class citizen.

LspRequest as a User autocmd had limited functionality. Namely, the only
thing you could do was use the notification to do a lookup on all the
clients' requests tables to figure out what changed.

Promoting the autocmd to a full autocmd lets us set the buffer the
request was initiated on (so people can set buffer-local autocmds for
listening to these events).

Additionally, when used from Lua, we can pass additional metadata about
the request along with the notification, including the client ID, the
request ID, and the actual request object stored on the client's
requests table. Users can now listen for these events and act on them
proactively instead of polling all of the requests tables and looking
for changes.
---
 test/functional/plugin/lsp_spec.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'test/functional')

diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 1a7a656d1d..e0ce62c0db 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -948,7 +948,7 @@ describe('LSP', function()
         test_name = "check_tracked_requests_cleared";
         on_init = function(_client)
           command('let g:requests = 0')
-          command('autocmd User LspRequest let g:requests+=1')
+          command('autocmd LspRequest * let g:requests+=1')
           client = _client
           client.request("slow_request")
           eq(1, eval('g:requests'))
-- 
cgit 


From 7e3ff8afa435607c703706a99cf9006893bdb399 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Wed, 31 May 2023 06:50:37 +0800
Subject: test(extmarks): folding inline virt_text on empty line (#23847)

---
 test/functional/ui/decorations_spec.lua | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 975da35355..2d0223dec7 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -2227,34 +2227,55 @@ bbbbbbb]])
   end)
 
   it('does not crash at column 0 when folded in a wide window', function()
-    screen:try_resize(82, 4)
+    screen:try_resize(82, 5)
     command('hi! CursorLine guibg=NONE guifg=Red gui=NONE')
     command('set cursorline')
     insert([[
       aaaaa
       bbbbb
+
       ccccc]])
     meths.buf_set_extmark(0, ns, 0, 0, { virt_text = {{'foo'}}, virt_text_pos = 'inline' })
+    meths.buf_set_extmark(0, ns, 2, 0, { virt_text = {{'bar'}}, virt_text_pos = 'inline' })
     screen:expect{grid=[[
       fooaaaaa                                                                          |
       bbbbb                                                                             |
+      bar                                                                               |
       {16:cccc^c                                                                             }|
                                                                                         |
     ]]}
     command('1,2fold')
     screen:expect{grid=[[
       {17:+--  2 lines: aaaaa·······························································}|
+      bar                                                                               |
       {16:cccc^c                                                                             }|
       {1:~                                                                                 }|
                                                                                         |
     ]]}
-    feed('k')
+    feed('2k')
     screen:expect{grid=[[
       {18:^+--  2 lines: aaaaa·······························································}|
+      bar                                                                               |
       ccccc                                                                             |
       {1:~                                                                                 }|
                                                                                         |
     ]]}
+    command('3,4fold')
+    screen:expect{grid=[[
+      {18:^+--  2 lines: aaaaa·······························································}|
+      {17:+--  2 lines: ccccc·······························································}|
+      {1:~                                                                                 }|
+      {1:~                                                                                 }|
+                                                                                        |
+    ]]}
+    feed('j')
+    screen:expect{grid=[[
+      {17:+--  2 lines: aaaaa·······························································}|
+      {18:^+--  2 lines: ccccc·······························································}|
+      {1:~                                                                                 }|
+      {1:~                                                                                 }|
+                                                                                        |
+    ]]}
   end)
 end)
 
-- 
cgit 


From 2bdef6dd2a7572602aeb2efec76812769bcee246 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Thu, 1 Jun 2023 16:20:31 +0800
Subject: fix(column): don't overflow sign column with extmark signs (#23854)

---
 test/functional/ui/decorations_spec.lua | 37 +++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 2d0223dec7..54441984a3 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -3342,8 +3342,8 @@ l5
     insert(example_test3)
     feed 'gg'
 
-    helpers.command('sign define Oldsign text=O3')
-    helpers.command([[exe 'sign place 42 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
+    command('sign define Oldsign text=O3')
+    command([[exe 'sign place 42 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
 
     meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S4', priority=100})
     meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S2', priority=5})
@@ -3366,6 +3366,39 @@ l5
     ]]}
   end)
 
+  it('does not overflow with many old signs #23852', function()
+    screen:try_resize(20, 3)
+
+    command('set signcolumn:auto:9')
+    command('sign define Oldsign text=O3')
+    command([[exe 'sign place 01 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
+    command([[exe 'sign place 02 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
+    command([[exe 'sign place 03 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
+    command([[exe 'sign place 04 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
+    command([[exe 'sign place 05 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
+    command([[exe 'sign place 06 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
+    command([[exe 'sign place 07 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
+    command([[exe 'sign place 08 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
+    command([[exe 'sign place 09 line=1 name=Oldsign priority=10 buffer=' . bufnr('')]])
+    screen:expect{grid=[[
+      O3O3O3O3O3O3O3O3O3^  |
+      {2:~                   }|
+                          |
+    ]]}
+
+    meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1', priority=1})
+    screen:expect_unchanged()
+
+    meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S5', priority=200})
+    screen:expect{grid=[[
+      O3O3O3O3O3O3O3O3S5^  |
+      {2:~                   }|
+                          |
+    ]]}
+
+    assert_alive()
+  end)
+
   it('does not set signcolumn for signs without text', function()
     screen:try_resize(20, 3)
     meths.set_option_value('signcolumn', 'auto', {})
-- 
cgit 


From 68e7a6a6dccff344f880e85e4e9f87104904c8a8 Mon Sep 17 00:00:00 2001
From: Folke Lemaitre 
Date: Thu, 1 Jun 2023 12:23:42 +0200
Subject: test: added tests for set_height with winminheight=0 and a winbar

---
 test/functional/api/window_spec.lua | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index a6d1807961..55d4ff6b2e 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -285,6 +285,22 @@ describe('API/win', function()
       eq(2, window('get_height', nvim('list_wins')[2]))
     end)
 
+    it('correctly handles height=1', function()
+      nvim('command', 'split')
+      nvim('set_current_win', nvim('list_wins')[1])
+      window('set_height', nvim('list_wins')[2], 1)
+      eq(1, window('get_height', nvim('list_wins')[2]))
+    end)
+
+    it('correctly handles height=1 with a winbar', function()
+      nvim('command', 'set winbar=foobar')
+      nvim('command', 'set winminheight=0')
+      nvim('command', 'split')
+      nvim('set_current_win', nvim('list_wins')[1])
+      window('set_height', nvim('list_wins')[2], 1)
+      eq(1, window('get_height', nvim('list_wins')[2]))
+    end)
+
     it('do not cause ml_get errors with foldmethod=expr #19989', function()
       insert([[
         aaaaa
-- 
cgit 


From ac1ad9651e88eef1eea92fe5bd1497344c83dc53 Mon Sep 17 00:00:00 2001
From: Luuk van Baal 
Date: Wed, 31 May 2023 21:13:58 +0200
Subject: vim-patch:9.0.1595: line pointer becomes invalid when using spell
 checking

Problem:    Line pointer becomes invalid when using spell checking.
Solution:   Call ml_get() at the right places. (Luuk van Baal, closes vim/vim#12456)

https://github.com/vim/vim/commit/e84c773d42e8b6ef0f8ae9b6c7312e0fd47909af
---
 test/functional/ui/spell_spec.lua | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua
index 630d0d0948..d18e19e5b2 100644
--- a/test/functional/ui/spell_spec.lua
+++ b/test/functional/ui/spell_spec.lua
@@ -178,6 +178,30 @@ describe("'spell'", function()
       {0:~                                                                               }|
                                                                                       |
     ]])
+    -- Adding an empty line does not remove Cap in "mod_bot" area
+    feed('zbO')
+    screen:expect([[
+         This line has a {1:sepll} error. {2:and} missing caps and trailing spaces.           |
+      ^                                                                                |
+      {2:another} missing cap here                                                        |
+      {10:+--  2 lines: Not·······························································}|
+      {2:and} here.                                                                       |
+      {0:~                                                                               }|
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
+    -- Multiple empty lines does not remove Cap in the line after
+    feed('O')
+    screen:expect([[
+         This line has a {1:sepll} error. {2:and} missing caps and trailing spaces.           |
+      ^                                                                                |
+                                                                                      |
+      {2:another} missing cap here                                                        |
+      {10:+--  2 lines: Not·······························································}|
+      {2:and} here.                                                                       |
+      {0:~                                                                               }|
+                                                                                      |
+    ]])
   end)
 
   -- oldtest: Test_spell_compatible()
-- 
cgit 


From fb54e6980ea6fec218a11f118e97ef65f250395a Mon Sep 17 00:00:00 2001
From: Gregory Anders 
Date: Thu, 1 Jun 2023 11:15:33 -0500
Subject: feat(lsp): set client offset_encoding if server supports
 positionEncoding

If the server sends the positionEncoding capability in its
initialization response, automatically set the client's offset_encoding
to use the value provided.
---
 test/functional/plugin/lsp_spec.lua | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index e0ce62c0db..dac49345d0 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -218,6 +218,34 @@ describe('LSP', function()
       })
     end)
 
+    it("should set the client's offset_encoding when positionEncoding capability is supported", function()
+      clear()
+      exec_lua(create_server_definition)
+      local result = exec_lua([[
+        local server = _create_server({
+          capabilities = {
+            positionEncoding = "utf-8"
+          },
+        })
+
+        local client_id = vim.lsp.start({
+          name = 'dummy',
+          cmd = server.cmd,
+        })
+
+        if not client_id then
+          return 'vim.lsp.start did not return client_id'
+        end
+
+        local client = vim.lsp.get_client_by_id(client_id)
+        if not client then
+          return 'No client found with id ' .. client_id
+        end
+        return client.offset_encoding
+      ]])
+      eq('utf-8', result)
+    end)
+
     it('should succeed with manual shutdown', function()
       if is_ci() then
         pending('hangs the build on CI #14028, re-enable with freeze timeout #14204')
-- 
cgit 


From 9f3c4c152664b21593636a59ce21e74ab7000b20 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Fri, 2 Jun 2023 08:48:49 +0800
Subject: vim-patch:9.0.1597: cursor ends up below the window after a put
 (#23873)

Problem:    Cursor ends up below the window after a put.
Solution:   Mark w_crow and w_botline invalid when changing the cursor line.
            (closes vim/vim#12465)

https://github.com/vim/vim/commit/8509014adda188ee8bdf6a2e123fbf15a91b29d2

Co-authored-by: Bram Moolenaar 
---
 test/functional/legacy/put_spec.lua | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

(limited to 'test/functional')

diff --git a/test/functional/legacy/put_spec.lua b/test/functional/legacy/put_spec.lua
index e83fde774a..4a42a1c8a3 100644
--- a/test/functional/legacy/put_spec.lua
+++ b/test/functional/legacy/put_spec.lua
@@ -70,4 +70,29 @@ describe('put', function()
                                                                                       |
     ]])
   end)
+
+  -- oldtest: Test_put_in_last_displayed_line()
+  it('in last displayed line', function()
+    local screen = Screen.new(75, 10)
+    screen:attach()
+    source([[
+      autocmd CursorMoved * eval line('w$')
+      let @a = 'x'->repeat(&columns * 2 - 2)
+      eval range(&lines)->setline(1)
+      call feedkeys('G"ap')
+    ]])
+
+    screen:expect([[
+      2                                                                          |
+      3                                                                          |
+      4                                                                          |
+      5                                                                          |
+      6                                                                          |
+      7                                                                          |
+      8                                                                          |
+      9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
+      xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^x |
+                                                                                 |
+    ]])
+  end)
 end)
-- 
cgit 


From 4b60267f82ef1947f8a583c02eaf502cf1db69ca Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Fri, 2 Jun 2023 21:00:55 +0800
Subject: feat(:source): source current ft=lua buffer as Lua code (#23802)

---
 test/functional/ex_cmds/source_spec.lua | 108 +++++++++++++++++---------------
 1 file changed, 59 insertions(+), 49 deletions(-)

(limited to 'test/functional')

diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
index 02f5bff021..24987354a4 100644
--- a/test/functional/ex_cmds/source_spec.lua
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -7,6 +7,7 @@ local meths = helpers.meths
 local feed = helpers.feed
 local feed_command = helpers.feed_command
 local write_file = helpers.write_file
+local tmpname = helpers.tmpname
 local exec = helpers.exec
 local exc_exec = helpers.exc_exec
 local exec_lua = helpers.exec_lua
@@ -179,56 +180,65 @@ describe(':source', function()
     os.remove(test_file)
   end)
 
-  it('can source selected region in lua file', function()
-    local test_file = 'test.lua'
-
-    write_file (test_file, [[
-      vim.g.b = 5
-      vim.g.b = 6
-      vim.g.b = 7
-      a = [=[
-       "\ a
-        \ b]=]
-    ]])
-
-    command('edit '..test_file)
-
-    feed('ggjV')
-    feed_command(':source')
-    eq(6, eval('g:b'))
-
-    feed('GVkk')
-    feed_command(':source')
-    eq('   "\\ a\n    \\ b', exec_lua('return _G.a'))
-
-    os.remove(test_file)
-  end)
-
-  it('can source current lua buffer without argument', function()
-    local test_file = 'test.lua'
-
-    write_file(test_file, [[
-      vim.g.c = 10
-      vim.g.c = 11
-      vim.g.c = 12
-      a = [=[
-        \ 1
-       "\ 2]=]
-      vim.g.sfile_value = vim.fn.expand('')
-      vim.g.stack_value = vim.fn.expand('')
-      vim.g.script_value = vim.fn.expand('