diff options
Diffstat (limited to 'test')
23 files changed, 1393 insertions, 87 deletions
diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index 058706718a..21e3094f8e 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -158,3 +158,98 @@ describe('API: highlight',function() assert_alive() end) end) + +describe("API: set highlight", function() + local highlight_color = { + fg = tonumber('0xff0000'), + bg = tonumber('0x0032aa'), + ctermfg = 8, + ctermbg = 15, + } + local highlight1 = { + background = highlight_color.bg, + foreground = highlight_color.fg, + bold = true, + italic = true, + } + local highlight2_config = { + ctermbg = highlight_color.ctermbg, + ctermfg = highlight_color.ctermfg, + underline = true, + reverse = true, + } + local highlight2_result = { + background = highlight_color.ctermbg, + foreground = highlight_color.ctermfg, + underline = true, + reverse = true, + } + local highlight3_config = { + background = highlight_color.bg, + foreground = highlight_color.fg, + ctermbg = highlight_color.ctermbg, + ctermfg = highlight_color.ctermfg, + bold = true, + italic = true, + reverse = true, + undercurl = true, + underline = true, + cterm = { + italic = true, + reverse = true, + undercurl = true, + } + } + local highlight3_result_gui = { + background = highlight_color.bg, + foreground = highlight_color.fg, + bold = true, + italic = true, + reverse = true, + undercurl = true, + underline = true, + } + local highlight3_result_cterm = { + background = highlight_color.ctermbg, + foreground = highlight_color.ctermfg, + italic = true, + reverse = true, + undercurl = true, + } + + local function get_ns() + local ns = meths.create_namespace('Test_set_hl') + meths._set_hl_ns(ns) + return ns + end + + before_each(clear) + + it ("can set gui highlight", function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', highlight1) + eq(highlight1, meths.get_hl_by_name('Test_hl', true)) + end) + + it ("can set cterm highlight", function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', highlight2_config) + eq(highlight2_result, meths.get_hl_by_name('Test_hl', false)) + end) + + it ("cterm attr defaults to gui attr", function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', highlight1) + eq({ + bold = true, + italic = true, + }, meths.get_hl_by_name('Test_hl', false)) + end) + + it ("can overwrite attr for cterm", function() + local ns = get_ns() + meths.set_hl(ns, 'Test_hl', highlight3_config) + eq(highlight3_result_gui, meths.get_hl_by_name('Test_hl', true)) + eq(highlight3_result_cterm, meths.get_hl_by_name('Test_hl', false)) + end) +end) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 3db44f3f11..6926022ee3 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -193,6 +193,44 @@ describe('API', function() eq('', nvim('exec', 'echo', true)) eq('foo 42', nvim('exec', 'echo "foo" 42', true)) end) + + it('displays messages when output=false', function() + local screen = Screen.new(40, 8) + screen:attach() + screen:set_default_attr_ids({ + [0] = {bold=true, foreground=Screen.colors.Blue}, + }) + meths.exec("echo 'hello'", false) + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + hello | + ]]} + end) + + it('does\'t display messages when output=true', function() + local screen = Screen.new(40, 8) + screen:attach() + screen:set_default_attr_ids({ + [0] = {bold=true, foreground=Screen.colors.Blue}, + }) + meths.exec("echo 'hello'", true) + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + end) end) describe('nvim_command', function() diff --git a/test/functional/autoread/focus_spec.lua b/test/functional/autoread/focus_spec.lua index 1d52e9948f..3f9a0ad09b 100644 --- a/test/functional/autoread/focus_spec.lua +++ b/test/functional/autoread/focus_spec.lua @@ -9,6 +9,7 @@ local feed_data = thelpers.feed_data if helpers.pending_win32(pending) then return end describe('autoread TUI FocusGained/FocusLost', function() + local f1 = 'xtest-foo' local screen before_each(function() @@ -17,8 +18,12 @@ describe('autoread TUI FocusGained/FocusLost', function() ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]') end) + teardown(function() + os.remove(f1) + end) + it('external file change', function() - local path = 'xtest-foo' + local path = f1 local expected_addition = [[ line 1 line 2 diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index b59d87eb12..34ab90d760 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -118,6 +118,32 @@ describe('jobs', function() end end) + it('handles case-insensitively matching #env vars', function() + nvim('command', "let $TOTO = 'abc'") + -- Since $Toto is being set in the job, it should take precedence over the + -- global $TOTO on Windows + nvim('command', "let g:job_opts = {'env': {'Toto': 'def'}, 'stdout_buffered': v:true}") + if iswin() then + nvim('command', [[let j = jobstart('set | find /I "toto="', g:job_opts)]]) + else + nvim('command', [[let j = jobstart('env | grep -i toto=', g:job_opts)]]) + end + nvim('command', "call jobwait([j])") + nvim('command', "let g:output = Normalize(g:job_opts.stdout)") + local actual = eval('g:output') + local expected + if iswin() then + -- Toto is normalized to TOTO so we can detect duplicates, and because + -- Windows doesn't care about case + expected = {'TOTO=def', ''} + else + expected = {'TOTO=abc', 'Toto=def', ''} + end + table.sort(actual) + table.sort(expected) + eq(expected, actual) + end) + it('uses &shell and &shellcmdflag if passed a string', function() nvim('command', "let $VAR = 'abc'") if iswin() then @@ -963,8 +989,10 @@ describe('jobs', function() return rv end + local j local function send(str) - nvim('command', 'call jobsend(j, "'..str..'")') + -- check no nvim_chan_free double free with pty job (#14198) + meths.chan_send(j, str) end before_each(function() @@ -979,6 +1007,7 @@ describe('jobs', function() nvim('command', 'let g:job_opts.pty = 1') nvim('command', 'let exec = [expand("<cfile>:p")]') nvim('command', "let j = jobstart(exec, g:job_opts)") + j = eval'j' eq('tty ready', next_chunk()) end) diff --git a/test/functional/eval/null_spec.lua b/test/functional/eval/null_spec.lua index fa8f7d873f..8f0041ff27 100644 --- a/test/functional/eval/null_spec.lua +++ b/test/functional/eval/null_spec.lua @@ -14,7 +14,8 @@ describe('NULL', function() clear() command('let L = v:_null_list') command('let D = v:_null_dict') - command('let S = $XXX_NONEXISTENT_VAR_XXX') + command('let S = v:_null_string') + command('let V = $XXX_NONEXISTENT_VAR_XXX') end) local tmpfname = 'Xtest-functional-viml-null' after_each(function() @@ -72,6 +73,7 @@ describe('NULL', function() null_expr_test('does not crash col()', 'col(L)', 0, 0) null_expr_test('does not crash virtcol()', 'virtcol(L)', 0, 0) null_expr_test('does not crash line()', 'line(L)', 0, 0) + null_expr_test('does not crash line() with window id', 'line(L, 1000)', 0, 0) null_expr_test('does not crash count()', 'count(L, 1)', 0, 0) null_expr_test('does not crash cursor()', 'cursor(L)', 'E474: Invalid argument', -1) null_expr_test('does not crash map()', 'map(L, "v:val")', 0, {}) @@ -95,7 +97,7 @@ describe('NULL', function() null_expr_test('makes filter() return v:_null_list', 'filter(L, "1") is# L', 0, 1) null_test('is treated by :let as empty list', ':let [l] = L', 'Vim(let):E688: More targets than List items') null_expr_test('is accepted as an empty list by inputlist()', '[feedkeys("\\n"), inputlist(L)]', - 'Type number and <Enter> or click with mouse (empty cancels): ', {0, 0}) + 'Type number and <Enter> or click with the mouse (q or empty cancels): ', {0, 0}) null_expr_test('is accepted as an empty list by writefile()', ('[writefile(L, "%s"), readfile("%s")]'):format(tmpfname, tmpfname), 0, {0, {}}) @@ -129,6 +131,7 @@ describe('NULL', function() null_expr_test('is accepted by setloclist()', 'setloclist(1, L)', 0, 0) null_test('is accepted by :cexpr', 'cexpr L', 0) null_test('is accepted by :lexpr', 'lexpr L', 0) + null_expr_test('does not crash execute()', 'execute(L)', 0, '') end) describe('dict', function() it('does not crash when indexing NULL dict', function() @@ -142,4 +145,26 @@ describe('NULL', function() null_expr_test('makes map() return v:_null_dict', 'map(D, "v:val") is# D', 0, 1) null_expr_test('makes filter() return v:_null_dict', 'filter(D, "1") is# D', 0, 1) end) + describe('string', function() + null_test('does not crash :echomsg', 'echomsg S', 0) + null_test('does not crash :execute', 'execute S', 0) + null_expr_test('does not crash execute()', 'execute(S)', 0, '') + null_expr_test('makes executable() error out', 'executable(S)', 'E928: String required', 0) + null_expr_test('does not crash filereadable()', 'filereadable(S)', 0, 0) + null_expr_test('does not crash filewritable()', 'filewritable(S)', 0, 0) + null_expr_test('does not crash fnamemodify()', 'fnamemodify(S, S)', 0, '') + null_expr_test('does not crash getfperm()', 'getfperm(S)', 0, '') + null_expr_test('does not crash getfsize()', 'getfsize(S)', 0, -1) + null_expr_test('does not crash getftime()', 'getftime(S)', 0, -1) + null_expr_test('does not crash getftype()', 'getftype(S)', 0, '') + null_expr_test('does not crash glob()', 'glob(S)', 0, '') + null_expr_test('does not crash globpath()', 'globpath(S, S)', 0, '') + null_expr_test('does not crash mkdir()', 'mkdir(S)', 0, 0) + null_expr_test('does not crash sort()', 'sort(["b", S, "a"])', 0, {'', 'a', 'b'}) + null_expr_test('does not crash split()', 'split(S)', 0, {}) + + null_test('can be used to set an option', 'let &grepprg = S', 0) + + null_expr_test('is equal to non-existent variable', 'S == V', 0, 1) + end) end) diff --git a/test/functional/eval/writefile_spec.lua b/test/functional/eval/writefile_spec.lua index 0bb7523d7e..356680ba7c 100644 --- a/test/functional/eval/writefile_spec.lua +++ b/test/functional/eval/writefile_spec.lua @@ -59,6 +59,16 @@ describe('writefile()', function() eq('\n', read_file(fname)) end) + it('writes list with a null string to a file', function() + eq(0, exc_exec( + ('call writefile([v:_null_string], "%s", "b")'):format( + fname))) + eq('', read_file(fname)) + eq(0, exc_exec(('call writefile([v:_null_string], "%s")'):format( + fname))) + eq('\n', read_file(fname)) + end) + it('appends to a file', function() eq(nil, read_file(fname)) eq(0, funcs.writefile({'abc', 'def', 'ghi'}, fname)) diff --git a/test/functional/legacy/packadd_spec.lua b/test/functional/legacy/packadd_spec.lua index 609f825177..486a1fe471 100644 --- a/test/functional/legacy/packadd_spec.lua +++ b/test/functional/legacy/packadd_spec.lua @@ -267,6 +267,8 @@ describe('packadd', function() call assert_match('look-here', tags1[0]) let tags2 = readfile(docdir2 . '/tags') call assert_match('look-away', tags2[0]) + + call assert_fails('helptags abcxyz', 'E150:') endfunc func Test_colorscheme() diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index 6d7d9b4d8b..54e10fabd6 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -461,6 +461,36 @@ describe('lua: nvim_buf_attach on_bytes', function() } end) + it("deleting lines", function() + local check_events = setup_eventcheck(verify, origlines) + + feed("dd") + + check_events { + { "test1", "bytes", 1, 3, 0, 0, 0, 1, 0, 16, 0, 0, 0 }; + } + + feed("d2j") + + check_events { + { "test1", "bytes", 1, 4, 0, 0, 0, 3, 0, 48, 0, 0, 0 }; + } + + feed("ld<c-v>2j") + + check_events { + { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 0, 0 }; + { "test1", "bytes", 1, 5, 1, 1, 16, 0, 1, 1, 0, 0, 0 }; + { "test1", "bytes", 1, 5, 2, 1, 31, 0, 1, 1, 0, 0, 0 }; + } + + feed("vjwd") + + check_events { + { "test1", "bytes", 1, 10, 0, 1, 1, 1, 9, 23, 0, 0, 0 }; + } + end) + it("changing lines", function() local check_events = setup_eventcheck(verify, origlines) @@ -537,20 +567,65 @@ describe('lua: nvim_buf_attach on_bytes', function() end) it('inccomand=nosplit and substitute', function() - local check_events = setup_eventcheck(verify, {"abcde"}) + local check_events = setup_eventcheck(verify, + {"abcde", "12345"}) meths.set_option('inccommand', 'nosplit') - feed ':%s/bcd/' + -- linewise substitute + feed(':%s/bcd/') check_events { { "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 0, 0 }; { "test1", "bytes", 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 }; } - feed 'a' + feed('a') check_events { { "test1", "bytes", 1, 3, 0, 1, 1, 0, 3, 3, 0, 1, 1 }; { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 3, 3 }; } + + feed("<esc>") + + -- splitting lines + feed([[:%s/abc/\r]]) + check_events { + { "test1", "bytes", 1, 3, 0, 0, 0, 0, 3, 3, 1, 0, 1 }; + { "test1", "bytes", 1, 6, 0, 0, 0, 1, 0, 1, 0, 3, 3 }; + } + + feed("<esc>") + -- multi-line regex + feed([[:%s/de\n123/a]]) + + check_events { + { "test1", "bytes", 1, 3, 0, 3, 3, 1, 3, 6, 0, 1, 1 }; + { "test1", "bytes", 1, 6, 0, 3, 3, 0, 1, 1, 1, 3, 6 }; + } + + feed("<esc>") + -- replacing with unicode + feed(":%s/b/β") + + check_events { + { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 3, 3 }; + { "test1", "bytes", 1, 5, 0, 1, 1, 0, 3, 3, 0, 1, 1 }; + } + + feed("<esc>") + -- replacing with escaped characters + feed([[:%s/b/\\]]) + check_events { + { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 1, 1 }; + { "test1", "bytes", 1, 5, 0, 1, 1, 0, 1, 1, 0, 1, 1 }; + } + + feed("<esc>") + -- replacing with expression register + feed([[:%s/b/\=5+5]]) + check_events { + { "test1", "bytes", 1, 3, 0, 1, 1, 0, 1, 1, 0, 2, 2 }; + { "test1", "bytes", 1, 5, 0, 1, 1, 0, 2, 2, 0, 1, 1 }; + } end) it('nvim_buf_set_text insert', function() @@ -670,7 +745,7 @@ describe('lua: nvim_buf_attach on_bytes', function() command("set noet") command("set ts=4") command("set sw=2") - command("set sts=2") + command("set sts=4") local check_events = setup_eventcheck(verify, {'asdfasdf'}) @@ -689,6 +764,7 @@ describe('lua: nvim_buf_attach on_bytes', function() { "test1", "bytes", 1, 7, 0, 0, 0, 0, 4, 4, 0, 1, 1 }, } + feed("<esc>u") check_events { { "test1", "bytes", 1, 8, 0, 0, 0, 0, 1, 1, 0, 4, 4 }, @@ -728,6 +804,29 @@ describe('lua: nvim_buf_attach on_bytes', function() { "test1", "bytes", 1, 29, 0, 0, 0, 0, 0, 0, 0, 1, 1 }; { "test1", "bytes", 1, 31, 0, 0, 0, 0, 4, 4, 0, 1, 1 }; } + + -- inserting tab after other tabs + command("set sw=4") + feed("<esc>0a<tab>") + check_events { + { "test1", "bytes", 1, 32, 0, 1, 1, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 33, 0, 2, 2, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 34, 0, 3, 3, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 35, 0, 4, 4, 0, 0, 0, 0, 1, 1 }; + { "test1", "bytes", 1, 36, 0, 1, 1, 0, 4, 4, 0, 1, 1 }; + } + end) + + it("retab", function() + command("set noet") + command("set ts=4") + + local check_events = setup_eventcheck(verify, {" asdf"}) + command("retab 8") + + check_events { + { "test1", "bytes", 1, 3, 0, 0, 0, 0, 7, 7, 0, 9, 9 }; + } end) it("sends events when undoing with undofile", function() @@ -802,6 +901,106 @@ describe('lua: nvim_buf_attach on_bytes', function() end) + it(":luado", function() + local check_events = setup_eventcheck(verify, {"abc", "12345"}) + + command(".luado return 'a'") + + check_events { + { "test1", "bytes", 1, 3, 0, 0, 0, 0, 3, 3, 0, 1, 1 }; + } + + command("luado return 10") + + check_events { + { "test1", "bytes", 1, 4, 0, 0, 0, 0, 1, 1, 0, 2, 2 }; + { "test1", "bytes", 1, 5, 1, 0, 3, 0, 5, 5, 0, 2, 2 }; + } + + end) + + it("flushes deleted bytes on move", function() + local check_events = setup_eventcheck(verify, {"AAA", "BBB", "CCC", "DDD"}) + + feed(":.move+1<cr>") + + check_events { + { "test1", "bytes", 1, 5, 0, 0, 0, 1, 0, 4, 0, 0, 0 }; + { "test1", "bytes", 1, 5, 1, 0, 4, 0, 0, 0, 1, 0, 4 }; + } + + feed("jd2j") + + check_events { + { "test1", "bytes", 1, 6, 2, 0, 8, 2, 0, 8, 0, 0, 0 }; + } + end) + + it("virtual edit", function () + local check_events = setup_eventcheck(verify, { "", " " }) + + meths.set_option("virtualedit", "all") + + feed [[<Right><Right>iab<ESC>]] + + check_events { + { "test1", "bytes", 1, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2 }; + { "test1", "bytes", 1, 4, 0, 2, 2, 0, 0, 0, 0, 2, 2 }; + } + + feed [[j<Right><Right>iab<ESC>]] + + check_events { + { "test1", "bytes", 1, 5, 1, 0, 5, 0, 1, 1, 0, 8, 8 }; + { "test1", "bytes", 1, 6, 1, 5, 10, 0, 0, 0, 0, 2, 2 }; + } + end) + + it("block visual paste", function() + local check_events = setup_eventcheck(verify, {"AAA", + "BBB", + "CCC", + "DDD", + "EEE", + "FFF"}) + funcs.setreg("a", "___") + feed([[gg0l<c-v>3jl"ap]]) + + check_events { + { "test1", "bytes", 1, 3, 0, 1, 1, 0, 2, 2, 0, 0, 0 }; + { "test1", "bytes", 1, 3, 1, 1, 3, 0, 2, 2, 0, 0, 0 }; + { "test1", "bytes", 1, 3, 2, 1, 5, 0, 2, 2, 0, 0, 0 }; + { "test1", "bytes", 1, 3, 3, 1, 7, 0, 2, 2, 0, 0, 0 }; + { "test1", "bytes", 1, 5, 0, 1, 1, 0, 0, 0, 0, 3, 3 }; + { "test1", "bytes", 1, 6, 1, 1, 6, 0, 0, 0, 0, 3, 3 }; + { "test1", "bytes", 1, 7, 2, 1, 11, 0, 0, 0, 0, 3, 3 }; + { "test1", "bytes", 1, 8, 3, 1, 16, 0, 0, 0, 0, 3, 3 }; + } + end) + + it("nvim_buf_set_lines", function() + local check_events = setup_eventcheck(verify, {"AAA", "BBB"}) + + -- delete + meths.buf_set_lines(0, 0, 1, true, {}) + + check_events { + { "test1", "bytes", 1, 3, 0, 0, 0, 1, 0, 4, 0, 0, 0 }; + } + + -- add + meths.buf_set_lines(0, 0, 0, true, {'asdf'}) + check_events { + { "test1", "bytes", 1, 4, 0, 0, 0, 0, 0, 0, 1, 0, 5 }; + } + + -- replace + meths.buf_set_lines(0, 0, 1, true, {'asdf', 'fdsa'}) + check_events { + { "test1", "bytes", 1, 5, 0, 0, 0, 1, 0, 5, 2, 0, 10 }; + } + end) + teardown(function() os.remove "Xtest-reload" os.remove "Xtest-undofile" diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 9bf00b594b..6566da4807 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -945,12 +945,20 @@ describe('lua stdlib', function() exec_lua [[ vim.api.nvim_set_var("testing", "hi") vim.api.nvim_set_var("other", 123) + vim.api.nvim_set_var("floaty", 5120.1) + vim.api.nvim_set_var("nullvar", vim.NIL) vim.api.nvim_set_var("to_delete", {hello="world"}) ]] eq('hi', funcs.luaeval "vim.g.testing") eq(123, funcs.luaeval "vim.g.other") + eq(5120.1, funcs.luaeval "vim.g.floaty") eq(NIL, funcs.luaeval "vim.g.nonexistant") + eq(NIL, funcs.luaeval "vim.g.nullvar") + -- lost over RPC, so test locally: + eq({false, true}, exec_lua [[ + return {vim.g.nonexistant == vim.NIL, vim.g.nullvar == vim.NIL} + ]]) eq({hello="world"}, funcs.luaeval "vim.g.to_delete") exec_lua [[ @@ -963,12 +971,20 @@ describe('lua stdlib', function() exec_lua [[ vim.api.nvim_buf_set_var(0, "testing", "hi") vim.api.nvim_buf_set_var(0, "other", 123) + vim.api.nvim_buf_set_var(0, "floaty", 5120.1) + vim.api.nvim_buf_set_var(0, "nullvar", vim.NIL) vim.api.nvim_buf_set_var(0, "to_delete", {hello="world"}) ]] eq('hi', funcs.luaeval "vim.b.testing") eq(123, funcs.luaeval "vim.b.other") + eq(5120.1, funcs.luaeval "vim.b.floaty") eq(NIL, funcs.luaeval "vim.b.nonexistant") + eq(NIL, funcs.luaeval "vim.b.nullvar") + -- lost over RPC, so test locally: + eq({false, true}, exec_lua [[ + return {vim.b.nonexistant == vim.NIL, vim.b.nullvar == vim.NIL} + ]]) eq({hello="world"}, funcs.luaeval "vim.b.to_delete") exec_lua [[ diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index a78ed07876..85c67be8f9 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -118,7 +118,7 @@ describe('health.vim', function() Error = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, Heading = { bold=true, foreground=Screen.colors.Magenta }, Heading2 = { foreground = Screen.colors.SlateBlue }, - Bar = { foreground=Screen.colors.Purple }, + Bar = { foreground = 0x6a0dad }, Bullet = { bold=true, foreground=Screen.colors.Brown }, }) command("checkhealth foo success1") diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 6d3af115fa..663271deab 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -9,6 +9,7 @@ local eq = helpers.eq local pcall_err = helpers.pcall_err local pesc = helpers.pesc local insert = helpers.insert +local funcs = helpers.funcs local retry = helpers.retry local NIL = helpers.NIL local read_file = require('test.helpers').read_file @@ -29,6 +30,16 @@ teardown(function() os.remove(fake_lsp_logfile) end) +local function clear_notrace() + -- problem: here be dragons + -- solution: don't look for dragons to closely + clear {env={ + NVIM_LUA_NOTRACK="1"; + VIMRUNTIME=os.getenv"VIMRUNTIME"; + }} +end + + local function fake_lsp_server_setup(test_name, timeout_ms, options) exec_lua([=[ lsp = require('vim.lsp') @@ -36,6 +47,7 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options) TEST_RPC_CLIENT_ID = lsp.start_client { cmd_env = { NVIM_LOG_FILE = logfile; + NVIM_LUA_NOTRACK = "1"; }; cmd = { vim.v.progpath, '-Es', '-u', 'NONE', '--headless', @@ -65,7 +77,7 @@ end local function test_rpc_server(config) if config.test_name then - clear() + clear_notrace() fake_lsp_server_setup(config.test_name, config.timeout_ms or 1e3, config.options) end local client = setmetatable({}, { @@ -120,7 +132,7 @@ end describe('LSP', function() describe('server_name specified', function() before_each(function() - clear() + clear_notrace() -- Run an instance of nvim on the file which contains our "scripts". -- Pass TEST_NAME to pick the script. local test_name = "basic_init" @@ -250,6 +262,10 @@ describe('LSP', function() end) it('should succeed with manual shutdown', function() + if 'openbsd' == helpers.uname() then + pending('hangs the build on openbsd #14028, re-enable with freeze timeout #14204') + return + end local expected_callbacks = { {NIL, "shutdown", {}, 1, NIL}; {NIL, "test", {}, 1}; @@ -314,7 +330,7 @@ describe('LSP', function() } end) it('workspace/configuration returns NIL per section if client was started without config.settings', function() - clear() + clear_notrace() fake_lsp_server_setup('workspace/configuration no settings') eq({ NIL, NIL, }, exec_lua [[ local params = { @@ -941,7 +957,7 @@ end) describe('LSP', function() before_each(function() - clear() + clear_notrace() end) local function make_edit(y_0, x_0, y_1, x_1, text) @@ -1109,14 +1125,14 @@ describe('LSP', function() '2nd line of θ―text'; }, buf_lines(target_bufnr)) end) - it('correctly goes ahead with the edit if the version is vim.NIL', function() - -- we get vim.NIL when we decode json null value. - local json = exec_lua[[ - return vim.fn.json_decode("{ \"a\": 1, \"b\": null }") - ]] - eq(json.b, exec_lua("return vim.NIL")) - - exec_lua('vim.lsp.util.apply_text_document_edit(...)', text_document_edit(exec_lua("return vim.NIL"))) + it('always accepts edit with version = 0', function() + exec_lua([[ + local args = {...} + local bufnr = select(1, ...) + local text_edit = select(2, ...) + vim.lsp.util.buf_versions[bufnr] = 10 + vim.lsp.util.apply_text_document_edit(text_edit) + ]], target_bufnr, text_document_edit(0)) eq({ 'First β₯ π€¦ π¦ line of text'; '2nd line of θ―text'; @@ -1377,10 +1393,10 @@ describe('LSP', function() { label='foocar', sortText="e", insertText='foodar', textEdit={newText='foobar'} }, { label='foocar', sortText="f", textEdit={newText='foobar'} }, -- real-world snippet text - { label='foocar', sortText="g", insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} }, - { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} }, + { label='foocar', sortText="g", insertText='foodar', insertTextFormat=2, textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} }, + { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', insertTextFormat=2, textEdit={} }, -- nested snippet tokens - { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} }, + { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', insertTextFormat=2, textEdit={} }, -- plain text { label='foocar', sortText="j", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} }, } @@ -1392,9 +1408,9 @@ describe('LSP', function() { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="d", insertText='foobar', textEdit={} } } } } }, { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="e", insertText='foodar', textEdit={newText='foobar'} } } } } }, { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="f", textEdit={newText='foobar'} } } } } }, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar(place holder, more ...holder{})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="g", insertText='foodar', textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} } } } } }, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ1, var2 *typ2) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', textEdit={} } } } } }, - { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2,typ3 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', textEdit={} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar(place holder, more ...holder{})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="g", insertText='foodar', insertTextFormat=2, textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ1, var2 *typ2) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', insertTextFormat=2, textEdit={} } } } } }, + { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2,typ3 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', insertTextFormat=2, textEdit={} } } } } }, { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(${1:var1})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="j", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} } } } } }, } @@ -1863,6 +1879,18 @@ describe('LSP', function() eq(4, pos.col) eq('Γ₯', exec_lua[[return vim.fn.expand('<cword>')]]) end) + + it('adds current position to jumplist before jumping', function() + funcs.nvim_win_set_buf(0, target_bufnr) + local mark = funcs.nvim_buf_get_mark(target_bufnr, "'") + eq({ 1, 0 }, mark) + + funcs.nvim_win_set_cursor(0, {2, 3}) + jump(location(0, 9, 0, 9)) + + mark = funcs.nvim_buf_get_mark(target_bufnr, "'") + eq({ 2, 3 }, mark) + end) end) describe('lsp.util._make_floating_popup_size', function() diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 209537831f..c61bf108cb 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -258,6 +258,13 @@ describe(':terminal buffer', function() it('handles wqall', function() eq('Vim(wqall):E948: Job still running', exc_exec('wqall')) end) + + it('does not segfault when pasting empty buffer #13955', function() + feed_command('terminal') + feed('<c-\\><c-n>') + feed_command('put a') -- buffer a is empty + helpers.assert_alive() + end) end) describe('No heap-buffer-overflow when using', function() diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index d80d0fdbaf..05e0c5fe2c 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -445,7 +445,7 @@ describe('treesitter highlighting', function() exec_lua [[ local parser = vim.treesitter.get_parser(0, "c", { - queries = {c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"} + injections = {c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"} }) local highlighter = vim.treesitter.highlighter test_hl = highlighter.new(parser, {queries = {c = hl_query}}) diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index a5801271cb..afb17dd2cf 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -45,7 +45,7 @@ describe('treesitter API', function() return {keys, lang.fields, symbols} ]])) - eq({fields=true, symbols=true}, keys) + eq({fields=true, symbols=true, _abi_version=true}, keys) local fset = {} for _,f in pairs(fields) do diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index f99362fbdf..d2f9148e8f 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -235,6 +235,100 @@ void ui_refresh(void) }, res) end) + it('can match special regex characters like \\ * + ( with `vim-match?`', function() + if pending_c_parser(pending) then return end + + insert('char* astring = "\\n"; (1 + 1) * 2 != 2;') + + local res = exec_lua([[ + cquery = vim.treesitter.parse_query("c", '((_) @plus (vim-match? @plus "^\\\\+$"))'.. + '((_) @times (vim-match? @times "^\\\\*$"))'.. + '((_) @paren (vim-match? @paren "^\\\\($"))'.. + '((_) @escape (vim-match? @escape "^\\\\\\\\n$"))'.. + '((_) @string (vim-match? @string "^\\"\\\\\\\\n\\"$"))') + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse()[1] + res = {} + for pattern, match in cquery:iter_matches(tree:root(), 0) do + -- can't transmit node over RPC. just check the name and range + local mrepr = {} + for cid,node in pairs(match) do + table.insert(mrepr, {cquery.captures[cid], node:type(), node:range()}) + end + table.insert(res, {pattern, mrepr}) + end + return res + ]]) + + eq({ + { 2, { { "times", '*', 0, 4, 0, 5 } } }, + { 5, { { "string", 'string_literal', 0, 16, 0, 20 } } }, + { 4, { { "escape", 'escape_sequence', 0, 17, 0, 19 } } }, + { 3, { { "paren", '(', 0, 22, 0, 23 } } }, + { 1, { { "plus", '+', 0, 25, 0, 26 } } }, + { 2, { { "times", '*', 0, 30, 0, 31 } } }, + }, res) + end) + + it('supports builtin query predicate any-of?', function() + if pending_c_parser(pending) then return end + + insert([[ + #include <stdio.h> + + int main(void) { + int i; + for(i=1; i<=100; i++) { + if(((i%3)||(i%5))== 0) + printf("number= %d FizzBuzz\n", i); + else if((i%3)==0) + printf("number= %d Fizz\n", i); + else if((i%5)==0) + printf("number= %d Buzz\n", i); + else + printf("number= %d\n",i); + } + return 0; + } + ]]) + exec_lua([[ + function get_query_result(query_text) + cquery = vim.treesitter.parse_query("c", query_text) + parser = vim.treesitter.get_parser(0, "c") + tree = parser:parse()[1] + res = {} + for cid, node in cquery:iter_captures(tree:root(), 0) do + -- can't transmit node over RPC. just check the name, range, and text + local text = vim.treesitter.get_node_text(node, 0) + local range = {node:range()} + table.insert(res, {cquery.captures[cid], node:type(), range, text}) + end + return res + end + ]]) + + local res0 = exec_lua([[return get_query_result(...)]], + [[((primitive_type) @c-keyword (#any-of? @c-keyword "int" "float"))]]) + eq({ + { "c-keyword", "primitive_type", { 2, 2, 2, 5 }, "int" }, + { "c-keyword", "primitive_type", { 3, 4, 3, 7 }, "int" }, + }, res0) + + local res1 = exec_lua([[return get_query_result(...)]], + [[ + ((string_literal) @fizzbuzz-strings (#any-of? @fizzbuzz-strings + "\"number= %d FizzBuzz\\n\"" + "\"number= %d Fizz\\n\"" + "\"number= %d Buzz\\n\"" + )) + ]]) + eq({ + { "fizzbuzz-strings", "string_literal", { 6, 15, 6, 38 }, "\"number= %d FizzBuzz\\n\""}, + { "fizzbuzz-strings", "string_literal", { 8, 15, 8, 34 }, "\"number= %d Fizz\\n\""}, + { "fizzbuzz-strings", "string_literal", { 10, 15, 10, 34 }, "\"number= %d Buzz\\n\""}, + }, res1) + end) + it('allow loading query with escaped quotes and capture them with `lua-match?` and `vim-match?`', function() if pending_c_parser(pending) then return end @@ -308,7 +402,7 @@ void ui_refresh(void) return list ]] - eq({ 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list) + eq({ 'any-of?', 'contains?', 'eq?', 'is-main?', 'lua-match?', 'match?', 'vim-match?' }, res_list) end) @@ -468,7 +562,7 @@ int x = INT_MAX; it("should inject a language", function() exec_lua([[ parser = vim.treesitter.get_parser(0, "c", { - queries = { + injections = { c = "(preproc_def (preproc_arg) @c) (preproc_function_def value: (preproc_arg) @c)"}}) ]]) @@ -489,7 +583,7 @@ int x = INT_MAX; it("should inject a language", function() exec_lua([[ parser = vim.treesitter.get_parser(0, "c", { - queries = { + injections = { c = "(preproc_def (preproc_arg) @c @combined) (preproc_function_def value: (preproc_arg) @c @combined)"}}) ]]) @@ -506,11 +600,39 @@ int x = INT_MAX; end) end) + describe("when providing parsing information through a directive", function() + it("should inject a language", function() + exec_lua([=[ + vim.treesitter.add_directive("inject-clang!", function(match, _, _, pred, metadata) + metadata.language = "c" + metadata.combined = true + metadata.content = pred[2] + end) + + parser = vim.treesitter.get_parser(0, "c", { + injections = { + c = "(preproc_def ((preproc_arg) @_c (#inject-clang! @_c)))" .. + "(preproc_function_def value: ((preproc_arg) @_a (#inject-clang! @_a)))"}}) + ]=]) + + eq("table", exec_lua("return type(parser:children().c)")) + eq(2, exec_lua("return #parser:children().c:trees()")) + eq({ + {0, 0, 7, 0}, -- root tree + {3, 14, 5, 18}, -- VALUE 123 + -- VALUE1 123 + -- VALUE2 123 + {1, 26, 2, 68} -- READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y)) + -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y)) + }, get_ranges()) + end) + end) + describe("when using the offset directive", function() it("should shift the range by the directive amount", function() exec_lua([[ parser = vim.treesitter.get_parser(0, "c", { - queries = { + injections = { c = "(preproc_def ((preproc_arg) @c (#offset! @c 0 2 0 -1))) (preproc_function_def value: (preproc_arg) @c)"}}) ]]) @@ -538,7 +660,7 @@ int x = INT_MAX; it("should return the correct language tree", function() local result = exec_lua([[ parser = vim.treesitter.get_parser(0, "c", { - queries = { c = "(preproc_def (preproc_arg) @c)"}}) + injections = { c = "(preproc_def (preproc_arg) @c)"}}) local sub_tree = parser:language_for_range({1, 18, 1, 19}) @@ -571,28 +693,55 @@ int x = INT_MAX; eq(result, "value") end) - end) - - describe("when setting for a capture match", function() - it("should set/get the data correctly", function() - insert([[ - int x = 3; - ]]) - - local result = exec_lua([[ - local result - query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value"))') - parser = vim.treesitter.get_parser(0, "c") - - for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do - result = metadata[pattern].key - end - - return result - ]]) - - eq(result, "value") + describe("when setting a key on a capture", function() + it("it should create the nested table", function() + insert([[ + int x = 3; + ]]) + + local result = exec_lua([[ + local query = require("vim.treesitter.query") + local value + + query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value"))') + parser = vim.treesitter.get_parser(0, "c") + + for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do + for _, nested_tbl in pairs(metadata) do + return nested_tbl.key + end + end + ]]) + + eq(result, "value") + end) + + it("it should not overwrite the nested table", function() + insert([[ + int x = 3; + ]]) + + local result = exec_lua([[ + local query = require("vim.treesitter.query") + local result + + query = vim.treesitter.parse_query("c", '((number_literal) @number (#set! @number "key" "value") (#set! @number "key2" "value2"))') + parser = vim.treesitter.get_parser(0, "c") + + for pattern, match, metadata in query:iter_matches(parser:parse()[1]:root(), 0) do + for _, nested_tbl in pairs(metadata) do + return nested_tbl + end + end + ]]) + local expected = { + ["key"] = "value", + ["key2"] = "value2", + } + + eq(expected, result) + end) end) end) end) diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 21c01b3458..0ea8bab957 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local clear, feed = helpers.clear, helpers.feed local source = helpers.source local command = helpers.command +local assert_alive = helpers.assert_alive local function new_screen(opt) local screen = Screen.new(25, 5) @@ -758,6 +759,7 @@ local function test_cmdline(linegrid) end) it("doesn't send invalid events when aborting mapping #10000", function() + command('set notimeout') command('cnoremap ab c') feed(':xa') @@ -842,3 +844,14 @@ describe('cmdline redraw', function() ]], unchanged=true} end) end) + +describe("cmdline height", function() + it("does not crash resized screen #14263", function() + clear() + local screen = Screen.new(25, 10) + screen:attach() + command('set cmdheight=9999') + screen:try_resize(25, 5) + assert_alive() + end) +end) diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 295a54aec8..98aafd8757 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -29,6 +29,7 @@ describe('decorations providers', function() [10] = {italic = true, background = Screen.colors.Magenta}; [11] = {foreground = Screen.colors.Red, background = tonumber('0x005028')}; [12] = {foreground = tonumber('0x990000')}; + [13] = {background = Screen.colors.LightBlue}; } end) @@ -65,6 +66,18 @@ describe('decorations providers', function() expect_events(expected, actual, "beam trace") end + it('does not OOM when inserting, rather than appending, to the decoration provider vector', function() + -- Add a dummy decoration provider with a larger ns id than what setup_provider() creates. + -- This forces get_decor_provider() to insert into the providers vector, + -- rather than append, which used to spin in an infinite loop allocating + -- memory until nvim crashed/was killed. + setup_provider([[ + local ns2 = a.nvim_create_namespace "ns2" + a.nvim_set_decoration_provider(ns2, {}) + ]]) + helpers.assert_alive() + end) + it('leave a trace', function() insert(mulholland) @@ -331,10 +344,70 @@ describe('decorations providers', function() | ]]} end) + + it('can have virtual text of the style: right_align', function() + insert(mulholland) + setup_provider [[ + local hl = a.nvim_get_hl_id_by_name "ErrorMsg" + local test_ns = a.nvim_create_namespace "mulholland" + function on_do(event, ...) + if event == "line" then + local win, buf, line = ... + a.nvim_buf_set_extmark(buf, test_ns, line, 0, { + virt_text = {{'+'}, {string.rep(' ', line+1), 'ErrorMsg'}}; + virt_text_pos='right_align'; + ephemeral = true; + }) + end + end + ]] + + screen:expect{grid=[[ + // just to see if there was an acciden+{2: }| + // on Mulholland Drive +{2: }| + try_start(); +{2: }| + bufref_T save_buf; +{2: }| + switch_buffer(&save_buf, buf); +{2: }| + posp = getmark(mark, false); +{2: }| + restore_buffer(&save_buf);^ +{2: }| + | + ]]} + end) + + it('can highlight beyond EOL', function() + insert(mulholland) + setup_provider [[ + local test_ns = a.nvim_create_namespace "veberod" + function on_do(event, ...) + if event == "line" then + local win, buf, line = ... + if string.find(a.nvim_buf_get_lines(buf, line, line+1, true)[1], "buf") then + a.nvim_buf_set_extmark(buf, test_ns, line, 0, { + end_line = line+1; + hl_group = 'DiffAdd'; + hl_eol = true; + ephemeral = true; + }) + end + end + end + ]] + + screen:expect{grid=[[ + // just to see if there was an accident | + // on Mulholland Drive | + try_start(); | + {13:bufref_T save_buf; }| + {13:switch_buffer(&save_buf, buf); }| + posp = getmark(mark, false); | + {13:restore_buffer(&save_buf);^ }| + | + ]]} + end) end) describe('extmark decorations', function() - local screen + local screen, ns before_each( function() clear() screen = Screen.new(50, 15) @@ -365,6 +438,8 @@ describe('extmark decorations', function() [23] = {foreground = Screen.colors.Magenta1, background = Screen.colors.LightGrey}; [24] = {bold = true}; } + + ns = meths.create_namespace 'test' end) local example_text = [[ @@ -385,7 +460,6 @@ end]] insert(example_text) feed 'gg' - local ns = meths.create_namespace 'test' for i = 1,9 do meths.buf_set_extmark(0, ns, i, 0, { virt_text={{'|', 'LineNr'}}, virt_text_pos='overlay'}) if i == 3 or (i >= 6 and i <= 9) then @@ -452,7 +526,6 @@ end]] it('can have virtual text of overlay position and styling', function() insert(example_text) feed 'gg' - local ns = meths.create_namespace 'test' command 'set ft=lua' command 'syntax on' @@ -540,4 +613,88 @@ end]] {24:-- VISUAL LINE --} | ]]} end) + + it('can have virtual text of fixed win_col position', function() + insert(example_text) + feed 'gg' + meths.buf_set_extmark(0, ns, 1, 0, { virt_text={{'Very', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 2, 10, { virt_text={{'Much', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 3, 15, { virt_text={{'Error', 'ErrorMsg'}}, virt_text_win_col=31, hl_mode='blend'}) + meths.buf_set_extmark(0, ns, 7, 21, { virt_text={{'-', 'NonText'}}, virt_text_win_col=4, hl_mode='blend'}) + + screen:expect{grid=[[ + ^for _,item in ipairs(items) do | + local text, hl_id_cell, cou{4:Very} unpack(item) | + if hl_id_cell ~= nil then {4:Much} | + hl_id = hl_id_cell {4:Error} | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + {1:-} cell.text = text | + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + {1:~ }| + {1:~ }| + | + ]]} + + feed '3G12|i<cr><esc>' + screen:expect{grid=[[ + for _,item in ipairs(items) do | + local text, hl_id_cell, cou{4:Very} unpack(item) | + if hl_i {4:Much} | + ^d_cell ~= nil then | + hl_id = hl_id_cell {4:Error} | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + {1:-} cell.text = text | + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + {1:~ }| + | + ]]} + + feed 'u:<cr>' + screen:expect{grid=[[ + for _,item in ipairs(items) do | + local text, hl_id_cell, cou{4:Very} unpack(item) | + if hl_i^d_cell ~= nil then {4:Much} | + hl_id = hl_id_cell {4:Error} | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + {1:-} cell.text = text | + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + {1:~ }| + {1:~ }| + : | + ]]} + + feed '8|i<cr><esc>' + screen:expect{grid=[[ + for _,item in ipairs(items) do | + local text, hl_id_cell, cou{4:Very} unpack(item) | + if | + ^hl_id_cell ~= nil then {4:Much} | + hl_id = hl_id_cell {4:Error} | + end | + for _ = 1, (count or 1) do | + local cell = line[colpos] | + {1:-} cell.text = text | + cell.hl_id = hl_id | + colpos = colpos+1 | + end | + end | + {1:~ }| + | + ]]} + end) end) diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 664b8e7ab7..f3b840da21 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -42,6 +42,10 @@ describe('float window', function() [20] = {bold = true, foreground = Screen.colors.Brown}, [21] = {background = Screen.colors.Gray90}, [22] = {background = Screen.colors.LightRed}, + [23] = {foreground = Screen.colors.Black, background = Screen.colors.White}; + [24] = {foreground = Screen.colors.Black, background = Screen.colors.Grey80}; + [25] = {blend = 100, background = Screen.colors.Gray0}; + [26] = {blend = 80, background = Screen.colors.Gray0}; } it('behavior', function() @@ -58,6 +62,27 @@ describe('float window', function() eq(1000, funcs.win_getid()) end) + it('win_execute() should work' , function() + local buf = meths.create_buf(false, false) + meths.buf_set_lines(buf, 0, -1, true, {'the floatwin', 'abc', 'def'}) + local win = meths.open_win(buf, false, {relative='win', width=16, height=1, row=0, col=10}) + local line = funcs.win_execute(win, 'echo getline(1)') + eq('\nthe floatwin', line) + eq('\n1', funcs.win_execute(win, 'echo line(".",'..win.id..')')) + eq('\n3', funcs.win_execute(win, 'echo line("$",'..win.id..')')) + eq('\n0', funcs.win_execute(win, 'echo line("$", 123456)')) + funcs.win_execute(win, 'bwipe!') + end) + + it('win_execute() call commands that not allowed' , function() + local buf = meths.create_buf(false, false) + meths.buf_set_lines(buf, 0, -1, true, {'the floatwin'}) + local win = meths.open_win(buf, true, {relative='win', width=16, height=1, row=0, col=10}) + eq(pcall_err(funcs.win_execute, win, 'close'), 'Vim(close):E37: No write since last change (add ! to override)') + eq(pcall_err(funcs.win_execute, win, 'bdelete'), 'Vim(bdelete):E89: No write since last change for buffer 2 (add ! to override)') + funcs.win_execute(win, 'bwipe!') + end) + it('closed immediately by autocmd #11383', function() eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately', pcall_err(exec_lua, [[ @@ -644,7 +669,6 @@ describe('float window', function() end meths.win_set_config(win, {border="single"}) - if multigrid then screen:expect{grid=[[ ## grid 1 @@ -687,9 +711,51 @@ describe('float window', function() ]]} end + meths.win_set_config(win, {border="solid"}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + {5: }| + {5: }{1: halloj! }{5: }| + {5: }{1: BORDAA }{5: }| + {5: }| + ]], float_pos={ + [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5: }{0: }| + {0:~ }{5: }{1: halloj! }{5: }{0: }| + {0:~ }{5: }{1: BORDAA }{5: }{0: }| + {0:~ }{5: }{0: }| + | + ]]} + end + -- support: ascii char, UTF-8 char, composed char, highlight per char meths.win_set_config(win, {border={"x", {"Γ₯", "ErrorMsg"}, {"\\"}, {"nΜΜ", "Search"}}}) - if multigrid then screen:expect{grid=[[ ## grid 1 @@ -710,10 +776,10 @@ describe('float window', function() ## grid 3 | ## grid 5 - {5:xΓ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯\}| - {5:nΜΜ}{1: halloj! }{5:nΜΜ}| - {5:nΜΜ}{1: BORDAA }{5:nΜΜ}| - {5:\Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯x}| + {5:x}{7:Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯}{5:\}| + {17:nΜΜ}{1: halloj! }{17:nΜΜ}| + {17:nΜΜ}{1: BORDAA }{17:nΜΜ}| + {5:\}{7:Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯Γ₯}{5:x}| ]], float_pos={ [5] = { { id = 1002 }, "NW", 1, 2, 5, true } }, win_viewport={ @@ -772,6 +838,148 @@ describe('float window', function() | ]]} end + + meths.win_set_config(win, {border={"", "", "", ">", "", "", "", "<"}}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + {5:<}{1: halloj! }{5:>}| + {5:<}{1: BORDAA }{5:>}| + ]], float_pos={ + [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:<}{1: halloj! }{5:>}{0: }| + {0:~ }{5:<}{1: BORDAA }{5:>}{0: }| + {0:~ }| + {0:~ }| + | + ]]} + end + + insert [[ + neeed some dummy + background text + to show the effect + of color blending + of border shadow + ]] + + meths.win_set_config(win, {border="shadow"}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + neeed some dummy | + background text | + to show the effect | + of color blending | + of border shadow | + ^ | + ## grid 3 + | + ## grid 5 + {1: halloj! }{25: }| + {1: BORDAA }{26: }| + {25: }{26: }| + ]], float_pos={ + [5] = { { id = 1002 }, "NW", 1, 2, 5, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 5, curcol = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + neeed some dummy | + background text | + to {1: halloj! }{23:e}ffect | + of {1: BORDAA }{24:n}ding | + of {23:b}{24:order sha}dow | + ^ | + | + ]]} + end + end) + + it('terminates border on edge of viewport when window extends past viewport', function() + local buf = meths.create_buf(false, false) + meths.open_win(buf, false, {relative='editor', width=40, height=7, row=0, col=0, border="single"}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {5:ββββββββββββββββββββββββββββββββββββββββββ}| + {5:β}{1: }{5:β}| + {5:β}{2:~ }{5:β}| + {5:β}{2:~ }{5:β}| + {5:β}{2:~ }{5:β}| + {5:β}{2:~ }{5:β}| + {5:β}{2:~ }{5:β}| + {5:β}{2:~ }{5:β}| + {5:ββββββββββββββββββββββββββββββββββββββββββ}| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 0, 0, true } + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + {5:^ββββββββββββββββββββββββββββββββββββββββ}| + {5:β}{1: }{5:β}| + {5:β}{2:~ }{5:β}| + {5:β}{2:~ }{5:β}| + {5:β}{2:~ }{5:β}| + {5:ββββββββββββββββββββββββββββββββββββββββ}| + | + ]]} + end end) it('with border show popupmenu', function() @@ -835,7 +1043,6 @@ describe('float window', function() end feed 'i<c-x><c-p>' - if multigrid then screen:expect{grid=[[ ## grid 1 @@ -873,12 +1080,8 @@ describe('float window', function() {1: abb }| {13: acc }| ]], float_pos={ - [5] = { { - id = 1002 - }, "NW", 1, 0, 5, true }, - [6] = { { - id = -1 - }, "NW", 5, 4, 0, false } + [5] = { { id = 1002 }, "NW", 1, 0, 5, true, 50 }, + [6] = { { id = -1 }, "NW", 5, 4, 0, false, 100 } }, win_viewport={ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3}; @@ -2555,8 +2758,8 @@ describe('float window', function() {1: word }| {1: longtext }| ]], float_pos={ - [4] = {{ id = 1001 }, "NW", 1, 2, 5, true}, - [5] = {{ id = -1 }, "NW", 4, 1, 1, false} + [4] = {{ id = 1001 }, "NW", 1, 2, 5, true, 50}, + [5] = {{ id = -1 }, "NW", 4, 1, 1, false, 100} }} else screen:expect([[ @@ -2642,8 +2845,8 @@ describe('float window', function() {1:yy }| {1:zz }| ]], float_pos={ - [4] = {{ id = 1001 }, "NW", 1, 2, 5, true}, - [5] = {{ id = -1 }, "NW", 2, 1, 0, false} + [4] = {{ id = 1001 }, "NW", 1, 2, 5, true, 50}, + [5] = {{ id = -1 }, "NW", 2, 1, 0, false, 100} }} else screen:expect([[ @@ -2904,7 +3107,7 @@ describe('float window', function() {1:word }| {1:longtext }| ]], float_pos={ - [4] = {{id = -1}, "NW", 2, 1, 0, false}} + [4] = {{id = -1}, "NW", 2, 1, 0, false, 100}} } else screen:expect([[ @@ -2948,8 +3151,8 @@ describe('float window', function() {15:some info }| {15:about item }| ]], float_pos={ - [4] = {{id = -1}, "NW", 2, 1, 0, false}, - [6] = {{id = 1002}, "NW", 2, 1, 12, true}, + [4] = {{id = -1}, "NW", 2, 1, 0, false, 100}, + [6] = {{id = 1002}, "NW", 2, 1, 12, true, 50}, }} else screen:expect([[ @@ -3063,7 +3266,7 @@ describe('float window', function() {1:word }| {1:longtext }| ]], float_pos={ - [4] = {{id = -1}, "NW", 2, 1, 0, false}, + [4] = {{id = -1}, "NW", 2, 1, 0, false, 100}, }} else screen:expect([[ @@ -5886,6 +6089,279 @@ describe('float window', function() ]]) end end) + + it("correctly orders multiple opened floats (current last)", function() + local buf = meths.create_buf(false,false) + local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5}) + meths.win_set_option(win, "winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg") + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {7: }| + {7:~ }| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true }; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{7: }{0: }| + {0:~ }{7:~ }{0: }| + {0:~ }| + {0:~ }| + | + ]]} + end + + exec_lua [[ + local buf = vim.api.nvim_create_buf(false,false) + local win = vim.api.nvim_open_win(buf, false, {relative='editor', width=16, height=2, row=3, col=8}) + vim.api.nvim_win_set_option(win, "winhl", "EndOfBuffer:Normal") + buf = vim.api.nvim_create_buf(false,false) + win = vim.api.nvim_open_win(buf, true, {relative='editor', width=12, height=2, row=4, col=10}) + vim.api.nvim_win_set_option(win, "winhl", "Normal:Search,EndOfBuffer:Search") + ]] + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {7: }| + {7:~ }| + ## grid 5 + {1: }| + {1:~ }| + ## grid 6 + {17:^ }| + {17:~ }| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true }; + [5] = { { id = 1002 }, "NW", 1, 3, 8, true }; + [6] = { { id = 1003 }, "NW", 1, 4, 10, true }; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }{7: }{0: }| + {0:~ }{7:~ }{1: }{7: }{0: }| + {0:~ }{1:~ }{17:^ }{1: }{0: }| + {0:~ }{17:~ }{0: }| + | + ]]} + end + end) + + it("correctly orders multiple opened floats (non-current last)", function() + local buf = meths.create_buf(false,false) + local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5}) + meths.win_set_option(win, "winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg") + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {7: }| + {7:~ }| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true }; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{7: }{0: }| + {0:~ }{7:~ }{0: }| + {0:~ }| + {0:~ }| + | + ]]} + end + + exec_lua [[ + local buf = vim.api.nvim_create_buf(false,false) + local win = vim.api.nvim_open_win(buf, true, {relative='editor', width=12, height=2, row=4, col=10}) + vim.api.nvim_win_set_option(win, "winhl", "Normal:Search,EndOfBuffer:Search") + buf = vim.api.nvim_create_buf(false,false) + win = vim.api.nvim_open_win(buf, false, {relative='editor', width=16, height=2, row=3, col=8}) + vim.api.nvim_win_set_option(win, "winhl", "EndOfBuffer:Normal") + ]] + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {7: }| + {7:~ }| + ## grid 5 + {17:^ }| + {17:~ }| + ## grid 6 + {1: }| + {1:~ }| + ]], float_pos={ + [4] = { { id = 1001 }, "NW", 1, 2, 5, true }; + [5] = { { id = 1002 }, "NW", 1, 4, 10, true }; + [6] = { { id = 1003 }, "NW", 1, 3, 8, true }; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + | + {0:~ }| + {0:~ }{7: }{0: }| + {0:~ }{7:~ }{1: }{7: }{0: }| + {0:~ }{1:~ }{17:^ }{1: }{0: }| + {0:~ }{17:~ }{0: }| + | + ]]} + end + end) + + it('can use z-index', function() + local buf = meths.create_buf(false,false) + local win1 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=1, col=5, zindex=30}) + meths.win_set_option(win1, "winhl", "Normal:ErrorMsg,EndOfBuffer:ErrorMsg") + local win2 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=2, col=6, zindex=50}) + meths.win_set_option(win2, "winhl", "Normal:Search,EndOfBuffer:Search") + local win3 = meths.open_win(buf, false, {relative='editor', width=20, height=3, row=3, col=7, zindex=40}) + meths.win_set_option(win3, "winhl", "Normal:Question,EndOfBuffer:Question") + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {7: }| + {7:~ }| + {7:~ }| + ## grid 5 + {17: }| + {17:~ }| + {17:~ }| + ## grid 6 + {8: }| + {8:~ }| + {8:~ }| + ]], float_pos={ + [4] = {{id = 1001}, "NW", 1, 1, 5, true, 30}; + [5] = {{id = 1002}, "NW", 1, 2, 6, true, 50}; + [6] = {{id = 1003}, "NW", 1, 3, 7, true, 40}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0}; + [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }{7: }{0: }| + {0:~ }{7:~}{17: }{0: }| + {0:~ }{7:~}{17:~ }{8: }{0: }| + {0:~ }{17:~ }{8: }{0: }| + {0:~ }{8:~ }{0: }| + | + ]]} + end + end) end describe('with ext_multigrid', function() diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 1fe3a4128e..72468392ee 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -456,6 +456,8 @@ describe('ui/ext_messages', function() {1:~ }| ]], messages={ {kind="echomsg", content={{"stuff"}}}, + }, showmode={ + { "-- INSERT --", 3 } }} end) @@ -809,7 +811,7 @@ describe('ui/ext_messages', function() {1:~ }| {1:^~ }| ]], messages={ - {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Helli"\nType number and <Enter> or click with mouse (empty cancels): ' } }, kind = ""} + {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Helli"\nType number and <Enter> or click with the mouse (q or empty cancels): ' } }, kind = ""} }} feed('1') @@ -820,7 +822,7 @@ describe('ui/ext_messages', function() {1:~ }| {1:^~ }| ]], messages={ - {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Helli"\nType number and <Enter> or click with mouse (empty cancels): ' } }, kind = ""}, + {content = { { 'Change "helllo" to:\n 1 "Hello"\n 2 "Hallo"\n 3 "Helli"\nType number and <Enter> or click with the mouse (q or empty cancels): ' } }, kind = ""}, { content = { { "1" } }, kind = "" } }} diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index fcf6926433..f73d051857 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -429,6 +429,15 @@ screen:redraw_debug() to show all intermediate screen states. ]]) extstate.win_viewport = nil end + if expected.float_pos then + expected.float_pos = deepcopy(expected.float_pos) + for _, v in pairs(expected.float_pos) do + if not v.external and v[7] == nil then + v[7] = 50 + end + end + end + -- Convert assertion errors into invalid screen state descriptions. for _, k in ipairs(concat_tables(ext_keys, {'mode', 'mouse_enabled'})) do -- Empty states are considered the default and need not be mentioned. @@ -1287,6 +1296,11 @@ function Screen:get_snapshot(attrs, ignore) end local function fmt_ext_state(name, state) + local function remove_all_metatables(item, path) + if path[#path] ~= inspect.METATABLE then + return item + end + end if name == "win_viewport" then local str = "{\n" for k,v in pairs(state) do @@ -1295,13 +1309,18 @@ local function fmt_ext_state(name, state) ..", curcol = "..v.curcol.."};\n") end return str .. "}" - else - -- TODO(bfredl): improve formatting of more states - local function remove_all_metatables(item, path) - if path[#path] ~= inspect.METATABLE then - return item + elseif name == "float_pos" then + local str = "{\n" + for k,v in pairs(state) do + str = str.." ["..k.."] = {{id = "..v[1].id.."}" + for i = 2, #v do + str = str..", "..inspect(v[i]) end + str = str .. "};\n" end + return str .. "}" + else + -- TODO(bfredl): improve formatting of more states return inspect(state,{process=remove_all_metatables}) end end diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index 656f613c6a..5540b3c2dc 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -507,7 +507,21 @@ describe('search highlighting', function() {1:~ }| :syntax keyword MyGroup special | ]]) + end) + it('highlights entire pattern on :%g@a/b', function() + command('set inccommand=nosplit') + feed('ia/b/c<Esc>') + feed(':%g@a/b') + screen:expect([[ + {3:a/b}/c | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :%g@a/b^ | + ]]) end) end) diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index 1937102782..06c92a4b10 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -264,6 +264,24 @@ describe('Signs', function() {0:~ }| | ]]} + -- line deletion deletes signs. + command('2d') + screen:expect([[ + {1:>>}XX{2: }{6: 1 }a | + XX{1:>>}WW{6: 2 }^c | + {2: }{6: 3 } | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) end) it('auto-resize sign column with minimum size (#13783)', function() diff --git a/test/helpers.lua b/test/helpers.lua index 8dbd82cb8c..12d9f19187 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -365,7 +365,11 @@ function module.check_cores(app, force) db_cmd = lldb_db_cmd else initial_path = '.' - re = '/core[^/]*$' + if 'freebsd' == module.uname() then + re = '/nvim.core$' + else + re = '/core[^/]*$' + end exc_re = { '^/%.deps$', '^/%'..deps_prefix()..'$', local_tmpdir, '^/%node_modules$' } db_cmd = gdb_db_cmd random_skip = true |