diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-25 19:15:05 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-25 19:27:38 +0000 |
commit | c5d770d311841ea5230426cc4c868e8db27300a8 (patch) | |
tree | dd21f70127b4b8b5f109baefc8ecc5016f507c91 /test | |
parent | 9be89f131f87608f224f0ee06d199fcd09d32176 (diff) | |
parent | 081beb3659bd6d8efc3e977a160b1e72becbd8a2 (diff) | |
download | rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.tar.gz rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.tar.bz2 rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.zip |
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'test')
214 files changed, 9565 insertions, 2716 deletions
diff --git a/test/cmakeconfig/paths.lua.in b/test/cmakeconfig/paths.lua.in index ce0eb870e0..78c66a4eac 100644 --- a/test/cmakeconfig/paths.lua.in +++ b/test/cmakeconfig/paths.lua.in @@ -5,6 +5,7 @@ for p in ("${TEST_INCLUDE_DIRS}" .. ";"):gmatch("[^;]+") do table.insert(M.include_paths, p) end +M.vterm_test_file = "${VTERM_TEST_FILE}" M.test_build_dir = "${CMAKE_BINARY_DIR}" M.test_source_path = "${CMAKE_SOURCE_DIR}" M.test_lua_prg = "${LUA_PRG}" diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 3775c8c7b7..0cc875bb51 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -125,7 +125,6 @@ describe('api/buf', function() it('cursor position is maintained consistently with viewport', function() local screen = Screen.new(20, 12) - screen:attach() local lines = { 'line1', 'line2', 'line3', 'line4', 'line5', 'line6' } local buf = api.nvim_get_current_buf() @@ -211,7 +210,6 @@ describe('api/buf', function() local screen before_each(function() screen = Screen.new(20, 12) - screen:attach() api.nvim_buf_set_lines( 0, 0, @@ -735,7 +733,6 @@ describe('api/buf', function() it("set_lines of invisible buffer doesn't move cursor in current window", function() local screen = Screen.new(20, 5) - screen:attach() insert([[ Who would win? @@ -1689,7 +1686,6 @@ describe('api/buf', function() it('correctly marks changed region for redraw #13890', function() local screen = Screen.new(20, 5) - screen:attach() insert([[ AAA @@ -1742,7 +1738,6 @@ describe('api/buf', function() local screen before_each(function() screen = Screen.new(20, 12) - screen:attach() api.nvim_buf_set_lines( 0, 0, diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 52d8fd5097..43be0c0e43 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -455,7 +455,6 @@ describe('API/extmarks', function() it('join works when no marks are present', function() screen = Screen.new(15, 10) - screen:attach() feed('a<cr>1<esc>') feed('kJ') -- This shouldn't seg fault @@ -508,7 +507,6 @@ describe('API/extmarks', function() it('marks move with char inserts', function() -- insertchar in edit.c (the ins_str branch) screen = Screen.new(15, 10) - screen:attach() set_extmark(ns, marks[1], 0, 3) feed('0') insert('abc') @@ -759,7 +757,7 @@ describe('API/extmarks', function() { Ïf (!nlua_is_deferred_safe(lstate)) { // strictly not allowed - Яetörn luaL_error(lstate, e_luv_api_disabled, "rpcrequest"); + Яetörn luaL_error(lstate, e_fast_api_disabled, "rpcrequest"); } return nlua_rpc(lstate, true); }]]) @@ -1726,7 +1724,6 @@ describe('API/extmarks', function() it('invalidated marks are deleted', function() screen = Screen.new(40, 6) - screen:attach() feed('dd6iaaa bbb ccc<CR><ESC>gg') api.nvim_set_option_value('signcolumn', 'auto:2', {}) set_extmark(ns, 1, 0, 0, { invalidate = true, sign_text = 'S1', end_row = 1 }) @@ -1811,7 +1808,6 @@ describe('API/extmarks', function() it('respects priority', function() screen = Screen.new(15, 10) - screen:attach() set_extmark(ns, marks[1], 0, 0, { hl_group = 'Comment', @@ -1983,7 +1979,6 @@ describe('API/win_extmark', function() it('sends and only sends ui-watched marks to ui', function() screen = Screen.new(20, 4) - screen:attach() -- should send this set_extmark(ns, marks[1], 1, 0, { ui_watched = true }) -- should not send this @@ -2006,7 +2001,6 @@ describe('API/win_extmark', function() it('sends multiple ui-watched marks to ui', function() screen = Screen.new(20, 4) - screen:attach() feed('15A!<Esc>') -- should send all of these set_extmark(ns, marks[1], 1, 0, { ui_watched = true, virt_text_pos = 'overlay' }) @@ -2052,7 +2046,6 @@ describe('API/win_extmark', function() it('updates ui-watched marks', function() screen = Screen.new(20, 4) - screen:attach() -- should send this set_extmark(ns, marks[1], 1, 0, { ui_watched = true }) -- should not send this @@ -2096,8 +2089,7 @@ describe('API/win_extmark', function() end) it('sends ui-watched to splits', function() - screen = Screen.new(20, 8) - screen:attach({ ext_multigrid = true }) + screen = Screen.new(20, 8, { ext_multigrid = true }) -- should send this set_extmark(ns, marks[1], 1, 0, { ui_watched = true }) -- should not send this diff --git a/test/functional/api/menu_spec.lua b/test/functional/api/menu_spec.lua index 76eef164c9..7556a5bc3f 100644 --- a/test/functional/api/menu_spec.lua +++ b/test/functional/api/menu_spec.lua @@ -11,7 +11,6 @@ describe('update_menu notification', function() before_each(function() clear() screen = Screen.new() - screen:attach() end) local function expect_sent(expected) diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua index 2145db7f8a..5976610af1 100644 --- a/test/functional/api/ui_spec.lua +++ b/test/functional/api/ui_spec.lua @@ -18,8 +18,7 @@ describe('nvim_ui_attach()', function() end) it('handles very large width/height #2180', function() - local screen = Screen.new(999, 999) - screen:attach() + local _ = Screen.new(999, 999) eq(999, eval('&lines')) eq(999, eval('&columns')) end) @@ -64,8 +63,7 @@ describe('nvim_ui_attach()', function() eq('UI not attached to channel: 1', pcall_err(request, 'nvim_ui_set_option', 'rgb', true)) eq('UI not attached to channel: 1', pcall_err(request, 'nvim_ui_detach')) - local screen = Screen.new() - screen:attach({ rgb = false }) + local _ = Screen.new(nil, nil, { rgb = false }) eq( 'UI already attached to channel: 1', pcall_err(request, 'nvim_ui_attach', 40, 10, { rgb = false }) @@ -82,7 +80,6 @@ it('autocmds UIEnter/UILeave', function() autocmd VimEnter * call add(g:evs, "VimEnter") ]]) local screen = Screen.new() - screen:attach() eq({ chan = 1 }, eval('g:uienter_ev')) screen:detach() eq({ chan = 1 }, eval('g:uileave_ev')) @@ -96,7 +93,6 @@ end) it('autocmds VimSuspend/VimResume #22041', function() clear() local screen = Screen.new() - screen:attach() exec([[ let g:ev = [] autocmd VimResume * :call add(g:ev, 'r') diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index af4d4854f5..3f1e378bc1 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -366,7 +366,6 @@ describe('API', function() it('displays messages when opts.output=false', function() local screen = Screen.new(40, 8) - screen:attach() api.nvim_exec2("echo 'hello'", { output = false }) screen:expect { grid = [[ @@ -379,7 +378,6 @@ describe('API', function() it("doesn't display messages when output=true", function() local screen = Screen.new(40, 6) - screen:attach() api.nvim_exec2("echo 'hello'", { output = true }) screen:expect { grid = [[ @@ -1278,7 +1276,6 @@ describe('API', function() end) it('pasting with empty last chunk in Cmdline mode', function() local screen = Screen.new(20, 4) - screen:attach() feed(':') api.nvim_paste('Foo', true, 1) api.nvim_paste('', true, 3) @@ -1290,7 +1287,6 @@ describe('API', function() end) it('pasting text with control characters in Cmdline mode', function() local screen = Screen.new(20, 4) - screen:attach() feed(':') api.nvim_paste('normal! \023\022\006\027', true, -1) screen:expect([[ @@ -1675,7 +1671,6 @@ describe('API', function() eq({ 1, 5 }, api.nvim_win_get_cursor(0)) local screen = Screen.new(60, 3) - screen:attach() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ @@ -2130,7 +2125,6 @@ describe('API', function() it('does not complete ("interrupt") `d` #3732', function() local screen = Screen.new(20, 4) - screen:attach() command('set listchars=eol:$') command('set list') feed('ia<cr>b<cr>c<cr><Esc>kkk') @@ -2391,7 +2385,6 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) - screen:attach() end) it('prints long messages correctly #20534', function() @@ -2461,7 +2454,6 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) - screen:attach() end) it('can show one line', function() @@ -2543,7 +2535,6 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) - screen:attach() end) it('shows only one return prompt after all lines are shown', function() @@ -3100,8 +3091,7 @@ describe('API', function() eq({}, api.nvim_list_uis()) end) it('returns attached UIs', function() - local screen = Screen.new(20, 4) - screen:attach({ override = true }) + local screen = Screen.new(20, 4, { override = true }) local expected = { { chan = 1, @@ -3129,8 +3119,7 @@ describe('API', function() eq(expected, api.nvim_list_uis()) screen:detach() - screen = Screen.new(44, 99) - screen:attach({ rgb = false }) + screen = Screen.new(44, 99, { rgb = false }) -- luacheck: ignore expected[1].rgb = false expected[1].override = false expected[1].width = 44 @@ -3165,7 +3154,6 @@ describe('API', function() eq(1, api.nvim_get_current_buf()) local screen = Screen.new(20, 4) - screen:attach() api.nvim_buf_set_lines(2, 0, -1, true, { 'some text' }) api.nvim_set_current_buf(2) screen:expect( @@ -3229,7 +3217,6 @@ describe('API', function() eq(1, api.nvim_get_current_buf()) local screen = Screen.new(20, 4) - screen:attach() -- -- Editing a scratch-buffer does NOT change its properties. @@ -3591,11 +3578,19 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) - screen:attach() command('highlight Statement gui=bold guifg=Brown') command('highlight Special guifg=SlateBlue') end) + it('validation', function() + eq("Invalid 'chunk': expected Array, got String", pcall_err(api.nvim_echo, { 'msg' }, 1, {})) + eq( + 'Invalid chunk: expected Array with 1 or 2 Strings', + pcall_err(api.nvim_echo, { { '', '', '' } }, 1, {}) + ) + eq('Invalid hl_group: text highlight', pcall_err(api.nvim_echo, { { '', false } }, 1, {})) + end) + it('should clear cmdline message before echo', function() feed(':call nvim_echo([["msg"]], v:false, {})<CR>') screen:expect { @@ -3620,6 +3615,18 @@ describe('API', function() msg_a{15:msg_b}{16:msg_c} | ]], } + async_meths.nvim_echo({ + { 'msg_d' }, + { 'msg_e', api.nvim_get_hl_id_by_name('Statement') }, + { 'msg_f', api.nvim_get_hl_id_by_name('Special') }, + }, true, {}) + screen:expect { + grid = [[ + ^ | + {1:~ }|*6 + msg_d{15:msg_e}{16:msg_f} | + ]], + } end) it('can show highlighted multiline', function() @@ -3654,7 +3661,6 @@ describe('API', function() before_each(function() screen = Screen.new(100, 35) - screen:attach() screen:add_extra_attr_ids { [100] = { background = tonumber('0xffff40'), bg_indexed = true }, [101] = { @@ -3933,7 +3939,6 @@ describe('API', function() command('set readonly') eq({ str = '[RO]', width = 4 }, api.nvim_eval_statusline('%r', { maxwidth = 5 })) local screen = Screen.new(80, 24) - screen:attach() command('set showcmd') feed('1234') screen:expect({ any = '1234' }) @@ -4591,7 +4596,6 @@ describe('API', function() end) it('does not interfere with printing line in Ex mode #19400', function() local screen = Screen.new(60, 7) - screen:attach() insert([[ foo bar]]) @@ -5048,7 +5052,6 @@ describe('API', function() it("doesn't display messages when output=true", function() local screen = Screen.new(40, 6) - screen:attach() api.nvim_cmd({ cmd = 'echo', args = { [['hello']] } }, { output = true }) screen:expect { grid = [[ @@ -5131,7 +5134,6 @@ describe('API', function() it('nvim__redraw', function() local screen = Screen.new(60, 5) - screen:attach() eq('at least one action required', pcall_err(api.nvim__redraw, {})) eq('at least one action required', pcall_err(api.nvim__redraw, { buf = 0 })) eq('at least one action required', pcall_err(api.nvim__redraw, { win = 0 })) diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 5ce93f9e04..92999f383a 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -170,7 +170,6 @@ describe('API/win', function() it('updates the screen, and also when the window is unfocused', function() local screen = Screen.new(30, 9) - screen:attach() insert('prologue') feed('100o<esc>') @@ -281,7 +280,6 @@ describe('API/win', function() it('updates cursorline and statusline ruler in non-current window', function() local screen = Screen.new(60, 8) - screen:attach() command('set ruler') command('set cursorline') insert([[ @@ -314,7 +312,6 @@ describe('API/win', function() it('updates cursorcolumn in non-current window', function() local screen = Screen.new(60, 8) - screen:attach() command('set cursorcolumn') insert([[ aaa @@ -857,7 +854,6 @@ describe('API/win', function() it('with two diff windows', function() local X = api.nvim_get_vvar('maxcol') local screen = Screen.new(45, 22) - screen:attach() exec([[ set diffopt+=context:2 number let expr = 'printf("%08d", v:val) .. repeat("!", v:val)' @@ -975,7 +971,6 @@ describe('API/win', function() it('with wrapped lines', function() local X = api.nvim_get_vvar('maxcol') local screen = Screen.new(45, 22) - screen:attach() exec([[ set number cpoptions+=n call setline(1, repeat([repeat('foobar-', 36)], 3)) @@ -2557,7 +2552,6 @@ describe('API/win', function() it('updates statusline when moving bottom split', function() local screen = Screen.new(10, 10) - screen:attach() exec([[ set laststatus=0 belowright split diff --git a/test/functional/autocmd/autocmd_oldtest_spec.lua b/test/functional/autocmd/autocmd_oldtest_spec.lua index 5e4beb7684..7b40b0a25b 100644 --- a/test/functional/autocmd/autocmd_oldtest_spec.lua +++ b/test/functional/autocmd/autocmd_oldtest_spec.lua @@ -102,7 +102,6 @@ describe('oldtests', function() -- oldtest: Test_delete_ml_get_errors() it('no ml_get error with TextChanged autocommand and delete', function() local screen = Screen.new(75, 10) - screen:attach() screen:add_extra_attr_ids { [100] = { background = Screen.colors.Cyan1 }, } diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua index 0429cfee89..c62e4752e0 100644 --- a/test/functional/autocmd/autocmd_spec.lua +++ b/test/functional/autocmd/autocmd_spec.lua @@ -258,7 +258,6 @@ describe('autocmd', function() -- Check redrawing and API accesses to this window. local screen = Screen.new(50, 10) - screen:attach() source([[ function! Doit() @@ -333,7 +332,6 @@ describe('autocmd', function() it('`aucmd_win` cannot be changed into a normal window #13699', function() local screen = Screen.new(50, 10) - screen:attach() -- Create specific layout and ensure it's left unchanged. -- Use vim._with on a hidden buffer so aucmd_win is used. @@ -498,7 +496,6 @@ describe('autocmd', function() it(':doautocmd does not warn "No matching autocommands" #10689', function() local screen = Screen.new(32, 3) - screen:attach() feed(':doautocmd User Foo<cr>') screen:expect { diff --git a/test/functional/autocmd/cmdline_spec.lua b/test/functional/autocmd/cmdline_spec.lua index ca137debb8..7e13c0f349 100644 --- a/test/functional/autocmd/cmdline_spec.lua +++ b/test/functional/autocmd/cmdline_spec.lua @@ -60,7 +60,6 @@ describe('cmdline autocommands', function() it('handles errors correctly', function() clear() local screen = Screen.new(72, 8) - screen:attach() command("autocmd CmdlineEnter * echoerr 'FAIL'") command("autocmd CmdlineLeave * echoerr 'very error'") diff --git a/test/functional/autocmd/show_spec.lua b/test/functional/autocmd/show_spec.lua index 10d242527f..fcac706349 100644 --- a/test/functional/autocmd/show_spec.lua +++ b/test/functional/autocmd/show_spec.lua @@ -46,7 +46,6 @@ describe(':autocmd', function() screen:add_extra_attr_ids { [100] = { foreground = Screen.colors.Magenta, bold = true }, } - screen:attach() exec([[ set more autocmd! BufEnter diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua index 64f16cf779..baf2bb6071 100644 --- a/test/functional/autocmd/termxx_spec.lua +++ b/test/functional/autocmd/termxx_spec.lua @@ -198,8 +198,11 @@ it('autocmd TermEnter, TermLeave', function() end) describe('autocmd TextChangedT', function() - clear() - local screen = tt.setup_screen() + local screen + before_each(function() + clear() + screen = tt.setup_screen() + end) it('works', function() command('autocmd TextChangedT * ++once let g:called = 1') diff --git a/test/functional/autocmd/win_scrolled_resized_spec.lua b/test/functional/autocmd/win_scrolled_resized_spec.lua index 72bbc1e469..23de83e3dc 100644 --- a/test/functional/autocmd/win_scrolled_resized_spec.lua +++ b/test/functional/autocmd/win_scrolled_resized_spec.lua @@ -225,8 +225,7 @@ end) describe('WinScrolled', function() -- oldtest: Test_WinScrolled_mouse() it('is triggered by mouse scrolling in another window', function() - local screen = Screen.new(75, 10) - screen:attach() + local _ = Screen.new(75, 10) exec([[ set nowrap scrolloff=0 set mouse=a @@ -304,7 +303,6 @@ describe('WinScrolled', function() it('is triggered by mouse scrolling in unfocused floating window #18222', function() local screen = Screen.new(80, 24) - screen:attach() exec([[ let g:scrolled = 0 diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index d33710a63d..cf9715f848 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -59,7 +59,6 @@ describe('fileio', function() local screen_nvim = spawn(argv) set_session(screen_nvim) local screen = Screen.new(70, 10) - screen:attach() screen:set_default_attr_ids({ [1] = { foreground = Screen.colors.NvimDarkGrey4 }, [2] = { background = Screen.colors.NvimDarkGrey1, foreground = Screen.colors.NvimLightGrey3 }, @@ -276,7 +275,6 @@ describe('fileio', function() write_file('Xtest-overwrite-forced', 'foobar') command('set nofixendofline') local screen = Screen.new(40, 4) - screen:attach() command('set shortmess-=F') command('e Xtest-overwrite-forced') diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 68ac0a50f6..618c294566 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -498,7 +498,6 @@ describe('jobs', function() it('can redefine callbacks being used by a job', function() local screen = Screen.new() - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue }, }) @@ -524,7 +523,6 @@ describe('jobs', function() it('requires funcrefs for script-local (s:) functions', function() local screen = Screen.new(60, 5) - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, @@ -910,7 +908,6 @@ describe('jobs', function() it('hides cursor and flushes messages before blocking', function() local screen = Screen.new(50, 6) - screen:attach() command([[let g:id = jobstart([v:progpath, '--clean', '--headless'])]]) source([[ func PrintAndWait() @@ -1223,7 +1220,6 @@ describe('pty process teardown', function() before_each(function() clear() screen = Screen.new(30, 6) - screen:attach() screen:expect([[ ^ | {1:~ }|*4 diff --git a/test/functional/core/log_spec.lua b/test/functional/core/log_spec.lua index a952730779..57dfd6364c 100644 --- a/test/functional/core/log_spec.lua +++ b/test/functional/core/log_spec.lua @@ -15,6 +15,7 @@ describe('log', function() after_each(function() expect_exit(command, 'qa!') + vim.uv.sleep(10) -- Wait for Nvim to fully exit os.remove(testlog) end) diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua index a6e917b4b2..a445423efc 100644 --- a/test/functional/core/main_spec.lua +++ b/test/functional/core/main_spec.lua @@ -89,7 +89,6 @@ describe('command-line option', function() it('does not crash after reading from stdin in non-headless mode', function() skip(is_os('win')) local screen = Screen.new(40, 8) - screen:attach() local args = { nvim_prog_abs(), '-u', diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index f48bcb9360..7062211187 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -55,7 +55,6 @@ describe('startup', function() clear() local screen screen = Screen.new(84, 3) - screen:attach() fn.termopen({ nvim_prog, '-u', 'NONE', '--server', eval('v:servername'), '--remote-ui' }) screen:expect([[ ^Cannot attach UI of :terminal child to its parent. (Unset $NVIM to skip this check) | @@ -74,11 +73,29 @@ describe('startup', function() assert_log("require%('vim%._editor'%)", testfile, 100) end) + it('--startuptime does not crash on error #31125', function() + eq( + "E484: Can't open file .", + fn.system({ + nvim_prog, + '-u', + 'NONE', + '-i', + 'NONE', + '--headless', + '--startuptime', + '.', + '-c', + '42cquit', + }) + ) + eq(42, api.nvim_get_vvar('shell_error')) + end) + it('-D does not hang #12647', function() clear() local screen screen = Screen.new(60, 7) - screen:attach() -- not the same colors on windows for some reason screen._default_attr_ids = nil local id = fn.termopen({ @@ -260,10 +277,8 @@ describe('startup', function() -- nvim <vim args> -l foo.lua <vim args> assert_l_out( - -- luacheck: ignore 611 (Line contains only whitespaces) [[ wrap - bufs: nvim args: 7 lua args: { "-c", "set wrap?", @@ -327,7 +342,6 @@ describe('startup', function() it('with --embed: has("ttyin")==0 has("ttyout")==0', function() local screen = Screen.new(25, 3) -- Remote UI connected by --embed. - screen:attach() -- TODO: a lot of tests in this file already use the new default color scheme. -- once we do the batch update of tests to use it, remove this workarond screen._default_attr_ids = nil @@ -341,7 +355,6 @@ describe('startup', function() it('in a TTY: has("ttyin")==1 has("ttyout")==1', function() local screen = Screen.new(25, 4) - screen:attach() screen._default_attr_ids = nil if is_os('win') then command([[set shellcmdflag=/s\ /c shellxquote=\"]]) @@ -436,7 +449,6 @@ describe('startup', function() it('input from pipe (implicit) #7679', function() clear({ env = { NVIM_LOG_FILE = testlog } }) local screen = Screen.new(25, 4) - screen:attach() screen._default_attr_ids = nil if is_os('win') then command([[set shellcmdflag=/s\ /c shellxquote=\"]]) @@ -601,7 +613,6 @@ describe('startup', function() it('ENTER dismisses early message #7967', function() local screen screen = Screen.new(60, 6) - screen:attach() screen._default_attr_ids = nil local id = fn.termopen({ nvim_prog, @@ -699,7 +710,6 @@ describe('startup', function() it('-e/-E interactive #7679', function() clear('-e') local screen = Screen.new(25, 3) - screen:attach() feed("put ='from -e'<CR>") screen:expect([[ :put ='from -e' | @@ -709,7 +719,6 @@ describe('startup', function() clear('-E') screen = Screen.new(25, 3) - screen:attach() feed("put ='from -E'<CR>") screen:expect([[ :put ='from -E' | @@ -719,9 +728,8 @@ describe('startup', function() end) it('-e sets ex mode', function() - local screen = Screen.new(25, 3) clear('-e') - screen:attach() + local screen = Screen.new(25, 3) -- Verify we set the proper mode both before and after :vi. feed('put =mode(1)<CR>vi<CR>:put =mode(1)<CR>') screen:expect([[ @@ -773,7 +781,6 @@ describe('startup', function() it("sets 'shortmess' when loading other tabs", function() clear({ args = { '-p', 'a', 'b', 'c' } }) local screen = Screen.new(25, 4) - screen:attach() screen:expect({ grid = [[ {1: a }{2: b c }{3: }{2:X}| @@ -1136,7 +1143,6 @@ describe('user config init', function() eq('---', eval('g:exrc_file')) local screen = Screen.new(50, 8) - screen:attach() screen._default_attr_ids = nil fn.termopen({ nvim_prog }, { env = { @@ -1412,7 +1418,6 @@ describe('inccommand on ex mode', function() clear() local screen screen = Screen.new(60, 10) - screen:attach() local id = fn.termopen({ nvim_prog, '-u', diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index d543de4acd..030181764d 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -17,7 +17,6 @@ describe('completion', function() before_each(function() clear() screen = Screen.new(60, 8) - screen:attach() screen:add_extra_attr_ids { [100] = { foreground = Screen.colors.Gray0, background = Screen.colors.Yellow }, [101] = { background = Screen.colors.Gray0 }, diff --git a/test/functional/editor/ctrl_c_spec.lua b/test/functional/editor/ctrl_c_spec.lua index e1258c7df8..cb6bc57681 100644 --- a/test/functional/editor/ctrl_c_spec.lua +++ b/test/functional/editor/ctrl_c_spec.lua @@ -13,7 +13,6 @@ describe('CTRL-C (mapped)', function() before_each(function() clear() screen = Screen.new(52, 6) - screen:attach() end) it('interrupts :global', function() diff --git a/test/functional/editor/defaults_spec.lua b/test/functional/editor/defaults_spec.lua index 47fd177f7b..82d285cc9a 100644 --- a/test/functional/editor/defaults_spec.lua +++ b/test/functional/editor/defaults_spec.lua @@ -35,7 +35,6 @@ describe('default', function() args = { '+autocmd! nvim_popupmenu', '+aunmenu PopUp' }, } local screen = Screen.new(40, 8) - screen:attach() n.insert([[ 1 line 1 2 https://example.com @@ -58,7 +57,6 @@ describe('default', function() it('right-click on URL shows "Open in web browser"', function() n.clear() local screen = Screen.new(40, 8) - screen:attach() n.insert([[ 1 line 1 2 https://example.com @@ -95,6 +93,157 @@ describe('default', function() end) end) - -- describe('key mappings', function() - -- end) + describe('key mappings', function() + describe('unimpaired-style mappings', function() + it('do not show a full stack trace #30625', function() + n.clear({ args_rm = { '--cmd' } }) + local screen = Screen.new(40, 8) + screen:set_default_attr_ids({ + [1] = { foreground = Screen.colors.NvimDarkGray4 }, + [2] = { + background = Screen.colors.NvimLightGrey3, + foreground = Screen.colors.NvimDarkGray3, + }, + [3] = { foreground = Screen.colors.NvimLightRed }, + [4] = { foreground = Screen.colors.NvimLightCyan }, + }) + + n.feed('[a') + screen:expect({ + grid = [[ + | + {1:~ }|*4 + {2: }| + {3:E163: There is only one file to edit} | + {4:Press ENTER or type command to continue}^ | + ]], + }) + + n.feed('[q') + screen:expect({ + grid = [[ + ^ | + {1:~ }|*5 + {2:[No Name] 0,0-1 All}| + {3:E42: No Errors} | + ]], + }) + + n.feed('[l') + screen:expect({ + grid = [[ + ^ | + {1:~ }|*5 + {2:[No Name] 0,0-1 All}| + {3:E776: No location list} | + ]], + }) + + n.feed('[t') + screen:expect({ + grid = [[ + ^ | + {1:~ }|*5 + {2:[No Name] 0,0-1 All}| + {3:E73: Tag stack empty} | + ]], + }) + end) + + describe('[<Space>', function() + it('adds an empty line above the current line', function() + n.clear({ args_rm = { '--cmd' } }) + n.insert([[first line]]) + n.feed('[<Space>') + n.expect([[ + + first line]]) + end) + + it('works with a count', function() + n.clear({ args_rm = { '--cmd' } }) + n.insert([[first line]]) + n.feed('5[<Space>') + n.expect([[ + + + + + + first line]]) + end) + + it('supports dot repetition', function() + n.clear({ args_rm = { '--cmd' } }) + n.insert([[first line]]) + n.feed('[<Space>') + n.feed('.') + n.expect([[ + + + first line]]) + end) + + it('supports dot repetition and a count', function() + n.clear({ args_rm = { '--cmd' } }) + n.insert([[first line]]) + n.feed('[<Space>') + n.feed('3.') + n.expect([[ + + + + + first line]]) + end) + end) + + describe(']<Space>', function() + it('adds an empty line below the current line', function() + n.clear({ args_rm = { '--cmd' } }) + n.insert([[first line]]) + n.feed(']<Space>') + n.expect([[ + first line + ]]) + end) + + it('works with a count', function() + n.clear({ args_rm = { '--cmd' } }) + n.insert([[first line]]) + n.feed('5]<Space>') + n.expect([[ + first line + + + + + ]]) + end) + + it('supports dot repetition', function() + n.clear({ args_rm = { '--cmd' } }) + n.insert([[first line]]) + n.feed(']<Space>') + n.feed('.') + n.expect([[ + first line + + ]]) + end) + + it('supports dot repetition and a count', function() + n.clear({ args_rm = { '--cmd' } }) + n.insert([[first line]]) + n.feed(']<Space>') + n.feed('2.') + n.expect([[ + first line + + + ]]) + end) + end) + end) + end) end) diff --git a/test/functional/editor/jump_spec.lua b/test/functional/editor/jump_spec.lua index ab4cefaf84..dab8fb3fda 100644 --- a/test/functional/editor/jump_spec.lua +++ b/test/functional/editor/jump_spec.lua @@ -56,7 +56,6 @@ describe('jumplist', function() write_file(fname2, 'baz') local screen = Screen.new(5, 25) - screen:attach() command('set number') command('edit ' .. fname1) feed('35gg') @@ -386,7 +385,6 @@ describe('jumpoptions=view', function() it('restores the view', function() local screen = Screen.new(5, 8) - screen:attach() command('edit ' .. file1) feed('12Gztj') feed('gg<C-o>') @@ -404,7 +402,6 @@ describe('jumpoptions=view', function() it('restores the view across files', function() local screen = Screen.new(5, 5) - screen:attach() command('args ' .. file1 .. ' ' .. file2) feed('12Gzt') command('next') @@ -428,7 +425,6 @@ describe('jumpoptions=view', function() it('restores the view across files with <C-^>', function() local screen = Screen.new(5, 5) - screen:attach() command('args ' .. file1 .. ' ' .. file2) feed('12Gzt') command('next') @@ -452,7 +448,6 @@ describe('jumpoptions=view', function() it("falls back to standard behavior when view can't be recovered", function() local screen = Screen.new(5, 8) - screen:attach() command('edit ' .. file1) feed('7GzbG') api.nvim_buf_set_lines(0, 0, 2, true, {}) @@ -477,7 +472,6 @@ describe('jumpoptions=view', function() it('falls back to standard behavior for a mark without a view', function() local screen = Screen.new(5, 8) - screen:attach() command('edit ' .. file1) feed('10ggzzvwy') screen:expect([[ diff --git a/test/functional/editor/mark_spec.lua b/test/functional/editor/mark_spec.lua index 69cb95e1c3..08f90b088d 100644 --- a/test/functional/editor/mark_spec.lua +++ b/test/functional/editor/mark_spec.lua @@ -348,7 +348,6 @@ describe('named marks view', function() it('is restored in normal mode but not op-pending mode', function() local screen = Screen.new(5, 8) - screen:attach() command('edit ' .. file1) feed('<C-e>jWma') feed("G'a") @@ -390,7 +389,6 @@ describe('named marks view', function() it('is restored across files', function() local screen = Screen.new(5, 5) - screen:attach() command('args ' .. file1 .. ' ' .. file2) feed('<C-e>mA') local mark_view = [[ @@ -415,7 +413,6 @@ describe('named marks view', function() it("fallback to standard behavior when view can't be recovered", function() local screen = Screen.new(10, 10) - screen:attach() command('edit ' .. file1) feed('7GzbmaG') -- Seven lines from the top command('new') -- Screen size for window is now half the height can't be restored @@ -434,7 +431,6 @@ describe('named marks view', function() 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') diff --git a/test/functional/editor/mode_cmdline_spec.lua b/test/functional/editor/mode_cmdline_spec.lua index efd7a37c0b..52f2bf7f8c 100644 --- a/test/functional/editor/mode_cmdline_spec.lua +++ b/test/functional/editor/mode_cmdline_spec.lua @@ -38,6 +38,26 @@ describe('cmdline', function() feed([[:<C-R>="foo\nbar\rbaz"<CR>]]) eq('foo\nbar\rbaz', fn.getcmdline()) end) + + it('pasting handles composing chars properly', function() + local screen = Screen.new(60, 4) + -- 'arabicshape' cheats and always redraws everything which trivially works, + -- this test is for partial redraws in 'noarabicshape' mode. + command('set noarabicshape') + fn.setreg('a', '💻') + feed(':test 🧑') + screen:expect([[ + | + {1:~ }|*2 + :test 🧑^ | + ]]) + feed('<c-r><c-r>a') + screen:expect([[ + | + {1:~ }|*2 + :test 🧑💻^ | + ]]) + end) end) it('Ctrl-Shift-V supports entering unsimplified key notations', function() @@ -48,7 +68,6 @@ describe('cmdline', function() it('redraws statusline when toggling overstrike', function() local screen = Screen.new(60, 4) - screen:attach() command('set laststatus=2 statusline=%!mode(1)') feed(':') screen:expect { diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua index 87d5c46134..a9fa93590f 100644 --- a/test/functional/editor/mode_insert_spec.lua +++ b/test/functional/editor/mode_insert_spec.lua @@ -55,7 +55,6 @@ describe('insert-mode', function() it('double quote is removed after hit-enter prompt #22609', function() local screen = Screen.new(50, 6) - screen:attach() feed('i<C-R>') screen:expect([[ {18:^"} | @@ -180,7 +179,6 @@ describe('insert-mode', function() it('multi-char mapping updates screen properly #25626', function() local screen = Screen.new(60, 6) - screen:attach() command('vnew') insert('foo\nfoo\nfoo') command('wincmd w') @@ -228,8 +226,7 @@ describe('insert-mode', function() end it('works with tabs and spaces', function() - local screen = Screen.new(30, 2) - screen:attach() + local _ = Screen.new(30, 2) command('setl ts=4 sw=4') set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a') feed('$i') @@ -246,8 +243,7 @@ describe('insert-mode', function() end) it('works with varsofttabstop', function() - local screen = Screen.new(30, 2) - screen:attach() + local _ = Screen.new(30, 2) command('setl vsts=6,2,5,3') set_lines(0, 1, 'a\t' .. s(4) .. '\t a') feed('$i') @@ -263,8 +259,7 @@ describe('insert-mode', function() end) it('works with tab as ^I', function() - local screen = Screen.new(30, 2) - screen:attach() + local _ = Screen.new(30, 2) command('set list listchars=space:.') command('setl ts=4 sw=4') set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a') @@ -280,8 +275,7 @@ describe('insert-mode', function() end) it('works in replace mode', function() - local screen = Screen.new(50, 2) - screen:attach() + local _ = Screen.new(50, 2) command('setl ts=8 sw=8 sts=8') set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a') feed('$R') @@ -296,8 +290,7 @@ describe('insert-mode', function() end) it('works with breakindent', function() - local screen = Screen.new(17, 4) - screen:attach() + local _ = Screen.new(17, 4) command('setl ts=4 sw=4 bri briopt=min:5') set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a') feed('$i') @@ -314,8 +307,7 @@ describe('insert-mode', function() end) it('works with inline virtual text', function() - local screen = Screen.new(50, 2) - screen:attach() + local _ = Screen.new(50, 2) command('setl ts=4 sw=4') set_lines(0, 1, '\t' .. s(4) .. '\t' .. s(9) .. '\t a') local ns = api.nvim_create_namespace('') @@ -335,8 +327,7 @@ describe('insert-mode', function() end) it("works with 'revins'", function() - local screen = Screen.new(30, 3) - screen:attach() + local _ = Screen.new(30, 3) command('setl ts=4 sw=4 revins') set_lines(0, 1, ('a'):rep(16), s(3) .. '\t' .. s(4) .. '\t a') feed('j$i') @@ -354,7 +345,6 @@ describe('insert-mode', function() it('backspace after replacing multibyte chars', function() local screen = Screen.new(30, 3) - screen:attach() api.nvim_buf_set_lines(0, 0, -1, true, { 'test ȧ̟̜̝̅̚m̆̉̐̐̇̈ å' }) feed('^Rabcdefghi') screen:expect([[ diff --git a/test/functional/editor/mode_normal_spec.lua b/test/functional/editor/mode_normal_spec.lua index b3ef4866dc..5237f51237 100644 --- a/test/functional/editor/mode_normal_spec.lua +++ b/test/functional/editor/mode_normal_spec.lua @@ -9,6 +9,7 @@ local feed = n.feed local fn = n.fn local command = n.command local eq = t.eq +local api = n.api describe('Normal mode', function() before_each(clear) @@ -25,7 +26,6 @@ describe('Normal mode', function() it('&showcmd does not crash with :startinsert #28419', function() local screen = Screen.new(60, 17) - screen:attach() fn.termopen( { n.nvim_prog, '--clean', '--cmd', 'startinsert' }, { env = { VIMRUNTIME = os.getenv('VIMRUNTIME') } } @@ -41,4 +41,22 @@ describe('Normal mode', function() attr_ids = {}, }) end) + + it('replacing with ZWJ emoji sequences', function() + local screen = Screen.new(30, 8) + api.nvim_buf_set_lines(0, 0, -1, true, { 'abcdefg' }) + feed('05r🧑🌾') -- ZWJ + screen:expect([[ + 🧑🌾🧑🌾🧑🌾🧑🌾^🧑🌾fg | + {1:~ }|*6 + | + ]]) + + feed('2r🏳️⚧️') -- ZWJ and variant selectors + screen:expect([[ + 🧑🌾🧑🌾🧑🌾🧑🌾🏳️⚧️^🏳️⚧️g | + {1:~ }|*6 + | + ]]) + end) end) diff --git a/test/functional/editor/put_spec.lua b/test/functional/editor/put_spec.lua index 0f6936cd31..79f9d97bc5 100644 --- a/test/functional/editor/put_spec.lua +++ b/test/functional/editor/put_spec.lua @@ -883,7 +883,6 @@ describe('put command', function() local screen setup(function() screen = Screen.new() - screen:attach() end) local function bell_test(actions, should_ring) diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua index c20a6e5cb5..b6fbebb20c 100644 --- a/test/functional/editor/tabpage_spec.lua +++ b/test/functional/editor/tabpage_spec.lua @@ -105,7 +105,6 @@ describe('tabpage', function() screen:add_extra_attr_ids { [100] = { bold = true, foreground = Screen.colors.Fuchsia }, } - screen:attach() command('tabnew') command('tabprev') diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua index df62aecc7f..59862d5e77 100644 --- a/test/functional/ex_cmds/append_spec.lua +++ b/test/functional/ex_cmds/append_spec.lua @@ -65,7 +65,6 @@ describe('the first line is redrawn correctly after inserting text in an empty b [1] = { bold = true, foreground = Screen.colors.Blue }, [2] = { bold = true, reverse = true }, }) - screen:attach() end) it('using :append', function() diff --git a/test/functional/ex_cmds/cmd_map_spec.lua b/test/functional/ex_cmds/cmd_map_spec.lua index 6c1ac8eae5..17156e483b 100644 --- a/test/functional/ex_cmds/cmd_map_spec.lua +++ b/test/functional/ex_cmds/cmd_map_spec.lua @@ -37,7 +37,6 @@ describe('mappings with <Cmd>', function() [9] = { background = Screen.colors.LightMagenta }, [10] = { foreground = Screen.colors.Red }, }) - screen:attach() cmdmap('<F3>', 'let m = mode(1)') cmdmap('<F4>', 'normal! ww') diff --git a/test/functional/ex_cmds/debug_spec.lua b/test/functional/ex_cmds/debug_spec.lua index ebb3cdd38a..d657f9aa6d 100644 --- a/test/functional/ex_cmds/debug_spec.lua +++ b/test/functional/ex_cmds/debug_spec.lua @@ -15,7 +15,6 @@ describe(':debug', function() [3] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, [4] = { bold = true, foreground = Screen.colors.SeaGreen4 }, }) - screen:attach() end) it('scrolls messages correctly', function() feed(':echoerr bork<cr>') diff --git a/test/functional/ex_cmds/digraphs_spec.lua b/test/functional/ex_cmds/digraphs_spec.lua index fde25c028f..c45378e494 100644 --- a/test/functional/ex_cmds/digraphs_spec.lua +++ b/test/functional/ex_cmds/digraphs_spec.lua @@ -19,7 +19,6 @@ describe(':digraphs', function() [6] = { foreground = Screen.colors.Blue1 }, [7] = { bold = true, reverse = true }, }) - screen:attach() end) it('displays digraphs', function() diff --git a/test/functional/ex_cmds/drop_spec.lua b/test/functional/ex_cmds/drop_spec.lua index 54ddd79a35..d341c823b9 100644 --- a/test/functional/ex_cmds/drop_spec.lua +++ b/test/functional/ex_cmds/drop_spec.lua @@ -11,7 +11,6 @@ describe(':drop', function() before_each(function() clear() screen = Screen.new(35, 10) - screen:attach() screen:set_default_attr_ids({ [0] = { bold = true, foreground = Screen.colors.Blue }, [1] = { bold = true, reverse = true }, diff --git a/test/functional/ex_cmds/highlight_spec.lua b/test/functional/ex_cmds/highlight_spec.lua index 3cb6cc2579..58709f314f 100644 --- a/test/functional/ex_cmds/highlight_spec.lua +++ b/test/functional/ex_cmds/highlight_spec.lua @@ -10,12 +10,9 @@ local fn = n.fn local api = n.api describe(':highlight', function() - local screen - before_each(function() clear() - screen = Screen.new() - screen:attach() + local _ = Screen.new() end) it('invalid color name', function() diff --git a/test/functional/ex_cmds/map_spec.lua b/test/functional/ex_cmds/map_spec.lua index 9ef0a8ec2e..954dae9335 100644 --- a/test/functional/ex_cmds/map_spec.lua +++ b/test/functional/ex_cmds/map_spec.lua @@ -103,7 +103,6 @@ describe('Screen', function() before_each(function() clear() screen = Screen.new(20, 5) - screen:attach() end) it('cursor is restored after :map <expr> which calls input()', function() diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua index 8f09e802eb..95e118d570 100644 --- a/test/functional/ex_cmds/mksession_spec.lua +++ b/test/functional/ex_cmds/mksession_spec.lua @@ -201,8 +201,7 @@ describe(':mksession', function() local cwd_dir = fn.fnamemodify('.', ':p:~'):gsub([[[\/]*$]], '') local session_path = cwd_dir .. '/' .. session_file - screen = Screen.new(50, 6) - screen:attach({ rgb = false }) + screen = Screen.new(50, 6, { rgb = false }) local expected_screen = [[ ^/ | | @@ -222,8 +221,7 @@ describe(':mksession', function() -- Create a new test instance of Nvim. clear() - screen = Screen.new(50, 6) - screen:attach({ rgb = false }) + screen = Screen.new(50, 6, { rgb = false }) command('silent source ' .. session_path) -- Verify that the terminal's working directory is "/". diff --git a/test/functional/ex_cmds/oldfiles_spec.lua b/test/functional/ex_cmds/oldfiles_spec.lua index 927d780181..6f81878f2d 100644 --- a/test/functional/ex_cmds/oldfiles_spec.lua +++ b/test/functional/ex_cmds/oldfiles_spec.lua @@ -38,7 +38,6 @@ describe(':oldfiles', function() it('shows most recently used files', function() local screen = Screen.new(100, 5) - screen:attach() screen._default_attr_ids = nil feed_command('edit testfile1') feed_command('edit testfile2') diff --git a/test/functional/ex_cmds/quickfix_commands_spec.lua b/test/functional/ex_cmds/quickfix_commands_spec.lua index 9c47b1f05f..c1592d85d0 100644 --- a/test/functional/ex_cmds/quickfix_commands_spec.lua +++ b/test/functional/ex_cmds/quickfix_commands_spec.lua @@ -199,7 +199,6 @@ describe('quickfix', function() it('jump message does not scroll with cmdheight=0 and shm+=O #29597', function() local screen = Screen.new(40, 6) - screen:attach() command('set cmdheight=0') local file = file_base .. '_reuse_qfbuf_BufAdd' write_file(file, 'foobar') @@ -226,7 +225,6 @@ it(':vimgrep can specify Unicode pattern without delimiters', function() [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText [1] = { reverse = true }, -- IncSearch }) - screen:attach() feed('i→<Esc>:vimgrep →') screen:expect([[ {1:→} | diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua index 5bb2a0181e..2820cc9663 100644 --- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua +++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua @@ -114,7 +114,6 @@ describe("preserve and (R)ecover with custom 'directory'", function() it('killing TUI process without :preserve #22096', function() t.skip(t.is_os('win')) local screen0 = Screen.new() - screen0:attach() local child_server = new_pipename() fn.termopen({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--listen', child_server }, { env = { VIMRUNTIME = os.getenv('VIMRUNTIME') }, @@ -171,7 +170,6 @@ describe('swapfile detection', function() local nvim2 = spawn({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed' }, true, nil, true) set_session(nvim2) local screen2 = Screen.new(256, 40) - screen2:attach() screen2._default_attr_ids = nil exec(init) command('autocmd! nvim_swapfile') -- Delete the default handler (which skips the dialog). @@ -254,7 +252,6 @@ describe('swapfile detection', function() local nvim1 = spawn(new_argv(), true, nil, true) set_session(nvim1) local screen = Screen.new(75, 18) - screen:attach() exec(init) feed(':edit Xfile1\n') @@ -325,7 +322,6 @@ describe('swapfile detection', function() [1] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg [2] = { background = Screen.colors.Red, foreground = Screen.colors.White }, -- ErrorMsg }) - screen:attach() exec(init) if not swapexists then diff --git a/test/functional/example_spec.lua b/test/functional/example_spec.lua index 8db5c3d867..25554c5a7d 100644 --- a/test/functional/example_spec.lua +++ b/test/functional/example_spec.lua @@ -14,7 +14,6 @@ describe('example', function() before_each(function() clear() screen = Screen.new(20, 5) - screen:attach() screen:set_default_attr_ids({ [0] = { bold = true, foreground = Screen.colors.Blue }, [1] = { bold = true, foreground = Screen.colors.Brown }, @@ -47,8 +46,7 @@ describe('example', function() -- The UI must declare that it wants to handle the UI events. -- For this example, we enable `ext_tabline`: screen:detach() - screen = Screen.new(25, 5) - screen:attach({ rgb = true, ext_tabline = true }) + screen = Screen.new(25, 5, { rgb = true, ext_tabline = true }) -- From ":help ui" we find that `tabline_update` receives `curtab` and -- `tabs` objects. So we declare the UI handler like this: diff --git a/test/functional/legacy/012_directory_spec.lua b/test/functional/legacy/012_directory_spec.lua index 5c9185982f..d6f2203aa2 100644 --- a/test/functional/legacy/012_directory_spec.lua +++ b/test/functional/legacy/012_directory_spec.lua @@ -15,7 +15,6 @@ local clear = n.clear local insert = n.insert local command = n.command local write_file = t.write_file -local expect_exit = n.expect_exit local mkdir = t.mkdir local function ls_dir_sorted(dirname) @@ -44,7 +43,9 @@ describe("'directory' option", function() clear() end) teardown(function() - expect_exit(command, 'qall!') + command('%bwipe!') + api.nvim_set_option_value('swapfile', false, {}) + api.nvim_set_option_value('directory', '.', {}) n.rmdir('Xtest.je') n.rmdir('Xtest2') os.remove('Xtest1') @@ -58,7 +59,6 @@ describe("'directory' option", function() end of testfile]]) api.nvim_set_option_value('swapfile', true, {}) - api.nvim_set_option_value('swapfile', true, {}) api.nvim_set_option_value('directory', '.', {}) -- sanity check: files should not exist yet. diff --git a/test/functional/legacy/063_match_and_matchadd_spec.lua b/test/functional/legacy/063_match_and_matchadd_spec.lua index 7515bcf182..639a97f68f 100644 --- a/test/functional/legacy/063_match_and_matchadd_spec.lua +++ b/test/functional/legacy/063_match_and_matchadd_spec.lua @@ -11,7 +11,6 @@ describe('063: Test for ":match", "matchadd()" and related functions', function( it('is working', function() local screen = Screen.new(40, 5) - screen:attach() command('highlight MyGroup1 term=bold ctermbg=red guibg=red') command('highlight MyGroup2 term=italic ctermbg=green guibg=green') 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 d56a2654e3..eb5e36120f 100644 --- a/test/functional/legacy/074_global_var_in_viminfo_spec.lua +++ b/test/functional/legacy/074_global_var_in_viminfo_spec.lua @@ -150,5 +150,7 @@ describe('storing global variables in ShaDa files', function() teardown(function() os.remove(tempname) + command('set shadafile=NONE') + os.remove('Xviminfo') end) end) diff --git a/test/functional/legacy/078_swapfile_recover_spec.lua b/test/functional/legacy/078_swapfile_recover_spec.lua index fa53482393..6ff7539940 100644 --- a/test/functional/legacy/078_swapfile_recover_spec.lua +++ b/test/functional/legacy/078_swapfile_recover_spec.lua @@ -45,7 +45,7 @@ describe('78', function() silent recover Xtest call delete(g:swapname) - new + noswapfile new call append(0, 'recovery start') wincmd w diff --git a/test/functional/legacy/107_adjust_window_and_contents_spec.lua b/test/functional/legacy/107_adjust_window_and_contents_spec.lua index 57ecf76f3a..e97c9c074b 100644 --- a/test/functional/legacy/107_adjust_window_and_contents_spec.lua +++ b/test/functional/legacy/107_adjust_window_and_contents_spec.lua @@ -13,7 +13,6 @@ describe('107', function() it('is working', function() local screen = Screen.new() - screen:attach() insert('start:') poke_eventloop() diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua index ac2a39a381..4c083a8a4b 100644 --- a/test/functional/legacy/arglist_spec.lua +++ b/test/functional/legacy/arglist_spec.lua @@ -20,7 +20,6 @@ describe('argument list commands', function() it(':confirm quit with unedited files in arglist', function() local screen = Screen.new(60, 6) - screen:attach() command('set nomore') command('args a b c') feed(':confirm quit\n') diff --git a/test/functional/legacy/breakindent_spec.lua b/test/functional/legacy/breakindent_spec.lua index 8c3d73b17b..db27e19e50 100644 --- a/test/functional/legacy/breakindent_spec.lua +++ b/test/functional/legacy/breakindent_spec.lua @@ -17,7 +17,6 @@ describe('breakindent', function() [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue }, -- SignColumn [2] = { bold = true }, -- ModeMsg }) - screen:attach() exec([[ set listchars=eol:$ let &signcolumn = 'yes' @@ -68,7 +67,6 @@ describe('breakindent', function() setlocal breakindent call setline(1, "\t" .. join(range(100))) ]]) - screen:attach() feed('v$') screen:expect([[ diff --git a/test/functional/legacy/cmdline_spec.lua b/test/functional/legacy/cmdline_spec.lua index 2e0e52117d..bf146e1322 100644 --- a/test/functional/legacy/cmdline_spec.lua +++ b/test/functional/legacy/cmdline_spec.lua @@ -15,7 +15,6 @@ describe('cmdline', function() -- oldtest: Test_cmdlineclear_tabenter() it('is cleared when switching tabs', function() local screen = Screen.new(30, 10) - screen:attach() feed_command([[call setline(1, range(30))]]) screen:expect([[ @@ -79,7 +78,6 @@ describe('cmdline', function() -- oldtest: Test_verbose_option() it('prints every executed Ex command if verbose >= 16', function() local screen = Screen.new(60, 12) - screen:attach() exec([[ command DoSomething echo 'hello' |set ts=4 |let v = '123' |echo v call feedkeys("\r", 't') " for the hit-enter prompt @@ -104,7 +102,6 @@ describe('cmdline', function() -- oldtest: Test_cmdline_redraw_tabline() it('tabline is redrawn on entering cmdline', function() local screen = Screen.new(30, 6) - screen:attach() exec([[ set showtabline=2 autocmd CmdlineEnter * set tabline=foo @@ -121,7 +118,6 @@ describe('cmdline', function() -- oldtest: Test_redraw_in_autocmd() it('cmdline cursor position is correct after :redraw with cmdheight=2', function() local screen = Screen.new(30, 6) - screen:attach() exec([[ set cmdheight=2 autocmd CmdlineChanged * redraw @@ -143,11 +139,17 @@ describe('cmdline', function() ]]) end) - it("setting 'cmdheight' works after outputting two messages vim-patch:9.0.0665", function() + -- oldtest: Test_changing_cmdheight() + it("changing 'cmdheight'", function() local screen = Screen.new(60, 8) - screen:attach() exec([[ set cmdheight=1 laststatus=2 + func EchoOne() + set laststatus=2 cmdheight=1 + echo 'foo' + echo 'bar' + set cmdheight=2 + endfunc func EchoTwo() set laststatus=2 set cmdheight=5 @@ -156,6 +158,8 @@ describe('cmdline', function() set cmdheight=1 endfunc ]]) + + -- setting 'cmdheight' works after outputting two messages feed(':call EchoTwo()') screen:expect([[ | @@ -170,12 +174,22 @@ describe('cmdline', function() {3:[No Name] }| | ]]) + + -- increasing 'cmdheight' doesn't clear the messages that need hit-enter + feed(':call EchoOne()<CR>') + screen:expect([[ + | + {1:~ }|*3 + {3: }| + foo | + bar | + {6:Press ENTER or type command to continue}^ | + ]]) end) -- oldtest: Test_cmdheight_tabline() it("changing 'cmdheight' when there is a tabline", function() local screen = Screen.new(60, 8) - screen:attach() api.nvim_set_option_value('laststatus', 2, {}) api.nvim_set_option_value('showtabline', 2, {}) api.nvim_set_option_value('cmdheight', 1, {}) @@ -191,7 +205,6 @@ describe('cmdline', function() -- oldtest: Test_rulerformat_position() it("ruler has correct position with 'rulerformat' set", function() local screen = Screen.new(20, 3) - screen:attach() api.nvim_set_option_value('ruler', true, {}) api.nvim_set_option_value('rulerformat', 'longish', {}) api.nvim_set_option_value('laststatus', 0, {}) @@ -218,7 +231,6 @@ describe('cmdwin', function() [3] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg [4] = { bold = true }, -- ModeMsg }) - screen:attach() command('set more') command('autocmd WinNew * highlight') feed('q:') diff --git a/test/functional/legacy/conceal_spec.lua b/test/functional/legacy/conceal_spec.lua index f4c1983bb7..66a99fe684 100644 --- a/test/functional/legacy/conceal_spec.lua +++ b/test/functional/legacy/conceal_spec.lua @@ -21,7 +21,6 @@ describe('Conceal', function() -- oldtest: Test_conceal_two_windows() it('works', function() local screen = Screen.new(75, 12) - screen:attach() exec([[ let lines = ["one one one one one", "two |hidden| here", "three |hidden| three"] call setline(1, lines) @@ -382,12 +381,9 @@ describe('Conceal', function() -- 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() + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.LightRed }, + } -- 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) @@ -408,12 +404,12 @@ describe('Conceal', function() -- luacheck: pop screen:expect([[ - one one one one one one {1:o}ne | - {0: >>> }one {2:o}ne one one | + one one one one one one {21:o}ne | + {1: >>> }one {100: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:~ }|*4 + three three three three {21:t}hree | + {1: >>> }thre{100:e} three three three | + {1:~ }|*4 /here | ]]) @@ -421,11 +417,11 @@ describe('Conceal', function() feed('$') screen:expect([[ one one one one one one one | - {0: >>> }one {2:o}ne one one | + {1: >>> }one {100: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:~ }|*4 + {1: >>> }thre{100:e} three three three | + {1:~ }|*4 /here | ]]) end) @@ -433,12 +429,9 @@ describe('Conceal', function() -- oldtest: Test_conceal_wrapped_cursorline_wincolor() it('CursorLine highlight on wrapped lines', function() local screen = Screen.new(40, 4) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { background = Screen.colors.Green }, -- CursorLine (low-priority) - [2] = { foreground = Screen.colors.Red }, -- CursorLine (high-priority) - }) - screen:attach() + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.WebGreen }, + } exec([[ call setline(1, 'one one one |hidden| one one one one one one one one') syntax match test /|hidden|/ conceal @@ -447,16 +440,16 @@ describe('Conceal', function() hi! CursorLine guibg=Green ]]) screen:expect([[ - {1:one one one one one one one on^e }| - {1: one one one }| - {0:~ }| + {100:one one one one one one one on^e }| + {100: one one one }| + {1:~ }| | ]]) command('hi! CursorLine guibg=NONE guifg=Red') screen:expect([[ - {2:one one one one one one one on^e }| - {2: one one one }| - {0:~ }| + {19:one one one one one one one on^e }| + {19: one one one }| + {1:~ }| | ]]) end) @@ -464,12 +457,9 @@ describe('Conceal', function() -- oldtest: Test_conceal_wrapped_cursorline_wincolor_rightleft() it('CursorLine highlight on wrapped lines with rightleft', function() local screen = Screen.new(40, 4) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { background = Screen.colors.Green }, -- CursorLine (low-priority) - [2] = { foreground = Screen.colors.Red }, -- CursorLine (high-priority) - }) - screen:attach() + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.WebGreen }, + } exec([[ call setline(1, 'one one one |hidden| one one one one one one one one') syntax match test /|hidden|/ conceal @@ -478,16 +468,16 @@ describe('Conceal', function() hi! CursorLine guibg=Green ]]) screen:expect([[ - {1: ^eno eno eno eno eno eno eno eno}| - {1: eno eno eno }| - {0: ~}| + {100: ^eno eno eno eno eno eno eno eno}| + {100: eno eno eno }| + {1: ~}| | ]]) command('hi! CursorLine guibg=NONE guifg=Red') screen:expect([[ - {2: ^eno eno eno eno eno eno eno eno}| - {2: eno eno eno }| - {0: ~}| + {19: ^eno eno eno eno eno eno eno eno}| + {19: eno eno eno }| + {1: ~}| | ]]) end) @@ -495,7 +485,6 @@ describe('Conceal', function() -- oldtest: Test_conceal_resize_term() it('resize editor', function() local screen = Screen.new(75, 6) - screen:attach() exec([[ call setline(1, '`one` `two` `three` `four` `five`, the backticks should be concealed') setl cocu=n cole=3 @@ -519,7 +508,6 @@ describe('Conceal', function() -- oldtest: Test_conceal_linebreak() it('with linebreak', function() local screen = Screen.new(75, 8) - screen:attach() exec([[ let &wrap = v:true let &conceallevel = 2 @@ -625,10 +613,6 @@ describe('Conceal', function() local function test_conceal_virtualedit_after_eol(wrap) local screen = Screen.new(60, 3) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - }) - screen:attach() api.nvim_set_option_value('wrap', wrap, {}) exec([[ call setline(1, 'abcdefgh|hidden|ijklmnpop') @@ -638,31 +622,31 @@ describe('Conceal', function() ]]) screen:expect([[ abcdefghijklmnpo^p | - {0:~ }| + {1:~ }| | ]]) feed('l') screen:expect([[ abcdefghijklmnpop^ | - {0:~ }| + {1:~ }| | ]]) feed('l') screen:expect([[ abcdefghijklmnpop ^ | - {0:~ }| + {1:~ }| | ]]) feed('l') screen:expect([[ abcdefghijklmnpop ^ | - {0:~ }| + {1:~ }| | ]]) feed('rr') screen:expect([[ abcdefghijklmnpop ^r | - {0:~ }| + {1:~ }| | ]]) end @@ -679,10 +663,6 @@ describe('Conceal', function() local function test_conceal_virtualedit_after_eol_rightleft(wrap) local screen = Screen.new(60, 3) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - }) - screen:attach() api.nvim_set_option_value('wrap', wrap, {}) exec([[ call setline(1, 'abcdefgh|hidden|ijklmnpop') @@ -692,31 +672,31 @@ describe('Conceal', function() ]]) screen:expect([[ ^popnmlkjihgfedcba| - {0: ~}| + {1: ~}| | ]]) feed('h') screen:expect([[ ^ popnmlkjihgfedcba| - {0: ~}| + {1: ~}| | ]]) feed('h') screen:expect([[ ^ popnmlkjihgfedcba| - {0: ~}| + {1: ~}| | ]]) feed('h') screen:expect([[ ^ popnmlkjihgfedcba| - {0: ~}| + {1: ~}| | ]]) feed('rr') screen:expect([[ ^r popnmlkjihgfedcba| - {0: ~}| + {1: ~}| | ]]) end @@ -733,12 +713,9 @@ describe('Conceal', function() local function test_conceal_double_width(wrap) local screen = Screen.new(60, 4) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey }, - [2] = { background = Screen.colors.LightRed }, - }) - screen:attach() + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.LightRed }, + } api.nvim_set_option_value('wrap', wrap, {}) exec([[ call setline(1, ['aaaaa口=口bbbbb口=口ccccc', 'foobar']) @@ -747,30 +724,30 @@ describe('Conceal', function() normal! $ ]]) screen:expect([[ - aaaaa{1:β}bbbbb{1:β}cccc^c {2: } | - foobar {2: } | - {0:~ }| + aaaaa{14:β}bbbbb{14:β}cccc^c {100: } | + foobar {100: } | + {1:~ }| | ]]) feed('gM') screen:expect([[ - aaaaa{1:β}bb^bbb{1:β}ccccc {2: } | - foobar {2: } | - {0:~ }| + aaaaa{14:β}bb^bbb{14:β}ccccc {100: } | + foobar {100: } | + {1:~ }| | ]]) command('set conceallevel=3') screen:expect([[ - aaaaabb^bbbccccc {2: } | - foobar {2: } | - {0:~ }| + aaaaabb^bbbccccc {100: } | + foobar {100: } | + {1:~ }| | ]]) feed('$') screen:expect([[ - aaaaabbbbbcccc^c {2: } | - foobar {2: } | - {0:~ }| + aaaaabbbbbcccc^c {100: } | + foobar {100: } | + {1:~ }| | ]]) end @@ -788,12 +765,9 @@ describe('Conceal', function() -- oldtest: Test_conceal_double_width_wrap() it('line wraps correctly when double-width chars are concealed', function() local screen = Screen.new(20, 4) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey }, - [2] = { background = Screen.colors.LightRed }, - }) - screen:attach() + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.LightRed }, + } exec([[ call setline(1, 'aaaaaaaaaa口=口bbbbbbbbbb口=口cccccccccc') syntax match test /口=口/ conceal cchar=β @@ -801,30 +775,30 @@ describe('Conceal', function() normal! $ ]]) screen:expect([[ - aaaaaaaaaa{1:β}bbbbb | - bbbbb{1:β}ccccccccc^c | - {0:~ }| + aaaaaaaaaa{14:β}bbbbb | + bbbbb{14:β}ccccccccc^c | + {1:~ }| | ]]) feed('gM') screen:expect([[ - aaaaaaaaaa{1:β}bbbbb | - ^bbbbb{1:β}cccccccccc | - {0:~ }| + aaaaaaaaaa{14:β}bbbbb | + ^bbbbb{14:β}cccccccccc | + {1:~ }| | ]]) command('set conceallevel=3') screen:expect([[ aaaaaaaaaabbbbb | ^bbbbbcccccccccc | - {0:~ }| + {1:~ }| | ]]) feed('$') screen:expect([[ aaaaaaaaaabbbbb | bbbbbccccccccc^c | - {0:~ }| + {1:~ }| | ]]) end) diff --git a/test/functional/legacy/cpoptions_spec.lua b/test/functional/legacy/cpoptions_spec.lua index 56b0e72c72..bd1390c874 100644 --- a/test/functional/legacy/cpoptions_spec.lua +++ b/test/functional/legacy/cpoptions_spec.lua @@ -10,7 +10,6 @@ before_each(clear) describe('cpoptions', function() it('$', function() local screen = Screen.new(30, 6) - screen:attach() command('set cpo+=$') command([[call setline(1, 'one two three')]]) feed('c2w') diff --git a/test/functional/legacy/debugger_spec.lua b/test/functional/legacy/debugger_spec.lua index c6f552ab51..624e797f1c 100644 --- a/test/functional/legacy/debugger_spec.lua +++ b/test/functional/legacy/debugger_spec.lua @@ -14,7 +14,6 @@ describe('debugger', function() before_each(function() screen = Screen.new(999, 10) - screen:attach() end) -- oldtest: Test_Debugger_breakadd_expr() diff --git a/test/functional/legacy/digraph_spec.lua b/test/functional/legacy/digraph_spec.lua index ed1071079c..a90eb48f17 100644 --- a/test/functional/legacy/digraph_spec.lua +++ b/test/functional/legacy/digraph_spec.lua @@ -10,7 +10,6 @@ describe('digraph', function() -- oldtest: Test_entering_digraph() it('characters displayed on the screen', function() local screen = Screen.new(10, 6) - screen:attach() feed('i<C-K>') screen:expect([[ {18:^?} | diff --git a/test/functional/legacy/display_spec.lua b/test/functional/legacy/display_spec.lua index 98b9596847..945cd21710 100644 --- a/test/functional/legacy/display_spec.lua +++ b/test/functional/legacy/display_spec.lua @@ -12,7 +12,6 @@ describe('display', function() -- oldtest: Test_display_scroll_at_topline() it('scroll when modified at topline vim-patch:8.2.1488', function() local screen = Screen.new(20, 4) - screen:attach() command([[call setline(1, repeat('a', 21))]]) feed('O') @@ -27,7 +26,6 @@ describe('display', function() -- oldtest: Test_display_scroll_update_visual() it('scrolling when modified at topline in Visual mode vim-patch:8.2.4626', function() local screen = Screen.new(60, 8) - screen:attach() exec([[ set scrolloff=0 @@ -52,7 +50,6 @@ describe('display', function() [2] = { bold = true, reverse = true }, -- StatusLine [3] = { reverse = true }, -- StatusLineNC }) - screen:attach() exec([[ call setline(1, ['aaa', 'b'->repeat(200)]) set display=truncate @@ -131,7 +128,6 @@ describe('display', function() -- oldtest: Test_display_long_lastline() it('"lastline" shows correct text when end of wrapped line is deleted', function() local screen = Screen.new(35, 14) - screen:attach() exec([[ set display=lastline smoothscroll scrolloff=0 call setline(1, [ @@ -183,7 +179,6 @@ describe('display', function() -- 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', 'b ' .. 'bbbbb'->repeat(150), 'c']) norm $j diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua index 2d98188f9b..d2ce80efda 100644 --- a/test/functional/legacy/edit_spec.lua +++ b/test/functional/legacy/edit_spec.lua @@ -31,7 +31,6 @@ describe('edit', function() -- oldtest: Test_edit_insert_reg() it('inserting a register using CTRL-R', function() local screen = Screen.new(10, 6) - screen:attach() feed('a<C-R>') screen:expect([[ {18:^"} | @@ -55,7 +54,6 @@ describe('edit', function() -- oldtest: Test_edit_ctrl_r_failed() it('positioning cursor after CTRL-R expression failed', function() local screen = Screen.new(60, 6) - screen:attach() feed('i<C-R>') screen:expect([[ diff --git a/test/functional/legacy/ex_mode_spec.lua b/test/functional/legacy/ex_mode_spec.lua index e033898d7a..af4490e7f2 100644 --- a/test/functional/legacy/ex_mode_spec.lua +++ b/test/functional/legacy/ex_mode_spec.lua @@ -47,7 +47,6 @@ describe('Ex mode', function() it('substitute confirmation prompt', function() command('set noincsearch nohlsearch inccommand=') local screen = Screen.new(60, 6) - screen:attach() command([[call setline(1, repeat(['foo foo'], 4))]]) command([[set number]]) feed('gQ') @@ -134,7 +133,6 @@ describe('Ex mode', function() it('pressing Ctrl-C in :append inside a loop in Ex mode does not hang', function() local screen = Screen.new(60, 6) - screen:attach() feed('gQ') feed('for i in range(1)<CR>') feed('append<CR>') diff --git a/test/functional/legacy/excmd_spec.lua b/test/functional/legacy/excmd_spec.lua index 753a45ee05..24b648c3c5 100644 --- a/test/functional/legacy/excmd_spec.lua +++ b/test/functional/legacy/excmd_spec.lua @@ -19,7 +19,6 @@ describe(':confirm command dialog', function() local function start_new() clear() screen = Screen.new(75, 20) - screen:attach() end -- Test for the :confirm command dialog diff --git a/test/functional/legacy/fold_spec.lua b/test/functional/legacy/fold_spec.lua index 4fea1ef113..2bad70e384 100644 --- a/test/functional/legacy/fold_spec.lua +++ b/test/functional/legacy/fold_spec.lua @@ -14,7 +14,6 @@ describe('folding', function() n.clear() screen = Screen.new(45, 8) - screen:attach() end) it('creation, opening, moving (to the end) and closing', function() diff --git a/test/functional/legacy/global_spec.lua b/test/functional/legacy/global_spec.lua index 718fd421b0..a39e7d5d38 100644 --- a/test/functional/legacy/global_spec.lua +++ b/test/functional/legacy/global_spec.lua @@ -12,7 +12,6 @@ describe(':global', function() -- oldtest: Test_interrupt_global() it('can be interrupted using Ctrl-C in cmdline mode vim-patch:9.0.0082', function() local screen = Screen.new(75, 6) - screen:attach() exec([[ set nohlsearch noincsearch diff --git a/test/functional/legacy/highlight_spec.lua b/test/functional/legacy/highlight_spec.lua index 35afd9bb4a..e663931bd7 100644 --- a/test/functional/legacy/highlight_spec.lua +++ b/test/functional/legacy/highlight_spec.lua @@ -15,7 +15,6 @@ before_each(clear) describe(':highlight', function() it('is working', function() local screen = Screen.new(35, 10) - screen:attach() -- Basic test if ":highlight" doesn't crash feed_command('set more') feed(':highlight<CR>') @@ -101,7 +100,6 @@ describe('Visual selection highlight', function() -- oldtest: Test_visual_sbr() it("when 'showbreak' is set", function() local screen = Screen.new(60, 6) - screen:attach() exec([[ set showbreak=> call setline(1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.') diff --git a/test/functional/legacy/listchars_spec.lua b/test/functional/legacy/listchars_spec.lua index db9ec7fc9d..b4d07e03ef 100644 --- a/test/functional/legacy/listchars_spec.lua +++ b/test/functional/legacy/listchars_spec.lua @@ -103,7 +103,6 @@ describe("'listchars'", function() it('"exceeds" character does not appear in foldcolumn vim-patch:8.2.3121', function() local screen = Screen.new(60, 10) - screen:attach() exec([[ call setline(1, ['aaa', '', 'a', 'aaaaaa']) vsplit diff --git a/test/functional/legacy/listlbr_spec.lua b/test/functional/legacy/listlbr_spec.lua index da641c3b6f..09835bf97d 100644 --- a/test/functional/legacy/listlbr_spec.lua +++ b/test/functional/legacy/listlbr_spec.lua @@ -205,7 +205,6 @@ describe('listlbr', function() -- oldtest: Test_linebreak_reset_restore() it('cursor position is drawn correctly after operator', function() local screen = Screen.new(60, 6) - screen:attach() -- f_wincol() calls validate_cursor() source([[ diff --git a/test/functional/legacy/listlbr_utf8_spec.lua b/test/functional/legacy/listlbr_utf8_spec.lua index 74cc594cc1..3a0aa7b2b3 100644 --- a/test/functional/legacy/listlbr_utf8_spec.lua +++ b/test/functional/legacy/listlbr_utf8_spec.lua @@ -215,7 +215,6 @@ describe('linebreak', function() -- oldtest: Test_visual_ends_before_showbreak() it("Visual area is correct when it ends before multibyte 'showbreak'", function() local screen = Screen.new(60, 8) - screen:attach() exec([[ let &wrap = v:true let &linebreak = v:true diff --git a/test/functional/legacy/mapping_spec.lua b/test/functional/legacy/mapping_spec.lua index 3fc324f66a..8593868c83 100644 --- a/test/functional/legacy/mapping_spec.lua +++ b/test/functional/legacy/mapping_spec.lua @@ -196,7 +196,6 @@ describe('mapping', function() -- oldtest: Test_showcmd_part_map() it("'showcmd' with a partial mapping", function() local screen = Screen.new(60, 6) - screen:attach() exec([[ set notimeout showcmd nnoremap ,a <Ignore> diff --git a/test/functional/legacy/match_spec.lua b/test/functional/legacy/match_spec.lua index 0fc8708244..64e223ab8c 100644 --- a/test/functional/legacy/match_spec.lua +++ b/test/functional/legacy/match_spec.lua @@ -11,7 +11,6 @@ describe('matchaddpos()', function() -- oldtest: Test_matchaddpos_dump() it('can add more than 8 match positions vim-patch:9.0.0620', function() local screen = Screen.new(60, 14) - screen:attach() exec([[ call setline(1, ['1234567890123']->repeat(14)) call matchaddpos('Search', range(1, 12)->map({i, v -> [v, v]})) @@ -39,7 +38,6 @@ describe('match highlighting', function() -- oldtest: Test_match_in_linebreak() it('does not continue in linebreak vim-patch:8.2.3698', function() local screen = Screen.new(75, 10) - screen:attach() exec([=[ set breakindent linebreak breakat+=] call printf('%s]%s', repeat('x', 50), repeat('x', 70))->setline(1) @@ -55,7 +53,6 @@ describe('match highlighting', function() it('is shown with incsearch vim-patch:8.2.3940', function() local screen = Screen.new(75, 6) - screen:attach() exec([[ set incsearch call setline(1, range(20)) @@ -82,7 +79,6 @@ describe('match highlighting', function() it('on a Tab vim-patch:8.2.4062', function() local screen = Screen.new(75, 10) - screen:attach() exec([[ set linebreak call setline(1, "\tix") diff --git a/test/functional/legacy/matchparen_spec.lua b/test/functional/legacy/matchparen_spec.lua index df0d80f0ab..d992420c30 100644 --- a/test/functional/legacy/matchparen_spec.lua +++ b/test/functional/legacy/matchparen_spec.lua @@ -11,7 +11,6 @@ describe('matchparen', function() -- oldtest: Test_visual_block_scroll() it('redraws properly after scrolling with scrolloff=1', function() local screen = Screen.new(30, 7) - screen:attach() exec([[ source $VIMRUNTIME/plugin/matchparen.vim set scrolloff=1 @@ -34,20 +33,18 @@ describe('matchparen', function() -- oldtest: Test_matchparen_clear_highlight() it('matchparen highlight is cleared when switching buffer', function() local screen = Screen.new(20, 5) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.Cyan }, - }) - screen:attach() + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Cyan1 }, + } local screen1 = [[ - {1:^()} | - {0:~ }|*3 + {100:^()} | + {1:~ }|*3 | ]] local screen2 = [[ ^aa | - {0:~ }|*3 + {1:~ }|*3 | ]] @@ -77,12 +74,9 @@ describe('matchparen', function() -- oldtest: Test_matchparen_win_execute() it('matchparen highlight when switching buffer in win_execute()', function() local screen = Screen.new(20, 5) - screen:set_default_attr_ids({ - [1] = { background = Screen.colors.Cyan }, - [2] = { reverse = true, bold = true }, - [3] = { reverse = true }, - }) - screen:attach() + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Cyan1 }, + } exec([[ source $VIMRUNTIME/plugin/matchparen.vim @@ -95,10 +89,10 @@ describe('matchparen', function() endfunc ]]) screen:expect([[ - {1:^{}} | - {2:[No Name] [+] }| - {} | + {100:^{}} | {3:[No Name] [+] }| + {} | + {2:[No Name] [+] }| | ]]) @@ -110,7 +104,6 @@ describe('matchparen', function() -- oldtest: Test_matchparen_pum_clear() it('is cleared when completion popup is shown', function() local screen = Screen.new(30, 9) - screen:attach() exec([[ source $VIMRUNTIME/plugin/matchparen.vim @@ -136,12 +129,9 @@ describe('matchparen', function() -- oldtest: Test_matchparen_mbyte() it("works with multibyte chars in 'matchpairs'", function() local screen = Screen.new(30, 10) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.Cyan }, - [2] = { bold = true }, - }) - screen:attach() + screen:add_extra_attr_ids { + [100] = { background = Screen.colors.Cyan1 }, + } exec([[ source $VIMRUNTIME/plugin/matchparen.vim @@ -152,57 +142,57 @@ describe('matchparen', function() screen:expect([[ ^aaaaaaaa( | bbbb)cc | - {0:~ }|*7 + {1:~ }|*7 | ]]) feed('$') screen:expect([[ - aaaaaaaa{1:^(} | - bbbb{1:)}cc | - {0:~ }|*7 + aaaaaaaa{100:^(} | + bbbb{100:)}cc | + {1:~ }|*7 | ]]) feed('j') screen:expect([[ aaaaaaaa( | bbbb)c^c | - {0:~ }|*7 + {1:~ }|*7 | ]]) feed('2h') screen:expect([[ - aaaaaaaa{1:(} | - bbbb{1:^)}cc | - {0:~ }|*7 + aaaaaaaa{100:(} | + bbbb{100:^)}cc | + {1:~ }|*7 | ]]) feed('0') screen:expect([[ aaaaaaaa( | ^bbbb)cc | - {0:~ }|*7 + {1:~ }|*7 | ]]) feed('kA') screen:expect([[ - aaaaaaaa{1:(}^ | - bbbb{1:)}cc | - {0:~ }|*7 - {2:-- INSERT --} | + aaaaaaaa{100:(}^ | + bbbb{100:)}cc | + {1:~ }|*7 + {5:-- INSERT --} | ]]) feed('<Down>') screen:expect([[ aaaaaaaa( | bbbb)cc^ | - {0:~ }|*7 - {2:-- INSERT --} | + {1:~ }|*7 + {5:-- INSERT --} | ]]) feed('<C-W>') screen:expect([[ - aaaaaaaa{1:(} | - bbbb{1:)}^ | - {0:~ }|*7 - {2:-- INSERT --} | + aaaaaaaa{100:(} | + bbbb{100:)}^ | + {1:~ }|*7 + {5:-- INSERT --} | ]]) end) end) diff --git a/test/functional/legacy/messages_spec.lua b/test/functional/legacy/messages_spec.lua index 2f3693b5ad..bc58551a34 100644 --- a/test/functional/legacy/messages_spec.lua +++ b/test/functional/legacy/messages_spec.lua @@ -17,7 +17,6 @@ describe('messages', function() -- oldtest: Test_warning_scroll() it('a warning causes scrolling if and only if it has a stacktrace', function() screen = Screen.new(75, 6) - screen:attach() -- When the warning comes from a script, messages are scrolled so that the -- stacktrace is visible. @@ -45,7 +44,6 @@ describe('messages', function() -- oldtest: Test_message_not_cleared_after_mode() it('clearing mode does not remove message', function() screen = Screen.new(60, 10) - screen:attach() exec([[ nmap <silent> gx :call DebugSilent('normal')<CR> vmap <silent> gx :call DebugSilent('visual')<CR> @@ -101,7 +99,6 @@ describe('messages', function() [1] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg [2] = { foreground = Screen.colors.Brown }, -- LineNr }) - screen:attach() command('call setline(1, range(1, 100))') @@ -394,7 +391,6 @@ describe('messages', function() -- oldtest: Test_echo_verbose_system() it('verbose message before echo command', function() screen = Screen.new(60, 10) - screen:attach() command('cd ' .. nvim_dir) api.nvim_set_option_value('shell', './shell-test', {}) @@ -494,7 +490,6 @@ describe('messages', function() -- oldtest: Test_quit_long_message() it('with control characters can be quit vim-patch:8.2.1844', function() screen = Screen.new(40, 10) - screen:attach() feed([[:echom range(9999)->join("\x01")<CR>]]) screen:expect([[ @@ -521,7 +516,6 @@ describe('messages', function() describe('mode is cleared when', function() before_each(function() screen = Screen.new(40, 6) - screen:attach() end) -- oldtest: Test_mode_message_at_leaving_insert_by_ctrl_c() @@ -591,7 +585,6 @@ describe('messages', function() -- oldtest: Test_ask_yesno() it('y/n prompt works', function() screen = Screen.new(75, 6) - screen:attach() command('set noincsearch nohlsearch inccommand=') command('call setline(1, range(1, 2))') @@ -644,7 +637,6 @@ describe('messages', function() -- oldtest: Test_fileinfo_tabpage_cmdheight() it("fileinfo works when 'cmdheight' has just decreased", function() screen = Screen.new(40, 6) - screen:attach() exec([[ set shortmess-=o @@ -673,7 +665,6 @@ describe('messages', function() -- oldtest: Test_fileinfo_after_echo() it('fileinfo does not overwrite echo message vim-patch:8.2.4156', function() screen = Screen.new(40, 6) - screen:attach() exec([[ set shortmess-=F diff --git a/test/functional/legacy/move_spec.lua b/test/functional/legacy/move_spec.lua index c2be8bb3eb..ae01193049 100644 --- a/test/functional/legacy/move_spec.lua +++ b/test/functional/legacy/move_spec.lua @@ -11,7 +11,6 @@ describe(':move', function() -- oldtest: Test_move_undo() it('redraws correctly when undone', function() local screen = Screen.new(60, 10) - screen:attach() fn.setline(1, { 'First', 'Second', 'Third', 'Fourth' }) feed('gg:move +1<CR>') diff --git a/test/functional/legacy/normal_spec.lua b/test/functional/legacy/normal_spec.lua index 5158ca3009..1ae22a83bd 100644 --- a/test/functional/legacy/normal_spec.lua +++ b/test/functional/legacy/normal_spec.lua @@ -15,7 +15,6 @@ describe('normal', function() before_each(function() clear() screen = Screen.new(40, 19) - screen:attach() end) -- oldtest: Test_normal_j_below_botline() @@ -103,4 +102,33 @@ describe('normal', function() ]], }) end) + + -- oldtest: Test_normal_gm() + it('gm sets curswant correctly', function() + screen:try_resize(75, 10) + exec([[ + call setline(1, repeat([" abcd\tefgh\tij"], 10)) + call cursor(1, 1) + ]]) + feed('jVjzf') + -- gm + feed('gmk') + eq(18, fn.virtcol('.')) + -- g0 + feed('gj0k') + eq(1, fn.virtcol('.')) + -- g^ + feed('jg^k') + eq(3, fn.virtcol('.')) + exec('call cursor(10, 1)') + -- gm + feed('gmk') + eq(18, fn.virtcol('.')) + -- g0 + feed('gj0k') + eq(1, fn.virtcol('.')) + -- g^ + feed('jg^k') + eq(3, fn.virtcol('.')) + end) end) diff --git a/test/functional/legacy/number_spec.lua b/test/functional/legacy/number_spec.lua index 0ebd731f65..4636cd0369 100644 --- a/test/functional/legacy/number_spec.lua +++ b/test/functional/legacy/number_spec.lua @@ -17,7 +17,6 @@ describe("'number' and 'relativenumber'", function() [2] = { foreground = Screen.colors.Blue }, [3] = { foreground = Screen.colors.Green }, }) - screen:attach() exec([[ call setline(1, range(200)) 111 @@ -86,7 +85,6 @@ describe("'number' and 'relativenumber'", function() [3] = { background = Screen.colors.Green, foreground = Screen.colors.Black }, [4] = { bold = true, foreground = Screen.colors.Blue }, }) - screen:attach() exec([[ set display=lastline scrolloff=0 call setline(1, range(200)->map('v:val->string()->repeat(40)')) @@ -215,7 +213,6 @@ describe("'number' and 'relativenumber'", function() -- oldtest: Test_relativenumber_callback() it('relative line numbers are updated if cursor is moved from timer', function() local screen = Screen.new(50, 8) - screen:attach() exec([[ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd']) set relativenumber @@ -253,7 +250,6 @@ describe("'number' and 'relativenumber'", function() -- oldtest: Test_number_insert_delete_lines() it('line numbers are updated when deleting/inserting lines', function() local screen = Screen.new(50, 8) - screen:attach() exec([[ call setline(1, range(1, 7)) set number diff --git a/test/functional/legacy/options_spec.lua b/test/functional/legacy/options_spec.lua index e9a3b73cf7..fa84e0db66 100644 --- a/test/functional/legacy/options_spec.lua +++ b/test/functional/legacy/options_spec.lua @@ -32,8 +32,7 @@ describe('set', function() end) it('winminheight works', function() - local screen = Screen.new(20, 11) - screen:attach() + local _ = Screen.new(20, 11) source([[ set wmh=0 stal=2 below sp | wincmd _ @@ -45,8 +44,7 @@ describe('set', function() end) it('winminheight works with tabline', function() - local screen = Screen.new(20, 11) - screen:attach() + local _ = Screen.new(20, 11) source([[ set wmh=0 stal=2 split @@ -60,7 +58,6 @@ describe('set', function() it('scroll works', function() local screen = Screen.new(42, 16) - screen:attach() source([[ set scroll=2 set laststatus=2 diff --git a/test/functional/legacy/prompt_buffer_spec.lua b/test/functional/legacy/prompt_buffer_spec.lua index 72ec420b15..6a4d5fe7f7 100644 --- a/test/functional/legacy/prompt_buffer_spec.lua +++ b/test/functional/legacy/prompt_buffer_spec.lua @@ -18,7 +18,6 @@ describe('prompt buffer', function() before_each(function() clear() screen = Screen.new(25, 10) - screen:attach() command('set laststatus=0 nohidden') end) @@ -68,10 +67,6 @@ describe('prompt buffer', function() ]]) end - after_each(function() - screen:detach() - end) - -- oldtest: Test_prompt_basic() it('works', function() source_script() diff --git a/test/functional/legacy/put_spec.lua b/test/functional/legacy/put_spec.lua index 8b9b495679..2656142176 100644 --- a/test/functional/legacy/put_spec.lua +++ b/test/functional/legacy/put_spec.lua @@ -10,7 +10,6 @@ describe('put', function() -- 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' @@ -36,7 +35,6 @@ describe('put', function() -- 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) diff --git a/test/functional/legacy/scroll_opt_spec.lua b/test/functional/legacy/scroll_opt_spec.lua index ec1dc59d53..a92b95731e 100644 --- a/test/functional/legacy/scroll_opt_spec.lua +++ b/test/functional/legacy/scroll_opt_spec.lua @@ -13,7 +13,6 @@ describe('smoothscroll', function() before_each(function() screen = Screen.new(40, 12) - screen:attach() end) -- oldtest: Test_CtrlE_CtrlY_stop_at_end() diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua index d421a96579..db7d6bc34b 100644 --- a/test/functional/legacy/search_spec.lua +++ b/test/functional/legacy/search_spec.lua @@ -18,7 +18,6 @@ describe('search cmdline', function() clear() command('set nohlsearch inccommand=') screen = Screen.new(20, 3) - screen:attach() screen:set_default_attr_ids({ inc = { reverse = true }, err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, @@ -747,7 +746,6 @@ describe('Search highlight', function() -- oldtest: Test_hlsearch_dump() it('beyond line end vim-patch:8.2.2542', function() local screen = Screen.new(50, 6) - screen:attach() exec([[ set hlsearch noincsearch cursorline call setline(1, ["xxx", "xxx", "xxx"]) @@ -773,7 +771,6 @@ describe('Search highlight', function() [4] = { background = Screen.colors.Yellow, bold = true }, -- Search [5] = { background = Screen.colors.LightGrey, bold = true, foreground = Screen.colors.Black }, }) - screen:attach() exec([[ set hlsearch noincsearch call setline(1, repeat(["xxx yyy zzz"], 3)) diff --git a/test/functional/legacy/search_stat_spec.lua b/test/functional/legacy/search_stat_spec.lua index 7779b8bef1..1ffae89b0c 100644 --- a/test/functional/legacy/search_stat_spec.lua +++ b/test/functional/legacy/search_stat_spec.lua @@ -15,7 +15,6 @@ describe('search stat', function() [4] = { reverse = true }, -- IncSearch, TabLineFill [5] = { foreground = Screen.colors.Red }, -- WarningMsg }) - screen:attach() end) -- oldtest: Test_search_stat_screendump() diff --git a/test/functional/legacy/signs_spec.lua b/test/functional/legacy/signs_spec.lua index 27145f4c91..ac7c8cd0bc 100644 --- a/test/functional/legacy/signs_spec.lua +++ b/test/functional/legacy/signs_spec.lua @@ -26,7 +26,6 @@ describe('signs', function() -- oldtest: Test_sign_cursor_position() it('are drawn correctly', function() local screen = Screen.new(75, 6) - screen:attach() exec([[ call setline(1, [repeat('x', 75), 'mmmm', 'yyyy']) call cursor(2,1) diff --git a/test/functional/legacy/source_spec.lua b/test/functional/legacy/source_spec.lua index a910dc3d43..7358ba2d57 100644 --- a/test/functional/legacy/source_spec.lua +++ b/test/functional/legacy/source_spec.lua @@ -18,7 +18,6 @@ describe(':source!', function() ]] ) local screen = Screen.new(75, 6) - screen:attach() feed(':source! Xscript.vim\n') screen:expect([[ ^ | diff --git a/test/functional/legacy/statusline_spec.lua b/test/functional/legacy/statusline_spec.lua index 148166fdc3..0bc77fe67e 100644 --- a/test/functional/legacy/statusline_spec.lua +++ b/test/functional/legacy/statusline_spec.lua @@ -12,7 +12,6 @@ describe('statusline', function() before_each(function() screen = Screen.new(50, 7) - screen:attach() end) it('is updated in cmdline mode when using window-local statusline vim-patch:8.2.2737', function() diff --git a/test/functional/legacy/substitute_spec.lua b/test/functional/legacy/substitute_spec.lua index 647d62782c..0081371f7f 100644 --- a/test/functional/legacy/substitute_spec.lua +++ b/test/functional/legacy/substitute_spec.lua @@ -211,7 +211,6 @@ describe(':substitute', function() it('first char is highlighted with confirmation dialog and empty match', function() local screen = Screen.new(60, 8) - screen:attach() exec([[ set nohlsearch noincsearch call setline(1, ['one', 'two', 'three']) diff --git a/test/functional/legacy/tabline_spec.lua b/test/functional/legacy/tabline_spec.lua index 4ce32f2fdd..949bec6dea 100644 --- a/test/functional/legacy/tabline_spec.lua +++ b/test/functional/legacy/tabline_spec.lua @@ -12,7 +12,6 @@ describe('tabline', function() before_each(function() screen = Screen.new(50, 7) - screen:attach() end) -- oldtest: Test_tabline_showcmd() diff --git a/test/functional/legacy/vimscript_spec.lua b/test/functional/legacy/vimscript_spec.lua index 66054810a6..e2e3493be8 100644 --- a/test/functional/legacy/vimscript_spec.lua +++ b/test/functional/legacy/vimscript_spec.lua @@ -12,7 +12,6 @@ describe('Vim script', function() -- oldtest: Test_deep_nest() it('Error when if/for/while/try/function is nested too deep', function() local screen = Screen.new(80, 24) - screen:attach() api.nvim_set_option_value('laststatus', 2, {}) exec([[ " Deep nesting of if ... endif @@ -84,7 +83,6 @@ describe('Vim script', function() -- oldtest: Test_typed_script_var() it('using s: with a typed command', function() local screen = Screen.new(80, 24) - screen:attach() feed(":echo get(s:, 'foo', 'x')\n") screen:expect({ any = 'E116: ' }) end) diff --git a/test/functional/legacy/visual_spec.lua b/test/functional/legacy/visual_spec.lua index ab2213b2fc..e52d12bba9 100644 --- a/test/functional/legacy/visual_spec.lua +++ b/test/functional/legacy/visual_spec.lua @@ -12,7 +12,6 @@ describe('Visual highlight', function() before_each(function() screen = Screen.new(50, 6) - screen:attach() end) -- oldtest: Test_visual_block_with_virtualedit() diff --git a/test/functional/legacy/window_cmd_spec.lua b/test/functional/legacy/window_cmd_spec.lua index 332240d04a..d68c780f49 100644 --- a/test/functional/legacy/window_cmd_spec.lua +++ b/test/functional/legacy/window_cmd_spec.lua @@ -11,7 +11,6 @@ local feed = n.feed it('scrolling with laststatus=0 and :botright split', function() clear('--cmd', 'set ruler') local screen = Screen.new(40, 10) - screen:attach() exec([[ set laststatus=0 call setline(1, range(1, 100)) @@ -38,7 +37,6 @@ describe('splitkeep', function() before_each(function() clear('--cmd', 'set splitkeep=screen') screen = Screen.new() - screen:attach() end) -- oldtest: Test_splitkeep_cursor() diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index f277868b1c..7d034222c8 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -344,7 +344,6 @@ describe('lua buffer event callbacks: on_lines', function() it('setting extmark in on_lines callback works', function() local screen = Screen.new(40, 6) - screen:attach() api.nvim_buf_set_lines(0, 0, -1, true, { 'aaa', 'bbb', 'ccc' }) exec_lua(function() diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 456ee13da2..1fd01cfd5a 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -111,7 +111,6 @@ describe(':lua', function() it('can show multiline error messages', function() local screen = Screen.new(40, 10) - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { bold = true, reverse = true }, @@ -204,7 +203,6 @@ describe(':lua', function() it('with range', function() local screen = Screen.new(40, 10) - screen:attach() api.nvim_buf_set_lines(0, 0, 0, 0, { 'nonsense', 'function x() print "hello" end', 'x()' }) -- ":{range}lua" fails on invalid Lua code. diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 4ae1146703..eb1ac3e6a1 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -111,6 +111,19 @@ describe('vim.diagnostic', function() { details = true } ) end + + ---@param ns integer + function _G.get_underline_extmarks(ns) + ---@type integer + local underline_ns = vim.diagnostic.get_namespace(ns).user_data.underline_ns + return vim.api.nvim_buf_get_extmarks( + _G.diagnostic_bufnr, + underline_ns, + 0, + -1, + { details = true } + ) + end end) exec_lua(function() @@ -1813,6 +1826,21 @@ describe('vim.diagnostic', function() _G.make_info('Info', 4, 4, 4, 4), }) + function _G.get_highest_underline_hl(severity_sort) + vim.diagnostic.config({ + underline = true, + severity_sort = severity_sort, + }) + + local extmarks = _G.get_underline_extmarks(_G.diagnostic_ns) + + table.sort(extmarks, function(a, b) + return a[4].priority > b[4].priority + end) + + return extmarks[1][4].hl_group + end + function _G.get_virt_text_and_signs(severity_sort) vim.diagnostic.config({ severity_sort = severity_sort, @@ -1864,6 +1892,12 @@ describe('vim.diagnostic', function() result = exec_lua [[return _G.get_virt_text_and_signs({ reverse = true })]] eq({ 'Error', 'Warn', 'Info' }, result[1]) eq({ 'Info', 'Warn', 'Error' }, result[2]) + + local underline_hl = exec_lua [[return _G.get_highest_underline_hl(true)]] + eq('DiagnosticUnderlineError', underline_hl) + + underline_hl = exec_lua [[return _G.get_highest_underline_hl({ reverse = true })]] + eq('DiagnosticUnderlineInfo', underline_hl) end) it('can show diagnostic sources in virtual text', function() diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua index 574c837f92..b6011d5268 100644 --- a/test/functional/lua/filetype_spec.lua +++ b/test/functional/lua/filetype_spec.lua @@ -161,6 +161,18 @@ describe('vim.filetype', function() end end end) + + it('.get_option() cleans up buffer on error', function() + api.nvim_create_autocmd('FileType', { pattern = 'foo', command = 'lua error()' }) + + local buf = api.nvim_get_current_buf() + + exec_lua(function() + pcall(vim.filetype.get_option, 'foo', 'lisp') + end) + + eq(buf, api.nvim_get_current_buf()) + end) end) describe('filetype.lua', function() diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/hl_spec.lua index c048949df8..89881973bf 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/hl_spec.lua @@ -9,7 +9,7 @@ local command = n.command local clear = n.clear local api = n.api -describe('vim.highlight.range', function() +describe('vim.hl.range', function() local screen before_each(function() @@ -18,7 +18,6 @@ describe('vim.highlight.range', function() screen:add_extra_attr_ids({ [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true }, }) - screen:attach() api.nvim_set_option_value('list', true, {}) api.nvim_set_option_value('listchars', 'eol:$', {}) api.nvim_buf_set_lines(0, 0, -1, true, { @@ -33,7 +32,7 @@ describe('vim.highlight.range', function() it('works with charwise selection', function() exec_lua(function() local ns = vim.api.nvim_create_namespace('') - vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 }) + vim.hl.range(0, ns, 'Search', { 1, 5 }, { 3, 10 }) end) screen:expect([[ ^asdfghjkl{1:$} | @@ -48,7 +47,7 @@ describe('vim.highlight.range', function() it('works with linewise selection', function() exec_lua(function() local ns = vim.api.nvim_create_namespace('') - vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' }) + vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' }) end) screen:expect([[ {10:^asdfghjkl}{100:$} | @@ -63,7 +62,7 @@ describe('vim.highlight.range', function() it('works with blockwise selection', function() exec_lua(function() local ns = vim.api.nvim_create_namespace('') - vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' }) + vim.hl.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' }) end) screen:expect([[ {10:^asdf}ghjkl{1:$} | @@ -78,7 +77,7 @@ describe('vim.highlight.range', function() it('works with blockwise selection with width', function() exec_lua(function() local ns = vim.api.nvim_create_namespace('') - vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' }) + vim.hl.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' }) end) screen:expect([[ ^asdf{10:ghjkl}{1:$} | @@ -93,8 +92,8 @@ describe('vim.highlight.range', function() it('can use -1 or v:maxcol to indicate end of line', function() exec_lua(function() local ns = vim.api.nvim_create_namespace('') - vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {}) - vim.highlight.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {}) + vim.hl.range(0, ns, 'Search', { 0, 4 }, { 1, -1 }, {}) + vim.hl.range(0, ns, 'Search', { 2, 6 }, { 3, vim.v.maxcol }, {}) end) screen:expect([[ ^asdf{10:ghjkl}{100:$} | @@ -107,7 +106,7 @@ describe('vim.highlight.range', function() end) end) -describe('vim.highlight.on_yank', function() +describe('vim.hl.on_yank', function() before_each(function() clear() end) @@ -115,7 +114,7 @@ describe('vim.highlight.on_yank', function() it('does not show errors even if buffer is wiped before timeout', function() command('new') exec_lua(function() - vim.highlight.on_yank({ + vim.hl.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y', regtype = 'v' }, @@ -129,10 +128,10 @@ describe('vim.highlight.on_yank', function() it('does not close timer twice', function() exec_lua(function() - vim.highlight.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } }) + vim.hl.on_yank({ timeout = 10, on_macro = true, event = { operator = 'y' } }) vim.uv.sleep(10) vim.schedule(function() - vim.highlight.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) + vim.hl.on_yank({ timeout = 0, on_macro = true, event = { operator = 'y' } }) end) end) eq('', eval('v:errmsg')) @@ -143,7 +142,7 @@ describe('vim.highlight.on_yank', function() exec_lua(function() vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) - vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) + vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) end) local ns = api.nvim_create_namespace('hlyank') local win = api.nvim_get_current_win() @@ -157,7 +156,7 @@ describe('vim.highlight.on_yank', function() exec_lua(function() vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) - vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) + vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) end) local ns = api.nvim_create_namespace('hlyank') eq(api.nvim_get_current_win(), api.nvim__ns_get(ns).wins[1]) @@ -165,7 +164,7 @@ describe('vim.highlight.on_yank', function() exec_lua(function() vim.api.nvim_buf_set_mark(0, '[', 1, 1, {}) vim.api.nvim_buf_set_mark(0, ']', 1, 1, {}) - vim.highlight.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) + vim.hl.on_yank({ timeout = math.huge, on_macro = true, event = { operator = 'y' } }) end) local win = api.nvim_get_current_win() eq({ win }, api.nvim__ns_get(ns).wins) diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua index de8200a5f1..52a8fec0bf 100644 --- a/test/functional/lua/loop_spec.lua +++ b/test/functional/lua/loop_spec.lua @@ -65,7 +65,6 @@ describe('vim.uv', function() it('is API safe', function() local screen = Screen.new(50, 10) - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { bold = true, reverse = true }, @@ -88,9 +87,9 @@ describe('vim.uv', function() screen:expect([[ | {2: }| - {3:Error executing luv callback:} | + {3:Error executing callback:} | {3:[string "<nvim>"]:5: E5560: nvim_set_var must not }| - {3:be called in a lua loop callback} | + {3:be called in a fast event context} | {3:stack traceback:} | {3: [C]: in function 'nvim_set_var'} | {3: [string "<nvim>"]:5: in function <[string }| diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua index 2b23f72c7d..5fea79141c 100644 --- a/test/functional/lua/luaeval_spec.lua +++ b/test/functional/lua/luaeval_spec.lua @@ -510,7 +510,6 @@ describe('v:lua', function() it('works in func options', function() local screen = Screen.new(60, 8) - screen:attach() api.nvim_set_option_value('omnifunc', 'v:lua.mymod.omni', {}) feed('isome st<c-x><c-o>') screen:expect{grid=[[ diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua index 33a2813200..2f332d2c10 100644 --- a/test/functional/lua/overrides_spec.lua +++ b/test/functional/lua/overrides_spec.lua @@ -158,7 +158,6 @@ describe('print', function() it('blank line in message works', function() local screen = Screen.new(40, 8) - screen:attach() screen:set_default_attr_ids({ [0] = { bold = true, foreground = Screen.colors.Blue }, [1] = { bold = true, foreground = Screen.colors.SeaGreen }, @@ -196,7 +195,6 @@ describe('debug.debug', function() before_each(function() screen = Screen.new() - screen:attach() screen:set_default_attr_ids { [0] = { bold = true, foreground = 255 }, [1] = { bold = true, reverse = true }, diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index f63363d6d9..6705dff847 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -21,7 +21,9 @@ describe('runtime:', function() exec('set rtp+=' .. plug_dir) exec([[ set shell=doesnotexist - set completeslash=slash + if exists('+completeslash') + set completeslash=slash + endif set isfname+=(,) ]]) end) diff --git a/test/functional/lua/secure_spec.lua b/test/functional/lua/secure_spec.lua index c58fd689b7..b40b084ef9 100644 --- a/test/functional/lua/secure_spec.lua +++ b/test/functional/lua/secure_spec.lua @@ -39,7 +39,6 @@ describe('vim.secure', function() it('works', function() local screen = Screen.new(80, 8) - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { bold = true, reverse = true }, diff --git a/test/functional/lua/system_spec.lua b/test/functional/lua/system_spec.lua index 482bfcf1a9..afbada007d 100644 --- a/test/functional/lua/system_spec.lua +++ b/test/functional/lua/system_spec.lua @@ -9,7 +9,7 @@ local function system_sync(cmd, opts) return exec_lua(function() local obj = vim.system(cmd, opts) - if opts.timeout then + if opts and opts.timeout then -- Minor delay before calling wait() so the timeout uv timer can have a headstart over the -- internal call to vim.wait() in wait(). vim.wait(10) @@ -75,7 +75,7 @@ describe('vim.system', function() it('kill processes', function() exec_lua(function() - local signal + local signal --- @type integer? local cmd = vim.system({ 'cat', '-' }, { stdin = true }, function(r) signal = r.signal end) -- run forever @@ -112,4 +112,12 @@ describe('vim.system', function() ) eq(true, exec_lua([[return _G.processed]])) end) + + if t.is_os('win') then + it('can resolve windows command extentions.', function() + t.write_file('test.bat', 'echo hello world') + system_sync({ 'chmod', '+x', 'test.bat' }) + system_sync({ './test' }) + end) + end end) diff --git a/test/functional/lua/thread_spec.lua b/test/functional/lua/thread_spec.lua index cbf23517dc..310705fd97 100644 --- a/test/functional/lua/thread_spec.lua +++ b/test/functional/lua/thread_spec.lua @@ -17,7 +17,6 @@ describe('thread', function() before_each(function() clear() screen = Screen.new(50, 10) - screen:attach() end) it('entry func is executed in protected mode', function() @@ -257,7 +256,6 @@ describe('threadpool', function() it('with invalid return value', function() local screen = Screen.new(50, 10) - screen:attach() exec_lua [[ local work = vim.uv.new_work(function() return {} end, function() end) diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 0a6deaa41c..c8616e3e11 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -32,16 +32,6 @@ describe('vim.ui_attach', function() ]] screen = Screen.new(40, 5) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true }, - [3] = { background = Screen.colors.Grey }, - [4] = { background = Screen.colors.LightMagenta }, - [5] = { reverse = true }, - [6] = { reverse = true, bold = true }, - [7] = { background = Screen.colors.Yellow1 }, - }) - screen:attach() end) local function expect_events(expected) @@ -56,7 +46,7 @@ describe('vim.ui_attach', function() grid = [[ fo^ | {1:~ }|*3 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], } @@ -65,7 +55,7 @@ describe('vim.ui_attach', function() grid = [[ food^ | {1:~ }|*3 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], } expect_events { @@ -84,7 +74,7 @@ describe('vim.ui_attach', function() grid = [[ foobar^ | {1:~ }|*3 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], } expect_events { @@ -106,10 +96,10 @@ describe('vim.ui_attach', function() screen:expect { grid = [[ food^ | - {3:food }{1: }| + {12:food }{1: }| {4:foobar }{1: }| {4:foo }{1: }| - {2:-- INSERT --} | + {5:-- INSERT --} | ]], } expect_events {} @@ -151,9 +141,9 @@ describe('vim.ui_attach', function() { 'msg_history_show', { - { 'echomsg', { { 0, 'message1' } } }, - { '', { { 0, 'message2' } } }, - { 'echomsg', { { 0, 'message3' } } }, + { 'echomsg', { { 0, 'message1', 0 } } }, + { 'lua_print', { { 0, 'message2', 0 } } }, + { 'echomsg', { { 0, 'message3', 0 } } }, }, }, }, actual, vim.inspect(actual)) @@ -181,12 +171,17 @@ describe('vim.ui_attach', function() exec_lua([[ _G.cmdline = 0 vim.ui_attach(ns, { ext_messages = true }, function(ev) - vim.cmd.redraw() + if ev == 'msg_show' then + vim.schedule(function() vim.cmd.redraw() end) + else + vim.cmd.redraw() + end _G.cmdline = _G.cmdline + (ev == 'cmdline_show' and 1 or 0) end )]]) feed(':') - eq(1, exec_lua('return _G.cmdline')) + n.assert_alive() + eq(2, exec_lua('return _G.cmdline')) n.assert_alive() feed('version<CR><CR>v<Esc>') n.assert_alive() @@ -212,9 +207,9 @@ describe('vim.ui_attach', function() screen:expect({ grid = [[ cmdline | - {5:cmdline [+] }| + {2:cmdline [+] }| fooba^r | - {6:[No Name] [+] }| + {3:[No Name] [+] }| | ]], }) @@ -223,9 +218,9 @@ describe('vim.ui_attach', function() screen:expect({ grid = [[ foo | - {5:cmdline [+] }| - {5:foo}ba^r | - {6:[No Name] [+] }| + {2:cmdline [+] }| + {2:foo}ba^r | + {3:[No Name] [+] }| | ]], }) @@ -234,25 +229,78 @@ describe('vim.ui_attach', function() screen:expect({ grid = [[ %s/bar/baz | - {5:cmdline [+] }| - foo{7:ba^z} | - {6:[No Name] [+] }| + {2:cmdline [+] }| + foo{10:ba^z} | + {3:[No Name] [+] }| | ]], }) end) + + it('msg_show in fast context', function() + exec_lua([[ + vim.ui_attach(ns, { ext_messages = true }, function(event, _, content) + if event == "msg_show" then + vim.api.nvim_get_runtime_file("foo", false) + -- non-"fast-api" is not allowed in msg_show callback and should be scheduled + local _, err = pcall(vim.api.nvim_buf_set_lines, 0, -2, -1, false, { content[1][2] }) + pcall(vim.api.nvim__redraw, { flush = true }) + vim.schedule(function() + vim.api.nvim_buf_set_lines(0, -2, -1, false, { content[1][2], err }) + end) + end + end) + ]]) + -- "fast-api" does not prevent aborting :function + feed(':func Foo()<cr>bar<cr>endf<cr>:func Foo()<cr>') + screen:expect({ + grid = [[ + ^E122: Function Foo already exists, add !| + to replace it | + E5560: nvim_buf_set_lines must not be ca| + lled in a fast event context | + {1:~ }| + ]], + messages = { + { + content = { { 'E122: Function Foo already exists, add ! to replace it', 9, 7 } }, + kind = 'emsg', + }, + }, + }) + -- No fast context for prompt message kinds + feed(':%s/Function/Replacement/c<cr>') + screen:expect({ + grid = [[ + ^E122: {10:Function} Foo already exists, add !| + to replace it | + replace with Replacement (y/n/a/q/l/^E/^| + Y)? | + {1:~ }| + ]], + messages = { + { + content = { { 'replace with Replacement (y/n/a/q/l/^E/^Y)?', 6, 19 } }, + kind = 'confirm_sub', + }, + }, + }) + end) end) describe('vim.ui_attach', function() + local screen + before_each(function() + clear({ env = { NVIM_LOG_FILE = testlog } }) + screen = Screen.new(40, 5) + end) + after_each(function() check_close() os.remove(testlog) end) it('error in callback is logged', function() - clear({ env = { NVIM_LOG_FILE = testlog } }) - local screen = Screen.new() - screen:attach() exec_lua([[ local ns = vim.api.nvim_create_namespace('testspace') vim.ui_attach(ns, { ext_popupmenu = true }, function() error(42) end) @@ -260,4 +308,83 @@ describe('vim.ui_attach', function() feed('ifoo<CR>foobar<CR>fo<C-X><C-N>') assert_log('Error executing UI event callback: Error executing lua: .*: 42', testlog, 100) end) + + it('detaches after excessive errors', function() + screen:add_extra_attr_ids({ [100] = { bold = true, foreground = Screen.colors.SeaGreen } }) + exec_lua([[ + vim.ui_attach(vim.api.nvim_create_namespace(''), { ext_messages = true }, function() + vim.api.nvim_buf_set_lines(0, -2, -1, false, { err[1] }) + end) + ]]) + screen:expect({ + grid = [[ + ^ | + {1:~ }|*4 + ]], + }) + feed('ifoo') + screen:expect({ + grid = [[ + foo^ | + {1:~ }|*4 + ]], + showmode = { { '-- INSERT --', 5, 12 } }, + }) + feed('<esc>:1mes clear<cr>:mes<cr>') + screen:expect({ + grid = [[ + foo | + {3: }| + {9:Excessive errors in vim.ui_attach() call}| + {9:back from ns: 1.} | + {100:Press ENTER or type command to continue}^ | + ]], + }) + feed('<cr>') + -- Also when scheduled + exec_lua([[ + vim.ui_attach(vim.api.nvim_create_namespace(''), { ext_messages = true }, function() + vim.schedule(function() vim.api.nvim_buf_set_lines(0, -2, -1, false, { err[1] }) end) + end) + ]]) + screen:expect({ + any = 'fo^o', + messages = { + { + content = { + { + 'Error executing vim.schedule lua callback: [string "<nvim>"]:2: attempt to index global \'err\' (a nil value)\nstack traceback:\n\t[string "<nvim>"]:2: in function <[string "<nvim>"]:2>', + 9, + 7, + }, + }, + kind = 'lua_error', + }, + { + content = { + { + 'Error executing vim.schedule lua callback: [string "<nvim>"]:2: attempt to index global \'err\' (a nil value)\nstack traceback:\n\t[string "<nvim>"]:2: in function <[string "<nvim>"]:2>', + 9, + 7, + }, + }, + kind = 'lua_error', + }, + { + content = { { 'Press ENTER or type command to continue', 100, 19 } }, + kind = 'return_prompt', + }, + }, + }) + feed('<esc>:1mes clear<cr>:mes<cr>') + screen:expect({ + grid = [[ + foo | + {3: }| + {9:Excessive errors in vim.ui_attach() call}| + {9:back from ns: 2.} | + {100:Press ENTER or type command to continue}^ | + ]], + }) + end) end) diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua index d5eede2885..5c727b3347 100644 --- a/test/functional/lua/ui_spec.lua +++ b/test/functional/lua/ui_spec.lua @@ -153,7 +153,7 @@ describe('vim.ui', function() vim.fn.executable = function() return 0 end ]] eq( - 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open)', + 'vim.ui.open: no handler found (tried: wslview, explorer.exe, xdg-open, lemonade)', exec_lua [[local _, err = vim.ui.open('foo') ; return err]] ) end) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 3c65ec664e..3cfbfe167a 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -28,6 +28,7 @@ local rmdir = n.rmdir local write_file = t.write_file local poke_eventloop = n.poke_eventloop local assert_alive = n.assert_alive +local expect = n.expect describe('lua stdlib', function() before_each(clear) @@ -155,10 +156,10 @@ describe('lua stdlib', function() end) it('plugin=nil, no error if soft-deprecated', function() - eq( - vim.NIL, - exec_lua('return vim.deprecate(...)', 'foo.baz()', 'foo.better_baz()', '0.99.0') - ) + eq(vim.NIL, exec_lua [[return vim.deprecate('old1', 'new1', '0.99.0')]]) + -- Major version > current Nvim major is always "soft-deprecated". + -- XXX: This is also a reminder to update the hardcoded `nvim_major`, when Nvim reaches 1.0. + eq(vim.NIL, exec_lua [[return vim.deprecate('old2', 'new2', '1.0.0')]]) end) it('plugin=nil, show error if hard-deprecated', function() @@ -175,13 +176,6 @@ describe('lua stdlib', function() ) end) - it('plugin=nil, to be deleted in the next major version (1.0)', function() - eq( - [[foo.baz() is deprecated. Run ":checkhealth vim.deprecated" for more information]], - exec_lua [[ return vim.deprecate('foo.baz()', nil, '1.0') ]] - ) - end) - it('plugin specified', function() -- When `plugin` is specified, don't show ":help deprecated". #22235 eq( @@ -319,21 +313,106 @@ describe('lua stdlib', function() 49, 51, } + local indices8 = { + [0] = 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + } for i, k in pairs(indices32) do eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ...)', i), i) + eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., false)', i), i) + eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-32", ...)', i), i) end for i, k in pairs(indices16) do eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., true)', i), i) + eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-16", ...)', i), i) end - eq( + for i, k in pairs(indices8) do + eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-8", ...)', i), i) + end + matches( 'index out of range', pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ...)', #indices32 + 1) ) - eq( + matches( 'index out of range', pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ..., true)', #indices16 + 1) ) - local i32, i16 = 0, 0 + matches( + 'index out of range', + pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, "utf-16", ...)', #indices16 + 1) + ) + matches( + 'index out of range', + pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, "utf-32", ...)', #indices32 + 1) + ) + matches( + 'invalid encoding', + pcall_err(exec_lua, 'return vim.str_byteindex("hello", "madeupencoding", 1)') + ) + eq( + indices32[#indices32], + exec_lua('return vim.str_byteindex(_G.test_text, "utf-32", 99999, false)') + ) + eq( + indices16[#indices16], + exec_lua('return vim.str_byteindex(_G.test_text, "utf-16", 99999, false)') + ) + eq( + indices8[#indices8], + exec_lua('return vim.str_byteindex(_G.test_text, "utf-8", 99999, false)') + ) + eq(2, exec_lua('return vim.str_byteindex("é", "utf-16", 2, false)')) + local i32, i16, i8 = 0, 0, 0 local len = 51 for k = 0, len do if indices32[i32] < k then @@ -345,9 +424,29 @@ describe('lua stdlib', function() i16 = i16 + 1 end end + if indices8[i8] < k then + i8 = i8 + 1 + end eq({ i32, i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, ...)}', k), k) + eq({ i32 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-32", ...)}', k), k) + eq({ i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-16", ...)}', k), k) + eq({ i8 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-8", ...)}', k), k) end - eq( + + eq({ #indices32, #indices16 }, exec_lua('return {vim.str_utfindex(_G.test_text)}')) + + eq(#indices32, exec_lua('return vim.str_utfindex(_G.test_text, "utf-32", math.huge, false)')) + eq(#indices16, exec_lua('return vim.str_utfindex(_G.test_text, "utf-16", math.huge, false)')) + eq(#indices8, exec_lua('return vim.str_utfindex(_G.test_text, "utf-8", math.huge, false)')) + + eq(#indices32, exec_lua('return vim.str_utfindex(_G.test_text, "utf-32")')) + eq(#indices16, exec_lua('return vim.str_utfindex(_G.test_text, "utf-16")')) + eq(#indices8, exec_lua('return vim.str_utfindex(_G.test_text, "utf-8")')) + matches( + 'invalid encoding', + pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, "madeupencoding", ...)', 1) + ) + matches( 'index out of range', pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, ...)', len + 1) ) @@ -538,7 +637,6 @@ describe('lua stdlib', function() matches('big failure\nvery async', remove_trace(eval('v:errmsg'))) local screen = Screen.new(60, 5) - screen:attach() screen:expect { grid = [[ ^ | @@ -1304,7 +1402,6 @@ describe('lua stdlib', function() end) local screen = Screen.new(50, 7) - screen:attach() exec_lua([[ timer = vim.uv.new_timer() timer:start(20, 0, function () @@ -1317,7 +1414,7 @@ describe('lua stdlib', function() screen:expect { grid = [[ {9:[string "<nvim>"]:6: E5560: rpcrequest must not be}| - {9: called in a lua loop callback} | + {9: called in a fast event context} | {9:stack traceback:} | {9: [C]: in function 'rpcrequest'} | {9: [string "<nvim>"]:6: in function <[string }| @@ -1326,7 +1423,9 @@ describe('lua stdlib', function() ]], } feed('<cr>') - eq({ 3, NIL }, api.nvim_get_var('yy')) + retry(10, nil, function() + eq({ 3, NIL }, api.nvim_get_var('yy')) + end) exec_lua([[timer:close()]]) end) @@ -1363,7 +1462,79 @@ describe('lua stdlib', function() eq('{"a": {}, "b": []}', exec_lua([[ return vim.fn.json_encode({a=vim.empty_dict(), b={}}) ]])) end) - it('vim.validate', function() + it('vim.validate (fast form)', function() + exec_lua("vim.validate('arg1', {}, 'table')") + exec_lua("vim.validate('arg1', nil, 'table', true)") + exec_lua("vim.validate('arg1', { foo='foo' }, 'table')") + exec_lua("vim.validate('arg1', { 'foo' }, 'table')") + exec_lua("vim.validate('arg1', 'foo', 'string')") + exec_lua("vim.validate('arg1', nil, 'string', true)") + exec_lua("vim.validate('arg1', 1, 'number')") + exec_lua("vim.validate('arg1', 0, 'number')") + exec_lua("vim.validate('arg1', 0.1, 'number')") + exec_lua("vim.validate('arg1', nil, 'number', true)") + exec_lua("vim.validate('arg1', true, 'boolean')") + exec_lua("vim.validate('arg1', false, 'boolean')") + exec_lua("vim.validate('arg1', nil, 'boolean', true)") + exec_lua("vim.validate('arg1', function()end, 'function')") + exec_lua("vim.validate('arg1', nil, 'function', true)") + exec_lua("vim.validate('arg1', nil, 'nil')") + exec_lua("vim.validate('arg1', nil, 'nil', true)") + exec_lua("vim.validate('arg1', coroutine.create(function()end), 'thread')") + exec_lua("vim.validate('arg1', nil, 'thread', true)") + exec_lua("vim.validate('arg1', 2, function(a) return (a % 2) == 0 end, 'even number')") + exec_lua("vim.validate('arg1', 5, {'number', 'string'})") + exec_lua("vim.validate('arg2', 'foo', {'number', 'string'})") + + matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number')) + matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string')) + matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table')) + matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function')) + matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string')) + matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table')) + matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function')) + matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number')) + matches('arg1: expected x, got number', pcall_err(exec_lua, "vim.validate('arg1', 1, 'x')")) + matches('invalid validator: 1', pcall_err(exec_lua, "vim.validate('arg1', 1, 1)")) + matches('invalid arguments', pcall_err(exec_lua, "vim.validate('arg1', { 1 })")) + + -- Validated parameters are required by default. + matches( + 'arg1: expected string, got nil', + pcall_err(exec_lua, "vim.validate('arg1', nil, 'string')") + ) + -- Explicitly required. + matches( + 'arg1: expected string, got nil', + pcall_err(exec_lua, "vim.validate('arg1', nil, 'string', false)") + ) + + matches( + 'arg1: expected table, got number', + pcall_err(exec_lua, "vim.validate('arg1', 1, 'table')") + ) + + matches( + 'arg1: expected even number, got 3', + pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1 end, 'even number')") + ) + matches( + 'arg1: expected %?, got 3', + pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1 end)") + ) + matches( + 'arg1: expected number|string, got nil', + pcall_err(exec_lua, "vim.validate('arg1', nil, {'number', 'string'})") + ) + + -- Pass an additional message back. + matches( + 'arg1: expected %?, got 3. Info: TEST_MSG', + pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1, 'TEST_MSG' end)") + ) + end) + + it('vim.validate (spec form)', function() exec_lua("vim.validate{arg1={{}, 'table' }}") exec_lua("vim.validate{arg1={{}, 't' }}") exec_lua("vim.validate{arg1={nil, 't', true }}") @@ -1392,29 +1563,11 @@ describe('lua stdlib', function() exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}") exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}") exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}") - vim.validate('arg1', 5, 'number') - vim.validate('arg1', '5', 'string') - vim.validate('arg1', { 5 }, 'table') - vim.validate('arg1', function() - return 5 - end, 'function') - vim.validate('arg1', nil, 'number', true) - vim.validate('arg1', nil, 'string', true) - vim.validate('arg1', nil, 'table', true) - vim.validate('arg1', nil, 'function', true) - matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number')) - matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string')) - matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table')) - matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function')) - matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string')) - matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table')) - matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function')) - matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number')) matches('expected table, got number', pcall_err(exec_lua, "vim.validate{ 1, 'x' }")) - matches('invalid type name: x', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}")) - matches('invalid type name: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}')) - matches('invalid type name: nil', pcall_err(exec_lua, 'vim.validate{ arg1={ 1 }}')) + matches('arg1: expected x, got number', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}")) + matches('invalid validator: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}')) + matches('invalid validator: nil', pcall_err(exec_lua, 'vim.validate{ arg1={ 1 }}')) -- Validated parameters are required by default. matches( @@ -1975,7 +2128,6 @@ describe('lua stdlib', function() eq({ 1, 5 }, api.nvim_win_get_cursor(0)) local screen = Screen.new(60, 3) - screen:attach() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ @@ -3157,10 +3309,17 @@ describe('lua stdlib', function() eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]]) end) - it('skips any function that caused an error', function() + it('skips any function that caused an error and shows stacktrace', function() insert([[hello world]]) exec_lua [[ + local function ErrF2() + error("Dumb Error") + end + local function ErrF1() + ErrF2() + end + keys = {} return vim.on_key(function(buf) @@ -3171,7 +3330,7 @@ describe('lua stdlib', function() table.insert(keys, buf) if buf == 'l' then - error("Dumb Error") + ErrF1() end end) ]] @@ -3181,6 +3340,19 @@ describe('lua stdlib', function() -- Only the first letter gets added. After that we remove the callback eq('inext l', exec_lua [[ return table.concat(keys, '') ]]) + + local errmsg = api.nvim_get_vvar('errmsg') + matches( + [[ +^Error executing vim%.on%_key%(%) callbacks:.* +With ns%_id %d+: .*: Dumb Error +stack traceback: +.*: in function 'error' +.*: in function 'ErrF2' +.*: in function 'ErrF1' +.*]], + errmsg + ) end) it('argument 1 is keys after mapping, argument 2 is typed keys', function() @@ -3223,6 +3395,109 @@ describe('lua stdlib', function() feed('<C-C>') eq('/', exec_lua([[return _G.ctrl_c_cmdtype]])) end) + + it('callback is not invoked recursively #30752', function() + local screen = Screen.new(60, 10) + exec_lua([[ + vim.on_key(function(key, typed) + vim.api.nvim_echo({ + { 'key_cb\n' }, + { ("KEYCB: key '%s', typed '%s'\n"):format(key, typed) }, + }, false, {}) + end) + ]]) + feed('^') + screen:expect([[ + | + {1:~ }|*5 + {3: }| + key_cb | + KEYCB: key '^', typed '^' | + {6:Press ENTER or type command to continue}^ | + ]]) + feed('<C-C>') + screen:expect([[ + | + {1:~ }|*3 + {3: }| + key_cb | + KEYCB: key '^', typed '^' | + key_cb | + KEYCB: key '{18:^C}', typed '{18:^C}' | + {6:Press ENTER or type command to continue}^ | + ]]) + feed('<C-C>') + screen:expect([[ + ^ | + {1:~ }|*8 + | + ]]) + end) + + it('can discard input', function() + clear() + -- discard every other normal 'x' command + exec_lua [[ + n_key = 0 + + vim.on_key(function(buf, typed_buf) + if typed_buf == 'x' then + n_key = n_key + 1 + end + return (n_key % 2 == 0) and "" or nil + end) + ]] + + api.nvim_buf_set_lines(0, 0, -1, true, { '54321' }) + + feed('x') + expect('4321') + feed('x') + expect('4321') + feed('x') + expect('321') + feed('x') + expect('321') + end) + + it('callback invalid return', function() + clear() + -- second key produces an error which removes the callback + exec_lua [[ + n_call = 0 + + vim.on_key(function(buf, typed_buf) + if typed_buf == 'x' then + n_call = n_call + 1 + end + return n_call >= 2 and '!' or nil + end) + ]] + + api.nvim_buf_set_lines(0, 0, -1, true, { '54321' }) + + local function cleanup_msg(msg) + return msg:gsub('^Error .*\nWith ns%_id %d+: ', '') + end + + feed('x') + eq(1, exec_lua [[ return n_call ]]) + + eq(1, exec_lua [[ return vim.on_key(nil, nil) ]]) + + eq('', cleanup_msg(eval('v:errmsg'))) + feed('x') + eq(2, exec_lua [[ return n_call ]]) + eq('return string must be empty', cleanup_msg(eval('v:errmsg'))) + command('let v:errmsg = ""') + + eq(0, exec_lua [[ return vim.on_key(nil, nil) ]]) + + feed('x') + eq(2, exec_lua [[ return n_call ]]) + expect('21') + eq('', cleanup_msg(eval('v:errmsg'))) + end) end) describe('vim.wait', function() @@ -3500,7 +3775,6 @@ describe('lua stdlib', function() it('fails in fast callbacks #26122', function() local screen = Screen.new(80, 10) - screen:attach() exec_lua([[ local timer = vim.uv.new_timer() timer:start(0, 0, function() @@ -3509,7 +3783,7 @@ describe('lua stdlib', function() end) ]]) screen:expect({ - any = pesc('E5560: vim.wait must not be called in a lua loop callback'), + any = pesc('E5560: vim.wait must not be called in a fast event context'), }) feed('<CR>') assert_alive() @@ -3518,7 +3792,6 @@ describe('lua stdlib', function() it('vim.notify_once', function() local screen = Screen.new(60, 5) - screen:attach() screen:expect { grid = [[ ^ | @@ -3715,7 +3988,6 @@ describe('lua stdlib', function() it('updates ruler if cursor moved', function() -- Fixed for win_execute in vim-patch:8.1.2124, but should've applied to nvim_win_call too! local screen = Screen.new(30, 5) - screen:attach() exec_lua [[ _G.api = vim.api vim.opt.ruler = true @@ -3858,7 +4130,6 @@ describe('lua stdlib', function() it('vim.lua_omnifunc', function() local screen = Screen.new(60, 5) - screen:attach() command [[ set omnifunc=v:lua.vim.lua_omnifunc ]] -- Note: the implementation is shared with lua command line completion. @@ -4060,11 +4331,16 @@ describe('vim.keymap', function() ) matches( - 'opts: expected table, got function', + 'rhs: expected string|function, got number', pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 42, function() end)]]) ) matches( + 'opts: expected table, got function', + pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 'x', function() end)]]) + ) + + matches( 'rhs: expected string|function, got number', pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 42)]]) ) diff --git a/test/functional/lua/with_spec.lua b/test/functional/lua/with_spec.lua index 99b80ef749..6127e83619 100644 --- a/test/functional/lua/with_spec.lua +++ b/test/functional/lua/with_spec.lua @@ -1029,7 +1029,6 @@ describe('vim._with', function() [1] = { bold = true, reverse = true }, [2] = { bold = true, foreground = Screen.colors.Blue }, } - screen:attach() exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echo('"ccc"') end) ]] screen:expect [[ ^ | @@ -1178,7 +1177,6 @@ describe('vim._with', function() [1] = { reverse = true }, [2] = { bold = true, reverse = true }, } - screen:attach() exec_lua [[ vim.opt.ruler = true local lines = {} diff --git a/test/functional/options/belloff_spec.lua b/test/functional/options/belloff_spec.lua new file mode 100644 index 0000000000..575e79d1a9 --- /dev/null +++ b/test/functional/options/belloff_spec.lua @@ -0,0 +1,78 @@ +local t = require('test.testutil') +local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') + +local clear = n.clear +local command = n.command +local api = n.api +local feed = n.feed +local poke_eventloop = n.poke_eventloop +local eq = t.eq +local retry = t.retry + +describe("'belloff'", function() + local screen + + before_each(function() + clear() + screen = Screen.new(42, 5) + screen:expect([[ + ^ | + {1:~ }|*3 + | + ]]) + end) + + it('various flags work properly', function() + command('set cpoptions+=E') + + local map = { + backspace = 'i<BS><Esc>', + cursor = 'i<Up><Esc>', + copy = 'i<C-Y><Esc>', + ctrlg = 'i<C-G><C-G><Esc>', + error = 'J', + esc = '<Esc>', + operator = 'y0', + register = 'i<C-R>@<Esc>', + } + + local items = {} ---@type string[] + local inputs = {} ---@type string[] + for item, input in pairs(map) do + table.insert(items, item) + table.insert(inputs, input) + end + + local values = {} ---@type string[] + for i, _ in ipairs(items) do + -- each tested 'belloff' value enables at most one item + local parts = vim.deepcopy(items) + table.remove(parts, i) + local value = table.concat(parts, ',') + table.insert(values, value) + end + table.insert(values, 'all') + + for i, value in ipairs(values) do + api.nvim_set_option_value('belloff', value, {}) + + for j, input in ipairs(inputs) do + screen.bell = false + local beep = value ~= 'all' and i == j + -- Nvim avoids beeping more than 3 times in half a second, + -- so retry if beeping is expected but not received. + retry(not beep and 1 or nil, 1000, function() + feed(input) + poke_eventloop() + screen:expect({ + condition = function() + eq(beep, screen.bell, ('%s with belloff=%s'):format(items[j], value)) + end, + unchanged = not beep, + }) + end) + end + end + end) +end) diff --git a/test/functional/options/chars_spec.lua b/test/functional/options/chars_spec.lua index 8e63e07e09..42ca41a145 100644 --- a/test/functional/options/chars_spec.lua +++ b/test/functional/options/chars_spec.lua @@ -16,7 +16,6 @@ describe("'fillchars'", function() before_each(function() clear() screen = Screen.new(25, 5) - screen:attach() end) describe('"eob" flag', function() @@ -157,7 +156,6 @@ describe("'listchars'", function() before_each(function() clear() screen = Screen.new(50, 5) - screen:attach() end) it('has global value', function() diff --git a/test/functional/options/cursorbind_spec.lua b/test/functional/options/cursorbind_spec.lua index 19551b928f..21e0ba8e75 100644 --- a/test/functional/options/cursorbind_spec.lua +++ b/test/functional/options/cursorbind_spec.lua @@ -18,7 +18,6 @@ describe("'cursorbind'", function() [3] = { reverse = true }, -- StatusLineNC [4] = { background = Screen.colors.Grey90 }, -- CursorLine, CursorColumn }) - screen:attach() exec([[ call setline(1, 'aa bb cc dd ee ff gg hh ii jj kk ll mm' .. \ ' nn oo pp qq rr ss tt uu vv ww xx yy zz') diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index e3d15fa30f..e7f47ef4e9 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -34,7 +34,6 @@ describe('startup defaults', function() describe(':filetype', function() local function expect_filetype(expected) local screen = Screen.new(50, 4) - screen:attach() command('filetype') screen:expect([[ ^ | @@ -127,7 +126,6 @@ describe('startup defaults', function() it('vert/fold flags', function() clear() local screen = Screen.new(50, 5) - screen:attach() command('set laststatus=0') insert([[ 1 diff --git a/test/functional/options/shortmess_spec.lua b/test/functional/options/shortmess_spec.lua index dcbf9d15e0..04dbada7d8 100644 --- a/test/functional/options/shortmess_spec.lua +++ b/test/functional/options/shortmess_spec.lua @@ -14,7 +14,6 @@ describe("'shortmess'", function() before_each(function() clear() screen = Screen.new(42, 5) - screen:attach() end) describe('"F" flag', function() diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 7089313303..753da64522 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -155,7 +155,6 @@ describe('vim.health', function() it('highlights OK, ERROR', function() local screen = Screen.new(50, 12) - screen:attach() screen:set_default_attr_ids({ h1 = { reverse = true }, h2 = { foreground = tonumber('0x6a0dad') }, @@ -222,7 +221,7 @@ describe(':checkhealth window', function() end) it('opens directly if no buffer created', function() - local screen = Screen.new(50, 12) + local screen = Screen.new(50, 12, { ext_multigrid = true }) screen:set_default_attr_ids { h1 = { reverse = true }, h2 = { foreground = tonumber('0x6a0dad') }, @@ -230,7 +229,6 @@ describe(':checkhealth window', function() [14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }, [32] = { foreground = Screen.colors.PaleGreen2 }, } - screen:attach({ ext_multigrid = true }) command('checkhealth success1') screen:expect { grid = [[ @@ -256,7 +254,7 @@ describe(':checkhealth window', function() end) local function test_health_vsplit(left, emptybuf, mods) - local screen = Screen.new(50, 20) + local screen = Screen.new(50, 20, { ext_multigrid = true }) screen:set_default_attr_ids { h1 = { reverse = true }, h2 = { foreground = tonumber('0x6a0dad') }, @@ -264,7 +262,6 @@ describe(':checkhealth window', function() [14] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }, [32] = { foreground = Screen.colors.PaleGreen2 }, } - screen:attach({ ext_multigrid = true }) if not emptybuf then insert('hello') end @@ -322,8 +319,7 @@ describe(':checkhealth window', function() end local function test_health_split(top, emptybuf, mods) - local screen = Screen.new(50, 25) - screen:attach({ ext_multigrid = true }) + local screen = Screen.new(50, 25, { ext_multigrid = true }) screen._default_attr_ids = nil if not emptybuf then insert('hello') diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 4df8d77d44..39b6ddc105 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -134,10 +134,14 @@ describe('vim.lsp.completion: item conversion', function() eq(expected, result) end) - it('filters on label if filterText is missing', function() + it('does not filter if there is a textEdit', function() + local range0 = { + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, + } local completion_list = { - { label = 'foo' }, - { label = 'bar' }, + { label = 'foo', textEdit = { newText = 'foo', range = range0 } }, + { label = 'bar', textEdit = { newText = 'bar', range = range0 } }, } local result = complete('fo|', completion_list) local expected = { @@ -145,6 +149,10 @@ describe('vim.lsp.completion: item conversion', function() abbr = 'foo', word = 'foo', }, + { + abbr = 'bar', + word = 'bar', + }, } result = vim.tbl_map(function(x) return { @@ -152,7 +160,259 @@ describe('vim.lsp.completion: item conversion', function() word = x.word, } end, result.items) + local sorter = function(a, b) + return a.word > b.word + end + table.sort(expected, sorter) + table.sort(result, sorter) + eq(expected, result) + end) + + ---@param prefix string + ---@param items lsp.CompletionItem[] + ---@param expected table[] + local assert_completion_matches = function(prefix, items, expected) + local result = complete(prefix .. '|', items) + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + local sorter = function(a, b) + return a.word > b.word + end + table.sort(expected, sorter) + table.sort(result, sorter) eq(expected, result) + end + + describe('when completeopt has fuzzy matching enabled', function() + before_each(function() + exec_lua(function() + vim.opt.completeopt:append('fuzzy') + end) + end) + after_each(function() + exec_lua(function() + vim.opt.completeopt:remove('fuzzy') + end) + end) + + it('fuzzy matches on filterText', function() + assert_completion_matches('fo', { + { label = '?.foo', filterText = 'foo' }, + { label = 'faz other', filterText = 'faz other' }, + { label = 'bar', filterText = 'bar' }, + }, { + { + abbr = 'faz other', + word = 'faz other', + }, + { + abbr = '?.foo', + word = '?.foo', + }, + }) + end) + + it('fuzzy matches on label when filterText is missing', function() + assert_completion_matches('fo', { + { label = 'foo' }, + { label = 'faz other' }, + { label = 'bar' }, + }, { + { + abbr = 'faz other', + word = 'faz other', + }, + { + abbr = 'foo', + word = 'foo', + }, + }) + end) + end) + + describe('when smartcase is enabled', function() + before_each(function() + exec_lua(function() + vim.opt.smartcase = true + end) + end) + after_each(function() + exec_lua(function() + vim.opt.smartcase = false + end) + end) + + it('matches filterText case sensitively', function() + assert_completion_matches('Fo', { + { label = 'foo', filterText = 'foo' }, + { label = '?.Foo', filterText = 'Foo' }, + { label = 'Faz other', filterText = 'Faz other' }, + { label = 'faz other', filterText = 'faz other' }, + { label = 'bar', filterText = 'bar' }, + }, { + { + abbr = '?.Foo', + word = '?.Foo', + }, + }) + end) + + it('matches label case sensitively when filterText is missing', function() + assert_completion_matches('Fo', { + { label = 'foo' }, + { label = 'Foo' }, + { label = 'Faz other' }, + { label = 'faz other' }, + { label = 'bar' }, + }, { + { + abbr = 'Foo', + word = 'Foo', + }, + }) + end) + + describe('when ignorecase is enabled', function() + before_each(function() + exec_lua(function() + vim.opt.ignorecase = true + end) + end) + after_each(function() + exec_lua(function() + vim.opt.ignorecase = false + end) + end) + + it('matches filterText case insensitively if prefix is lowercase', function() + assert_completion_matches('fo', { + { label = '?.foo', filterText = 'foo' }, + { label = '?.Foo', filterText = 'Foo' }, + { label = 'Faz other', filterText = 'Faz other' }, + { label = 'faz other', filterText = 'faz other' }, + { label = 'bar', filterText = 'bar' }, + }, { + { + abbr = '?.Foo', + word = '?.Foo', + }, + { + abbr = '?.foo', + word = '?.foo', + }, + }) + end) + + it( + 'matches label case insensitively if prefix is lowercase and filterText is missing', + function() + assert_completion_matches('fo', { + { label = 'foo' }, + { label = 'Foo' }, + { label = 'Faz other' }, + { label = 'faz other' }, + { label = 'bar' }, + }, { + { + abbr = 'Foo', + word = 'Foo', + }, + { + abbr = 'foo', + word = 'foo', + }, + }) + end + ) + + it('matches filterText case sensitively if prefix has uppercase letters', function() + assert_completion_matches('Fo', { + { label = 'foo', filterText = 'foo' }, + { label = '?.Foo', filterText = 'Foo' }, + { label = 'Faz other', filterText = 'Faz other' }, + { label = 'faz other', filterText = 'faz other' }, + { label = 'bar', filterText = 'bar' }, + }, { + { + abbr = '?.Foo', + word = '?.Foo', + }, + }) + end) + + it( + 'matches label case sensitively if prefix has uppercase letters and filterText is missing', + function() + assert_completion_matches('Fo', { + { label = 'foo' }, + { label = 'Foo' }, + { label = 'Faz other' }, + { label = 'faz other' }, + { label = 'bar' }, + }, { + { + abbr = 'Foo', + word = 'Foo', + }, + }) + end + ) + end) + end) + + describe('when ignorecase is enabled', function() + before_each(function() + exec_lua(function() + vim.opt.ignorecase = true + end) + end) + after_each(function() + exec_lua(function() + vim.opt.ignorecase = false + end) + end) + + it('matches filterText case insensitively', function() + assert_completion_matches('Fo', { + { label = '?.foo', filterText = 'foo' }, + { label = '?.Foo', filterText = 'Foo' }, + { label = 'Faz other', filterText = 'Faz other' }, + { label = 'faz other', filterText = 'faz other' }, + { label = 'bar', filterText = 'bar' }, + }, { + { + abbr = '?.Foo', + word = '?.Foo', + }, + { + abbr = '?.foo', + word = '?.foo', + }, + }) + end) + + it('matches label case insensitively when filterText is missing', function() + assert_completion_matches('Fo', { + { label = 'foo' }, + { label = 'Foo' }, + { label = 'Faz other' }, + { label = 'faz other' }, + { label = 'bar' }, + }, { + { + abbr = 'Foo', + word = 'Foo', + }, + { + abbr = 'foo', + word = 'foo', + }, + }) + end) end) it('works on non word prefix', function() @@ -320,7 +580,7 @@ describe('vim.lsp.completion: item conversion', function() info = '', kind = 'Module', menu = '', - hl_group = '', + abbr_hlgroup = '', word = 'this_thread', } local result = complete(' std::this|', completion_list) @@ -376,7 +636,7 @@ describe('vim.lsp.completion: item conversion', function() info = '', kind = 'Module', menu = '', - hl_group = '', + abbr_hlgroup = '', word = 'this_thread', } local result = complete(' std::this|is', completion_list) @@ -471,6 +731,39 @@ describe('vim.lsp.completion: item conversion', function() ) end) +--- @param completion_result lsp.CompletionList +--- @return integer +local function create_server(completion_result) + return exec_lua(function() + local server = _G._create_server({ + capabilities = { + completionProvider = { + triggerCharacters = { '.' }, + }, + }, + handlers = { + ['textDocument/completion'] = function(_, _, callback) + callback(nil, completion_result) + end, + }, + }) + + local bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_win_set_buf(0, bufnr) + return vim.lsp.start({ + name = 'dummy', + cmd = server.cmd, + on_attach = function(client, bufnr0) + vim.lsp.completion.enable(true, client.id, bufnr0, { + convert = function(item) + return { abbr = item.label:gsub('%b()', '') } + end, + }) + end, + }) + end) +end + describe('vim.lsp.completion: protocol', function() before_each(function() clear() @@ -487,39 +780,6 @@ describe('vim.lsp.completion: protocol', function() after_each(clear) - --- @param completion_result lsp.CompletionList - --- @return integer - local function create_server(completion_result) - return exec_lua(function() - local server = _G._create_server({ - capabilities = { - completionProvider = { - triggerCharacters = { '.' }, - }, - }, - handlers = { - ['textDocument/completion'] = function(_, _, callback) - callback(nil, completion_result) - end, - }, - }) - - local bufnr = vim.api.nvim_get_current_buf() - vim.api.nvim_win_set_buf(0, bufnr) - return vim.lsp.start({ - name = 'dummy', - cmd = server.cmd, - on_attach = function(client, bufnr0) - vim.lsp.completion.enable(true, client.id, bufnr0, { - convert = function(item) - return { abbr = item.label:gsub('%b()', '') } - end, - }) - end, - }) - end) - end - local function assert_matches(fn) retry(nil, nil, function() fn(exec_lua('return _G.capture.matches')) @@ -570,7 +830,7 @@ describe('vim.lsp.completion: protocol', function() info = '', kind = 'Unknown', menu = '', - hl_group = '', + abbr_hlgroup = '', user_data = { nvim = { lsp = { @@ -591,7 +851,7 @@ describe('vim.lsp.completion: protocol', function() info = '', kind = 'Unknown', menu = '', - hl_group = 'DiagnosticDeprecated', + abbr_hlgroup = 'DiagnosticDeprecated', user_data = { nvim = { lsp = { @@ -613,7 +873,7 @@ describe('vim.lsp.completion: protocol', function() info = '', kind = 'Unknown', menu = '', - hl_group = 'DiagnosticDeprecated', + abbr_hlgroup = 'DiagnosticDeprecated', user_data = { nvim = { lsp = { @@ -726,3 +986,58 @@ describe('vim.lsp.completion: protocol', function() end) end) end) + +describe('vim.lsp.completion: integration', function() + before_each(function() + clear() + exec_lua(create_server_definition) + exec_lua(function() + vim.fn.complete = vim.schedule_wrap(vim.fn.complete) + end) + end) + + after_each(clear) + + it('puts cursor at the end of completed word', function() + local completion_list = { + isIncomplete = false, + items = { + { + label = 'hello', + insertText = '${1:hello} friends', + insertTextFormat = 2, + }, + }, + } + exec_lua(function() + vim.o.completeopt = 'menuone,noselect' + end) + create_server(completion_list) + feed('i world<esc>0ih<c-x><c-o>') + retry(nil, nil, function() + eq( + 1, + exec_lua(function() + return vim.fn.pumvisible() + end) + ) + end) + feed('<C-n><C-y>') + eq( + { true, { 'hello friends world' } }, + exec_lua(function() + return { + vim.snippet.active({ direction = 1 }), + vim.api.nvim_buf_get_lines(0, 0, -1, true), + } + end) + ) + feed('<tab>') + eq( + #'hello friends', + exec_lua(function() + return vim.api.nvim_win_get_cursor(0)[2] + end) + ) + end) +end) diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 78c684083b..5afbe22793 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -120,85 +120,6 @@ describe('vim.lsp.diagnostic', function() end) describe('vim.lsp.diagnostic.on_publish_diagnostics', function() - it('allows configuring the virtual text via vim.lsp.with', function() - local expected_spacing = 10 - local extmarks = exec_lua(function() - _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { - virtual_text = { - spacing = expected_spacing, - }, - }) - - _G.PublishDiagnostics(nil, { - uri = fake_uri, - diagnostics = { - _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), - }, - }, { client_id = client_id }) - - return _G.get_extmarks(diagnostic_bufnr, client_id) - end) - - local spacing = extmarks[1][4].virt_text[1][1] - - eq(expected_spacing, #spacing) - end) - - it('allows configuring the virtual text via vim.lsp.with using a function', function() - local expected_spacing = 10 - local extmarks = exec_lua(function() - _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { - virtual_text = function() - return { - spacing = expected_spacing, - } - end, - }) - - _G.PublishDiagnostics(nil, { - uri = fake_uri, - diagnostics = { - _G.make_error('Delayed Diagnostic', 4, 4, 4, 4), - }, - }, { client_id = client_id }) - - return _G.get_extmarks(diagnostic_bufnr, client_id) - end) - - local spacing = extmarks[1][4].virt_text[1][1] - - eq(expected_spacing, #spacing) - end) - - it('allows filtering via severity limit', function() - local get_extmark_count_with_severity = function(severity_limit) - return exec_lua(function() - _G.PublishDiagnostics = vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, { - underline = false, - virtual_text = { - severity = { min = severity_limit }, - }, - }) - - _G.PublishDiagnostics(nil, { - uri = fake_uri, - diagnostics = { - _G.make_warning('Delayed Diagnostic', 4, 4, 4, 4), - }, - }, { client_id = client_id }) - - return #_G.get_extmarks(diagnostic_bufnr, client_id) - end, client_id, fake_uri, severity_limit) - end - - -- No messages with Error or higher - eq(0, get_extmark_count_with_severity('ERROR')) - - -- But now we don't filter it - eq(1, get_extmark_count_with_severity('WARN')) - eq(1, get_extmark_count_with_severity('HINT')) - end) - it('correctly handles UTF-16 offsets', function() local line = 'All 💼 and no 🎉 makes Jack a dull 👦' local result = exec_lua(function() @@ -219,13 +140,13 @@ describe('vim.lsp.diagnostic', function() eq(1, #result) eq( exec_lua(function() - return vim.str_byteindex(line, 7, true) + return vim.str_byteindex(line, 'utf-16', 7) end), result[1].col ) eq( exec_lua(function() - return vim.str_byteindex(line, 8, true) + return vim.str_byteindex(line, 'utf-16', 8) end), result[1].end_col ) @@ -380,34 +301,6 @@ describe('vim.lsp.diagnostic', function() eq(1, diagnostics[1].severity) end) - it('allows configuring the virtual text via vim.lsp.with', function() - local expected_spacing = 10 - local extmarks = exec_lua(function() - _G.Diagnostic = vim.lsp.with(vim.lsp.diagnostic.on_diagnostic, { - virtual_text = { - spacing = expected_spacing, - }, - }) - - _G.Diagnostic(nil, { - kind = 'full', - items = { - _G.make_error('Pull Diagnostic', 4, 4, 4, 4), - }, - }, { - params = { - textDocument = { uri = fake_uri }, - }, - uri = fake_uri, - client_id = client_id, - }, {}) - - return _G.get_extmarks(diagnostic_bufnr, client_id) - end) - eq(2, #extmarks) - eq(expected_spacing, #extmarks[1][4].virt_text[1][1]) - end) - it('clears diagnostics when client detaches', function() exec_lua(function() vim.lsp.diagnostic.on_diagnostic(nil, { diff --git a/test/functional/plugin/lsp/inlay_hint_spec.lua b/test/functional/plugin/lsp/inlay_hint_spec.lua index 471f2cc3e8..fc6c3f46f7 100644 --- a/test/functional/plugin/lsp/inlay_hint_spec.lua +++ b/test/functional/plugin/lsp/inlay_hint_spec.lua @@ -67,7 +67,6 @@ int main() { before_each(function() clear_notrace() screen = Screen.new(50, 9) - screen:attach() bufnr = n.api.nvim_get_current_buf() exec_lua(create_server_definition) @@ -339,7 +338,6 @@ test text before_each(function() clear_notrace() screen = Screen.new(50, 3) - screen:attach() exec_lua(create_server_definition) bufnr = n.api.nvim_get_current_buf() diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index f72aab7e0b..280bd27207 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -28,7 +28,6 @@ describe('semantic token highlighting', function() local screen --- @type test.functional.ui.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 }, diff --git a/test/functional/plugin/lsp/utils_spec.lua b/test/functional/plugin/lsp/utils_spec.lua index 64d58eeffd..813b8de812 100644 --- a/test/functional/plugin/lsp/utils_spec.lua +++ b/test/functional/plugin/lsp/utils_spec.lua @@ -181,11 +181,9 @@ describe('vim.lsp.util', function() eq(expected_anchor, string.sub(opts.anchor, 1, 1)) end - local screen --- @type test.functional.ui.screen before_each(function() n.clear() - screen = Screen.new(80, 80) - screen:attach() + local _ = Screen.new(80, 80) feed('79i<CR><Esc>') -- fill screen with empty lines end) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 9956fdf628..5222216faf 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2586,7 +2586,7 @@ describe('LSP', function() }, }, } - eq(false, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit)) + eq(false, pcall(exec_lua, 'vim.lsp.util.apply_workspace_edit(...)', edit, 'utf-16')) eq(false, vim.uv.fs_stat(tmpfile) ~= nil) end) end) @@ -3134,44 +3134,6 @@ describe('LSP', function() end) end) - describe('lsp.util._get_symbol_kind_name', function() - it('returns the name specified by protocol', function() - eq( - 'File', - exec_lua(function() - return vim.lsp.util._get_symbol_kind_name(1) - end) - ) - eq( - 'TypeParameter', - exec_lua(function() - return vim.lsp.util._get_symbol_kind_name(26) - end) - ) - end) - - it('returns the name not specified by protocol', function() - eq( - 'Unknown', - exec_lua(function() - return vim.lsp.util._get_symbol_kind_name(nil) - end) - ) - eq( - 'Unknown', - exec_lua(function() - return vim.lsp.util._get_symbol_kind_name(vim.NIL) - end) - ) - eq( - 'Unknown', - exec_lua(function() - return vim.lsp.util._get_symbol_kind_name(1000) - end) - ) - end) - end) - describe('lsp.util.jump_to_location', function() local target_bufnr --- @type integer @@ -3519,6 +3481,30 @@ describe('LSP', function() local expected = { '```cs', 'TestEntity.TestEntity()', '```', 'some doc' } eq(expected, result) end) + + it('highlights active parameters in multiline signature labels', function() + local _, hl = exec_lua(function() + local signature_help = { + activeSignature = 0, + signatures = { + { + activeParameter = 1, + label = 'fn bar(\n _: void,\n _: void,\n) void', + parameters = { + { label = '_: void' }, + { label = '_: void' }, + }, + }, + }, + } + return vim.lsp.util.convert_signature_help_to_markdown_lines(signature_help, 'zig', { '(' }) + end) + -- Note that although the higlight positions below are 0-indexed, the 2nd parameter + -- corresponds to the 3rd line because the first line is the ``` from the + -- Markdown block. + local expected = { 3, 4, 3, 11 } + eq(expected, hl) + end) end) describe('lsp.util.get_effective_tabstop', function() @@ -5090,6 +5076,91 @@ describe('LSP', function() end) end) + describe('lsp.buf.definition', function() + it('jumps to single location', function() + exec_lua(create_server_definition) + local result = exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + local server = _G._create_server({ + capabilities = { + definitionProvider = true, + }, + handlers = { + ['textDocument/definition'] = function(_, _, callback) + local location = { + range = { + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, + }, + uri = vim.uri_from_bufnr(bufnr), + } + callback(nil, location) + end, + }, + }) + local win = vim.api.nvim_get_current_win() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'local x = 10', '', 'print(x)' }) + vim.api.nvim_win_set_cursor(win, { 3, 6 }) + local client_id = assert(vim.lsp.start({ name = 'dummy', cmd = server.cmd })) + vim.lsp.buf.definition() + vim.lsp.stop_client(client_id) + return { + cursor = vim.api.nvim_win_get_cursor(win), + messages = server.messages, + tagstack = vim.fn.gettagstack(win), + } + end) + eq('textDocument/definition', result.messages[3].method) + eq({ 1, 0 }, result.cursor) + eq(1, #result.tagstack.items) + eq('x', result.tagstack.items[1].tagname) + eq(3, result.tagstack.items[1].from[2]) + eq(7, result.tagstack.items[1].from[3]) + end) + it('merges results from multiple servers', function() + exec_lua(create_server_definition) + local result = exec_lua(function() + local bufnr = vim.api.nvim_get_current_buf() + local function serveropts(character) + return { + capabilities = { + definitionProvider = true, + }, + handlers = { + ['textDocument/definition'] = function(_, _, callback) + local location = { + range = { + start = { line = 0, character = character }, + ['end'] = { line = 0, character = character }, + }, + uri = vim.uri_from_bufnr(bufnr), + } + callback(nil, location) + end, + }, + } + end + local server1 = _G._create_server(serveropts(0)) + local server2 = _G._create_server(serveropts(7)) + local win = vim.api.nvim_get_current_win() + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, { 'local x = 10', '', 'print(x)' }) + vim.api.nvim_win_set_cursor(win, { 3, 6 }) + local client_id1 = assert(vim.lsp.start({ name = 'dummy', cmd = server1.cmd })) + local client_id2 = assert(vim.lsp.start({ name = 'dummy', cmd = server2.cmd })) + local response + vim.lsp.buf.definition({ + on_list = function(r) + response = r + end, + }) + vim.lsp.stop_client(client_id1) + vim.lsp.stop_client(client_id2) + return response + end) + eq(2, #result.items) + end) + end) + describe('vim.lsp.tagfunc', function() before_each(function() clear() diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index 6f0eeff748..8906e60dce 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -60,7 +60,6 @@ describe(':Man', function() c = { foreground = Screen.colors.Blue }, -- control chars eob = { bold = true, foreground = Screen.colors.Blue }, -- empty line '~'s }) - screen:attach() end) it('clears backspaces from text and adds highlights', function() diff --git a/test/functional/plugin/matchparen_spec.lua b/test/functional/plugin/matchparen_spec.lua index ae718ac1bd..b2bbdb2ef6 100644 --- a/test/functional/plugin/matchparen_spec.lua +++ b/test/functional/plugin/matchparen_spec.lua @@ -14,7 +14,6 @@ describe('matchparen', function() before_each(function() clear { args = { '-u', 'NORC' } } screen = Screen.new(20, 5) - screen:attach() screen:set_default_attr_ids({ [0] = { bold = true, foreground = 255 }, [1] = { bold = true }, diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua index c9d49f7d01..f33819f364 100644 --- a/test/functional/plugin/shada_spec.lua +++ b/test/functional/plugin/shada_spec.lua @@ -3053,7 +3053,6 @@ describe('syntax/shada.vim', function() [7] = { bold = true, reverse = true }, [8] = { bold = true, foreground = Screen.colors.Blue }, } - screen:attach() api.nvim_buf_set_lines(0, 0, 1, true, { 'Header with timestamp ' .. epoch .. ':', diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua index 1d05f4d6b4..afd4169006 100644 --- a/test/functional/plugin/tohtml_spec.lua +++ b/test/functional/plugin/tohtml_spec.lua @@ -185,8 +185,7 @@ describe(':TOhtml', function() local screen before_each(function() clear({ args = { '--clean' } }) - screen = Screen.new(80, 80) - screen:attach({ term_name = 'xterm' }) + screen = Screen.new(80, 80, { term_name = 'xterm' }) exec('colorscheme default') end) diff --git a/test/functional/plugin/tutor_spec.lua b/test/functional/plugin/tutor_spec.lua index 9f381d45db..09cd22ab6c 100644 --- a/test/functional/plugin/tutor_spec.lua +++ b/test/functional/plugin/tutor_spec.lua @@ -24,7 +24,6 @@ describe(':Tutor', function() [5] = { bold = true, foreground = Screen.colors.Magenta1 }, [6] = { italic = true }, }) - screen:attach() end) it('applies {unix:…,win:…} transform', function() diff --git a/test/functional/plugin/vim_syntax_spec.lua b/test/functional/plugin/vim_syntax_spec.lua index d99a69eab9..bdb4534cba 100644 --- a/test/functional/plugin/vim_syntax_spec.lua +++ b/test/functional/plugin/vim_syntax_spec.lua @@ -21,7 +21,6 @@ describe('Vimscript syntax highlighting', function() [1] = { foreground = Screen.colors.Brown, bold = true }, [2] = { foreground = tonumber('0x6a0dad') }, }) - screen:attach() end) it('prefixed boolean options are highlighted properly', function() diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua index 1094f9f4e5..722442acbd 100644 --- a/test/functional/provider/clipboard_spec.lua +++ b/test/functional/provider/clipboard_spec.lua @@ -94,7 +94,6 @@ describe('clipboard', function() before_each(function() clear() screen = Screen.new(72, 4) - screen:attach() end) it('unnamed register works without provider', function() @@ -318,7 +317,6 @@ describe('clipboard (with fake clipboard.vim)', function() it('`:redir @+>|bogus_cmd|redir END` must not recurse #7184', function() local screen = Screen.new(72, 4) - screen:attach() feed_command('redir @+> | bogus_cmd | redir END') screen:expect([[ ^ | @@ -641,7 +639,6 @@ describe('clipboard (with fake clipboard.vim)', function() it('supports "+ and "* in registers', function() local screen = Screen.new(60, 10) - screen:attach() feed_command("let g:test_clip['*'] = ['some', 'star data','']") feed_command("let g:test_clip['+'] = ['such', 'plus', 'stuff']") feed_command('registers') @@ -709,7 +706,6 @@ describe('clipboard (with fake clipboard.vim)', function() feed_command('set mouse=a') local screen = Screen.new(30, 5) - screen:attach() insert([[ the source a target]]) diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 7a30367917..05258a9e50 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -411,7 +411,6 @@ describe(':terminal buffer', function() it('handles split UTF-8 sequences #16245', function() local screen = Screen.new(50, 7) - screen:attach() fn.termopen({ testprg('shell-test'), 'UTF-8' }) screen:expect([[ ^å | @@ -422,6 +421,43 @@ describe(':terminal buffer', function() |*2 ]]) end) + + it("handles bell respecting 'belloff' and 'visualbell'", function() + local screen = Screen.new(50, 7) + local chan = api.nvim_open_term(0, {}) + + command('set belloff=') + api.nvim_chan_send(chan, '\a') + screen:expect(function() + eq({ true, false }, { screen.bell, screen.visual_bell }) + end) + screen.bell = false + + command('set visualbell') + api.nvim_chan_send(chan, '\a') + screen:expect(function() + eq({ false, true }, { screen.bell, screen.visual_bell }) + end) + screen.visual_bell = false + + command('set belloff=term') + api.nvim_chan_send(chan, '\a') + screen:expect({ + condition = function() + eq({ false, false }, { screen.bell, screen.visual_bell }) + end, + unchanged = true, + }) + + command('set belloff=all') + api.nvim_chan_send(chan, '\a') + screen:expect({ + condition = function() + eq({ false, false }, { screen.bell, screen.visual_bell }) + end, + unchanged = true, + }) + end) end) describe('on_lines does not emit out-of-bounds line indexes when', function() @@ -662,7 +698,6 @@ describe('termopen()', function() local function test_term_colorterm(expected, opts) local screen = Screen.new(50, 4) - screen:attach() fn.termopen({ nvim_prog, '-u', diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua index 774ff01291..9912c1ff7b 100644 --- a/test/functional/terminal/channel_spec.lua +++ b/test/functional/terminal/channel_spec.lua @@ -21,7 +21,6 @@ describe('terminal channel is closed and later released if', function() before_each(function() clear() screen = Screen.new() - screen:attach() end) it('opened by nvim_open_term() and deleted by :bdelete!', function() @@ -122,7 +121,6 @@ end) it('chansend sends lines to terminal channel in proper order', function() clear({ args = { '--cmd', 'set laststatus=2' } }) local screen = Screen.new(100, 20) - screen:attach() screen._default_attr_ids = nil local shells = is_os('win') and { 'cmd.exe', 'pwsh.exe -nop', 'powershell.exe -nop' } or { 'sh' } for _, sh in ipairs(shells) do @@ -149,7 +147,6 @@ describe('no crash when TermOpen autocommand', function() screen:set_default_attr_ids({ [0] = { bold = true, foreground = Screen.colors.Blue }, }) - screen:attach() end) it('processes job exit event when using termopen()', function() @@ -231,7 +228,6 @@ describe('nvim_open_term', function() before_each(function() clear() screen = Screen.new(8, 10) - screen:attach() end) it('with force_crlf=true converts newlines', function() diff --git a/test/functional/terminal/cursor_spec.lua b/test/functional/terminal/cursor_spec.lua index 0c5de45829..f223cdd417 100644 --- a/test/functional/terminal/cursor_spec.lua +++ b/test/functional/terminal/cursor_spec.lua @@ -122,13 +122,12 @@ describe('cursor with customized highlighting', function() clear() command('highlight TermCursor ctermfg=45 ctermbg=46 cterm=NONE') command('highlight TermCursorNC ctermfg=55 ctermbg=56 cterm=NONE') - screen = Screen.new(50, 7) + screen = Screen.new(50, 7, { rgb = false }) screen:set_default_attr_ids({ [1] = { foreground = 45, background = 46 }, [2] = { foreground = 55, background = 56 }, [3] = { bold = true }, }) - screen:attach({ rgb = false }) command('call termopen(["' .. testprg('tty-test') .. '"])') feed('i') poke_eventloop() diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua index 24c5eb28e5..dcd566d04a 100644 --- a/test/functional/terminal/edit_spec.lua +++ b/test/functional/terminal/edit_spec.lua @@ -1,7 +1,7 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local screen = require('test.functional.ui.screen') +local Screen = require('test.functional.ui.screen') local testprg = n.testprg local command = n.command @@ -13,12 +13,6 @@ local matches = t.matches local pesc = vim.pesc describe(':edit term://*', function() - local get_screen = function(columns, lines) - local scr = screen.new(columns, lines) - scr:attach({ rgb = false }) - return scr - end - before_each(function() clear() api.nvim_set_option_value('shell', testprg('shell-test'), {}) @@ -37,7 +31,7 @@ describe(':edit term://*', function() it("runs TermOpen early enough to set buffer-local 'scrollback'", function() local columns, lines = 20, 4 - local scr = get_screen(columns, lines) + local scr = Screen.new(columns, lines, { rgb = false }) local rep = 97 api.nvim_set_option_value('shellcmdflag', 'REP ' .. rep, {}) command('set shellxquote=') -- win: avoid extra quotes diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index 1039572210..5ebe7bd4fc 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -21,8 +21,7 @@ describe(':terminal', function() before_each(function() clear() - screen = Screen.new(50, 4) - screen:attach({ rgb = false }) + screen = Screen.new(50, 4, { rgb = false }) screen._default_attr_ids = nil end) @@ -169,8 +168,7 @@ local function test_terminal_with_fake_shell(backslash) before_each(function() clear() - screen = Screen.new(50, 4) - screen:attach({ rgb = false }) + screen = Screen.new(50, 4, { rgb = false }) screen._default_attr_ids = nil api.nvim_set_option_value('shell', shell_path, {}) api.nvim_set_option_value('shellcmdflag', 'EXE', {}) diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua index 05d68f6754..7822a27b93 100644 --- a/test/functional/terminal/highlight_spec.lua +++ b/test/functional/terminal/highlight_spec.lua @@ -17,7 +17,7 @@ describe(':terminal highlight', function() before_each(function() clear() - screen = Screen.new(50, 7) + screen = Screen.new(50, 7, { rgb = false }) screen:set_default_attr_ids({ [1] = { foreground = 45 }, [2] = { background = 46 }, @@ -33,7 +33,6 @@ describe(':terminal highlight', function() [12] = { bold = true, underdouble = true }, [13] = { italic = true, undercurl = true }, }) - screen:attach({ rgb = false }) command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) feed('i') screen:expect([[ @@ -130,7 +129,7 @@ end) it(':terminal highlight has lower precedence than editor #9964', function() clear() - local screen = Screen.new(30, 4) + local screen = Screen.new(30, 4, { rgb = true }) screen:set_default_attr_ids({ -- "Normal" highlight emitted by the child nvim process. N_child = { @@ -150,7 +149,6 @@ it(':terminal highlight has lower precedence than editor #9964', function() bg_indexed = true, }, }) - screen:attach({ rgb = true }) -- Child nvim process in :terminal (with cterm colors). fn.termopen({ nvim_prog_abs(), @@ -202,7 +200,6 @@ it('CursorLine and CursorColumn work in :terminal buffer in Normal mode', functi [4] = { background = Screen.colors.Grey90, reverse = true }, [5] = { background = Screen.colors.Red }, }) - screen:attach() command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) screen:expect([[ ^tty ready | @@ -308,7 +305,6 @@ describe(':terminal highlight forwarding', function() [3] = { { fg_indexed = true, foreground = tonumber('0xe0e000') }, { foreground = 3 } }, [4] = { { foreground = tonumber('0xff8000') }, {} }, }) - screen:attach() command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) feed('i') screen:expect([[ @@ -343,7 +339,7 @@ describe(':terminal highlight with custom palette', function() before_each(function() clear() - screen = Screen.new(50, 7) + screen = Screen.new(50, 7, { rgb = true }) screen:set_default_attr_ids({ [1] = { foreground = tonumber('0x123456') }, -- no fg_indexed when overridden [2] = { foreground = 12 }, @@ -354,7 +350,6 @@ describe(':terminal highlight with custom palette', function() [8] = { background = 11 }, [9] = { bold = true }, }) - screen:attach({ rgb = true }) api.nvim_set_var('terminal_color_3', '#123456') command(("enew | call termopen(['%s'])"):format(testprg('tty-test'))) feed('i') @@ -389,7 +384,6 @@ describe(':terminal', function() screen:add_extra_attr_ids { [100] = { url = 'https://example.com' }, } - screen:attach() local chan = api.nvim_open_term(0, {}) api.nvim_chan_send(chan, '\027]8;;https://example.com\027\\Example\027]8;;\027\\') screen:expect({ diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index da0bd97270..1751db1aa9 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -354,8 +354,7 @@ end) describe(':terminal prints more lines than the screen height and exits', function() it('will push extra lines to scrollback', function() clear() - local screen = Screen.new(30, 7) - screen:attach({ rgb = false }) + local screen = Screen.new(30, 7, { rgb = false }) command(("call termopen(['%s', '10']) | startinsert"):format(testprg('tty-test'))) screen:expect([[ line6 | @@ -580,7 +579,6 @@ describe('pending scrollback line handling', function() before_each(function() clear() screen = Screen.new(30, 7) - screen:attach() screen:set_default_attr_ids { [1] = { foreground = Screen.colors.Brown }, [2] = { reverse = true }, diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index a7d87bb231..ded0cd99d3 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -13,7 +13,6 @@ local eq = t.eq local feed_data = tt.feed_data local clear = n.clear local command = n.command -local dedent = t.dedent local exec = n.exec local exec_lua = n.exec_lua local testprg = n.testprg @@ -87,6 +86,21 @@ describe('TUI', function() end) end + -- Ensure both child client and child server have processed pending events. + local function poke_both_eventloop() + child_exec_lua([[ + _G.termresponse = nil + vim.api.nvim_create_autocmd('TermResponse', { + once = true, + callback = function(ev) _G.termresponse = ev.data end, + }) + ]]) + feed_data('\027P0$r\027\\') + retry(nil, nil, function() + eq('\027P0$r', child_exec_lua('return _G.termresponse')) + end) + end + it('rapid resize #7572 #7628', function() -- Need buffer rows to provoke the behavior. feed_data(':edit test/functional/fixtures/bigfile.txt\n') @@ -975,6 +989,7 @@ describe('TUI', function() {3:-- TERMINAL --} | ]]) feed_data('\027[201~') -- End paste. + poke_both_eventloop() screen:expect_unchanged() feed_data('\027[27u') -- ESC: go to Normal mode. wait_for_mode('n') @@ -1157,6 +1172,7 @@ describe('TUI', function() feed_data('\027[200~line 1\nline 2\n') wait_for_mode('c') feed_data('line 3\nline 4\n\027[201~') + poke_both_eventloop() wait_for_mode('c') screen:expect([[ foo | @@ -1201,22 +1217,19 @@ describe('TUI', function() expect_cmdline('"stuff 1 more"') -- End the paste sequence. feed_data('\027[201~') + poke_both_eventloop() expect_cmdline('"stuff 1 more"') feed_data(' typed') expect_cmdline('"stuff 1 more typed"') end) it('paste: recovers from vim.paste() failure', function() - child_session:request( - 'nvim_exec_lua', - [[ + child_exec_lua([[ _G.save_paste_fn = vim.paste -- Stack traces for this test are non-deterministic, so disable them _G.debug.traceback = function(msg) return msg end vim.paste = function(lines, phase) error("fake fail") end - ]], - {} - ) + ]]) -- Prepare something for dot-repeat/redo. feed_data('ifoo\n\027[27u') wait_for_mode('n') @@ -1269,7 +1282,7 @@ describe('TUI', function() {3:-- TERMINAL --} | ]]) -- Paste works if vim.paste() succeeds. - child_session:request('nvim_exec_lua', [[vim.paste = _G.save_paste_fn]], {}) + child_exec_lua([[vim.paste = _G.save_paste_fn]]) feed_data('\027[200~line A\nline B\n\027[201~') screen:expect([[ foo | @@ -1285,13 +1298,9 @@ describe('TUI', function() it('paste: vim.paste() cancel (retval=false) #10865', function() -- This test only exercises the "cancel" case. Use-case would be "dangling -- paste", but that is not implemented yet. #10865 - child_session:request( - 'nvim_exec_lua', - [[ + child_exec_lua([[ vim.paste = function(lines, phase) return false end - ]], - {} - ) + ]]) feed_data('\027[200~line A\nline B\n\027[201~') expect_child_buf_lines({ '' }) feed_data('ifoo\n\027[27u') @@ -1299,22 +1308,18 @@ describe('TUI', function() end) it('paste: vim.paste() cancel (retval=false) with streaming #30462', function() - child_session:request( - 'nvim_exec_lua', - [[ - vim.paste = (function(overridden) - return function(lines, phase) - for i, line in ipairs(lines) do - if line:find('!') then - return false - end + child_exec_lua([[ + vim.paste = (function(overridden) + return function(lines, phase) + for i, line in ipairs(lines) do + if line:find('!') then + return false end - return overridden(lines, phase) end - end)(vim.paste) - ]], - {} - ) + return overridden(lines, phase) + end + end)(vim.paste) + ]]) feed_data('A') wait_for_mode('i') feed_data('\027[200~aaa') @@ -1324,6 +1329,7 @@ describe('TUI', function() feed_data('ccc!') -- This chunk is cancelled. expect_child_buf_lines({ 'aaabbb' }) feed_data('ddd\027[201~') -- This chunk is ignored. + poke_both_eventloop() expect_child_buf_lines({ 'aaabbb' }) feed_data('\027[27u') wait_for_mode('n') @@ -1334,15 +1340,11 @@ describe('TUI', function() end) it("paste: 'nomodifiable' buffer", function() - child_session:request('nvim_command', 'set nomodifiable') - child_session:request( - 'nvim_exec_lua', - [[ + child_exec_lua([[ + vim.bo.modifiable = false -- Truncate the error message to hide the line number _G.debug.traceback = function(msg) return msg:sub(-49) end - ]], - {} - ) + ]]) feed_data('\027[200~fail 1\nfail 2\n\027[201~') screen:expect([[ | @@ -1354,7 +1356,7 @@ describe('TUI', function() {3:-- TERMINAL --} | ]]) feed_data('\n') -- <Enter> to dismiss hit-enter prompt - child_session:request('nvim_command', 'set modifiable') + child_exec_lua('vim.bo.modifiable = true') feed_data('\027[200~success 1\nsuccess 2\n\027[201~') screen:expect([[ success 1 | @@ -1509,9 +1511,7 @@ describe('TUI', function() end) it('paste: streamed paste with isolated "stop paste" code', function() - child_session:request( - 'nvim_exec_lua', - [[ + child_exec_lua([[ _G.paste_phases = {} vim.paste = (function(overridden) return function(lines, phase) @@ -1519,9 +1519,7 @@ describe('TUI', function() overridden(lines, phase) end end)(vim.paste) - ]], - {} - ) + ]]) feed_data('i') wait_for_mode('i') feed_data('\027[200~pasted') -- phase 1 @@ -1542,8 +1540,9 @@ describe('TUI', function() ]]) -- Send isolated "stop paste" sequence. feed_data('\027[201~') -- phase 3 + poke_both_eventloop() screen:expect_unchanged() - local _, rv = child_session:request('nvim_exec_lua', [[return _G.paste_phases]], {}) + local rv = child_exec_lua('return _G.paste_phases') -- In rare cases there may be multiple chunks of phase 2 because of timing. eq({ 1, 2, 3 }, { rv[1], rv[2], rv[#rv] }) end) @@ -1729,9 +1728,7 @@ describe('TUI', function() eq(expected, rv) ---@type table - local expected_version = ({ - child_session:request('nvim_exec_lua', 'return vim.version()', {}), - })[2] + local expected_version = child_exec_lua('return vim.version()') -- vim.version() returns `prerelease` string. Coerce it to boolean. expected_version.prerelease = not not expected_version.prerelease @@ -1855,45 +1852,73 @@ describe('TUI', function() end) it('draws correctly when cursor_address overflows #21643', function() - t.skip(is_os('mac'), 'FIXME: crashes/errors on macOS') - screen:try_resize(77, 855) + screen:try_resize(70, 333) retry(nil, nil, function() - eq({ true, 852 }, { child_session:request('nvim_win_get_height', 0) }) + eq({ true, 330 }, { child_session:request('nvim_win_get_height', 0) }) end) + child_session:request('nvim_set_option_value', 'cursorline', true, {}) -- Use full screen message so that redrawing afterwards is more deterministic. child_session:notify('nvim_command', 'intro') - screen:expect({ any = 'Nvim' }) + screen:expect({ any = 'Nvim is open source and freely distributable' }) -- Going to top-left corner needs 3 bytes. -- Setting underline attribute needs 9 bytes. - -- The whole line needs 3 + 9 + 65513 + 3 = 65528 bytes. + -- A Ꝩ character takes 3 bytes. + -- The whole line needs 3 + 9 + 3 * 21838 + 3 = 65529 bytes. -- The cursor_address that comes after will overflow the 65535-byte buffer. - local line = ('a'):rep(65513) .. '℃' - child_session:notify( - 'nvim_exec_lua', - [[ - vim.api.nvim_buf_set_lines(0, 0, -1, true, {...}) - vim.o.cursorline = true - ]], - { line, 'b' } - ) + local line = ('Ꝩ'):rep(21838) .. '℃' + child_session:notify('nvim_buf_set_lines', 0, 0, -1, true, { line, 'b' }) -- Close the :intro message and redraw the lines. feed_data('\n') - screen:expect( - '{13:a}{12:' - .. ('a'):rep(76) - .. '}|\n' - .. ('{12:' .. ('a'):rep(77) .. '}|\n'):rep(849) - .. '{12:' - .. ('a'):rep(63) - .. '℃' - .. (' '):rep(13) - .. '}|\n' - .. dedent([[ - b | - {5:[No Name] [+] }| - | - {3:-- TERMINAL --} |]]) - ) + screen:expect([[ + {13:Ꝩ}{12:ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ}| + {12:ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ}|*310 + {12:ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ℃ }| + b | + {4:~ }|*17 + {5:[No Name] [+] }| + | + {3:-- TERMINAL --} | + ]]) + end) + + it('draws correctly when setting title overflows #30793', function() + screen:try_resize(67, 327) + retry(nil, nil, function() + eq({ true, 324 }, { child_session:request('nvim_win_get_height', 0) }) + end) + child_exec_lua([[ + vim.o.cmdheight = 0 + vim.o.laststatus = 0 + vim.o.ruler = false + vim.o.showcmd = false + vim.o.termsync = false + vim.o.title = true + ]]) + retry(nil, nil, function() + eq('[No Name] - Nvim', api.nvim_buf_get_var(0, 'term_title')) + eq({ true, 326 }, { child_session:request('nvim_win_get_height', 0) }) + end) + -- Use full screen message so that redrawing afterwards is more deterministic. + child_session:notify('nvim_command', 'intro') + screen:expect({ any = 'Nvim is open source and freely distributable' }) + -- Going to top-left corner needs 3 bytes. + -- A Ꝩ character takes 3 bytes. + -- The whole line needs 3 + 3 * 21842 = 65529 bytes. + -- The title will be updated because the buffer is now modified. + -- The start of the OSC 0 sequence to set title can fit in the 65535-byte buffer, + -- but the title string cannot. + local line = ('Ꝩ'):rep(21842) + child_session:notify('nvim_buf_set_lines', 0, 0, -1, true, { line }) + -- Close the :intro message and redraw the lines. + feed_data('\n') + screen:expect([[ + {1:Ꝩ}ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ| + ꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨꝨ|*325 + {3:-- TERMINAL --} | + ]]) + retry(nil, nil, function() + eq('[No Name] + - Nvim', api.nvim_buf_get_var(0, 'term_title')) + end) end) it('visual bell (padding) does not crash #21610', function() @@ -2089,7 +2114,6 @@ describe('TUI', function() [5] = { bold = true, reverse = true }, [6] = { foreground = Screen.colors.White, background = Screen.colors.DarkGreen }, }) - screen:attach() fn.termopen({ nvim_prog, '--clean', @@ -2122,7 +2146,6 @@ describe('TUI', function() for _, guicolors in ipairs({ 'notermguicolors', 'termguicolors' }) do it('has no black flicker when clearing regions during startup with ' .. guicolors, function() local screen = Screen.new(50, 10) - screen:attach() fn.termopen({ nvim_prog, '--clean', diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua index e9218e9a3b..272fc513af 100644 --- a/test/functional/terminal/window_split_tab_spec.lua +++ b/test/functional/terminal/window_split_tab_spec.lua @@ -30,10 +30,6 @@ describe(':terminal', function() command('highlight VertSplit NONE') end) - after_each(function() - screen:detach() - end) - it('next to a closing window', function() command('split') command('terminal') diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 8a2281e2a1..60b2f872fc 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -920,36 +920,38 @@ function M.exec_lua(code, ...) return M.api.nvim_exec_lua(code, { ... }) end - assert(session) + assert(session, 'no Nvim session') if not session.exec_lua_setup then - M.api.nvim_exec_lua( - [[ - _G.__test_exec_lua = { - get_upvalues = loadstring((select(1,...))), - set_upvalues = loadstring((select(2,...))), - handler = loadstring((select(3,...))) - } - setmetatable(_G.__test_exec_lua, { __index = _G.__test_exec_lua }) - ]], - { string.dump(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) } + assert( + session:request( + 'nvim_exec_lua', + [[ + _G.__test_exec_lua = { + get_upvalues = loadstring((select(1,...))), + set_upvalues = loadstring((select(2,...))), + handler = loadstring((select(3,...))) + } + setmetatable(_G.__test_exec_lua, { __index = _G.__test_exec_lua }) + ]], + { string.dump(get_upvalues), string.dump(set_upvalues), string.dump(exec_lua_handler) } + ) ) session.exec_lua_setup = true end + local stat, rv = session:request( + 'nvim_exec_lua', + 'return { _G.__test_exec_lua:handler(...) }', + { string.dump(code), get_upvalues(code), ... } + ) + + if not stat then + error(rv[2]) + end + --- @type any[], table<string,any> - local ret, upvalues = unpack(M.api.nvim_exec_lua( - [[ - return { - _G.__test_exec_lua:handler(...) - } - ]], - { - string.dump(code), - get_upvalues(code), - ..., - } - )) + local ret, upvalues = unpack(rv) -- Update upvalues if next(upvalues) then diff --git a/test/functional/testterm.lua b/test/functional/testterm.lua index e46ae0793c..3aadcc59a7 100644 --- a/test/functional/testterm.lua +++ b/test/functional/testterm.lua @@ -112,7 +112,7 @@ function M.setup_screen(extra_rows, cmd, cols, env, screen_opts) api.nvim_command('highlight StatusLineTerm ctermbg=2 ctermfg=0') api.nvim_command('highlight StatusLineTermNC ctermbg=2 ctermfg=8') - local screen = Screen.new(cols, 7 + extra_rows) + local screen = Screen.new(cols, 7 + extra_rows, screen_opts or { rgb = false }) screen:set_default_attr_ids({ [1] = { reverse = true }, -- focused cursor [2] = { background = 11 }, -- unfocused cursor @@ -134,8 +134,6 @@ function M.setup_screen(extra_rows, cmd, cols, env, screen_opts) [18] = { background = 2, foreground = 8 }, -- StatusLineTermNC }) - screen:attach(screen_opts or { rgb = false }) - api.nvim_command('enew') api.nvim_call_function('termopen', { cmd, env and { env = env } or nil }) api.nvim_input('<CR>') diff --git a/test/functional/treesitter/fold_spec.lua b/test/functional/treesitter/fold_spec.lua index 24b085920c..e38e58ff92 100644 --- a/test/functional/treesitter/fold_spec.lua +++ b/test/functional/treesitter/fold_spec.lua @@ -442,7 +442,6 @@ t3]]) it('updates folds in all windows', function() local screen = Screen.new(60, 48) - screen:attach() screen:set_default_attr_ids({ [1] = { background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue }, [2] = { bold = true, foreground = Screen.colors.Blue1 }, @@ -603,7 +602,6 @@ t3]]) it("doesn't open folds in diff mode", function() local screen = Screen.new(60, 36) - screen:attach() parse('c') command( @@ -660,7 +658,6 @@ t3]]) it('does not extend closed fold with `o`/`O`', function() local screen = Screen.new(60, 24) - screen:attach() insert(test_text) parse('c') @@ -727,7 +724,6 @@ t3]]) [3] = { foreground = Screen.colors.Blue1, bold = true }, [4] = { bold = true }, }) - screen:attach() insert([[ # h1 diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index b5a6cb5c17..5c6be869c6 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -161,7 +161,6 @@ describe('treesitter highlighting (C)', function() before_each(function() clear() screen = Screen.new(65, 18) - screen:attach() screen:set_default_attr_ids { [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { foreground = Screen.colors.Blue1 }, @@ -848,7 +847,6 @@ describe('treesitter highlighting (lua)', function() before_each(function() clear() screen = Screen.new(65, 18) - screen:attach() screen:set_default_attr_ids { [1] = { bold = true, foreground = Screen.colors.Blue }, [2] = { foreground = Screen.colors.DarkCyan }, @@ -887,7 +885,6 @@ describe('treesitter highlighting (help)', function() before_each(function() clear() screen = Screen.new(40, 6) - screen:attach() screen:set_default_attr_ids { [1] = { foreground = Screen.colors.Blue1 }, [2] = { bold = true, foreground = Screen.colors.Blue1 }, @@ -1025,7 +1022,6 @@ describe('treesitter highlighting (nested injections)', function() before_each(function() clear() screen = Screen.new(80, 7) - screen:attach() screen:set_default_attr_ids { [1] = { foreground = Screen.colors.SlateBlue }, [2] = { bold = true, foreground = Screen.colors.Brown }, @@ -1093,7 +1089,6 @@ describe('treesitter highlighting (markdown)', function() before_each(function() clear() screen = Screen.new(40, 6) - screen:attach() exec_lua(function() vim.bo.filetype = 'markdown' vim.treesitter.start() @@ -1161,7 +1156,6 @@ it('starting and stopping treesitter highlight in init.lua works #29541', functi eq('', api.nvim_get_vvar('errmsg')) local screen = Screen.new(65, 18) - screen:attach() screen:set_default_attr_ids { [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { foreground = Screen.colors.Blue1 }, diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index e1e34fcecc..120a15d7f9 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -51,7 +51,7 @@ describe('treesitter language API', function() it('inspects language', function() local keys, fields, symbols = unpack(exec_lua(function() local lang = vim.treesitter.language.inspect('c') - local keys, symbols = {}, {} + local keys = {} for k, v in pairs(lang) do if type(v) == 'boolean' then keys[k] = v @@ -60,12 +60,7 @@ describe('treesitter language API', function() end end - -- symbols array can have "holes" and is thus not a valid msgpack array - -- but we don't care about the numbers here (checked in the parser test) - for _, v in pairs(lang.symbols) do - table.insert(symbols, v) - end - return { keys, lang.fields, symbols } + return { keys, lang.fields, lang.symbols } end)) eq({ fields = true, symbols = true, _abi_version = true, _wasm = false }, keys) @@ -78,17 +73,22 @@ describe('treesitter language API', function() eq(true, fset['directive']) eq(true, fset['initializer']) - local has_named, has_anonymous - for _, s in pairs(symbols) do - eq('string', type(s[1])) - eq('boolean', type(s[2])) - if s[1] == 'for_statement' and s[2] == true then + local has_named, has_anonymous, has_supertype + for symbol, named in pairs(symbols) do + eq('string', type(symbol)) + eq('boolean', type(named)) + if symbol == 'for_statement' and named == true then has_named = true - elseif s[1] == '|=' and s[2] == false then + elseif symbol == '"|="' and named == false then has_anonymous = true + elseif symbol == 'statement' and named == true then + has_supertype = true end end - eq({ true, true }, { has_named, has_anonymous }) + eq( + { has_named = true, has_anonymous = true, has_supertype = true }, + { has_named = has_named, has_anonymous = has_anonymous, has_supertype = has_supertype } + ) end) it( diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua index d07ed35368..c87a56b160 100644 --- a/test/functional/treesitter/node_spec.lua +++ b/test/functional/treesitter/node_spec.lua @@ -186,4 +186,28 @@ describe('treesitter node API', function() ) eq(vim.NIL, lua_eval('declarator:child_containing_descendant(value)')) end) + + it('child_with_descendant() works', function() + insert([[ + int main() { + int x = 3; + }]]) + + exec_lua(function() + local tree = vim.treesitter.get_parser(0, 'c'):parse()[1] + _G.root = assert(tree:root()) + _G.main = assert(_G.root:child(0)) + _G.body = assert(_G.main:child(2)) + _G.statement = assert(_G.body:child(1)) + _G.declarator = assert(_G.statement:child(1)) + _G.value = assert(_G.declarator:child(1)) + end) + + eq(lua_eval('main:type()'), lua_eval('root:child_with_descendant(value):type()')) + eq(lua_eval('body:type()'), lua_eval('main:child_with_descendant(value):type()')) + eq(lua_eval('statement:type()'), lua_eval('body:child_with_descendant(value):type()')) + eq(lua_eval('declarator:type()'), lua_eval('statement:child_with_descendant(value):type()')) + eq(lua_eval('value:type()'), lua_eval('declarator:child_with_descendant(value):type()')) + eq(vim.NIL, lua_eval('value:child_with_descendant(value)')) + end) end) diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index c8829f4785..2f8d204d36 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -42,13 +42,13 @@ describe('treesitter parser API', function() eq('function_definition', exec_lua('return child:type()')) eq(true, exec_lua('return child:named()')) eq('number', type(exec_lua('return child:symbol()'))) - eq({ 'function_definition', true }, exec_lua('return lang.symbols[child:symbol()]')) + eq(true, exec_lua('return lang.symbols[child:type()]')) exec_lua('anon = root:descendant_for_range(0,8,0,9)') eq('(', exec_lua('return anon:type()')) eq(false, exec_lua('return anon:named()')) eq('number', type(exec_lua('return anon:symbol()'))) - eq({ '(', false }, exec_lua('return lang.symbols[anon:symbol()]')) + eq(false, exec_lua([=[return lang.symbols[string.format('"%s"', anon:type())]]=])) exec_lua('descendant = root:descendant_for_range(1,2,1,12)') eq('<node declaration>', exec_lua('return tostring(descendant)')) diff --git a/test/functional/treesitter/query_spec.lua b/test/functional/treesitter/query_spec.lua index c97619c913..634f8af83d 100644 --- a/test/functional/treesitter/query_spec.lua +++ b/test/functional/treesitter/query_spec.lua @@ -405,6 +405,20 @@ void ui_refresh(void) { 'literal', 'number_literal', { 0, 8, 0, 11 }, '123' }, { 'literal', 'number_literal', { 2, 21, 2, 24 }, '125' }, }, result) + + result = exec_lua( + get_query_result, + [[((number_literal) @literal (#has-ancestor? @literal "enumerator"))]] + ) + eq({ + { 'literal', 'number_literal', { 1, 13, 1, 16 }, '124' }, + }, result) + + result = exec_lua( + get_query_result, + [[((number_literal) @literal (#has-ancestor? @literal "number_literal"))]] + ) + eq({}, result) end) it('allows loading query with escaped quotes and capture them `#{lua,vim}-match`?', function() @@ -708,7 +722,25 @@ void ui_refresh(void) eq(exp, pcall_err(exec_lua, "vim.treesitter.query.parse('c', ...)", cquery)) end - -- Invalid node type + -- Invalid node types + test( + '.../query.lua:0: Query error at 1:2. Invalid node type ">\\">>":\n' + .. '">\\">>" @operator\n' + .. ' ^', + '">\\">>" @operator' + ) + test( + '.../query.lua:0: Query error at 1:2. Invalid node type "\\\\":\n' + .. '"\\\\" @operator\n' + .. ' ^', + '"\\\\" @operator' + ) + test( + '.../query.lua:0: Query error at 1:2. Invalid node type ">>>":\n' + .. '">>>" @operator\n' + .. ' ^', + '">>>" @operator' + ) test( '.../query.lua:0: Query error at 1:2. Invalid node type "dentifier":\n' .. '(dentifier) @variable\n' diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 5590db5bc4..b7cf8504ff 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -16,7 +16,6 @@ describe('Buffer highlighting', function() clear() command('syntax on') screen = Screen.new(40, 8) - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue }, [2] = { foreground = Screen.colors.Fuchsia }, -- String diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua index 1c6f19245a..0ee994ba0a 100644 --- a/test/functional/ui/cmdline_highlight_spec.lua +++ b/test/functional/ui/cmdline_highlight_spec.lua @@ -24,7 +24,6 @@ end before_each(function() clear() screen = Screen.new(40, 8) - screen:attach() source([[ highlight RBP1 guibg=Red highlight RBP2 guibg=Yellow diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 6edfb4a49c..0221c1e0b0 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -13,30 +13,12 @@ local eq = t.eq local is_os = t.is_os local api = n.api -local function new_screen(opt) - local screen = Screen.new(25, 5) - screen:attach(opt) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true }, - [3] = { bold = true, reverse = true }, - [4] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [5] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [6] = { foreground = Screen.colors.Magenta }, - [7] = { bold = true, foreground = Screen.colors.Brown }, - [8] = { foreground = Screen.colors.Black, background = Screen.colors.LightGrey }, - [9] = { bold = true }, - [10] = { background = Screen.colors.Yellow1 }, - }) - return screen -end - local function test_cmdline(linegrid) local screen before_each(function() clear() - screen = new_screen({ rgb = true, ext_cmdline = true, ext_linegrid = linegrid }) + screen = Screen.new(25, 5, { rgb = true, ext_cmdline = true, ext_linegrid = linegrid }) end) it('works', function() @@ -189,7 +171,7 @@ local function test_cmdline(linegrid) }, { firstc = '=', - content = { { '1', 6 }, { '+', 7 }, { '2', 6 } }, + content = { { '1', 26 }, { '+', 15 }, { '2', 26 } }, pos = 3, }, } @@ -503,29 +485,24 @@ local function test_cmdline(linegrid) map <f5> :let x = input({'prompt':'>','highlight':'RainBowParens'})<cr> "map <f5> :let x = input({'prompt':'>'})<cr> ]]) - screen:set_default_attr_ids({ - RBP1 = { background = Screen.colors.Red }, - RBP2 = { background = Screen.colors.Yellow }, - EOB = { bold = true, foreground = Screen.colors.Blue1 }, - }) feed('<f5>(a(b)a)') screen:expect { grid = [[ ^ | - {EOB:~ }|*3 + {1:~ }|*3 | ]], cmdline = { { prompt = '>', content = { - { '(', 'RBP1' }, + { '(', 30 }, { 'a' }, - { '(', 'RBP2' }, + { '(', 10 }, { 'b' }, - { ')', 'RBP2' }, + { ')', 10 }, { 'a' }, - { ')', 'RBP1' }, + { ')', 30 }, }, pos = 7, }, @@ -865,7 +842,7 @@ describe('cmdline redraw', function() local screen before_each(function() clear() - screen = new_screen({ rgb = true }) + screen = Screen.new(25, 5, { rgb = true }) end) it('with timer', function() @@ -929,17 +906,17 @@ describe('cmdline redraw', function() | {1:~ }|*3 {2:[No Name] }| - {1::}^a{8:bc} | + {1::}^a{17:bc} | {1:~ }|*2 {3:[Command Line] }| - {9:-- VISUAL --} | + {5:-- VISUAL --} | ]]) feed('<C-C>') screen:expect([[ | {1:~ }|*3 {2:[No Name] }| - {1::}a{8:bc} | + {1::}a{17:bc} | {1:~ }|*2 {3:[Command Line] }| :^abc | @@ -1030,7 +1007,7 @@ describe('statusline is redrawn on entering cmdline', function() before_each(function() clear() - screen = new_screen() + screen = Screen.new(25, 5) command('set laststatus=2') end) @@ -1093,61 +1070,61 @@ describe('statusline is redrawn on entering cmdline', function() feed(':echoerr doesnotexist<cr>') screen:expect { grid = [[ - {9:c1 }| + {5:c1 }| | {3:c1 }| | {1:~ }|*5 {3: }| - {4:E121: Undefined variable: doesnotex}| - {4:ist} | - {5:Press ENTER or type command to cont}| - {5:inue}^ | + {9:E121: Undefined variable: doesnotex}| + {9:ist} | + {6:Press ENTER or type command to cont}| + {6:inue}^ | ]], } feed(':echoerr doesnotexist<cr>') screen:expect { grid = [[ - {9:c2 }| + {5:c2 }| | {3:c2 }| | {1:~ }|*2 {3: }| - {4:E121: Undefined variable: doesnotex}| - {4:ist} | - {5:Press ENTER or type command to cont}| - {4:E121: Undefined variable: doesnotex}| - {4:ist} | - {5:Press ENTER or type command to cont}| - {5:inue}^ | + {9:E121: Undefined variable: doesnotex}| + {9:ist} | + {6:Press ENTER or type command to cont}| + {9:E121: Undefined variable: doesnotex}| + {9:ist} | + {6:Press ENTER or type command to cont}| + {6:inue}^ | ]], } feed(':echoerr doesnotexist<cr>') screen:expect { grid = [[ - {9:c3 }| + {5:c3 }| | {3:c3 }| {3: }| - {4:E121: Undefined variable: doesnotex}| - {4:ist} | - {5:Press ENTER or type command to cont}| - {4:E121: Undefined variable: doesnotex}| - {4:ist} | - {5:Press ENTER or type command to cont}| - {4:E121: Undefined variable: doesnotex}| - {4:ist} | - {5:Press ENTER or type command to cont}| - {5:inue}^ | + {9:E121: Undefined variable: doesnotex}| + {9:ist} | + {6:Press ENTER or type command to cont}| + {9:E121: Undefined variable: doesnotex}| + {9:ist} | + {6:Press ENTER or type command to cont}| + {9:E121: Undefined variable: doesnotex}| + {9:ist} | + {6:Press ENTER or type command to cont}| + {6:inue}^ | ]], } feed('<cr>') screen:expect { grid = [[ - {9:n3 }| + {5:n3 }| ^ | {3:n3 }| | @@ -1202,12 +1179,6 @@ end) it('tabline is not redrawn in Ex mode #24122', function() clear() local screen = Screen.new(60, 5) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- MsgSeparator - [2] = { reverse = true }, -- TabLineFill - }) - screen:attach() exec([[ set showtabline=2 @@ -1224,7 +1195,7 @@ it('tabline is not redrawn in Ex mode #24122', function() grid = [[ {2:foo }| | - {1: }| + {3: }| Entering Ex mode. Type "visual" to go to Normal mode. | :^ | ]], @@ -1233,7 +1204,7 @@ it('tabline is not redrawn in Ex mode #24122', function() feed('echo 1<CR>') screen:expect { grid = [[ - {1: }| + {3: }| Entering Ex mode. Type "visual" to go to Normal mode. | :echo 1 | 1 | @@ -1247,7 +1218,6 @@ describe('cmdline height', function() it('does not crash resized screen #14263', function() local screen = Screen.new(25, 10) - screen:attach() command('set cmdheight=9999') screen:try_resize(25, 5) assert_alive() @@ -1268,7 +1238,6 @@ describe('cmdheight=0', function() before_each(function() clear() screen = Screen.new(25, 5) - screen:attach() end) it('with redrawdebug=invalid resize -1', function() @@ -1535,7 +1504,7 @@ describe('cmdheight=0', function() it('with silent! at startup', function() clear { args = { '-c', 'set cmdheight=0', '-c', 'autocmd VimEnter * silent! call Foo()' } } - screen:attach() + screen = Screen.new(25, 5) -- doesn't crash while not displaying silent! error message screen:expect { grid = [[ @@ -1547,7 +1516,7 @@ describe('cmdheight=0', function() it('with multigrid', function() clear { args = { '--cmd', 'set cmdheight=0' } } - screen:attach { ext_multigrid = true } + screen = Screen.new(25, 5, { ext_multigrid = true }) api.nvim_buf_set_lines(0, 0, -1, true, { 'p' }) screen:expect { grid = [[ @@ -1710,7 +1679,7 @@ describe('cmdheight=0', function() it('can be resized with external messages', function() clear() - screen = new_screen({ rgb = true, ext_messages = true }) + screen = Screen.new(25, 5, { rgb = true, ext_messages = true }) command('set laststatus=2 mouse=a') command('resize -1') screen:expect([[ diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index 619153724b..d7c0657820 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -12,7 +12,6 @@ describe('ui/cursor', function() before_each(function() clear() screen = Screen.new(25, 5) - screen:attach() end) it("'guicursor' is published as a UI event", function() diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 042975f898..fbf16f3afe 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -20,7 +20,6 @@ describe('decorations providers', function() before_each(function() clear() screen = Screen.new(40, 8) - screen:attach() screen:set_default_attr_ids { [1] = {bold=true, foreground=Screen.colors.Blue}; [2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}; @@ -766,7 +765,6 @@ describe('extmark decorations', function() before_each( function() clear() screen = Screen.new(50, 15) - screen:attach() screen:set_default_attr_ids { [1] = {bold=true, foreground=Screen.colors.Blue}; [2] = {foreground = Screen.colors.Brown}; @@ -1964,7 +1962,7 @@ describe('extmark decorations', function() ]]} end) - pending('highlight applies to a full TAB in visual block mode', function() + it('highlight applies to a full TAB in visual block mode', function() screen:try_resize(50, 8) command('hi! Visual guifg=NONE guibg=LightGrey') api.nvim_buf_set_lines(0, 0, -1, true, {'asdf', '\tasdf', '\tasdf', '\tasdf', 'asdf'}) @@ -2501,7 +2499,6 @@ describe('decorations: inline virtual text', function() before_each( function() clear() screen = Screen.new(50, 3) - screen:attach() screen:set_default_attr_ids { [1] = {bold=true, foreground=Screen.colors.Blue}; [2] = {foreground = Screen.colors.Brown}; @@ -4121,7 +4118,6 @@ describe('decorations: virtual lines', function() before_each(function() clear() screen = Screen.new(50, 12) - screen:attach() screen:add_extra_attr_ids { [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow }, } @@ -5046,7 +5042,6 @@ describe('decorations: signs', function() before_each(function() clear() screen = Screen.new(50, 10) - screen:attach() screen:add_extra_attr_ids { [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow }, } @@ -5662,7 +5657,6 @@ describe('decorations: virt_text', function() before_each(function() clear() screen = Screen.new(50, 10) - screen:attach() end) it('avoids regression in #17638', function() @@ -5737,7 +5731,6 @@ describe('decorations: window scoped', function() before_each(function() clear() screen = Screen.new(20, 10) - screen:attach() screen:add_extra_attr_ids { [100] = { special = Screen.colors.Red, undercurl = true }, [101] = { url = 'https://example.com' }, diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index d6a04f90f6..95159011f1 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -53,7 +53,6 @@ describe('Diff mode screen', function() feed('<c-w>w:diffthis<cr><c-w>w') screen = Screen.new(40, 16) - screen:attach() end) it('Add a line in beginning of file 2', function() @@ -1172,7 +1171,6 @@ end) it('win_update redraws lines properly', function() local screen screen = Screen.new(50, 10) - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, @@ -1250,7 +1248,6 @@ end) -- oldtest: Test_diff_rnu() it('diff updates line numbers below filler lines', function() local screen = Screen.new(40, 14) - screen:attach() exec([[ call setline(1, ['a', 'a', 'a', 'y', 'b', 'b', 'b', 'b', 'b']) vnew @@ -1310,7 +1307,6 @@ end) -- oldtest: Test_diff_with_scroll_and_change() it('Align the filler lines when changing text in diff mode', function() local screen = Screen.new(40, 20) - screen:attach() exec([[ call setline(1, range(1, 15)) vnew @@ -1376,7 +1372,6 @@ end) it("diff mode doesn't restore invalid 'foldcolumn' value #21647", function() local screen = Screen.new(60, 6) - screen:attach() eq('0', api.nvim_get_option_value('foldcolumn', {})) command('diffsplit | bd') screen:expect([[ @@ -1389,7 +1384,6 @@ end) it("'relativenumber' doesn't draw beyond end of window in diff mode #29403", function() local screen = Screen.new(60, 12) - screen:attach() command('set relativenumber') feed('10aa<CR><Esc>gg') command('vnew') @@ -1433,7 +1427,6 @@ it('diff mode works properly if file contains NUL bytes vim-patch:8.2.3925', fun screen:add_extra_attr_ids { [100] = { foreground = Screen.colors.Blue, bold = true, background = Screen.colors.Red }, } - screen:attach() exec([[ call setline(1, ['a', 'b', "c\n", 'd', 'e', 'f', 'g']) vnew @@ -1510,7 +1503,6 @@ end) -- oldtest: Test_diff_breakindent_after_filler() it("diff mode draws 'breakindent' correctly after filler lines", function() local screen = Screen.new(45, 8) - screen:attach() exec([[ set laststatus=0 diffopt+=followwrap breakindent breakindentopt=min:0 call setline(1, ['a', ' ' .. repeat('c', 50)]) @@ -1562,7 +1554,6 @@ it('diff mode overlapped diff blocks will be merged', function() ]]) local screen = Screen.new(35, 20) - screen:attach() command('set winwidth=10 diffopt=filler,internal') command('args Xdifile1 Xdifile2 | vert all | windo diffthis') @@ -2054,3 +2045,108 @@ it('diff mode overlapped diff blocks will be merged', function() | ]]) end) + +-- oldtest: Test_diff_topline_noscroll() +it('diff mode does not scroll with line("w0")', function() + local screen = Screen.new(45, 20) + exec([[ + set scrolloff=5 + call setline(1, range(1,60)) + vnew + call setline(1, range(1,10) + range(50,60)) + windo diffthis + norm! G + exe "norm! 30\<C-y>" + ]]) + screen:expect([[ + {7: }9 │{7: }9 | + {7: }10 │{7: }10 | + {7: }{23:--------------------}│{7: }{22:11 }| + {7: }{23:--------------------}│{7: }{22:12 }| + {7: }{23:--------------------}│{7: }{22:13 }| + {7: }{23:--------------------}│{7: }{22:14 }| + {7: }{23:--------------------}│{7: }{22:15 }| + {7: }{23:--------------------}│{7: }{22:16 }| + {7: }{23:--------------------}│{7: }{22:17 }| + {7: }{23:--------------------}│{7: }{22:18 }| + {7: }{23:--------------------}│{7: }{22:19 }| + {7: }{23:--------------------}│{7: }{22:20 }| + {7: }{23:--------------------}│{7: }{22:^21 }| + {7: }{23:--------------------}│{7: }{22:22 }| + {7: }{23:--------------------}│{7: }{22:23 }| + {7: }{23:--------------------}│{7: }{22:24 }| + {7: }{23:--------------------}│{7: }{22:25 }| + {7: }{23:--------------------}│{7: }{22:26 }| + {2:[No Name] [+] }{3:[No Name] [+] }| + | + ]]) + command([[echo line('w0', 1001)]]) + screen:expect([[ + {7: }9 │{7: }9 | + {7: }10 │{7: }10 | + {7: }{23:--------------------}│{7: }{22:11 }| + {7: }{23:--------------------}│{7: }{22:12 }| + {7: }{23:--------------------}│{7: }{22:13 }| + {7: }{23:--------------------}│{7: }{22:14 }| + {7: }{23:--------------------}│{7: }{22:15 }| + {7: }{23:--------------------}│{7: }{22:16 }| + {7: }{23:--------------------}│{7: }{22:17 }| + {7: }{23:--------------------}│{7: }{22:18 }| + {7: }{23:--------------------}│{7: }{22:19 }| + {7: }{23:--------------------}│{7: }{22:20 }| + {7: }{23:--------------------}│{7: }{22:^21 }| + {7: }{23:--------------------}│{7: }{22:22 }| + {7: }{23:--------------------}│{7: }{22:23 }| + {7: }{23:--------------------}│{7: }{22:24 }| + {7: }{23:--------------------}│{7: }{22:25 }| + {7: }{23:--------------------}│{7: }{22:26 }| + {2:[No Name] [+] }{3:[No Name] [+] }| + 9 | + ]]) + feed('<C-W>p') + screen:expect([[ + {7: }{23:--------------------}│{7: }{22:39 }| + {7: }{23:--------------------}│{7: }{22:40 }| + {7: }{23:--------------------}│{7: }{22:41 }| + {7: }{23:--------------------}│{7: }{22:42 }| + {7: }{23:--------------------}│{7: }{22:43 }| + {7: }{23:--------------------}│{7: }{22:44 }| + {7: }{23:--------------------}│{7: }{22:45 }| + {7: }{23:--------------------}│{7: }{22:46 }| + {7: }{23:--------------------}│{7: }{22:47 }| + {7: }{23:--------------------}│{7: }{22:48 }| + {7: }{23:--------------------}│{7: }{22:49 }| + {7: }^50 │{7: }50 | + {7: }51 │{7: }51 | + {7: }52 │{7: }52 | + {7: }53 │{7: }53 | + {7: }54 │{7: }54 | + {7: }55 │{7: }55 | + {7:+ }{13:+-- 5 lines: 56····}│{7:+ }{13:+-- 5 lines: 56····}| + {3:[No Name] [+] }{2:[No Name] [+] }| + 9 | + ]]) + feed('<C-W>p') + screen:expect([[ + {7: }{23:--------------------}│{7: }{22:39 }| + {7: }{23:--------------------}│{7: }{22:40 }| + {7: }{23:--------------------}│{7: }{22:41 }| + {7: }{23:--------------------}│{7: }{22:42 }| + {7: }{23:--------------------}│{7: }{22:43 }| + {7: }{23:--------------------}│{7: }{22:^44 }| + {7: }{23:--------------------}│{7: }{22:45 }| + {7: }{23:--------------------}│{7: }{22:46 }| + {7: }{23:--------------------}│{7: }{22:47 }| + {7: }{23:--------------------}│{7: }{22:48 }| + {7: }{23:--------------------}│{7: }{22:49 }| + {7: }50 │{7: }50 | + {7: }51 │{7: }51 | + {7: }52 │{7: }52 | + {7: }53 │{7: }53 | + {7: }54 │{7: }54 | + {7: }55 │{7: }55 | + {7:+ }{13:+-- 5 lines: 56····}│{7:+ }{13:+-- 5 lines: 56····}| + {2:[No Name] [+] }{3:[No Name] [+] }| + 9 | + ]]) +end) diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua index e1abd43e20..977141ae3e 100644 --- a/test/functional/ui/embed_spec.lua +++ b/test/functional/ui/embed_spec.lua @@ -25,34 +25,31 @@ local function test_embed(ext_linegrid) clear { args_rm = { '--headless' }, args = { ... } } -- attach immediately after startup, for early UI - screen = Screen.new(60, 8) - screen:attach { ext_linegrid = ext_linegrid } - screen:set_default_attr_ids({ - [1] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [2] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [3] = { bold = true, foreground = Screen.colors.Blue1 }, - [4] = { bold = true, foreground = Screen.colors.Green }, - [5] = { bold = true, reverse = true }, - [6] = { foreground = Screen.colors.NvimLightGrey3, background = Screen.colors.NvimDarkGrey3 }, - [7] = { foreground = Screen.colors.NvimDarkRed }, - [8] = { foreground = Screen.colors.NvimDarkCyan }, - }) + screen = Screen.new(60, 8, { ext_linegrid = ext_linegrid }) + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.NvimDarkCyan }, + [101] = { foreground = Screen.colors.NvimDarkRed }, + [102] = { + background = Screen.colors.NvimDarkGrey3, + foreground = Screen.colors.NvimLightGrey3, + }, + } end it('can display errors', function() startup('--cmd', 'echoerr invalid+') screen:expect([[ |*4 - {6: }| - {7:Error detected while processing pre-vimrc command line:} | - {7:E121: Undefined variable: invalid} | - {8:Press ENTER or type command to continue}^ | + {102: }| + {9:Error detected while processing pre-vimrc command line:} | + {9:E121: Undefined variable: invalid} | + {6:Press ENTER or type command to continue}^ | ]]) feed('<cr>') screen:expect([[ ^ | - {3:~ }|*6 + {1:~ }|*6 | ]]) end) @@ -64,11 +61,11 @@ local function test_embed(ext_linegrid) startup('--cmd', 'echoerr "foo"', '--cmd', 'color default', '--cmd', 'echoerr "bar"') screen:expect([[ |*3 - {6: }| - {7:Error detected while processing pre-vimrc command line:} | - {7:foo} | - {7:bar} | - {8:Press ENTER or type command to continue}^ | + {102: }| + {9:Error detected while processing pre-vimrc command line:} | + {9:foo} | + {101:bar} | + {100:Press ENTER or type command to continue}^ | ]]) end) @@ -77,11 +74,11 @@ local function test_embed(ext_linegrid) screen:expect { grid = [[ |*3 - {6: }| - {7:Error detected while processing pre-vimrc command line:} | - {7:foo} | - {7:bar} | - {8:Press ENTER or type command to continue}^ | + {102: }| + {9:Error detected while processing pre-vimrc command line:} | + {9:foo} | + {9:bar} | + {6:Press ENTER or type command to continue}^ | ]], condition = function() eq(Screen.colors.Green, screen.default_colors.rgb_bg) @@ -112,13 +109,10 @@ describe('--embed UI', function() clear { args_rm = { '--headless' }, io_extra = pipe.read, env = { NVIM_LOG_FILE = testlog } } -- attach immediately after startup, for early UI - local screen = Screen.new(40, 8) + -- rpc_async: Avoid hanging. #24888 + local screen = Screen.new(40, 8, { stdin_fd = 3 }, false) screen.rpc_async = true -- Avoid hanging. #24888 - screen:attach { stdin_fd = 3 } - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true }, - } + screen:attach() writer:write 'hello nvim\nfrom external input\n' writer:shutdown(function() @@ -139,7 +133,7 @@ describe('--embed UI', function() ^ | from external input | {1:~ }|*4 - {2:-- INSERT --} | + {5:-- INSERT --} | ]] if not is_os('win') then @@ -170,13 +164,9 @@ describe('--embed UI', function() clear { args_rm = { '--headless' }, args = { '-q', '-' }, io_extra = pipe.read } -- attach immediately after startup, for early UI - local screen = Screen.new(60, 8) + local screen = Screen.new(60, 8, { stdin_fd = 3 }, false) screen.rpc_async = true -- Avoid hanging. #24888 - screen:attach { stdin_fd = 3 } - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true }, - } + screen:attach() writer:write [[Xbadfile.c:4:12: error: expected ';' before '}' token]] writer:shutdown(function() @@ -202,7 +192,7 @@ describe('--embed UI', function() return 666^ | } | {1:~ }|*2 - {2:-- INSERT --} | + {5:-- INSERT --} | ]] eq('-', api.nvim_get_option_value('errorfile', {})) @@ -222,7 +212,6 @@ describe('--embed UI', function() -- attach immediately after startup, for early UI screen = Screen.new(40, 8) screen._handle_default_colors_set = handle_default_colors_set - screen:attach() end startup() @@ -249,7 +238,6 @@ describe('--embed UI', function() clear { args_rm = { '--headless' } } local screen = Screen.new(40, 8) - screen:attach() screen:expect { condition = function() @@ -336,8 +324,7 @@ describe('--embed --listen UI', function() ok(var_ok) eq({}, var) - local child_screen = Screen.new(40, 6) - child_screen:attach(nil, child_session) + local child_screen = Screen.new(40, 6, nil, child_session) child_screen:expect { grid = [[ ^ | diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 9b77cb4014..57ef9bcff6 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -640,8 +640,7 @@ describe('float window', function() end) it('tp_curwin updated if external window is moved into split', function() - local screen = Screen.new(20, 7) - screen:attach { ext_multigrid = true } + local _ = Screen.new(20, 7, { ext_multigrid = true }) command('tabnew') local external_win = api.nvim_open_win(0, true, {external = true, width = 5, height = 5}) @@ -658,8 +657,6 @@ describe('float window', function() command('tabnext') eq(2, fn.tabpagenr()) neq(external_win, api.nvim_get_current_win()) - - screen:detach() end) it('no crash with relative="win" after %bdelete #30569', function() @@ -1018,8 +1015,7 @@ describe('float window', function() local function with_ext_multigrid(multigrid) local screen, attrs before_each(function() - screen = Screen.new(40,7) - screen:attach {ext_multigrid=multigrid} + screen = Screen.new(40,7, {ext_multigrid=multigrid}) attrs = { [0] = {bold=true, foreground=Screen.colors.Blue}, [1] = {background = Screen.colors.LightMagenta}, @@ -1278,7 +1274,7 @@ describe('float window', function() it('return their configuration', function() local buf = api.nvim_create_buf(false, false) local win = api.nvim_open_win(buf, false, {relative='editor', width=20, height=2, row=3, col=5, zindex=60}) - local expected = {anchor='NW', col=5, external=false, focusable=true, height=2, relative='editor', row=3, width=20, zindex=60, hide=false} + local expected = {anchor='NW', col=5, external=false, focusable=true, mouse=true, height=2, relative='editor', row=3, width=20, zindex=60, hide=false} eq(expected, api.nvim_win_get_config(win)) eq(true, exec_lua([[ local expected, win = ... @@ -1290,11 +1286,11 @@ describe('float window', function() end return true]], expected, win)) - eq({external=false, focusable=true, hide=false, relative='',split="left",width=40,height=6}, api.nvim_win_get_config(0)) + eq({external=false, focusable=true, mouse=true, hide=false, relative='',split="left",width=40,height=6}, api.nvim_win_get_config(0)) if multigrid then api.nvim_win_set_config(win, {external=true, width=10, height=1}) - eq({external=true,focusable=true,width=10,height=1,relative='',hide=false}, api.nvim_win_get_config(win)) + eq({external=true,focusable=true,mouse=true,width=10,height=1,relative='',hide=false}, api.nvim_win_get_config(win)) end end) @@ -3988,7 +3984,7 @@ describe('float window', function() ]]} end eq({relative='win', width=12, height=1, bufpos={1,32}, anchor='NW', hide=false, - external=false, col=0, row=1, win=firstwin, focusable=true, zindex=50}, api.nvim_win_get_config(win)) + external=false, col=0, row=1, win=firstwin, focusable=true, mouse=true, zindex=50}, api.nvim_win_get_config(win)) feed('<c-e>') if multigrid then @@ -5606,7 +5602,7 @@ describe('float window', function() end end) - it("focus by mouse", function() + local function test_float_mouse_focus() if multigrid then api.nvim_input_mouse('left', 'press', '', 4, 0, 0) screen:expect{grid=[[ @@ -5660,10 +5656,18 @@ describe('float window', function() | ]]) end + end + + it("focus by mouse (focusable=true)", function() + test_float_mouse_focus() end) - it("focus by mouse (focusable=false)", function() - api.nvim_win_set_config(win, {focusable=false}) + it("focus by mouse (focusable=false, mouse=true)", function() + api.nvim_win_set_config(win, {focusable=false, mouse=true}) + test_float_mouse_focus() + end) + + local function test_float_mouse_no_focus() api.nvim_buf_set_lines(0, -1, -1, true, {"a"}) expected_pos[4][6] = false if multigrid then @@ -5721,6 +5725,16 @@ describe('float window', function() | ]]) end + end + + it("focus by mouse (focusable=false)", function() + api.nvim_win_set_config(win, {focusable=false}) + test_float_mouse_no_focus() + end) + + it("focus by mouse (focusable=true, mouse=false)", function() + api.nvim_win_set_config(win, {mouse=false}) + test_float_mouse_no_focus() end) it("j", function() diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 2712e5ff48..aea629df07 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -28,8 +28,7 @@ describe('folded lines', function() local function with_ext_multigrid(multigrid) local screen before_each(function() - screen = Screen.new(45, 8) - screen:attach({ rgb = true, ext_multigrid = multigrid }) + screen = Screen.new(45, 8, { rgb = true, ext_multigrid = multigrid }) screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { reverse = true }, @@ -55,6 +54,8 @@ describe('folded lines', function() }, [19] = { background = Screen.colors.Yellow, foreground = Screen.colors.DarkBlue }, [20] = { background = Screen.colors.Red, bold = true, foreground = Screen.colors.Blue }, + [21] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Green }, + [22] = { background = Screen.colors.Red, foreground = Screen.colors.Green }, }) end) @@ -2625,6 +2626,8 @@ describe('folded lines', function() command('hi! CursorLine guibg=NONE guifg=Red gui=NONE') command('hi F0 guibg=Red guifg=Black') command('hi F1 guifg=White') + command([[syn match Keyword /\<sentence\>/]]) + command('hi! Keyword guibg=NONE guifg=Green') api.nvim_set_option_value('cursorline', true, {}) api.nvim_set_option_value('foldcolumn', '4', {}) api.nvim_set_option_value('foldtext', '', {}) @@ -2662,7 +2665,7 @@ describe('folded lines', function() ## grid 2 {7: }This is a | {7:- }valid English | - {7:│+ }{5:sentence composed by······}| + {7:│+ }{21:sentence}{5: composed by······}| {7:│+ }{13:^in his cave.··············}| {1:~ }|*2 ## grid 3 @@ -2672,7 +2675,7 @@ describe('folded lines', function() screen:expect([[ {7: }This is a | {7:- }valid English | - {7:│+ }{5:sentence composed by······}| + {7:│+ }{21:sentence}{5: composed by······}| {7:│+ }{13:^in his cave.··············}| {1:~ }|*2 | @@ -2689,7 +2692,7 @@ describe('folded lines', function() ## grid 2 {7: }This is a | {7:- }^v{14:alid English} | - {7:│+ }{15:sentence composed by······}| + {7:│+ }{22:sentence}{15: composed by······}| {7:│+ }{15:in his cave.··············}| {1:~ }|*2 ## grid 3 @@ -2699,7 +2702,7 @@ describe('folded lines', function() screen:expect([[ {7: }This is a | {7:- }^v{14:alid English} | - {7:│+ }{15:sentence composed by······}| + {7:│+ }{22:sentence}{15: composed by······}| {7:│+ }{15:in his cave.··············}| {1:~ }|*2 {11:-- VISUAL LINE --} | @@ -2715,7 +2718,7 @@ describe('folded lines', function() ## grid 2 a si sihT{7: }| {14:hsilgnE dila}^v{7: -}| - {15:······yb desopmoc ecnetnes}{7: +│}| + {15:······yb desopmoc }{22:ecnetnes}{7: +│}| {15:··············.evac sih ni}{7: +│}| {1: ~}|*2 ## grid 3 @@ -2725,7 +2728,7 @@ describe('folded lines', function() screen:expect([[ a si sihT{7: }| {14:hsilgnE dila}^v{7: -}| - {15:······yb desopmoc ecnetnes}{7: +│}| + {15:······yb desopmoc }{22:ecnetnes}{7: +│}| {15:··············.evac sih ni}{7: +│}| {1: ~}|*2 {11:-- VISUAL LINE --} | diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 87d66fa604..0f4696f3d3 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -32,7 +32,6 @@ describe('highlight: `:syntax manual`', function() before_each(function() clear() screen = Screen.new(20, 5) - screen:attach() -- syntax highlight for vimscript's "echo" end) @@ -93,7 +92,6 @@ describe('highlight defaults', function() [100] = { foreground = Screen.colors.Red, background = Screen.colors.WebGreen }, [101] = { italic = true }, } - screen:attach() end) it('window status bar', function() @@ -303,7 +301,6 @@ describe('highlight', function() it('Visual', function() local screen = Screen.new(45, 5) - screen:attach() insert([[ line1 foo bar abcdefghijklmnopqrs @@ -428,7 +425,6 @@ describe('highlight', function() it('cterm=standout gui=standout', function() local screen = Screen.new(20, 5) - screen:attach() screen:add_extra_attr_ids { [100] = { foreground = Screen.colors.Blue1, @@ -454,7 +450,6 @@ describe('highlight', function() it('strikethrough', function() local screen = Screen.new(25, 6) - screen:attach() feed_command('syntax on') feed_command('syn keyword TmpKeyword foo') feed_command('hi! Awesome cterm=strikethrough gui=strikethrough') @@ -490,7 +485,6 @@ describe('highlight', function() background = Screen.colors.Yellow, }, } - screen:attach() feed_command('syntax on') feed_command('hi! Underlined cterm=underline gui=underline') feed_command('syn keyword Underlined foobar') @@ -532,7 +526,6 @@ describe('highlight', function() it('guisp (special/undercurl)', function() local screen = Screen.new(25, 10) - screen:attach() feed_command('syntax on') feed_command('syn keyword TmpKeyword neovim') feed_command('syn keyword TmpKeyword1 special') @@ -585,7 +578,6 @@ describe('highlight', function() it("'diff', syntax and extmark #23722", function() local screen = Screen.new(25, 10) - screen:attach() exec([[ new call setline(1, ['', '01234 6789']) @@ -631,7 +623,6 @@ describe("'listchars' highlight", function() before_each(function() clear() screen = Screen.new(20, 5) - screen:attach() end) it("'cursorline' and 'cursorcolumn'", function() @@ -873,7 +864,6 @@ describe('CursorLine and CursorLineNr highlights', function() [100] = { background = Screen.colors.LightRed }, [101] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.Grey90 }, } - screen:attach() command('filetype on') command('syntax on') @@ -906,7 +896,6 @@ describe('CursorLine and CursorLineNr highlights', function() [102] = { foreground = Screen.colors.Grey0, background = Screen.colors.Grey100 }, [103] = { foreground = Screen.colors.Yellow1, background = Screen.colors.Grey100 }, } - screen:attach() feed_command('set wrap cursorline') feed_command('set showbreak=>>>') @@ -957,7 +946,6 @@ describe('CursorLine and CursorLineNr highlights', function() [102] = { foreground = Screen.colors.Black, background = Screen.colors.Grey100 }, [103] = { foreground = Screen.colors.WebGreen, background = Screen.colors.Red }, } - screen:attach() command('set wrap cursorline cursorlineopt=screenline') command('set showbreak=>>>') @@ -1081,7 +1069,6 @@ describe('CursorLine and CursorLineNr highlights', function() -- oldtest: Test_cursorline_screenline_resize() it("'cursorlineopt' screenline is updated on window resize", function() local screen = Screen.new(75, 8) - screen:attach() exec([[ 50vnew call setline(1, repeat('xyz ', 30)) @@ -1123,7 +1110,6 @@ describe('CursorLine and CursorLineNr highlights', function() [100] = { background = Screen.colors.LightRed }, [101] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.Grey90 }, } - screen:attach() command('set cursorline relativenumber') command('call setline(1, ["","1","2","3",""])') feed('Gy3k') @@ -1151,7 +1137,6 @@ describe('CursorLine and CursorLineNr highlights', function() [100] = { foreground = Screen.colors.SlateBlue, background = Screen.colors.Grey90 }, [101] = { background = Screen.colors.LightRed }, } - screen:attach() command('set cursorline') command('call setline(1, repeat(["abc"], 50))') feed('V<C-f>zbkkjk') @@ -1166,7 +1151,6 @@ describe('CursorLine and CursorLineNr highlights', function() -- oldtest: Test_cursorline_callback() it('is updated if cursor is moved up from timer vim-patch:8.2.4591', function() local screen = Screen.new(50, 8) - screen:attach() exec([[ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd']) set cursorline @@ -1207,7 +1191,6 @@ describe('CursorLine and CursorLineNr highlights', function() [100] = { background = Screen.colors.Plum1, underline = true }, [101] = { background = Screen.colors.Red1, bold = true, underline = true }, } - screen:attach() command('hi CursorLine ctermbg=red ctermfg=white guibg=red guifg=white') command('set cursorline') @@ -1267,7 +1250,6 @@ describe('CursorLine and CursorLineNr highlights', function() screen:add_extra_attr_ids { [100] = { foreground = Screen.colors.Black, bold = true, background = Screen.colors.Grey100 }, } - screen:attach() command('hi CursorLine guibg=red guifg=white') command('hi CursorLineNr guibg=white guifg=black gui=bold') @@ -1308,7 +1290,6 @@ describe('CursorColumn highlight', function() screen:add_extra_attr_ids { [100] = { background = Screen.colors.Blue1 }, } - screen:attach() end) it('is updated when pressing "i" on a TAB character', function() @@ -1435,7 +1416,6 @@ describe('ColorColumn highlight', function() [101] = { background = Screen.colors.LightRed }, [102] = { foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.LightRed }, } - screen:attach() end) -- oldtest: Test_colorcolumn() @@ -1538,7 +1518,6 @@ describe('MsgSeparator highlight and msgsep fillchar', function() [12] = { background = Screen.colors.Gray60, bold = true, foreground = tonumber('0x297d4e') }, [13] = { background = tonumber('0xff4cff'), bold = true, foreground = tonumber('0xb200ff') }, }) - screen:attach() end) it('works', function() @@ -1653,7 +1632,6 @@ describe("'winhighlight' highlight", function() before_each(function() clear() screen = Screen.new(20, 8) - screen:attach() screen:set_default_attr_ids { [0] = { bold = true, foreground = Screen.colors.Blue }, [1] = { background = Screen.colors.DarkBlue }, @@ -1691,6 +1669,7 @@ describe("'winhighlight' highlight", function() [29] = { foreground = Screen.colors.Blue1, background = Screen.colors.Red, bold = true }, [30] = { background = tonumber('0xff8800') }, [31] = { background = tonumber('0xff8800'), bold = true, foreground = Screen.colors.Blue }, + [32] = { bold = true, reverse = true, background = Screen.colors.DarkGreen }, } command('hi Background1 guibg=DarkBlue') command('hi Background2 guibg=DarkGreen') @@ -2253,10 +2232,10 @@ describe("'winhighlight' highlight", function() some text | more tex^t | {0:~ }| - {3:[No Name] }{1:2,9 All}| + {3:[No Name] }{11:2,9 All}| some text | more text | - {4:[No Name] }{1:1,1 All}| + {4:[No Name] }{14:1,1 All}| | ]], } @@ -2267,10 +2246,10 @@ describe("'winhighlight' highlight", function() some text | more tex^t | {0:~ }| - {3:[No Name] }{5:2,9 All}| + {3:[No Name] }{32:2,9 All}| some text | more text | - {4:[No Name] }{1:1,1 All}| + {4:[No Name] }{14:1,1 All}| | ]], } @@ -2281,10 +2260,10 @@ describe("'winhighlight' highlight", function() some tex^t | more text | {0:~ }| - {3:[No Name] }{5:1,9 All}| + {3:[No Name] }{32:1,9 All}| some text | more text | - {4:[No Name] }{1:1,1 All}| + {4:[No Name] }{14:1,1 All}| | ]], } @@ -2316,7 +2295,6 @@ describe('highlight namespaces', function() before_each(function() clear() screen = Screen.new(25, 10) - screen:attach() screen:set_default_attr_ids { [1] = { foreground = Screen.colors.Blue, bold = true }, [2] = { background = Screen.colors.DarkGrey }, @@ -2425,16 +2403,24 @@ describe('highlight namespaces', function() end) it('winhl does not accept invalid value #24586', function() - local res = exec_lua([[ - local curwin = vim.api.nvim_get_current_win() - vim.api.nvim_command("set winhl=Normal:Visual") - local _, msg = pcall(vim.api.nvim_command,"set winhl='Normal:Wrong'") - return { msg, vim.wo[curwin].winhl } - ]]) - eq({ - 'Vim(set):E5248: Invalid character in group name', - 'Normal:Visual', - }, res) + command('set winhl=Normal:Visual') + for _, cmd in ipairs({ + [[set winhl='Normal:Wrong']], + [[set winhl=Normal:Wrong']], + [[set winhl='Normal:Wrong]], + }) do + local res = exec_lua( + [[ + local _, msg = pcall(vim.api.nvim_command, ...) + return { msg, vim.wo.winhl } + ]], + cmd + ) + eq({ + 'Vim(set):E5248: Invalid character in group name', + 'Normal:Visual', + }, res) + end end) it('Normal in set_hl #25474', function() @@ -2458,10 +2444,8 @@ describe('highlight namespaces', function() end) describe('synIDattr()', function() - local screen before_each(function() clear() - screen = Screen.new(50, 7) command('highlight Normal ctermfg=252 guifg=#ff0000 guibg=Black') -- Salmon #fa8072 Maroon #800000 command( @@ -2486,7 +2470,7 @@ describe('synIDattr()', function() end) it('returns gui-color if RGB-capable UI is attached', function() - screen:attach({ rgb = true }) + local _ = Screen.new(50, 7, { rgb = true }) eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg")')) eq('Black', eval('synIDattr(hlID("Normal"), "bg")')) eq('Salmon', eval('synIDattr(hlID("Keyword"), "fg")')) @@ -2494,15 +2478,15 @@ describe('synIDattr()', function() end) it('returns #RRGGBB value for fg#/bg#/sp#', function() - screen:attach({ rgb = true }) + local _ = Screen.new(50, 7, { rgb = true }) eq('#ff0000', eval('synIDattr(hlID("Normal"), "fg#")')) eq('#000000', eval('synIDattr(hlID("Normal"), "bg#")')) eq('#fa8072', eval('synIDattr(hlID("Keyword"), "fg#")')) eq('#800000', eval('synIDattr(hlID("Keyword"), "sp#")')) end) - it('returns color number if non-GUI', function() - screen:attach({ rgb = false }) + it('returns color number if non-RGB GUI', function() + local _ = Screen.new(50, 7, { rgb = false }) eq('252', eval('synIDattr(hlID("Normal"), "fg")')) eq('79', eval('synIDattr(hlID("Keyword"), "fg")')) end) @@ -2527,10 +2511,8 @@ describe('synIDattr()', function() end) describe('fg/bg special colors', function() - local screen before_each(function() clear() - screen = Screen.new(50, 7) command('highlight Normal ctermfg=145 ctermbg=16 guifg=#ff0000 guibg=Black') command('highlight Visual ctermfg=bg ctermbg=fg guifg=bg guibg=fg guisp=bg') end) @@ -2549,7 +2531,7 @@ describe('fg/bg special colors', function() end) it('resolve to "Normal" values in RGB-capable UI', function() - screen:attach({ rgb = true }) + local _ = Screen.new(50, 7, { rgb = true }) eq('bg', eval('synIDattr(hlID("Visual"), "fg")')) eq(eval('synIDattr(hlID("Normal"), "bg#")'), eval('synIDattr(hlID("Visual"), "fg#")')) eq('fg', eval('synIDattr(hlID("Visual"), "bg")')) @@ -2559,7 +2541,7 @@ describe('fg/bg special colors', function() end) it('resolve after the "Normal" group is modified', function() - screen:attach({ rgb = true }) + local _ = Screen.new(50, 7, { rgb = true }) local new_guibg = '#282c34' local new_guifg = '#abb2bf' command('highlight Normal guifg=' .. new_guifg .. ' guibg=' .. new_guibg) diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua index a255047ed7..f8f5ee9488 100644 --- a/test/functional/ui/hlstate_spec.lua +++ b/test/functional/ui/hlstate_spec.lua @@ -17,12 +17,7 @@ describe('ext_hlstate detailed highlights', function() clear() command('syntax on') command('hi VertSplit gui=reverse') - screen = Screen.new(40, 8) - screen:attach({ ext_hlstate = true }) - end) - - after_each(function() - screen:detach() + screen = Screen.new(40, 8, { ext_hlstate = true }) end) it('work with combined UI and syntax highlights', function() @@ -33,42 +28,42 @@ describe('ext_hlstate detailed highlights', function() api.nvim_buf_add_highlight(0, -1, 'Statement', 1, 5, -1) command('/th co') - screen:expect( - [[ + screen:expect { + grid = [[ these are {1:some} lines | ^wi{2:th }{4:co}{3:lorful text} | {5:~ }|*5 - {8:search hit BOTTOM, continuing at TOP}{7: }| + {8:search hit BOTTOM, continuing at TOP}{6: }| ]], - { + attr_ids = { [1] = { - { foreground = Screen.colors.Magenta }, - { { hi_name = 'Constant', kind = 'syntax' } }, + { foreground = Screen.colors.Magenta1 }, + { { kind = 'syntax', hi_name = 'Constant' } }, }, [2] = { - { background = Screen.colors.Yellow }, - { { hi_name = 'Search', ui_name = 'Search', kind = 'ui' } }, + { background = Screen.colors.Yellow1 }, + { { kind = 'ui', ui_name = 'Search', hi_name = 'Search' } }, }, [3] = { - { bold = true, foreground = Screen.colors.Brown }, - { { hi_name = 'Statement', kind = 'syntax' } }, + { foreground = Screen.colors.Brown, bold = true }, + { { kind = 'syntax', hi_name = 'Statement' } }, }, [4] = { - { bold = true, background = Screen.colors.Yellow, foreground = Screen.colors.Brown }, + { background = Screen.colors.Yellow1, bold = true, foreground = Screen.colors.Brown }, { 3, 2 }, }, [5] = { - { bold = true, foreground = Screen.colors.Blue1 }, - { { hi_name = 'NonText', ui_name = 'EndOfBuffer', kind = 'ui' } }, + { foreground = Screen.colors.Blue, bold = true }, + { { kind = 'ui', ui_name = 'EndOfBuffer', hi_name = 'NonText' } }, }, - [6] = { - { foreground = Screen.colors.Red }, - { { hi_name = 'WarningMsg', ui_name = 'WarningMsg', kind = 'ui' } }, + [6] = { {}, { { kind = 'ui', ui_name = 'MsgArea', hi_name = 'MsgArea' } } }, + [7] = { + { foreground = Screen.colors.Red1 }, + { { kind = 'syntax', hi_name = 'WarningMsg' } }, }, - [7] = { {}, { { hi_name = 'MsgArea', ui_name = 'MsgArea', kind = 'ui' } } }, - [8] = { { foreground = Screen.colors.Red }, { 7, 6 } }, - } - ) + [8] = { { foreground = Screen.colors.Red1 }, { 6, 7 } }, + }, + } end) it('work with cleared UI highlights', function() diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index c11e009fef..37dc0f5195 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -66,7 +66,6 @@ local function common_setup(screen, inccommand, text) command('syntax on') command('set nohlsearch') command('hi Substitute guifg=red guibg=yellow') - screen:attach() screen:add_extra_attr_ids { [100] = { underline = true }, @@ -556,10 +555,9 @@ describe(":substitute, 'inccommand' preserves undo", function() end) it('with undolevels=1', function() - local screen = Screen.new(20, 10) - for _, case in pairs(cases) do clear() + local screen = Screen.new(20, 10) common_setup(screen, case, default_text) screen:expect([[ Inc substitution on | @@ -617,10 +615,9 @@ describe(":substitute, 'inccommand' preserves undo", function() end) it('with undolevels=2', function() - local screen = Screen.new(20, 10) - for _, case in pairs(cases) do clear() + local screen = Screen.new(20, 10) common_setup(screen, case, default_text) command('set undolevels=2') @@ -697,10 +694,9 @@ describe(":substitute, 'inccommand' preserves undo", function() end) it('with undolevels=-1', function() - local screen = Screen.new(20, 10) - for _, case in pairs(cases) do clear() + local screen = Screen.new(20, 10) common_setup(screen, case, default_text) command('set undolevels=-1') @@ -728,6 +724,7 @@ describe(":substitute, 'inccommand' preserves undo", function() -- repeat with an interrupted substitution clear() + screen = Screen.new(20, 10) common_setup(screen, case, default_text) command('set undolevels=-1') @@ -2510,7 +2507,7 @@ describe(':substitute', function() end) it("doesn't prompt to swap cmd range", function() - screen = Screen.new(50, 8) -- wide to avoid hit-enter prompt + screen:try_resize(50, 8) -- wide to avoid hit-enter prompt common_setup(screen, 'split', default_text) feed(':2,1s/tw/MO/g') diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua index 12f3640b54..2d26d2c5e0 100644 --- a/test/functional/ui/inccommand_user_spec.lua +++ b/test/functional/ui/inccommand_user_spec.lua @@ -239,7 +239,6 @@ describe("'inccommand' for user commands", function() before_each(function() clear() screen = Screen.new(40, 17) - screen:attach() exec_lua(setup_replace_cmd) command('set cmdwinheight=5') insert [[ @@ -508,6 +507,39 @@ describe("'inccommand' for user commands", function() feed(':Test') eq('nosplit', api.nvim_get_option_value('inccommand', {})) end) + + it('does not flush intermediate cursor position at end of message grid', function() + exec_lua([[ + vim.api.nvim_create_user_command('Test', function() end, { + nargs = '*', + preview = function(_, _, _) + vim.api.nvim_buf_set_text(0, 0, 0, 1, -1, { "Preview" }) + vim.cmd.sleep("1m") + return 1 + end + }) + ]]) + local cursor_goto = screen._handle_grid_cursor_goto + screen._handle_grid_cursor_goto = function(...) + cursor_goto(...) + assert(screen._cursor.col < 12) + end + feed(':Test baz<Left><Left>arb') + screen:expect({ + grid = [[ + Preview | + oh no, even more text | + will the text ever stop | + oh well | + did the text stop | + why won't it stop | + make the text stop | + | + {1:~ }|*8 + :Test barb^az | + ]], + }) + end) end) describe("'inccommand' with multiple buffers", function() @@ -516,7 +548,6 @@ describe("'inccommand' with multiple buffers", function() before_each(function() clear() screen = Screen.new(40, 17) - screen:attach() exec_lua(setup_replace_cmd) command('set cmdwinheight=10') insert [[ diff --git a/test/functional/ui/input_spec.lua b/test/functional/ui/input_spec.lua index f377939458..90e0b3e380 100644 --- a/test/functional/ui/input_spec.lua +++ b/test/functional/ui/input_spec.lua @@ -282,7 +282,6 @@ end) it('typing a simplifiable key at hit-enter prompt triggers mapping vim-patch:8.2.0839', function() local screen = Screen.new(60, 8) - screen:attach() command([[nnoremap <C-6> <Cmd>echo 'hit ctrl-6'<CR>]]) feed_command('ls') screen:expect([[ @@ -328,7 +327,6 @@ describe('input non-printable chars', function() it("doesn't crash when echoing them back", function() write_file('Xtest-overwrite', [[foobar]]) local screen = Screen.new(60, 8) - screen:attach() command('set shortmess-=F') feed_command('e Xtest-overwrite') @@ -428,7 +426,6 @@ describe('display is updated', function() local screen before_each(function() screen = Screen.new(60, 8) - screen:attach() end) it('in Insert mode after <Nop> mapping #17911', function() diff --git a/test/functional/ui/linematch_spec.lua b/test/functional/ui/linematch_spec.lua index 03eed5a49c..b564c01eaa 100644 --- a/test/functional/ui/linematch_spec.lua +++ b/test/functional/ui/linematch_spec.lua @@ -38,7 +38,6 @@ describe('Diff mode screen with 3 diffs open', function() feed(':windo diffthis<cr>') screen = Screen.new(100, 16) - screen:attach() feed('<c-w>=') feed(':windo set nu!<cr>') end) @@ -217,7 +216,6 @@ describe('Diff mode screen with 2 diffs open', function() feed(':windo diffthis<cr>') screen = Screen.new(100, 20) - screen:attach() feed('<c-w>=') feed(':windo set nu!<cr>') end) @@ -1093,7 +1091,6 @@ describe('regressions', function() clear() feed(':set diffopt+=linematch:30<cr>') screen = Screen.new(100, 20) - screen:attach() -- line must be greater than MATCH_CHAR_MAX_LEN n.api.nvim_buf_set_lines(0, 0, -1, false, { string.rep('a', 1000) .. 'hello' }) n.exec 'vnew' @@ -1105,7 +1102,6 @@ describe('regressions', function() clear() feed(':set diffopt+=linematch:10<cr>') screen = Screen.new(100, 20) - screen:attach() local lines = {} for i = 0, 29 do lines[#lines + 1] = tostring(i) diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index a3e5068e55..734877d262 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -30,8 +30,7 @@ describe('ui/ext_messages', function() before_each(function() clear() - screen = Screen.new(25, 5) - screen:attach({ rgb = true, ext_messages = true, ext_popupmenu = true }) + screen = Screen.new(25, 5, { rgb = true, ext_messages = true, ext_popupmenu = true }) screen:add_extra_attr_ids { [100] = { undercurl = true, special = Screen.colors.Red }, } @@ -50,7 +49,7 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { '\ntest\n[O]k: ', 6 } }, + content = { { '\ntest\n[O]k: ', 6, 11 } }, kind = 'confirm', }, }, @@ -78,7 +77,7 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { '\ntest\n[O]k: ', 6 } }, + content = { { '\ntest\n[O]k: ', 6, 11 } }, kind = 'confirm', }, }, @@ -92,7 +91,7 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { '\ntest\n[O]k: ', 6 } }, + content = { { '\ntest\n[O]k: ', 6, 11 } }, kind = 'confirm', }, { @@ -100,7 +99,7 @@ describe('ui/ext_messages', function() kind = 'echo', }, { - content = { { 'Press ENTER or type command to continue', 6 } }, + content = { { 'Press ENTER or type command to continue', 6, 19 } }, kind = 'return_prompt', }, }, @@ -117,7 +116,7 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { 'replace with X (y/n/a/q/l/^E/^Y)?', 6 } }, + content = { { 'replace with X (y/n/a/q/l/^E/^Y)?', 6, 19 } }, kind = 'confirm_sub', }, }, @@ -136,7 +135,7 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { 'W10: Warning: Changing a readonly file', 19 } }, + content = { { 'W10: Warning: Changing a readonly file', 19, 27 } }, kind = 'wmsg', }, }, @@ -152,7 +151,7 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { 'search hit BOTTOM, continuing at TOP', 19 } }, + content = { { 'search hit BOTTOM, continuing at TOP', 19, 27 } }, kind = 'wmsg', }, }, @@ -168,15 +167,15 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { 'Error detected while processing :', 9 } }, + content = { { 'Error detected while processing :', 9, 7 } }, kind = 'emsg', }, { - content = { { 'E605: Exception not caught: foo', 9 } }, + content = { { 'E605: Exception not caught: foo', 9, 7 } }, kind = '', }, { - content = { { 'Press ENTER or type command to continue', 6 } }, + content = { { 'Press ENTER or type command to continue', 6, 19 } }, kind = 'return_prompt', }, }, @@ -209,7 +208,7 @@ describe('ui/ext_messages', function() {1:~ }|*4 ]], messages = { { - content = { { 'raa', 9 } }, + content = { { 'raa', 9, 7 } }, kind = 'echoerr', } }, } @@ -236,15 +235,15 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { 'bork', 9 } }, + content = { { 'bork', 9, 7 } }, kind = 'echoerr', }, { - content = { { 'fail', 9 } }, + content = { { 'fail', 9, 7 } }, kind = 'echoerr', }, { - content = { { 'Press ENTER or type command to continue', 6 } }, + content = { { 'Press ENTER or type command to continue', 6, 19 } }, kind = 'return_prompt', }, }, @@ -258,19 +257,19 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { 'bork', 9 } }, + content = { { 'bork', 9, 7 } }, kind = 'echoerr', }, { - content = { { 'fail', 9 } }, + content = { { 'fail', 9, 7 } }, kind = 'echoerr', }, { - content = { { 'extrafail', 9 } }, + content = { { 'extrafail', 9, 7 } }, kind = 'echoerr', }, { - content = { { 'Press ENTER or type command to continue', 6 } }, + content = { { 'Press ENTER or type command to continue', 6, 19 } }, kind = 'return_prompt', }, }, @@ -292,7 +291,7 @@ describe('ui/ext_messages', function() {1:~ }|*4 ]], messages = { { - content = { { 'problem', 9 } }, + content = { { 'problem', 9, 7 } }, kind = 'echoerr', } }, cmdline = { @@ -320,15 +319,15 @@ describe('ui/ext_messages', function() {1:~ }|*4 ]], msg_history = { - { kind = 'echoerr', content = { { 'raa', 9 } } }, - { kind = 'echoerr', content = { { 'bork', 9 } } }, - { kind = 'echoerr', content = { { 'fail', 9 } } }, - { kind = 'echoerr', content = { { 'extrafail', 9 } } }, - { kind = 'echoerr', content = { { 'problem', 9 } } }, + { kind = 'echoerr', content = { { 'raa', 9, 7 } } }, + { kind = 'echoerr', content = { { 'bork', 9, 7 } } }, + { kind = 'echoerr', content = { { 'fail', 9, 7 } } }, + { kind = 'echoerr', content = { { 'extrafail', 9, 7 } } }, + { kind = 'echoerr', content = { { 'problem', 9, 7 } } }, }, messages = { { - content = { { 'Press ENTER or type command to continue', 6 } }, + content = { { 'Press ENTER or type command to continue', 6, 19 } }, kind = 'return_prompt', }, }, @@ -351,10 +350,12 @@ describe('ui/ext_messages', function() ^ | {1:~ }|*4 ]], - messages = { { - content = { { 'bork\nfail', 9 } }, - kind = 'echoerr', - } }, + messages = { + { + content = { { 'bork\nfail', 9, 7 } }, + kind = 'echoerr', + }, + }, } feed(':messages<cr>') @@ -365,13 +366,13 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { 'Press ENTER or type command to continue', 6 } }, + content = { { 'Press ENTER or type command to continue', 6, 19 } }, kind = 'return_prompt', }, }, msg_history = { { - content = { { 'bork\nfail', 9 } }, + content = { { 'bork\nfail', 9, 7 } }, kind = 'echoerr', }, }, @@ -418,15 +419,15 @@ describe('ui/ext_messages', function() { content = { { '\nErrorMsg ' }, - { 'xxx', 9 }, + { 'xxx', 9, 7 }, { ' ' }, - { 'ctermfg=', 18 }, + { 'ctermfg=', 18, 6 }, { '15 ' }, - { 'ctermbg=', 18 }, + { 'ctermbg=', 18, 6 }, { '1 ' }, - { 'guifg=', 18 }, + { 'guifg=', 18, 6 }, { 'White ' }, - { 'guibg=', 18 }, + { 'guibg=', 18, 6 }, { 'Red' }, }, kind = '', @@ -446,7 +447,10 @@ describe('ui/ext_messages', function() messages = { { content = { { 'x #1' } }, kind = '' }, { content = { { 'y #2' } }, kind = '' }, - { content = { { 'Press ENTER or type command to continue', 6 } }, kind = 'return_prompt' }, + { + content = { { 'Press ENTER or type command to continue', 6, 19 } }, + kind = 'return_prompt', + }, }, } end) @@ -459,7 +463,7 @@ describe('ui/ext_messages', function() ^ | {1:~ }|*4 ]], - showmode = { { '-- INSERT --', 5 } }, + showmode = { { '-- INSERT --', 5, 12 } }, } feed('alphpabet<cr>alphanum<cr>') @@ -470,7 +474,7 @@ describe('ui/ext_messages', function() ^ | {1:~ }|*2 ]], - showmode = { { '-- INSERT --', 5 } }, + showmode = { { '-- INSERT --', 5, 12 } }, } feed('<c-x>') @@ -481,7 +485,7 @@ describe('ui/ext_messages', function() ^ | {1:~ }|*2 ]], - showmode = { { '-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)', 5 } }, + showmode = { { '-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)', 5, 12 } }, } feed('<c-p>') @@ -497,7 +501,7 @@ describe('ui/ext_messages', function() items = { { 'alphpabet', '', '', '' }, { 'alphanum', '', '', '' } }, pos = 1, }, - showmode = { { '-- Keyword Local completion (^N^P) ', 5 }, { 'match 1 of 2', 6 } }, + showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 1 of 2', 6, 19 } }, } -- echomsg and showmode don't overwrite each other, this is the same @@ -519,7 +523,7 @@ describe('ui/ext_messages', function() content = { { 'stuff' } }, kind = 'echomsg', } }, - showmode = { { '-- Keyword Local completion (^N^P) ', 5 }, { 'match 1 of 2', 6 } }, + showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 1 of 2', 6, 19 } }, } feed('<c-p>') @@ -539,7 +543,7 @@ describe('ui/ext_messages', function() content = { { 'stuff' } }, kind = 'echomsg', } }, - showmode = { { '-- Keyword Local completion (^N^P) ', 5 }, { 'match 2 of 2', 6 } }, + showmode = { { '-- Keyword Local completion (^N^P) ', 5, 12 }, { 'match 2 of 2', 6, 19 } }, } feed('<esc>:messages<cr>') @@ -556,7 +560,7 @@ describe('ui/ext_messages', function() } }, messages = { { - content = { { 'Press ENTER or type command to continue', 6 } }, + content = { { 'Press ENTER or type command to continue', 6, 19 } }, kind = 'return_prompt', }, }, @@ -570,7 +574,7 @@ describe('ui/ext_messages', function() ^ | {1:~ }|*4 ]], - showmode = { { 'recording @q', 5 } }, + showmode = { { 'recording @q', 5, 12 } }, } feed('i') @@ -579,7 +583,7 @@ describe('ui/ext_messages', function() ^ | {1:~ }|*4 ]], - showmode = { { '-- INSERT --recording @q', 5 } }, + showmode = { { '-- INSERT --recording @q', 5, 12 } }, } feed('<esc>') @@ -588,7 +592,7 @@ describe('ui/ext_messages', function() ^ | {1:~ }|*4 ]], - showmode = { { 'recording @q', 5 } }, + showmode = { { 'recording @q', 5, 12 } }, } feed('q') @@ -607,7 +611,7 @@ describe('ui/ext_messages', function() ^ | {1:~ }|*4 ]], - showmode = { { 'recording @q', 5 } }, + showmode = { { 'recording @q', 5, 12 } }, mode = 'normal', } @@ -617,7 +621,7 @@ describe('ui/ext_messages', function() ^ | {1:~ }|*4 ]], - showmode = { { 'recording @q', 5 } }, + showmode = { { 'recording @q', 5, 12 } }, mode = 'insert', } @@ -627,7 +631,7 @@ describe('ui/ext_messages', function() ^ | {1:~ }|*4 ]], - showmode = { { 'recording @q', 5 } }, + showmode = { { 'recording @q', 5, 12 } }, mode = 'normal', } @@ -643,20 +647,22 @@ describe('ui/ext_messages', function() it('supports &showcmd and &ruler', function() command('set showcmd ruler') - screen:expect { + command('hi link MsgArea ErrorMsg') + screen:expect({ grid = [[ - ^ | - {1:~ }|*4 - ]], - ruler = { { '0,0-1 All' } }, - } + ^ | + {1:~ }|*4 + ]], + ruler = { { '0,0-1 All', 9, 62 } }, + }) + command('hi clear MsgArea') feed('i') screen:expect { grid = [[ ^ | {1:~ }|*4 ]], - showmode = { { '-- INSERT --', 5 } }, + showmode = { { '-- INSERT --', 5, 12 } }, ruler = { { '0,1 All' } }, } feed('abcde<cr>12345<esc>') @@ -694,7 +700,7 @@ describe('ui/ext_messages', function() {17:123}45 | {1:~ }|*3 ]], - showmode = { { '-- VISUAL BLOCK --', 5 } }, + showmode = { { '-- VISUAL BLOCK --', 5, 12 } }, showcmd = { { '2x3' } }, ruler = { { '1,3 All' } }, }) @@ -775,7 +781,7 @@ describe('ui/ext_messages', function() {1:~ }|*4 ]], messages = { { - content = { { 'bork', 9 } }, + content = { { 'bork', 9, 7 } }, kind = 'echoerr', } }, } @@ -800,7 +806,7 @@ describe('ui/ext_messages', function() ]], messages = { { - content = { { 'E117: Unknown function: nosuchfunction', 9 } }, + content = { { 'E117: Unknown function: nosuchfunction', 9, 7 } }, kind = 'emsg', }, }, @@ -815,12 +821,12 @@ describe('ui/ext_messages', function() msg_history = { { kind = 'echomsg', content = { { 'howdy' } } }, { kind = '', content = { { 'Type :qa and press <Enter> to exit Nvim' } } }, - { kind = 'echoerr', content = { { 'bork', 9 } } }, - { kind = 'emsg', content = { { 'E117: Unknown function: nosuchfunction', 9 } } }, + { kind = 'echoerr', content = { { 'bork', 9, 7 } } }, + { kind = 'emsg', content = { { 'E117: Unknown function: nosuchfunction', 9, 7 } } }, }, messages = { { - content = { { 'Press ENTER or type command to continue', 6 } }, + content = { { 'Press ENTER or type command to continue', 6, 19 } }, kind = 'return_prompt', }, }, @@ -893,6 +899,7 @@ stack traceback: [C]: in function 'error' [string ":lua"]:1: in main chunk]], 9, + 7, }, }, kind = 'lua_error', @@ -912,7 +919,7 @@ stack traceback: messages = { { content = { - { "Error invoking 'test_method' on channel 1:\ncomplete\nerror\n\nmessage", 9 }, + { "Error invoking 'test_method' on channel 1:\ncomplete\nerror\n\nmessage", 9, 7 }, }, kind = 'rpc_error', }, @@ -937,7 +944,7 @@ stack traceback: { content = { { '\nn Q @@\nn Y y$\nn j ' }, - { '*', 18 }, + { '*', 18, 1 }, { ' k' }, }, kind = '', @@ -1035,7 +1042,10 @@ stack traceback: {1:~ }|*4 ]], messages = { - { content = { { 'wow, ', 10 }, { 'such\n\nvery ', 9 }, { 'color', 8 } }, kind = 'echomsg' }, + { + content = { { 'wow, ', 10, 9 }, { 'such\n\nvery ', 9, 7 }, { 'color', 8, 13 } }, + kind = 'echomsg', + }, }, } @@ -1057,10 +1067,16 @@ stack traceback: {1:~ }|*4 ]], messages = { - { content = { { 'Press ENTER or type command to continue', 6 } }, kind = 'return_prompt' }, + { + content = { { 'Press ENTER or type command to continue', 6, 19 } }, + kind = 'return_prompt', + }, }, msg_history = { - { content = { { 'wow, ', 10 }, { 'such\n\nvery ', 9 }, { 'color', 8 } }, kind = 'echomsg' }, + { + content = { { 'wow, ', 10, 9 }, { 'such\n\nvery ', 9, 7 }, { 'color', 8, 13 } }, + kind = 'echomsg', + }, }, } @@ -1097,14 +1113,40 @@ stack traceback: }) eq(showmode, 1) end) + + it('emits single message for multiline print())', function() + exec_lua([[print("foo\nbar\nbaz")]]) + screen:expect({ + messages = { + { + content = { { 'foo\nbar\nbaz' } }, + kind = 'lua_print', + }, + }, + }) + exec_lua([[print(vim.inspect({ foo = "bar" }))]]) + screen:expect({ + grid = [[ + ^ | + {1:~ }|*4 + ]], + messages = { + { + content = { { '{\n foo = "bar"\n}' } }, + kind = 'lua_print', + }, + }, + }) + exec_lua([[vim.print({ foo = "bar" })]]) + screen:expect_unchanged() + end) end) describe('ui/builtin messages', function() local screen before_each(function() clear() - screen = Screen.new(60, 7) - screen:attach({ rgb = true, ext_popupmenu = true }) + screen = Screen.new(60, 7, { rgb = true, ext_popupmenu = true }) screen:add_extra_attr_ids { [100] = { background = Screen.colors.LightRed }, [101] = { background = Screen.colors.Grey20 }, @@ -1652,8 +1694,7 @@ describe('ui/ext_messages', function() before_each(function() clear { args_rm = { '--headless' }, args = { '--cmd', 'set shortmess-=I' } } - screen = Screen.new(80, 24) - screen:attach({ rgb = true, ext_messages = true, ext_popupmenu = true }) + screen = Screen.new(80, 24, { rgb = true, ext_messages = true, ext_popupmenu = true }) end) it('supports intro screen', function() @@ -1678,7 +1719,7 @@ describe('ui/ext_messages', function() {1:~ }type :help iccf{18:<Enter>} for information {1: }| {1:~ }|*5 ]] - local showmode = { { '-- INSERT --', 5 } } + local showmode = { { '-- INSERT --', 5, 12 } } screen:expect(introscreen) -- <c-l> (same as :mode) does _not_ clear intro message @@ -1752,7 +1793,10 @@ describe('ui/ext_messages', function() |*5 ]], messages = { - { content = { { 'Press ENTER or type command to continue', 6 } }, kind = 'return_prompt' }, + { + content = { { 'Press ENTER or type command to continue', 6, 19 } }, + kind = 'return_prompt', + }, }, } @@ -1875,8 +1919,7 @@ end) it('ui/ext_multigrid supports intro screen', function() clear { args_rm = { '--headless' }, args = { '--cmd', 'set shortmess-=I' } } - local screen = Screen.new(80, 24) - screen:attach({ rgb = true, ext_multigrid = true }) + local screen = Screen.new(80, 24, { rgb = true, ext_multigrid = true }) screen:expect { grid = [[ @@ -1951,7 +1994,6 @@ describe('ui/msg_puts_printf', function() clear({ env = { LANG = 'ja_JP.UTF-8' } }) screen = Screen.new(25, 5) - screen:attach() if is_os('win') then if os.execute('chcp 932 > NUL 2>&1') ~= 0 then @@ -1992,7 +2034,6 @@ describe('pager', function() before_each(function() clear() screen = Screen.new(35, 8) - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue1 }, [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, @@ -2048,8 +2089,6 @@ aliquip ex ea commodo consequat.]] end) it('can be quit with Lua #11224 #16537', function() - -- NOTE: adds "4" to message history, although not displayed initially - -- (triggered the more prompt). screen:try_resize(40, 5) feed(':lua for i=0,10 do print(i) end<cr>') screen:expect { @@ -2079,13 +2118,13 @@ aliquip ex ea commodo consequat.]] {4:-- More --}^ | ]], } - feed('j') + feed('G') screen:expect { grid = [[ - 1 | - 2 | - 3 | - 4 | + 7 | + 8 | + 9 | + 10 | {4:Press ENTER or type command to continue}^ | ]], } @@ -2788,8 +2827,7 @@ it('pager works in headless mode with UI attached', function() end) local child_session = n.connect(child_server) - local child_screen = Screen.new(40, 6) - child_screen:attach(nil, child_session) + local child_screen = Screen.new(40, 6, nil, child_session) child_screen._default_attr_ids = nil -- TODO: unskip with new color scheme child_session:notify('nvim_command', [[echo range(100)->join("\n")]]) diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua index f623cfda06..8c6a284cd6 100644 --- a/test/functional/ui/mode_spec.lua +++ b/test/functional/ui/mode_spec.lua @@ -11,8 +11,7 @@ describe('ui mode_change event', function() before_each(function() clear() - screen = Screen.new(25, 4) - screen:attach({ rgb = true }) + screen = Screen.new(25, 4, { rgb = true }) end) it('works in normal mode', function() diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index bc18680749..3ee4d429c7 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -21,30 +21,20 @@ describe('ui/mouse/input', function() command('set listchars=eol:$') command('setl listchars=nbsp:x') screen = Screen.new(25, 5) - screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.LightGrey, foreground = Screen.colors.Black }, - [2] = { bold = true }, - [3] = { - foreground = Screen.colors.Blue, - background = Screen.colors.LightGrey, + screen:add_extra_attr_ids { + [100] = { bold = true, + background = Screen.colors.LightGrey, + foreground = Screen.colors.Blue1, }, - [4] = { reverse = true }, - [5] = { bold = true, reverse = true }, - [6] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [7] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - [8] = { foreground = Screen.colors.Brown }, - [9] = { background = Screen.colors.DarkGrey, foreground = Screen.colors.LightGrey }, - }) + } command('set mousemodel=extend') feed('itesting<cr>mouse<cr>support and selection<esc>') screen:expect([[ testing | mouse | support and selectio^n | - {0:~ }| + {1:~ }| | ]]) end) @@ -56,7 +46,7 @@ describe('ui/mouse/input', function() testing | mo^use | support and selection | - {0:~ }| + {1:~ }| | ]], mouse_enabled = true, @@ -66,7 +56,7 @@ describe('ui/mouse/input', function() ^testing | mouse | support and selection | - {0:~ }| + {1:~ }| | ]]) end) @@ -79,7 +69,7 @@ describe('ui/mouse/input', function() testing | mo^use | support and selection | - {0:~ }| + {1:~ }| | ]], mouse_enabled = false, @@ -89,7 +79,7 @@ describe('ui/mouse/input', function() ^testing | mouse | support and selection | - {0:~ }| + {1:~ }| | ]]) end) @@ -100,11 +90,11 @@ describe('ui/mouse/input', function() feed('<LeftMouse><0,0>') feed('<LeftRelease><0,0>') screen:expect([[ - {1:testin}^g | + {17:testin}^g | mouse | support and selection | - {0:~ }| - {2:-- VISUAL --} | + {1:~ }| + {5:-- VISUAL --} | ]]) end) @@ -116,11 +106,11 @@ describe('ui/mouse/input', function() feed('<LeftMouse><0,0>') feed('<LeftRelease><0,0>') screen:expect([[ - ^t{1:esting} | + ^t{17:esting} | mouse | support and selection | - {0:~ }| - {2:-- VISUAL LINE --} | + {1:~ }| + {5:-- VISUAL LINE --} | ]]) end) @@ -137,44 +127,35 @@ describe('ui/mouse/input', function() ^testing | mouse | support and selection | - {0:~ }| - {2:-- VISUAL BLOCK --} | + {1:~ }| + {5:-- VISUAL BLOCK --} | ]]) end) describe('tab drag', function() - before_each(function() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - tab = { background = Screen.colors.LightGrey, underline = true }, - sel = { bold = true }, - fill = { reverse = true }, - }) - end) - it('in tabline on filler space moves tab to the end', function() feed_command('%delete') insert('this is foo') feed_command('silent file foo | tabnew | file bar') insert('this is bar') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<LeftMouse><4,0>') screen:expect([[ - {sel: + foo }{tab: + bar }{fill: }{tab:X}| + {5: + foo }{24: + bar }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<LeftDrag><14,0>') screen:expect([[ - {tab: + bar }{sel: + foo }{fill: }{tab:X}| + {24: + bar }{5: + foo }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) end) @@ -185,9 +166,9 @@ describe('ui/mouse/input', function() feed_command('silent file foo | tabnew | file bar') insert('this is bar') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<LeftMouse><11,0>') @@ -196,18 +177,18 @@ describe('ui/mouse/input', function() poke_eventloop() screen:expect { grid = [[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]], unchanged = true, } feed('<LeftDrag><6,0>') screen:expect([[ - {sel: + bar }{tab: + foo }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {5: + bar }{24: + foo }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) end) @@ -218,23 +199,23 @@ describe('ui/mouse/input', function() feed_command('silent file foo | tabnew | file bar') insert('this is bar') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<LeftMouse><4,0>') screen:expect([[ - {sel: + foo }{tab: + bar }{fill: }{tab:X}| + {5: + foo }{24: + bar }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<LeftDrag><7,0>') screen:expect([[ - {tab: + bar }{sel: + foo }{fill: }{tab:X}| + {24: + bar }{5: + foo }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) end) @@ -245,33 +226,33 @@ describe('ui/mouse/input', function() feed_command('silent file foo | tabnew | file bar') insert('this is bar') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<LeftMouse><4,0>') screen:expect([[ - {sel: + foo }{tab: + bar }{fill: }{tab:X}| + {5: + foo }{24: + bar }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<LeftDrag><4,1>') screen:expect { grid = [[ - {sel: + foo }{tab: + bar }{fill: }{tab:X}| + {5: + foo }{24: + bar }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]], unchanged = true, } feed('<LeftDrag><14,1>') screen:expect([[ - {tab: + bar }{sel: + foo }{fill: }{tab:X}| + {24: + bar }{5: + foo }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) end) @@ -282,9 +263,9 @@ describe('ui/mouse/input', function() feed_command('silent file foo | tabnew | file bar') insert('this is bar') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<LeftMouse><11,0>') @@ -293,9 +274,9 @@ describe('ui/mouse/input', function() poke_eventloop() screen:expect { grid = [[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]], unchanged = true, @@ -303,18 +284,18 @@ describe('ui/mouse/input', function() feed('<LeftDrag><11,1>') screen:expect { grid = [[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]], unchanged = true, } feed('<LeftDrag><6,1>') screen:expect([[ - {sel: + bar }{tab: + foo }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {5: + bar }{24: + foo }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) end) @@ -325,73 +306,64 @@ describe('ui/mouse/input', function() feed_command('silent file foo | tabnew | file bar') insert('this is bar') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<LeftMouse><4,0>') screen:expect([[ - {sel: + foo }{tab: + bar }{fill: }{tab:X}| + {5: + foo }{24: + bar }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<LeftDrag><4,1>') screen:expect { grid = [[ - {sel: + foo }{tab: + bar }{fill: }{tab:X}| + {5: + foo }{24: + bar }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]], unchanged = true, } feed('<LeftDrag><7,1>') screen:expect([[ - {tab: + bar }{sel: + foo }{fill: }{tab:X}| + {24: + bar }{5: + foo }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) end) end) describe('tabline', function() - before_each(function() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - tab = { background = Screen.colors.LightGrey, underline = true }, - sel = { bold = true }, - fill = { reverse = true }, - }) - end) - it('left click in default tabline (tabpage label) switches to tab', function() feed_command('%delete') insert('this is foo') feed_command('silent file foo | tabnew | file bar') insert('this is bar') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<LeftMouse><4,0>') screen:expect([[ - {sel: + foo }{tab: + bar }{fill: }{tab:X}| + {5: + foo }{24: + bar }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<LeftMouse><6,0>') screen:expect_unchanged() feed('<LeftMouse><10,0>') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<LeftMouse><12,0>') @@ -404,23 +376,23 @@ describe('ui/mouse/input', function() feed_command('silent file foo | tabnew | file bar') insert('this is bar') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<LeftMouse><20,0>') screen:expect([[ - {sel: + foo }{tab: + bar }{fill: }{tab:X}| + {5: + foo }{24: + bar }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<LeftMouse><22,0>') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) end) @@ -432,15 +404,15 @@ describe('ui/mouse/input', function() feed_command('silent file foo | tabnew | file bar') insert('this is bar') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<LeftMouse><24,0>') screen:expect([[ this is fo^o | - {0:~ }|*3 + {1:~ }|*3 | ]]) end) @@ -451,44 +423,44 @@ describe('ui/mouse/input', function() feed_command('silent file foo | tabnew | file bar') insert('this is bar') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<2-LeftMouse><4,0>') screen:expect([[ - {sel: Name] }{tab: + foo + bar }{fill: }{tab:X}| - {0:^$} | - {0:~ }|*2 + {5: Name] }{24: + foo + bar }{2: }{24:X}| + {1:^$} | + {1:~ }|*2 | ]]) command('tabclose') screen:expect([[ - {sel: + foo }{tab: + bar }{fill: }{tab:X}| + {5: + foo }{24: + bar }{2: }{24:X}| this is fo^o | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<2-LeftMouse><20,0>') screen:expect([[ - {tab: + foo + bar }{sel: Name] }{fill: }{tab:X}| - {0:^$} | - {0:~ }|*2 + {24: + foo + bar }{5: Name] }{2: }{24:X}| + {1:^$} | + {1:~ }|*2 | ]]) command('tabclose') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - this is ba^r{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + this is ba^r{1:$} | + {1:~ }|*2 | ]]) feed('<2-LeftMouse><10,0>') screen:expect([[ - {tab: + foo }{sel: Name] }{tab: + bar }{fill: }{tab:X}| - {0:^$} | - {0:~ }|*2 + {24: + foo }{5: Name] }{24: + bar }{2: }{24:X}| + {1:^$} | + {1:~ }|*2 | ]]) end) @@ -509,7 +481,7 @@ describe('ui/mouse/input', function() api.nvim_set_option_value('tabline', '%@Test@test%X-%5@Test2@test2', {}) api.nvim_set_option_value('showtabline', 2, {}) screen:expect([[ - {fill:test-test2 }| + {2:test-test2 }| testing | mouse | support and selectio^n | @@ -594,48 +566,41 @@ describe('ui/mouse/input', function() testing | mo^use | support and selection | - {0:~ }| + {1:~ }| | ]]) feed('<LeftDrag><4,1>') screen:expect([[ testing | - mo{1:us}^e | + mo{17:us}^e | support and selection | - {0:~ }| - {2:-- VISUAL --} | + {1:~ }| + {5:-- VISUAL --} | ]]) feed('<LeftDrag><2,2>') screen:expect([[ testing | - mo{1:use} | - {1:su}^pport and selection | - {0:~ }| - {2:-- VISUAL --} | + mo{17:use} | + {17:su}^pport and selection | + {1:~ }| + {5:-- VISUAL --} | ]]) feed('<LeftDrag><0,0>') screen:expect([[ - ^t{1:esting} | - {1:mou}se | + ^t{17:esting} | + {17:mou}se | support and selection | - {0:~ }| - {2:-- VISUAL --} | + {1:~ }| + {5:-- VISUAL --} | ]]) end) it('left drag changes visual selection after tab click', function() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - tab = { background = Screen.colors.LightGrey, underline = true }, - sel = { bold = true }, - fill = { reverse = true }, - vis = { background = Screen.colors.LightGrey, foreground = Screen.colors.Black }, - }) feed_command('silent file foo | tabnew | file bar') insert('this is bar') feed_command('tabprevious') -- go to first tab screen:expect([[ - {sel: + foo }{tab: + bar }{fill: }{tab:X}| + {5: + foo }{24: + bar }{2: }{24:X}| testing | mouse | support and selectio^n | @@ -645,17 +610,17 @@ describe('ui/mouse/input', function() n.poke_eventloop() feed('<LeftMouse><0,1>') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - ^this is bar{0:$} | - {0:~ }|*2 + {24: + foo }{5: + bar }{2: }{24:X}| + ^this is bar{1:$} | + {1:~ }|*2 :tabprevious | ]]) feed('<LeftDrag><4,1>') screen:expect([[ - {tab: + foo }{sel: + bar }{fill: }{tab:X}| - {vis:this}^ is bar{0:$} | - {0:~ }|*2 - {sel:-- VISUAL --} | + {24: + foo }{5: + bar }{2: }{24:X}| + {17:this}^ is bar{1:$} | + {1:~ }|*2 + {5:-- VISUAL --} | ]]) end) @@ -673,12 +638,12 @@ describe('ui/mouse/input', function() testing │testing | mouse │mouse | support and selection │support and selection | - {0:~ }│{0:~ }|*2 - {0:~ }│{4:[No Name] [+] }| - {0:~ }│foo{0:$} | - {0:~ }│ba^r{0:$} | - {0:~ }│{0:~ }|*4 - {4:[No Name] [+] }{5:[No Name] [+] }| + {1:~ }│{1:~ }|*2 + {1:~ }│{2:[No Name] [+] }| + {1:~ }│foo{1:$} | + {1:~ }│ba^r{1:$} | + {1:~ }│{1:~ }|*4 + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } @@ -689,12 +654,12 @@ describe('ui/mouse/input', function() testing │testing | mouse │mouse | support and selection │support and selection | - {0:~ }│{0:~ }|*2 - {0:~ }│{4:[No Name] [+] }| - {0:~ }│^foo{0:$} | - {0:~ }│bar{0:$} | - {0:~ }│{0:~ }|*4 - {4:[No Name] [+] }{5:[No Name] [+] }| + {1:~ }│{1:~ }|*2 + {1:~ }│{2:[No Name] [+] }| + {1:~ }│^foo{1:$} | + {1:~ }│bar{1:$} | + {1:~ }│{1:~ }|*4 + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } @@ -705,13 +670,13 @@ describe('ui/mouse/input', function() testing │testing | mouse │mouse | support and selection │support and selection | - {0:~ }│{0:~ }|*2 - {0:~ }│{4:[No Name] [+] }| - {0:~ }│{1:foo}{3:$} | - {0:~ }│{1:bar}{0:^$} | - {0:~ }│{0:~ }|*4 - {4:[No Name] [+] }{5:[No Name] [+] }| - {2:-- VISUAL --} | + {1:~ }│{1:~ }|*2 + {1:~ }│{2:[No Name] [+] }| + {1:~ }│{17:foo}{100:$} | + {1:~ }│{17:bar}{1:^$} | + {1:~ }│{1:~ }|*4 + {2:[No Name] [+] }{3:[No Name] [+] }| + {5:-- VISUAL --} | ]], } end) @@ -723,33 +688,33 @@ describe('ui/mouse/input', function() screen:expect([[ testing | mouse | - {1:suppor}^t and selection | - {0:~ }| - {2:-- VISUAL --} | + {17:suppor}^t and selection | + {1:~ }| + {5:-- VISUAL --} | ]]) feed('<LeftDrag><0,1>') screen:expect([[ testing | - ^m{1:ouse} | - {1:support} and selection | - {0:~ }| - {2:-- VISUAL --} | + ^m{17:ouse} | + {17:support} and selection | + {1:~ }| + {5:-- VISUAL --} | ]]) feed('<LeftDrag><4,0>') screen:expect([[ - ^t{1:esting} | - {1:mouse} | - {1:support} and selection | - {0:~ }| - {2:-- VISUAL --} | + ^t{17:esting} | + {17:mouse} | + {17:support} and selection | + {1:~ }| + {5:-- VISUAL --} | ]]) feed('<LeftDrag><14,2>') screen:expect([[ testing | mouse | - {1:support and selectio}^n | - {0:~ }| - {2:-- VISUAL --} | + {17:support and selectio}^n | + {1:~ }| + {5:-- VISUAL --} | ]]) end) @@ -762,33 +727,33 @@ describe('ui/mouse/input', function() screen:expect([[ testing | mouse | - {1:su}^p{1:port and selection} | - {0:~ }| - {2:-- VISUAL LINE --} | + {17:su}^p{17:port and selection} | + {1:~ }| + {5:-- VISUAL LINE --} | ]]) feed('<LeftDrag><0,1>') screen:expect([[ testing | - ^m{1:ouse} | - {1:support and selection} | - {0:~ }| - {2:-- VISUAL LINE --} | + ^m{17:ouse} | + {17:support and selection} | + {1:~ }| + {5:-- VISUAL LINE --} | ]]) feed('<LeftDrag><4,0>') screen:expect([[ - {1:test}^i{1:ng} | - {1:mouse} | - {1:support and selection} | - {0:~ }| - {2:-- VISUAL LINE --} | + {17:test}^i{17:ng} | + {17:mouse} | + {17:support and selection} | + {1:~ }| + {5:-- VISUAL LINE --} | ]]) feed('<LeftDrag><14,2>') screen:expect([[ testing | mouse | - {1:support and se}^l{1:ection} | - {0:~ }| - {2:-- VISUAL LINE --} | + {17:support and se}^l{17:ection} | + {1:~ }| + {5:-- VISUAL LINE --} | ]]) end) @@ -804,32 +769,32 @@ describe('ui/mouse/input', function() testing | mouse | su^pport and selection | - {0:~ }| - {2:-- VISUAL BLOCK --} | + {1:~ }| + {5:-- VISUAL BLOCK --} | ]]) feed('<LeftDrag><0,1>') screen:expect([[ testing | - ^m{1:ou}se | - {1:sup}port and selection | - {0:~ }| - {2:-- VISUAL BLOCK --} | + ^m{17:ou}se | + {17:sup}port and selection | + {1:~ }| + {5:-- VISUAL BLOCK --} | ]]) feed('<LeftDrag><4,0>') screen:expect([[ - te{1:st}^ing | - mo{1:use} | - su{1:ppo}rt and selection | - {0:~ }| - {2:-- VISUAL BLOCK --} | + te{17:st}^ing | + mo{17:use} | + su{17:ppo}rt and selection | + {1:~ }| + {5:-- VISUAL BLOCK --} | ]]) feed('<LeftDrag><14,2>') screen:expect([[ testing | mouse | - su{1:pport and se}^lection | - {0:~ }| - {2:-- VISUAL BLOCK --} | + su{17:pport and se}^lection | + {1:~ }| + {5:-- VISUAL BLOCK --} | ]]) end) @@ -839,16 +804,16 @@ describe('ui/mouse/input', function() ^testing | mouse | support and selection | - {0:~ }| + {1:~ }| | ]]) feed('<RightMouse><2,2>') screen:expect([[ - {1:testing} | - {1:mouse} | - {1:su}^pport and selection | - {0:~ }| - {2:-- VISUAL --} | + {17:testing} | + {17:mouse} | + {17:su}^pport and selection | + {1:~ }| + {5:-- VISUAL --} | ]]) end) @@ -856,11 +821,11 @@ describe('ui/mouse/input', function() api.nvim_set_option_value('tags', './non-existent-tags-file', {}) feed('<C-LeftMouse><0,0>') screen:expect([[ - {6:E433: No tags file} | - {6:E426: Tag not found: test}| - {6:ing} | - {7:Press ENTER or type comma}| - {7:nd to continue}^ | + {9:E433: No tags file} | + {9:E426: Tag not found: test}| + {9:ing} | + {6:Press ENTER or type comma}| + {6:nd to continue}^ | ]]) feed('<cr>') end) @@ -890,54 +855,54 @@ describe('ui/mouse/input', function() local oldwin = api.nvim_get_current_win() command('rightbelow vnew') screen:expect([[ - testing │{0:^$} | - mouse │{0:~ }| - support and selection │{0:~ }| - {4:[No Name] [+] }{5:[No Name] }| + testing │{1:^$} | + mouse │{1:~ }| + support and selection │{1:~ }| + {2:[No Name] [+] }{3:[No Name] }| | ]]) api.nvim_input_mouse('left', 'press', '', 0, 0, 22) poke_eventloop() api.nvim_input_mouse('left', 'drag', '', 0, 1, 12) screen:expect([[ - testing │{0:^$} | - mouse │{0:~ }| - support and │{0:~ }| - {4:< Name] [+] }{5:[No Name] }| + testing │{1:^$} | + mouse │{1:~ }| + support and │{1:~ }| + {2:< Name] [+] }{3:[No Name] }| | ]]) api.nvim_input_mouse('left', 'drag', '', 0, 2, 2) screen:expect([[ - te│{0:^$} | - mo│{0:~ }| - su│{0:~ }| - {4:< }{5:[No Name] }| + te│{1:^$} | + mo│{1:~ }| + su│{1:~ }| + {2:< }{3:[No Name] }| | ]]) api.nvim_input_mouse('left', 'release', '', 0, 2, 2) api.nvim_set_option_value('statuscolumn', 'foobar', { win = oldwin }) screen:expect([[ - {8:fo}│{0:^$} | - {8:fo}│{0:~ }|*2 - {4:< }{5:[No Name] }| + {8:fo}│{1:^$} | + {8:fo}│{1:~ }|*2 + {2:< }{3:[No Name] }| | ]]) api.nvim_input_mouse('left', 'press', '', 0, 0, 2) poke_eventloop() api.nvim_input_mouse('left', 'drag', '', 0, 1, 12) screen:expect([[ - {8:foobar}testin│{0:^$} | - {8:foobar}mouse │{0:~ }| - {8:foobar}suppor│{0:~ }| - {4:< Name] [+] }{5:[No Name] }| + {8:foobar}testin│{1:^$} | + {8:foobar}mouse │{1:~ }| + {8:foobar}suppor│{1:~ }| + {2:< Name] [+] }{3:[No Name] }| | ]]) api.nvim_input_mouse('left', 'drag', '', 0, 2, 22) screen:expect([[ - {8:foobar}testing │{0:^$} | - {8:foobar}mouse │{0:~ }| - {8:foobar}support and sele│{0:~ }| - {4:[No Name] [+] }{5:[No Name] }| + {8:foobar}testing │{1:^$} | + {8:foobar}mouse │{1:~ }| + {8:foobar}support and sele│{1:~ }| + {2:[No Name] [+] }{3:[No Name] }| | ]]) api.nvim_input_mouse('left', 'release', '', 0, 2, 22) @@ -964,14 +929,14 @@ describe('ui/mouse/input', function() test │test | ^mouse scrolling │mouse scrolling | │ | - {0:~ }│{0:~ }| - {5:[No Name] [+] }{4:[No Name] [+] }| + {1:~ }│{1:~ }| + {3:[No Name] [+] }{2:[No Name] [+] }| to | test | mouse scrolling | | - {0:~ }| - {4:[No Name] [+] }| + {1:~ }| + {2:[No Name] [+] }| :vsp | ]]) if use_api then @@ -982,17 +947,17 @@ describe('ui/mouse/input', function() screen:expect([[ ^mouse scrolling │lines | │to | - {0:~ }│test | - {0:~ }│mouse scrolling | - {0:~ }│ | - {0:~ }│{0:~ }| - {5:[No Name] [+] }{4:[No Name] [+] }| + {1:~ }│test | + {1:~ }│mouse scrolling | + {1:~ }│ | + {1:~ }│{1:~ }| + {3:[No Name] [+] }{2:[No Name] [+] }| to | test | mouse scrolling | | - {0:~ }| - {4:[No Name] [+] }| + {1:~ }| + {2:[No Name] [+] }| :vsp | ]]) if use_api then @@ -1003,17 +968,17 @@ describe('ui/mouse/input', function() screen:expect([[ ^mouse scrolling │text | │with | - {0:~ }│many | - {0:~ }│lines | - {0:~ }│to | - {0:~ }│test | - {5:[No Name] [+] }{4:[No Name] [+] }| + {1:~ }│many | + {1:~ }│lines | + {1:~ }│to | + {1:~ }│test | + {3:[No Name] [+] }{2:[No Name] [+] }| to | test | mouse scrolling | | - {0:~ }| - {4:[No Name] [+] }| + {1:~ }| + {2:[No Name] [+] }| :vsp | ]]) if use_api then @@ -1025,17 +990,17 @@ describe('ui/mouse/input', function() screen:expect([[ ^mouse scrolling │text | │with | - {0:~ }│many | - {0:~ }│lines | - {0:~ }│to | - {0:~ }│test | - {5:[No Name] [+] }{4:[No Name] [+] }| + {1:~ }│many | + {1:~ }│lines | + {1:~ }│to | + {1:~ }│test | + {3:[No Name] [+] }{2:[No Name] [+] }| Inserting | text | with | many | lines | - {4:[No Name] [+] }| + {2:[No Name] [+] }| :vsp | ]]) end @@ -1056,7 +1021,7 @@ describe('ui/mouse/input', function() screen:expect([[ |*2 bbbbbbbbbbbbbbb^b | - {0:~ }| + {1:~ }| | ]]) @@ -1064,7 +1029,7 @@ describe('ui/mouse/input', function() screen:expect([[ |*2 n bbbbbbbbbbbbbbbbbbb^b | - {0:~ }| + {1:~ }| | ]]) @@ -1073,7 +1038,7 @@ describe('ui/mouse/input', function() g | | ^t and selection bbbbbbbbb| - {0:~ }| + {1:~ }| | ]]) end) @@ -1086,7 +1051,7 @@ describe('ui/mouse/input', function() screen:expect([[ |*2 bbbbbbbbbbbbbbb^b | - {0:~ }| + {1:~ }| | ]]) @@ -1094,7 +1059,7 @@ describe('ui/mouse/input', function() screen:expect([[ |*2 n bbbbbbbbbbbbbbbbbbb^b | - {0:~ }| + {1:~ }| | ]]) @@ -1104,7 +1069,7 @@ describe('ui/mouse/input', function() g | | ^t and selection bbbbbbbbb| - {0:~ }| + {1:~ }| | ]]) end) @@ -1118,7 +1083,7 @@ describe('ui/mouse/input', function() testing | mouse | ^bbbbbbbbbbbbbbbbbbbb supp| - {0:~ }| + {1:~ }| | ]]) @@ -1127,7 +1092,7 @@ describe('ui/mouse/input', function() g | | bbbb^bbbbbbbbbb support an| - {0:~ }| + {1:~ }| | ]]) @@ -1138,7 +1103,7 @@ describe('ui/mouse/input', function() testing | mouse | ^bbbbbbbbbbbbbbbbbbbb supp| - {0:~ }| + {1:~ }| | ]]) @@ -1147,7 +1112,7 @@ describe('ui/mouse/input', function() g | | bb^bbbbbbbbbbbb support an| - {0:~ }| + {1:~ }| | ]]) end) @@ -1158,71 +1123,71 @@ describe('ui/mouse/input', function() feed('<esc><LeftMouse><0,0>') screen:expect([[ - ^Section{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| - {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}| + ^Section{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }| + {14:>} 私は猫が大好き{1:>---}{14: X } {1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><1,0>') screen:expect([[ - S^ection{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| - {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}| + S^ection{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }| + {14:>} 私は猫が大好き{1:>---}{14: X } {1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><21,0>') screen:expect([[ - Section{0:>>--->--->---}{c: }^t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| - {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}| + Section{1:>>--->--->---}{14: }^t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }| + {14:>} 私は猫が大好き{1:>---}{14: X } {1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><21,1>') screen:expect([[ - Section{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t^3{c: } {c: }| - {c:>} 私は猫が大好き{0:>---}{c: X } {0:>}| + Section{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t^3{14: } {14: }| + {14:>} 私は猫が大好き{1:>---}{14: X } {1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><0,2>') screen:expect([[ - Section{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| - {c:^>} 私は猫が大好き{0:>---}{c: X } {0:>}| + Section{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }| + {14:^>} 私は猫が大好き{1:>---}{14: X } {1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><7,2>') screen:expect([[ - Section{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| - {c:>} 私は^猫が大好き{0:>---}{c: X } {0:>}| + Section{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }| + {14:>} 私は^猫が大好き{1:>---}{14: X } {1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><21,2>') screen:expect([[ - Section{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| - {c:>} 私は猫が大好き{0:>---}{c: ^X } {0:>}| + Section{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }| + {14:>} 私は猫が大好き{1:>---}{14: ^X } {1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) end) -- level 1 - non wrapped @@ -1232,51 +1197,51 @@ describe('ui/mouse/input', function() feed('<esc><LeftMouse><24,1>') screen:expect([[ - Section{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c:^ }| - t4{c: } | - {c:>} 私は猫が大好き{0:>---}{c: X} | - {c: } ✨🐈✨ | + Section{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14:^ }| + t4{14: } | + {14:>} 私は猫が大好き{1:>---}{14: X} | + {14: } ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><0,2>') screen:expect([[ - Section{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| - ^t4{c: } | - {c:>} 私は猫が大好き{0:>---}{c: X} | - {c: } ✨🐈✨ | + Section{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }| + ^t4{14: } | + {14:>} 私は猫が大好き{1:>---}{14: X} | + {14: } ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><8,3>') screen:expect([[ - Section{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| - t4{c: } | - {c:>} 私は猫^が大好き{0:>---}{c: X} | - {c: } ✨🐈✨ | + Section{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }| + t4{14: } | + {14:>} 私は猫^が大好き{1:>---}{14: X} | + {14: } ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><21,3>') screen:expect([[ - Section{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| - t4{c: } | - {c:>} 私は猫が大好き{0:>---}{c: ^X} | - {c: } ✨🐈✨ | + Section{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }| + t4{14: } | + {14:>} 私は猫が大好き{1:>---}{14: ^X} | + {14: } ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><4,4>') screen:expect([[ - Section{0:>>--->--->---}{c: }t1{c: } | - {0:>--->--->---} {c: }t2{c: } {c: }t3{c: } {c: }| - t4{c: } | - {c:>} 私は猫が大好き{0:>---}{c: X} | - {c: } ✨^🐈✨ | + Section{1:>>--->--->---}{14: }t1{14: } | + {1:>--->--->---} {14: }t2{14: } {14: }t3{14: } {14: }| + t4{14: } | + {14:>} 私は猫が大好き{1:>---}{14: X} | + {14: } ✨^🐈✨ | |*2 ]]) end) -- level 1 - wrapped @@ -1286,61 +1251,61 @@ describe('ui/mouse/input', function() feed('<esc><LeftMouse><20,0>') screen:expect([[ - Section{0:>>--->--->---}^t1 | - {0:>--->--->---} t2 t3 t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| + Section{1:>>--->--->---}^t1 | + {1:>--->--->---} t2 t3 t4 | + {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><14,1>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} ^t2 t3 t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} ^t2 t3 t4 | + {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><18,1>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t^3 t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t^3 t4 | + {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><0,2>') -- Weirdness screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 t4 | - {c:^>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 t4 | + {14:^>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><8,2>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 t4 | - {c:>} 私は猫^が大好き{0:>---}{c:X} ✨{0:>}| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 t4 | + {14:>} 私は猫^が大好き{1:>---}{14:X} ✨{1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><20,2>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 t4 | - {c:>} 私は猫が大好き{0:>---}{c:^X} ✨{0:>}| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 t4 | + {14:>} 私は猫が大好き{1:>---}{14:^X} ✨{1:>}| | - {0:~ }|*2 + {1:~ }|*2 | ]]) end) -- level 2 - non wrapped @@ -1350,62 +1315,62 @@ describe('ui/mouse/input', function() feed('<esc>i<LeftMouse><20,0>') screen:expect([[ - Section{0:>>--->--->---}^t1 | - {0:>--->--->---} t2 t3 t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| + Section{1:>>--->--->---}^t1 | + {1:>--->--->---} t2 t3 t4 | + {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}| | - {0:~ }|*2 - {sm:-- INSERT --} | + {1:~ }|*2 + {5:-- INSERT --} | ]]) feed('<LeftMouse><14,1>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} ^t2 t3 t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} ^t2 t3 t4 | + {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}| | - {0:~ }|*2 - {sm:-- INSERT --} | + {1:~ }|*2 + {5:-- INSERT --} | ]]) feed('<LeftMouse><18,1>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t^3 t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t^3 t4 | + {14:>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}| | - {0:~ }|*2 - {sm:-- INSERT --} | + {1:~ }|*2 + {5:-- INSERT --} | ]]) feed('<LeftMouse><0,2>') -- Weirdness screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 t4 | - {c:^>} 私は猫が大好き{0:>---}{c:X} ✨{0:>}| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 t4 | + {14:^>} 私は猫が大好き{1:>---}{14:X} ✨{1:>}| | - {0:~ }|*2 - {sm:-- INSERT --} | + {1:~ }|*2 + {5:-- INSERT --} | ]]) feed('<LeftMouse><8,2>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 t4 | - {c:>} 私は猫^が大好き{0:>---}{c:X} ✨{0:>}| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 t4 | + {14:>} 私は猫^が大好き{1:>---}{14:X} ✨{1:>}| | - {0:~ }|*2 - {sm:-- INSERT --} | + {1:~ }|*2 + {5:-- INSERT --} | ]]) feed('<LeftMouse><20,2>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 t4 | - {c:>} 私は猫が大好き{0:>---}{c:^X} ✨{0:>}| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 t4 | + {14:>} 私は猫が大好き{1:>---}{14:^X} ✨{1:>}| | - {0:~ }|*2 - {sm:-- INSERT --} | + {1:~ }|*2 + {5:-- INSERT --} | ]]) end) -- level 2 - non wrapped (insert mode) @@ -1414,30 +1379,30 @@ describe('ui/mouse/input', function() feed('<esc><LeftMouse><20,0>') screen:expect([[ - Section{0:>>--->--->---}^t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}^t1 | + {1:>--->--->---} t2 t3 | t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} | + {14:>} 私は猫が大好き{1:>---}{14:X} | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><14,1>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} ^t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} ^t2 t3 | t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} | + {14:>} 私は猫が大好き{1:>---}{14:X} | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><18,1>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t^3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t^3 | t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} | + {14:>} 私は猫が大好き{1:>---}{14:X} | ✨🐈✨ | |*2 ]]) @@ -1450,60 +1415,60 @@ describe('ui/mouse/input', function() -- reevaluated. feed('<esc><LeftMouse><0,2>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 ^ | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 ^ | t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} | + {14:>} 私は猫が大好き{1:>---}{14:X} | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><1,2>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t^4 | - {c:>} 私は猫が大好き{0:>---}{c:X} | + {14:>} 私は猫が大好き{1:>---}{14:X} | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><0,3>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t4 | - {c:^>} 私は猫が大好き{0:>---}{c:X} | + {14:^>} 私は猫が大好き{1:>---}{14:X} | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><20,3>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t4 | - {c:>} 私は猫が大好き{0:>---}{c:^X} | + {14:>} 私は猫が大好き{1:>---}{14:^X} | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><1,4>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} | + {14:>} 私は猫が大好き{1:>---}{14:X} | ^✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><5,4>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t4 | - {c:>} 私は猫が大好き{0:>---}{c:X} | + {14:>} 私は猫が大好き{1:>---}{14:X} | ✨🐈^✨ | |*2 ]]) @@ -1514,42 +1479,42 @@ describe('ui/mouse/input', function() feed('<esc><LeftMouse><0,2>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 t4 | - ^ 私は猫が大好き{0:>----} ✨🐈| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 t4 | + ^ 私は猫が大好き{1:>----} ✨🐈| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><1,2>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 t4 | - ^私は猫が大好き{0:>----} ✨🐈| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 t4 | + ^私は猫が大好き{1:>----} ✨🐈| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><13,2>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 t4 | - 私は猫が大好^き{0:>----} ✨🐈| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 t4 | + 私は猫が大好^き{1:>----} ✨🐈| | - {0:~ }|*2 + {1:~ }|*2 | ]]) feed('<esc><LeftMouse><20,2>') feed('zH') -- FIXME: unnecessary horizontal scrolling screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 t4 | - 私は猫が大好き{0:>----}^ ✨🐈| + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 t4 | + 私は猫が大好き{1:>----}^ ✨🐈| | - {0:~ }|*2 + {1:~ }|*2 | ]]) end) -- level 3 - non wrapped @@ -1559,80 +1524,80 @@ describe('ui/mouse/input', function() feed('<esc><LeftMouse><14,1>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} ^t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} ^t2 t3 | t4 | - 私は猫が大好き{0:>----} | + 私は猫が大好き{1:>----} | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><18,1>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t^3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t^3 | t4 | - 私は猫が大好き{0:>----} | + 私は猫が大好き{1:>----} | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><1,2>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t^4 | - 私は猫が大好き{0:>----} | + 私は猫が大好き{1:>----} | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><0,3>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t4 | - ^ 私は猫が大好き{0:>----} | + ^ 私は猫が大好き{1:>----} | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><20,3>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t4 | - 私は猫が大好き{0:>----}^ | + 私は猫が大好き{1:>----}^ | ✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><1,4>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t4 | - 私は猫が大好き{0:>----} | + 私は猫が大好き{1:>----} | ^✨🐈✨ | |*2 ]]) feed('<esc><LeftMouse><3,4>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t4 | - 私は猫が大好き{0:>----} | + 私は猫が大好き{1:>----} | ✨^🐈✨ | |*2 ]]) feed('<esc><LeftMouse><5,4>') screen:expect([[ - Section{0:>>--->--->---}t1 | - {0:>--->--->---} t2 t3 | + Section{1:>>--->--->---}t1 | + {1:>--->--->---} t2 t3 | t4 | - 私は猫が大好き{0:>----} | + 私は猫が大好き{1:>----} | ✨🐈^✨ | |*2 ]]) @@ -1645,11 +1610,6 @@ describe('ui/mouse/input', function() before_each(function() screen:try_resize(25, 7) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - c = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }, - sm = { bold = true }, - }) feed('ggdG') command([[setlocal concealcursor=ni nowrap shiftwidth=2 tabstop=4 list listchars=tab:>-]]) @@ -1712,23 +1672,23 @@ describe('ui/mouse/input', function() command('syntax match test /|hidden|/ conceal cchar=X') command('set conceallevel=2 concealcursor=n virtualedit=all') screen:expect([[ - aaaaaaaaaa{9:X}bbbbbbb | - bbb{9:X}ccccccccc^c | - {0:~ }|*2 + aaaaaaaaaa{14:X}bbbbbbb | + bbb{14:X}ccccccccc^c | + {1:~ }|*2 | ]]) api.nvim_input_mouse('left', 'press', '', 0, 0, 22) screen:expect([[ - aaaaaaaaaa{9:X}bbbbbb^b | - bbb{9:X}cccccccccc | - {0:~ }|*2 + aaaaaaaaaa{14:X}bbbbbb^b | + bbb{14:X}cccccccccc | + {1:~ }|*2 | ]]) api.nvim_input_mouse('left', 'press', '', 0, 1, 16) screen:expect([[ - aaaaaaaaaa{9:X}bbbbbbb | - bbb{9:X}cccccccccc ^ | - {0:~ }|*2 + aaaaaaaaaa{14:X}bbbbbbb | + bbb{14:X}cccccccccc ^ | + {1:~ }|*2 | ]]) @@ -1738,23 +1698,23 @@ describe('ui/mouse/input', function() virt_text_repeat_linebreak = true, }) screen:expect([[ - aaaaaaaaaa{9:X}bbbbbbb {6:?}| - bbb{9:X}cccccccccc ^ {6:?}| - {0:~ }|*2 + aaaaaaaaaa{14:X}bbbbbbb {9:?}| + bbb{14:X}cccccccccc ^ {9:?}| + {1:~ }|*2 | ]]) api.nvim_input_mouse('left', 'press', '', 0, 0, 22) screen:expect([[ - aaaaaaaaaa{9:X}bbbbbb^b {6:?}| - bbb{9:X}cccccccccc {6:?}| - {0:~ }|*2 + aaaaaaaaaa{14:X}bbbbbb^b {9:?}| + bbb{14:X}cccccccccc {9:?}| + {1:~ }|*2 | ]]) api.nvim_input_mouse('left', 'press', '', 0, 1, 16) screen:expect([[ - aaaaaaaaaa{9:X}bbbbbbb {6:?}| - bbb{9:X}cccccccccc ^ {6:?}| - {0:~ }|*2 + aaaaaaaaaa{14:X}bbbbbbb {9:?}| + bbb{14:X}cccccccccc ^ {9:?}| + {1:~ }|*2 | ]]) end) @@ -1908,19 +1868,40 @@ describe('ui/mouse/input', function() eq(0, api.nvim_get_var('mouse_up2')) end) - it('<MouseMove> is not translated into multiclicks and can be mapped', function() + it('<MouseMove> to different locations can be mapped', function() api.nvim_set_var('mouse_move', 0) api.nvim_set_var('mouse_move2', 0) command('nnoremap <MouseMove> <Cmd>let g:mouse_move += 1<CR>') command('nnoremap <2-MouseMove> <Cmd>let g:mouse_move2 += 1<CR>') - feed('<MouseMove><0,0>') - feed('<MouseMove><0,0>') - api.nvim_input_mouse('move', '', '', 0, 0, 0) - api.nvim_input_mouse('move', '', '', 0, 0, 0) + feed('<MouseMove><1,0>') + feed('<MouseMove><2,0>') + api.nvim_input_mouse('move', '', '', 0, 0, 3) + api.nvim_input_mouse('move', '', '', 0, 0, 4) eq(4, api.nvim_get_var('mouse_move')) eq(0, api.nvim_get_var('mouse_move2')) end) + it('<MouseMove> to same location does not generate events #31103', function() + api.nvim_set_var('mouse_move', 0) + api.nvim_set_var('mouse_move2', 0) + command('nnoremap <MouseMove> <Cmd>let g:mouse_move += 1<CR>') + command('nnoremap <2-MouseMove> <Cmd>let g:mouse_move2 += 1<CR>') + api.nvim_input_mouse('move', '', '', 0, 0, 3) + eq(1, api.nvim_get_var('mouse_move')) + eq(0, api.nvim_get_var('mouse_move2')) + feed('<MouseMove><3,0>') + feed('<MouseMove><3,0>') + api.nvim_input_mouse('move', '', '', 0, 0, 3) + api.nvim_input_mouse('move', '', '', 0, 0, 3) + eq(1, api.nvim_get_var('mouse_move')) + eq(0, api.nvim_get_var('mouse_move2')) + eq({ mode = 'n', blocking = false }, api.nvim_get_mode()) + feed('<MouseMove><3,0><Insert>') + eq(1, api.nvim_get_var('mouse_move')) + eq(0, api.nvim_get_var('mouse_move2')) + eq({ mode = 'i', blocking = false }, api.nvim_get_mode()) + end) + it('feeding <MouseMove> in Normal mode does not use uninitialized memory #19480', function() feed('<MouseMove>') n.poke_eventloop() diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua index f16f750ea1..001d3cb430 100644 --- a/test/functional/ui/multibyte_spec.lua +++ b/test/functional/ui/multibyte_spec.lua @@ -16,8 +16,7 @@ describe('multibyte rendering', function() local screen before_each(function() clear() - screen = Screen.new(60, 6) - screen:attach({ rgb = true }) + screen = Screen.new(60, 6, { rgb = true }) end) it('works with composed char at start of line', function() @@ -384,7 +383,6 @@ describe('multibyte rendering: statusline', function() before_each(function() clear() screen = Screen.new(40, 4) - screen:attach() command('set laststatus=2') end) @@ -474,26 +472,42 @@ describe('multibyte rendering: statusline', function() end) it('emoji with ZWJ in filename with custom stl', function() + screen:add_extra_attr_ids { + [100] = { + bold = true, + reverse = true, + foreground = Screen.colors.Gray100, + background = Screen.colors.Red, + }, + } command('set statusline=xx%#ErrorMsg#%f%##yy') command('file 🧑💻') screen:expect { grid = [[ ^ | {1:~ }| - {3:xx}{9:🧑💻}{3:yy }| + {3:xx}{100:🧑💻}{3:yy }| | ]], } end) it('unprintable chars in filename with custom stl', function() + screen:add_extra_attr_ids { + [100] = { + bold = true, + reverse = true, + foreground = Screen.colors.Gray100, + background = Screen.colors.Red, + }, + } command('set statusline=xx%#ErrorMsg#%f%##yy') command('file 🧑💻') screen:expect { grid = [[ ^ | {1:~ }| - {3:xx}{9:🧑<200b>💻}{3:yy }| + {3:xx}{100:🧑<200b>💻}{3:yy }| | ]], } diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index e009ed0a29..3afda0c4af 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -16,8 +16,7 @@ describe('ext_multigrid', function() before_each(function() clear{args_rm={'--headless'}, args={'--cmd', 'set laststatus=2'}} - screen = Screen.new(53,14) - screen:attach({ext_multigrid=true}) + screen = Screen.new(53,14, {ext_multigrid=true}) screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, [2] = {foreground = Screen.colors.Magenta}, diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index b40ff29dec..211fc1dc77 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -44,8 +44,7 @@ describe('UI receives option updates', function() clear_opts.args_rm = clear_opts.args_rm or {} table.insert(clear_opts.args_rm or {}, '--cmd') clear(clear_opts) - screen = Screen.new(20, 5) - screen:attach(screen_opts) + screen = Screen.new(20, 5, screen_opts) -- NB: UI test suite can be run in both "linegrid" and legacy grid mode. -- In both cases check that the received value is the one requested. defaults.ext_linegrid = screen._options.ext_linegrid or false @@ -70,7 +69,6 @@ describe('UI receives option updates', function() function screen:_handle_mouse_off() table.insert(evs, 'mouse_off') end - screen:attach() screen:expect(function() eq({ 'mouse_on' }, evs) end) @@ -215,24 +213,22 @@ describe('UI receives option updates', function() end) describe('UI can set terminal option', function() - local screen before_each(function() -- by default we implicitly "--cmd 'set bg=light'" which ruins everything clear { args_rm = { '--cmd' } } - screen = Screen.new(20, 5) end) it('term_name', function() eq('nvim', eval '&term') - screen:attach { term_name = 'xterm' } + local _ = Screen.new(20, 5, { term_name = 'xterm' }) eq('xterm', eval '&term') end) it('term_colors', function() eq('256', eval '&t_Co') - screen:attach { term_colors = 8 } + local _ = Screen.new(20, 5, { term_colors = 8 }) eq('8', eval '&t_Co') end) end) diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index 220af06f53..b5a09d814c 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -109,7 +109,6 @@ describe('shell command :!', function() it('handles control codes', function() skip(is_os('win'), 'missing printf') local screen = Screen.new(50, 4) - screen:attach() -- Print TAB chars. #2958 feed([[:!printf '1\t2\t3'<CR>]]) screen:expect { @@ -167,7 +166,6 @@ describe('shell command :!', function() write_file('bang_filter_spec/f2', 'f2') write_file('bang_filter_spec/f3', 'f3') screen = Screen.new(53, 10) - screen:attach() end) after_each(function() @@ -241,7 +239,6 @@ describe('shell command :!', function() it('powershell supports literal strings', function() set_shell_powershell() local screen = Screen.new(45, 4) - screen:attach() feed_command([[!'Write-Output $a']]) screen:expect([[ :!'Write-Output $a' | diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index f84362ede8..8fe8975b4a 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -19,18 +19,7 @@ describe('ui/ext_popupmenu', function() local screen before_each(function() clear() - screen = Screen.new(60, 8) - screen:attach({ rgb = true, ext_popupmenu = true }) - screen:set_default_attr_ids({ - [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] = { background = Screen.colors.WebGray }, - [7] = { background = Screen.colors.LightMagenta }, - [8] = { foreground = Screen.colors.Red }, - }) + screen = Screen.new(60, 8, { rgb = true, ext_popupmenu = true }) source([[ function! TestComplete() abort call complete(1, [{'word':'foo', 'abbr':'fo', 'menu':'the foo', 'info':'foo-y', 'kind':'x'}, 'bar', 'spam']) @@ -52,7 +41,7 @@ describe('ui/ext_popupmenu', function() | foo^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -67,7 +56,7 @@ describe('ui/ext_popupmenu', function() | ^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -83,7 +72,7 @@ describe('ui/ext_popupmenu', function() | ^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -98,7 +87,7 @@ describe('ui/ext_popupmenu', function() | bar^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], } end) @@ -110,7 +99,7 @@ describe('ui/ext_popupmenu', function() | foo^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -125,7 +114,7 @@ describe('ui/ext_popupmenu', function() | foo^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -140,7 +129,7 @@ describe('ui/ext_popupmenu', function() | spam^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -154,7 +143,7 @@ describe('ui/ext_popupmenu', function() | foo^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) feed('<c-w><C-r>=TestComplete()<CR>') @@ -163,7 +152,7 @@ describe('ui/ext_popupmenu', function() | foo^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -178,7 +167,7 @@ describe('ui/ext_popupmenu', function() | foo^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -193,7 +182,7 @@ describe('ui/ext_popupmenu', function() | bar^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -208,7 +197,7 @@ describe('ui/ext_popupmenu', function() | ^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -223,7 +212,7 @@ describe('ui/ext_popupmenu', function() | foo^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -237,7 +226,7 @@ describe('ui/ext_popupmenu', function() | ^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) command('set wildmenu') @@ -332,7 +321,7 @@ describe('ui/ext_popupmenu', function() | foo^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -347,7 +336,7 @@ describe('ui/ext_popupmenu', function() | spam^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -362,7 +351,7 @@ describe('ui/ext_popupmenu', function() | spam^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -376,7 +365,7 @@ describe('ui/ext_popupmenu', function() | bar^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) feed('<Esc>:sign <Tab>') @@ -440,33 +429,33 @@ describe('ui/ext_popupmenu', function() screen:expect([[ | foo^ | - {6:fo x the foo }{1: }| - {7:bar }{1: }| - {7:spam }{1: }| + {12:fo x the foo }{1: }| + {4:bar }{1: }| + {4:spam }{1: }| {1:~ }|*2 - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) feed('<f1>') screen:expect([[ | spam^ | - {7:fo x the foo }{1: }| - {7:bar }{1: }| - {6:spam }{1: }| + {4:fo x the foo }{1: }| + {4:bar }{1: }| + {12:spam }{1: }| {1:~ }|*2 - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) feed('<f2>') screen:expect([[ | spam^ | - {7:fo x the foo }{1: }| - {7:bar }{1: }| - {7:spam }{1: }| + {4:fo x the foo }{1: }| + {4:bar }{1: }| + {4:spam }{1: }| {1:~ }|*2 - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) feed('<f3>') @@ -474,42 +463,42 @@ describe('ui/ext_popupmenu', function() | bar^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) feed('<Esc>:sign <Tab>') screen:expect([[ | - bar {6: define } | - {1:~ }{7: jump }{1: }| - {1:~ }{7: list }{1: }| - {1:~ }{7: place }{1: }| - {1:~ }{7: undefine }{1: }| - {1:~ }{7: unplace }{1: }| + bar {12: define } | + {1:~ }{4: jump }{1: }| + {1:~ }{4: list }{1: }| + {1:~ }{4: place }{1: }| + {1:~ }{4: undefine }{1: }| + {1:~ }{4: unplace }{1: }| :sign define^ | ]]) feed('<f1>') screen:expect([[ | - bar {7: define } | - {1:~ }{7: jump }{1: }| - {1:~ }{6: list }{1: }| - {1:~ }{7: place }{1: }| - {1:~ }{7: undefine }{1: }| - {1:~ }{7: unplace }{1: }| + bar {4: define } | + {1:~ }{4: jump }{1: }| + {1:~ }{12: list }{1: }| + {1:~ }{4: place }{1: }| + {1:~ }{4: undefine }{1: }| + {1:~ }{4: unplace }{1: }| :sign list^ | ]]) feed('<f2>') screen:expect([[ | - bar {7: define } | - {1:~ }{7: jump }{1: }| - {1:~ }{7: list }{1: }| - {1:~ }{7: place }{1: }| - {1:~ }{7: undefine }{1: }| - {1:~ }{7: unplace }{1: }| + bar {4: define } | + {1:~ }{4: jump }{1: }| + {1:~ }{4: list }{1: }| + {1:~ }{4: place }{1: }| + {1:~ }{4: undefine }{1: }| + {1:~ }{4: unplace }{1: }| :sign ^ | ]]) @@ -542,33 +531,33 @@ describe('ui/ext_popupmenu', function() screen:expect([[ aa bb cc | aa^ | - {6:aa }{1: }| - {7:bb }{1: }| - {7:cc }{1: }| + {12:aa }{1: }| + {4:bb }{1: }| + {4:cc }{1: }| {1:~ }|*2 - {2:-- Keyword Local completion (^N^P) }{5:match 1 of 3} | + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 3} | ]]) feed('<f1>') screen:expect([[ aa bb cc | cc^ | - {7:aa }{1: }| - {7:bb }{1: }| - {6:cc }{1: }| + {4:aa }{1: }| + {4:bb }{1: }| + {12:cc }{1: }| {1:~ }|*2 - {2:-- Keyword Local completion (^N^P) }{5:match 3 of 3} | + {5:-- Keyword Local completion (^N^P) }{6:match 3 of 3} | ]]) feed('<f2>') screen:expect([[ aa bb cc | cc^ | - {7:aa }{1: }| - {7:bb }{1: }| - {7:cc }{1: }| + {4:aa }{1: }| + {4:bb }{1: }| + {4:cc }{1: }| {1:~ }|*2 - {2:-- Keyword Local completion (^N^P) }{8:Back at original} | + {5:-- Keyword Local completion (^N^P) }{19:Back at original} | ]]) feed('<f3>') @@ -576,7 +565,7 @@ describe('ui/ext_popupmenu', function() aa bb cc | bb^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) end) @@ -619,7 +608,7 @@ describe('ui/ext_popupmenu', function() | January^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = month_expected, @@ -671,7 +660,7 @@ describe('ui/ext_popupmenu', function() | January^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = month_expected, @@ -726,7 +715,7 @@ describe('ui/ext_popupmenu', function() | January^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = month_expected, @@ -740,7 +729,7 @@ describe('ui/ext_popupmenu', function() | January^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = month_expected, @@ -832,10 +821,10 @@ describe('ui/ext_popupmenu', function() grid = [[ | {1:~ }|*3 - {4:långfile2 }| + {3:långfile2 }| | {1:~ }|*2 - {3:långfile1 }| + {2:långfile1 }| :b långfile1^ | ]], popupmenu = { @@ -863,7 +852,7 @@ describe('ui/ext_popupmenu', function() | foo^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -878,7 +867,7 @@ describe('ui/ext_popupmenu', function() | ^ | {1:~ }|*5 - {2:-- INSERT --} | + {5:-- INSERT --} | ]], popupmenu = { items = expected, @@ -899,9 +888,9 @@ describe('ui/ext_popupmenu', function() feed('<RightMouse><0,0>') screen:expect([[ | - {7:^foo } | - {7:bar }{1: }| - {7:baz }{1: }| + {4:^foo } | + {4:bar }{1: }| + {4:baz }{1: }| {1:~ }|*3 | ]]) @@ -967,7 +956,6 @@ describe("builtin popupmenu 'pumblend'", 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') @@ -1117,7 +1105,7 @@ describe("builtin popupmenu 'pumblend'", function() end) it('256-color (non-RGB)', function() - local screen = Screen.new(60, 8) + local screen = Screen.new(60, 8, { rgb = false }) screen:set_default_attr_ids({ [1] = { foreground = Screen.colors.Grey0, background = tonumber('0x000007') }, [2] = { foreground = tonumber('0x000055'), background = tonumber('0x000007') }, @@ -1130,7 +1118,6 @@ describe("builtin popupmenu 'pumblend'", function() [9] = { bold = true }, [10] = { foreground = tonumber('0x000002') }, }) - screen:attach({ rgb = false }) command('set pumblend=10') insert([[ Lorem ipsum dolor sit amet, consectetur @@ -1159,7 +1146,7 @@ describe('builtin popupmenu', function() local function with_ext_multigrid(multigrid) local screen before_each(function() - screen = Screen.new(32, 20) + screen = Screen.new(32, 20, { ext_multigrid = multigrid }) screen:set_default_attr_ids({ -- popup selected item / scrollbar track s = { background = Screen.colors.Grey }, @@ -1204,7 +1191,6 @@ describe('builtin popupmenu', function() underline = true, }, }) - screen:attach({ ext_multigrid = multigrid }) end) it('with preview-window above', function() @@ -3636,6 +3622,58 @@ describe('builtin popupmenu', function() :sign un^ | ]]) end) + + it( + 'cascading highlights for matched text (PmenuMatch, PmenuMatchSel) in cmdline pum', + function() + screen:add_extra_attr_ids { + [100] = { + background = Screen.colors.Grey, + italic = true, + underline = true, + foreground = Screen.colors.White, + }, + [101] = { + strikethrough = true, + foreground = Screen.colors.Grey0, + italic = true, + bold = true, + underline = true, + background = Screen.colors.White, + }, + [102] = { + strikethrough = true, + foreground = Screen.colors.Red, + italic = true, + underline = true, + background = Screen.colors.Grey, + }, + [103] = { + foreground = Screen.colors.Yellow, + italic = true, + bold = true, + underline = true, + background = Screen.colors.Pink, + }, + } + exec([[ + set wildoptions=pum,fuzzy + hi Pmenu guifg=White guibg=Grey gui=underline,italic + hi PmenuSel guifg=Red gui=strikethrough + hi PmenuMatch guifg=Yellow guibg=Pink gui=bold + hi PmenuMatchSel guifg=Black guibg=White + ]]) + + feed(':sign plc<Tab>') + screen:expect([[ + | + {1:~ }|*16 + {1:~ }{102: }{101:pl}{102:a}{101:c}{102:e }{1: }| + {1:~ }{100: un}{103:pl}{100:a}{103:c}{100:e }{1: }| + :sign place^ | + ]]) + end + ) end it("'pumheight'", function() @@ -4453,9 +4491,10 @@ describe('builtin popupmenu', function() :let g:menustr = 'foo' | ]]) end + local no_menu_screen ---@type string|test.function.ui.screen.Expect if multigrid then api.nvim_input_mouse('left', 'press', '', 4, 1, 2) - screen:expect({ + no_menu_screen = { grid = [[ ## grid 1 [2:--------------------------------]|*2 @@ -4474,19 +4513,189 @@ describe('builtin popupmenu', function() {2:WINBAR }| ^popup menu test | ]], - }) + } else feed('<LeftMouse><31,2>') - screen:expect([[ + no_menu_screen = { + grid = [[ popup menu test | {1:~ }| {3:[No Name] [+] }| popup menu test│{2:WINBAR }| {1:~ }│^popup menu test | :let g:menustr = 'bar' | - ]]) + ]], + } end + screen:expect(no_menu_screen) eq('bar', api.nvim_get_var('menustr')) + + local no_sel_screen ---@type string|test.function.ui.screen.Expect + if multigrid then + no_sel_screen = { + grid = [[ + ## grid 1 + [2:--------------------------------]|*2 + {3:[No Name] [+] }| + [5:---------------]│[6:----------------]|*2 + [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:~ }| + ## grid 6 + {2:WINBAR }| + ^popup menu test | + ]], + float_pos = { [4] = { -1, 'NW', 1, 1, 19, false, 250 } }, + } + else + no_sel_screen = { + grid = [[ + popup menu test | + {1:~ }{n: foo }{1: }| + {3:[No Name] [+] }{n: bar }{3: }| + popup menu test│{2:WIN}{n: baz }{2: }| + {1:~ }│^popup menu test | + :let g:menustr = 'bar' | + ]], + } + end + local sel_screens = {} ---@type (string|test.function.ui.screen.Expect)[] + for i, s in ipairs({ 'foo', 'bar', 'baz' }) do + local sel_screen = vim.deepcopy(no_sel_screen) + local grid = assert(sel_screen.grid) + grid = grid:gsub(vim.pesc(('{n: %s }'):format(s)), ('{s: %s }'):format(s)) + sel_screen.grid = grid + sel_screens[i] = sel_screen + end + + command([[let g:menustr = '']]) + local g = multigrid and 1 or 0 + + api.nvim_input_mouse('right', 'press', '', g, 0, 20) + screen:expect(no_sel_screen) + api.nvim_input_mouse('move', '', '', g, 1, 19) + screen:expect(sel_screens[1]) + api.nvim_input_mouse('move', '', '', g, 1, 18) + screen:expect(no_sel_screen) + api.nvim_input_mouse('move', '', '', g, 2, 23) + screen:expect(sel_screens[2]) + api.nvim_input_mouse('move', '', '', g, 2, 24) + screen:expect(no_sel_screen) + api.nvim_input_mouse('move', '', '', g, 3, 19) + screen:expect(sel_screens[3]) + api.nvim_input_mouse('left', 'press', '', g, 3, 18) + screen:expect(no_menu_screen) + eq('', api.nvim_get_var('menustr')) + + command('wincmd t | set rightleft') + if multigrid then + no_menu_screen = { + grid = [[ + ## grid 1 + [2:--------------------------------]|*2 + {4:[No Name] [+] }| + [5:---------------]│[6:----------------]|*2 + [3:--------------------------------]| + ## grid 2 + tset unem pupo^p| + {1: ~}| + ## grid 3 + :let g:menustr = 'bar' | + ## grid 5 + popup menu test| + {1:~ }| + ## grid 6 + {2:WINBAR }| + popup menu test | + ]], + } + else + no_menu_screen = { + grid = [[ + tset unem pupo^p| + {1: ~}| + {4:[No Name] [+] }| + popup menu test│{2:WINBAR }| + {1:~ }│popup menu test | + :let g:menustr = 'bar' | + ]], + } + end + screen:expect(no_menu_screen) + + if multigrid then + no_sel_screen = { + grid = [[ + ## grid 1 + [2:--------------------------------]|*2 + {4:[No Name] [+] }| + [5:---------------]│[6:----------------]|*2 + [3:--------------------------------]| + ## grid 2 + tset unem pupo^p| + {1: ~}| + ## grid 3 + :let g:menustr = 'bar' | + ## grid 4 + {n: oof }| + {n: rab }| + {n: zab }| + ## grid 5 + popup menu test| + {1:~ }| + ## grid 6 + {2:WINBAR }| + popup menu test | + ]], + float_pos = { [4] = { -1, 'NW', 1, 1, 17, false, 250 } }, + } + else + no_sel_screen = { + grid = [[ + tset unem pupo^p| + {1: }{n: oof }{1: ~}| + {4:[No Name] [+] }{n: rab }{4: }| + popup menu test│{2:W}{n: zab }{2: }| + {1:~ }│popup menu test | + :let g:menustr = 'bar' | + ]], + } + end + for i, s in ipairs({ 'oof', 'rab', 'zab' }) do + local sel_screen = vim.deepcopy(no_sel_screen) + local grid = assert(sel_screen.grid) + grid = grid:gsub(vim.pesc(('{n: %s }'):format(s)), ('{s: %s }'):format(s)) + sel_screen.grid = grid + sel_screens[i] = sel_screen + end + + api.nvim_input_mouse('right', 'press', '', g, 0, 20) + screen:expect(no_sel_screen) + api.nvim_input_mouse('move', '', '', g, 1, 21) + screen:expect(sel_screens[1]) + api.nvim_input_mouse('move', '', '', g, 1, 22) + screen:expect(no_sel_screen) + api.nvim_input_mouse('move', '', '', g, 2, 17) + screen:expect(sel_screens[2]) + api.nvim_input_mouse('move', '', '', g, 2, 16) + screen:expect(no_sel_screen) + api.nvim_input_mouse('move', '', '', g, 3, 21) + screen:expect(sel_screens[3]) + api.nvim_input_mouse('left', 'press', '', g, 3, 22) + screen:expect(no_menu_screen) + eq('', api.nvim_get_var('menustr')) + + command('set norightleft') end) if not multigrid then @@ -4963,20 +5172,31 @@ describe('builtin popupmenu', function() feed('<C-E><Esc>') end) - -- oldtest: Test_pum_user_hl_group() - it('custom hl_group override', function() + -- oldtest: Test_pum_user_abbr_hlgroup() + it('custom abbr_hlgroup override', function() exec([[ - func CompleteFunc( findstart, base ) + let s:var = 0 + func CompleteFunc(findstart, base) if a:findstart return 0 endif + if s:var == 1 + return { + \ 'words': [ + \ { 'word': 'aword1', 'abbr_hlgroup': 'StrikeFake' }, + \ { 'word': '你好', 'abbr_hlgroup': 'StrikeFake' }, + \]} + endif return { \ 'words': [ - \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' }, + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'abbr_hlgroup': 'StrikeFake' }, \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', }, - \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' }, + \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'abbr_hlgroup': 'StrikeFake' }, \]} endfunc + func ChangeVar() + let s:var = 1 + endfunc set completeopt=menu set completefunc=CompleteFunc @@ -4990,9 +5210,9 @@ describe('builtin popupmenu', function() feed('Saw<C-X><C-U>') screen:expect([[ aword1^ | - {ds:aword1 W extra text 1 }{1: }| + {ds:aword1}{s: W extra text 1 }{1: }| {n:aword2 W extra text 2 }{1: }| - {dn:你好 W extra text 3 }{1: }| + {dn:你好}{n: W extra text 3 }{1: }| {1:~ }|*15 {2:-- }{5:match 1 of 3} | ]]) @@ -5003,22 +5223,33 @@ describe('builtin popupmenu', function() feed('Saw<C-X><C-U>') screen:expect([[ aword1^ | - {uds:aw}{ds:ord1 W extra text 1 }{1: }| + {uds:aw}{ds:ord1}{s: W extra text 1 }{1: }| {umn:aw}{n:ord2 W extra text 2 }{1: }| - {dn:你好 W extra text 3 }{1: }| + {dn:你好}{n: W extra text 3 }{1: }| {1:~ }|*15 {2:-- }{5:match 1 of 3} | ]]) feed('<C-N>') screen:expect([[ aword2^ | - {udn:aw}{dn:ord1 W extra text 1 }{1: }| + {udn:aw}{dn:ord1}{n: W extra text 1 }{1: }| {ums:aw}{s:ord2 W extra text 2 }{1: }| - {dn:你好 W extra text 3 }{1: }| + {dn:你好}{n: W extra text 3 }{1: }| {1:~ }|*15 {2:-- }{5:match 2 of 3} | ]]) feed('<C-E><Esc>') + + command('call ChangeVar()') + feed('S<C-X><C-U>') + screen:expect([[ + aword1^ | + {ds:aword1}{s: }{1: }| + {dn:你好}{n: }{1: }| + {1:~ }|*16 + {2:-- }{5:match 1 of 2} | + ]]) + feed('<C-E><Esc>') end) -- oldtest: Test_pum_user_kind_hlgroup() @@ -5030,7 +5261,7 @@ describe('builtin popupmenu', function() endif return { \ 'words': [ - \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'hl_group': 'StrikeFake' }, + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'abbr_hlgroup': 'StrikeFake' }, \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'function', 'kind_hlgroup': 'KindFunc' }, \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'class', 'kind_hlgroup': 'KindClass' }, \]} @@ -5053,9 +5284,9 @@ describe('builtin popupmenu', function() feed('S<C-X><C-U>') screen:expect([[ aword1^ | - {ds:aword1 }{kvs:variable }{ds:extra text 1 }{1: }| - {n:aword2 }{kfn:function }{n:extra text 2 }{1: }| - {n:你好 }{kcn:class }{n:extra text 3 }{1: }| + {ds:aword1}{s: }{kvs:variable}{s: extra text 1 }{1: }| + {n:aword2 }{kfn:function}{n: extra text 2 }{1: }| + {n:你好 }{kcn:class}{n: extra text 3 }{1: }| {1:~ }|*15 {2:-- }{5:match 1 of 3} | ]]) diff --git a/test/functional/ui/quickfix_spec.lua b/test/functional/ui/quickfix_spec.lua index 73923a153a..3750ce3d3f 100644 --- a/test/functional/ui/quickfix_spec.lua +++ b/test/functional/ui/quickfix_spec.lua @@ -11,7 +11,6 @@ describe('quickfix selection highlight', function() clear() screen = Screen.new(25, 10) - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue }, [2] = { reverse = true }, diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index f1891b608e..8e15e6c35f 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -6,23 +6,15 @@ -- -- Example usage: -- +-- -- Attach a screen to the current Nvim instance. -- local screen = Screen.new(25, 10) --- -- Attach the screen to the current Nvim instance. --- screen:attach() -- -- Enter insert-mode and type some text. -- feed('ihello screen') -- -- Assert the expected screen state. -- screen:expect([[ --- hello screen | --- ~ | --- ~ | --- ~ | --- ~ | --- ~ | --- ~ | --- ~ | --- ~ | --- -- INSERT -- | +-- hello screen^ | +-- {1:~ }|*8 +-- {5:-- INSERT --} | -- ]]) -- <- Last line is stripped -- -- Since screen updates are received asynchronously, expect() actually specifies @@ -36,36 +28,19 @@ -- * If the timeout expires, the last match error will be reported and the -- test will fail. -- --- Continuing the above example, say we want to assert that "-- INSERT --" is --- highlighted with the bold attribute. The expect() call should look like this: --- --- NonText = Screen.colors.Blue --- screen:expect([[ --- hello screen | --- ~ | --- ~ | --- ~ | --- ~ | --- ~ | --- ~ | --- ~ | --- ~ | --- {b:-- INSERT --} | --- ]], {b = {bold = true}}, {{bold = true, foreground = NonText}}) --- --- In this case "b" is a string associated with the set composed of one --- attribute: bold. Note that since the {b:} markup is not a real part of the +-- The 30 most common highlight groups are predefined, see init_colors() below. +-- In this case "5" is a predefined highlight associated with the set composed of one +-- attribute: bold. Note that since the {5:} markup is not a real part of the -- screen, the delimiter "|" moved to the right. Also, the highlighting of the --- NonText markers "~" is ignored in this test. +-- NonText markers "~" is visible. -- --- Tests will often share a group of attribute sets to expect(). Those can be +-- Tests will often share a group of extra attribute sets to expect(). Those can be -- defined at the beginning of a test: -- --- NonText = Screen.colors.Blue --- screen:set_default_attr_ids( { --- [1] = {reverse = true, bold = true}, --- [2] = {reverse = true} --- }) +-- screen:add_extra_attr_ids { +-- [100] = { background = Screen.colors.Plum1, underline = true }, +-- [101] = { background = Screen.colors.Red1, bold = true, underline = true }, +-- } -- -- To help write screen tests, see Screen:snapshot_util(). -- To debug screen tests, see Screen:redraw_debug(). @@ -180,14 +155,30 @@ local function _init_colors() } end +--- @class test.functional.ui.screen.Opts +--- @field ext_linegrid? boolean +--- @field ext_multigrid? boolean +--- @field ext_newgrid? boolean +--- @field ext_popupmenu? boolean +--- @field ext_wildmenu? boolean +--- @field rgb? boolean +--- @field _debug_float? boolean + --- @param width? integer --- @param height? integer +--- @param options? test.functional.ui.screen.Opts +--- @param session? test.Session|false --- @return test.functional.ui.screen -function Screen.new(width, height) +function Screen.new(width, height, options, session) if not Screen.colors then _init_colors() end + options = options or {} + if options.ext_linegrid == nil then + options.ext_linegrid = true + end + local self = setmetatable({ timeout = default_screen_timeout, title = '', @@ -227,6 +218,7 @@ function Screen.new(width, height) _new_attrs = false, _width = width or 53, _height = height or 14, + _options = options, _grids = {}, _grid_win_extmarks = {}, _cursor = { @@ -250,6 +242,11 @@ function Screen.new(width, height) self.uimeths = create_callindex(ui) + -- session is often nil, which implies the default session + if session ~= false then + self:attach(session) + end + return self end @@ -277,20 +274,10 @@ function Screen:set_rgb_cterm(val) self._rgb_cterm = val end ---- @class test.functional.ui.screen.Opts ---- @field ext_linegrid? boolean ---- @field ext_multigrid? boolean ---- @field ext_newgrid? boolean ---- @field ext_popupmenu? boolean ---- @field ext_wildmenu? boolean ---- @field rgb? boolean ---- @field _debug_float? boolean - ---- @param options? test.functional.ui.screen.Opts --- @param session? test.Session -function Screen:attach(options, session) +function Screen:attach(session) session = session or get_session() - options = options or {} + local options = self._options if options.ext_linegrid == nil then options.ext_linegrid = true @@ -1524,7 +1511,7 @@ end function Screen:_chunks_repr(chunks, attr_state) local repr_chunks = {} for i, chunk in ipairs(chunks) do - local hl, text = unpack(chunk) + local hl, text, id = unpack(chunk) local attrs if self._options.ext_linegrid then attrs = self._attr_table[hl][1] @@ -1532,7 +1519,7 @@ function Screen:_chunks_repr(chunks, attr_state) attrs = hl end local attr_id = self:_get_attr_id(attr_state, attrs, hl) - repr_chunks[i] = { text, attr_id } + repr_chunks[i] = { text, attr_id, attr_id and id or nil } end return repr_chunks end diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 85a653df36..f39e9ecc33 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -29,7 +29,6 @@ describe('screen', function() local screen_nvim = spawn(nvim_argv) set_session(screen_nvim) screen = Screen.new() - screen:attach() end) it('default initial screen', function() @@ -47,8 +46,7 @@ local function screen_tests(linegrid) before_each(function() clear() - screen = Screen.new() - screen:attach({ rgb = true, ext_linegrid = linegrid }) + screen = Screen.new(53, 14, { rgb = true, ext_linegrid = linegrid }) screen:set_default_attr_ids({ [0] = { bold = true, foreground = 255 }, [1] = { bold = true, reverse = true }, @@ -717,8 +715,7 @@ describe('Screen default colors', function() } local screen_nvim = spawn(nvim_argv) set_session(screen_nvim) - screen = Screen.new() - screen:attach(termcolors and { rgb = true, ext_termcolors = true } or { rgb = true }) + screen = Screen.new(53, 14, { rgb = true, ext_termcolors = termcolors or nil }) end it('are dark per default', function() @@ -777,7 +774,6 @@ end) 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, api.nvim_get_option_value('lines', {})) eq(99, api.nvim_get_option_value('window', {})) eq(99, api.nvim_win_get_height(0)) @@ -810,7 +806,6 @@ end) it("showcmd doesn't cause empty grid_line with redrawdebug=compositor #22593", function() clear() local screen = Screen.new(30, 2) - screen:attach() command('set showcmd redrawdebug=compositor') feed('d') screen:expect { @@ -824,7 +819,6 @@ end) it("scrolling in narrow window doesn't draw over separator #29033", function() clear() local screen = Screen.new(60, 8) - screen:attach() feed('100Oa<Esc>gg') exec([[ set number nowrap diff --git a/test/functional/ui/scrollbind_spec.lua b/test/functional/ui/scrollbind_spec.lua index 9e70b25efa..84316762e4 100644 --- a/test/functional/ui/scrollbind_spec.lua +++ b/test/functional/ui/scrollbind_spec.lua @@ -10,7 +10,6 @@ describe('Scrollbind', function() before_each(function() screen = Screen.new(40, 12) - screen:attach() end) it('works with one buffer with virtual lines', function() diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index eab265cbb1..86490b4527 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -16,7 +16,6 @@ describe('search highlighting', function() before_each(function() clear() screen = Screen.new(40, 7) - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true, foreground = Screen.colors.Blue }, [2] = { background = Screen.colors.Yellow }, -- Search diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index 30da79af47..7874c04c39 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -12,21 +12,9 @@ describe('Signs', function() before_each(function() clear() screen = Screen.new() - screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = 255 }, - [1] = { background = Screen.colors.Yellow }, - [2] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.Grey }, - [3] = { background = Screen.colors.Gray90 }, - [4] = { bold = true, reverse = true }, - [5] = { reverse = true }, - [6] = { foreground = Screen.colors.Brown }, - [7] = { foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGrey }, - [8] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [9] = { bold = true, foreground = Screen.colors.Magenta }, - [10] = { foreground = Screen.colors.Blue1 }, - [11] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - }) + screen:add_extra_attr_ids { + [100] = { bold = true, foreground = Screen.colors.Magenta1 }, + } end) describe(':sign place', function() @@ -39,10 +27,10 @@ describe('Signs', function() sign place 2 line=2 name=piet2 buffer=1 ]]) screen:expect([[ - {1:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}a | - {1:𠜎̀́̂̃̄̅}b | - {2: }^ | - {0:~ }|*10 + {10:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}a | + {10:𠜎̀́̂̃̄̅}b | + {7: }^ | + {1:~ }|*10 | ]]) end) @@ -57,11 +45,11 @@ describe('Signs', function() sign place 3 line=1 name=pietx buffer=1 ]]) screen:expect([[ - {1:>!}a | - {2: }b | - {1:>>}c | - {2: }^ | - {0:~ }|*9 + {10:>!}a | + {7: }b | + {10:>>}c | + {7: }^ | + {1:~ }|*9 | ]]) end) @@ -74,7 +62,7 @@ describe('Signs', function() a | b | ^ | - {0:~ }|*10 + {1:~ }|*10 | ]]) end) @@ -91,18 +79,18 @@ describe('Signs', function() sign place 3 line=2 name=piet buffer=1 ]]) screen:expect([[ - {2: }{3:^a }| - {1:>>}b | - {2: }c | - {2: } | - {0:~ }|*2 - {4:[No Name] [+] }| - {2: }{3:a }| - {1:>>}b | - {2: }c | - {2: } | - {0:~ }| - {5:[No Name] [+] }| + {7: }{21:^a }| + {10:>>}b | + {7: }c | + {7: } | + {1:~ }|*2 + {3:[No Name] [+] }| + {7: }{21:a }| + {10:>>}b | + {7: }c | + {7: } | + {1:~ }| + {2:[No Name] [+] }| | ]]) end) @@ -122,11 +110,11 @@ describe('Signs', function() sign place 6 line=4 name=pietxx buffer=1 ]]) screen:expect([[ - {1:>>}{6: 1 }a | - {2: }{6: 2 }{8:b }| - {2: }{7: 3 }c | - {1:>>}{7: 4 }{8:^ }| - {0:~ }|*9 + {10:>>}{8: 1 }a | + {7: }{8: 2 }{9:b }| + {7: }{13: 3 }c | + {10:>>}{13: 4 }{9:^ }| + {1:~ }|*9 | ]]) -- Check that 'statuscolumn' correctly applies numhl @@ -144,45 +132,45 @@ describe('Signs', function() set cursorline ]]) screen:expect([[ - {1:>>}a | - {1:>>}b | - {8:>>}{3:^c }| - {0:~ }|*10 + {10:>>}a | + {10:>>}b | + {9:>>}{21:^c }| + {1:~ }|*10 | ]]) feed('k') screen:expect([[ - {1:>>}a | - {8:>>}{3:^b }| - {1:>>}c | - {0:~ }|*10 + {10:>>}a | + {9:>>}{21:^b }| + {10:>>}c | + {1:~ }|*10 | ]]) exec('set nocursorline') screen:expect([[ - {1:>>}a | - {1:>>}^b | - {1:>>}c | - {0:~ }|*10 + {10:>>}a | + {10:>>}^b | + {10:>>}c | + {1:~ }|*10 | ]]) exec('set cursorline cursorlineopt=line') screen:expect([[ - {1:>>}a | - {1:>>}{3:^b }| - {1:>>}c | - {0:~ }|*10 + {10:>>}a | + {10:>>}{21:^b }| + {10:>>}c | + {1:~ }|*10 | ]]) exec('set cursorlineopt=number') exec('hi! link SignColumn IncSearch') feed('Go<esc>2G') screen:expect([[ - {1:>>}a | - {8:>>}^b | - {1:>>}c | - {5: } | - {0:~ }|*9 + {10:>>}a | + {9:>>}^b | + {10:>>}c | + {2: } | + {1:~ }|*9 | ]]) -- Check that 'statuscolumn' cursorline/signcolumn highlights are the same (#21726) @@ -206,11 +194,11 @@ describe('Signs', function() -- of signs, the ones with the highest Ids are being picked, -- and presented by their sorted Id order. screen:expect([[ - {2: }{6: 1 }a | - {2: }{6: 2 }b | - WW{1:>>}{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {7: }{8: 1 }a | + {7: }{8: 2 }b | + WW{10:>>}{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) exec([[ @@ -221,42 +209,42 @@ describe('Signs', function() sign place 3 line=2 name=pietError buffer=1 ]]) screen:expect([[ - {8:XX}{1:>>}{6: 1 }a | - {1:>>}{8:XX}{6: 2 }b | - WW{1:>>}{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {9:XX}{10:>>}{8: 1 }a | + {10:>>}{9:XX}{8: 2 }b | + WW{10:>>}{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) -- With the default setting, we get the sign with the top id. exec('set signcolumn=yes:1') screen:expect([[ - {8:XX}{6: 1 }a | - {1:>>}{6: 2 }b | - WW{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {9:XX}{8: 1 }a | + {10:>>}{8: 2 }b | + WW{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) -- "auto:3" accommodates all the signs we defined so far. exec('set signcolumn=auto:3') local s3 = [[ - {8:XX}{1:>>}{2: }{6: 1 }a | - {1:>>}{8:XX}{2: }{6: 2 }b | - WW{1:>>}{8:XX}{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {9:XX}{10:>>}{7: }{8: 1 }a | + {10:>>}{9:XX}{7: }{8: 2 }b | + WW{10:>>}{9:XX}{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]] screen:expect(s3) -- Check "yes:9". exec('set signcolumn=yes:9') screen:expect([[ - {8:XX}{1:>>}{2: }{6: 1 }a | - {1:>>}{8:XX}{2: }{6: 2 }b | - WW{1:>>}{8:XX}{2: }{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {9:XX}{10:>>}{7: }{8: 1 }a | + {10:>>}{9:XX}{7: }{8: 2 }b | + WW{10:>>}{9:XX}{7: }{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) -- Check "auto:N" larger than the maximum number of signs defined in @@ -267,19 +255,19 @@ describe('Signs', function() exec('3move1') exec('2d') screen:expect([[ - {8:XX}{1:>>}{6: 1 }a | - {1:>>}{8:XX}{6: 2 }^b | - {2: }{6: 3 } | - {0:~ }|*10 + {9:XX}{10:>>}{8: 1 }a | + {10:>>}{9:XX}{8: 2 }^b | + {7: }{8: 3 } | + {1:~ }|*10 | ]]) -- character deletion does not delete signs. feed('x') screen:expect([[ - {8:XX}{1:>>}{6: 1 }a | - {1:>>}{8:XX}{6: 2 }^ | - {2: }{6: 3 } | - {0:~ }|*10 + {9:XX}{10:>>}{8: 1 }a | + {10:>>}{9:XX}{8: 2 }^ | + {7: }{8: 3 } | + {1:~ }|*10 | ]]) end) @@ -290,21 +278,21 @@ describe('Signs', function() -- sign column should always accommodate at the minimum size exec('set signcolumn=auto:1-3') screen:expect([[ - {2: }{6: 1 }a | - {2: }{6: 2 }b | - {2: }{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {7: }{8: 1 }a | + {7: }{8: 2 }b | + {7: }{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) -- should support up to 8 signs at minimum exec('set signcolumn=auto:8-9') screen:expect([[ - {2: }{6: 1 }a | - {2: }{6: 2 }b | - {2: }{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {7: }{8: 1 }a | + {7: }{8: 2 }b | + {7: }{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) -- should keep the same sign size when signs are not exceeding @@ -313,11 +301,11 @@ describe('Signs', function() exec('sign define pietSearch text=>> texthl=Search') exec('sign place 1 line=1 name=pietSearch buffer=1') screen:expect([[ - {1:>>}{2: }{6: 1 }a | - {2: }{6: 2 }b | - {2: }{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {10:>>}{7: }{8: 1 }a | + {7: }{8: 2 }b | + {7: }{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) -- should resize itself when signs are exceeding minimum but @@ -328,11 +316,11 @@ describe('Signs', function() sign place 4 line=1 name=pietSearch buffer=1 ]]) screen:expect([[ - {1:>>>>>>>>}{6: 1 }a | - {2: }{6: 2 }b | - {2: }{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {10:>>>>>>>>}{8: 1 }a | + {7: }{8: 2 }b | + {7: }{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) -- should not increase size because sign with existing id is moved @@ -340,11 +328,11 @@ describe('Signs', function() screen:expect_unchanged() exec('sign unplace 4') screen:expect([[ - {1:>>>>>>}{6: 1 }a | - {2: }{6: 2 }b | - {2: }{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {10:>>>>>>}{8: 1 }a | + {7: }{8: 2 }b | + {7: }{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) exec('sign place 4 line=1 name=pietSearch buffer=1') @@ -357,11 +345,11 @@ describe('Signs', function() sign place 8 line=1 name=pietSearch buffer=1 ]]) screen:expect([[ - {1:>>>>>>>>>>}{6: 1 }a | - {2: }{6: 2 }b | - {2: }{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {10:>>>>>>>>>>}{8: 1 }a | + {7: }{8: 2 }b | + {7: }{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) end) @@ -377,21 +365,21 @@ describe('Signs', function() ]]) -- no signcolumn with only empty sign screen:expect([[ - {6: 1 }a | - {6: 2 }b | - {6: 3 }c | - {6: 4 }^ | - {0:~ }|*9 + {8: 1 }a | + {8: 2 }b | + {8: 3 }c | + {8: 4 }^ | + {1:~ }|*9 | ]]) -- single column with 1 sign with text and one sign without exec('sign place 1 line=1 name=pietSearch buffer=1') screen:expect([[ - {1:>>}{6: 1 }a | - {2: }{6: 2 }b | - {2: }{6: 3 }c | - {2: }{6: 4 }^ | - {0:~ }|*9 + {10:>>}{8: 1 }a | + {7: }{8: 2 }b | + {7: }{8: 3 }c | + {7: }{8: 4 }^ | + {1:~ }|*9 | ]]) end) @@ -408,23 +396,23 @@ describe('Signs', function() -- line number should be drawn if sign has no text -- no signcolumn, line number for "a" is Search, for "b" is Error, for "c" is LineNr screen:expect([[ - {1: >> }a | - {8: 2 }b | - {6: 3 }c | - {6: 4 }^ | - {0:~ }|*9 + {10: >> }a | + {9: 2 }b | + {8: 3 }c | + {8: 4 }^ | + {1:~ }|*9 | ]]) -- number column on wrapped part of a line should be empty feed('gg100aa<Esc>') screen:expect([[ - {1: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {8: }aa^a | - {8: 2 }b | - {6: 3 }c | - {6: 4 } | - {0:~ }|*7 + {10: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {9: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {9: }aa^a | + {9: 2 }b | + {8: 3 }c | + {8: 4 } | + {1:~ }|*7 | ]]) api.nvim_buf_set_extmark(0, api.nvim_create_namespace('test'), 0, 0, { @@ -434,14 +422,14 @@ describe('Signs', function() feed('<C-Y>') -- number column on virtual lines should be empty screen:expect([[ - {6: }VIRT LINES | - {1: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {8: }aa^a | - {8: 2 }b | - {6: 3 }c | - {6: 4 } | - {0:~ }|*6 + {8: }VIRT LINES | + {10: >> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {9: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {9: }aa^a | + {9: 2 }b | + {8: 3 }c | + {8: 4 } | + {1:~ }|*6 | ]]) end) @@ -451,21 +439,21 @@ describe('Signs', function() exec('sign place 100000 line=1 name=piet buffer=1') feed(':sign place<cr>') screen:expect([[ - {1:>>} | - {0:~ }|*6 - {4: }| + {10:>>} | + {1:~ }|*6 + {3: }| :sign place | - {9:--- Signs ---} | - {10:Signs for [NULL]:} | + {100:--- Signs ---} | + {18:Signs for [NULL]:} | line=1 id=100000 name=piet priority=10 | | - {11:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]]) feed('<cr>') screen:expect([[ - {1:>>}^ | - {0:~ }|*12 + {10:>>}^ | + {1:~ }|*12 | ]]) end) @@ -479,11 +467,11 @@ describe('Signs', function() exec('2delete') exec('sign unplace 10001') screen:expect([[ - {2: }a | - {2: }^c | - {2: }d | + {7: }a | + {7: }^c | + {7: }d | >>e | - {0:~ }|*9 + {1:~ }|*9 | ]]) exec('sign unplace 10002') @@ -492,7 +480,7 @@ describe('Signs', function() ^c | d | e | - {0:~ }|*9 + {1:~ }|*9 | ]]) end) @@ -505,13 +493,13 @@ describe('Signs', function() exec('copy .') exec('sign unplace 10001') screen:expect([[ - {2: }a | - {2: }^a | - {2: }b | - {2: }c | - {2: }d | + {7: }a | + {7: }^a | + {7: }b | + {7: }c | + {7: }d | >>e | - {0:~ }|*7 + {1:~ }|*7 | ]]) exec('sign unplace 10002') @@ -522,7 +510,7 @@ describe('Signs', function() c | d | e | - {0:~ }|*7 + {1:~ }|*7 | ]]) end) @@ -537,9 +525,9 @@ describe('Signs', function() call sign_place(0, '', 'foo', bufnr(''), { 'lnum':2 }) ]]) screen:expect([[ - {8: 1 }^line1 | - {8: 2 }line2 | - {6: 3 }line3 | + {9: 1 }^line1 | + {9: 2 }line2 | + {8: 3 }line3 | | ]]) end) @@ -561,11 +549,11 @@ describe('Signs', function() exec('norm 2Gdd') exec('silent undo') screen:expect([[ - {2: }1 | + {7: }1 | S1^2 | - {2: }3 | - {2: }4 | - {0:~ }|*9 + {7: }3 | + {7: }4 | + {1:~ }|*9 | ]]) end) @@ -590,7 +578,7 @@ describe('Signs', function() local s1 = { grid = [[ S2^ | - {0:~ }|*12 + {1:~ }|*12 | ]], } @@ -600,7 +588,7 @@ describe('Signs', function() screen:expect({ grid = [[ S2S1^ | - {0:~ }|*12 + {1:~ }|*12 | ]], }) diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua index da112148cd..86d5a362e5 100644 --- a/test/functional/ui/spell_spec.lua +++ b/test/functional/ui/spell_spec.lua @@ -17,7 +17,6 @@ describe("'spell'", function() before_each(function() clear() screen = Screen.new(80, 8) - screen:attach() screen:set_default_attr_ids({ [0] = { bold = true, foreground = Screen.colors.Blue }, [1] = { special = Screen.colors.Red, undercurl = true }, @@ -377,4 +376,83 @@ describe("'spell'", function() | ]]) end) + + it('overrides syntax when Visual selection is active', function() + screen:try_resize(43, 3) + screen:set_default_attr_ids({ + [0] = { bold = true, foreground = Screen.colors.Blue }, + [1] = { foreground = Screen.colors.Blue }, + [2] = { foreground = Screen.colors.Red }, + [3] = { foreground = Screen.colors.Blue, underline = true }, + [4] = { foreground = Screen.colors.Red, underline = true }, + [5] = { bold = true }, + }) + exec([[ + hi! Comment guibg=NONE guifg=Blue gui=NONE guisp=NONE + hi! SpellBad guibg=NONE guifg=Red gui=NONE guisp=NONE + hi! Visual guibg=NONE guifg=NONE gui=underline guisp=NONE + syn match Comment "//.*" + call setline(1, '// Here is a misspeld word.') + set spell + ]]) + screen:expect([[ + {1:^// Here is a }{2:misspeld}{1: word.} | + {0:~ }| + | + ]]) + feed('V') + screen:expect([[ + {1:^/}{3:/ Here is a }{4:misspeld}{3: word.} | + {0:~ }| + {5:-- VISUAL LINE --} | + ]]) + end) + + it("global value works properly for 'spelloptions'", function() + screen:try_resize(43, 3) + exec('set spell') + -- :setglobal applies to future buffers but not current buffer + exec('setglobal spelloptions=camel') + insert('Here is TheCamelWord being spellchecked') + screen:expect([[ + Here is {1:TheCamelWord} being spellchecke^d | + {0:~ }| + | + ]]) + exec('enew') + insert('There is TheCamelWord being spellchecked') + screen:expect([[ + There is TheCamelWord being spellchecke^d | + {0:~ }| + | + ]]) + -- :setlocal applies to current buffer but not future buffers + exec('setlocal spelloptions=') + screen:expect([[ + There is {1:TheCamelWord} being spellchecke^d | + {0:~ }| + | + ]]) + exec('enew') + insert('What is TheCamelWord being spellchecked') + screen:expect([[ + What is TheCamelWord being spellchecke^d | + {0:~ }| + | + ]]) + -- :set applies to both current buffer and future buffers + exec('set spelloptions=') + screen:expect([[ + What is {1:TheCamelWord} being spellchecke^d | + {0:~ }| + | + ]]) + exec('enew') + insert('Where is TheCamelWord being spellchecked') + screen:expect([[ + Where is {1:TheCamelWord} being spellchecke^d | + {0:~ }| + | + ]]) + end) end) diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua index b4d4c94a5e..268e7173e6 100644 --- a/test/functional/ui/statuscolumn_spec.lua +++ b/test/functional/ui/statuscolumn_spec.lua @@ -20,7 +20,6 @@ describe('statuscolumn', function() before_each(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) @@ -235,30 +234,24 @@ describe('statuscolumn', function() it('works with wrapped lines, signs and folds', function() command([[set stc=%C%s%=%{v:virtnum?'':v:lnum}│\ ]]) command("call setline(1,repeat([repeat('aaaaa',10)],16))") - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.Brown }, - [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] = { foreground = Screen.colors.Red }, - [6] = { foreground = Screen.colors.Red, background = Screen.colors.LightGrey }, - }) + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Red, background = Screen.colors.LightGray }, + } command('hi! CursorLine guifg=Red guibg=NONE') screen:expect([[ - {1: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1: │ }a | - {1: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1: │ }a | - {1: 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1: │ }a | - {1: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1: │ }a | - {1: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1: │ }a | - {1: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1: │ }a | - {1:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{0:@@@}| + {8: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8: │ }a | + {8: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8: │ }a | + {8: 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8: │ }a | + {8: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8: │ }a | + {8: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8: │ }a | + {8: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8: │ }a | + {8:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:@@@}| | ]]) command([[set stc=%C%s%=%l│\ ]]) @@ -271,108 +264,108 @@ describe('statuscolumn', function() command('sign place 3 line=6 name=piet1 buffer=1') command('sign place 4 line=6 name=piet2 buffer=1') screen:expect([[ - {1:>>}{2: }{1: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │ }aaaaa | - {0:>!}{2: }{1: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │ }aaaaa | - {0:>!}{1:>> 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │ }aaaaa | - {2: }{1: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │ }aaaaa | - {2: }{1: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │ }aaaaa | - {2: }{1: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │ }aaaaa | - {2: }{1:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{0:@@@}| + {8:>>}{7: }{8: 4│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │ }aaaaa | + {1:>!}{7: }{8: 5│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │ }aaaaa | + {1:>!}{8:>> 6│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │ }aaaaa | + {7: }{8: 7│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │ }aaaaa | + {7: }{8: 8│ }^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │ }aaaaa | + {7: }{8: 9│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │ }aaaaa | + {7: }{8:10│ }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:@@@}| | ]]) command('norm zf$') -- Check that alignment works properly with signs after %= command([[set stc=%C%=%{v:virtnum?'':v:lnum}│%s\ ]]) screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 5│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 6│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2:+}{1: 8│}{2: }{1: }{3:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{1: 9│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1:10│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | + {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | + {7: }{8: 5│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | + {7: }{8: 6│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | + {7: }{8: 7│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | + {7:+}{8: 8│}{7: }{8: }{13:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {7: }{8: 9│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | + {7: }{8:10│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | | ]]) command('set cursorline') screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 5│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 6│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaa | - {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| - {2: }{1: │}{2: }{1: }aaaaaa | + {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | + {7: }{8: 5│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | + {7: }{8: 6│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | + {7: }{8: 7│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | + {7:+}{15: 8│}{7: }{15: }{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {7: }{8: 9│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | + {7: }{8:10│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaa | | ]]) -- v:lnum is the same value on wrapped lines command([[set stc=%C%=%{v:lnum}│%s\ ]]) screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 4│}{2: }{1: }aaaaaa | - {2: }{1: 5│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 5│}{2: }{1: }aaaaaa | - {2: }{1: 6│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 6│}{2: }{1: }aaaaaa | - {2: }{1: 7│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 7│}{2: }{1: }aaaaaa | - {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| - {2: }{1:10│}{2: }{1: }aaaaaa | + {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 4│}{7: }{8: }aaaaaa | + {7: }{8: 5│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 5│}{7: }{8: }aaaaaa | + {7: }{8: 6│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 6│}{7: }{8: }aaaaaa | + {7: }{8: 7│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 7│}{7: }{8: }aaaaaa | + {7:+}{15: 8│}{7: }{15: }{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {7: }{8: 9│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 9│}{7: }{8: }aaaaaa | + {7: }{8:10│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8:10│}{7: }{8: }aaaaaa | | ]]) -- v:relnum is the same value on wrapped lines command([[set stc=%C%=\ %{v:relnum}│%s\ ]]) screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 4│}{2: }{1: }aaaaaaa | - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 3│}{2: }{1: }aaaaaaa | - {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 2│}{2: }{1: }aaaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 1│}{2: }{1: }aaaaaaa | - {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 1│}{2: }{1: }aaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: 2│}{2: }{1: }aaaaaaa | + {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 4│}{7: }{8: }aaaaaaa | + {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 3│}{7: }{8: }aaaaaaa | + {7: }{8: 2│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 2│}{7: }{8: }aaaaaaa | + {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 1│}{7: }{8: }aaaaaaa | + {7:+}{15: 0│}{7: }{15: }{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 1│}{7: }{8: }aaaaaaa | + {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: 2│}{7: }{8: }aaaaaaa | | ]]) command([[set stc=%C%=\ %{v:virtnum?'':v:relnum}│%s\ ]]) screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaa | - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaa | - {2: }{1: 2│}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaa | - {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaa | + {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaa | + {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaa | + {7: }{8: 2│}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaa | + {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaa | + {7:+}{15: 0│}{7: }{15: }{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaa | + {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaa | | ]]) -- Up to 9 signs in a line @@ -385,75 +378,75 @@ describe('statuscolumn', function() command('sign place 10 line=6 name=piet2 buffer=1') command('sign place 11 line=6 name=piet1 buffer=1') screen:expect([[ - {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | - {2:+}{4: 0│}{2: }{4: }{6:^+-- 1 line: aaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 4│>>}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 2│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa | + {7:+}{15: 0│}{7: }{15: }{100:^+-- 1 line: aaaaaaaaaaaaaaaa}| + {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }{8: │}{7: }{8: }aaaaaaaaaaaaaaaaaaaaa | | ]]) -- Also test fold and sign column when 'cpoptions' includes "n" command('set cpoptions+=n') feed('Hgjg0') screen:expect([[ - {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{5:^aaaaaaaaaaaaaaaaaaaaa }| - {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaaa | - {2:+}{1: 4│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}| - {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{15: 0│}{8:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {7: }{19:^aaaaaaaaaaaaaaaaaaaaa }| + {7: }{8: 3│}{1:>!}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 2│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }aaaaaaaaaaaaaaaaaaaaa | + {7:+}{8: 4│}{7: }{8: }{13:+-- 1 line: aaaaaaaaaaaaaaaa}| + {7: }{8: 1│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }aaaaaaaaaaaaaaaaaaaaa | | ]]) command('set breakindent') command('sign unplace 2') feed('J2gjg0') screen:expect([[ - {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: } {5:aaaaaaaaaaaaaaaaaaaaa aaaaaaa}| - {2: } {5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: } {5:^aaaaaaaaaaaaaa }| - {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaaa | - {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}| - {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: } aaaaaaaaaaaaaaaaaaaaa | + {7: }{15: 0│}{8:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {7: } {19:aaaaaaaaaaaaaaaaaaaaa aaaaaaa}| + {7: } {19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {7: } {19:^aaaaaaaaaaaaaa }| + {7: }{8: 1│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: } aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: } aaaaaaaaaaaaaaaaaaaaa | + {7:+}{8: 3│}{7: }{8: }{13:+-- 1 line: aaaaaaaaaaaaaaaa}| + {7: }{8: 4│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: } aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 5│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: } aaaaaaaaaaaaaaaaaaaaa | | ]]) command('set nobreakindent') feed('$g0') screen:expect([[ - {2: }{4: 0│}{1:>>}{2: }{4: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{5:aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa}| - {2: }{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {2: }{5:^aaaa }| - {2: }{1: 1│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaaa | - {2:+}{1: 3│}{2: }{1: }{3:+-- 1 line: aaaaaaaaaaaaaaaa}| - {2: }{1: 4│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaaa | - {2: }{1: 5│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {2: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{15: 0│}{8:>>}{7: }{15: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {7: }{19:aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaa}| + {7: }{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {7: }{19:^aaaa }| + {7: }{8: 1│>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>>}{1:>!}{8:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 2│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }aaaaaaaaaaaaaaaaaaaaa | + {7:+}{8: 3│}{7: }{8: }{13:+-- 1 line: aaaaaaaaaaaaaaaa}| + {7: }{8: 4│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }aaaaaaaaaaaaaaaaaaaaa | + {7: }{8: 5│}{7: }{8: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {7: }aaaaaaaaaaaaaaaaaaaaa | | ]]) command('silent undo') @@ -467,38 +460,38 @@ describe('statuscolumn', function() ]]) command('set foldcolumn=0 signcolumn=number stc=%l') screen:expect([[ - {1:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | - {1: 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | - {1: }virt_line | - {1: }virt_line above | - {1:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | - {1: 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | - {4: 8}{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {1: 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | - {1:10}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | - {1:11}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | - {1:12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | - {1:13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | - {1:14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {8:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {8: 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {8: }virt_line | + {8: }virt_line above | + {8:>>}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {8: 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {15: 8}{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {8: 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {8:10}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {8:11}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {8:12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {8:13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | + {8:14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | | ]]) command( [[set stc=%{v:virtnum<0?'virtual':(!v:virtnum?'buffer':'wrapped')}%=%{'\ '.v:virtnum.'\ '.v:lnum}]] ) screen:expect([[ - {1:buffer 0 4}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 4}aaaaaaaa | - {1:buffer 0 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 5}aaaaaaaa | - {1:virtual-2 5}virt_line | - {1:virtual-1 5}virt_line above | - {1:buffer 0 6}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 6}aaaaaaaa | - {1:buffer 0 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 7}aaaaaaaa | - {4:buffer 0 8}{6:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {1:buffer 0 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 9}aaaaaaaa | + {8:buffer 0 4}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 4}aaaaaaaa | + {8:buffer 0 5}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 5}aaaaaaaa | + {8:virtual-2 5}virt_line | + {8:virtual-1 5}virt_line above | + {8:buffer 0 6}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 6}aaaaaaaa | + {8:buffer 0 7}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 7}aaaaaaaa | + {15:buffer 0 8}{100:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {8:buffer 0 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 9}aaaaaaaa | | ]]) -- Also test virt_lines at the end of buffer @@ -507,17 +500,17 @@ describe('statuscolumn', function() ]]) feed('GkJzz') screen:expect([[ - {1:buffer 0 12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 12}aaaaaaaaa | - {1:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 13}aaaaaaaaa | - {1:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 14}aaaaaaaaa | - {4:buffer 0 15}{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {4:wrapped 1 15}{5:aaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {4:wrapped 2 15}{5:aaaaaaaaaaaaaaaaaaa }| - {1:virtual-1 15}END | - {0:~ }|*3 + {8:buffer 0 12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 12}aaaaaaaaa | + {8:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 13}aaaaaaaaa | + {8:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 14}aaaaaaaaa | + {15:buffer 0 15}{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {15:wrapped 1 15}{19:aaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {15:wrapped 2 15}{19:aaaaaaaaaaaaaaaaaaa }| + {8:virtual-1 15}END | + {1:~ }|*3 | ]]) -- Also test virt_lines when 'cpoptions' includes "n" @@ -527,19 +520,19 @@ describe('statuscolumn', function() vim.api.nvim_buf_set_extmark(0, ns, 14, 0, { virt_lines = {{{"virt_line2", ""}}} }) ]]) screen:expect([[ - {1:buffer 0 12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:buffer 0 12}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| aaaaaaaaa | - {1:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:buffer 0 13}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| aaaaaaaaa | - {1:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:buffer 0 14}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| aaaaaaaaa | - {4:buffer 0 15}{5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {5:aaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| - {5:aaaaaaa }| - {1:virtual-3 15}virt_line1 | - {1:virtual-2 15}virt_line2 | - {1:virtual-1 15}END | - {0:~ }| + {15:buffer 0 15}{19:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {19:aaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {19:aaaaaaa }| + {8:virtual-3 15}virt_line1 | + {8:virtual-2 15}virt_line2 | + {8:virtual-1 15}END | + {1:~ }| | ]]) -- Also test "col_rows" code path for 'relativenumber' cursor movement @@ -548,36 +541,36 @@ describe('statuscolumn', function() set stc=%{v:virtnum<0?'virtual':(!v:virtnum?'buffer':'wrapped')}%=%{'\ '.v:virtnum.'\ '.v:lnum.'\ '.v:relnum} ]]) screen:expect([[ - {1:buffer 0 12 3}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 12 3}aaaaaaaaaaa | - {1:buffer 0 13 2}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 13 2}aaaaaaaaaaa | - {1:buffer 0 14 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 14 1}aaaaaaaaaaa | - {1:buffer 0 15 0}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 15 0}aaaaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 2 15 0}aaaaaaaaaaaaaaaaaaaaaaa | - {1:virtual-3 15 0}virt_line1 | - {1:virtual-2 15 0}virt_line2 | - {1:virtual-1 15 0}END | - {0:~ }| + {8:buffer 0 12 3}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 12 3}aaaaaaaaaaa | + {8:buffer 0 13 2}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 13 2}aaaaaaaaaaa | + {8:buffer 0 14 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 14 1}aaaaaaaaaaa | + {8:buffer 0 15 0}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 15 0}aaaaaaaaaaa^ aaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 2 15 0}aaaaaaaaaaaaaaaaaaaaaaa | + {8:virtual-3 15 0}virt_line1 | + {8:virtual-2 15 0}virt_line2 | + {8:virtual-1 15 0}END | + {1:~ }| | ]]) feed('kk') screen:expect([[ - {1:buffer 0 12 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 12 1}aaaaaaaaaaa | - {1:buffer 0 13 0}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 13 0}aaaaaaaaaa^a | - {1:buffer 0 14 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 14 1}aaaaaaaaaaa | - {1:buffer 0 15 2}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 1 15 2}aaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaa| - {1:wrapped 2 15 2}aaaaaaaaaaaaaaaaaaaaaaa | - {1:virtual-3 15 2}virt_line1 | - {1:virtual-2 15 2}virt_line2 | - {1:virtual-1 15 2}END | - {0:~ }| + {8:buffer 0 12 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 12 1}aaaaaaaaaaa | + {8:buffer 0 13 0}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 13 0}aaaaaaaaaa^a | + {8:buffer 0 14 1}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 14 1}aaaaaaaaaaa | + {8:buffer 0 15 2}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 1 15 2}aaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaa| + {8:wrapped 2 15 2}aaaaaaaaaaaaaaaaaaaaaaa | + {8:virtual-3 15 2}virt_line1 | + {8:virtual-2 15 2}virt_line2 | + {8:virtual-1 15 2}END | + {1:~ }| | ]]) end) @@ -680,10 +673,6 @@ describe('statuscolumn', function() it('popupmenu callback does not drag mouse on close', function() screen:try_resize(screen._width, 2) - screen:set_default_attr_ids({ - [0] = { foreground = Screen.colors.Brown }, - [1] = { background = Screen.colors.Plum1 }, - }) api.nvim_set_option_value('statuscolumn', '%0@MyClickFunc@%l%T', {}) exec([[ function! MyClickFunc(minwid, clicks, button, mods) @@ -695,26 +684,26 @@ describe('statuscolumn', function() -- clicking an item does not drag mouse api.nvim_input_mouse('left', 'press', '', 0, 0, 0) screen:expect([[ - {0: 8}^aaaaa | - {1: Echo } | + {8: 8}^aaaaa | + {4: Echo } | ]]) api.nvim_input_mouse('left', 'press', '', 0, 1, 5) api.nvim_input_mouse('left', 'release', '', 0, 1, 5) screen:expect([[ - {0: 8}^aaaaa | + {8: 8}^aaaaa | 0 1 l 8 | ]]) command('echo') -- clicking outside to close the menu does not drag mouse api.nvim_input_mouse('left', 'press', '', 0, 0, 0) screen:expect([[ - {0: 8}^aaaaa | - {1: Echo } | + {8: 8}^aaaaa | + {4: Echo } | ]]) api.nvim_input_mouse('left', 'press', '', 0, 0, 10) api.nvim_input_mouse('left', 'release', '', 0, 0, 10) screen:expect([[ - {0: 8}^aaaaa | + {8: 8}^aaaaa | | ]]) end) @@ -943,16 +932,15 @@ describe('statuscolumn', function() it('does not wrap multibyte characters at the end of a line', function() screen:try_resize(33, 4) - screen:set_default_attr_ids { - [8] = { foreground = Screen.colors.Brown }, - [31] = { undercurl = true, special = Screen.colors.Red }, + screen:add_extra_attr_ids { + [100] = { undercurl = true, special = Screen.colors.Red }, } command([[set spell stc=%l\ ]]) command('call setline(8, "This is a line that contains ᶏ multibyte character.")') screen:expect([[ - {8: 8 }^This is a line that contains {31:ᶏ}| - {8: } {31:multibyte} character. | - {8: 9 }{31:aaaaa} | + {8: 8 }^This is a line that contains {100:ᶏ}| + {8: } {100:multibyte} character. | + {8: 9 }{100:aaaaa} | | ]]) end) diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index 937e709d66..1d0f181244 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -24,11 +24,9 @@ for _, model in ipairs(mousemodels) do before_each(function() clear() screen = Screen.new(40, 8) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- StatusLine - }) - screen:attach() + screen:add_extra_attr_ids { + [100] = { bold = true, reverse = true, foreground = Screen.colors.Blue }, + } command('set laststatus=2 mousemodel=' .. model) exec([=[ function! MyClickFunc(minwid, clicks, button, mods) @@ -86,8 +84,8 @@ for _, model in ipairs(mousemodels) do screen:expect { grid = [[ ^ | - {0:~ }|*5 - {1:^I}{0:^A^I^A^I}{1:^A }| + {1:~ }|*5 + {3:^I}{100:^A^I^A^I}{3:^A }| | ]], } @@ -210,8 +208,8 @@ for _, model in ipairs(mousemodels) do screen:expect { grid = [[ ^ │ | - {0:~ }│{0:~ }|*5 - {1:Clicky stuff Clicky stuff}| + {1:~ }│{1:~ }|*5 + {3:Clicky stuff Clicky stuff}| | ]], } @@ -255,14 +253,9 @@ describe('global statusline', function() before_each(function() clear() screen = Screen.new(60, 16) - screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, - [2] = { bold = true, reverse = true }, - [3] = { bold = true }, - [4] = { reverse = true }, - [5] = { bold = true, foreground = Screen.colors.Fuchsia }, - }) + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Magenta1, bold = true }, + } command('set laststatus=3') command('set ruler') end) @@ -271,7 +264,7 @@ describe('global statusline', function() screen:expect([[ ^ | {1:~ }|*13 - {2:[No Name] 0,0-1 All}| + {3:[No Name] 0,0-1 All}| | ]]) @@ -280,8 +273,8 @@ describe('global statusline', function() |*2 ^ | {1:~ }|*11 - {2:[No Name] [+] 3,1 All}| - {3:-- INSERT --} | + {3:[No Name] [+] 3,1 All}| + {5:-- INSERT --} | ]]) end) @@ -298,7 +291,7 @@ describe('global statusline', function() ────────────────────┴────────────────┴─┤{1:~ }| │{1:~ }| {1:~ }│{1:~ }|*3 - {2:[No Name] 0,0-1 All}| + {3:[No Name] 0,0-1 All}| | ]]) end) @@ -315,7 +308,7 @@ describe('global statusline', function() screen:expect([[ ^ | {1:~ }|*13 - {2:[No Name] 0,0-1 All}| + {3:[No Name] 0,0-1 All}| | ]]) @@ -324,15 +317,15 @@ describe('global statusline', function() screen:expect([[ │ │ │^ | {1:~ }│{1:~ }│{1:~}│{1:~ }|*3 - {1:~ }│{4:< Name] 0,0-1 }│{1:~}│{1:~ }| + {1:~ }│{2:< Name] 0,0-1 }│{1:~}│{1:~ }| {1:~ }│ │{1:~}│{1:~ }| {1:~ }│{1:~ }│{1:~}│{1:~ }| - {1:~ }│{1:~ }│{1:~}│{2:<No Name] 0,0-1 All}| + {1:~ }│{1:~ }│{1:~}│{3:<No Name] 0,0-1 All}| {1:~ }│{1:~ }│{1:~}│ | - {4:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }| + {2:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }| │{1:~ }| {1:~ }│{1:~ }|*3 - {4:[No Name] 0,0-1 All <No Name] 0,0-1 All}| + {2:[No Name] 0,0-1 All <No Name] 0,0-1 All}| | ]]) @@ -348,7 +341,7 @@ describe('global statusline', function() ────────────────────┴────────────────┴─┤{1:~ }| │{1:~ }| {1:~ }│{1:~ }|*3 - {2:[No Name] 0,0-1 All}| + {3:[No Name] 0,0-1 All}| | ]]) @@ -356,12 +349,12 @@ describe('global statusline', function() screen:expect([[ │ │ │^ | {1:~ }│{1:~ }│{1:~}│{1:~ }|*3 - {1:~ }│{4:< Name] 0,0-1 }│{1:~}│{1:~ }| + {1:~ }│{2:< Name] 0,0-1 }│{1:~}│{1:~ }| {1:~ }│ │{1:~}│{1:~ }| {1:~ }│{1:~ }│{1:~}│{1:~ }| - {1:~ }│{1:~ }│{1:~}│{2:<No Name] 0,0-1 All}| + {1:~ }│{1:~ }│{1:~}│{3:<No Name] 0,0-1 All}| {1:~ }│{1:~ }│{1:~}│ | - {4:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }| + {2:<No Name] 0,0-1 All < Name] 0,0-1 <}│{1:~ }| │{1:~ }| {1:~ }│{1:~ }|*4 0,0-1 All | @@ -379,7 +372,7 @@ describe('global statusline', function() ────────────────────┴────────────────┴─┤{1:~ }| │{1:~ }| {1:~ }│{1:~ }|*3 - {2:[No Name] 0,0-1 All}| + {3:[No Name] 0,0-1 All}| | ]]) end) @@ -429,7 +422,7 @@ describe('global statusline', function() 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; | 0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; | ^0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; | - {2:test/functional/fixtures/bigfile.txt 7,1 Top}| + {3:test/functional/fixtures/bigfile.txt 7,1 Top}| | ]]) feed('j') @@ -444,12 +437,12 @@ describe('global statusline', function() 0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; | 0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; | ^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; | - {2:test/functional/fixtures/bigfile.txt 8,1 0%}| + {3:test/functional/fixtures/bigfile.txt 8,1 0%}| | ]]) api.nvim_set_option_value('showtabline', 2, {}) screen:expect([[ - {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }| + {5: }{100:2}{5: t/f/f/bigfile.txt }{2: }| | {1:~ }|*5 ────────────────────────────────────────────────────────────| @@ -459,12 +452,12 @@ describe('global statusline', function() 0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; | 0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; | ^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; | - {2:test/functional/fixtures/bigfile.txt 8,1 0%}| + {3:test/functional/fixtures/bigfile.txt 8,1 0%}| | ]]) api.nvim_set_option_value('cmdheight', 0, {}) screen:expect([[ - {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }| + {5: }{100:2}{5: t/f/f/bigfile.txt }{2: }| | {1:~ }|*5 ────────────────────────────────────────────────────────────| @@ -475,11 +468,11 @@ describe('global statusline', function() 0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; | 0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; | ^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; | - {2:test/functional/fixtures/bigfile.txt 8,1 0%}| + {3:test/functional/fixtures/bigfile.txt 8,1 0%}| ]]) api.nvim_set_option_value('cmdheight', 1, {}) screen:expect([[ - {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }| + {5: }{100:2}{5: t/f/f/bigfile.txt }{2: }| | {1:~ }|*5 ────────────────────────────────────────────────────────────| @@ -489,7 +482,7 @@ describe('global statusline', function() 0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;; | 0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;; | ^0007;<control>;Cc;0;BN;;;;;N;BELL;;;; | - {2:test/functional/fixtures/bigfile.txt 8,1 0%}| + {3:test/functional/fixtures/bigfile.txt 8,1 0%}| | ]]) end) @@ -508,7 +501,7 @@ describe('global statusline', function() ────────────────────────────────────────────────────────────| ^ | {1:~ }|*6 - {2:[No Name] 0,0-1 All}| + {3:[No Name] 0,0-1 All}| | ]]) end) @@ -525,11 +518,6 @@ end) it('statusline is redrawn with :resize from <Cmd> mapping #19629', function() clear() local screen = Screen.new(40, 8) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- StatusLine - }) - screen:attach() exec([[ set laststatus=2 nnoremap <Up> <cmd>resize -1<CR> @@ -538,15 +526,15 @@ it('statusline is redrawn with :resize from <Cmd> mapping #19629', function() feed('<Up>') screen:expect([[ ^ | - {0:~ }|*4 - {1:[No Name] }| + {1:~ }|*4 + {3:[No Name] }| |*2 ]]) feed('<Down>') screen:expect([[ ^ | - {0:~ }|*5 - {1:[No Name] }| + {1:~ }|*5 + {3:[No Name] }| | ]]) end) @@ -554,19 +542,13 @@ end) it('showcmdloc=statusline does not show if statusline is too narrow', function() clear() local screen = Screen.new(40, 8) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- StatusLine - [2] = { reverse = true }, -- StatusLineNC - }) - screen:attach() command('set showcmd') command('set showcmdloc=statusline') command('1vsplit') screen:expect([[ ^ │ | - {0:~}│{0:~ }|*5 - {1:< }{2:[No Name] }| + {1:~}│{1:~ }|*5 + {3:< }{2:[No Name] }| | ]]) feed('1234') @@ -575,8 +557,7 @@ end) it('K_EVENT does not trigger a statusline redraw unnecessarily', function() clear() - local screen = Screen.new(40, 8) - screen:attach() + local _ = Screen.new(40, 8) -- does not redraw on vim.schedule (#17937) command([[ set laststatus=2 @@ -608,7 +589,6 @@ end) it('statusline is redrawn on various state changes', function() clear() local screen = Screen.new(40, 4) - screen:attach() -- recording state change #22683 command('set ls=2 stl=%{repeat(reg_recording(),5)}') @@ -674,7 +654,6 @@ 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} @@ -691,12 +670,6 @@ 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 @@ -713,7 +686,7 @@ it('shows correct ruler in cmdline with no statusline', function() screen:expect [[ ^ | {1:~ }|*2 - {2:[No Name] 1longlonglong }| + {3:[No Name] 1longlonglong }| │ | {1:~ }│{1:~ }|*2 3longlonglong | @@ -724,7 +697,7 @@ it('shows correct ruler in cmdline with no statusline', function() screen:expect [[ | {1:~ }|*2 - {3:[No Name] 1longlonglong }| + {2:[No Name] 1longlonglong }| ^ │ | {1:~ }│{1:~ }|*2 2longlonglong | @@ -734,7 +707,7 @@ it('shows correct ruler in cmdline with no statusline', function() screen:expect [[ | {1:~ }|*2 - {3:[No Name] 1longlonglong }| + {2:[No Name] 1longlonglong }| │^ | {1:~ }│{1:~ }|*2 3longlonglong | @@ -744,10 +717,6 @@ end) it('uses "stl" and "stlnc" fillchars even if they are the same #19803', function() clear() local screen = Screen.new(53, 4) - screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - }) command('hi clear StatusLine') command('hi clear StatusLineNC') command('vsplit') @@ -764,19 +733,13 @@ end) it('showcmdloc=statusline works with vertical splits', function() clear() local screen = Screen.new(53, 4) - 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() command('rightbelow vsplit') command('set showcmd showcmdloc=statusline') feed('1234') screen:expect([[ │^ | {1:~ }│{1:~ }| - {3:[No Name] }{2:[No Name] 1234 }| + {2:[No Name] }{3:[No Name] 1234 }| | ]]) feed('<Esc>') @@ -785,7 +748,7 @@ it('showcmdloc=statusline works with vertical splits', function() screen:expect([[ │^ | {1:~ }│{1:~ }| - {2:[No Name] 1234 }| + {3:[No Name] 1234 }| | ]]) end) @@ -793,25 +756,19 @@ end) it('keymap is shown with vertical splits #27269', function() clear() local screen = Screen.new(53, 4) - 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() command('setlocal keymap=dvorak') command('rightbelow vsplit') screen:expect([[ │^ | {1:~ }│{1:~ }| - {3:[No Name] <en-dv> }{2:[No Name] <en-dv> }| + {2:[No Name] <en-dv> }{3:[No Name] <en-dv> }| | ]]) command('set laststatus=3') screen:expect([[ │^ | {1:~ }│{1:~ }| - {2:[No Name] <en-dv> }| + {3:[No Name] <en-dv> }| | ]]) end) diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua index be35e9bf4f..57d76e54df 100644 --- a/test/functional/ui/syntax_conceal_spec.lua +++ b/test/functional/ui/syntax_conceal_spec.lua @@ -14,7 +14,6 @@ describe('Screen', function() before_each(function() clear() screen = Screen.new(nil, 10) - screen:attach() screen:set_default_attr_ids({ [0] = { bold = true, foreground = Screen.colors.Blue }, [1] = { foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray }, diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua index 5cda70df21..6d212823eb 100644 --- a/test/functional/ui/tabline_spec.lua +++ b/test/functional/ui/tabline_spec.lua @@ -13,8 +13,7 @@ describe('ui/ext_tabline', function() before_each(function() clear() - screen = Screen.new(25, 5) - screen:attach({ rgb = true, ext_tabline = true }) + screen = Screen.new(25, 5, { rgb = true, ext_tabline = true }) function screen:_handle_tabline_update(curtab, tabs, curbuf, buffers) event_curtab = curtab event_tabs = tabs @@ -100,7 +99,6 @@ describe('tabline', function() before_each(function() clear() screen = Screen.new(42, 5) - screen:attach() end) it('redraws when tabline option is set', function() @@ -125,6 +123,26 @@ describe('tabline', function() } end) + it('combines highlight attributes', function() + screen:set_default_attr_ids({ + [1] = { foreground = Screen.colors.Blue1, bold = true }, -- StatusLine + [2] = { bold = true, italic = true }, -- StatusLine + [3] = { bold = true, italic = true, foreground = Screen.colors.Red }, -- NonText combined with StatusLine + }) + command('hi TabLineFill gui=bold,italic') + command('hi Identifier guifg=red') + command('set tabline=Test%#Identifier#here') + command('set showtabline=2') + screen:expect { + grid = [[ + {2:Test}{3:here }| + ^ | + {1:~ }|*2 + | + ]], + } + end) + it('click definitions do not leak memory #21765', function() command('set tabline=%@MyClickFunc@MyClickText%T') command('set showtabline=2') @@ -196,4 +214,43 @@ describe('tabline', function() api.nvim_input_mouse('middle', 'press', '', 0, 0, 1) eq({ 1, 1 }, api.nvim_eval('[tabpagenr(), tabpagenr("$")]')) end) + + it('does not show floats with focusable=false', function() + screen:set_default_attr_ids({ + [1] = { background = Screen.colors.Plum1 }, + [2] = { underline = true, background = Screen.colors.LightGrey }, + [3] = { bold = true }, + [4] = { reverse = true }, + [5] = { bold = true, foreground = Screen.colors.Blue1 }, + [6] = { foreground = Screen.colors.Fuchsia, bold = true }, + [7] = { foreground = Screen.colors.SeaGreen, bold = true }, + }) + command('tabnew') + api.nvim_open_win(0, false, { + focusable = false, + relative = 'editor', + height = 1, + width = 1, + row = 0, + col = 0, + }) + screen:expect { + grid = [[ + {1: }{2:[No Name] }{3: [No Name] }{4: }{2:X}| + ^ | + {5:~ }|*2 + | + ]], + } + command('tabs') + screen:expect { + grid = [[ + {6:Tab page 1} | + # [No Name] | + {6:Tab page 2} | + > [No Name] | + {7:Press ENTER or type command to continue}^ | + ]], + } + end) end) diff --git a/test/functional/ui/title_spec.lua b/test/functional/ui/title_spec.lua index 3189232957..66eb15478b 100644 --- a/test/functional/ui/title_spec.lua +++ b/test/functional/ui/title_spec.lua @@ -18,7 +18,6 @@ describe('title', function() before_each(function() clear() screen = Screen.new() - screen:attach() end) it('has correct default title with unnamed file', function() diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 4d01b7a779..94710bfb74 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -19,7 +19,6 @@ describe("'wildmenu'", function() screen:add_extra_attr_ids { [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black }, } - screen:attach() end) -- oldtest: Test_wildmenu_screendump() @@ -492,7 +491,6 @@ describe('command line completion', function() screen:add_extra_attr_ids { [100] = { background = Screen.colors.Yellow1, foreground = Screen.colors.Black }, } - screen:attach() end) after_each(function() os.remove('Xtest-functional-viml-compl-dir') @@ -592,8 +590,7 @@ describe('ui/ext_wildmenu', function() before_each(function() clear() - screen = Screen.new(25, 5) - screen:attach({ rgb = true, ext_wildmenu = true }) + screen = Screen.new(25, 5, { rgb = true, ext_wildmenu = true }) end) it('works with :sign <tab>', function() diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua index fb907026a5..d1fd273dc1 100644 --- a/test/functional/ui/winbar_spec.lua +++ b/test/functional/ui/winbar_spec.lua @@ -18,7 +18,6 @@ describe('winbar', function() before_each(function() clear() screen = Screen.new(60, 13) - screen:attach() screen:set_default_attr_ids({ [1] = { bold = true }, [2] = { reverse = true }, @@ -40,6 +39,16 @@ describe('winbar', function() bold = true, foreground = Screen.colors.Magenta, }, + [12] = { + underline = true, + background = Screen.colors.Red, + }, + [13] = { + underline = true, + bold = true, + foreground = Screen.colors.Blue, + background = Screen.colors.Red, + }, }) api.nvim_set_option_value('winbar', 'Set Up The Bars', {}) end) @@ -182,6 +191,18 @@ describe('winbar', function() ]]) end) + it('works with combined highlight attributes', function() + command('hi Winbar guibg=red gui=underline') + command('hi Identifier guifg=blue gui=bold') + command('set winbar=Lookatmy%#Identifier#highlights') + screen:expect([[ + {12:Lookatmy}{13:highlights }| + ^ | + {3:~ }|*10 + | + ]]) + end) + it('can be ruler', function() insert [[ just some @@ -526,7 +547,6 @@ describe('local winbar with tabs', function() before_each(function() clear() screen = Screen.new(60, 10) - screen:attach() api.nvim_set_option_value('winbar', 'foo', { scope = 'local', win = 0 }) end) @@ -604,7 +624,6 @@ it('winbar works properly when redrawing is postponed #23534', function() }, }) local screen = Screen.new(60, 6) - screen:attach() screen:expect([[ {5:(winbar) }| ^ | diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua index 30d6c969ca..5db8c24120 100644 --- a/test/functional/vimscript/api_functions_spec.lua +++ b/test/functional/vimscript/api_functions_spec.lua @@ -129,8 +129,6 @@ describe('eval-API', function() end) it('use buffer numbers and windows ids as handles', function() - local screen = Screen.new(40, 8) - screen:attach() local bnr = eval("bufnr('')") local bhnd = eval('nvim_get_current_buf()') local wid = eval('win_getid()') @@ -192,14 +190,6 @@ describe('eval-API', function() it('are highlighted by vim.vim syntax file', function() local screen = Screen.new(40, 8) - screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Brown }, - [2] = { foreground = Screen.colors.DarkCyan }, - [3] = { foreground = Screen.colors.SlateBlue }, - [4] = { foreground = Screen.colors.Fuchsia }, - [5] = { bold = true, foreground = Screen.colors.Blue }, - }) command('set ft=vim') command('set rtp^=build/runtime/') @@ -210,10 +200,10 @@ describe('eval-API', function() call not_a_function(42)]]) screen:expect([[ - {1:call} {2:bufnr}{3:(}{4:'%'}{3:)} | - {1:call} {2:nvim_input}{3:(}{4:'typing...'}{3:)} | - {1:call} not_a_function{3:(}{4:42}{3:^)} | - {5:~ }|*4 + {15:call} {25:bufnr}{16:(}{26:'%'}{16:)} | + {15:call} {25:nvim_input}{16:(}{26:'typing...'}{16:)} | + {15:call} not_a_function{16:(}{26:42}{16:^)} | + {1:~ }|*4 | ]]) end) diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua index 0c812d968e..2a4835f7e1 100644 --- a/test/functional/vimscript/eval_spec.lua +++ b/test/functional/vimscript/eval_spec.lua @@ -25,8 +25,6 @@ local command = n.command local write_file = t.write_file local api = n.api local sleep = vim.uv.sleep -local matches = t.matches -local pcall_err = t.pcall_err local assert_alive = n.assert_alive local poke_eventloop = n.poke_eventloop local feed = n.feed @@ -189,12 +187,6 @@ describe('uncaught exception', function() it('multiline exception remains multiline #25350', function() local screen = Screen.new(80, 11) - screen:set_default_attr_ids({ - [1] = { bold = true, reverse = true }, -- MsgSeparator - [2] = { foreground = Screen.colors.White, background = Screen.colors.Red }, -- ErrorMsg - [3] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg - }) - screen:attach() exec_lua([[ function _G.Oops() error("oops") @@ -203,17 +195,17 @@ describe('uncaught exception', function() feed(':try\rlua _G.Oops()\rendtry\r') screen:expect { grid = [[ - {1: }| + {3: }| :try | : lua _G.Oops() | : endtry | - {2:Error detected while processing :} | - {2:E5108: Error executing lua [string "<nvim>"]:2: oops} | - {2:stack traceback:} | - {2: [C]: in function 'error'} | - {2: [string "<nvim>"]:2: in function 'Oops'} | - {2: [string ":lua"]:1: in main chunk} | - {3:Press ENTER or type command to continue}^ | + {9:Error detected while processing :} | + {9:E5108: Error executing lua [string "<nvim>"]:2: oops} | + {9:stack traceback:} | + {9: [C]: in function 'error'} | + {9: [string "<nvim>"]:2: in function 'Oops'} | + {9: [string ":lua"]:1: in main chunk} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -233,74 +225,6 @@ describe('listing functions using :function', function() exec_capture(('function <lambda>%s'):format(num)) ) end) - - 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, - [=[ - 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 Func3') - end - end) - - vim.cmd('function') - - vim.ui_detach(ns) - ]=] - ) - ) - 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() diff --git a/test/functional/vimscript/execute_spec.lua b/test/functional/vimscript/execute_spec.lua index 8caaea39a7..2404538e77 100644 --- a/test/functional/vimscript/execute_spec.lua +++ b/test/functional/vimscript/execute_spec.lua @@ -114,7 +114,6 @@ describe('execute()', function() it('does not corrupt the command display #5422', function() local screen = Screen.new(70, 7) - screen:attach() feed(':echo execute("hi ErrorMsg")<CR>') screen:expect( [[ @@ -136,7 +135,6 @@ describe('execute()', function() it('places cursor correctly #6035', function() local screen = Screen.new(40, 6) - screen:attach() source([=[ " test 1: non-silenced output goes as usual function! Test1() @@ -263,7 +261,6 @@ describe('execute()', function() describe('{silent} argument', function() it('captures & displays output for ""', function() local screen = Screen.new(40, 5) - screen:attach() command('let g:mes = execute("echon 42", "")') screen:expect([[ ^ | @@ -287,7 +284,6 @@ describe('execute()', function() it('captures but does not display output for "silent"', function() local screen = Screen.new(40, 5) - screen:attach() command('let g:mes = execute("echon 42")') screen:expect([[ ^ | diff --git a/test/functional/vimscript/has_spec.lua b/test/functional/vimscript/has_spec.lua index 1d2187be6b..ff90edfe30 100644 --- a/test/functional/vimscript/has_spec.lua +++ b/test/functional/vimscript/has_spec.lua @@ -4,6 +4,7 @@ local Screen = require('test.functional.ui.screen') local clear = n.clear local connect = n.connect +local get_session = n.get_session local eq = t.eq local fn = n.fn local is_os = t.is_os @@ -74,12 +75,12 @@ describe('has()', function() it('"gui_running"', function() eq(0, fn.has('gui_running')) - local tui = Screen.new(50, 15) + local tui_session = get_session() local gui_session = connect(fn.serverstart()) - local gui = Screen.new(50, 15) eq(0, fn.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) + local tui = Screen.new(50, 5, { rgb = true, stdin_tty = true, stdout_tty = true }, tui_session) + eq(0, fn.has('gui_running')) + local gui = Screen.new(50, 15, { ext_multigrid = true, rgb = true }, gui_session) eq(1, fn.has('gui_running')) tui:detach() eq(1, fn.has('gui_running')) diff --git a/test/functional/vimscript/input_spec.lua b/test/functional/vimscript/input_spec.lua index 0b774404eb..1995b033b9 100644 --- a/test/functional/vimscript/input_spec.lua +++ b/test/functional/vimscript/input_spec.lua @@ -17,7 +17,6 @@ local screen before_each(function() clear() screen = Screen.new(25, 5) - screen:attach() source([[ hi Test ctermfg=Red guifg=Red term=bold function CustomCompl(...) diff --git a/test/functional/vimscript/match_functions_spec.lua b/test/functional/vimscript/match_functions_spec.lua index 87c57f1c15..46c876da99 100644 --- a/test/functional/vimscript/match_functions_spec.lua +++ b/test/functional/vimscript/match_functions_spec.lua @@ -174,7 +174,6 @@ describe('matchaddpos()', function() end) it('works with zero length', function() local screen = Screen.new(40, 5) - screen:attach() fn.setline(1, 'abcdef') command('hi PreProc guifg=Red') eq(4, fn.matchaddpos('PreProc', { { 1, 2, 0 } }, 3, 4)) diff --git a/test/functional/vimscript/system_spec.lua b/test/functional/vimscript/system_spec.lua index 792e4c46c3..b5c4972d7b 100644 --- a/test/functional/vimscript/system_spec.lua +++ b/test/functional/vimscript/system_spec.lua @@ -132,7 +132,6 @@ describe('system()', function() before_each(function() screen = Screen.new() - screen:attach() end) if is_os('win') then @@ -430,11 +429,6 @@ describe('systemlist()', function() before_each(function() screen = Screen.new() - screen:attach() - end) - - after_each(function() - screen:detach() end) it('`echo` and waits for its return', function() @@ -567,7 +561,6 @@ describe('shell :!', function() it(':{range}! with powershell filter/redirect #16271 #19250', function() local screen = Screen.new(500, 8) - screen:attach() local found = n.set_shell_powershell(true) insert([[ 3 @@ -598,7 +591,6 @@ describe('shell :!', function() it(':{range}! without redirecting to buffer', function() local screen = Screen.new(500, 10) - screen:attach() insert([[ 3 1 diff --git a/test/functional/vimscript/timer_spec.lua b/test/functional/vimscript/timer_spec.lua index f075e382bc..d1b8bfe5d9 100644 --- a/test/functional/vimscript/timer_spec.lua +++ b/test/functional/vimscript/timer_spec.lua @@ -108,10 +108,6 @@ describe('timers', function() it('can invoke redraw in blocking getchar() call', function() local screen = Screen.new(40, 6) - screen:attach() - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, - }) api.nvim_buf_set_lines(0, 0, -1, true, { 'ITEM 1', 'ITEM 2' }) source([[ @@ -228,8 +224,6 @@ describe('timers', function() it("doesn't mess up the cmdline", function() local screen = Screen.new(40, 6) - screen:attach() - screen:set_default_attr_ids({ [0] = { bold = true, foreground = 255 } }) source([[ let g:val = 0 func! MyHandler(timer) @@ -247,7 +241,7 @@ describe('timers', function() feed(':good') screen:expect([[ | - {0:~ }|*4 + {1:~ }|*4 :good^ | ]]) command('let g:val = 1') @@ -267,7 +261,6 @@ describe('timers', function() it('can be triggered after an empty string <expr> mapping #17257', function() local screen = Screen.new(40, 6) - screen:attach() command([=[imap <expr> <F2> [timer_start(0, { _ -> execute("throw 'x'", "") }), ''][-1]]=]) feed('i<F2>') screen:expect({ any = 'E605: Exception not caught: x' }) diff --git a/test/old/testdir/Makefile b/test/old/testdir/Makefile index 20272a24c7..d73571f463 100644 --- a/test/old/testdir/Makefile +++ b/test/old/testdir/Makefile @@ -55,6 +55,8 @@ else endif endif +default: nongui + nongui: nolog $(FIXFF) newtests report .gdbinit: @@ -112,6 +114,7 @@ CLEAN_FILES := *.out \ *.rej \ *.orig \ *.tlog \ + opt_test.vim \ test_result.log \ $(CLEANUP_FILES) \ $(RM_ON_RUN) \ @@ -151,6 +154,18 @@ newtests: newtestssilent newtestssilent: $(NEW_TESTS_RES) +GEN_OPT_DEPS = gen_opt_test.vim ../../../src/nvim/options.lua ../../../runtime/doc/options.txt + +opt_test.vim: $(GEN_OPT_DEPS) + $(NVIM_PRG) -e -s -u NONE $(NO_INITS) -S $(GEN_OPT_DEPS) + @if test -f test.log; then \ + cat test.log; \ + exit 1; \ + fi + +# Explicit dependencies. +test_options_all.res: opt_test.vim + %.res: %.vim .gdbinit @echo "[OLDTEST] Running" $* @rm -rf $*.failed test.ok $(RM_ON_RUN) diff --git a/test/old/testdir/gen_opt_test.vim b/test/old/testdir/gen_opt_test.vim new file mode 100644 index 0000000000..be5a7e6ee4 --- /dev/null +++ b/test/old/testdir/gen_opt_test.vim @@ -0,0 +1,507 @@ +" Script to generate test/old/testdir/opt_test.vim from src/nvim/options.lua +" and runtime/doc/options.txt + +set cpo&vim + +" Only do this when build with the +eval feature. +if 1 + +try + +set nomore + +const K_KENTER = -16715 + +" Get global-local options. +" "key" is full-name of the option. +" "value" is the local value to switch back to the global value. +b options.txt +call cursor(1, 1) +let global_locals = {} +while search("^'[^']*'.*\\n.*|global-local", 'W') + let fullname = getline('.')->matchstr("^'\\zs[^']*") + let global_locals[fullname] = '' +endwhile +call extend(global_locals, #{ + \ scrolloff: -1, + \ sidescrolloff: -1, + \ undolevels: -123456, + \}) + +" Get local-noglobal options. +" "key" is full-name of the option. +" "value" is no used. +b options.txt +call cursor(1, 1) +let local_noglobals = {} +while search("^'[^']*'.*\\n.*|local-noglobal", 'W') + let fullname = getline('.')->matchstr("^'\\zs[^']*") + let local_noglobals[fullname] = v:true +endwhile + +" Options to skip `setglobal` tests. +" "key" is full-name of the option. +" "value" is the reason. +let skip_setglobal_reasons = #{ + \ iminsert: 'The global value is always overwritten by the local value', + \ imsearch: 'The global value is always overwritten by the local value', + \} + +" Script header. +" The test values contains multibyte characters. +let script = [ + \ '" DO NOT EDIT: Generated with gen_opt_test.vim', + \ '" Used by test_options_all.vim.', + \ '', + \ 'scriptencoding utf-8', + \ ] + +let options = luaeval('loadfile("../../../src/nvim/options.lua")().options') + +" font name that works everywhere (hopefully) +let fontname = has('win32') ? 'fixedsys' : 'fixed' + +" Two lists with values: values that work and values that fail. +" When not listed, "othernum" or "otherstring" is used. +" When both lists are empty, skip tests for the option. +" For boolean options, if non-empty a fixed test will be run, otherwise skipped. +let test_values = { + "\ Nvim-only options + \ 'channel': [[], []], + \ 'inccommand': [['', 'nosplit', 'split'], ['xxx']], + \ 'mousescroll': [['ver:1', 'hor:2', 'ver:1,hor:2', 'hor:1,ver:2'], + \ ['xxx', 'ver:1,xxx', 'hor:2,xxx']], + \ 'redrawdebug': [[''], ['xxx']], + \ 'shada': [['', '''50', '"30'], ['xxx']], + \ 'termpastefilter': [['BS', 'HT', 'FF', 'ESC', 'DEL', 'C0', 'C1', 'C0,C1'], + \ ['xxx', 'C0,C1,xxx']], + \ 'winhighlight': [['', 'a:b', 'a:', 'a:b,c:d'], + \ ['a', ':', ':b', 'a:b:c', 'a:/', '/:b', ',', 'a:b,,', 'a:b,c']], + \ + "\ Options for which Nvim has different allowed values + \ 'backspace': [[2, '', 'indent', 'eol', 'start', 'nostop', + \ 'eol,start', 'indent,eol,nostop'], + \ [-1, 4, 'xxx']], + \ 'buftype': [['', 'nofile', 'nowrite', 'acwrite', 'quickfix', 'help', + \ 'prompt'], + \ ['xxx', 'help,nofile']], + \ 'clipboard': [['', 'unnamed'], ['xxx', '\ze*', 'exclude:\\%(']], + \ 'completeopt': [['', 'menu', 'menuone', 'longest', 'preview', 'popup', + \ 'noinsert', 'noselect', 'fuzzy', 'menu,longest'], + \ ['xxx', 'menu,,,longest,']], + \ 'encoding': [['utf8'], []], + \ 'foldcolumn': [[0, 1, 4, 'auto', 'auto:1', 'auto:9'], [-1, 13, 999]], + \ 'foldlevel': [[0, 100], [-1, '']], + \ 'highlight': [[&highlight], []], + \ 'iminsert': [[0, 1], [-1, 2, 3, 999]], + \ 'imsearch': [[-1, 0, 1], [-2, 2, 3, 999]], + \ 'signcolumn': [['auto', 'no', 'yes', 'number', 'yes:1', 'auto:1-9'], + \ ['', 'xxx', 'no,yes', 'auto:0-9', 'auto:9-1', 'auto:1-@']], + \ 'writedelay': [[0, 100], [-1, '']], + \ + "\ boolean options + \ 'termguicolors': [ + \ has('vtp') && !has('vcon') && !has('gui_running') ? [] : [1], + \ []], + \ + "\ number options + \ 'cmdheight': [[0, 1, 2, 10], [-1]], + \ 'cmdwinheight': [[1, 2, 10], [-1, 0]], + \ 'columns': [[12, 80, 10000], [-1, 0, 10]], + \ 'conceallevel': [[0, 1, 2, 3], [-1, 4, 99]], + "\ 'foldcolumn': [[0, 1, 4, 12], [-1, 13, 999]], + \ 'helpheight': [[0, 10, 100], [-1]], + \ 'history': [[0, 1, 100, 10000], [-1, 10001]], + "\ 'iminsert': [[0, 1, 2], [-1, 3, 999]], + "\ 'imsearch': [[-1, 0, 1, 2], [-2, 3, 999]], + "\ 'imstyle': [[0, 1], [-1, 2, 999]], + \ 'lines': [[2, 24, 1000], [-1, 0, 1]], + \ 'linespace': [[-1, 0, 2, 4, 999], ['']], + \ 'msghistory': [[0, 1, 100, 10000], [-1, 10001]], + \ 'numberwidth': [[1, 4, 8, 10, 11, 20], [-1, 0, 21]], + \ 'regexpengine': [[0, 1, 2], [-1, 3, 999]], + \ 'report': [[0, 1, 2, 9999], [-1]], + \ 'scroll': [[0, 1, 2, 20], [-1, 999]], + \ 'scrolljump': [[-100, -1, 0, 1, 2, 20], [-101, 999]], + \ 'scrolloff': [[0, 1, 8, 999], [-1]], + \ 'shiftwidth': [[0, 1, 8, 999], [-1]], + \ 'sidescroll': [[0, 1, 8, 999], [-1]], + \ 'sidescrolloff': [[0, 1, 8, 999], [-1]], + \ 'tabstop': [[1, 4, 8, 12, 9999], [-1, 0, 10000]], + \ 'textwidth': [[0, 1, 8, 99], [-1]], + \ 'timeoutlen': [[0, 8, 99999], [-1]], + \ 'titlelen': [[0, 1, 8, 9999], [-1]], + \ 'updatecount': [[0, 1, 8, 9999], [-1]], + \ 'updatetime': [[0, 1, 8, 9999], [-1]], + \ 'verbose': [[-1, 0, 1, 8, 9999], ['']], + \ 'wildchar': [[-1, 0, 100, 'x', '^Y', '^@', '<Esc>', '<t_xx>', '<', '^'], + \ ['', 'xxx', '<xxx>', '<t_xxx>', '<Esc', '<t_xx', '<C-C>', + \ '<NL>', '<CR>', K_KENTER]], + \ 'wildcharm': [[-1, 0, 100, 'x', '^Y', '^@', '<Esc>', '<', '^'], + \ ['', 'xxx', '<xxx>', '<t_xxx>', '<Esc', '<t_xx', '<C-C>', + \ '<NL>', '<CR>', K_KENTER]], + \ 'winheight': [[1, 10, 999], [-1, 0]], + \ 'winminheight': [[0, 1], [-1]], + \ 'winminwidth': [[0, 1, 10], [-1]], + \ 'winwidth': [[1, 10, 999], [-1, 0]], + \ + "\ string options + \ 'ambiwidth': [['', 'single', 'double'], ['xxx']], + \ 'background': [['', 'light', 'dark'], ['xxx']], + "\ 'backspace': [[0, 1, 2, 3, '', 'indent', 'eol', 'start', 'nostop', + "\ " 'eol,start', 'indent,eol,nostop'], + "\ " [-1, 4, 'xxx']], + \ 'backupcopy': [['yes', 'no', 'auto'], ['', 'xxx', 'yes,no']], + \ 'backupext': [['xxx'], [&patchmode, '*']], + \ 'belloff': [['', 'all', 'backspace', 'cursor', 'complete', 'copy', + \ 'ctrlg', 'error', 'esc', 'ex', 'hangul', 'insertmode', 'lang', + \ 'mess', 'showmatch', 'operator', 'register', 'shell', 'spell', + \ 'term', 'wildmode', 'copy,error,shell'], + \ ['xxx']], + \ 'breakindentopt': [['', 'min:3', 'shift:4', 'shift:-2', 'sbr', 'list:5', + \ 'list:-1', 'column:10', 'column:-5', 'min:1,sbr,shift:2'], + \ ['xxx', 'min', 'min:x', 'min:-1', 'shift:x', 'sbr:1', 'list:x', + \ 'column:x']], + \ 'browsedir': [['', 'last', 'buffer', 'current', './Xdir\ with\ space'], + \ ['xxx']], + \ 'bufhidden': [['', 'hide', 'unload', 'delete', 'wipe'], + \ ['xxx', 'hide,wipe']], + "\ 'buftype': [['', 'nofile', 'nowrite', 'acwrite', 'quickfix', 'help', + "\ " 'terminal', 'prompt', 'popup'], + "\ " ['xxx', 'help,nofile']], + \ 'casemap': [['', 'internal', 'keepascii', 'internal,keepascii'], + \ ['xxx']], + \ 'cedit': [['', '^Y', '^@', '<Esc>', '<t_xx>'], + \ ['xxx', 'f', '<xxx>', '<t_xxx>', '<Esc', '<t_xx']], + "\ 'clipboard': [['', 'unnamed', 'unnamedplus', 'autoselect', + "\ " 'autoselectplus', 'autoselectml', 'html', 'exclude:vimdisplay', + "\ " 'autoselect,unnamed', 'unnamed,exclude:.*'], + "\ " ['xxx', 'exclude:\\ze*', 'exclude:\\%(']], + \ 'colorcolumn': [['', '8', '+2', '1,+1,+3'], ['xxx', '-a', '1,', '1;']], + \ 'comments': [['', 'b:#', 'b:#,:%'], ['xxx', '-']], + \ 'commentstring': [['', '/*\ %s\ */'], ['xxx']], + \ 'complete': [['', '.', 'w', 'b', 'u', 'U', 'i', 'd', ']', 't', + \ 'k', 'kspell', 'k/tmp/dir\\\ with\\\ space/*', + \ 's', 's/tmp/dir\\\ with\\\ space/*', + \ 'w,b,k/tmp/dir\\\ with\\\ space/*,s'], + \ ['xxx']], + \ 'concealcursor': [['', 'n', 'v', 'i', 'c', 'nvic'], ['xxx']], + "\ 'completeopt': [['', 'menu', 'menuone', 'longest', 'preview', 'popup', + "\ " 'popuphidden', 'noinsert', 'noselect', 'fuzzy', 'menu,longest'], + "\ " ['xxx', 'menu,,,longest,']], + \ 'completeitemalign': [['abbr,kind,menu', 'menu,abbr,kind'], + \ ['', 'xxx', 'abbr', 'abbr,menu', 'abbr,menu,kind,abbr', + \ 'abbr1234,kind,menu']], + "\ 'completepopup': [['', 'height:13', 'width:20', 'highlight:That', + "\ " 'align:item', 'align:menu', 'border:on', 'border:off', + "\ " 'width:10,height:234,highlight:Mine'], + "\ " ['xxx', 'xxx:99', 'height:yes', 'width:no', 'align:xxx', + "\ " 'border:maybe', 'border:1', 'border:']], + \ 'completeslash': [['', 'slash', 'backslash'], ['xxx']], + "\ 'cryptmethod': [['', 'zip'], ['xxx']], + "\ 'cscopequickfix': [['', 's-', 'g-', 'd-', 'c-', 't-', 'e-', 'f-', 'i-', + "\ " 'a-', 's-,c+,e0'], + "\ " ['xxx', 's,g,d']], + \ 'cursorlineopt': [['both', 'line', 'number', 'screenline', + \ 'line,number'], + \ ['', 'xxx', 'line,screenline']], + \ 'debug': [['', 'msg', 'throw', 'beep'], ['xxx']], + \ 'diffopt': [['', 'filler', 'context:0', 'context:999', 'iblank', + \ 'icase', 'iwhite', 'iwhiteall', 'horizontal', 'vertical', + \ 'closeoff', 'hiddenoff', 'foldcolumn:0', 'foldcolumn:12', + \ 'followwrap', 'internal', 'indent-heuristic', 'algorithm:myers', + \ 'algorithm:minimal', 'algorithm:patience', + \ 'algorithm:histogram', 'icase,iwhite'], + \ ['xxx', 'foldcolumn:xxx', 'algorithm:xxx', 'algorithm:']], + \ 'display': [['', 'lastline', 'truncate', 'uhex', 'lastline,uhex'], + \ ['xxx']], + \ 'eadirection': [['', 'both', 'ver', 'hor'], ['xxx', 'ver,hor']], + "\ 'encoding': [['latin1'], ['xxx', '']], + \ 'eventignore': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter'], + \ ['xxx']], + \ 'fileencoding': [['', 'latin1', 'xxx'], []], + \ 'fileformat': [['', 'dos', 'unix', 'mac'], ['xxx']], + \ 'fileformats': [['', 'dos', 'dos,unix'], ['xxx']], + \ 'fillchars': [['', 'stl:x', 'stlnc:x', 'vert:x', 'fold:x', 'foldopen:x', + \ 'foldclose:x', 'foldsep:x', 'diff:x', 'eob:x', 'lastline:x', + \ 'stl:\ ,vert:\|,fold:\\,diff:x'], + \ ['xxx', 'vert:']], + \ 'foldclose': [['', 'all'], ['xxx']], + \ 'foldmethod': [['manual', 'indent', 'expr', 'marker', 'syntax', 'diff'], + \ ['', 'xxx', 'expr,diff']], + \ 'foldopen': [['', 'all', 'block', 'hor', 'insert', 'jump', 'mark', + \ 'percent', 'quickfix', 'search', 'tag', 'undo', 'hor,jump'], + \ ['xxx']], + \ 'foldmarker': [['((,))'], ['', 'xxx', '{{{,']], + \ 'formatoptions': [['', 't', 'c', 'r', 'o', '/', 'q', 'w', 'a', 'n', '2', + \ 'v', 'b', 'l', 'm', 'M', 'B', '1', ']', 'j', 'p', 'vt', 'v,t'], + \ ['xxx']], + \ 'guicursor': [['', 'n:block-Cursor'], ['xxx']], + \ 'guifont': [['', fontname], []], + \ 'guifontwide': [['', fontname], []], + "\ 'guifontset': [['', fontname], []], + \ 'guioptions': [['', '!', 'a', 'P', 'A', 'c', 'd', 'e', 'f', 'i', 'm', + \ 'M', 'g', 't', 'T', 'r', 'R', 'l', 'L', 'b', 'h', 'v', 'p', 'F', + \ 'k', '!abvR'], + \ ['xxx', 'a,b']], + \ 'helplang': [['', 'de', 'de,it'], ['xxx']], + "\ 'highlight': [['', 'e:Error'], ['xxx']], + "\ 'imactivatekey': [['', 'S-space'], ['xxx']], + \ 'isfname': [['', '@', '@,48-52'], ['xxx', '@48']], + \ 'isident': [['', '@', '@,48-52'], ['xxx', '@48']], + \ 'iskeyword': [['', '@', '@,48-52'], ['xxx', '@48']], + \ 'isprint': [['', '@', '@,48-52'], ['xxx', '@48']], + \ 'jumpoptions': [['', 'stack'], ['xxx']], + \ 'keymap': [['', 'accents'], ['/']], + \ 'keymodel': [['', 'startsel', 'stopsel', 'startsel,stopsel'], ['xxx']], + "\ 'keyprotocol': [['', 'xxx:none', 'yyy:mok2', 'zzz:kitty'], + "\ " ['xxx', ':none', 'xxx:', 'x:non', 'y:mok3', 'z:kittty']], + \ 'langmap': [['', 'xX', 'aA,bB'], ['xxx']], + \ 'lispoptions': [['', 'expr:0', 'expr:1'], ['xxx', 'expr:x', 'expr:']], + \ 'listchars': [['', 'eol:x', 'tab:xy', 'tab:xyz', 'space:x', + \ 'multispace:xxxy', 'lead:x', 'leadmultispace:xxxy', 'trail:x', + \ 'extends:x', 'precedes:x', 'conceal:x', 'nbsp:x', 'eol:\\x24', + \ 'eol:\\u21b5', 'eol:\\U000021b5', 'eol:x,space:y'], + \ ['xxx', 'eol:']], + \ 'matchpairs': [['', '(:)', '(:),<:>'], ['xxx']], + \ 'mkspellmem': [['10000,100,12'], ['', 'xxx', '10000,100']], + \ 'mouse': [['', 'n', 'v', 'i', 'c', 'h', 'a', 'r', 'nvi'], + \ ['xxx', 'n,v,i']], + \ 'mousemodel': [['', 'extend', 'popup', 'popup_setpos'], ['xxx']], + \ 'mouseshape': [['', 'n:arrow'], ['xxx']], + \ 'nrformats': [['', 'alpha', 'octal', 'hex', 'bin', 'unsigned', 'blank', + \ 'alpha,hex,bin'], + \ ['xxx']], + \ 'patchmode': [['', 'xxx', '.x'], [&backupext, '*']], + "\ 'previewpopup': [['', 'height:13', 'width:20', 'highlight:That', + "\ " 'align:item', 'align:menu', 'border:on', 'border:off', + "\ " 'width:10,height:234,highlight:Mine'], + "\ " ['xxx', 'xxx:99', 'height:yes', 'width:no', 'align:xxx', + "\ " 'border:maybe', 'border:1', 'border:']], + "\ 'printmbfont': [['', 'r:some', 'b:some', 'i:some', 'o:some', 'c:yes', + "\ " 'c:no', 'a:yes', 'a:no', 'b:Bold,c:yes'], + "\ " ['xxx', 'xxx,c:yes', 'xxx:', 'xxx:,c:yes']], + "\ 'printoptions': [['', 'header:0', 'left:10pc,top:5pc'], + "\ " ['xxx', 'header:-1']], + \ 'scrollopt': [['', 'ver', 'hor', 'jump', 'ver,hor'], ['xxx']], + "\ 'renderoptions': [[''], ['xxx']], + \ 'rightleftcmd': [['search'], ['xxx']], + \ 'rulerformat': [['', 'xxx'], ['%-', '%(', '%15(%%']], + \ 'selection': [['old', 'inclusive', 'exclusive'], ['', 'xxx']], + \ 'selectmode': [['', 'mouse', 'key', 'cmd', 'key,cmd'], ['xxx']], + \ 'sessionoptions': [['', 'blank', 'curdir', 'sesdir', + \ 'help,options,slash'], + \ ['xxx', 'curdir,sesdir']], + \ 'showcmdloc': [['', 'last', 'statusline', 'tabline'], ['xxx']], + "\ 'signcolumn': [['', 'auto', 'no', 'yes', 'number'], ['xxx', 'no,yes']], + \ 'spellfile': [['', 'file.en.add', 'xxx.en.add,yyy.gb.add,zzz.ja.add', + \ '/tmp/dir\ with\ space/en.utf-8.add', + \ '/tmp/dir\\,with\\,comma/en.utf-8.add'], + \ ['xxx', '/tmp/file', '/tmp/dir*with:invalid?char/file.en.add', + \ ',file.en.add', 'xxx,yyy.en.add', 'xxx.en.add,yyy,zzz.ja.add']], + \ 'spelllang': [['', 'xxx', 'sr@latin'], ['not&lang', "that\\\rthere"]], + \ 'spelloptions': [['', 'camel'], ['xxx']], + \ 'spellsuggest': [['', 'best', 'double', 'fast', '100', 'timeout:100', + \ 'timeout:-1', 'file:/tmp/file', 'expr:Func()', 'double,33'], + \ ['xxx', '-1', 'timeout:', 'best,double', 'double,fast']], + \ 'splitkeep': [['', 'cursor', 'screen', 'topline'], ['xxx']], + \ 'statusline': [['', 'xxx'], ['%$', '%{', '%{%', '%{%}', '%(', '%)']], + "\ 'swapsync': [['', 'sync', 'fsync'], ['xxx']], + \ 'switchbuf': [['', 'useopen', 'usetab', 'split', 'vsplit', 'newtab', + \ 'uselast', 'split,newtab'], + \ ['xxx']], + \ 'tabclose': [['', 'left', 'uselast', 'left,uselast'], ['xxx']], + \ 'tabline': [['', 'xxx'], ['%$', '%{', '%{%', '%{%}', '%(', '%)']], + \ 'tagcase': [['followic', 'followscs', 'ignore', 'match', 'smart'], + \ ['', 'xxx', 'smart,match']], + \ 'termencoding': [has('gui_gtk') ? [] : ['', 'utf-8'], ['xxx']], + "\ 'termwinkey': [['', 'f', '^Y', '^@', '<Esc>', '<t_xx>', "\u3042", '<', + "\ " '^'], + "\ " ['<xxx>', '<t_xxx>', '<Esc', '<t_xx']], + "\ 'termwinsize': [['', '24x80', '0x80', '32x0', '0x0'], + "\ " ['xxx', '80', '8ax9', '24x80b']], + "\ 'termwintype': [['', 'winpty', 'conpty'], ['xxx']], + "\ 'titlestring': [['', 'xxx', '%('], []], + "\ 'toolbar': [['', 'icons', 'text', 'horiz', 'tooltips', 'icons,text'], + "\ " ['xxx']], + "\ 'toolbariconsize': [['', 'tiny', 'small', 'medium', 'large', 'huge', + "\ " 'giant'], + "\ " ['xxx']], + "\ 'ttymouse': [['', 'xterm'], ['xxx']], + \ 'varsofttabstop': [['8', '4,8,16,32'], ['xxx', '-1', '4,-1,20', '1,']], + \ 'vartabstop': [['8', '4,8,16,32'], ['xxx', '-1', '4,-1,20', '1,']], + \ 'verbosefile': [['', './Xfile'], []], + \ 'viewoptions': [['', 'cursor', 'folds', 'options', 'localoptions', + \ 'slash', 'unix', 'curdir', 'unix,slash'], ['xxx']], + \ 'viminfo': [['', '''50', '"30', "'100,<50,s10,h"], ['xxx', 'h']], + \ 'virtualedit': [['', 'block', 'insert', 'all', 'onemore', 'none', + \ 'NONE', 'all,block'], + \ ['xxx']], + \ 'whichwrap': [['', 'b', 's', 'h', 'l', '<', '>', '~', '[', ']', 'b,s', + \ 'bs'], + \ ['xxx']], + \ 'wildmode': [['', 'full', 'longest', 'list', 'lastused', 'list:full', + \ 'full,longest', 'full,full,full,full'], + \ ['xxx', 'a4', 'full,full,full,full,full']], + \ 'wildoptions': [['', 'tagfile', 'pum', 'fuzzy'], ['xxx']], + \ 'winaltkeys': [['no', 'yes', 'menu'], ['', 'xxx']], + \ + "\ skipped options + "\ 'luadll': [[], []], + "\ 'perldll': [[], []], + "\ 'pythondll': [[], []], + "\ 'pythonthreedll': [[], []], + \ 'pyxversion': [[], []], + "\ 'rubydll': [[], []], + "\ 'tcldll': [[], []], + \ 'term': [[], []], + \ 'ttytype': [[], []], + \ + "\ default behaviours + \ 'othernum': [[-1, 0, 100], ['']], + \ 'otherstring': [['', 'xxx'], []], + \} + +" Two lists with values: values that pre- and post-processing in test. +" Clear out t_WS: we don't want to resize the actual terminal. +let test_prepost = { + \ 'browsedir': [["call mkdir('Xdir with space', 'D')"], []], + \ 'columns': [[ + \ 'set t_WS=', + \ 'let save_columns = &columns' + \ ], [ + \ 'let &columns = save_columns', + \ 'set t_WS&' + \ ]], + \ 'lines': [[ + \ 'set t_WS=', + \ 'let save_lines = &lines' + \ ], [ + \ 'let &lines = save_lines', + \ 'set t_WS&' + \ ]], + \ 'verbosefile': [[], ['call delete("Xfile")']], + \} + +const invalid_options = test_values->keys() + \->filter({-> v:val !~# '^other' && !exists($"&{v:val}")}) +if !empty(invalid_options) + throw $"Invalid option name in test_values: '{invalid_options->join("', '")}'" +endif + +for option in options + let fullname = option.full_name + let shortname = get(option, 'abbreviation', fullname) + + if !exists('+' .. fullname) + continue + endif + + let [valid_values, invalid_values] = test_values[ + \ has_key(test_values, fullname) ? fullname + \ : option.type == 'number' ? 'othernum' + \ : 'otherstring'] + + if empty(valid_values) && empty(invalid_values) + continue + endif + + call add(script, $"func Test_opt_set_{fullname}()") + call add(script, $"if exists('+{fullname}') && execute('set!') =~# '\\n..{fullname}\\([=\\n]\\|$\\)'") + call add(script, $"let l:saved = [&g:{fullname}, &l:{fullname}]") + call add(script, 'endif') + + let [pre_processing, post_processing] = get(test_prepost, fullname, [[], []]) + let script += pre_processing + + if option.type == 'boolean' + for opt in [fullname, shortname] + for cmd in ['set', 'setlocal', 'setglobal'] + call add(script, $'{cmd} {opt}') + call add(script, $'{cmd} no{opt}') + call add(script, $'{cmd} inv{opt}') + call add(script, $'{cmd} {opt}!') + endfor + endfor + else " P_NUM || P_STRING + " Normal tests + for opt in [fullname, shortname] + for cmd in ['set', 'setlocal', 'setglobal'] + for val in valid_values + if local_noglobals->has_key(fullname) && cmd ==# 'setglobal' + " Skip `:setglobal {option}={val}` for local-noglobal option. + " It has no effect. + let pre = '" Skip local-noglobal: ' + else + let pre = '' + endif + call add(script, $'{pre}{cmd} {opt}={val}') + endfor + endfor + " Testing to clear the local value and switch back to the global value. + if global_locals->has_key(fullname) + let switchback_val = global_locals[fullname] + call add(script, $'setlocal {opt}={switchback_val}') + call add(script, $'call assert_equal(&g:{fullname}, &{fullname})') + endif + endfor + + " Failure tests + " Setting an option can only fail when it's implemented. + call add(script, $"if exists('+{fullname}')") + for opt in [fullname, shortname] + for cmd in ['set', 'setlocal', 'setglobal'] + for val in invalid_values + if val is# global_locals->get(fullname, {}) && cmd ==# 'setlocal' + " Skip setlocal switchback-value to global-local option. It will + " not result in failure. + let pre = '" Skip global-local: ' + elseif local_noglobals->has_key(fullname) && cmd ==# 'setglobal' + " Skip setglobal to local-noglobal option. It will not result in + " failure. + let pre = '" Skip local-noglobal: ' + elseif skip_setglobal_reasons->has_key(fullname) && cmd ==# 'setglobal' + " Skip setglobal to reasoned option. It will not result in failure. + let reason = skip_setglobal_reasons[fullname] + let pre = $'" Skip {reason}: ' + else + let pre = '' + endif + let cmdline = $'{cmd} {opt}={val}' + call add(script, $"{pre}silent! call assert_fails({string(cmdline)})") + endfor + endfor + endfor + call add(script, "endif") + endif + + " Cannot change 'termencoding' in GTK + if fullname != 'termencoding' || !has('gui_gtk') + call add(script, $'set {fullname}&') + call add(script, $'set {shortname}&') + call add(script, $"if exists('l:saved')") + call add(script, $"let [&g:{fullname}, &l:{fullname}] = l:saved") + call add(script, 'endif') + endif + + let script += post_processing + call add(script, 'endfunc') +endfor + +call writefile(script, 'opt_test.vim') + +" Write error messages if error occurs. +catch + " Append errors to test.log + let error = $'Error: {v:exception} in {v:throwpoint}' + echo error + split test.log + call append('$', error) + write +endtry + +endif + +qa! + +" vim:sw=2:ts=8:noet:nosta: diff --git a/test/old/testdir/runtest.vim b/test/old/testdir/runtest.vim index e05a78e9ca..058635c332 100644 --- a/test/old/testdir/runtest.vim +++ b/test/old/testdir/runtest.vim @@ -174,10 +174,6 @@ func GetAllocId(name) return lnum - top - 1 endfunc -if has('reltime') - let g:func_start = reltime() -endif - " Get the list of swap files in the current directory. func s:GetSwapFileList() let save_dir = &directory @@ -567,6 +563,16 @@ for g:testfunc in sort(s:tests) " A test can set g:test_is_flaky to retry running the test. let g:test_is_flaky = 0 + " A test can set g:max_run_nr to change the max retry count. + let g:max_run_nr = 5 + if has('mac') + let g:max_run_nr = 10 + endif + + " By default, give up if the same error occurs. A test can set + " g:giveup_same_error to 0 to not give up on the same error and keep trying. + let g:giveup_same_error = 1 + let starttime = strftime("%H:%M:%S") call RunTheTest(g:testfunc) @@ -582,10 +588,15 @@ for g:testfunc in sort(s:tests) call extend(s:messages, v:errors) let endtime = strftime("%H:%M:%S") - call add(total_errors, $'Run {g:run_nr}, {starttime} - {endtime}:') + if has('reltime') + let suffix = $' in{reltimestr(reltime(g:func_start))} seconds' + else + let suffix = '' + endif + call add(total_errors, $'Run {g:run_nr}, {starttime} - {endtime}{suffix}:') call extend(total_errors, v:errors) - if g:run_nr >= 5 || prev_error == v:errors[0] + if g:run_nr >= g:max_run_nr || g:giveup_same_error && prev_error == v:errors[0] call add(total_errors, 'Flaky test failed too often, giving up') let v:errors = total_errors break @@ -596,7 +607,8 @@ for g:testfunc in sort(s:tests) " Flakiness is often caused by the system being very busy. Sleep a " couple of seconds to have a higher chance of succeeding the second " time. - sleep 2 + let delay = g:run_nr * 2 + exe 'sleep' delay let prev_error = v:errors[0] let v:errors = [] diff --git a/test/old/testdir/script_util.vim b/test/old/testdir/script_util.vim index 28d6a621d6..a300b670c7 100644 --- a/test/old/testdir/script_util.vim +++ b/test/old/testdir/script_util.vim @@ -1,4 +1,4 @@ -" Functions shared by the tests for Vim Script +" Functions shared by the tests for Vim script " Commands to track the execution path of a script com! XpathINIT let g:Xpath = '' diff --git a/test/old/testdir/shared.vim b/test/old/testdir/shared.vim index e7a5f471e7..bb1a6c8f5b 100644 --- a/test/old/testdir/shared.vim +++ b/test/old/testdir/shared.vim @@ -35,12 +35,20 @@ func PythonProg() if has('unix') " We also need the job feature or the pkill command to make sure the server " can be stopped. - if !(executable('python') && (has('job') || executable('pkill'))) + if !(has('job') || executable('pkill')) return '' endif - let s:python = 'python' + if executable('python3') + let s:python = 'python3' + elseif executable('python') + let s:python = 'python' + else + return '' + end elseif has('win32') " Use Python Launcher for Windows (py.exe) if available. + " NOTE: if you get a "Python was not found" error, disable the Python + " shortcuts in "Windows menu / Settings / Manage App Execution Aliases". if executable('py.exe') let s:python = 'py.exe' elseif executable('python.exe') @@ -64,7 +72,7 @@ func RunCommand(cmd) let job = job_start(a:cmd, {"stoponexit": "hup"}) call job_setoptions(job, {"stoponexit": "kill"}) elseif has('win32') - exe 'silent !start cmd /c start "test_channel" ' . a:cmd + exe 'silent !start cmd /D /c start "test_channel" ' . a:cmd else exe 'silent !' . a:cmd . '&' endif diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index 9d06ebb2be..64599c869a 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -88,9 +88,9 @@ if has('timers') " CursorHoldI event. let g:triggered = 0 au CursorHoldI * let g:triggered += 1 - set updatetime=500 - call job_start(has('win32') ? 'cmd /c echo:' : 'echo', - \ {'exit_cb': {-> timer_start(1000, 'ExitInsertMode')}}) + set updatetime=100 + call job_start(has('win32') ? 'cmd /D /c echo:' : 'echo', + \ {'exit_cb': {-> timer_start(200, 'ExitInsertMode')}}) call feedkeys('a', 'x!') call assert_equal(1, g:triggered) unlet g:triggered @@ -2003,7 +2003,10 @@ func Test_Cmdline() au! CmdlineLeave let save_shellslash = &shellslash - set noshellslash + " Nvim doesn't allow setting value of a hidden option to non-default value + if exists('+shellslash') + set noshellslash + endif au! CmdlineEnter / let g:entered = expand('<afile>') au! CmdlineLeave / let g:left = expand('<afile>') let g:entered = 0 diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index 9f25a42c38..290af4a4ca 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -271,6 +271,12 @@ func Test_changing_cmdheight() let lines =<< trim END set cmdheight=1 laststatus=2 + func EchoOne() + set laststatus=2 cmdheight=1 + echo 'foo' + echo 'bar' + set cmdheight=2 + endfunc func EchoTwo() set laststatus=2 set cmdheight=5 @@ -306,6 +312,10 @@ func Test_changing_cmdheight() call term_sendkeys(buf, ":call EchoTwo()\<CR>") call VerifyScreenDump(buf, 'Test_changing_cmdheight_6', {}) + " increasing 'cmdheight' doesn't clear the messages that need hit-enter + call term_sendkeys(buf, ":call EchoOne()\<CR>") + call VerifyScreenDump(buf, 'Test_changing_cmdheight_7', {}) + " clean up call StopVimInTerminal(buf) endfunc @@ -727,8 +737,8 @@ func Test_fullcommand() \ ':5s': 'substitute', \ "'<,'>s": 'substitute', \ ":'<,'>s": 'substitute', - \ 'CheckUni': 'CheckUnix', - \ 'CheckUnix': 'CheckUnix', + \ 'CheckLin': 'CheckLinux', + \ 'CheckLinux': 'CheckLinux', \ } for [in, want] in items(tests) @@ -1012,8 +1022,7 @@ func Test_cmdline_complete_user_names() call feedkeys(':e ~' . first_letter . "\<c-a>\<c-B>\"\<cr>", 'tx') call assert_match('^"e \~.*\<' . whoami . '\>', @:) endif - endif - if has('win32') + elseif has('win32') " Just in case: check that the system has an Administrator account. let names = system('net user') if names =~ 'Administrator' @@ -1022,14 +1031,27 @@ func Test_cmdline_complete_user_names() call feedkeys(':e ~A' . "\<c-a>\<c-B>\"\<cr>", 'tx') call assert_match('^"e \~.*Administrator', @:) endif + else + throw 'Skipped: does not work on this platform' endif endfunc +func Test_cmdline_complete_shellcmdline() + CheckExecutable whoami + command -nargs=1 -complete=shellcmdline MyCmd + + call feedkeys(":MyCmd whoam\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_match('^".*\<whoami\>', @:) + let l = getcompletion('whoam', 'shellcmdline') + call assert_match('\<whoami\>', join(l, ' ')) + + delcommand MyCmd +endfunc + func Test_cmdline_complete_bang() - if executable('whoami') - call feedkeys(":!whoam\<C-A>\<C-B>\"\<CR>", 'tx') - call assert_match('^".*\<whoami\>', @:) - endif + CheckExecutable whoami + call feedkeys(":!whoam\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_match('^".*\<whoami\>', @:) endfunc func Test_cmdline_complete_languages() @@ -2307,6 +2329,7 @@ endfunc " Test for 'imcmdline' and 'imsearch' " This test doesn't actually test the input method functionality. func Test_cmdline_inputmethod() + throw 'Skipped: Nvim does not allow setting the value of a hidden option' new call setline(1, ['', 'abc', '']) set imcmdline @@ -3800,6 +3823,60 @@ func Test_cmdline_complete_substitute_short() endfor endfunc +" Test for shellcmdline command argument completion +func Test_cmdline_complete_shellcmdline_argument() + command -nargs=+ -complete=shellcmdline MyCmd + + set wildoptions=fuzzy + + call feedkeys(":MyCmd vim test_cmdline.\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"MyCmd vim test_cmdline.vim', @:) + call assert_equal(['test_cmdline.vim'], + \ getcompletion('vim test_cmdline.', 'shellcmdline')) + + call feedkeys(":MyCmd vim nonexistentfile\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"MyCmd vim nonexistentfile', @:) + call assert_equal([], + \ getcompletion('vim nonexistentfile', 'shellcmdline')) + + let compl1 = getcompletion('', 'file')[0] + let compl2 = getcompletion('', 'file')[1] + call feedkeys(":MyCmd vim \<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"MyCmd vim ' .. compl1, @:) + + call feedkeys(":MyCmd vim \<Tab> \<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl1, @:) + + let compl = getcompletion('', 'file')[1] + call feedkeys(":MyCmd vim \<Tab> \<Tab>\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl2, @:) + + set wildoptions& + call feedkeys(":MyCmd vim test_cmdline.\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"MyCmd vim test_cmdline.vim', @:) + call assert_equal(['test_cmdline.vim'], + \ getcompletion('vim test_cmdline.', 'shellcmdline')) + + call feedkeys(":MyCmd vim nonexistentfile\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"MyCmd vim nonexistentfile', @:) + call assert_equal([], + \ getcompletion('vim nonexistentfile', 'shellcmdline')) + + let compl1 = getcompletion('', 'file')[0] + let compl2 = getcompletion('', 'file')[1] + call feedkeys(":MyCmd vim \<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"MyCmd vim ' .. compl1, @:) + + call feedkeys(":MyCmd vim \<Tab> \<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl1, @:) + + let compl = getcompletion('', 'file')[1] + call feedkeys(":MyCmd vim \<Tab> \<Tab>\<Tab>\<C-B>\"\<CR>", 'xt') + call assert_equal('"MyCmd vim ' .. compl1 .. ' ' .. compl2, @:) + + delcommand MyCmd +endfunc + " Test for :! shell command argument completion func Test_cmdline_complete_bang_cmd_argument() set wildoptions=fuzzy @@ -3811,30 +3888,32 @@ func Test_cmdline_complete_bang_cmd_argument() endfunc func Call_cmd_funcs() - return [getcmdpos(), getcmdscreenpos(), getcmdcompltype()] + return [getcmdpos(), getcmdscreenpos(), getcmdcompltype(), getcmdcomplpat()] endfunc func Test_screenpos_and_completion() call assert_equal(0, getcmdpos()) call assert_equal(0, getcmdscreenpos()) call assert_equal('', getcmdcompltype()) + call assert_equal('', getcmdcomplpat()) cnoremap <expr> <F2> string(Call_cmd_funcs()) call feedkeys(":let a\<F2>\<C-B>\"\<CR>", "xt") - call assert_equal("\"let a[6, 7, 'var']", @:) + call assert_equal("\"let a[6, 7, 'var', 'a']", @:) call feedkeys(":quit \<F2>\<C-B>\"\<CR>", "xt") - call assert_equal("\"quit [6, 7, '']", @:) + call assert_equal("\"quit [6, 7, '', '']", @:) call feedkeys(":nosuchcommand \<F2>\<C-B>\"\<CR>", "xt") - call assert_equal("\"nosuchcommand [15, 16, '']", @:) + call assert_equal("\"nosuchcommand [15, 16, '', '']", @:) - " Check that getcmdcompltype() doesn't interfere with cmdline completion. + " Check that getcmdcompltype() and getcmdcomplpat() don't interfere with + " cmdline completion. let g:results = [] cnoremap <F2> <Cmd>let g:results += [[getcmdline()] + Call_cmd_funcs()]<CR> call feedkeys(":sign un\<Tab>\<F2>\<Tab>\<F2>\<Tab>\<F2>\<C-C>", "xt") call assert_equal([ - \ ['sign undefine', 14, 15, 'sign'], - \ ['sign unplace', 13, 14, 'sign'], - \ ['sign un', 8, 9, 'sign']], g:results) + \ ['sign undefine', 14, 15, 'sign', 'undefine'], + \ ['sign unplace', 13, 14, 'sign', 'unplace'], + \ ['sign un', 8, 9, 'sign', 'un']], g:results) unlet g:results cunmap <F2> @@ -4070,7 +4149,7 @@ func Test_term_option() let &cpo = _cpo endfunc -func Test_cd_bslsh_completion_windows() +func Test_cd_bslash_completion_windows() CheckMSWindows let save_shellslash = &shellslash set noshellslash diff --git a/test/old/testdir/test_compiler.vim b/test/old/testdir/test_compiler.vim index 69420b4b7f..07b57b76d9 100644 --- a/test/old/testdir/test_compiler.vim +++ b/test/old/testdir/test_compiler.vim @@ -10,9 +10,12 @@ func Test_compiler() let save_LC_ALL = $LC_ALL let $LC_ALL= "C" - " %:S does not work properly with 'shellslash' set let save_shellslash = &shellslash - set noshellslash + " Nvim doesn't allow setting value of a hidden option to non-default value + if exists('+shellslash') + " %:S does not work properly with 'shellslash' set + set noshellslash + endif e Xfoo.pl compiler perl diff --git a/test/old/testdir/test_curswant.vim b/test/old/testdir/test_curswant.vim index e54cd4b280..c67cca5f7d 100644 --- a/test/old/testdir/test_curswant.vim +++ b/test/old/testdir/test_curswant.vim @@ -1,4 +1,7 @@ -" Tests for curswant not changing when setting an option +" Tests for not changing curswant + +source check.vim +source term_util.vim func Test_curswant() new @@ -19,5 +22,50 @@ func Test_curswant() let &ttimeoutlen=&ttimeoutlen call assert_equal(7, winsaveview().curswant) - enew! + bw! +endfunc + +func Test_normal_gm() + CheckRunVimInTerminal + let lines =<< trim END + call setline(1, repeat([" abcd\tefgh\tij"], 10)) + call cursor(1, 1) + END + call writefile(lines, 'XtestCurswant', 'D') + let buf = RunVimInTerminal('-S XtestCurswant', #{rows: 10}) + if has("folding") + call term_sendkeys(buf, "jVjzf") + " gm + call term_sendkeys(buf, "gmk") + call term_sendkeys(buf, ":echo virtcol('.')\<cr>") + call WaitFor({-> term_getline(buf, 10) =~ '^18\s\+'}) + " g0 + call term_sendkeys(buf, "jg0k") + call term_sendkeys(buf, ":echo virtcol('.')\<cr>") + call WaitFor({-> term_getline(buf, 10) =~ '^1\s\+'}) + " g^ + call term_sendkeys(buf, "jg^k") + call term_sendkeys(buf, ":echo virtcol('.')\<cr>") + call WaitFor({-> term_getline(buf, 10) =~ '^3\s\+'}) + endif + call term_sendkeys(buf, ":call cursor(10, 1)\<cr>") + " gm + call term_sendkeys(buf, "gmk") + call term_sendkeys(buf, ":echo virtcol('.')\<cr>") + call term_wait(buf) + call WaitFor({-> term_getline(buf, 10) =~ '^18\s\+'}) + " g0 + call term_sendkeys(buf, "g0k") + call term_sendkeys(buf, ":echo virtcol('.')\<cr>") + call WaitFor({-> term_getline(buf, 10) =~ '^1\s\+'}) + " g^ + call term_sendkeys(buf, "g^k") + call term_sendkeys(buf, ":echo virtcol('.')\<cr>") + call WaitFor({-> term_getline(buf, 10) =~ '^3\s\+'}) + " clean up + call StopVimInTerminal(buf) + wincmd p + wincmd c endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_diffmode.vim b/test/old/testdir/test_diffmode.vim index a448ed9b7f..880286d329 100644 --- a/test/old/testdir/test_diffmode.vim +++ b/test/old/testdir/test_diffmode.vim @@ -2007,4 +2007,31 @@ func Test_diff_overlapped_diff_blocks_will_be_merged() call StopVimInTerminal(buf) endfunc +" switching windows in diff mode caused an unnecessary scroll +func Test_diff_topline_noscroll() + CheckScreendump + + let content =<< trim END + call setline(1, range(1,60)) + vnew + call setline(1, range(1,10) + range(50,60)) + windo diffthis + norm! G + exe "norm! 30\<C-y>" + END + call writefile(content, 'Xcontent', 'D') + let buf = RunVimInTerminal('-S Xcontent', {'rows': 20}) + call VerifyScreenDump(buf, 'Test_diff_topline_1', {}) + call term_sendkeys(buf, ":echo line('w0', 1001)\<cr>") + call term_wait(buf) + call VerifyScreenDump(buf, 'Test_diff_topline_2', {}) + call term_sendkeys(buf, "\<C-W>p") + call term_wait(buf) + call VerifyScreenDump(buf, 'Test_diff_topline_3', {}) + call term_sendkeys(buf, "\<C-W>p") + call term_wait(buf) + call VerifyScreenDump(buf, 'Test_diff_topline_4', {}) + call StopVimInTerminal(buf) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_edit.vim b/test/old/testdir/test_edit.vim index 037282bf1a..9114cf8b11 100644 --- a/test/old/testdir/test_edit.vim +++ b/test/old/testdir/test_edit.vim @@ -2035,7 +2035,7 @@ func Test_edit_browse() au! augroup END - " When the USE_FNAME_CASE is defined this used to cause a crash. + " When the CASE_INSENSITIVE_FILENAME is defined this used to cause a crash. browse enew bwipe! diff --git a/test/old/testdir/test_expr.vim b/test/old/testdir/test_expr.vim index 8871e7e7d7..56a4c3bffa 100644 --- a/test/old/testdir/test_expr.vim +++ b/test/old/testdir/test_expr.vim @@ -799,10 +799,10 @@ func Test_expr_completion() call assert_equal('"echo 1 || g:tvar1 g:tvar2', @:) " completion for options - call feedkeys(":echo &compat\<C-A>\<C-B>\"\<CR>", 'xt') - call assert_equal('"echo &compatible', @:) - call feedkeys(":echo 1 && &compat\<C-A>\<C-B>\"\<CR>", 'xt') - call assert_equal('"echo 1 && &compatible', @:) + "call feedkeys(":echo &compat\<C-A>\<C-B>\"\<CR>", 'xt') + "call assert_equal('"echo &compatible', @:) + "call feedkeys(":echo 1 && &compat\<C-A>\<C-B>\"\<CR>", 'xt') + "call assert_equal('"echo 1 && &compatible', @:) call feedkeys(":echo &g:equala\<C-A>\<C-B>\"\<CR>", 'xt') call assert_equal('"echo &g:equalalways', @:) @@ -883,7 +883,7 @@ func Test_string_interp() #" String conversion. call assert_equal('hello from ' .. v:version, $"hello from {v:version}") call assert_equal('hello from ' .. v:version, $'hello from {v:version}') - #" Paper over a small difference between VimScript behaviour. + #" Paper over a small difference between Vim script behaviour. call assert_equal(string(v:true), $"{v:true}") call assert_equal('(1+1=2)', $"(1+1={1 + 1})") #" Hex-escaped opening brace: char2nr('{') == 0x7b diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim index d99656be47..19b7d41552 100644 --- a/test/old/testdir/test_filetype.vim +++ b/test/old/testdir/test_filetype.vim @@ -97,8 +97,17 @@ func s:GetFilenameChecks() abort \ 'ampl': ['file.run'], \ 'ant': ['build.xml'], \ 'antlr4': ['parser.g4'], - \ 'apache': ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'srm.conf', 'srm.conf-file', '/etc/httpd/mods-some/file', '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'], - \ 'apachestyle': ['/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file', 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'], + \ 'apache': ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', + \ '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', + \ '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', + \ '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', + \ 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', + \ 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', + \ 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'httpd-some.conf', + \ 'httpd-some.conf-file', 'srm.conf', 'srm.conf-file', 'proxy-html.conf', 'proxy-html.conf-file', '/etc/httpd/mods-some/file', + \ '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'], + \ 'apachestyle': ['/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file', + \ 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'], \ 'applescript': ['file.scpt'], \ 'aptconf': ['apt.conf', '/.aptitude/config', 'any/.aptitude/config'], \ 'arch': ['.arch-inventory', '=tagging-method'], @@ -125,7 +134,7 @@ func s:GetFilenameChecks() abort \ 'bib': ['file.bib'], \ 'bicep': ['file.bicep', 'file.bicepparam'], \ 'bindzone': ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file', 'foobar.zone'], - \ 'bitbake': ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf'], + \ 'bitbake': ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf', 'project-spec/configs/zynqmp-generic-xczu7ev.conf'], \ 'blade': ['file.blade.php'], \ 'blank': ['file.bl'], \ 'blueprint': ['file.blp'], @@ -218,7 +227,7 @@ func s:GetFilenameChecks() abort \ 'dockerfile': ['Containerfile', 'Dockerfile', 'dockerfile', 'file.Dockerfile', 'file.dockerfile', 'Dockerfile.debian', 'Containerfile.something'], \ 'dosbatch': ['file.bat'], \ 'dosini': ['/etc/yum.conf', '/etc/nfs.conf', '/etc/nfsmount.conf', 'file.ini', - \ 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', + \ 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', 'php-fpm.conf', 'php-fpm.conf.default', 'www.conf', 'www.conf.default', \ '/etc/yum.repos.d/file', 'any/etc/yum.conf', 'any/etc/yum.repos.d/file', 'file.wrap', \ 'file.vbp', 'ja2.ini', 'JA2.INI', 'mimeapps.list', 'pip.conf', 'setup.cfg', 'pudb.cfg', \ '.coveragerc', '.pypirc', '.gitlint', '.oelint.cfg', 'pylintrc', '.pylintrc', @@ -230,7 +239,7 @@ func s:GetFilenameChecks() abort \ 'dracula': ['file.drac', 'file.drc', 'file.lvs', 'file.lpe', 'drac.file'], \ 'dtd': ['file.dtd'], \ 'dtrace': ['/usr/lib/dtrace/io.d'], - \ 'dts': ['file.dts', 'file.dtsi', 'file.dtso', 'file.its', 'file.keymap'], + \ 'dts': ['file.dts', 'file.dtsi', 'file.dtso', 'file.its', 'file.keymap', 'file.overlay'], \ 'dune': ['jbuild', 'dune', 'dune-project', 'dune-workspace', 'dune-file'], \ 'dylan': ['file.dylan'], \ 'dylanintr': ['file.intr'], @@ -349,12 +358,14 @@ func s:GetFilenameChecks() abort \ 'ibasic': ['file.iba', 'file.ibi'], \ 'icemenu': ['/.icewm/menu', 'any/.icewm/menu'], \ 'icon': ['file.icn'], + \ 'idris2': ['file.idr'], \ 'indent': ['.indent.pro', 'indentrc'], \ 'inform': ['file.inf', 'file.INF'], \ 'initng': ['/etc/initng/any/file.i', 'file.ii', 'any/etc/initng/any/file.i'], \ 'inittab': ['inittab'], \ 'inko': ['file.inko'], \ 'ipfilter': ['ipf.conf', 'ipf6.conf', 'ipf.rules'], + \ 'ipkg': ['file.ipkg'], \ 'iss': ['file.iss'], \ 'ist': ['file.ist', 'file.mst'], \ 'j': ['file.ijs'], @@ -397,10 +408,13 @@ func s:GetFilenameChecks() abort \ 'lean': ['file.lean'], \ 'ledger': ['file.ldg', 'file.ledger', 'file.journal'], \ 'less': ['file.less'], + \ 'leo': ['file.leo'], \ 'lex': ['file.lex', 'file.l', 'file.lxx', 'file.l++'], + \ 'lf': ['lfrc'], \ 'lftp': ['lftp.conf', '.lftprc', 'anylftp/rc', 'lftp/rc', 'some-lftp/rc'], \ 'lhaskell': ['file.lhs'], \ 'libao': ['/etc/libao.conf', '/.libao', 'any/.libao', 'any/etc/libao.conf'], + \ 'lidris2': ['file.lidr'], \ 'lifelines': ['file.ll'], \ 'lilo': ['lilo.conf', 'lilo.conf-file'], \ 'lilypond': ['file.ly', 'file.ily'], @@ -477,6 +491,7 @@ func s:GetFilenameChecks() abort \ 'mgp': ['file.mgp'], \ 'mib': ['file.mib', 'file.my'], \ 'mix': ['file.mix', 'file.mixal'], + \ 'mlir': ['file.mlir'], \ 'mma': ['file.nb', 'file.wl'], \ 'mmp': ['file.mmp'], \ 'modconf': ['/etc/modules.conf', '/etc/modules', '/etc/conf.modules', '/etc/modprobe.file', 'any/etc/conf.modules', 'any/etc/modprobe.file', 'any/etc/modules', 'any/etc/modules.conf'], @@ -489,6 +504,7 @@ func s:GetFilenameChecks() abort \ 'mplayerconf': ['mplayer.conf', '/.mplayer/config', 'any/.mplayer/config'], \ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'], \ 'msidl': ['file.odl', 'file.mof'], + \ 'mss': ['file.mss'], \ 'msql': ['file.msql'], \ 'mojo': ['file.mojo', 'file.🔥'], \ 'msmtp': ['.msmtprc'], @@ -513,6 +529,7 @@ func s:GetFilenameChecks() abort \ 'nanorc': ['/etc/nanorc', 'file.nanorc', 'any/etc/nanorc'], \ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'], \ 'ncf': ['file.ncf'], + \ 'neomuttlog': ['/home/user/.neomuttdebug1'], \ 'neomuttrc': ['Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'], \ 'netrc': ['.netrc'], \ 'nginx': ['file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'], @@ -659,7 +676,7 @@ func s:GetFilenameChecks() abort \ '/tmp/bash-fc-3Ozjlw', '/tmp/bash-fc.3Ozjlw', 'PKGBUILD', 'APKBUILD', 'file.bash', '/usr/share/doc/bash-completion/filter.sh', \ '/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf', 'file.bats', '.ash_history', 'any/etc/neofetch/config.conf', '.xprofile', \ 'user-dirs.defaults', 'user-dirs.dirs', 'makepkg.conf', '.makepkg.conf', 'file.mdd', 'file.cygport', '.env', '.envrc', 'devscripts.conf', - \ '.devscripts'], + \ '.devscripts', 'file.lo', 'file.la', 'file.lai'], \ 'sieve': ['file.siv', 'file.sieve'], \ 'sil': ['file.sil'], \ 'simula': ['file.sim'], @@ -714,6 +731,7 @@ func s:GetFilenameChecks() abort \ 'svelte': ['file.svelte'], \ 'svg': ['file.svg'], \ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'], + \ 'sway': ['file.sw'], \ 'swayconfig': ['/home/user/.sway/config', '/home/user/.config/sway/config', '/etc/sway/config', '/etc/xdg/sway/config'], \ 'swift': ['file.swift', 'file.swiftinterface'], \ 'swiftgyb': ['file.swift.gyb'], @@ -853,7 +871,10 @@ func s:GetFilenameChecks() abort \ 'xinetd': ['/etc/xinetd.conf', '/etc/xinetd.d/file', 'any/etc/xinetd.conf', 'any/etc/xinetd.d/file'], \ 'xkb': ['/usr/share/X11/xkb/compat/pc', '/usr/share/X11/xkb/geometry/pc', '/usr/share/X11/xkb/keycodes/evdev', '/usr/share/X11/xkb/symbols/pc', '/usr/share/X11/xkb/types/pc'], \ 'xmath': ['file.msc', 'file.msf'], - \ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd', 'fonts.conf', 'file.xcu', 'file.xlb', 'file.xlc', 'file.xba', 'file.xpr', 'file.xpfm', 'file.spfm', 'file.bxml'], + \ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', + \ 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', + \ 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd', 'fonts.conf', 'file.xcu', 'file.xlb', 'file.xlc', 'file.xba', 'file.xpr', + \ 'file.xpfm', 'file.spfm', 'file.bxml', 'file.mmi'], \ 'xmodmap': ['anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'], \ 'xpm': ['file.xpm'], \ 'xpm2': ['file.xpm2'], @@ -862,7 +883,8 @@ func s:GetFilenameChecks() abort \ 'xsd': ['file.xsd'], \ 'xslt': ['file.xsl', 'file.xslt'], \ 'yacc': ['file.yy', 'file.yxx', 'file.y++'], - \ 'yaml': ['file.yaml', 'file.yml', 'file.eyaml', 'any/.bundle/config', '.clangd', '.clang-format', '.clang-tidy', 'file.mplstyle', 'matplotlibrc', 'yarn.lock'], + \ 'yaml': ['file.yaml', 'file.yml', 'file.eyaml', 'any/.bundle/config', '.clangd', '.clang-format', '.clang-tidy', 'file.mplstyle', 'matplotlibrc', 'yarn.lock', + \ '/home/user/.kube/config'], \ 'yang': ['file.yang'], \ 'yuck': ['file.yuck'], \ 'z8a': ['file.z8a'], @@ -2419,6 +2441,24 @@ func Test_inc_file() filetype off endfunc +func Test_ll_file() + filetype on + + " LLVM IR + call writefile(['target triple = "nvptx64-nvidia-cuda"'], 'Xfile.ll', 'D') + split Xfile.ll + call assert_equal('llvm', &filetype) + bwipe! + + " lifelines + call writefile(['proc main() {}'], 'Xfile.ll', 'D') + split Xfile.ll + call assert_equal('lifelines', &filetype) + bwipe! + + filetype off +endfunc + func Test_lsl_file() filetype on @@ -2697,4 +2737,15 @@ func Test_make_file() filetype off endfunc +func Test_org_file() + filetype on + + call writefile(['* org Headline', '*some bold text*', '/some italic text/'], 'Xfile.org', 'D') + split Xfile.org + call assert_equal('org', &filetype) + bwipe! + + filetype off +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_findfile.vim b/test/old/testdir/test_findfile.vim index 06d781ed69..539c7a661a 100644 --- a/test/old/testdir/test_findfile.vim +++ b/test/old/testdir/test_findfile.vim @@ -1,5 +1,8 @@ " Test findfile() and finddir() +source check.vim +source vim9.vim + let s:files = [ 'Xfinddir1/foo', \ 'Xfinddir1/bar', \ 'Xfinddir1/Xdir2/foo', @@ -286,4 +289,526 @@ func Test_find_non_existing_path() let &path = save_path endfunc +" Test for 'findfunc' +func Test_findfunc() + CheckUnix + call assert_equal('', &findfunc) + call writefile(['aFile'], 'Xfindfunc1.c', 'D') + call writefile(['bFile'], 'Xfindfunc2.c', 'D') + call writefile(['cFile'], 'Xfindfunc3.c', 'D') + + " basic tests + func FindFuncBasic(pat, cmdcomplete) + let fnames = ['Xfindfunc1.c', 'Xfindfunc2.c', 'Xfindfunc3.c'] + return fnames->copy()->filter('v:val =~? a:pat') + endfunc + + set findfunc=FindFuncBasic + find Xfindfunc3 + call assert_match('Xfindfunc3.c', @%) + bw! + 2find Xfind + call assert_match('Xfindfunc2.c', @%) + bw! + call assert_fails('4find Xfind', 'E347: No more file "Xfind" found in path') + call assert_fails('find foobar', 'E345: Can''t find file "foobar" in path') + + sfind Xfindfunc2.c + call assert_match('Xfindfunc2.c', @%) + call assert_equal(2, winnr('$')) + %bw! + call assert_fails('sfind foobar', 'E345: Can''t find file "foobar" in path') + + tabfind Xfindfunc3.c + call assert_match('Xfindfunc3.c', @%) + call assert_equal(2, tabpagenr()) + %bw! + call assert_fails('tabfind foobar', 'E345: Can''t find file "foobar" in path') + + " Test garbage collection + call test_garbagecollect_now() + find Xfindfunc2 + call assert_match('Xfindfunc2.c', @%) + bw! + delfunc FindFuncBasic + call test_garbagecollect_now() + call assert_fails('find Xfindfunc2', 'E117: Unknown function: FindFuncBasic') + + " Buffer-local option + func GlobalFindFunc(pat, cmdcomplete) + return ['global'] + endfunc + func LocalFindFunc(pat, cmdcomplete) + return ['local'] + endfunc + set findfunc=GlobalFindFunc + new + setlocal findfunc=LocalFindFunc + find xxxx + call assert_equal('local', @%) + wincmd w + find xxxx + call assert_equal('global', @%) + aboveleft new + call assert_equal("GlobalFindFunc", &findfunc) + wincmd k + aboveleft new + call assert_equal("GlobalFindFunc", &findfunc) + %bw! + delfunc GlobalFindFunc + delfunc LocalFindFunc + + " Assign an expression + set findfunc=[] + call assert_fails('find xxxx', 'E117: Unknown function: []') + + " Error cases + + " Function that doesn't take any arguments + func FindFuncNoArg() + endfunc + set findfunc=FindFuncNoArg + call assert_fails('find Xfindfunc1.c', 'E118: Too many arguments for function: FindFuncNoArg') + delfunc FindFuncNoArg + + " Syntax error in the function + func FindFuncSyntaxError(pat, cmdcomplete) + return l + endfunc + set findfunc=FindFuncSyntaxError + call assert_fails('find Xfindfunc1.c', 'E121: Undefined variable: l') + delfunc FindFuncSyntaxError + + " Find function throws an error + func FindFuncWithThrow(pat, cmdcomplete) + throw 'find error' + endfunc + set findfunc=FindFuncWithThrow + call assert_fails('find Xfindfunc1.c', 'find error') + delfunc FindFuncWithThrow + + " Try using a null function + "call assert_fails('let &findfunc = test_null_function()', 'E129: Function name required') + + " Try to create a new window from the find function + func FindFuncNewWindow(pat, cmdexpand) + new + return ["foo"] + endfunc + set findfunc=FindFuncNewWindow + call assert_fails('find Xfindfunc1.c', 'E565: Not allowed to change text or change window') + delfunc FindFuncNewWindow + + " Try to modify the current buffer from the find function + func FindFuncModifyBuf(pat, cmdexpand) + call setline(1, ['abc']) + return ["foo"] + endfunc + set findfunc=FindFuncModifyBuf + call assert_fails('find Xfindfunc1.c', 'E565: Not allowed to change text or change window') + delfunc FindFuncModifyBuf + + " Return the wrong type from the function + func FindFuncWrongRet(pat, cmdexpand) + return 'foo' + endfunc + set findfunc=FindFuncWrongRet + call assert_fails('find Xfindfunc1.c', "E1514: 'findfunc' did not return a List type") + delfunc FindFuncWrongRet + + set findfunc& +endfunc + +" Test for using a script-local function for 'findfunc' +func Test_findfunc_scriptlocal_func() + func! s:FindFuncScript(pat, cmdexpand) + let g:FindFuncArg = a:pat + return ['xxx'] + endfunc + + set findfunc=s:FindFuncScript + call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc) + call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc) + new | only + let g:FindFuncArg = '' + find abc + call assert_equal('abc', g:FindFuncArg) + bw! + + set findfunc=<SID>FindFuncScript + call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc) + call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc) + new | only + let g:FindFuncArg = '' + find abc + call assert_equal('abc', g:FindFuncArg) + bw! + + let &findfunc = 's:FindFuncScript' + call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc) + new | only + let g:FindFuncArg = '' + find abc + call assert_equal('abc', g:FindFuncArg) + bw! + + let &findfunc = '<SID>FindFuncScript' + call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc) + new | only + let g:FindFuncArg = '' + find abc + call assert_equal('abc', g:FindFuncArg) + bw! + + set findfunc= + setglobal findfunc=s:FindFuncScript + setlocal findfunc= + call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc) + call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc) + call assert_equal('', &l:findfunc) + new | only + let g:FindFuncArg = '' + find abc + call assert_equal('abc', g:FindFuncArg) + bw! + + new | only + set findfunc= + setglobal findfunc= + setlocal findfunc=s:FindFuncScript + call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc) + call assert_equal(expand('<SID>') .. 'FindFuncScript', &l:findfunc) + call assert_equal('', &g:findfunc) + let g:FindFuncArg = '' + find abc + call assert_equal('abc', g:FindFuncArg) + bw! + + new | only + set findfunc= + setlocal findfunc=NoSuchFunc + setglobal findfunc=s:FindFuncScript + call assert_equal('NoSuchFunc', &findfunc) + call assert_equal('NoSuchFunc', &l:findfunc) + call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc) + new | only + call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc) + call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc) + call assert_equal('', &l:findfunc) + let g:FindFuncArg = '' + find abc + call assert_equal('abc', g:FindFuncArg) + bw! + + new | only + set findfunc= + setlocal findfunc=NoSuchFunc + set findfunc=s:FindFuncScript + call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc) + call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc) + call assert_equal('', &l:findfunc) + let g:FindFuncArg = '' + find abc + call assert_equal('abc', g:FindFuncArg) + new | only + call assert_equal(expand('<SID>') .. 'FindFuncScript', &findfunc) + call assert_equal(expand('<SID>') .. 'FindFuncScript', &g:findfunc) + call assert_equal('', &l:findfunc) + let g:FindFuncArg = '' + find abc + call assert_equal('abc', g:FindFuncArg) + bw! + + set findfunc= + delfunc s:FindFuncScript +endfunc + +" Test for expanding the argument to the :find command using 'findfunc' +func Test_findfunc_expand_arg() + let s:fnames = ['Xfindfunc1.c', 'Xfindfunc2.c', 'Xfindfunc3.c'] + + " 'findfunc' that accepts a regular expression + func FindFuncRegexp(pat, cmdcomplete) + return s:fnames->copy()->filter('v:val =~? a:pat') + endfunc + + " 'findfunc' that accepts a glob + func FindFuncGlob(pat_arg, cmdcomplete) + let pat = glob2regpat(a:cmdcomplete ? $'*{a:pat_arg}*' : a:pat_arg) + return s:fnames->copy()->filter('v:val =~? pat') + endfunc + + for regexp in [v:true, v:false] + let &findfunc = regexp ? 'FindFuncRegexp' : 'FindFuncGlob' + + call feedkeys(":find \<Tab>\<C-B>\"\<CR>", "xt") + call assert_equal('"find Xfindfunc1.c', @:) + + call feedkeys(":find Xfind\<Tab>\<Tab>\<C-B>\"\<CR>", "xt") + call assert_equal('"find Xfindfunc2.c', @:) + + call assert_equal(s:fnames, getcompletion('find ', 'cmdline')) + call assert_equal(s:fnames, getcompletion('find Xfind', 'cmdline')) + + let pat = regexp ? 'X.*1\.c' : 'X*1.c' + call feedkeys($":find {pat}\<Tab>\<C-B>\"\<CR>", "xt") + call assert_equal('"find Xfindfunc1.c', @:) + call assert_equal(['Xfindfunc1.c'], getcompletion($'find {pat}', 'cmdline')) + + call feedkeys(":find 3\<Tab>\<C-B>\"\<CR>", "xt") + call assert_equal('"find Xfindfunc3.c', @:) + call assert_equal(['Xfindfunc3.c'], getcompletion($'find 3', 'cmdline')) + + call feedkeys(":find Xfind\<C-A>\<C-B>\"\<CR>", "xt") + call assert_equal('"find Xfindfunc1.c Xfindfunc2.c Xfindfunc3.c', @:) + + call feedkeys(":find abc\<Tab>\<C-B>\"\<CR>", "xt") + call assert_equal('"find abc', @:) + call assert_equal([], getcompletion('find abc', 'cmdline')) + endfor + + set findfunc& + delfunc! FindFuncRegexp + delfunc! FindFuncGlob + unlet s:fnames +endfunc + +" Test for different ways of setting the 'findfunc' option +func Test_findfunc_callback() + new + func FindFunc1(pat, cmdexpand) + let g:FindFunc1Args = [a:pat, a:cmdexpand] + return ['findfunc1'] + endfunc + + let lines =<< trim END + #" Test for using a function name + LET &findfunc = 'g:FindFunc1' + LET g:FindFunc1Args = [] + find abc1 + call assert_equal(['abc1', v:false], g:FindFunc1Args) + + #" Test for using a function() + set findfunc=function('g:FindFunc1') + LET g:FindFunc1Args = [] + find abc2 + call assert_equal(['abc2', v:false], g:FindFunc1Args) + + #" Using a funcref variable to set 'findfunc' + VAR Fn = function('g:FindFunc1') + LET &findfunc = Fn + LET g:FindFunc1Args = [] + find abc3 + call assert_equal(['abc3', v:false], g:FindFunc1Args) + + #" Using a string(funcref_variable) to set 'findfunc' + LET Fn = function('g:FindFunc1') + LET &findfunc = string(Fn) + LET g:FindFunc1Args = [] + find abc4 + call assert_equal(['abc4', v:false], g:FindFunc1Args) + + #" Test for using a funcref() + set findfunc=funcref('g:FindFunc1') + LET g:FindFunc1Args = [] + find abc5 + call assert_equal(['abc5', v:false], g:FindFunc1Args) + + #" Using a funcref variable to set 'findfunc' + LET Fn = funcref('g:FindFunc1') + LET &findfunc = Fn + LET g:FindFunc1Args = [] + find abc6 + call assert_equal(['abc6', v:false], g:FindFunc1Args) + + #" Using a string(funcref_variable) to set 'findfunc' + LET Fn = funcref('g:FindFunc1') + LET &findfunc = string(Fn) + LET g:FindFunc1Args = [] + find abc7 + call assert_equal(['abc7', v:false], g:FindFunc1Args) + + #" Test for using a lambda function using set + VAR optval = "LSTART pat, cmdexpand LMIDDLE FindFunc1(pat, cmdexpand) LEND" + LET optval = substitute(optval, ' ', '\\ ', 'g') + exe "set findfunc=" .. optval + LET g:FindFunc1Args = [] + find abc8 + call assert_equal(['abc8', v:false], g:FindFunc1Args) + + #" Test for using a lambda function using LET + LET &findfunc = LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND + LET g:FindFunc1Args = [] + find abc9 + call assert_equal(['abc9', v:false], g:FindFunc1Args) + + #" Set 'findfunc' to a string(lambda expression) + LET &findfunc = 'LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND' + LET g:FindFunc1Args = [] + find abc10 + call assert_equal(['abc10', v:false], g:FindFunc1Args) + + #" Set 'findfunc' to a variable with a lambda expression + VAR Lambda = LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND + LET &findfunc = Lambda + LET g:FindFunc1Args = [] + find abc11 + call assert_equal(['abc11', v:false], g:FindFunc1Args) + + #" Set 'findfunc' to a string(variable with a lambda expression) + LET Lambda = LSTART pat, _ LMIDDLE FindFunc1(pat, v:false) LEND + LET &findfunc = string(Lambda) + LET g:FindFunc1Args = [] + find abc12 + call assert_equal(['abc12', v:false], g:FindFunc1Args) + + #" Try to use 'findfunc' after the function is deleted + func g:TmpFindFunc(pat, cmdexpand) + let g:TmpFindFunc1Args = [a:pat, a:cmdexpand] + endfunc + LET &findfunc = function('g:TmpFindFunc') + delfunc g:TmpFindFunc + call test_garbagecollect_now() + LET g:TmpFindFunc1Args = [] + call assert_fails('find abc13', 'E117:') + call assert_equal([], g:TmpFindFunc1Args) + + #" Try to use a function with three arguments for 'findfunc' + func g:TmpFindFunc2(x, y, z) + let g:TmpFindFunc2Args = [a:x, a:y, a:z] + endfunc + set findfunc=TmpFindFunc2 + LET g:TmpFindFunc2Args = [] + call assert_fails('find abc14', 'E119:') + call assert_equal([], g:TmpFindFunc2Args) + delfunc TmpFindFunc2 + + #" Try to use a function with zero arguments for 'findfunc' + func g:TmpFindFunc3() + let g:TmpFindFunc3Called = v:true + endfunc + set findfunc=TmpFindFunc3 + LET g:TmpFindFunc3Called = v:false + call assert_fails('find abc15', 'E118:') + call assert_equal(v:false, g:TmpFindFunc3Called) + delfunc TmpFindFunc3 + + #" Try to use a lambda function with three arguments for 'findfunc' + LET &findfunc = LSTART a, b, c LMIDDLE FindFunc1(a, v:false) LEND + LET g:FindFunc1Args = [] + call assert_fails('find abc16', 'E119:') + call assert_equal([], g:FindFunc1Args) + + #" Test for clearing the 'findfunc' option + set findfunc='' + set findfunc& + call assert_fails("set findfunc=function('abc')", "E700:") + call assert_fails("set findfunc=funcref('abc')", "E700:") + + #" set 'findfunc' to a non-existing function + LET &findfunc = function('g:FindFunc1') + call assert_fails("set findfunc=function('NonExistingFunc')", 'E700:') + call assert_fails("LET &findfunc = function('NonExistingFunc')", 'E700:') + LET g:FindFunc1Args = [] + find abc17 + call assert_equal(['abc17', v:false], g:FindFunc1Args) + END + call CheckTransLegacySuccess(lines) + + " Test for using a script-local function name + func s:FindFunc2(pat, cmdexpand) + let g:FindFunc2Args = [a:pat, a:cmdexpand] + return ['findfunc2'] + endfunc + set findfunc=s:FindFunc2 + let g:FindFunc2Args = [] + find abc18 + call assert_equal(['abc18', v:false], g:FindFunc2Args) + + let &findfunc = 's:FindFunc2' + let g:FindFunc2Args = [] + find abc19 + call assert_equal(['abc19', v:false], g:FindFunc2Args) + delfunc s:FindFunc2 + + " Using Vim9 lambda expression in legacy context should fail + set findfunc=(pat,\ cmdexpand)\ =>\ FindFunc1(pat,\ v:false) + let g:FindFunc1Args = [] + call assert_fails('find abc20', 'E117:') + call assert_equal([], g:FindFunc1Args) + + " set 'findfunc' to a partial with dict. + func SetFindFunc() + let operator = {'execute': function('FindFuncExecute')} + let &findfunc = operator.execute + endfunc + func FindFuncExecute(pat, cmdexpand) dict + return ['findfuncexecute'] + endfunc + call SetFindFunc() + call test_garbagecollect_now() + set findfunc= + delfunc SetFindFunc + delfunc FindFuncExecute + + func FindFunc2(pat, cmdexpand) + let g:FindFunc2Args = [a:pat, a:cmdexpand] + return ['findfunc2'] + endfunc + + " Vim9 tests + let lines =<< trim END + vim9script + + def g:Vim9findFunc(pat: string, cmdexpand: bool): list<string> + g:FindFunc1Args = [pat, cmdexpand] + return ['vim9findfunc'] + enddef + + # Test for using a def function with findfunc + set findfunc=function('g:Vim9findFunc') + g:FindFunc1Args = [] + find abc21 + assert_equal(['abc21', false], g:FindFunc1Args) + + # Test for using a global function name + &findfunc = g:FindFunc2 + g:FindFunc2Args = [] + find abc22 + assert_equal(['abc22', false], g:FindFunc2Args) + bw! + + # Test for using a script-local function name + def LocalFindFunc(pat: string, cmdexpand: bool): list<string> + g:LocalFindFuncArgs = [pat, cmdexpand] + return ['localfindfunc'] + enddef + &findfunc = LocalFindFunc + g:LocalFindFuncArgs = [] + find abc23 + assert_equal(['abc23', false], g:LocalFindFuncArgs) + bw! + END + call CheckScriptSuccess(lines) + + " setting 'findfunc' to a script local function outside of a script context + " should fail + let cleanup =<< trim END + call writefile([execute('messages')], 'Xtest.out') + qall + END + call writefile(cleanup, 'Xverify.vim', 'D') + call RunVim([], [], "-c \"set findfunc=s:abc\" -S Xverify.vim") + call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0]) + call delete('Xtest.out') + + " cleanup + set findfunc& + delfunc FindFunc1 + delfunc FindFunc2 + unlet g:FindFunc1Args g:FindFunc2Args + %bw! +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_functions.vim b/test/old/testdir/test_functions.vim index ffe7f3fb39..327ea98e1c 100644 --- a/test/old/testdir/test_functions.vim +++ b/test/old/testdir/test_functions.vim @@ -272,17 +272,17 @@ func Test_strftime() let tz = $TZ endif - " Force EST and then UTC, save the current hour (24-hour clock) for each - let $TZ = 'EST' | let est = strftime('%H') - let $TZ = 'UTC' | let utc = strftime('%H') + " Force different time zones, save the current hour (24-hour clock) for each + let $TZ = 'GMT+1' | let one = strftime('%H') + let $TZ = 'GMT+2' | let two = strftime('%H') " Those hours should be two bytes long, and should not be the same; if they " are, a tzset(3) call may have failed somewhere - call assert_equal(strlen(est), 2) - call assert_equal(strlen(utc), 2) + call assert_equal(strlen(one), 2) + call assert_equal(strlen(two), 2) " TODO: this fails on MS-Windows if has('unix') - call assert_notequal(est, utc) + call assert_notequal(one, two) endif " If we cached a timezone value, put it back, otherwise clear it @@ -383,6 +383,12 @@ func Test_simplify() call assert_equal('/', simplify('/.')) call assert_equal('/', simplify('/..')) call assert_equal('/...', simplify('/...')) + call assert_equal('//path', simplify('//path')) + if has('unix') + call assert_equal('/path', simplify('///path')) + call assert_equal('/path', simplify('////path')) + endif + call assert_equal('./dir/file', './dir/file'->simplify()) call assert_equal('./dir/file', simplify('.///dir//file')) call assert_equal('./dir/file', simplify('./dir/./file')) @@ -2069,6 +2075,7 @@ endfunc " Test for the inputdialog() function func Test_inputdialog() + set timeout timeoutlen=10 if has('gui_running') call assert_fails('let v=inputdialog([], "xx")', 'E730:') call assert_fails('let v=inputdialog("Q", [])', 'E730:') @@ -2078,6 +2085,7 @@ func Test_inputdialog() call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\<CR>\<Esc>", 'xt') call assert_equal('yy', v) endif + set timeout& timeoutlen& endfunc " Test for inputlist() @@ -3089,7 +3097,7 @@ func Test_range() call assert_fails('call term_start(range(3, 4))', 'E474:') let g:terminal_ansi_colors = range(16) if has('win32') - let cmd = "cmd /c dir" + let cmd = "cmd /D /c dir" else let cmd = "ls" endif diff --git a/test/old/testdir/test_getvar.vim b/test/old/testdir/test_getvar.vim index 56f737ab9c..de00281ba3 100644 --- a/test/old/testdir/test_getvar.vim +++ b/test/old/testdir/test_getvar.vim @@ -22,6 +22,12 @@ func Test_var() call assert_equal('Chance', getwinvar(9, '', def_str)) call assert_equal(0, getwinvar(1, '&nu')) call assert_equal(0, getwinvar(1, '&nu', 1)) + call assert_match(v:t_dict, type(getwinvar(1, '&'))) + call assert_match(v:t_dict, type(getwinvar(1, '&', def_str))) + call assert_equal('', getwinvar(9, '&')) + call assert_equal('Chance', getwinvar(9, '&', def_str)) + call assert_equal('', getwinvar(1, '&nux')) + call assert_equal('Chance', getwinvar(1, '&nux', def_str)) unlet def_str " test for gettabvar() @@ -83,7 +89,12 @@ func Test_var() unlet def_dict + call assert_match(v:t_dict, type(gettabwinvar(2, 3, '&'))) + call assert_match(v:t_dict, type(gettabwinvar(2, 3, '&', 1))) call assert_equal("", gettabwinvar(9, 2020, '')) + call assert_equal(1, gettabwinvar(9, 2020, '', 1)) + call assert_equal('', gettabwinvar(9, 2020, '&')) + call assert_equal(1, gettabwinvar(9, 2020, '&', 1)) call assert_equal('', gettabwinvar(2, 3, '&nux')) call assert_equal(1, gettabwinvar(2, 3, '&nux', 1)) tabonly diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim index 48319f5017..c02aa1db62 100644 --- a/test/old/testdir/test_ins_complete.vim +++ b/test/old/testdir/test_ins_complete.vim @@ -950,6 +950,46 @@ func Test_completeopt_buffer_local() call assert_equal('menu', &completeopt) call assert_equal('menu', &g:completeopt) + new | only + call setline(1, ['foofoo', 'foobar', 'foobaz', '']) + set completeopt& + setlocal completeopt=menu,fuzzy,noinsert + setglobal completeopt=menu,longest + call assert_equal('menu,fuzzy,noinsert', &completeopt) + call assert_equal('menu,fuzzy,noinsert', &l:completeopt) + call assert_equal('menu,longest', &g:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>bz\<C-Y>", 'tnix') + call assert_equal('foobaz', getline('.')) + setlocal bufhidden=wipe + new | only! + call setline(1, ['foofoo', 'foobar', 'foobaz', '']) + call assert_equal('menu,longest', &completeopt) + call assert_equal('menu,longest', &g:completeopt) + call assert_equal('', &l:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix') + call assert_equal('foo', getline('.')) + bwipe! + + new | only + call setline(1, ['foofoo', 'foobar', 'foobaz', '']) + set completeopt& + setlocal completeopt=menu,fuzzy,noinsert + set completeopt=menu,longest + call assert_equal('menu,longest', &completeopt) + call assert_equal('menu,longest', &g:completeopt) + call assert_equal('', &l:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix') + call assert_equal('foo', getline('.')) + setlocal bufhidden=wipe + new | only! + call setline(1, ['foofoo', 'foobar', 'foobaz', '']) + call assert_equal('menu,longest', &completeopt) + call assert_equal('menu,longest', &g:completeopt) + call assert_equal('', &l:completeopt) + call feedkeys("Gccf\<C-X>\<C-N>\<C-X>\<C-Z>", 'tnix') + call assert_equal('foo', getline('.')) + bwipe! + set completeopt& endfunc @@ -1713,10 +1753,10 @@ func Test_completefunc_callback() call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x') " Using Vim9 lambda expression in legacy context should fail - " set completefunc=(a,\ b)\ =>\ CompleteFunc1(21,\ a,\ b) + set completefunc=(a,\ b)\ =>\ CompleteFunc1(21,\ a,\ b) new | only let g:CompleteFunc1Args = [] - " call assert_fails('call feedkeys("A\<C-X>\<C-U>\<Esc>", "x")', 'E117:') + call assert_fails('call feedkeys("A\<C-X>\<C-U>\<Esc>", "x")', 'E117:') call assert_equal([], g:CompleteFunc1Args) " set 'completefunc' to a partial with dict. This used to cause a crash. @@ -1970,10 +2010,10 @@ func Test_omnifunc_callback() call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x') " Using Vim9 lambda expression in legacy context should fail - " set omnifunc=(a,\ b)\ =>\ OmniFunc1(21,\ a,\ b) + set omnifunc=(a,\ b)\ =>\ OmniFunc1(21,\ a,\ b) new | only let g:OmniFunc1Args = [] - " call assert_fails('call feedkeys("A\<C-X>\<C-O>\<Esc>", "x")', 'E117:') + call assert_fails('call feedkeys("A\<C-X>\<C-O>\<Esc>", "x")', 'E117:') call assert_equal([], g:OmniFunc1Args) " set 'omnifunc' to a partial with dict. This used to cause a crash. @@ -2228,6 +2268,7 @@ func Test_thesaurusfunc_callback() call add(g:TsrFunc3Args, [a:findstart, a:base]) return a:findstart ? 0 : [] endfunc + set tsrfu=s:TsrFunc3 new call setline(1, 'script1') @@ -2243,6 +2284,46 @@ func Test_thesaurusfunc_callback() call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x') call assert_equal([[1, ''], [0, 'script2']], g:TsrFunc3Args) bw! + + new | only + set thesaurusfunc= + setlocal thesaurusfunc=NoSuchFunc + setglobal thesaurusfunc=s:TsrFunc3 + call assert_equal('NoSuchFunc', &thesaurusfunc) + call assert_equal('NoSuchFunc', &l:thesaurusfunc) + call assert_equal('s:TsrFunc3', &g:thesaurusfunc) + new | only + call assert_equal('s:TsrFunc3', &thesaurusfunc) + call assert_equal('s:TsrFunc3', &g:thesaurusfunc) + call assert_equal('', &l:thesaurusfunc) + call setline(1, 'script1') + let g:TsrFunc3Args = [] + call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x') + call assert_equal([[1, ''], [0, 'script1']], g:TsrFunc3Args) + bw! + + new | only + set thesaurusfunc= + setlocal thesaurusfunc=NoSuchFunc + set thesaurusfunc=s:TsrFunc3 + call assert_equal('s:TsrFunc3', &thesaurusfunc) + call assert_equal('s:TsrFunc3', &g:thesaurusfunc) + call assert_equal('', &l:thesaurusfunc) + call setline(1, 'script1') + let g:TsrFunc3Args = [] + call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x') + call assert_equal([[1, ''], [0, 'script1']], g:TsrFunc3Args) + setlocal bufhidden=wipe + new | only! + call assert_equal('s:TsrFunc3', &thesaurusfunc) + call assert_equal('s:TsrFunc3', &g:thesaurusfunc) + call assert_equal('', &l:thesaurusfunc) + call setline(1, 'script1') + let g:TsrFunc3Args = [] + call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x') + call assert_equal([[1, ''], [0, 'script1']], g:TsrFunc3Args) + bw! + delfunc s:TsrFunc3 " invalid return value @@ -2250,10 +2331,10 @@ func Test_thesaurusfunc_callback() call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x') " Using Vim9 lambda expression in legacy context should fail - " set thesaurusfunc=(a,\ b)\ =>\ TsrFunc1(21,\ a,\ b) + set thesaurusfunc=(a,\ b)\ =>\ TsrFunc1(21,\ a,\ b) new | only let g:TsrFunc1Args = [] - " call assert_fails('call feedkeys("A\<C-X>\<C-T>\<Esc>", "x")', 'E117:') + call assert_fails('call feedkeys("A\<C-X>\<C-T>\<Esc>", "x")', 'E117:') call assert_equal([], g:TsrFunc1Args) bw! diff --git a/test/old/testdir/test_map_functions.vim b/test/old/testdir/test_map_functions.vim index 8f7c8bae76..5118063b36 100644 --- a/test/old/testdir/test_map_functions.vim +++ b/test/old/testdir/test_map_functions.vim @@ -527,6 +527,25 @@ func Test_map_restore_negative_sid() call delete('Xresult') endfunc +" Check that restoring a mapping doesn't remove a mapping whose {rhs} matches +" the restored mapping's {lhs}. +func Test_map_restore_with_rhs_match_lhs() + nnoremap <F2> <F3> + nnoremap <F3> <F4> + call assert_equal('<F3>', maparg('<F2>', 'n')) + call assert_equal('<F4>', maparg('<F3>', 'n')) + let d = maparg('<F3>', 'n', v:false, v:true) + nunmap <F3> + call assert_equal('<F3>', maparg('<F2>', 'n')) + call assert_equal('', maparg('<F3>', 'n')) + call mapset(d) + call assert_equal('<F3>', maparg('<F2>', 'n')) + call assert_equal('<F4>', maparg('<F3>', 'n')) + + nunmap <F2> + nunmap <F3> +endfunc + func Test_maplist() new func s:ClearMappingsAbbreviations() diff --git a/test/old/testdir/test_mapping.vim b/test/old/testdir/test_mapping.vim index e4e446c55c..96fa0304dc 100644 --- a/test/old/testdir/test_mapping.vim +++ b/test/old/testdir/test_mapping.vim @@ -6,33 +6,62 @@ source screendump.vim source term_util.vim func Test_abbreviation() + new " abbreviation with 0x80 should work inoreab чкпр vim call feedkeys("Goчкпр \<Esc>", "xt") call assert_equal('vim ', getline('$')) iunab чкпр - set nomodified + bwipe! +endfunc + +func Test_abbreviation_with_noremap() + nnoremap <F2> :echo "cheese" + cabbr cheese xxx + call feedkeys(":echo \"cheese\"\<C-B>\"\<CR>", 'tx') + call assert_equal('"echo "xxx"', @:) + call feedkeys("\<F2>\<C-B>\"\<CR>", 'tx') + call assert_equal('"echo "cheese"', @:) + nnoremap <F2> :echo "cheese<C-]>" + call feedkeys("\<F2>\<C-B>\"\<CR>", 'tx') + call assert_equal('"echo "xxx"', @:) + nunmap <F2> + cunabbr cheese + + new + inoremap <buffer> ( <C-]>() + iabbr <buffer> fnu fun + call feedkeys("ifnu(", 'tx') + call assert_equal('fun()', getline(1)) + bwipe! endfunc func Test_abclear() - abbrev foo foobar - iabbrev fooi foobari - cabbrev fooc foobarc - call assert_equal("\n\nc fooc foobarc\ni fooi foobari\n! foo foobar", execute('abbrev')) + abbrev foo foobar + iabbrev fooi foobari + cabbrev fooc foobarc + call assert_equal("\n\n" + \ .. "c fooc foobarc\n" + \ .. "i fooi foobari\n" + \ .. "! foo foobar", execute('abbrev')) - iabclear - call assert_equal("\n\nc fooc foobarc\nc foo foobar", execute('abbrev')) - abbrev foo foobar - iabbrev fooi foobari + iabclear + call assert_equal("\n\n" + \ .. "c fooc foobarc\n" + \ .. "c foo foobar", execute('abbrev')) + abbrev foo foobar + iabbrev fooi foobari - cabclear - call assert_equal("\n\ni fooi foobari\ni foo foobar", execute('abbrev')) - abbrev foo foobar - cabbrev fooc foobarc + cabclear + call assert_equal("\n\n" + \ .. "i fooi foobari\n" + \ .. "i foo foobar", execute('abbrev')) + abbrev foo foobar + cabbrev fooc foobarc - abclear - call assert_equal("\n\nNo abbreviation found", execute('abbrev')) - call assert_fails('%abclear', 'E481:') + abclear + call assert_equal("\n\nNo abbreviation found", execute('abbrev')) + call assert_fails('%abclear', 'E481:') endfunc func Test_abclear_buffer() @@ -42,18 +71,24 @@ func Test_abclear_buffer() new X2 abbrev <buffer> foo2 foobar2 - call assert_equal("\n\n! foo2 @foobar2\n! foo foobar", execute('abbrev')) + call assert_equal("\n\n" + \ .. "! foo2 @foobar2\n" + \ .. "! foo foobar", execute('abbrev')) abclear <buffer> - call assert_equal("\n\n! foo foobar", execute('abbrev')) + call assert_equal("\n\n" + \ .. "! foo foobar", execute('abbrev')) b X1 - call assert_equal("\n\n! foo1 @foobar1\n! foo foobar", execute('abbrev')) + call assert_equal("\n\n" + \ .. "! foo1 @foobar1\n" + \ .. "! foo foobar", execute('abbrev')) abclear <buffer> - call assert_equal("\n\n! foo foobar", execute('abbrev')) + call assert_equal("\n\n" + \ .. "! foo foobar", execute('abbrev')) abclear - call assert_equal("\n\nNo abbreviation found", execute('abbrev')) + call assert_equal("\n\nNo abbreviation found", execute('abbrev')) %bwipe endfunc diff --git a/test/old/testdir/test_modeline.vim b/test/old/testdir/test_modeline.vim index 487a89e038..2cd9e49a12 100644 --- a/test/old/testdir/test_modeline.vim +++ b/test/old/testdir/test_modeline.vim @@ -217,6 +217,7 @@ func Test_modeline_fails_always() call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:') call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:') call s:modeline_fails('exrc', 'exrc=Something()', 'E520:') + call s:modeline_fails('findfunc', 'findfunc=Something', 'E520:') call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:') call s:modeline_fails('fsync', 'fsync=Something()', 'E520:') call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:') diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim index 46fddd6c1a..c89e73bada 100644 --- a/test/old/testdir/test_normal.vim +++ b/test/old/testdir/test_normal.vim @@ -692,9 +692,9 @@ func Test_opfunc_callback() delfunc s:OpFunc3 " Using Vim9 lambda expression in legacy context should fail - " set opfunc=(a)\ =>\ OpFunc1(24,\ a) + set opfunc=(a)\ =>\ OpFunc1(24,\ a) let g:OpFunc1Args = [] - " call assert_fails('normal! g@l', 'E117:') + call assert_fails('normal! g@l', 'E117:') call assert_equal([], g:OpFunc1Args) " set 'operatorfunc' to a partial with dict. This used to cause a crash. @@ -3958,8 +3958,7 @@ func Test_mouse_shape_after_failed_change() END call writefile(lines, 'Xmouseshape.vim', 'D') call RunVim([], [], "-g -S Xmouseshape.vim") - sleep 300m - call assert_equal(['busy', 'arrow'], readfile('Xmouseshapes')) + call WaitForAssert({-> assert_equal(['busy', 'arrow'], readfile('Xmouseshapes'))}, 300) call delete('Xmouseshapes') endfunc @@ -3990,8 +3989,7 @@ func Test_mouse_shape_after_cancelling_gr() END call writefile(lines, 'Xmouseshape.vim', 'D') call RunVim([], [], "-g -S Xmouseshape.vim") - sleep 300m - call assert_equal(['beam', 'arrow'], readfile('Xmouseshapes')) + call WaitForAssert({-> assert_equal(['beam', 'arrow'], readfile('Xmouseshapes'))}, 300) call delete('Xmouseshapes') endfunc diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim index d0ae33605b..b6bdb1be52 100644 --- a/test/old/testdir/test_options.vim +++ b/test/old/testdir/test_options.vim @@ -1,8 +1,11 @@ " Test for options +source shared.vim source check.vim source view_util.vim +scriptencoding utf-8 + func Test_whichwrap() set whichwrap=b,s call assert_equal('b,s', &whichwrap) @@ -740,6 +743,7 @@ func Test_set_option_errors() call assert_fails('set backupcopy=', 'E474:') call assert_fails('set regexpengine=3', 'E474:') call assert_fails('set history=10001', 'E474:') + call assert_fails('set msghistory=10001', 'E474:') call assert_fails('set numberwidth=21', 'E474:') call assert_fails('set colorcolumn=-a', 'E474:') call assert_fails('set colorcolumn=a', 'E474:') @@ -753,6 +757,7 @@ func Test_set_option_errors() endif call assert_fails('set helpheight=-1', 'E487:') call assert_fails('set history=-1', 'E487:') + call assert_fails('set msghistory=-1', 'E487:') call assert_fails('set report=-1', 'E487:') call assert_fails('set shiftwidth=-1', 'E487:') call assert_fails('set sidescroll=-1', 'E487:') @@ -766,8 +771,47 @@ func Test_set_option_errors() call assert_fails('set updatetime=-1', 'E487:') call assert_fails('set winheight=-1', 'E487:') call assert_fails('set tabstop!', 'E488:') + + " Test for setting unknown option errors call assert_fails('set xxx', 'E518:') - call assert_fails('set beautify?', 'E518:') + call assert_fails('setlocal xxx', 'E518:') + call assert_fails('setglobal xxx', 'E518:') + call assert_fails('set xxx=', 'E518:') + call assert_fails('setlocal xxx=', 'E518:') + call assert_fails('setglobal xxx=', 'E518:') + call assert_fails('set xxx:', 'E518:') + call assert_fails('setlocal xxx:', 'E518:') + call assert_fails('setglobal xxx:', 'E518:') + call assert_fails('set xxx!', 'E518:') + call assert_fails('setlocal xxx!', 'E518:') + call assert_fails('setglobal xxx!', 'E518:') + call assert_fails('set xxx?', 'E518:') + call assert_fails('setlocal xxx?', 'E518:') + call assert_fails('setglobal xxx?', 'E518:') + call assert_fails('set xxx&', 'E518:') + call assert_fails('setlocal xxx&', 'E518:') + call assert_fails('setglobal xxx&', 'E518:') + call assert_fails('set xxx<', 'E518:') + call assert_fails('setlocal xxx<', 'E518:') + call assert_fails('setglobal xxx<', 'E518:') + + " Test for missing-options errors. + " call assert_fails('set autoprint?', 'E519:') + " call assert_fails('set beautify?', 'E519:') + " call assert_fails('set flash?', 'E519:') + " call assert_fails('set graphic?', 'E519:') + " call assert_fails('set hardtabs?', 'E519:') + " call assert_fails('set mesg?', 'E519:') + " call assert_fails('set novice?', 'E519:') + " call assert_fails('set open?', 'E519:') + " call assert_fails('set optimize?', 'E519:') + " call assert_fails('set redraw?', 'E519:') + " call assert_fails('set slowopen?', 'E519:') + " call assert_fails('set sourceany?', 'E519:') + " call assert_fails('set w300?', 'E519:') + " call assert_fails('set w1200?', 'E519:') + " call assert_fails('set w9600?', 'E519:') + call assert_fails('set undolevels=x', 'E521:') call assert_fails('set tabstop=', 'E521:') call assert_fails('set comments=-', 'E524:') @@ -779,12 +823,16 @@ func Test_set_option_errors() call assert_fails('set rulerformat=%-', 'E539:') call assert_fails('set rulerformat=%(', 'E542:') call assert_fails('set rulerformat=%15(%%', 'E542:') + + " Test for 'statusline' errors call assert_fails('set statusline=%$', 'E539:') call assert_fails('set statusline=%{', 'E540:') call assert_fails('set statusline=%{%', 'E540:') call assert_fails('set statusline=%{%}', 'E539:') call assert_fails('set statusline=%(', 'E542:') call assert_fails('set statusline=%)', 'E542:') + + " Test for 'tabline' errors call assert_fails('set tabline=%$', 'E539:') call assert_fails('set tabline=%{', 'E540:') call assert_fails('set tabline=%{%', 'E540:') @@ -801,6 +849,7 @@ func Test_set_option_errors() call assert_fails('set guicursor=r-cr:horx', 'E548:') call assert_fails('set guicursor=r-cr:hor0', 'E549:') endif + if has('mouseshape') call assert_fails('se mouseshape=i-r:x', 'E547:') endif @@ -814,15 +863,19 @@ func Test_set_option_errors() call assert_equal('.bak', &backupext) set backupext& patchmode& + " 'winheight' cannot be smaller than 'winminheight' call assert_fails('set winminheight=10 winheight=9', 'E591:') set winminheight& winheight& set winheight=10 winminheight=10 call assert_fails('set winheight=9', 'E591:') set winminheight& winheight& + + " 'winwidth' cannot be smaller than 'winminwidth' call assert_fails('set winminwidth=10 winwidth=9', 'E592:') set winminwidth& winwidth& call assert_fails('set winwidth=9 winminwidth=10', 'E592:') set winwidth& winminwidth& + call assert_fails("set showbreak=\x01", 'E595:') " call assert_fails('set t_foo=', 'E846:') call assert_fails('set tabstop??', 'E488:') @@ -842,18 +895,23 @@ func Test_set_option_errors() call assert_fails('set sessionoptions=curdir,sesdir', 'E474:') call assert_fails('set foldmarker={{{,', 'E474:') call assert_fails('set sessionoptions=sesdir,curdir', 'E474:') + + " 'ambiwidth' conflict 'listchars' setlocal listchars=trail:· call assert_fails('set ambiwidth=double', 'E834:') setlocal listchars=trail:- setglobal listchars=trail:· call assert_fails('set ambiwidth=double', 'E834:') set listchars& + + " 'ambiwidth' conflict 'fillchars' setlocal fillchars=stl:· call assert_fails('set ambiwidth=double', 'E835:') setlocal fillchars=stl:- setglobal fillchars=stl:· call assert_fails('set ambiwidth=double', 'E835:') set fillchars& + call assert_fails('set fileencoding=latin1,utf-8', 'E474:') set nomodifiable call assert_fails('set fileencoding=latin1', 'E21:') @@ -861,6 +919,8 @@ func Test_set_option_errors() " call assert_fails('set t_#-&', 'E522:') call assert_fails('let &formatoptions = "?"', 'E539:') call assert_fails('call setbufvar("", "&formatoptions", "?")', 'E539:') + + " Should raises only one error if passing a wrong variable type. call assert_fails('call setwinvar(0, "&scrolloff", [])', ['E745:', 'E745:']) call assert_fails('call setwinvar(0, "&list", [])', ['E745:', 'E745:']) call assert_fails('call setwinvar(0, "&listchars", [])', ['E730:', 'E730:']) @@ -947,6 +1007,7 @@ func Test_set_ttytype() endif endfunc +" Test for :set all func Test_set_all() set tw=75 set iskeyword=a-z,A-Z @@ -958,7 +1019,8 @@ func Test_set_all() set tw& iskeyword& splitbelow& endfunc -func Test_set_one_column() +" Test for :set! all +func Test_set_all_one_column() let out_mult = execute('set all')->split("\n") let out_one = execute('set! all')->split("\n") call assert_true(len(out_mult) < len(out_one)) @@ -967,15 +1029,6 @@ func Test_set_one_column() call assert_equal(sort(copy(options)), options) endfunc -func Test_set_values() - " opt_test.vim is generated from ../optiondefs.h using gen_opt_test.vim - if filereadable('opt_test.vim') - source opt_test.vim - else - throw 'Skipped: opt_test.vim does not exist' - endif -endfunc - func Test_renderoptions() throw 'skipped: Nvim does not support renderoptions' " Only do this for Windows Vista and later, fails on Windows XP and earlier. @@ -1335,7 +1388,8 @@ func Test_local_scrolloff() call assert_equal(5, &so) wincmd w call assert_equal(3, &so) - setlocal so< + "setlocal so< + set so< call assert_equal(5, &so) setglob so=8 call assert_equal(8, &so) @@ -1352,7 +1406,8 @@ func Test_local_scrolloff() call assert_equal(7, &siso) wincmd w call assert_equal(3, &siso) - setlocal siso< + "setlocal siso< + set siso< call assert_equal(7, &siso) setglob siso=4 call assert_equal(4, &siso) @@ -1506,40 +1561,83 @@ endfunc " Test for changing options in a sandbox func Test_opt_sandbox() - for opt in ['backupdir', 'cdpath', 'exrc'] + for opt in ['backupdir', 'cdpath', 'exrc', 'findfunc'] call assert_fails('sandbox set ' .. opt .. '?', 'E48:') call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:') endfor call assert_fails('sandbox let &modelineexpr = 1', 'E48:') endfunc -" Test for setting an option with local value to global value -func Test_opt_local_to_global() +" Test for setting string global-local option value +func Test_set_string_global_local_option() setglobal equalprg=gprg setlocal equalprg=lprg call assert_equal('gprg', &g:equalprg) call assert_equal('lprg', &l:equalprg) call assert_equal('lprg', &equalprg) + + " :set {option}< removes the local value, so that the global value will be used. set equalprg< call assert_equal('', &l:equalprg) call assert_equal('gprg', &equalprg) + + " :setlocal {option}< set the effective value of {option} to its global value. setglobal equalprg=gnewprg setlocal equalprg=lnewprg setlocal equalprg< call assert_equal('gnewprg', &l:equalprg) call assert_equal('gnewprg', &equalprg) + set equalprg& +endfunc + +" Test for setting number global-local option value +func Test_set_number_global_local_option() + setglobal scrolloff=10 + setlocal scrolloff=12 + call assert_equal(10, &g:scrolloff) + call assert_equal(12, &l:scrolloff) + call assert_equal(12, &scrolloff) + + " :setlocal {option}< set the effective value of {option} to its global value. + "set scrolloff< + setlocal scrolloff< + call assert_equal(10, &l:scrolloff) + call assert_equal(10, &scrolloff) + + " :set {option}< removes the local value, so that the global value will be used. + setglobal scrolloff=15 + setlocal scrolloff=18 + "setlocal scrolloff< + set scrolloff< + call assert_equal(-1, &l:scrolloff) + call assert_equal(15, &scrolloff) + + set scrolloff& +endfunc - " Test for setting the global/local value of a boolean option +" Test for setting boolean global-local option value +func Test_set_boolean_global_local_option() setglobal autoread setlocal noautoread - call assert_false(&autoread) - set autoread< - call assert_true(&autoread) + call assert_equal(1, &g:autoread) + call assert_equal(0, &l:autoread) + call assert_equal(0, &autoread) + + " :setlocal {option}< set the effective value of {option} to its global value. + "set autoread< + setlocal autoread< + call assert_equal(1, &l:autoread) + call assert_equal(1, &autoread) + + " :set {option}< removes the local value, so that the global value will be used. setglobal noautoread setlocal autoread - setlocal autoread< - call assert_false(&autoread) + "setlocal autoread< + set autoread< + call assert_equal(-1, &l:autoread) + call assert_equal(0, &autoread) + set autoread& endfunc @@ -1565,32 +1663,437 @@ func Test_set_in_sandbox() set filetype& endfunc -" Test for incrementing, decrementing and multiplying a number option value -func Test_opt_num_op() +" Test for setting string option value +func Test_set_string_option() + " :set {option}= + set makeprg= + call assert_equal('', &mp) + set makeprg=abc + call assert_equal('abc', &mp) + + " :set {option}: + set makeprg: + call assert_equal('', &mp) + set makeprg:abc + call assert_equal('abc', &mp) + + " Let string + let &makeprg = '' + call assert_equal('', &mp) + let &makeprg = 'abc' + call assert_equal('abc', &mp) + + " Let number converts to string + let &makeprg = 42 + call assert_equal('42', &mp) + + " Appending + set makeprg=abc + set makeprg+=def + call assert_equal('abcdef', &mp) + set makeprg+=def + call assert_equal('abcdefdef', &mp, ':set+= appends a value even if it already contained') + let &makeprg .= 'gh' + call assert_equal('abcdefdefgh', &mp) + let &makeprg ..= 'ij' + call assert_equal('abcdefdefghij', &mp) + + " Removing + set makeprg=abcdefghi + set makeprg-=def + call assert_equal('abcghi', &mp) + set makeprg-=def + call assert_equal('abcghi', &mp, ':set-= does not remove a value if it is not contained') + + " Prepending + set makeprg=abc + set makeprg^=def + call assert_equal('defabc', &mp) + set makeprg^=def + call assert_equal('defdefabc', &mp, ':set+= prepends a value even if it already contained') + + set makeprg& +endfunc + +" Test for setting string comma-separated list option value +func Test_set_string_comma_list_option() + " :set {option}= + set wildignore= + call assert_equal('', &wildignore) + set wildignore=*.png + call assert_equal('*.png', &wildignore) + + " :set {option}: + set wildignore: + call assert_equal('', &wildignore) + set wildignore:*.png + call assert_equal('*.png', &wildignore) + + " Let string + let &wildignore = '' + call assert_equal('', &wildignore) + let &wildignore = '*.png' + call assert_equal('*.png', &wildignore) + + " Let number converts to string + let &wildignore = 42 + call assert_equal('42', &wildignore) + + " Appending + set wildignore=*.png + set wildignore+=*.jpg + call assert_equal('*.png,*.jpg', &wildignore, ':set+= prepends a comma to append a value') + set wildignore+=*.jpg + call assert_equal('*.png,*.jpg', &wildignore, ':set+= does not append a value if it already contained') + set wildignore+=jpg + call assert_equal('*.png,*.jpg,jpg', &wildignore, ':set+= prepends a comma to append a value if it is not exactly match to item') + let &wildignore .= 'foo' + call assert_equal('*.png,*.jpg,jpgfoo', &wildignore, ':let-& .= appends a value without a comma') + let &wildignore ..= 'bar' + call assert_equal('*.png,*.jpg,jpgfoobar', &wildignore, ':let-& ..= appends a value without a comma') + + " Removing + set wildignore=*.png,*.jpg,*.obj + set wildignore-=*.jpg + call assert_equal('*.png,*.obj', &wildignore) + set wildignore-=*.jpg + call assert_equal('*.png,*.obj', &wildignore, ':set-= does not remove a value if it is not contained') + set wildignore-=jpg + call assert_equal('*.png,*.obj', &wildignore, ':set-= does not remove a value if it is not exactly match to item') + + " Prepending + set wildignore=*.png + set wildignore^=*.jpg + call assert_equal('*.jpg,*.png', &wildignore) + set wildignore^=*.jpg + call assert_equal('*.jpg,*.png', &wildignore, ':set+= does not prepend a value if it already contained') + set wildignore^=jpg + call assert_equal('jpg,*.jpg,*.png', &wildignore, ':set+= prepend a value if it is not exactly match to item') + + set wildignore& +endfunc + +" Test for setting string flags option value +func Test_set_string_flags_option() + " :set {option}= + set formatoptions= + call assert_equal('', &fo) + set formatoptions=abc + call assert_equal('abc', &fo) + + " :set {option}: + set formatoptions: + call assert_equal('', &fo) + set formatoptions:abc + call assert_equal('abc', &fo) + + " Let string + let &formatoptions = '' + call assert_equal('', &fo) + let &formatoptions = 'abc' + call assert_equal('abc', &fo) + + " Let number converts to string + let &formatoptions = 12 + call assert_equal('12', &fo) + + " Appending + set formatoptions=abc + set formatoptions+=pqr + call assert_equal('abcpqr', &fo) + set formatoptions+=pqr + call assert_equal('abcpqr', &fo, ':set+= does not append a value if it already contained') + let &formatoptions .= 'r' + call assert_equal('abcpqrr', &fo, ':let-& .= appends a value even if it already contained') + let &formatoptions ..= 'r' + call assert_equal('abcpqrrr', &fo, ':let-& ..= appends a value even if it already contained') + + " Removing + set formatoptions=abcpqr + set formatoptions-=cp + call assert_equal('abqr', &fo) + set formatoptions-=cp + call assert_equal('abqr', &fo, ':set-= does not remove a value if it is not contained') + set formatoptions-=ar + call assert_equal('abqr', &fo, ':set-= does not remove a value if it is not exactly match') + + " Prepending + set formatoptions=abc + set formatoptions^=pqr + call assert_equal('pqrabc', &fo) + set formatoptions^=qr + call assert_equal('pqrabc', &fo, ':set+= does not prepend a value if it already contained') + + set formatoptions& +endfunc + +" Test for setting number option value +func Test_set_number_option() + " :set {option}= + set scrolljump=5 + call assert_equal(5, &sj) + set scrolljump=-3 + call assert_equal(-3, &sj) + + " :set {option}: + set scrolljump:7 + call assert_equal(7, &sj) + set scrolljump:-5 + call assert_equal(-5, &sj) + + " Set hex + set scrolljump=0x10 + call assert_equal(16, &sj) + set scrolljump=-0x10 + call assert_equal(-16, &sj) + set scrolljump=0X12 + call assert_equal(18, &sj) + set scrolljump=-0X12 + call assert_equal(-18, &sj) + + " Set octal + set scrolljump=010 + call assert_equal(8, &sj) + set scrolljump=-010 + call assert_equal(-8, &sj) + set scrolljump=0o12 + call assert_equal(10, &sj) + set scrolljump=-0o12 + call assert_equal(-10, &sj) + set scrolljump=0O15 + call assert_equal(13, &sj) + set scrolljump=-0O15 + call assert_equal(-13, &sj) + + " Let number + let &scrolljump = 4 + call assert_equal(4, &sj) + let &scrolljump = -6 + call assert_equal(-6, &sj) + + " Let numeric string converts to number + let &scrolljump = '7' + call assert_equal(7, &sj) + let &scrolljump = '-9' + call assert_equal(-9, &sj) + + " Incrementing set shiftwidth=4 set sw+=2 call assert_equal(6, &sw) + let &shiftwidth += 2 + call assert_equal(8, &sw) + + " Decrementing + set shiftwidth=6 set sw-=2 call assert_equal(4, &sw) + let &shiftwidth -= 2 + call assert_equal(2, &sw) + + " Multiplying + set shiftwidth=4 set sw^=2 call assert_equal(8, &sw) + let &shiftwidth *= 2 + call assert_equal(16, &sw) + + set scrolljump& set shiftwidth& endfunc -" Test for setting option values using v:false and v:true -func Test_opt_boolean() +" Test for setting boolean option value +func Test_set_boolean_option() set number& + + " :set {option} set number call assert_equal(1, &nu) + + " :set no{option} set nonu call assert_equal(0, &nu) + + " :set {option}! + set number! + call assert_equal(1, &nu) + set number! + call assert_equal(0, &nu) + + " :set inv{option} + set invnumber + call assert_equal(1, &nu) + set invnumber + call assert_equal(0, &nu) + + " Let number + let &number = 1 + call assert_equal(1, &nu) + let &number = 0 + call assert_equal(0, &nu) + + " Let numeric string converts to number + let &number = '1' + call assert_equal(1, &nu) + let &number = '0' + call assert_equal(0, &nu) + + " Let v:true and v:false let &nu = v:true call assert_equal(1, &nu) let &nu = v:false call assert_equal(0, &nu) + set number& endfunc +" Test for setting string option errors +func Test_set_string_option_errors() + " :set no{option} + call assert_fails('set nomakeprg', 'E474:') + call assert_fails('setlocal nomakeprg', 'E474:') + call assert_fails('setglobal nomakeprg', 'E474:') + + " :set inv{option} + call assert_fails('set invmakeprg', 'E474:') + call assert_fails('setlocal invmakeprg', 'E474:') + call assert_fails('setglobal invmakeprg', 'E474:') + + " :set {option}! + call assert_fails('set makeprg!', 'E488:') + call assert_fails('setlocal makeprg!', 'E488:') + call assert_fails('setglobal makeprg!', 'E488:') + + " Invalid trailing chars + call assert_fails('set makeprg??', 'E488:') + call assert_fails('setlocal makeprg??', 'E488:') + call assert_fails('setglobal makeprg??', 'E488:') + call assert_fails('set makeprg&&', 'E488:') + call assert_fails('setlocal makeprg&&', 'E488:') + call assert_fails('setglobal makeprg&&', 'E488:') + call assert_fails('set makeprg<<', 'E488:') + call assert_fails('setlocal makeprg<<', 'E488:') + call assert_fails('setglobal makeprg<<', 'E488:') + call assert_fails('set makeprg@', 'E488:') + call assert_fails('setlocal makeprg@', 'E488:') + call assert_fails('setglobal makeprg@', 'E488:') + + " Invalid type + call assert_fails("let &makeprg = ['xxx']", 'E730:') +endfunc + +" Test for setting number option errors +func Test_set_number_option_errors() + " :set no{option} + call assert_fails('set notabstop', 'E474:') + call assert_fails('setlocal notabstop', 'E474:') + call assert_fails('setglobal notabstop', 'E474:') + + " :set inv{option} + call assert_fails('set invtabstop', 'E474:') + call assert_fails('setlocal invtabstop', 'E474:') + call assert_fails('setglobal invtabstop', 'E474:') + + " :set {option}! + call assert_fails('set tabstop!', 'E488:') + call assert_fails('setlocal tabstop!', 'E488:') + call assert_fails('setglobal tabstop!', 'E488:') + + " Invalid trailing chars + call assert_fails('set tabstop??', 'E488:') + call assert_fails('setlocal tabstop??', 'E488:') + call assert_fails('setglobal tabstop??', 'E488:') + call assert_fails('set tabstop&&', 'E488:') + call assert_fails('setlocal tabstop&&', 'E488:') + call assert_fails('setglobal tabstop&&', 'E488:') + call assert_fails('set tabstop<<', 'E488:') + call assert_fails('setlocal tabstop<<', 'E488:') + call assert_fails('setglobal tabstop<<', 'E488:') + call assert_fails('set tabstop@', 'E488:') + call assert_fails('setlocal tabstop@', 'E488:') + call assert_fails('setglobal tabstop@', 'E488:') + + " Not a number + call assert_fails('set tabstop=', 'E521:') + call assert_fails('setlocal tabstop=', 'E521:') + call assert_fails('setglobal tabstop=', 'E521:') + call assert_fails('set tabstop=x', 'E521:') + call assert_fails('setlocal tabstop=x', 'E521:') + call assert_fails('setglobal tabstop=x', 'E521:') + call assert_fails('set tabstop=1x', 'E521:') + call assert_fails('setlocal tabstop=1x', 'E521:') + call assert_fails('setglobal tabstop=1x', 'E521:') + call assert_fails('set tabstop=-x', 'E521:') + call assert_fails('setlocal tabstop=-x', 'E521:') + call assert_fails('setglobal tabstop=-x', 'E521:') + call assert_fails('set tabstop=0x', 'E521:') + call assert_fails('setlocal tabstop=0x', 'E521:') + call assert_fails('setglobal tabstop=0x', 'E521:') + call assert_fails('set tabstop=0o', 'E521:') + call assert_fails('setlocal tabstop=0o', 'E521:') + call assert_fails('setglobal tabstop=0o', 'E521:') + call assert_fails("let &tabstop = 'x'", 'E521:') + call assert_fails("let &g:tabstop = 'x'", 'E521:') + call assert_fails("let &l:tabstop = 'x'", 'E521:') + + " Invalid type + call assert_fails("let &tabstop = 'xxx'", 'E521:') +endfunc + +" Test for setting boolean option errors +func Test_set_boolean_option_errors() + " :set {option}= + call assert_fails('set number=', 'E474:') + call assert_fails('setlocal number=', 'E474:') + call assert_fails('setglobal number=', 'E474:') + call assert_fails('set number=1', 'E474:') + call assert_fails('setlocal number=1', 'E474:') + call assert_fails('setglobal number=1', 'E474:') + + " :set {option}: + call assert_fails('set number:', 'E474:') + call assert_fails('setlocal number:', 'E474:') + call assert_fails('setglobal number:', 'E474:') + call assert_fails('set number:1', 'E474:') + call assert_fails('setlocal number:1', 'E474:') + call assert_fails('setglobal number:1', 'E474:') + + " :set {option}+= + call assert_fails('set number+=1', 'E474:') + call assert_fails('setlocal number+=1', 'E474:') + call assert_fails('setglobal number+=1', 'E474:') + + " :set {option}^= + call assert_fails('set number^=1', 'E474:') + call assert_fails('setlocal number^=1', 'E474:') + call assert_fails('setglobal number^=1', 'E474:') + + " :set {option}-= + call assert_fails('set number-=1', 'E474:') + call assert_fails('setlocal number-=1', 'E474:') + call assert_fails('setglobal number-=1', 'E474:') + + " Invalid trailing chars + call assert_fails('set number!!', 'E488:') + call assert_fails('setlocal number!!', 'E488:') + call assert_fails('setglobal number!!', 'E488:') + call assert_fails('set number??', 'E488:') + call assert_fails('setlocal number??', 'E488:') + call assert_fails('setglobal number??', 'E488:') + call assert_fails('set number&&', 'E488:') + call assert_fails('setlocal number&&', 'E488:') + call assert_fails('setglobal number&&', 'E488:') + call assert_fails('set number<<', 'E488:') + call assert_fails('setlocal number<<', 'E488:') + call assert_fails('setglobal number<<', 'E488:') + call assert_fails('set number@', 'E488:') + call assert_fails('setlocal number@', 'E488:') + call assert_fails('setglobal number@', 'E488:') + + " Invalid type + call assert_fails("let &number = 'xxx'", 'E521:') +endfunc + " Test for the 'window' option func Test_window_opt() " Needs only one open widow @@ -2289,4 +2792,24 @@ func Test_delcombine() bwipe! endfunc +" Should not raise errors when set missing-options. +func Test_set_missing_options() + throw 'Skipped: N/A' + set autoprint + set beautify + set flash + set graphic + set hardtabs=8 + set mesg + set novice + set open + set optimize + set redraw + set slowopen + set sourceany + set w300=23 + set w1200=23 + set w9600=23 +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_options_all.vim b/test/old/testdir/test_options_all.vim new file mode 100644 index 0000000000..a2330ecb90 --- /dev/null +++ b/test/old/testdir/test_options_all.vim @@ -0,0 +1,13 @@ +" Test for options + +" opt_test.vim is generated from src/optiondefs.h and runtime/doc/options.txt +" using gen_opt_test.vim +if filereadable('opt_test.vim') + source opt_test.vim +else + func Test_set_values() + throw 'Skipped: opt_test.vim does not exist' + endfunc +endif + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_popup.vim b/test/old/testdir/test_popup.vim index 472882fb87..601ba6c688 100644 --- a/test/old/testdir/test_popup.vim +++ b/test/old/testdir/test_popup.vim @@ -1506,20 +1506,31 @@ func Test_pum_highlights_match() call StopVimInTerminal(buf) endfunc -func Test_pum_user_hl_group() +func Test_pum_user_abbr_hlgroup() CheckScreendump let lines =<< trim END - func CompleteFunc( findstart, base ) + let s:var = 0 + func CompleteFunc(findstart, base) if a:findstart return 0 endif + if s:var == 1 + return { + \ 'words': [ + \ { 'word': 'aword1', 'abbr_hlgroup': 'StrikeFake' }, + \ { 'word': '你好', 'abbr_hlgroup': 'StrikeFake' }, + \]} + endif return { \ 'words': [ - \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' }, + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'abbr_hlgroup': 'StrikeFake' }, \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', }, - \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' }, + \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'abbr_hlgroup': 'StrikeFake' }, \]} endfunc + func ChangeVar() + let s:var = 1 + endfunc set completeopt=menu set completefunc=CompleteFunc @@ -1547,19 +1558,26 @@ func Test_pum_user_hl_group() call VerifyScreenDump(buf, 'Test_pum_highlights_14', {}) call term_sendkeys(buf, "\<C-E>\<Esc>") + call TermWait(buf) + call term_sendkeys(buf, ":call ChangeVar()\<CR>") + call TermWait(buf) + call term_sendkeys(buf, "S\<C-X>\<C-U>") + call VerifyScreenDump(buf, 'Test_pum_highlights_17', {}) + call term_sendkeys(buf, "\<C-E>\<Esc>") + call StopVimInTerminal(buf) endfunc func Test_pum_user_kind_hlgroup() CheckScreendump let lines =<< trim END - func CompleteFunc( findstart, base ) + func CompleteFunc(findstart, base) if a:findstart return 0 endif return { \ 'words': [ - \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'hl_group': 'StrikeFake' }, + \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'abbr_hlgroup': 'StrikeFake' }, \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'function', 'kind_hlgroup': 'KindFunc' }, \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'class', 'kind_hlgroup': 'KindClass' }, \]} diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim index 753875963b..ca48812e7d 100644 --- a/test/old/testdir/test_quickfix.vim +++ b/test/old/testdir/test_quickfix.vim @@ -6340,6 +6340,106 @@ func Test_quickfix_buffer_contents() call setqflist([], 'f') endfunc +func XquickfixUpdateTests(cchar) + call s:setup_commands(a:cchar) + + " Setup: populate a couple buffers + new + call setline(1, range(1, 5)) + let b1 = bufnr() + new + call setline(1, range(1, 3)) + let b2 = bufnr() + " Setup: set a quickfix list. + let items = [{'bufnr': b1, 'lnum': 1}, {'bufnr': b1, 'lnum': 2}, {'bufnr': b2, 'lnum': 1}, {'bufnr': b2, 'lnum': 2}] + call g:Xsetlist(items) + + " Open the quickfix list, select the third entry. + Xopen + exe "normal jj\<CR>" + call assert_equal(3, g:Xgetlist({'idx' : 0}).idx) + + " Update the quickfix list. Make sure the third entry is still selected. + call g:Xsetlist([], 'u', { 'items': items }) + call assert_equal(3, g:Xgetlist({'idx' : 0}).idx) + + " Update the quickfix list again, but this time with missing line number + " information. Confirm that we keep the current buffer selected. + call g:Xsetlist([{'bufnr': b1}, {'bufnr': b2}], 'u') + call assert_equal(2, g:Xgetlist({'idx' : 0}).idx) + + Xclose + + " Cleanup the buffers we allocated during this test. + %bwipe! +endfunc + +" Test for updating a quickfix list using the "u" flag in setqflist() +func Test_quickfix_update() + call XquickfixUpdateTests('c') + call XquickfixUpdateTests('l') +endfunc + +func Test_quickfix_update_with_missing_coordinate_info() + new + call setline(1, range(1, 5)) + let b1 = bufnr() + + new + call setline(1, range(1, 3)) + let b2 = bufnr() + + new + call setline(1, range(1, 2)) + let b3 = bufnr() + + " Setup: set a quickfix list with no coordinate information at all. + call setqflist([{}, {}]) + + " Open the quickfix list, select the second entry. + copen + exe "normal j\<CR>" + call assert_equal(2, getqflist({'idx' : 0}).idx) + + " Update the quickfix list. As the previously selected entry has no + " coordinate information, we expect the first entry to now be selected. + call setqflist([{'bufnr': b1}, {'bufnr': b2}, {'bufnr': b3}], 'u') + call assert_equal(1, getqflist({'idx' : 0}).idx) + + " Select the second entry in the quickfix list. + copen + exe "normal j\<CR>" + call assert_equal(2, getqflist({'idx' : 0}).idx) + + " Update the quickfix list again. The currently selected entry does not have + " a line number, but we should keep the file selected. + call setqflist([{'bufnr': b1}, {'bufnr': b2, 'lnum': 3}, {'bufnr': b3}], 'u') + call assert_equal(2, getqflist({'idx' : 0}).idx) + + " Update the quickfix list again. The currently selected entry (bufnr=b2, lnum=3) + " is no longer present. We should pick the nearest entry. + call setqflist([{'bufnr': b1}, {'bufnr': b2, 'lnum': 1}, {'bufnr': b2, 'lnum': 4}], 'u') + call assert_equal(3, getqflist({'idx' : 0}).idx) + + " Set the quickfix list again, with a specific column number. The currently selected entry doesn't have a + " column number, but they share a line number. + call setqflist([{'bufnr': b1}, {'bufnr': b2, 'lnum': 4, 'col': 5}, {'bufnr': b2, 'lnum': 4, 'col': 6}], 'u') + call assert_equal(2, getqflist({'idx' : 0}).idx) + + " Set the quickfix list again. The currently selected column number (6) is + " no longer present. We should select the nearest column number. + call setqflist([{'bufnr': b1}, {'bufnr': b2, 'lnum': 4, 'col': 2}, {'bufnr': b2, 'lnum': 4, 'col': 4}], 'u') + call assert_equal(3, getqflist({'idx' : 0}).idx) + + " Now set the quickfix list, but without columns. We should still pick the + " same line. + call setqflist([{'bufnr': b2, 'lnum': 3}, {'bufnr': b2, 'lnum': 4}, {'bufnr': b2, 'lnum': 4}], 'u') + call assert_equal(2, getqflist({'idx' : 0}).idx) + + " Cleanup the buffers we allocated during this test. + %bwipe! +endfunc + " Test for "%b" in "errorformat" func Test_efm_format_b() call setqflist([], 'f') @@ -6459,8 +6559,8 @@ func Test_cbuffer_range() call XbufferTests_range('l') endfunc -" Test for displaying fname pass from setqflist when the name -" are hard links to prevent seemly duplicate entries. +" Test for displaying fname passed from setqflist() when the names include +" hard links to prevent seemingly duplicate entries. func Xtest_hardlink_fname(cchar) call s:setup_commands(a:cchar) %bwipe diff --git a/test/old/testdir/test_spellfile.vim b/test/old/testdir/test_spellfile.vim index 48e46641f4..f356b12370 100644 --- a/test/old/testdir/test_spellfile.vim +++ b/test/old/testdir/test_spellfile.vim @@ -1155,7 +1155,7 @@ endfunc " 'spellfile' accepts '@' on top of 'isfname'. func Test_spellfile_allow_at_character() call mkdir('Xtest/the foo@bar,dir', 'p') - let &spellfile = './Xtest/the foo@bar,dir/Xspellfile.add' + let &spellfile = './Xtest/the foo@bar\,dir/Xspellfile.add' let &spellfile = '' call delete('Xtest', 'rf') endfunc diff --git a/test/old/testdir/test_swap.vim b/test/old/testdir/test_swap.vim index 8a1b3ce133..e174356ed7 100644 --- a/test/old/testdir/test_swap.vim +++ b/test/old/testdir/test_swap.vim @@ -420,7 +420,7 @@ func s:get_unused_pid(base) if has('job') " Execute 'echo' as a temporary job, and return its pid as an unused pid. if has('win32') - let cmd = 'cmd /c echo' + let cmd = 'cmd /D /c echo' else let cmd = 'echo' endif diff --git a/test/old/testdir/test_tagfunc.vim b/test/old/testdir/test_tagfunc.vim index 812603a430..ec1f93e9be 100644 --- a/test/old/testdir/test_tagfunc.vim +++ b/test/old/testdir/test_tagfunc.vim @@ -291,10 +291,10 @@ func Test_tagfunc_callback() call assert_fails("echo taglist('a')", "E987:") " Using Vim9 lambda expression in legacy context should fail - " set tagfunc=(a,\ b,\ c)\ =>\ g:TagFunc1(21,\ a,\ b,\ c) + set tagfunc=(a,\ b,\ c)\ =>\ g:TagFunc1(21,\ a,\ b,\ c) new let g:TagFunc1Args = [] - " call assert_fails("tag a17", "E117:") + call assert_fails("tag a17", "E117:") call assert_equal([], g:TagFunc1Args) bw! diff --git a/test/old/testdir/test_undo.vim b/test/old/testdir/test_undo.vim index a207f4f4e0..d876277850 100644 --- a/test/old/testdir/test_undo.vim +++ b/test/old/testdir/test_undo.vim @@ -187,7 +187,8 @@ func Test_global_local_undolevels() " Resetting the local 'undolevels' value to use the global value setlocal undolevels=5 - setlocal undolevels< + "setlocal undolevels< + set undolevels< call assert_equal(-123456, &l:undolevels) " Drop created windows diff --git a/test/old/testdir/test_window_cmd.vim b/test/old/testdir/test_window_cmd.vim index 50da2beb40..8048fa6ff8 100644 --- a/test/old/testdir/test_window_cmd.vim +++ b/test/old/testdir/test_window_cmd.vim @@ -539,7 +539,7 @@ func Test_equalalways_on_close() 1wincmd w split 4wincmd w - resize + 5 + resize +5 " left column has three windows, equalized heights. " right column has two windows, top one a bit higher let height_1 = winheight(1) diff --git a/test/old/testdir/test_windows_home.vim b/test/old/testdir/test_windows_home.vim index 3c2db01444..0f86124d3e 100644 --- a/test/old/testdir/test_windows_home.vim +++ b/test/old/testdir/test_windows_home.vim @@ -105,7 +105,7 @@ func Test_WindowsHome() RestoreEnv let $HOME = save_home let env = '' - let job = job_start('cmd /c set', {'out_cb': {ch,x->[env,execute('let env=x')]}}) + let job = job_start('cmd /D /c set', {'out_cb': {ch,x->[env,execute('let env=x')]}}) sleep 1 let env = filter(split(env, "\n"), 'v:val=="HOME"') let home = len(env) == 0 ? "" : env[0] diff --git a/test/testutil.lua b/test/testutil.lua index a920f658a1..00b30d74d5 100644 --- a/test/testutil.lua +++ b/test/testutil.lua @@ -392,9 +392,7 @@ function M.check_logs() ) end -local function sysname() - return uv.os_uname().sysname:lower() -end +local sysname = uv.os_uname().sysname:lower() --- @param s 'win'|'mac'|'freebsd'|'openbsd'|'bsd' --- @return boolean @@ -403,48 +401,27 @@ function M.is_os(s) error('unknown platform: ' .. tostring(s)) end return not not ( - (s == 'win' and (sysname():find('windows') or sysname():find('mingw'))) - or (s == 'mac' and sysname() == 'darwin') - or (s == 'freebsd' and sysname() == 'freebsd') - or (s == 'openbsd' and sysname() == 'openbsd') - or (s == 'bsd' and sysname():find('bsd')) + (s == 'win' and (sysname:find('windows') or sysname:find('mingw'))) + or (s == 'mac' and sysname == 'darwin') + or (s == 'freebsd' and sysname == 'freebsd') + or (s == 'openbsd' and sysname == 'openbsd') + or (s == 'bsd' and sysname:find('bsd')) ) end -local function tmpdir_get() - return os.getenv('TMPDIR') and os.getenv('TMPDIR') or os.getenv('TEMP') -end - ---- Is temp directory `dir` defined local to the project workspace? ---- @param dir string? ---- @return boolean -local function tmpdir_is_local(dir) - return not not (dir and dir:find('Xtest')) -end - local tmpname_id = 0 -local tmpdir = tmpdir_get() +local tmpdir = os.getenv('TMPDIR') or os.getenv('TEMP') +local tmpdir_is_local = not not (tmpdir and tmpdir:find('Xtest')) ---- Generates a unique filepath for use by tests, in a test-specific "…/Xtest_tmpdir/T42.7" ---- directory (which is cleaned up by the test runner), and writes the file unless `create=false`. ---- ----@param create? boolean (default true) Write the file. -function M.tmpname(create) - if tmpdir_is_local(tmpdir) then +local function get_tmpname() + if tmpdir_is_local then -- Cannot control os.tmpname() dir, so hack our own tmpname() impl. tmpname_id = tmpname_id + 1 -- "…/Xtest_tmpdir/T42.7" - local fname = ('%s/%s.%d'):format(tmpdir, (_G._nvim_test_id or 'nvim-test'), tmpname_id) - if create ~= false then - io.open(fname, 'w'):close() - end - return fname + return ('%s/%s.%d'):format(tmpdir, (_G._nvim_test_id or 'nvim-test'), tmpname_id) end local fname = os.tmpname() - if create == false then - os.remove(fname) - end if M.is_os('win') and fname:sub(1, 2) == '\\s' then -- In Windows tmpname() returns a filename starting with @@ -454,7 +431,20 @@ function M.tmpname(create) -- In OS X /tmp links to /private/tmp return '/private' .. fname end + return fname +end +--- Generates a unique filepath for use by tests, in a test-specific "…/Xtest_tmpdir/T42.7" +--- directory (which is cleaned up by the test runner). +--- +--- @param create? boolean (default true) Create the file. +--- @return string +function M.tmpname(create) + local fname = get_tmpname() + os.remove(fname) + if create ~= false then + assert(io.open(fname, 'w')):close() + end return fname end @@ -479,11 +469,11 @@ function M.check_cores(app, force) -- luacheck: ignore local random_skip = false -- Workspace-local $TMPDIR, scrubbed and pattern-escaped. -- "./Xtest-tmpdir/" => "Xtest%-tmpdir" - local local_tmpdir = ( - tmpdir_is_local(tmpdir_get()) - and relpath(tmpdir_get()):gsub('^[ ./]+', ''):gsub('%/+$', ''):gsub('([^%w])', '%%%1') - or nil - ) + local local_tmpdir = nil + if tmpdir_is_local and tmpdir then + local_tmpdir = vim.pesc(relpath(tmpdir):gsub('^[ ./]+', ''):gsub('%/+$', '')) + end + local db_cmd --- @type string local test_glob_dir = os.getenv('NVIM_TEST_CORE_GLOB_DIRECTORY') if test_glob_dir and test_glob_dir ~= '' then diff --git a/test/unit/testutil.lua b/test/unit/testutil.lua index a6db7beab1..4720d4d730 100644 --- a/test/unit/testutil.lua +++ b/test/unit/testutil.lua @@ -151,6 +151,13 @@ local function filter_complex_blocks(body) or string.find(line, 'mach_vm_range_recipe') ) then + -- HACK: remove bitfields from specific structs as luajit can't seem to handle them. + if line:find('struct VTermState') then + line = string.gsub(line, 'state : 8;', 'state;') + end + if line:find('VTermStringFragment') then + line = string.gsub(line, 'size_t.*len : 30;', 'size_t len;') + end result[#result + 1] = line end end diff --git a/test/unit/vterm_spec.lua b/test/unit/vterm_spec.lua new file mode 100644 index 0000000000..4ea5d9c29a --- /dev/null +++ b/test/unit/vterm_spec.lua @@ -0,0 +1,3591 @@ +local t = require('test.unit.testutil') +local itp = t.gen_itp(it) +local bit = require('bit') + +--- @class vterm +--- @field ENC_UTF8 integer +--- @field VTERM_ATTR_BLINK integer +--- @field VTERM_ATTR_BOLD integer +--- @field VTERM_ATTR_FONT integer +--- @field VTERM_ATTR_ITALIC integer +--- @field VTERM_ATTR_REVERSE integer +--- @field VTERM_ATTR_UNDERLINE integer +--- @field VTERM_BASELINE_RAISE integer +--- @field VTERM_KEY_ENTER integer +--- @field VTERM_KEY_FUNCTION_0 integer +--- @field VTERM_KEY_KP_0 integer +--- @field VTERM_KEY_NONE integer +--- @field VTERM_KEY_TAB integer +--- @field VTERM_KEY_UP integer +--- @field VTERM_MAX_CHARS_PER_CELL integer +--- @field VTERM_MOD_ALT integer +--- @field VTERM_MOD_CTRL integer +--- @field VTERM_MOD_SHIFT integer +--- @field parser_apc function +--- @field parser_csi function +--- @field parser_dcs function +--- @field parser_osc function +--- @field parser_pm function +--- @field parser_sos function +--- @field parser_text function +--- @field print_color function +--- @field screen_sb_clear function +--- @field screen_sb_popline function +--- @field screen_sb_pushline function +--- @field selection_query function +--- @field selection_set function +--- @field state_erase function +--- @field state_movecursor function +--- @field state_moverect function +--- @field state_pos function +--- @field state_putglyph function +--- @field state_sb_clear function +--- @field state_scrollrect function +--- @field state_setpenattr function +--- @field state_settermprop function +--- @field term_output function +--- @field vterm_input_write function +--- @field vterm_keyboard_end_paste function +--- @field vterm_keyboard_key function +--- @field vterm_keyboard_start_paste function +--- @field vterm_keyboard_unichar function +--- @field vterm_lookup_encoding fun(any, any):any +--- @field vterm_mouse_button function +--- @field vterm_mouse_move function +--- @field vterm_new fun(any, any):any +--- @field vterm_obtain_screen fun(any):any +--- @field vterm_obtain_state fun(any): any +--- @field vterm_output_set_callback function +--- @field vterm_parser_set_callbacks fun(any, any, any):any +--- @field vterm_screen_convert_color_to_rgb function +--- @field vterm_screen_enable_altscreen function +--- @field vterm_screen_enable_reflow function +--- @field vterm_screen_get_attrs_extent function +--- @field vterm_screen_get_cell function +--- @field vterm_screen_get_chars fun(any, any, any, any):any +--- @field vterm_screen_get_text fun(any, any, any, any):any +--- @field vterm_screen_is_eol fun(any, any):any +--- @field vterm_screen_reset function +--- @field vterm_screen_set_callbacks function +--- @field vterm_set_size function +--- @field vterm_set_utf8 fun(any, any, any):any +--- @field vterm_state_focus_in function +--- @field vterm_state_focus_out function +--- @field vterm_state_get_cursorpos fun(any, any) +--- @field vterm_state_get_lineinfo fun(any, any):any +--- @field vterm_state_get_penattr function +--- @field vterm_state_reset function +--- @field vterm_state_set_bold_highbright function +--- @field vterm_state_set_callbacks function +--- @field vterm_state_set_selection_callbacks function +--- @field vterm_state_set_unrecognised_fallbacks function +local vterm = t.cimport('./src/vterm/vterm.h', './src/vterm/vterm_internal.h') + +--- @return string +local function read_rm() + local f = assert(io.open(t.paths.vterm_test_file, 'rb')) + local text = f:read('*a') + f:close() + vim.fs.rm(t.paths.vterm_test_file, { force = true }) + return text +end + +local function append(str) + local f = assert(io.open(t.paths.vterm_test_file, 'a')) + f:write(str) + f:close() + return 1 +end + +local function parser_control(control) + return append(string.format('control %02x\n', control)) +end + +local function parser_escape(bytes) + return append(string.format('escape %s\n', t.ffi.string(bytes))) +end + +local function wantparser(vt) + assert(vt) + + local parser_cbs = t.ffi.new('VTermParserCallbacks') + parser_cbs['text'] = vterm.parser_text + parser_cbs['control'] = parser_control + parser_cbs['escape'] = parser_escape + parser_cbs['csi'] = vterm.parser_csi + parser_cbs['osc'] = vterm.parser_osc + parser_cbs['dcs'] = vterm.parser_dcs + parser_cbs['apc'] = vterm.parser_apc + parser_cbs['pm'] = vterm.parser_pm + parser_cbs['sos'] = vterm.parser_sos + + vterm.vterm_parser_set_callbacks(vt, parser_cbs, nil) +end + +--- @return any +local function init() + local vt = vterm.vterm_new(25, 80) + vterm.vterm_output_set_callback(vt, vterm.term_output, nil) + vterm.vterm_set_utf8(vt, true) + return vt +end + +local function state_setlineinfo() + return 1 +end + +--- @return any +local function wantstate(vt, opts) + opts = opts or {} + assert(vt) + local state = vterm.vterm_obtain_state(vt) + + local state_cbs = t.ffi.new('VTermStateCallbacks') + state_cbs['putglyph'] = vterm.state_putglyph + state_cbs['movecursor'] = vterm.state_movecursor + state_cbs['scrollrect'] = vterm.state_scrollrect + state_cbs['moverect'] = vterm.state_moverect + state_cbs['erase'] = vterm.state_erase + state_cbs['setpenattr'] = vterm.state_setpenattr + state_cbs['settermprop'] = vterm.state_settermprop + state_cbs['setlineinfo'] = state_setlineinfo + state_cbs['sb_clear'] = vterm.state_sb_clear + + local selection_cbs = t.ffi.new('VTermSelectionCallbacks') + selection_cbs['set'] = vterm.selection_set + selection_cbs['query'] = vterm.selection_query + + vterm.vterm_state_set_callbacks(state, state_cbs, nil) + + -- In some tests we want to check the behaviour of overflowing the buffer, so make it nicely small + vterm.vterm_state_set_selection_callbacks(state, selection_cbs, nil, nil, 16) + vterm.vterm_state_set_bold_highbright(state, 1) + vterm.vterm_state_reset(state, 1) + + local fallbacks = t.ffi.new('VTermStateFallbacks') + fallbacks['control'] = parser_control + fallbacks['csi'] = vterm.parser_csi + fallbacks['osc'] = vterm.parser_osc + fallbacks['dcs'] = vterm.parser_dcs + fallbacks['apc'] = vterm.parser_apc + fallbacks['pm'] = vterm.parser_pm + fallbacks['sos'] = vterm.parser_sos + + vterm.want_state_scrollback = opts.b or false + vterm.want_state_erase = opts.e or false + vterm.vterm_state_set_unrecognised_fallbacks(state, opts.f and fallbacks or nil, nil) + vterm.want_state_putglyph = opts.g or false + vterm.want_state_moverect = opts.m or false + vterm.want_state_settermprop = opts.p or false + vterm.want_state_scrollrect = opts.s or false + + return state +end + +--- @return any +local function wantscreen(vt, opts) + opts = opts or {} + local screen = vterm.vterm_obtain_screen(vt) + local screen_cbs = t.ffi.new('VTermScreenCallbacks') + + -- TODO(dundargoc): fix + -- screen_cbs['damage'] = vterm.screen_damage + screen_cbs['moverect'] = vterm.state_moverect + screen_cbs['movecursor'] = vterm.state_movecursor + screen_cbs['settermprop'] = vterm.state_settermprop + screen_cbs['sb_pushline'] = vterm.screen_sb_pushline + screen_cbs['sb_popline'] = vterm.screen_sb_popline + screen_cbs['sb_clear'] = vterm.screen_sb_clear + + vterm.vterm_screen_set_callbacks(screen, screen_cbs, nil) + + if opts.a then + vterm.vterm_screen_enable_altscreen(screen, 1) + end + vterm.want_screen_scrollback = opts.b or false + vterm.want_state_movecursor = opts.c or false + -- TODO(dundargoc): fix + -- vterm.want_screen_damage = opts.d or opts.D or false + -- vterm.want_screen_cells = opts.D or false + vterm.want_state_moverect = opts.m or false + vterm.want_state_settermprop = opts.p or false + if opts.r then + vterm.vterm_screen_enable_reflow(screen, true) + end + + return screen +end + +local function reset(state, screen) + if state then + vterm.vterm_state_reset(state, 1) + vterm.vterm_state_get_cursorpos(state, vterm.state_pos) + end + if screen then + vterm.vterm_screen_reset(screen, 1) + end +end + +local function push(input, vt) + vterm.vterm_input_write(vt, input, string.len(input)) +end + +local function expect(expected) + local actual = read_rm() + t.eq(expected .. '\n', actual) +end + +local function expect_output(expected_preformat) + local actual = read_rm() + local expected = 'output ' + + for c in string.gmatch(expected_preformat, '.') do + if expected ~= 'output ' then + expected = expected .. ',' + end + expected = string.format('%s%x', expected, string.byte(c)) + end + + t.eq(expected .. '\n', actual) +end + +local function cursor(row, col, state) + local pos = t.ffi.new('VTermPos') --- @type {row: integer, col: integer} + vterm.vterm_state_get_cursorpos(state, pos) + t.eq(row, pos.row) + t.eq(col, pos.col) +end + +local function lineinfo(row, expected, state) + local info = vterm.vterm_state_get_lineinfo(state, row) + local dwl = info.doublewidth == 1 + local dhl = info.doubleheight == 1 + local cont = info.continuation == 1 + + t.eq(dwl, expected.dwl or false) + t.eq(dhl, expected.dhl or false) + t.eq(cont, expected.cont or false) +end + +local function pen(attribute, expected, state) + local is_bool = { bold = true, italic = true, blink = true, reverse = true } + local vterm_attribute = { + bold = vterm.VTERM_ATTR_BOLD, + underline = vterm.VTERM_ATTR_UNDERLINE, + italic = vterm.VTERM_ATTR_ITALIC, + blink = vterm.VTERM_ATTR_BLINK, + reverse = vterm.VTERM_ATTR_REVERSE, + font = vterm.VTERM_ATTR_FONT, + } + + local val = t.ffi.new('VTermValue') --- @type {boolean: integer} + vterm.vterm_state_get_penattr(state, vterm_attribute[attribute], val) + local actual = val.boolean --- @type integer|boolean + if is_bool[attribute] then + actual = val.boolean == 1 + end + t.eq(expected, actual) +end + +local function resize(rows, cols, vt) + vterm.vterm_set_size(vt, rows, cols) +end + +local function screen_chars(start_row, start_col, end_row, end_col, expected, screen) + local rect = t.ffi.new('VTermRect') + rect['start_row'] = start_row + rect['start_col'] = start_col + rect['end_row'] = end_row + rect['end_col'] = end_col + + local len = vterm.vterm_screen_get_chars(screen, nil, 0, rect) + + local chars = t.ffi.new('uint32_t[?]', len) + vterm.vterm_screen_get_chars(screen, chars, len, rect) + + local actual = '' + for i = 0, tonumber(len) - 1 do + actual = actual .. string.char(chars[i]) + end + + t.eq(expected, actual) +end + +local function screen_text(start_row, start_col, end_row, end_col, expected, screen) + local rect = t.ffi.new('VTermRect') + rect['start_row'] = start_row + rect['start_col'] = start_col + rect['end_row'] = end_row + rect['end_col'] = end_col + + local len = vterm.vterm_screen_get_text(screen, nil, 0, rect) + + local text = t.ffi.new('unsigned char[?]', len) + vterm.vterm_screen_get_text(screen, text, len, rect) + + local actual = '' + for i = 0, tonumber(len) - 1 do + actual = string.format('%s%02x,', actual, text[i]) + end + actual = actual:sub(1, -2) + + t.eq(expected, actual) +end + +--- @param row integer +local function screen_row(row, expected, screen, end_col) + local rect = t.ffi.new('VTermRect') + rect['start_row'] = row + rect['start_col'] = 0 + rect['end_row'] = row + 1 + rect['end_col'] = end_col or 80 + + local len = vterm.vterm_screen_get_text(screen, nil, 0, rect) + + local text = t.ffi.new('unsigned char[?]', len) + vterm.vterm_screen_get_text(screen, text, len, rect) + + t.eq(expected, t.ffi.string(text)) +end + +local function screen_cell(row, col, expected, screen) + local pos = t.ffi.new('VTermPos') + pos['row'] = row + pos['col'] = col + + local cell = t.ffi.new('VTermScreenCell') + vterm.vterm_screen_get_cell(screen, pos, cell) + + local actual = '{' + for i = 0, vterm.VTERM_MAX_CHARS_PER_CELL - 1 do + if cell['chars'][i] ~= 0 then + if i > 0 then + actual = actual .. ',' + end + actual = string.format('%s%02x', actual, cell['chars'][i]) + end + end + actual = string.format('%s} width=%d attrs={', actual, cell['width']) + actual = actual .. (cell['attrs'].bold ~= 0 and 'B' or '') + actual = actual + .. (cell['attrs'].underline ~= 0 and string.format('U%d', cell['attrs'].underline) or '') + actual = actual .. (cell['attrs'].italic ~= 0 and 'I' or '') + actual = actual .. (cell['attrs'].blink ~= 0 and 'K' or '') + actual = actual .. (cell['attrs'].reverse ~= 0 and 'R' or '') + actual = actual .. (cell['attrs'].font ~= 0 and string.format('F%d', cell['attrs'].font) or '') + actual = actual .. (cell['attrs'].small ~= 0 and 'S' or '') + if cell['attrs'].baseline ~= 0 then + actual = actual .. (cell['attrs'].baseline == vterm.VTERM_BASELINE_RAISE and '^' or '_') + end + actual = actual .. '} ' + + actual = actual .. (cell['attrs'].dwl ~= 0 and 'dwl ' or '') + if cell['attrs'].dhl ~= 0 then + actual = actual .. string.format('dhl-%s ', cell['attrs'].dhl == 2 and 'bottom' or 'top') + end + + actual = string.format('%sfg=', actual) + vterm.vterm_screen_convert_color_to_rgb(screen, cell['fg']) + vterm.print_color(cell['fg']) + + actual = actual .. read_rm() + actual = actual .. ' bg=' + + vterm.vterm_screen_convert_color_to_rgb(screen, cell['bg']) + vterm.print_color(cell['bg']) + + actual = actual .. read_rm() + + t.eq(expected, actual) +end + +local function screen_eol(row, col, expected, screen) + local pos = t.ffi.new('VTermPos') + pos['row'] = row + pos['col'] = col + + local is_eol = vterm.vterm_screen_is_eol(screen, pos) + t.eq(expected, is_eol) +end + +local function screen_attrs_extent(row, col, expected, screen) + local pos = t.ffi.new('VTermPos') + pos['row'] = row + pos['col'] = col + + local rect = t.ffi.new('VTermRect') + rect['start_col'] = 0 + rect['end_col'] = -1 + vterm.vterm_screen_get_attrs_extent(screen, rect, pos, 1) + + local actual = string.format( + '%d,%d-%d,%d', + rect['start_row'], + rect['start_col'], + rect['end_row'], + rect['end_col'] + ) + + t.eq(expected, actual) +end + +local function wantencoding() + local encoding = t.ffi.new('VTermEncodingInstance') + encoding['enc'] = vterm.vterm_lookup_encoding(vterm.ENC_UTF8, string.byte('u')) + if encoding.enc.init then + encoding.enc.init(encoding.enc, encoding['data']) + end + return encoding +end + +local function encin(input, encoding) + local len = string.len(input) + + local cp = t.ffi.new('uint32_t[?]', len) + local cpi = t.ffi.new('int[1]') + local pos = t.ffi.new('size_t[1]', 0) + + encoding.enc.decode(encoding.enc, encoding.data, cp, cpi, len, input, pos, len) + + local f = assert(io.open(t.paths.vterm_test_file, 'w')) + if tonumber(cpi[0]) > 0 then + f:write('encout ') + for i = 0, cpi[0] - 1 do + if i == 0 then + f:write(string.format('%x', cp[i])) + else + f:write(string.format(',%x', cp[i])) + end + end + f:write('\n') + end + f:close() +end + +local function strpe_modifiers(input_mod) + local mod = t.ffi.new('VTermModifier') ---@type any + if input_mod.C then + mod = bit.bor(mod, vterm.VTERM_MOD_CTRL) + end + if input_mod.S then + mod = bit.bor(mod, vterm.VTERM_MOD_SHIFT) + end + if input_mod.A then + mod = bit.bor(mod, vterm.VTERM_MOD_ALT) + end + return mod +end + +local function strp_key(input_key) + if input_key == 'up' then + return vterm.VTERM_KEY_UP + end + + if input_key == 'tab' then + return vterm.VTERM_KEY_TAB + end + + if input_key == 'enter' then + return vterm.VTERM_KEY_ENTER + end + + if input_key == 'f1' then + return vterm.VTERM_KEY_FUNCTION_0 + 1 + end + + if input_key == 'kp0' then + return vterm.VTERM_KEY_KP_0 + end + + return vterm.VTERM_KEY_NONE +end + +local function mousemove(row, col, vt, input_mod) + input_mod = input_mod or {} + local mod = strpe_modifiers(input_mod) + vterm.vterm_mouse_move(vt, row, col, mod) +end + +local function mousebtn(press, button, vt, input_mod) + input_mod = input_mod or {} + local mod = strpe_modifiers(input_mod) + local flag = press == 'd' or press == 'D' + vterm.vterm_mouse_button(vt, button, flag, mod) +end + +local function inchar(c, vt, input_mod) + input_mod = input_mod or {} + local mod = strpe_modifiers(input_mod) + vterm.vterm_keyboard_unichar(vt, c, mod) +end + +local function inkey(input_key, vt, input_mod) + input_mod = input_mod or {} + local mod = strpe_modifiers(input_mod) + local key = strp_key(input_key) + vterm.vterm_keyboard_key(vt, key, mod) +end + +before_each(function() + vim.fs.rm(t.paths.vterm_test_file, { force = true }) +end) + +describe('vterm', function() + itp('02parser', function() + local vt = init() + vterm.vterm_set_utf8(vt, false) + wantparser(vt) + + -- Basic text + push('hello', vt) + expect('text 68,65,6c,6c,6f') + + -- C0 + push('\x03', vt) + expect('control 03') + push('\x1f', vt) + expect('control 1f') + + -- C1 8bit + push('\x83', vt) + expect('control 83') + push('\x99', vt) + expect('control 99') + + -- C1 7bit + push('\x1b\x43', vt) + expect('control 83') + push('\x1b\x59', vt) + expect('control 99') + + -- High bytes + push('\xa0\xcc\xfe', vt) + expect('text a0,cc,fe') + + -- Mixed + push('1\n2', vt) + expect('text 31\ncontrol 0a\ntext 32') + + -- Escape + push('\x1b=', vt) + expect('escape =') + + -- Escape 2-byte + push('\x1b(X', vt) + expect('escape (X') + + -- Split write Escape + push('\x1b(', vt) + push('Y', vt) + expect('escape (Y') + + -- Escape cancels Escape, starts another + push('\x1b(\x1b)Z', vt) + expect('escape )Z') + + -- CAN cancels Escape, returns to normal mode + push('\x1b(\x18AB', vt) + expect('text 41,42') + + -- C0 in Escape interrupts and continues + push('\x1b(\nX', vt) + expect('control 0a\nescape (X') + + -- CSI 0 args + push('\x1b[a', vt) + expect('csi 61 *') + + -- CSI 1 arg + push('\x1b[9b', vt) + expect('csi 62 9') + + -- CSI 2 args + push('\x1b[3;4c', vt) + expect('csi 63 3,4') + + -- CSI 1 arg 1 sub + push('\x1b[1:2c', vt) + expect('csi 63 1+,2') + + -- CSI many digits + push('\x1b[678d', vt) + expect('csi 64 678') + + -- CSI leading zero + push('\x1b[007e', vt) + expect('csi 65 7') + + -- CSI qmark + push('\x1b[?2;7f', vt) + expect('csi 66 L=3f 2,7') + + -- CSI greater + push('\x1b[>c', vt) + expect('csi 63 L=3e *') + + -- CSI SP + push('\x1b[12 q', vt) + expect('csi 71 12 I=20') + + -- Mixed CSI + push('A\x1b[8mB', vt) + expect('text 41\ncsi 6d 8\ntext 42') + + -- Split write + push('\x1b', vt) + push('[a', vt) + expect('csi 61 *') + push('foo\x1b[', vt) + expect('text 66,6f,6f') + push('4b', vt) + expect('csi 62 4') + push('\x1b[12;', vt) + push('3c', vt) + expect('csi 63 12,3') + + -- Escape cancels CSI, starts Escape + push('\x1b[123\x1b9', vt) + expect('escape 9') + + -- CAN cancels CSI, returns to normal mode + push('\x1b[12\x18AB', vt) + expect('text 41,42') + + -- C0 in Escape interrupts and continues + push('\x1b(\nX', vt) + expect('control 0a\nescape (X') + + -- OSC BEL + push('\x1b]1;Hello\x07', vt) + expect('osc [1;Hello]') + + -- OSC ST (7bit) + push('\x1b]1;Hello\x1b\\', vt) + expect('osc [1;Hello]') + + -- OSC ST (8bit) + push('\x9d1;Hello\x9c', vt) + expect('osc [1;Hello]') + + -- OSC in parts + push('\x1b]52;abc', vt) + expect('osc [52;abc') + push('def', vt) + expect('osc def') + push('ghi\x1b\\', vt) + expect('osc ghi]') + + -- OSC BEL without semicolon + push('\x1b]1234\x07', vt) + expect('osc [1234;]') + + -- OSC ST without semicolon + push('\x1b]1234\x1b\\', vt) + expect('osc [1234;]') + + -- Escape cancels OSC, starts Escape + push('\x1b]Something\x1b9', vt) + expect('escape 9') + + -- CAN cancels OSC, returns to normal mode + push('\x1b]12\x18AB', vt) + expect('text 41,42') + + -- C0 in OSC interrupts and continues + push('\x1b]2;\nBye\x07', vt) + expect('osc [2;\ncontrol 0a\nosc Bye]') + + -- DCS BEL + push('\x1bPHello\x07', vt) + expect('dcs [Hello]') + + -- DCS ST (7bit) + push('\x1bPHello\x1b\\', vt) + expect('dcs [Hello]') + + -- DCS ST (8bit) + push('\x90Hello\x9c', vt) + expect('dcs [Hello]') + + -- Split write of 7bit ST + push('\x1bPABC\x1b', vt) + expect('dcs [ABC') + push('\\', vt) + expect('dcs ]') + + -- Escape cancels DCS, starts Escape + push('\x1bPSomething\x1b9', vt) + expect('escape 9') + + -- CAN cancels DCS, returns to normal mode + push('\x1bP12\x18AB', vt) + expect('text 41,42') + + -- C0 in OSC interrupts and continues + push('\x1bPBy\ne\x07', vt) + expect('dcs [By\ncontrol 0a\ndcs e]') + + -- APC BEL + push('\x1b_Hello\x07', vt) + expect('apc [Hello]') + + -- APC ST (7bit) + push('\x1b_Hello\x1b\\', vt) + expect('apc [Hello]') + + -- APC ST (8bit) + push('\x9fHello\x9c', vt) + expect('apc [Hello]') + + -- PM BEL + push('\x1b^Hello\x07', vt) + expect('pm [Hello]') + + -- PM ST (7bit) + push('\x1b^Hello\x1b\\', vt) + expect('pm [Hello]') + + -- PM ST (8bit) + push('\x9eHello\x9c', vt) + expect('pm [Hello]') + + -- SOS BEL + push('\x1bXHello\x07', vt) + expect('sos [Hello]') + + -- SOS ST (7bit) + push('\x1bXHello\x1b\\', vt) + expect('sos [Hello]') + + -- SOS ST (8bit) + push('\x98Hello\x9c', vt) + expect('sos [Hello]') + + push('\x1bXABC\x01DEF\x1b\\', vt) + expect('sos [ABC\x01DEF]') + push('\x1bXABC\x99DEF\x1b\\', vt) + expect('sos [ABC\x99DEF]') + + -- NUL ignored + push('\x00', vt) + + -- NUL ignored within CSI + push('\x1b[12\x003m', vt) + expect('csi 6d 123') + + -- DEL ignored + push('\x7f', vt) + + -- DEL ignored within CSI + push('\x1b[12\x7f3m', vt) + expect('csi 6d 123') + + -- DEL inside text" + push('AB\x7fC', vt) + expect('text 41,42\ntext 43') + end) + + itp('03encoding_utf8', function() + local encoding = wantencoding() + + -- Low + encin('123', encoding) + expect('encout 31,32,33') + + -- We want to prove the UTF-8 parser correctly handles all the sequences. + -- Easy way to do this is to check it does low/high boundary cases, as that + -- leaves only two for each sequence length + -- + -- These ranges are therefore: + -- + -- Two bytes: + -- U+0080 = 000 10000000 => 00010 000000 + -- => 11000010 10000000 = C2 80 + -- U+07FF = 111 11111111 => 11111 111111 + -- => 11011111 10111111 = DF BF + -- + -- Three bytes: + -- U+0800 = 00001000 00000000 => 0000 100000 000000 + -- => 11100000 10100000 10000000 = E0 A0 80 + -- U+FFFD = 11111111 11111101 => 1111 111111 111101 + -- => 11101111 10111111 10111101 = EF BF BD + -- (We avoid U+FFFE and U+FFFF as they're invalid codepoints) + -- + -- Four bytes: + -- U+10000 = 00001 00000000 00000000 => 000 010000 000000 000000 + -- => 11110000 10010000 10000000 10000000 = F0 90 80 80 + -- U+1FFFFF = 11111 11111111 11111111 => 111 111111 111111 111111 + -- => 11110111 10111111 10111111 10111111 = F7 BF BF BF + + -- 2 byte + encin('\xC2\x80\xDF\xBF', encoding) + expect('encout 80,7ff') + + -- 3 byte + encin('\xE0\xA0\x80\xEF\xBF\xBD', encoding) + expect('encout 800,fffd') + + -- 4 byte + encin('\xF0\x90\x80\x80\xF7\xBF\xBF\xBF', encoding) + expect('encout 10000,1fffff') + + -- Next up, we check some invalid sequences + -- + Early termination (back to low bytes too soon) + -- + Early restart (another sequence introduction before the previous one was finished) + + -- Early termination + encin('\xC2!', encoding) + expect('encout fffd,21') + + encin('\xE0!\xE0\xA0!', encoding) + expect('encout fffd,21,fffd,21') + + encin('\xF0!\xF0\x90!\xF0\x90\x80!', encoding) + expect('encout fffd,21,fffd,21,fffd,21') + + -- Early restart + encin('\xC2\xC2\x90', encoding) + expect('encout fffd,90') + + encin('\xE0\xC2\x90\xE0\xA0\xC2\x90', encoding) + expect('encout fffd,90,fffd,90') + + encin('\xF0\xC2\x90\xF0\x90\xC2\x90\xF0\x90\x80\xC2\x90', encoding) + expect('encout fffd,90,fffd,90,fffd,90') + + -- Test the overlong sequences by giving an overlong encoding of U+0000 and + -- an encoding of the highest codepoint still too short + -- + -- Two bytes: + -- U+0000 = C0 80 + -- U+007F = 000 01111111 => 00001 111111 => + -- => 11000001 10111111 => C1 BF + -- + -- Three bytes: + -- U+0000 = E0 80 80 + -- U+07FF = 00000111 11111111 => 0000 011111 111111 + -- => 11100000 10011111 10111111 = E0 9F BF + -- + -- Four bytes: + -- U+0000 = F0 80 80 80 + -- U+FFFF = 11111111 11111111 => 000 001111 111111 111111 + -- => 11110000 10001111 10111111 10111111 = F0 8F BF BF + + -- Overlong + encin('\xC0\x80\xC1\xBF', encoding) + expect('encout fffd,fffd') + + encin('\xE0\x80\x80\xE0\x9F\xBF', encoding) + expect('encout fffd,fffd') + + encin('\xF0\x80\x80\x80\xF0\x8F\xBF\xBF', encoding) + expect('encout fffd,fffd') + + -- UTF-16 surrogates U+D800 and U+DFFF + -- UTF-16 Surrogates + encin('\xED\xA0\x80\xED\xBF\xBF', encoding) + expect('encout fffd,fffd') + + -- Split write + encin('\xC2', encoding) + encin('\xA0', encoding) + expect('encout a0') + + encin('\xE0', encoding) + encin('\xA0\x80', encoding) + expect('encout 800') + encin('\xE0\xA0', encoding) + encin('\x80', encoding) + expect('encout 800') + + encin('\xF0', encoding) + encin('\x90\x80\x80', encoding) + expect('encout 10000') + encin('\xF0\x90', encoding) + encin('\x80\x80', encoding) + expect('encout 10000') + encin('\xF0\x90\x80', encoding) + encin('\x80', encoding) + expect('encout 10000') + end) + + itp('10state_putglyph', function() + local vt = init() + local state = wantstate(vt, { g = true }) + + -- Low + reset(state, nil) + push('ABC', vt) + expect('putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,2') + + -- UTF-8 1 char + -- U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE + -- U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE + reset(state, nil) + push('\xC3\x81\xC3\xA9', vt) + expect('putglyph c1 1 0,0\nputglyph e9 1 0,1') + + -- UTF-8 split writes + reset(state, nil) + push('\xC3', vt) + push('\x81', vt) + expect('putglyph c1 1 0,0') + + -- UTF-8 wide char + -- U+FF10 = EF BC 90 name: FULLWIDTH DIGIT ZERO + reset(state, nil) + push('\xEF\xBC\x90 ', vt) + expect('putglyph ff10 2 0,0\nputglyph 20 1 0,2') + + -- UTF-8 emoji wide char + -- U+1F600 = F0 9F 98 80 name: GRINNING FACE + reset(state, nil) + push('\xF0\x9F\x98\x80 ', vt) + expect('putglyph 1f600 2 0,0\nputglyph 20 1 0,2') + + -- UTF-8 combining chars + -- U+0301 = CC 81 name: COMBINING ACUTE + reset(state, nil) + push('e\xCC\x81Z', vt) + expect('putglyph 65,301 1 0,0\nputglyph 5a 1 0,1') + + -- Combining across buffers + reset(state, nil) + push('e', vt) + expect('putglyph 65 1 0,0') + push('\xCC\x81Z', vt) + expect('putglyph 65,301 1 0,0\nputglyph 5a 1 0,1') + + -- Spare combining chars get truncated + reset(state, nil) + push('e' .. string.rep('\xCC\x81', 10), vt) + expect('putglyph 65,301,301,301,301,301 1 0,0') -- and nothing more + + reset(state, nil) + push('e', vt) + expect('putglyph 65 1 0,0') + push('\xCC\x81', vt) + expect('putglyph 65,301 1 0,0') + push('\xCC\x82', vt) + expect('putglyph 65,301,302 1 0,0') + + -- DECSCA protected + reset(state, nil) + push('A\x1b[1"qB\x1b[2"qC', vt) + expect('putglyph 41 1 0,0\nputglyph 42 1 0,1 prot\nputglyph 43 1 0,2') + end) + + itp('11state_movecursor', function() + local vt = init() + local state = wantstate(vt) + + -- Implicit + push('ABC', vt) + cursor(0, 3, state) + + -- Backspace + push('\b', vt) + cursor(0, 2, state) + -- Horizontal Tab + push('\t', vt) + cursor(0, 8, state) + -- Carriage Return + push('\r', vt) + cursor(0, 0, state) + -- Linefeed + push('\n', vt) + cursor(1, 0, state) + + -- Backspace bounded by lefthand edge + push('\x1b[4;2H', vt) + cursor(3, 1, state) + push('\b', vt) + cursor(3, 0, state) + push('\b', vt) + cursor(3, 0, state) + + -- Backspace cancels phantom + push('\x1b[4;80H', vt) + cursor(3, 79, state) + push('X', vt) + cursor(3, 79, state) + push('\b', vt) + cursor(3, 78, state) + + -- HT bounded by righthand edge + push('\x1b[1;78H', vt) + cursor(0, 77, state) + push('\t', vt) + cursor(0, 79, state) + push('\t', vt) + cursor(0, 79, state) + + reset(state, nil) + + -- Index + push('ABC\x1bD', vt) + cursor(1, 3, state) + -- Reverse Index + push('\x1bM', vt) + cursor(0, 3, state) + -- Newline + push('\x1bE', vt) + cursor(1, 0, state) + + reset(state, nil) + + -- Cursor Forward + push('\x1b[B', vt) + cursor(1, 0, state) + push('\x1b[3B', vt) + cursor(4, 0, state) + push('\x1b[0B', vt) + cursor(5, 0, state) + + -- Cursor Down + push('\x1b[C', vt) + cursor(5, 1, state) + push('\x1b[3C', vt) + cursor(5, 4, state) + push('\x1b[0C', vt) + cursor(5, 5, state) + + -- Cursor Up + push('\x1b[A', vt) + cursor(4, 5, state) + push('\x1b[3A', vt) + cursor(1, 5, state) + push('\x1b[0A', vt) + cursor(0, 5, state) + + -- Cursor Backward + push('\x1b[D', vt) + cursor(0, 4, state) + push('\x1b[3D', vt) + cursor(0, 1, state) + push('\x1b[0D', vt) + cursor(0, 0, state) + + -- Cursor Next Line + push(' ', vt) + cursor(0, 3, state) + push('\x1b[E', vt) + cursor(1, 0, state) + push(' ', vt) + cursor(1, 3, state) + push('\x1b[2E', vt) + cursor(3, 0, state) + push('\x1b[0E', vt) + cursor(4, 0, state) + + -- Cursor Previous Line + push(' ', vt) + cursor(4, 3, state) + push('\x1b[F', vt) + cursor(3, 0, state) + push(' ', vt) + cursor(3, 3, state) + push('\x1b[2F', vt) + cursor(1, 0, state) + push('\x1b[0F', vt) + cursor(0, 0, state) + + -- Cursor Horizonal Absolute + push('\n', vt) + cursor(1, 0, state) + push('\x1b[20G', vt) + cursor(1, 19, state) + push('\x1b[G', vt) + cursor(1, 0, state) + + -- Cursor Position + push('\x1b[10;5H', vt) + cursor(9, 4, state) + push('\x1b[8H', vt) + cursor(7, 0, state) + push('\x1b[H', vt) + cursor(0, 0, state) + + -- Cursor Position cancels phantom + push('\x1b[10;78H', vt) + cursor(9, 77, state) + push('ABC', vt) + cursor(9, 79, state) + push('\x1b[10;80H', vt) + push('C', vt) + cursor(9, 79, state) + push('X', vt) + cursor(10, 1, state) + + reset(state, nil) + + -- Bounds Checking + push('\x1b[A', vt) + cursor(0, 0, state) + push('\x1b[D', vt) + cursor(0, 0, state) + push('\x1b[25;80H', vt) + cursor(24, 79, state) + push('\x1b[B', vt) + cursor(24, 79, state) + push('\x1b[C', vt) + cursor(24, 79, state) + push('\x1b[E', vt) + cursor(24, 0, state) + push('\x1b[H', vt) + cursor(0, 0, state) + push('\x1b[F', vt) + cursor(0, 0, state) + push('\x1b[999G', vt) + cursor(0, 79, state) + push('\x1b[99;99H', vt) + cursor(24, 79, state) + + reset(state, nil) + + -- Horizontal Position Absolute + push('\x1b[5`', vt) + cursor(0, 4, state) + + -- Horizontal Position Relative + push('\x1b[3a', vt) + cursor(0, 7, state) + + -- Horizontal Position Backward + push('\x1b[3j', vt) + cursor(0, 4, state) + + -- Horizontal and Vertical Position + push('\x1b[3;3f', vt) + cursor(2, 2, state) + + -- Vertical Position Absolute + push('\x1b[5d', vt) + cursor(4, 2, state) + + -- Vertical Position Relative + push('\x1b[2e', vt) + cursor(6, 2, state) + + -- Vertical Position Backward + push('\x1b[2k', vt) + cursor(4, 2, state) + + reset(state, nil) + + -- Horizontal Tab + push('\t', vt) + cursor(0, 8, state) + push(' ', vt) + cursor(0, 11, state) + push('\t', vt) + cursor(0, 16, state) + push(' ', vt) + cursor(0, 23, state) + push('\t', vt) + cursor(0, 24, state) + push(' ', vt) + cursor(0, 32, state) + push('\t', vt) + cursor(0, 40, state) + + -- Cursor Horizontal Tab + push('\x1b[I', vt) + cursor(0, 48, state) + push('\x1b[2I', vt) + cursor(0, 64, state) + + -- Cursor Backward Tab + push('\x1b[Z', vt) + cursor(0, 56, state) + push('\x1b[2Z', vt) + cursor(0, 40, state) + end) + + itp('12state_scroll', function() + local vt = init() + local state = wantstate(vt, { s = true }) + + -- Linefeed + push(string.rep('\n', 24), vt) + cursor(24, 0, state) + push('\n', vt) + expect('scrollrect 0..25,0..80 => +1,+0') + cursor(24, 0, state) + + reset(state, nil) + + -- Index + push('\x1b[25H', vt) + push('\x1bD', vt) + expect('scrollrect 0..25,0..80 => +1,+0') + + reset(state, nil) + + -- Reverse Index + push('\x1bM', vt) + expect('scrollrect 0..25,0..80 => -1,+0') + + reset(state, nil) + + -- Linefeed in DECSTBM + push('\x1b[1;10r', vt) + cursor(0, 0, state) + push(string.rep('\n', 9), vt) + cursor(9, 0, state) + push('\n', vt) + expect('scrollrect 0..10,0..80 => +1,+0') + cursor(9, 0, state) + + -- Linefeed outside DECSTBM + push('\x1b[20H', vt) + cursor(19, 0, state) + push('\n', vt) + cursor(20, 0, state) + + -- Index in DECSTBM + push('\x1b[9;10r', vt) + push('\x1b[10H', vt) + push('\x1bM', vt) + cursor(8, 0, state) + push('\x1bM', vt) + expect('scrollrect 8..10,0..80 => -1,+0') + + -- Reverse Index in DECSTBM + push('\x1b[25H', vt) + cursor(24, 0, state) + push('\n', vt) + -- no scrollrect + cursor(24, 0, state) + + -- Linefeed in DECSTBM+DECSLRM + push('\x1b[?69h', vt) + push('\x1b[3;10r\x1b[10;40s', vt) + push('\x1b[10;10H\n', vt) + expect('scrollrect 2..10,9..40 => +1,+0') + + -- IND/RI in DECSTBM+DECSLRM + push('\x1bD', vt) + expect('scrollrect 2..10,9..40 => +1,+0') + push('\x1b[3;10H\x1bM', vt) + expect('scrollrect 2..10,9..40 => -1,+0') + + -- DECRQSS on DECSTBM + push('\x1bP$qr\x1b\\', vt) + expect_output('\x1bP1$r3;10r\x1b\\') + + -- DECRQSS on DECSLRM + push('\x1bP$qs\x1b\\', vt) + expect_output('\x1bP1$r10;40s\x1b\\') + + -- Setting invalid DECSLRM with !DECVSSM is still rejected + push('\x1b[?69l\x1b[;0s\x1b[?69h', vt) + + reset(state, nil) + + -- Scroll Down + push('\x1b[S', vt) + expect('scrollrect 0..25,0..80 => +1,+0') + cursor(0, 0, state) + push('\x1b[2S', vt) + expect('scrollrect 0..25,0..80 => +2,+0') + cursor(0, 0, state) + push('\x1b[100S', vt) + expect('scrollrect 0..25,0..80 => +25,+0') + + -- Scroll Up + push('\x1b[T', vt) + expect('scrollrect 0..25,0..80 => -1,+0') + cursor(0, 0, state) + push('\x1b[2T', vt) + expect('scrollrect 0..25,0..80 => -2,+0') + cursor(0, 0, state) + push('\x1b[100T', vt) + expect('scrollrect 0..25,0..80 => -25,+0') + + -- SD/SU in DECSTBM + push('\x1b[5;20r', vt) + push('\x1b[S', vt) + expect('scrollrect 4..20,0..80 => +1,+0') + push('\x1b[T', vt) + expect('scrollrect 4..20,0..80 => -1,+0') + + reset(state, nil) + + -- SD/SU in DECSTBM+DECSLRM + push('\x1b[?69h', vt) + push('\x1b[3;10r\x1b[10;40s', vt) + cursor(0, 0, state) + push('\x1b[3;10H', vt) + cursor(2, 9, state) + push('\x1b[S', vt) + expect('scrollrect 2..10,9..40 => +1,+0') + push('\x1b[?69l', vt) + push('\x1b[S', vt) + expect('scrollrect 2..10,0..80 => +1,+0') + + -- Invalid boundaries + reset(state, nil) + + push('\x1b[100;105r\x1bD', vt) + push('\x1b[5;2r\x1bD', vt) + + reset(state, nil) + state = wantstate(vt, { m = true, e = true }) + + -- Scroll Down move+erase emulation + push('\x1b[S', vt) + expect('moverect 1..25,0..80 -> 0..24,0..80\nerase 24..25,0..80') + cursor(0, 0, state) + push('\x1b[2S', vt) + expect('moverect 2..25,0..80 -> 0..23,0..80\nerase 23..25,0..80') + cursor(0, 0, state) + + -- Scroll Up move+erase emulation + push('\x1b[T', vt) + expect('moverect 0..24,0..80 -> 1..25,0..80\nerase 0..1,0..80') + cursor(0, 0, state) + push('\x1b[2T', vt) + expect('moverect 0..23,0..80 -> 2..25,0..80\nerase 0..2,0..80') + cursor(0, 0, state) + + -- DECSTBM resets cursor position + push('\x1b[5;5H', vt) + cursor(4, 4, state) + push('\x1b[r', vt) + cursor(0, 0, state) + end) + + itp('13state_edit', function() + local vt = init() + local state = wantstate(vt, { s = true, e = true, b = true }) + + -- ICH + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('ACD', vt) + push('\x1b[2D', vt) + cursor(0, 1, state) + push('\x1b[@', vt) + expect('scrollrect 0..1,1..80 => +0,-1') + cursor(0, 1, state) + push('B', vt) + cursor(0, 2, state) + push('\x1b[3@', vt) + expect('scrollrect 0..1,2..80 => +0,-3') + + -- ICH with DECSLRM + push('\x1b[?69h', vt) + push('\x1b[;50s', vt) + push('\x1b[20G\x1b[@', vt) + expect('scrollrect 0..1,19..50 => +0,-1') + + -- ICH outside DECSLRM + push('\x1b[70G\x1b[@', vt) + -- nothing happens + + -- DCH + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('ABBC', vt) + push('\x1b[3D', vt) + cursor(0, 1, state) + push('\x1b[P', vt) + expect('scrollrect 0..1,1..80 => +0,+1') + cursor(0, 1, state) + push('\x1b[3P', vt) + expect('scrollrect 0..1,1..80 => +0,+3') + cursor(0, 1, state) + + -- DCH with DECSLRM + push('\x1b[?69h', vt) + push('\x1b[;50s', vt) + push('\x1b[20G\x1b[P', vt) + expect('scrollrect 0..1,19..50 => +0,+1') + + -- DCH outside DECSLRM + push('\x1b[70G\x1b[P', vt) + -- nothing happens + + -- ECH + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('ABC', vt) + push('\x1b[2D', vt) + cursor(0, 1, state) + push('\x1b[X', vt) + expect('erase 0..1,1..2') + cursor(0, 1, state) + push('\x1b[3X', vt) + expect('erase 0..1,1..4') + cursor(0, 1, state) + -- ECH more columns than there are should be bounded + push('\x1b[100X', vt) + expect('erase 0..1,1..80') + + -- IL + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('A\r\nC', vt) + cursor(1, 1, state) + push('\x1b[L', vt) + expect('scrollrect 1..25,0..80 => -1,+0') + -- TODO(libvterm): ECMA-48 says we should move to line home, but neither xterm nor xfce4-terminal do this + cursor(1, 1, state) + push('\rB', vt) + cursor(1, 1, state) + push('\x1b[3L', vt) + expect('scrollrect 1..25,0..80 => -3,+0') + + -- IL with DECSTBM + push('\x1b[5;15r', vt) + push('\x1b[5H\x1b[L', vt) + expect('scrollrect 4..15,0..80 => -1,+0') + + -- IL outside DECSTBM + push('\x1b[20H\x1b[L', vt) + -- nothing happens + + -- IL with DECSTBM+DECSLRM + push('\x1b[?69h', vt) + push('\x1b[10;50s', vt) + push('\x1b[5;10H\x1b[L', vt) + expect('scrollrect 4..15,9..50 => -1,+0') + + -- DL + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('A\r\nB\r\nB\r\nC', vt) + cursor(3, 1, state) + push('\x1b[2H', vt) + cursor(1, 0, state) + push('\x1b[M', vt) + expect('scrollrect 1..25,0..80 => +1,+0') + cursor(1, 0, state) + push('\x1b[3M', vt) + expect('scrollrect 1..25,0..80 => +3,+0') + cursor(1, 0, state) + + -- DL with DECSTBM + push('\x1b[5;15r', vt) + push('\x1b[5H\x1b[M', vt) + expect('scrollrect 4..15,0..80 => +1,+0') + + -- DL outside DECSTBM + push('\x1b[20H\x1b[M', vt) + -- nothing happens + + -- DL with DECSTBM+DECSLRM + push('\x1b[?69h', vt) + push('\x1b[10;50s', vt) + push('\x1b[5;10H\x1b[M', vt) + expect('scrollrect 4..15,9..50 => +1,+0') + + -- DECIC + reset(state, nil) + expect('erase 0..25,0..80') + push("\x1b[20G\x1b[5'}", vt) + expect('scrollrect 0..25,19..80 => +0,-5') + + -- DECIC with DECSTBM+DECSLRM + push('\x1b[?69h', vt) + push('\x1b[4;20r\x1b[20;60s', vt) + push("\x1b[4;20H\x1b[3'}", vt) + expect('scrollrect 3..20,19..60 => +0,-3') + + -- DECIC outside DECSLRM + push("\x1b[70G\x1b['}", vt) + -- nothing happens + + -- DECDC + reset(state, nil) + expect('erase 0..25,0..80') + push("\x1b[20G\x1b[5'~", vt) + expect('scrollrect 0..25,19..80 => +0,+5') + + -- DECDC with DECSTBM+DECSLRM + push('\x1b[?69h', vt) + push('\x1b[4;20r\x1b[20;60s', vt) + push("\x1b[4;20H\x1b[3'~", vt) + expect('scrollrect 3..20,19..60 => +0,+3') + + -- DECDC outside DECSLRM + push("\x1b[70G\x1b['~", vt) + -- nothing happens + + -- EL 0 + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('ABCDE', vt) + push('\x1b[3D', vt) + cursor(0, 2, state) + push('\x1b[0K', vt) + expect('erase 0..1,2..80') + cursor(0, 2, state) + + -- EL 1 + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('ABCDE', vt) + push('\x1b[3D', vt) + cursor(0, 2, state) + push('\x1b[1K', vt) + expect('erase 0..1,0..3') + cursor(0, 2, state) + + -- EL 2 + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('ABCDE', vt) + push('\x1b[3D', vt) + cursor(0, 2, state) + push('\x1b[2K', vt) + expect('erase 0..1,0..80') + cursor(0, 2, state) + + -- SEL + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('\x1b[11G', vt) + cursor(0, 10, state) + push('\x1b[?0K', vt) + expect('erase 0..1,10..80 selective') + cursor(0, 10, state) + push('\x1b[?1K', vt) + expect('erase 0..1,0..11 selective') + cursor(0, 10, state) + push('\x1b[?2K', vt) + expect('erase 0..1,0..80 selective') + cursor(0, 10, state) + + -- ED 0 + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('\x1b[2;2H', vt) + cursor(1, 1, state) + push('\x1b[0J', vt) + expect('erase 1..2,1..80\nerase 2..25,0..80') + cursor(1, 1, state) + + -- ED 1 + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('\x1b[2;2H', vt) + cursor(1, 1, state) + push('\x1b[1J', vt) + expect('erase 0..1,0..80\nerase 1..2,0..2') + cursor(1, 1, state) + + -- ED 2 + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('\x1b[2;2H', vt) + cursor(1, 1, state) + push('\x1b[2J', vt) + expect('erase 0..25,0..80') + cursor(1, 1, state) + + -- ED 3 + push('\x1b[3J', vt) + expect('sb_clear') + + -- SED + reset(state, nil) + expect('erase 0..25,0..80') + push('\x1b[5;5H', vt) + cursor(4, 4, state) + push('\x1b[?0J', vt) + expect('erase 4..5,4..80 selective\nerase 5..25,0..80 selective') + cursor(4, 4, state) + push('\x1b[?1J', vt) + expect('erase 0..4,0..80 selective\nerase 4..5,0..5 selective') + cursor(4, 4, state) + push('\x1b[?2J', vt) + expect('erase 0..25,0..80 selective') + cursor(4, 4, state) + + -- DECRQSS on DECSCA + push('\x1b[2"q', vt) + push('\x1bP$q"q\x1b\\', vt) + expect_output('\x1bP1$r2"q\x1b\\') + + state = wantstate(vt, { m = true, e = true, b = true }) + expect('erase 0..25,0..80') -- TODO(dundargoc): strange, this should not be needed according to the original code + + -- ICH move+erase emuation + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('ACD', vt) + push('\x1b[2D', vt) + cursor(0, 1, state) + push('\x1b[@', vt) + expect('moverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2') + cursor(0, 1, state) + push('B', vt) + cursor(0, 2, state) + push('\x1b[3@', vt) + expect('moverect 0..1,2..77 -> 0..1,5..80\nerase 0..1,2..5') + + -- DCH move+erase emulation + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('ABBC', vt) + push('\x1b[3D', vt) + cursor(0, 1, state) + push('\x1b[P', vt) + expect('moverect 0..1,2..80 -> 0..1,1..79\nerase 0..1,79..80') + cursor(0, 1, state) + push('\x1b[3P', vt) + expect('moverect 0..1,4..80 -> 0..1,1..77\nerase 0..1,77..80') + cursor(0, 1, state) + end) + + itp('14state_encoding', function() + local vt = init() + vterm.vterm_set_utf8(vt, false) + local state = wantstate(vt, { g = true }) + + -- Default + reset(state, nil) + push('#', vt) + expect('putglyph 23 1 0,0') + + -- Designate G0=UK + reset(state, nil) + push('\x1b(A', vt) + push('#', vt) + expect('putglyph a3 1 0,0') + + -- Designate G0=DEC drawing + reset(state, nil) + push('\x1b(0', vt) + push('a', vt) + expect('putglyph 2592 1 0,0') + + -- Designate G1 + LS1 + reset(state, nil) + push('\x1b)0', vt) + push('a', vt) + expect('putglyph 61 1 0,0') + push('\x0e', vt) + push('a', vt) + expect('putglyph 2592 1 0,1') + -- LS0 + push('\x0f', vt) + push('a', vt) + expect('putglyph 61 1 0,2') + + -- Designate G2 + LS2 + push('\x1b*0', vt) + push('a', vt) + expect('putglyph 61 1 0,3') + push('\x1bn', vt) + push('a', vt) + expect('putglyph 2592 1 0,4') + push('\x0f', vt) + push('a', vt) + expect('putglyph 61 1 0,5') + + -- Designate G3 + LS3 + push('\x1b+0', vt) + push('a', vt) + expect('putglyph 61 1 0,6') + push('\x1bo', vt) + push('a', vt) + expect('putglyph 2592 1 0,7') + push('\x0f', vt) + push('a', vt) + expect('putglyph 61 1 0,8') + + -- SS2 + push('a\x8eaa', vt) + expect('putglyph 61 1 0,9\nputglyph 2592 1 0,10\nputglyph 61 1 0,11') + + -- SS3 + push('a\x8faa', vt) + expect('putglyph 61 1 0,12\nputglyph 2592 1 0,13\nputglyph 61 1 0,14') + + -- LS1R + reset(state, nil) + push('\x1b~', vt) + push('\xe1', vt) + expect('putglyph 61 1 0,0') + push('\x1b)0', vt) + push('\xe1', vt) + expect('putglyph 2592 1 0,1') + + -- LS2R + reset(state, nil) + push('\x1b}', vt) + push('\xe1', vt) + expect('putglyph 61 1 0,0') + push('\x1b*0', vt) + push('\xe1', vt) + expect('putglyph 2592 1 0,1') + + -- LS3R + reset(state, nil) + push('\x1b|', vt) + push('\xe1', vt) + expect('putglyph 61 1 0,0') + push('\x1b+0', vt) + push('\xe1', vt) + expect('putglyph 2592 1 0,1') + + vterm.vterm_set_utf8(vt, true) + -- U+0108 == c4 88 + reset(state, nil) + push('\x1b(B', vt) + push('AB\xc4\x88D', vt) + expect('putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 108 1 0,2\nputglyph 44 1 0,3') + end) + + itp('15state_mode', function() + local vt = init() + local state = wantstate(vt, { g = true, m = true, e = true }) + + -- Insert/Replace Mode + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('AC\x1b[DB', vt) + expect('putglyph 41 1 0,0\nputglyph 43 1 0,1\nputglyph 42 1 0,1') + push('\x1b[4h', vt) + push('\x1b[G', vt) + push('AC\x1b[DB', vt) + expect( + 'moverect 0..1,0..79 -> 0..1,1..80\nerase 0..1,0..1\nputglyph 41 1 0,0\nmoverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2\nputglyph 43 1 0,1\nmoverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2\nputglyph 42 1 0,1' + ) + + -- Insert mode only happens once for UTF-8 combining + push('e', vt) + expect('moverect 0..1,2..79 -> 0..1,3..80\nerase 0..1,2..3\nputglyph 65 1 0,2') + push('\xCC\x81', vt) + expect('putglyph 65,301 1 0,2') + + -- Newline/Linefeed mode + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('\x1b[5G\n', vt) + cursor(1, 4, state) + push('\x1b[20h', vt) + push('\x1b[5G\n', vt) + cursor(2, 0, state) + + -- DEC origin mode + reset(state, nil) + expect('erase 0..25,0..80') + cursor(0, 0, state) + push('\x1b[5;15r', vt) + push('\x1b[H', vt) + cursor(0, 0, state) + push('\x1b[3;3H', vt) + cursor(2, 2, state) + push('\x1b[?6h', vt) + push('\x1b[H', vt) + cursor(4, 0, state) + push('\x1b[3;3H', vt) + cursor(6, 2, state) + + -- DECRQM on DECOM + push('\x1b[?6h', vt) + push('\x1b[?6$p', vt) + expect_output('\x1b[?6;1$y') + push('\x1b[?6l', vt) + push('\x1b[?6$p', vt) + expect_output('\x1b[?6;2$y') + + -- Origin mode with DECSLRM + push('\x1b[?6h', vt) + push('\x1b[?69h', vt) + push('\x1b[20;60s', vt) + push('\x1b[H', vt) + cursor(4, 19, state) + + push('\x1b[?69l', vt) + + -- Origin mode bounds cursor to scrolling region + push('\x1b[H', vt) + push('\x1b[10A', vt) + cursor(4, 0, state) + push('\x1b[20B', vt) + cursor(14, 0, state) + + -- Origin mode without scroll region + push('\x1b[?6l', vt) + push('\x1b[r\x1b[?6h', vt) + cursor(0, 0, state) + end) + + itp('16state_resize', function() + local vt = init() + local state = wantstate(vt, { g = true }) + + -- Placement + reset(state, nil) + push('AB\x1b[79GCDE', vt) + expect( + 'putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,78\nputglyph 44 1 0,79\nputglyph 45 1 1,0' + ) + + -- Resize + reset(state, nil) + resize(27, 85, vt) + push('AB\x1b[79GCDE', vt) + expect( + 'putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,78\nputglyph 44 1 0,79\nputglyph 45 1 0,80' + ) + cursor(0, 81, state) + + -- Resize without reset + resize(28, 90, vt) + cursor(0, 81, state) + push('FGHI', vt) + expect('putglyph 46 1 0,81\nputglyph 47 1 0,82\nputglyph 48 1 0,83\nputglyph 49 1 0,84') + cursor(0, 85, state) + + -- Resize shrink moves cursor + resize(25, 80, vt) + cursor(0, 79, state) + + -- Resize grow doesn't cancel phantom + reset(state, nil) + push('\x1b[79GAB', vt) + expect('putglyph 41 1 0,78\nputglyph 42 1 0,79') + cursor(0, 79, state) + resize(30, 100, vt) + cursor(0, 80, state) + push('C', vt) + expect('putglyph 43 1 0,80') + cursor(0, 81, state) + end) + + itp('17state_mouse', function() + local vt = init() + local state = wantstate(vt, { p = true }) + + -- DECRQM on with mouse off + push('\x1b[?1000$p', vt) + expect_output('\x1b[?1000;2$y') + push('\x1b[?1002$p', vt) + expect_output('\x1b[?1002;2$y') + push('\x1b[?1003$p', vt) + expect_output('\x1b[?1003;2$y') + + -- Mouse in simple button report mode + reset(state, nil) + expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') + push('\x1b[?1000h', vt) + expect('settermprop 8 1') + + -- Press 1 + mousemove(0, 0, vt) + mousebtn('d', 1, vt) + expect_output('\x1b[M\x20\x21\x21') + + -- Release 1 + mousebtn('u', 1, vt) + expect_output('\x1b[M\x23\x21\x21') + + -- Ctrl-Press 1 + mousebtn('d', 1, vt, { C = true }) + expect_output('\x1b[M\x30\x21\x21') + mousebtn('u', 1, vt, { C = true }) + expect_output('\x1b[M\x33\x21\x21') + + -- Button 2 + mousebtn('d', 2, vt) + expect_output('\x1b[M\x21\x21\x21') + mousebtn('u', 2, vt) + expect_output('\x1b[M\x23\x21\x21') + + -- Position + mousemove(10, 20, vt) + mousebtn('d', 1, vt) + expect_output('\x1b[M\x20\x35\x2b') + + mousebtn('u', 1, vt) + expect_output('\x1b[M\x23\x35\x2b') + mousemove(10, 21, vt) + -- no output + + -- Wheel events + mousebtn('d', 4, vt) + expect_output('\x1b[M\x60\x36\x2b') + mousebtn('d', 4, vt) + expect_output('\x1b[M\x60\x36\x2b') + mousebtn('d', 5, vt) + expect_output('\x1b[M\x61\x36\x2b') + mousebtn('d', 6, vt) + expect_output('\x1b[M\x62\x36\x2b') + mousebtn('d', 7, vt) + expect_output('\x1b[M\x63\x36\x2b') + + -- DECRQM on mouse button mode + push('\x1b[?1000$p', vt) + expect_output('\x1b[?1000;1$y') + push('\x1b[?1002$p', vt) + expect_output('\x1b[?1002;2$y') + push('\x1b[?1003$p', vt) + expect_output('\x1b[?1003;2$y') + + -- Drag events + reset(state, nil) + expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') + push('\x1b[?1002h', vt) + expect('settermprop 8 2') + + mousemove(5, 5, vt) + mousebtn('d', 1, vt) + expect_output('\x1b[M\x20\x26\x26') + mousemove(5, 6, vt) + expect_output('\x1b[M\x40\x27\x26') + mousemove(6, 6, vt) + expect_output('\x1b[M\x40\x27\x27') + mousemove(6, 6, vt) + -- no output + mousebtn('u', 1, vt) + expect_output('\x1b[M\x23\x27\x27') + mousemove(6, 7, vt) + -- no output + + -- DECRQM on mouse drag mode + push('\x1b[?1000$p', vt) + expect_output('\x1b[?1000;2$y') + push('\x1b[?1002$p', vt) + expect_output('\x1b[?1002;1$y') + push('\x1b[?1003$p', vt) + expect_output('\x1b[?1003;2$y') + + -- Non-drag motion events + push('\x1b[?1003h', vt) + expect('settermprop 8 3') + + mousemove(6, 8, vt) + expect_output('\x1b[M\x43\x29\x27') + + -- DECRQM on mouse motion mode + push('\x1b[?1000$p', vt) + expect_output('\x1b[?1000;2$y') + push('\x1b[?1002$p', vt) + expect_output('\x1b[?1002;2$y') + push('\x1b[?1003$p', vt) + expect_output('\x1b[?1003;1$y') + + -- Bounds checking + mousemove(300, 300, vt) + expect_output('\x1b[M\x43\xff\xff') + mousebtn('d', 1, vt) + expect_output('\x1b[M\x20\xff\xff') + mousebtn('u', 1, vt) + expect_output('\x1b[M\x23\xff\xff') + + -- DECRQM on standard encoding mode + push('\x1b[?1005$p', vt) + expect_output('\x1b[?1005;2$y') + push('\x1b[?1006$p', vt) + expect_output('\x1b[?1006;2$y') + push('\x1b[?1015$p', vt) + expect_output('\x1b[?1015;2$y') + + -- UTF-8 extended encoding mode + -- 300 + 32 + 1 = 333 = U+014d = \xc5\x8d + push('\x1b[?1005h', vt) + mousebtn('d', 1, vt) + expect_output('\x1b[M\x20\xc5\x8d\xc5\x8d') + mousebtn('u', 1, vt) + expect_output('\x1b[M\x23\xc5\x8d\xc5\x8d') + + -- DECRQM on UTF-8 extended encoding mode + push('\x1b[?1005$p', vt) + expect_output('\x1b[?1005;1$y') + push('\x1b[?1006$p', vt) + expect_output('\x1b[?1006;2$y') + push('\x1b[?1015$p', vt) + expect_output('\x1b[?1015;2$y') + + -- SGR extended encoding mode + push('\x1b[?1006h', vt) + mousebtn('d', 1, vt) + expect_output('\x1b[<0;301;301M') + mousebtn('u', 1, vt) + expect_output('\x1b[<0;301;301m') + + -- DECRQM on SGR extended encoding mode + push('\x1b[?1005$p', vt) + expect_output('\x1b[?1005;2$y') + push('\x1b[?1006$p', vt) + expect_output('\x1b[?1006;1$y') + push('\x1b[?1015$p', vt) + expect_output('\x1b[?1015;2$y') + + -- rxvt extended encoding mode + push('\x1b[?1015h', vt) + mousebtn('d', 1, vt) + expect_output('\x1b[0;301;301M') + mousebtn('u', 1, vt) + expect_output('\x1b[3;301;301M') + + -- DECRQM on rxvt extended encoding mode + push('\x1b[?1005$p', vt) + expect_output('\x1b[?1005;2$y') + push('\x1b[?1006$p', vt) + expect_output('\x1b[?1006;2$y') + push('\x1b[?1015$p', vt) + expect_output('\x1b[?1015;1$y') + + -- Mouse disabled reports nothing + reset(state, nil) + expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') + mousemove(0, 0, vt) + mousebtn('d', 1, vt) + mousebtn('u', 1, vt) + + -- DECSM can set multiple modes at once + push('\x1b[?1002;1006h', vt) + expect('settermprop 8 2') + mousebtn('d', 1, vt) + expect_output('\x1b[<0;1;1M') + end) + + itp('18state_termprops', function() + local vt = init() + local state = wantstate(vt, { p = true }) + + reset(state, nil) + expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') + + -- Cursor visibility + push('\x1b[?25h', vt) + expect('settermprop 1 true') + push('\x1b[?25$p', vt) + expect_output('\x1b[?25;1$y') + push('\x1b[?25l', vt) + expect('settermprop 1 false') + push('\x1b[?25$p', vt) + expect_output('\x1b[?25;2$y') + + -- Cursor blink + push('\x1b[?12h', vt) + expect('settermprop 2 true') + push('\x1b[?12$p', vt) + expect_output('\x1b[?12;1$y') + push('\x1b[?12l', vt) + expect('settermprop 2 false') + push('\x1b[?12$p', vt) + expect_output('\x1b[?12;2$y') + + -- Cursor shape + push('\x1b[3 q', vt) + expect('settermprop 2 true\nsettermprop 7 2') + + -- Title + push('\x1b]2;Here is my title\a', vt) + expect('settermprop 4 ["Here is my title"]') + + -- Title split write + push('\x1b]2;Here is', vt) + expect('settermprop 4 ["Here is"') + push(' another title\a', vt) + expect('settermprop 4 " another title"]') + end) + + itp('20state_wrapping', function() + local vt = init() + local state = wantstate(vt, { g = true, m = true }) + + -- 79th Column + push('\x1b[75G', vt) + push(string.rep('A', 5), vt) + expect( + 'putglyph 41 1 0,74\nputglyph 41 1 0,75\nputglyph 41 1 0,76\nputglyph 41 1 0,77\nputglyph 41 1 0,78' + ) + cursor(0, 79, state) + + -- 80th Column Phantom + push('A', vt) + expect('putglyph 41 1 0,79') + cursor(0, 79, state) + + -- Line Wraparound + push('B', vt) + expect('putglyph 42 1 1,0') + cursor(1, 1, state) + + -- Line Wraparound during combined write + push('\x1b[78G', vt) + push('BBBCC', vt) + expect( + 'putglyph 42 1 1,77\nputglyph 42 1 1,78\nputglyph 42 1 1,79\nputglyph 43 1 2,0\nputglyph 43 1 2,1' + ) + cursor(2, 2, state) + + -- DEC Auto Wrap Mode + reset(state, nil) + push('\x1b[?7l', vt) + push('\x1b[75G', vt) + push(string.rep('D', 6), vt) + expect( + 'putglyph 44 1 0,74\nputglyph 44 1 0,75\nputglyph 44 1 0,76\nputglyph 44 1 0,77\nputglyph 44 1 0,78\nputglyph 44 1 0,79' + ) + cursor(0, 79, state) + push('D', vt) + expect('putglyph 44 1 0,79') + cursor(0, 79, state) + push('\x1b[?7h', vt) + + -- 80th column causes linefeed on wraparound + push('\x1b[25;78HABC', vt) + expect('putglyph 41 1 24,77\nputglyph 42 1 24,78\nputglyph 43 1 24,79') + cursor(24, 79, state) + push('D', vt) + expect('moverect 1..25,0..80 -> 0..24,0..80\nputglyph 44 1 24,0') + + -- 80th column phantom linefeed phantom cancelled by explicit cursor move + push('\x1b[25;78HABC', vt) + expect('putglyph 41 1 24,77\nputglyph 42 1 24,78\nputglyph 43 1 24,79') + cursor(24, 79, state) + push('\x1b[25;1HD', vt) + expect('putglyph 44 1 24,0') + end) + + itp('21state_tabstops', function() + local vt = init() + local state = wantstate(vt, { g = true }) + + -- Initial + reset(state, nil) + push('\tX', vt) + expect('putglyph 58 1 0,8') + push('\tX', vt) + expect('putglyph 58 1 0,16') + cursor(0, 17, state) + + -- HTS + push('\x1b[5G\x1bH', vt) + push('\x1b[G\tX', vt) + expect('putglyph 58 1 0,4') + cursor(0, 5, state) + + -- TBC 0 + push('\x1b[9G\x1b[g', vt) + push('\x1b[G\tX\tX', vt) + expect('putglyph 58 1 0,4\nputglyph 58 1 0,16') + cursor(0, 17, state) + + -- TBC 3 + push('\x1b[3g\x1b[50G\x1bH\x1b[G', vt) + cursor(0, 0, state) + push('\tX', vt) + expect('putglyph 58 1 0,49') + cursor(0, 50, state) + + -- Tabstops after resize + reset(state, nil) + resize(30, 100, vt) + -- Should be 100/8 = 12 tabstops + push('\tX', vt) + expect('putglyph 58 1 0,8') + push('\tX', vt) + expect('putglyph 58 1 0,16') + push('\tX', vt) + expect('putglyph 58 1 0,24') + push('\tX', vt) + expect('putglyph 58 1 0,32') + push('\tX', vt) + expect('putglyph 58 1 0,40') + push('\tX', vt) + expect('putglyph 58 1 0,48') + push('\tX', vt) + expect('putglyph 58 1 0,56') + push('\tX', vt) + expect('putglyph 58 1 0,64') + push('\tX', vt) + expect('putglyph 58 1 0,72') + push('\tX', vt) + expect('putglyph 58 1 0,80') + push('\tX', vt) + expect('putglyph 58 1 0,88') + push('\tX', vt) + expect('putglyph 58 1 0,96') + cursor(0, 97, state) + end) + + itp('22state_save', function() + local vt = init() + local state = wantstate(vt, { p = true }) + + reset(state, nil) + expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') + + -- Set up state + push('\x1b[2;2H', vt) + cursor(1, 1, state) + push('\x1b[1m', vt) + pen('bold', true, state) + + -- Save + push('\x1b[?1048h', vt) + + -- Change state + push('\x1b[5;5H', vt) + cursor(4, 4, state) + push('\x1b[4 q', vt) + expect('settermprop 2 false\nsettermprop 7 2') + push('\x1b[22;4m', vt) + pen('bold', false, state) + pen('underline', 1, state) + + -- Restore + push('\x1b[?1048l', vt) + expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') + cursor(1, 1, state) + pen('bold', true, state) + pen('underline', 0, state) + + -- Save/restore using DECSC/DECRC + push('\x1b[2;2H\x1b7', vt) + cursor(1, 1, state) + + push('\x1b[5;5H', vt) + cursor(4, 4, state) + push('\x1b8', vt) + expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') + cursor(1, 1, state) + + -- Save twice, restore twice happens on both edge transitions + push('\x1b[2;10H\x1b[?1048h\x1b[6;10H\x1b[?1048h', vt) + push('\x1b[H', vt) + cursor(0, 0, state) + push('\x1b[?1048l', vt) + expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') + cursor(5, 9, state) + push('\x1b[H', vt) + cursor(0, 0, state) + push('\x1b[?1048l', vt) + expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') + cursor(5, 9, state) + end) + + itp('25state_input', function() + local vt = init() + local state = wantstate(vt) + + -- Unmodified ASCII + inchar(41, vt) + expect('output 29') + inchar(61, vt) + expect('output 3d') + + -- Ctrl modifier on ASCII letters + inchar(41, vt, { C = true }) + expect('output 1b,5b,34,31,3b,35,75') + inchar(61, vt, { C = true }) + expect('output 1b,5b,36,31,3b,35,75') + + -- Alt modifier on ASCII letters + inchar(41, vt, { A = true }) + expect('output 1b,29') + inchar(61, vt, { A = true }) + expect('output 1b,3d') + + -- Ctrl-Alt modifier on ASCII letters + inchar(41, vt, { C = true, A = true }) + expect('output 1b,5b,34,31,3b,37,75') + inchar(61, vt, { C = true, A = true }) + expect('output 1b,5b,36,31,3b,37,75') + + -- Special handling of Ctrl-I + inchar(49, vt) + expect('output 31') + inchar(69, vt) + expect('output 45') + inchar(49, vt, { C = true }) + expect('output 1b,5b,34,39,3b,35,75') + inchar(69, vt, { C = true }) + expect('output 1b,5b,36,39,3b,35,75') + inchar(49, vt, { A = true }) + expect('output 1b,31') + inchar(69, vt, { A = true }) + expect('output 1b,45') + inchar(49, vt, { A = true, C = true }) + expect('output 1b,5b,34,39,3b,37,75') + inchar(69, vt, { A = true, C = true }) + expect('output 1b,5b,36,39,3b,37,75') + + -- Special handling of Space + inchar(20, vt) + expect('output 14') + inchar(20, vt, { S = true }) + expect('output 14') + inchar(20, vt, { C = true }) + expect('output 1b,5b,32,30,3b,35,75') + inchar(20, vt, { C = true, S = true }) + expect('output 1b,5b,32,30,3b,35,75') + inchar(20, vt, { A = true }) + expect('output 1b,14') + inchar(20, vt, { S = true, A = true }) + expect('output 1b,14') + inchar(20, vt, { C = true, A = true }) + expect('output 1b,5b,32,30,3b,37,75') + inchar(20, vt, { S = true, C = true, A = true }) + expect('output 1b,5b,32,30,3b,37,75') + + -- Cursor keys in reset (cursor) mode + inkey('up', vt) + expect_output('\x1b[A') + inkey('up', vt, { S = true }) + expect_output('\x1b[1;2A') + inkey('up', vt, { C = true }) + expect_output('\x1b[1;5A') + inkey('up', vt, { S = true, C = true }) + expect_output('\x1b[1;6A') + inkey('up', vt, { A = true }) + expect_output('\x1b[1;3A') + inkey('up', vt, { S = true, A = true }) + expect_output('\x1b[1;4A') + inkey('up', vt, { C = true, A = true }) + expect_output('\x1b[1;7A') + inkey('up', vt, { S = true, C = true, A = true }) + expect_output('\x1b[1;8A') + + -- Cursor keys in application mode + push('\x1b[?1h', vt) + -- Plain "Up" should be SS3 A now + inkey('up', vt) + expect_output('\x1bOA') + -- Modified keys should still use CSI + inkey('up', vt, { S = true }) + expect_output('\x1b[1;2A') + inkey('up', vt, { C = true }) + expect_output('\x1b[1;5A') + + -- Shift-Tab should be different + inkey('tab', vt) + expect_output('\x09') + inkey('tab', vt, { S = true }) + expect_output('\x1b[Z') + inkey('tab', vt, { C = true }) + expect_output('\x1b[9;5u') + inkey('tab', vt, { A = true }) + expect_output('\x1b\x09') + inkey('tab', vt, { C = true, A = true }) + expect_output('\x1b[9;7u') + + -- Enter in linefeed mode + inkey('enter', vt) + expect_output('\x0d') + + -- Enter in newline mode + push('\x1b[20h', vt) + inkey('enter', vt) + expect_output('\x0d\x0a') + + -- Unmodified F1 is SS3 P + inkey('f1', vt) + expect_output('\x1bOP') + + -- Modified F1 is CSI P + inkey('f1', vt, { S = true }) + expect_output('\x1b[1;2P') + inkey('f1', vt, { A = true }) + expect_output('\x1b[1;3P') + inkey('f1', vt, { C = true }) + expect_output('\x1b[1;5P') + + -- Keypad in DECKPNM + inkey('kp0', vt) + expect_output('0') + + -- Keypad in DECKPAM + push('\x1b=', vt) + inkey('kp0', vt) + expect_output('\x1bOp') + + -- Bracketed paste mode off + vterm.vterm_keyboard_start_paste(vt) + vterm.vterm_keyboard_end_paste(vt) + + -- Bracketed paste mode on + push('\x1b[?2004h', vt) + vterm.vterm_keyboard_start_paste(vt) + expect_output('\x1b[200~') + vterm.vterm_keyboard_end_paste(vt) + expect_output('\x1b[201~') + + -- Focus reporting disabled + vterm.vterm_state_focus_in(state) + vterm.vterm_state_focus_out(state) + + -- Focus reporting enabled + state = wantstate(vt, { p = true }) + push('\x1b[?1004h', vt) + expect('settermprop 9 true') + vterm.vterm_state_focus_in(state) + expect_output('\x1b[I') + vterm.vterm_state_focus_out(state) + expect_output('\x1b[O') + end) + + itp('26state_query', function() + local vt = init() + local state = wantstate(vt) + + -- DA + reset(state, nil) + push('\x1b[c', vt) + expect_output('\x1b[?1;2c') + + -- XTVERSION + reset(state, nil) + push('\x1b[>q', vt) + expect_output('\x1bP>|libvterm(0.3)\x1b\\') + + -- DSR + reset(state, nil) + push('\x1b[5n', vt) + expect_output('\x1b[0n') + + -- CPR + push('\x1b[6n', vt) + expect_output('\x1b[1;1R') + push('\x1b[10;10H\x1b[6n', vt) + expect_output('\x1b[10;10R') + + -- DECCPR + push('\x1b[?6n', vt) + expect_output('\x1b[?10;10R') + + -- DECRQSS on DECSCUSR + push('\x1b[3 q', vt) + push('\x1bP$q q\x1b\\', vt) + expect_output('\x1bP1$r3 q\x1b\\') + + -- DECRQSS on SGR + push('\x1b[1;5;7m', vt) + push('\x1bP$qm\x1b\\', vt) + expect_output('\x1bP1$r1;5;7m\x1b\\') + + -- DECRQSS on SGR ANSI colours + push('\x1b[0;31;42m', vt) + push('\x1bP$qm\x1b\\', vt) + expect_output('\x1bP1$r31;42m\x1b\\') + + -- DECRQSS on SGR ANSI hi-bright colours + push('\x1b[0;93;104m', vt) + push('\x1bP$qm\x1b\\', vt) + expect_output('\x1bP1$r93;104m\x1b\\') + + -- DECRQSS on SGR 256-palette colours + push('\x1b[0;38:5:56;48:5:78m', vt) + push('\x1bP$qm\x1b\\', vt) + expect_output('\x1bP1$r38:5:56;48:5:78m\x1b\\') + + -- DECRQSS on SGR RGB8 colours + push('\x1b[0;38:2:24:68:112;48:2:13:57:101m', vt) + push('\x1bP$qm\x1b\\', vt) + expect_output('\x1bP1$r38:2:24:68:112;48:2:13:57:101m\x1b\\') + + -- S8C1T on DSR + push('\x1b G', vt) + push('\x1b[5n', vt) + expect_output('\x9b0n') + push('\x1b F', vt) + end) + + itp('27state_reset', function() + local vt = init() + local state = wantstate(vt) + + reset(state, nil) + + -- RIS homes cursor + push('\x1b[5;5H', vt) + cursor(4, 4, state) + state = wantstate(vt, { m = true }) + push('\x1bc', vt) + cursor(0, 0, state) + wantstate(vt) + + -- RIS cancels scrolling region + push('\x1b[5;10r', vt) + wantstate(vt, { s = true }) + push('\x1bc\x1b[25H\n', vt) + expect('scrollrect 0..25,0..80 => +1,+0') + wantstate(vt) + + -- RIS erases screen + push('ABCDE', vt) + state = wantstate(vt, { e = true }) + push('\x1bc', vt) + expect('erase 0..25,0..80') + wantstate(vt) + + -- RIS clears tabstops + push('\x1b[5G\x1bH\x1b[G\t', vt) + cursor(0, 4, state) + push('\x1bc\t', vt) + cursor(0, 8, state) + end) + + itp('28state_dbl_wh', function() + local vt = init() + local state = wantstate(vt, { g = true }) + + -- Single Width, Single Height + reset(state, nil) + push('\x1b#5', vt) + push('Hello', vt) + expect( + 'putglyph 48 1 0,0\nputglyph 65 1 0,1\nputglyph 6c 1 0,2\nputglyph 6c 1 0,3\nputglyph 6f 1 0,4' + ) + + -- Double Width, Single Height + reset(state, nil) + push('\x1b#6', vt) + push('Hello', vt) + expect( + 'putglyph 48 1 0,0 dwl\nputglyph 65 1 0,1 dwl\nputglyph 6c 1 0,2 dwl\nputglyph 6c 1 0,3 dwl\nputglyph 6f 1 0,4 dwl' + ) + cursor(0, 5, state) + push('\x1b[40GAB', vt) + expect('putglyph 41 1 0,39 dwl\nputglyph 42 1 1,0') + cursor(1, 1, state) + + -- Double Height + reset(state, nil) + push('\x1b#3', vt) + push('Hello', vt) + expect( + 'putglyph 48 1 0,0 dwl dhl-top\nputglyph 65 1 0,1 dwl dhl-top\nputglyph 6c 1 0,2 dwl dhl-top\nputglyph 6c 1 0,3 dwl dhl-top\nputglyph 6f 1 0,4 dwl dhl-top' + ) + cursor(0, 5, state) + push('\r\n\x1b#4', vt) + push('Hello', vt) + expect( + 'putglyph 48 1 1,0 dwl dhl-bottom\nputglyph 65 1 1,1 dwl dhl-bottom\nputglyph 6c 1 1,2 dwl dhl-bottom\nputglyph 6c 1 1,3 dwl dhl-bottom\nputglyph 6f 1 1,4 dwl dhl-bottom' + ) + cursor(1, 5, state) + + -- Double Width scrolling + reset(state, nil) + push('\x1b[20H\x1b#6ABC', vt) + expect('putglyph 41 1 19,0 dwl\nputglyph 42 1 19,1 dwl\nputglyph 43 1 19,2 dwl') + push('\x1b[25H\n', vt) + push('\x1b[19;4HDE', vt) + expect('putglyph 44 1 18,3 dwl\nputglyph 45 1 18,4 dwl') + push('\x1b[H\x1bM', vt) + push('\x1b[20;6HFG', vt) + expect('putglyph 46 1 19,5 dwl\nputglyph 47 1 19,6 dwl') + end) + + itp('29state_fallback', function() + local vt = init() + local state = wantstate(vt, { f = true }) + reset(state, nil) + + -- Unrecognised control + push('\x03', vt) + expect('control 03') + + -- Unrecognised CSI + push('\x1b[?15;2z', vt) + expect('csi 7a L=3f 15,2') + + -- Unrecognised OSC + push('\x1b]27;Something\x1b\\', vt) + expect('osc [27;Something]') + + -- Unrecognised DCS + push('\x1bPz123\x1b\\', vt) + expect('dcs [z123]') + + -- Unrecognised APC + push('\x1b_z123\x1b\\', vt) + expect('apc [z123]') + + -- Unrecognised PM + push('\x1b^z123\x1b\\', vt) + expect('pm [z123]') + + -- Unrecognised SOS + push('\x1bXz123\x1b\\', vt) + expect('sos [z123]') + end) + + itp('30state_pen', function() + local vt = init() + local state = wantstate(vt) + + -- Reset + push('\x1b[m', vt) + pen('bold', false, state) + pen('underline', 0, state) + pen('italic', false, state) + pen('blink', false, state) + pen('reverse', false, state) + pen('font', 0, state) + -- TODO(dundargoc): fix + -- ?pen foreground = rgb(240,240,240,is_default_fg) + -- ?pen background = rgb(0,0,0,is_default_bg) + + -- Bold + push('\x1b[1m', vt) + pen('bold', true, state) + push('\x1b[22m', vt) + pen('bold', false, state) + push('\x1b[1m\x1b[m', vt) + pen('bold', false, state) + + -- Underline + push('\x1b[4m', vt) + pen('underline', 1, state) + push('\x1b[21m', vt) + pen('underline', 2, state) + push('\x1b[24m', vt) + pen('underline', 0, state) + push('\x1b[4m\x1b[4:0m', vt) + pen('underline', 0, state) + push('\x1b[4:1m', vt) + pen('underline', 1, state) + push('\x1b[4:2m', vt) + pen('underline', 2, state) + push('\x1b[4:3m', vt) + pen('underline', 3, state) + push('\x1b[4m\x1b[m', vt) + pen('underline', 0, state) + + -- Italic + push('\x1b[3m', vt) + pen('italic', true, state) + push('\x1b[23m', vt) + pen('italic', false, state) + push('\x1b[3m\x1b[m', vt) + pen('italic', false, state) + + -- Blink + push('\x1b[5m', vt) + pen('blink', true, state) + push('\x1b[25m', vt) + pen('blink', false, state) + push('\x1b[5m\x1b[m', vt) + pen('blink', false, state) + + -- Reverse + push('\x1b[7m', vt) + pen('reverse', true, state) + push('\x1b[27m', vt) + pen('reverse', false, state) + push('\x1b[7m\x1b[m', vt) + pen('reverse', false, state) + + -- Font Selection + push('\x1b[11m', vt) + pen('font', 1, state) + push('\x1b[19m', vt) + pen('font', 9, state) + push('\x1b[10m', vt) + pen('font', 0, state) + push('\x1b[11m\x1b[m', vt) + pen('font', 0, state) + + -- TODO(dundargoc): fix + -- Foreground + -- push "\x1b[31m" + -- ?pen foreground = idx(1) + -- push "\x1b[32m" + -- ?pen foreground = idx(2) + -- push "\x1b[34m" + -- ?pen foreground = idx(4) + -- push "\x1b[91m" + -- ?pen foreground = idx(9) + -- push "\x1b[38:2:10:20:30m" + -- ?pen foreground = rgb(10,20,30) + -- push "\x1b[38:5:1m" + -- ?pen foreground = idx(1) + -- push "\x1b[39m" + -- ?pen foreground = rgb(240,240,240,is_default_fg) + -- + -- Background + -- push "\x1b[41m" + -- ?pen background = idx(1) + -- push "\x1b[42m" + -- ?pen background = idx(2) + -- push "\x1b[44m" + -- ?pen background = idx(4) + -- push "\x1b[101m" + -- ?pen background = idx(9) + -- push "\x1b[48:2:10:20:30m" + -- ?pen background = rgb(10,20,30) + -- push "\x1b[48:5:1m" + -- ?pen background = idx(1) + -- push "\x1b[49m" + -- ?pen background = rgb(0,0,0,is_default_bg) + -- + -- Bold+ANSI colour == highbright + -- push "\x1b[m\x1b[1;37m" + -- ?pen bold = on + -- ?pen foreground = idx(15) + -- push "\x1b[m\x1b[37;1m" + -- ?pen bold = on + -- ?pen foreground = idx(15) + -- + -- Super/Subscript + -- push "\x1b[73m" + -- ?pen small = on + -- ?pen baseline = raise + -- push "\x1b[74m" + -- ?pen small = on + -- ?pen baseline = lower + -- push "\x1b[75m" + -- ?pen small = off + -- ?pen baseline = normal + -- + -- DECSTR resets pen attributes + -- push "\x1b[1;4m" + -- ?pen bold = on + -- ?pen underline = 1 + -- push "\x1b[!p" + -- ?pen bold = off + -- ?pen underline = 0 + end) + + itp('31state_rep', function() + local vt = init() + local state = wantstate(vt, { g = true }) + + -- REP no argument + reset(state, nil) + push('a\x1b[b', vt) + expect('putglyph 61 1 0,0\nputglyph 61 1 0,1') + + -- REP zero (zero should be interpreted as one) + reset(state, nil) + push('a\x1b[0b', vt) + expect('putglyph 61 1 0,0\nputglyph 61 1 0,1') + + -- REP lowercase a times two + reset(state, nil) + push('a\x1b[2b', vt) + expect('putglyph 61 1 0,0\nputglyph 61 1 0,1\nputglyph 61 1 0,2') + + -- REP with UTF-8 1 char + -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE + reset(state, nil) + push('\xC3\xA9\x1b[b', vt) + expect('putglyph e9 1 0,0\nputglyph e9 1 0,1') + + -- REP with UTF-8 wide char + -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE + reset(state, nil) + push('\xEF\xBC\x90\x1b[b', vt) + expect('putglyph ff10 2 0,0\nputglyph ff10 2 0,2') + + -- REP with UTF-8 combining character + reset(state, nil) + push('e\xCC\x81\x1b[b', vt) + expect('putglyph 65,301 1 0,0\nputglyph 65,301 1 0,1') + + -- REP till end of line + reset(state, nil) + push('a\x1b[1000bb', vt) + expect( + 'putglyph 61 1 0,0\nputglyph 61 1 0,1\nputglyph 61 1 0,2\nputglyph 61 1 0,3\nputglyph 61 1 0,4\nputglyph 61 1 0,5\nputglyph 61 1 0,6\nputglyph 61 1 0,7\nputglyph 61 1 0,8\nputglyph 61 1 0,9\nputglyph 61 1 0,10\nputglyph 61 1 0,11\nputglyph 61 1 0,12\nputglyph 61 1 0,13\nputglyph 61 1 0,14\nputglyph 61 1 0,15\nputglyph 61 1 0,16\nputglyph 61 1 0,17\nputglyph 61 1 0,18\nputglyph 61 1 0,19\nputglyph 61 1 0,20\nputglyph 61 1 0,21\nputglyph 61 1 0,22\nputglyph 61 1 0,23\nputglyph 61 1 0,24\nputglyph 61 1 0,25\nputglyph 61 1 0,26\nputglyph 61 1 0,27\nputglyph 61 1 0,28\nputglyph 61 1 0,29\nputglyph 61 1 0,30\nputglyph 61 1 0,31\nputglyph 61 1 0,32\nputglyph 61 1 0,33\nputglyph 61 1 0,34\nputglyph 61 1 0,35\nputglyph 61 1 0,36\nputglyph 61 1 0,37\nputglyph 61 1 0,38\nputglyph 61 1 0,39\nputglyph 61 1 0,40\nputglyph 61 1 0,41\nputglyph 61 1 0,42\nputglyph 61 1 0,43\nputglyph 61 1 0,44\nputglyph 61 1 0,45\nputglyph 61 1 0,46\nputglyph 61 1 0,47\nputglyph 61 1 0,48\nputglyph 61 1 0,49\nputglyph 61 1 0,50\nputglyph 61 1 0,51\nputglyph 61 1 0,52\nputglyph 61 1 0,53\nputglyph 61 1 0,54\nputglyph 61 1 0,55\nputglyph 61 1 0,56\nputglyph 61 1 0,57\nputglyph 61 1 0,58\nputglyph 61 1 0,59\nputglyph 61 1 0,60\nputglyph 61 1 0,61\nputglyph 61 1 0,62\nputglyph 61 1 0,63\nputglyph 61 1 0,64\nputglyph 61 1 0,65\nputglyph 61 1 0,66\nputglyph 61 1 0,67\nputglyph 61 1 0,68\nputglyph 61 1 0,69\nputglyph 61 1 0,70\nputglyph 61 1 0,71\nputglyph 61 1 0,72\nputglyph 61 1 0,73\nputglyph 61 1 0,74\nputglyph 61 1 0,75\nputglyph 61 1 0,76\nputglyph 61 1 0,77\nputglyph 61 1 0,78\nputglyph 61 1 0,79\nputglyph 62 1 1,0' + ) + end) + + itp('32state_flow', function() + local vt = init() + local state = wantstate(vt) + + -- Many of these test cases inspired by + -- https://blueprints.launchpad.net/libvterm/+spec/reflow-cases + + -- Spillover text marks continuation on second line + reset(state, nil) + push(string.rep('A', 100), vt) + push('\r\n', vt) + lineinfo(0, {}, state) + lineinfo(1, { cont = true }, state) + + -- CRLF in column 80 does not mark continuation + reset(state, nil) + push(string.rep('B', 80), vt) + push('\r\n', vt) + push(string.rep('B', 20), vt) + push('\r\n', vt) + lineinfo(0, {}, state) + lineinfo(1, {}, state) + + -- EL cancels continuation of following line + reset(state, nil) + push(string.rep('D', 100), vt) + lineinfo(1, { cont = true }, state) + push('\x1bM\x1b[79G\x1b[K', vt) + lineinfo(1, {}, state) + end) + + itp('40state_selection', function() + local vt = init() + wantstate(vt) + + -- Set clipboard; final chunk len 4 + push('\x1b]52;c;SGVsbG8s\x1b\\', vt) + expect('selection-set mask=0001 [Hello,]') + + -- Set clipboard; final chunk len 3 + push('\x1b]52;c;SGVsbG8sIHc=\x1b\\', vt) + expect('selection-set mask=0001 [Hello, w]') + + -- Set clipboard; final chunk len 2 + push('\x1b]52;c;SGVsbG8sIHdvcmxkCg==\x1b\\', vt) + expect('selection-set mask=0001 [Hello, world\n]') + + -- Set clipboard; split between chunks + push('\x1b]52;c;SGVs', vt) + expect('selection-set mask=0001 [Hel') + push('bG8s\x1b\\', vt) + expect('selection-set mask=0001 lo,]') + + -- Set clipboard; split within chunk + push('\x1b]52;c;SGVsbG', vt) + expect('selection-set mask=0001 [Hel') + push('8s\x1b\\', vt) + expect('selection-set mask=0001 lo,]') + + -- Set clipboard; empty first chunk + push('\x1b]52;c;', vt) + push('SGVsbG8s\x1b\\', vt) + expect('selection-set mask=0001 [Hello,]') + + -- Set clipboard; empty final chunk + push('\x1b]52;c;SGVsbG8s', vt) + expect('selection-set mask=0001 [Hello,') + push('\x1b\\', vt) + expect('selection-set mask=0001 ]') + + -- Set clipboard; longer than buffer + push('\x1b]52;c;' .. string.rep('LS0t', 10) .. '\x1b\\', vt) + expect('selection-set mask=0001 [---------------\nselection-set mask=0001 ---------------]') + + -- Clear clipboard + push('\x1b]52;c;\x1b\\', vt) + expect('selection-set mask=0001 []') + + -- Set invalid data clears and ignores + push('\x1b]52;c;SGVs*SGVsbG8s\x1b\\', vt) + expect('selection-set mask=0001 []') + + -- Query clipboard + push('\x1b]52;c;?\x1b\\', vt) + expect('selection-query mask=0001') + + -- TODO(dundargoc): fix + -- Send clipboard; final chunk len 4 + -- SELECTION 1 ["Hello,"] + -- output "\x1b]52;c;" + -- output "SGVsbG8s" + -- output "\x1b\\" + -- + -- Send clipboard; final chunk len 3 + -- SELECTION 1 ["Hello, w"] + -- output "\x1b]52;c;" + -- output "SGVsbG8s" + -- output "IHc=\x1b\\" + -- + -- Send clipboard; final chunk len 2 + -- SELECTION 1 ["Hello, world\n"] + -- output "\x1b]52;c;" + -- output "SGVsbG8sIHdvcmxk" + -- output "Cg==\x1b\\" + -- + -- Send clipboard; split between chunks + -- SELECTION 1 ["Hel" + -- output "\x1b]52;c;" + -- output "SGVs" + -- SELECTION 1 "lo,"] + -- output "bG8s" + -- output "\x1b\\" + -- + -- Send clipboard; split within chunk + -- SELECTION 1 ["Hello" + -- output "\x1b]52;c;" + -- output "SGVs" + -- SELECTION 1 ","] + -- output "bG8s" + -- output "\x1b\\" + end) + + itp('60screen_ascii', function() + local vt = init() + local screen = wantscreen(vt, { a = true, c = true }) + + -- Get + reset(nil, screen) + push('ABC', vt) + expect('movecursor 0,3') + screen_chars(0, 0, 1, 3, 'ABC', screen) + screen_chars(0, 0, 1, 80, 'ABC', screen) + screen_text(0, 0, 1, 3, '41,42,43', screen) + screen_text(0, 0, 1, 80, '41,42,43', screen) + screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + screen_cell(0, 1, '{42} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + screen_cell(0, 2, '{43} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + screen_row(0, 'ABC', screen) + screen_eol(0, 0, 0, screen) + screen_eol(0, 2, 0, screen) + screen_eol(0, 3, 1, screen) + push('\x1b[H', vt) + expect('movecursor 0,0') + screen_row(0, 'ABC', screen) + screen_text(0, 0, 1, 80, '41,42,43', screen) + push('E', vt) + expect('movecursor 0,1') + screen_row(0, 'EBC', screen) + screen_text(0, 0, 1, 80, '45,42,43', screen) + + screen = wantscreen(vt, { a = true }) + + -- Erase + reset(nil, screen) + push('ABCDE\x1b[H\x1b[K', vt) + -- TODO(dundargoc): fix + -- screen_row(0, '', screen) + screen_text(0, 0, 1, 80, '', screen) + + -- Copycell + reset(nil, screen) + push('ABC\x1b[H\x1b[@', vt) + push('1', vt) + screen_row(0, '1ABC', screen) + + reset(nil, screen) + push('ABC\x1b[H\x1b[P', vt) + screen_chars(0, 0, 1, 1, 'B', screen) + screen_chars(0, 1, 1, 2, 'C', screen) + screen_chars(0, 0, 1, 80, 'BC', screen) + + -- Space padding + reset(nil, screen) + push('Hello\x1b[CWorld', vt) + screen_row(0, 'Hello World', screen) + screen_text(0, 0, 1, 80, '48,65,6c,6c,6f,20,57,6f,72,6c,64', screen) + + -- Linefeed padding + reset(nil, screen) + push('Hello\r\nWorld', vt) + screen_chars(0, 0, 2, 80, 'Hello\nWorld', screen) + screen_text(0, 0, 2, 80, '48,65,6c,6c,6f,0a,57,6f,72,6c,64', screen) + + -- Altscreen + reset(nil, screen) + push('P', vt) + screen_row(0, 'P', screen) + -- TODO(dundargoc): fix + -- push('\x1b[?1049h', vt) + -- screen_row(0, '', screen) + -- push('\x1b[2K\x1b[HA', vt) + -- screen_row(0, 'A', screen) + -- push('\x1b[?1049l', vt) + -- screen_row(0, 'P', screen) + end) + + itp('61screen_unicode', function() + local vt = init() + local screen = wantscreen(vt) + + -- Single width UTF-8 + -- U+00C1 = C3 81 name: LATIN CAPITAL LETTER A WITH ACUTE + -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE + reset(nil, screen) + push('\xC3\x81\xC3\xA9', vt) + screen_row(0, 'Áé', screen) + screen_text(0, 0, 1, 80, 'c3,81,c3,a9', screen) + screen_cell(0, 0, '{c1} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- Wide char + -- U+FF10 = EF BC 90 name: FULLWIDTH DIGIT ZERO + reset(nil, screen) + push('0123\x1b[H', vt) + push('\xEF\xBC\x90', vt) + screen_row(0, '023', screen) + screen_text(0, 0, 1, 80, 'ef,bc,90,32,33', screen) + screen_cell(0, 0, '{ff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- Combining char + -- U+0301 = CC 81 name: COMBINING ACUTE + reset(nil, screen) + push('0123\x1b[H', vt) + push('e\xCC\x81', vt) + screen_row(0, 'é123', screen) + screen_text(0, 0, 1, 80, '65,cc,81,31,32,33', screen) + screen_cell(0, 0, '{65,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- 10 combining accents should not crash + reset(nil, screen) + push('e\xCC\x81\xCC\x82\xCC\x83\xCC\x84\xCC\x85\xCC\x86\xCC\x87\xCC\x88\xCC\x89\xCC\x8A', vt) + screen_cell( + 0, + 0, + '{65,301,302,303,304,305} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', + screen + ) + + -- 40 combining accents in two split writes of 20 should not crash + reset(nil, screen) + push( + 'e\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81', + vt + ) + push( + '\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81', + vt + ) + screen_cell( + 0, + 0, + '{65,301,301,301,301,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', + screen + ) + + -- Outputing CJK doublewidth in 80th column should wraparound to next line and not crash" + reset(nil, screen) + push('\x1b[80G\xEF\xBC\x90', vt) + screen_cell(0, 79, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + screen_cell(1, 0, '{ff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + end) + + pending('62screen_damage', function() end) + + itp('63screen_resize', function() + local vt = init() + local state = wantstate(vt) + local screen = wantscreen(vt) + + -- Resize wider preserves cells + reset(state, screen) + resize(25, 80, vt) + push('AB\r\nCD', vt) + screen_chars(0, 0, 1, 80, 'AB', screen) + screen_chars(1, 0, 2, 80, 'CD', screen) + resize(25, 100, vt) + screen_chars(0, 0, 1, 100, 'AB', screen) + screen_chars(1, 0, 2, 100, 'CD', screen) + + -- Resize wider allows print in new area + reset(state, screen) + resize(25, 80, vt) + push('AB\x1b[79GCD', vt) + screen_chars(0, 0, 1, 2, 'AB', screen) + screen_chars(0, 78, 1, 80, 'CD', screen) + resize(25, 100, vt) + screen_chars(0, 0, 1, 2, 'AB', screen) + screen_chars(0, 78, 1, 80, 'CD', screen) + push('E', vt) + screen_chars(0, 78, 1, 81, 'CDE', screen) + + -- Resize shorter with blanks just truncates + reset(state, screen) + resize(25, 80, vt) + push('Top\x1b[10HLine 10', vt) + screen_row(0, 'Top', screen) + screen_row(9, 'Line 10', screen) + cursor(9, 7, state) + resize(20, 80, vt) + screen_row(0, 'Top', screen) + screen_row(9, 'Line 10', screen) + cursor(9, 7, state) + + -- Resize shorter with content must scroll + reset(state, screen) + resize(25, 80, vt) + push('Top\x1b[25HLine 25\x1b[15H', vt) + screen_row(0, 'Top', screen) + screen_row(24, 'Line 25', screen) + cursor(14, 0, state) + screen = wantscreen(vt, { b = true }) + resize(20, 80, vt) + expect( + 'sb_pushline 80 = 54 6F 70\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =' + ) + -- TODO(dundargoc): fix or remove + -- screen_row( 0 , "",screen) + screen_row(19, 'Line 25', screen) + cursor(9, 0, state) + + -- Resize shorter does not lose line with cursor + -- See also https://github.com/neovim/libvterm/commit/1b745d29d45623aa8d22a7b9288c7b0e331c7088 + reset(state, screen) + wantscreen(vt) + resize(25, 80, vt) + screen = wantscreen(vt, { b = true }) + push('\x1b[24HLine 24\r\nLine 25\r\n', vt) + expect('sb_pushline 80 =') + screen_row(23, 'Line 25', screen) + cursor(24, 0, state) + resize(24, 80, vt) + expect('sb_pushline 80 =') + screen_row(22, 'Line 25', screen) + cursor(23, 0, state) + + -- Resize shorter does not send the cursor to a negative row + -- See also https://github.com/vim/vim/pull/6141 + reset(state, screen) + wantscreen(vt) + resize(25, 80, vt) + screen = wantscreen(vt, { b = true }) + push('\x1b[24HLine 24\r\nLine 25\x1b[H', vt) + cursor(0, 0, state) + resize(20, 80, vt) + expect( + 'sb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =' + ) + cursor(0, 0, state) + + -- Resize taller attempts to pop scrollback + reset(state, screen) + screen = wantscreen(vt) + resize(25, 80, vt) + push('Line 1\x1b[25HBottom\x1b[15H', vt) + screen_row(0, 'Line 1', screen) + screen_row(24, 'Bottom', screen) + cursor(14, 0, state) + screen = wantscreen(vt, { b = true }) + resize(30, 80, vt) + expect('sb_popline 80\nsb_popline 80\nsb_popline 80\nsb_popline 80\nsb_popline 80') + screen_row(0, 'ABCDE', screen) + screen_row(5, 'Line 1', screen) + screen_row(29, 'Bottom', screen) + cursor(19, 0, state) + screen = wantscreen(vt) + + -- Resize can operate on altscreen + reset(state, screen) + screen = wantscreen(vt, { a = true }) + resize(25, 80, vt) + push('Main screen\x1b[?1049h\x1b[HAlt screen', vt) + resize(30, 80, vt) + screen_row(0, 'Alt screen', screen) + push('\x1b[?1049l', vt) + screen_row(0, 'Main screen', screen) + end) + + itp('64screen_pen', function() + local vt = init() + local screen = wantscreen(vt) + + reset(nil, screen) + + -- Plain + push('A', vt) + screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- Bold + push('\x1b[1mB', vt) + screen_cell(0, 1, '{42} width=1 attrs={B} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- Italic + push('\x1b[3mC', vt) + screen_cell(0, 2, '{43} width=1 attrs={BI} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- Underline + push('\x1b[4mD', vt) + screen_cell(0, 3, '{44} width=1 attrs={BU1I} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- Reset + push('\x1b[mE', vt) + screen_cell(0, 4, '{45} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- Font + push('\x1b[11mF\x1b[m', vt) + screen_cell(0, 5, '{46} width=1 attrs={F1} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- Foreground + push('\x1b[31mG\x1b[m', vt) + screen_cell(0, 6, '{47} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)', screen) + + -- Background + push('\x1b[42mH\x1b[m', vt) + screen_cell(0, 7, '{48} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,224,0)', screen) + + -- Super/subscript + push('x\x1b[74m0\x1b[73m2\x1b[m', vt) + screen_cell(0, 8, '{78} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + screen_cell(0, 9, '{30} width=1 attrs={S_} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + screen_cell(0, 10, '{32} width=1 attrs={S^} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- EL sets only colours to end of line, not other attrs + push('\x1b[H\x1b[7;33;44m\x1b[K', vt) + screen_cell(0, 0, '{} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen) + screen_cell(0, 79, '{} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen) + + -- DECSCNM xors reverse for entire screen + push('R\x1b[?5h', vt) + screen_cell(0, 0, '{52} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen) + screen_cell(1, 0, '{} width=1 attrs={R} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + push('\x1b[?5$p', vt) + expect_output('\x1b[?5;1$y') + push('\x1b[?5l', vt) + screen_cell(0, 0, '{52} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen) + screen_cell(1, 0, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + -- TODO(dundargoc): fix + -- push('\x1b[?5$p') + -- expect_output('\x1b[?5;2$y') + + -- Set default colours + reset(nil, screen) + push('ABC\x1b[31mDEF\x1b[m', vt) + screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + screen_cell(0, 3, '{44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)', screen) + -- TODO(dundargoc): fix + -- SETDEFAULTCOL rgb(252,253,254) + -- ?screen_cell 0,0 = {41} width=1 attrs={} fg=rgb(252,253,254) bg=rgb(0,0,0) + -- ?screen_cell 0,3 = {44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0) + -- SETDEFAULTCOL rgb(250,250,250) rgb(10,20,30) + -- ?screen_cell 0,0 = {41} width=1 attrs={} fg=rgb(250,250,250) bg=rgb(10,20,30) + -- ?screen_cell 0,3 = {44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(10,20,30) + end) + + itp('65screen_protect', function() + local vt = init() + local screen = wantscreen(vt) + + -- Selective erase + reset(nil, screen) + push('A\x1b[1"qB\x1b["qC', vt) + screen_row(0, 'ABC', screen) + push('\x1b[G\x1b[?J', vt) + screen_row(0, ' B', screen) + + -- Non-selective erase + reset(nil, screen) + push('A\x1b[1"qB\x1b["qC', vt) + screen_row(0, 'ABC', screen) + -- TODO(dundargoc): fix + -- push('\x1b[G\x1b[J', vt) + -- screen_row(0, '', screen) + end) + + itp('66screen_extent', function() + local vt = init() + local screen = wantscreen(vt) + + -- Bold extent + reset(nil, screen) + push('AB\x1b[1mCD\x1b[mE', vt) + screen_attrs_extent(0, 0, '0,0-1,1', screen) + screen_attrs_extent(0, 1, '0,0-1,1', screen) + screen_attrs_extent(0, 2, '0,2-1,3', screen) + screen_attrs_extent(0, 3, '0,2-1,3', screen) + screen_attrs_extent(0, 4, '0,4-1,79', screen) + end) + + itp('67screen_dbl_wh', function() + local vt = init() + local screen = wantscreen(vt) + + reset(nil, screen) + + -- Single Width, Single Height + reset(nil, screen) + push('\x1b#5', vt) + push('abcde', vt) + screen_cell(0, 0, '{61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- Double Width, Single Height + reset(nil, screen) + push('\x1b#6', vt) + push('abcde', vt) + screen_cell(0, 0, '{61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- Double Height + reset(nil, screen) + push('\x1b#3', vt) + push('abcde', vt) + push('\r\n\x1b#4', vt) + push('abcde', vt) + screen_cell(0, 0, '{61} width=1 attrs={} dwl dhl-top fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + screen_cell( + 1, + 0, + '{61} width=1 attrs={} dwl dhl-bottom fg=rgb(240,240,240) bg=rgb(0,0,0)', + screen + ) + + -- Late change + reset(nil, screen) + push('abcde', vt) + screen_cell(0, 0, '{61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + push('\x1b#6', vt) + screen_cell(0, 0, '{61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + + -- DWL doesn't spill over on scroll + reset(nil, screen) + push('\x1b[25H\x1b#6Final\r\n', vt) + screen_cell(23, 0, '{46} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + screen_cell(24, 0, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) + end) + + itp('68screen_termprops', function() + local vt = init() + local screen = wantscreen(vt, { p = true }) + + reset(nil, screen) + expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') + + -- Cursor visibility + push('\x1b[?25h', vt) + expect('settermprop 1 true') + push('\x1b[?25l', vt) + expect('settermprop 1 false') + + -- Title + push('\x1b]2;Here is my title\a', vt) + expect('settermprop 4 ["Here is my title"]') + end) + + itp('69screen_pushline', function() + local vt = init() + -- Run these tests on a much smaller default screen, so debug output is nowhere near as noisy + resize(5, 10, vt) + local state = wantstate(vt) + local screen = wantscreen(vt, { r = true }) + reset(state, screen) + + -- Resize wider reflows wide lines + reset(state, screen) + push(string.rep('A', 12), vt) + screen_row(0, 'AAAAAAAAAA', screen, vt.cols) + screen_row(1, 'AA', screen, vt.cols) + lineinfo(1, { cont = true }, state) + cursor(1, 2, state) + resize(5, 15, vt) + screen_row(0, 'AAAAAAAAAAAA', screen, vt.cols) + -- TODO(dundargoc): fix + -- screen_row(1, '', screen, vt.cols) + lineinfo(1, {}, state) + cursor(0, 12, state) + resize(5, 20, vt) + screen_row(0, 'AAAAAAAAAAAA', screen, vt.cols) + -- TODO(dundargoc): fix + -- screen_row( 1 ,'',screen, vt.cols) + lineinfo(1, {}, state) + cursor(0, 12, state) + + -- Resize narrower can create continuation lines + reset(state, screen) + resize(5, 10, vt) + push('ABCDEFGHI', vt) + screen_row(0, 'ABCDEFGHI', screen, vt.cols) + -- TODO(dundargoc): fix + -- screen_row( 1 , "",screen, vt.cols) + lineinfo(1, {}, state) + cursor(0, 9, state) + resize(5, 8, vt) + -- TODO(dundargoc): fix + -- screen_row( 0 , "ABCDEFGH",screen,vt.cols) + screen_row(1, 'I', screen, vt.cols) + lineinfo(1, { cont = true }, state) + cursor(1, 1, state) + resize(5, 6, vt) + screen_row(0, 'ABCDEF', screen, vt.cols) + screen_row(1, 'GHI', screen, vt.cols) + lineinfo(1, { cont = true }, state) + cursor(1, 3, state) + + -- Shell wrapped prompt behaviour + reset(state, screen) + resize(5, 10, vt) + push('PROMPT GOES HERE\r\n> \r\n\r\nPROMPT GOES HERE\r\n> ', vt) + screen_row(0, '> ', screen, vt.cols) + -- TODO(dundargoc): fix + -- screen_row( 1 , "",screen,vt.cols) + screen_row(2, 'PROMPT GOE', screen, vt.cols) + screen_row(3, 'S HERE', screen, vt.cols) + lineinfo(3, { cont = true }, state) + screen_row(4, '> ', screen, vt.cols) + cursor(4, 2, state) + resize(5, 11, vt) + screen_row(0, '> ', screen, vt.cols) + -- TODO(dundargoc): fix + -- screen_row( 1 , "",screen,vt.cols) + screen_row(2, 'PROMPT GOES', screen, vt.cols) + screen_row(3, ' HERE', screen, vt.cols) + lineinfo(3, { cont = true }, state) + screen_row(4, '> ', screen, vt.cols) + cursor(4, 2, state) + resize(5, 12, vt) + screen_row(0, '> ', screen, vt.cols) + -- TODO(dundargoc): fix + -- screen_row( 1 , "",screen,vt.cols) + screen_row(2, 'PROMPT GOES ', screen, vt.cols) + screen_row(3, 'HERE', screen, vt.cols) + lineinfo(3, { cont = true }, state) + screen_row(4, '> ', screen, vt.cols) + cursor(4, 2, state) + resize(5, 16, vt) + screen_row(0, '> ', screen, vt.cols) + -- TODO(dundargoc): fix + -- screen_row( 1 , "",screen,vt.cols) + -- screen_row( 2 , "PROMPT GOES HERE",screen,vt.cols) + lineinfo(3, {}, state) + screen_row(3, '> ', screen, vt.cols) + cursor(3, 2, state) + + -- Cursor goes missing + -- For more context: https://github.com/neovim/neovim/pull/21124 + reset(state, screen) + resize(5, 5, vt) + resize(3, 1, vt) + push('\x1b[2;1Habc\r\n\x1b[H', vt) + resize(1, 1, vt) + cursor(0, 0, state) + end) + + pending('90vttest_01-movement-1', function() end) + pending('90vttest_01-movement-2', function() end) + + itp('90vttest_01-movement-3', function() + -- Test of cursor-control characters inside ESC sequences + local vt = init() + local state = wantstate(vt) + local screen = wantscreen(vt) + + reset(state, screen) + + push('A B C D E F G H I', vt) + push('\x0d\x0a', vt) + push('A\x1b[2\bCB\x1b[2\bCC\x1b[2\bCD\x1b[2\bCE\x1b[2\bCF\x1b[2\bCG\x1b[2\bCH\x1b[2\bCI', vt) + push('\x0d\x0a', vt) + push( + 'A \x1b[\x0d2CB\x1b[\x0d4CC\x1b[\x0d6CD\x1b[\x0d8CE\x1b[\x0d10CF\x1b[\x0d12CG\x1b[\x0d14CH\x1b[\x0d16CI', + vt + ) + push('\x0d\x0a', vt) + push( + 'A \x1b[1\x0bAB \x1b[1\x0bAC \x1b[1\x0bAD \x1b[1\x0bAE \x1b[1\x0bAF \x1b[1\x0bAG \x1b[1\x0bAH \x1b[1\x0bAI \x1b[1\x0bA', + vt + ) + + -- Output + + for i = 0, 2 do + screen_row(i, 'A B C D E F G H I', screen) + end + screen_row(3, 'A B C D E F G H I ', screen) + + cursor(3, 18, state) + end) + + itp('90vttest_01-movement-4', function() + -- Test of leading zeroes in ESC sequences + local vt = init() + local screen = wantscreen(vt) + + reset(nil, screen) + + push('\x1b[00000000004;000000001HT', vt) + push('\x1b[00000000004;000000002Hh', vt) + push('\x1b[00000000004;000000003Hi', vt) + push('\x1b[00000000004;000000004Hs', vt) + push('\x1b[00000000004;000000005H ', vt) + push('\x1b[00000000004;000000006Hi', vt) + push('\x1b[00000000004;000000007Hs', vt) + push('\x1b[00000000004;000000008H ', vt) + push('\x1b[00000000004;000000009Ha', vt) + push('\x1b[00000000004;0000000010H ', vt) + push('\x1b[00000000004;0000000011Hc', vt) + push('\x1b[00000000004;0000000012Ho', vt) + push('\x1b[00000000004;0000000013Hr', vt) + push('\x1b[00000000004;0000000014Hr', vt) + push('\x1b[00000000004;0000000015He', vt) + push('\x1b[00000000004;0000000016Hc', vt) + push('\x1b[00000000004;0000000017Ht', vt) + push('\x1b[00000000004;0000000018H ', vt) + push('\x1b[00000000004;0000000019Hs', vt) + push('\x1b[00000000004;0000000020He', vt) + push('\x1b[00000000004;0000000021Hn', vt) + push('\x1b[00000000004;0000000022Ht', vt) + push('\x1b[00000000004;0000000023He', vt) + push('\x1b[00000000004;0000000024Hn', vt) + push('\x1b[00000000004;0000000025Hc', vt) + push('\x1b[00000000004;0000000026He', vt) + + -- Output + + screen_row(3, 'This is a correct sentence', screen) + end) + + pending('90vttest_02-screen-1', function() end) + pending('90vttest_02-screen-2', function() end) + + itp('90vttest_02-screen-3', function() + -- Origin mode + local vt = init() + local screen = wantscreen(vt) + + reset(nil, screen) + + push('\x1b[?6h', vt) + push('\x1b[23;24r', vt) + push('\n', vt) + push('Bottom', vt) + push('\x1b[1;1H', vt) + push('Above', vt) + + -- Output + screen_row(22, 'Above', screen) + screen_row(23, 'Bottom', screen) + end) + + itp('90vttest_02-screen-4', function() + -- Origin mode (2) + local vt = init() + local screen = wantscreen(vt) + + reset(nil, screen) + + push('\x1b[?6l', vt) + push('\x1b[23;24r', vt) + push('\x1b[24;1H', vt) + push('Bottom', vt) + push('\x1b[1;1H', vt) + push('Top', vt) + + -- Output + screen_row(23, 'Bottom', screen) + screen_row(0, 'Top', screen) + end) + + itp('Mouse reporting should not break by idempotent DECSM 1002', function() + -- Regression test for https://bugs.launchpad.net/libvterm/+bug/1640917 + -- Related: https://github.com/neovim/neovim/issues/5583 + local vt = init() + wantstate(vt, {}) + + push('\x1b[?1002h', vt) + mousemove(0, 0, vt) + mousebtn('d', 1, vt) + expect_output('\x1b[M\x20\x21\x21') + mousemove(1, 0, vt) + expect_output('\x1b[M\x40\x21\x22') + push('\x1b[?1002h', vt) + mousemove(2, 0, vt) + expect_output('\x1b[M\x40\x21\x23') + end) +end) |