diff options
Diffstat (limited to 'test/functional/ui')
32 files changed, 5553 insertions, 624 deletions
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index 7c0831bd09..46bfae8de2 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -762,7 +762,7 @@ describe('Buffer highlighting', function() local s1 = {{'Köttbullar', 'Comment'}, {'Kräuterbutter'}} local s2 = {{'こんにちは', 'Comment'}} - -- TODO: only a virtual text from the same ns curretly overrides + -- TODO: only a virtual text from the same ns currently overrides -- an existing virtual text. We might add a prioritation system. set_virtual_text(id1, 0, s1, {}) eq({{1, 0, 0, { diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua index fa5771a8b3..eb5de693bd 100644 --- a/test/functional/ui/cmdline_highlight_spec.lua +++ b/test/functional/ui/cmdline_highlight_spec.lua @@ -61,7 +61,7 @@ before_each(function() endwhile return ret endfunction - function SplittedMultibyteStart(cmdline) + function SplitMultibyteStart(cmdline) let ret = [] let i = 0 while i < len(a:cmdline) @@ -77,7 +77,7 @@ before_each(function() endwhile return ret endfunction - function SplittedMultibyteEnd(cmdline) + function SplitMultibyteEnd(cmdline) let ret = [] let i = 0 while i < len(a:cmdline) @@ -296,7 +296,7 @@ describe('Command-line coloring', function() end it('does the right thing when hl start appears to split multibyte char', function() - set_color_cb('SplittedMultibyteStart') + set_color_cb('SplitMultibyteStart') start_prompt('echo "«') screen:expect{grid=[[ | @@ -322,7 +322,7 @@ describe('Command-line coloring', function() end) it('does the right thing when hl end appears to split multibyte char', function() - set_color_cb('SplittedMultibyteEnd') + set_color_cb('SplitMultibyteEnd') start_prompt('echo "«') screen:expect([[ | @@ -335,17 +335,17 @@ describe('Command-line coloring', function() :echo "«^ | ]]) end) - it('does the right thing when errorring', function() + it('does the right thing when erroring', function() set_color_cb('Echoerring') start_prompt('e') screen:expect([[ | {EOB:~ }| - {EOB:~ }| {MSEP: }| : | {ERR:E5407: Callback has thrown an exception:}| - {ERR: Vim(echoerr):HERE} | + {ERR: function DoPrompt[3]..Echoerring, line }| + {ERR:1: Vim(echoerr):HERE} | :e^ | ]]) end) @@ -400,16 +400,16 @@ describe('Command-line coloring', function() screen:expect([[ | {EOB:~ }| - {EOB:~ }| {MSEP: }| : | {ERR:E5407: Callback has thrown an exception:}| + {ERR: function DoPrompt[3]..Throwing, line 1:}| {ERR: ABC} | :e^ | ]]) end) it('stops executing callback after a number of errors', function() - set_color_cb('SplittedMultibyteStart') + set_color_cb('SplitMultibyteStart') start_prompt('let x = "«»«»«»«»«»"') screen:expect([[ | @@ -772,7 +772,7 @@ describe('Ex commands coloring', function() ]]) end) it('still executes command-line even if errored out', function() - meths.set_var('Nvim_color_cmdline', 'SplittedMultibyteStart') + meths.set_var('Nvim_color_cmdline', 'SplitMultibyteStart') feed(':let x = "«"\n') eq('«', meths.get_var('x')) local msg = 'E5405: Chunk 0 start 10 splits multibyte character' diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index db13647cc6..1c9ac7f7ba 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -4,9 +4,12 @@ local clear, feed = helpers.clear, helpers.feed local source = helpers.source local command = helpers.command local assert_alive = helpers.assert_alive -local uname = helpers.uname +local poke_eventloop = helpers.poke_eventloop +local exec = helpers.exec local eval = helpers.eval local eq = helpers.eq +local is_os = helpers.is_os +local meths = helpers.meths local function new_screen(opt) local screen = Screen.new(25, 5) @@ -716,7 +719,7 @@ describe('cmdline redraw', function() end) it('with <Cmd>', function() - if string.find(uname(), 'bsd') then + if is_os('bsd') then pending('FIXME #10804') end command('cmap a <Cmd>call sin(0)<CR>') -- no-op @@ -821,16 +824,27 @@ describe('statusline is redrawn on entering cmdline', function() ]]} end) - it('but not with scrolled messages', function() - command('set statusline=%{mode()}') - screen:try_resize(35,10) + it('with scrolled messages', function() + screen:try_resize(35,14) + exec([[ + let g:count = 0 + autocmd CmdlineEnter * let g:count += 1 + split + resize 1 + setlocal statusline=%{mode()}%{g:count} + setlocal winbar=%{mode()}%{g:count} + ]]) feed(':echoerr doesnotexist<cr>') screen:expect{grid=[[ + {9:c1 }| + | + {3:c1 }| | {1:~ }| {1:~ }| {1:~ }| {1:~ }| + {1:~ }| {3: }| {4:E121: Undefined variable: doesnotex}| {4:ist} | @@ -839,8 +853,12 @@ describe('statusline is redrawn on entering cmdline', function() ]]} feed(':echoerr doesnotexist<cr>') screen:expect{grid=[[ + {9:c2 }| + | + {3:c2 }| | {1:~ }| + {1:~ }| {3: }| {4:E121: Undefined variable: doesnotex}| {4:ist} | @@ -853,6 +871,10 @@ describe('statusline is redrawn on entering cmdline', function() feed(':echoerr doesnotexist<cr>') screen:expect{grid=[[ + {9:c3 }| + | + {3:c3 }| + {3: }| {4:E121: Undefined variable: doesnotex}| {4:ist} | {5:Press ENTER or type command to cont}| @@ -867,7 +889,10 @@ describe('statusline is redrawn on entering cmdline', function() feed('<cr>') screen:expect{grid=[[ + {9:n3 }| ^ | + {3:n3 }| + | {1:~ }| {1:~ }| {1:~ }| @@ -875,7 +900,8 @@ describe('statusline is redrawn on entering cmdline', function() {1:~ }| {1:~ }| {1:~ }| - {3:n }| + {1:~ }| + {2:[No Name] }| | ]]} end) @@ -934,6 +960,15 @@ describe('cmdheight=0', function() before_each(function() clear() screen = Screen.new(25, 5) + screen:set_default_attr_ids { + [1] = {bold = true, foreground = Screen.colors.Blue}; + [2] = {bold = true, reverse = true}; + [3] = {bold = true}; + [4] = {foreground = Screen.colors.White, background = Screen.colors.Red}; + [5] = {foreground = Screen.colors.SeaGreen4, bold = true}; + [6] = {reverse = true}; + [7] = {background = Screen.colors.Yellow}; + } screen:attach() end) @@ -941,9 +976,9 @@ describe('cmdheight=0', function() command("set cmdheight=1 noruler laststatus=2") screen:expect{grid=[[ ^ | - ~ | - ~ | - [No Name] | + {1:~ }| + {1:~ }| + {2:[No Name] }| | ]]} end) @@ -952,10 +987,10 @@ describe('cmdheight=0', function() command("set cmdheight=0 noruler laststatus=2") screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - [No Name] | + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] }| ]]} end) @@ -963,10 +998,10 @@ describe('cmdheight=0', function() command("set cmdheight=0 ruler laststatus=0") screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]]} end) @@ -975,10 +1010,10 @@ describe('cmdheight=0', function() feed('i') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]], showmode={}} feed('<Esc>') eq(0, eval('&cmdheight')) @@ -989,10 +1024,10 @@ describe('cmdheight=0', function() feed('i') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]], showmode={}} feed('<Esc>') eq(0, eval('&cmdheight')) @@ -1003,10 +1038,10 @@ describe('cmdheight=0', function() feed('i') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - -- INSERT -- | + {1:~ }| + {1:~ }| + {1:~ }| + {3:-- INSERT --} | ]]} feed('<Esc>') eq(1, eval('&cmdheight')) @@ -1017,19 +1052,19 @@ describe('cmdheight=0', function() feed(':') screen:expect{grid=[[ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| :^ | ]]} - eq(1, eval('&cmdheight')) + eq(0, eval('&cmdheight')) feed('<cr>') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]], showmode={}} eq(0, eval('&cmdheight')) end) @@ -1039,19 +1074,19 @@ describe('cmdheight=0', function() feed(':call input("foo >")<cr>') screen:expect{grid=[[ | - ~ | - ~ | - ~ | + {1:~ }| + {2: }| + :call input("foo >") | foo >^ | ]]} - eq(1, eval('&cmdheight')) + eq(0, eval('&cmdheight')) feed('<cr>') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]], showmode={}} eq(0, eval('&cmdheight')) end) @@ -1060,35 +1095,35 @@ describe('cmdheight=0', function() command("set cmdheight=0 noruler laststatus=3 winbar=foo") feed(':split<CR>') screen:expect{grid=[[ - foo | - | - E36: Not enough room | - Press ENTER or type comma| - nd to continue^ | + {2: }| + :split | + {4:E36: Not enough room} | + {5:Press ENTER or type comma}| + {5:nd to continue}^ | ]]} feed('<CR>') screen:expect{grid=[[ - foo | + {3:foo }| ^ | - ~ | - ~ | - [No Name] | + {1:~ }| + {1:~ }| + {2:[No Name] }| ]]} feed(':') screen:expect{grid=[[ - foo | + {3:foo }| | - ~ | - [No Name] | + {1:~ }| + {1:~ }| :^ | ]]} feed('<Esc>') screen:expect{grid=[[ - foo | + {3:foo }| ^ | - ~ | - ~ | - [No Name] | + {1:~ }| + {1:~ }| + {2:[No Name] }| ]], showmode={}} eq(0, eval('&cmdheight')) @@ -1100,19 +1135,19 @@ describe('cmdheight=0', function() feed('qq') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - recording @q | - ]], showmode={}} + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} feed('q') screen:expect{grid=[[ ^ | - ~ | - ~ | - ~ | - ~ | - ]], showmode={}} + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], unchanged=true} end) it("when substitute text", function() @@ -1120,28 +1155,28 @@ describe('cmdheight=0', function() feed('ifoo<ESC>') screen:expect{grid=[[ fo^o | - ~ | - ~ | - ~ | - [No Name] [+] | + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] [+] }| ]]} feed(':%s/foo/bar/gc<CR>') screen:expect{grid=[[ - foo | - ~ | - ~ | - [No Name] [+] | - replace wi...q/l/^E/^Y)?^ | + {6:foo} | + {1:~ }| + {1:~ }| + {1:~ }| + {5:replace wi...q/l/^E/^Y)?}^ | ]]} feed('y') screen:expect{grid=[[ ^bar | - ~ | - ~ | - ~ | - [No Name] [+] | + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] [+] }| ]]} assert_alive() @@ -1152,4 +1187,223 @@ describe('cmdheight=0', function() feed('<C-w>+') eq(0, eval('&cmdheight')) end) + + it("with non-silent mappings with cmdline", function() + command("set cmdheight=0") + command("map <f3> :nohlsearch<cr>") + feed('iaabbaa<esc>/aa<cr>') + screen:expect{grid=[[ + {7:^aa}bb{7:aa} | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + + feed('<f3>') + screen:expect{grid=[[ + ^aabbaa | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + end) + + it('with silent! at startup', function() + clear{args={'-c', 'set cmdheight=0', '-c', 'autocmd VimEnter * silent! call Foo()'}} + screen:attach() + -- doesn't crash while not displaying silent! error message + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + end) + + it('with multigrid', function() + clear{args={'--cmd', 'set cmdheight=0'}} + screen:attach{ext_multigrid=true} + screen:expect{grid=[[ + ## grid 1 + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + ## grid 2 + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + + feed '/p' + screen:expect{grid=[[ + ## grid 1 + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [3:-------------------------]| + ## grid 2 + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + /p^ | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + end) + + it('winbar is redrawn on entering cmdline and :redrawstatus #20336', function() + exec([[ + set cmdheight=0 + set winbar=%{mode()}%=:%{getcmdline()} + ]]) + feed(':') + screen:expect([[ + {3:c :}| + | + {1:~ }| + {1:~ }| + :^ | + ]]) + feed('echo') + -- not redrawn yet + screen:expect([[ + {3:c :}| + | + {1:~ }| + {1:~ }| + :echo^ | + ]]) + command('redrawstatus') + screen:expect([[ + {3:c :echo}| + | + {1:~ }| + {1:~ }| + :echo^ | + ]]) + end) + + it('window equalization with laststatus=0 #20367', function() + screen:try_resize(60, 9) + command('set cmdheight=0 laststatus=0') + command('vsplit') + screen:expect([[ + ^ │ | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + ]]) + feed(':') + command('split') + feed('<Esc>') + screen:expect([[ + ^ │ | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {2:[No Name] }│{1:~ }| + │{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + ]]) + command('resize 2') + screen:expect([[ + ^ │ | + {1:~ }│{1:~ }| + {2:[No Name] }│{1:~ }| + │{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + ]]) + feed(':') + command('wincmd =') + feed('<Esc>') + screen:expect([[ + ^ │ | + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {2:[No Name] }│{1:~ }| + │{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + {1:~ }│{1:~ }| + ]]) + end) + + it('no assert failure with showcmd', function() + command('set showcmd cmdheight=0') + feed('d') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]) + assert_alive() + end) + + it('can only be resized to 0 if set explicitly', function() + command('set laststatus=2') + command('resize +1') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {2:[No Name] }| + | + ]]) + command('set cmdheight=0') + command('resize -1') + command('resize +1') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] }| + ]]) + end) + + it("cannot be resized at all with external messages", function() + clear() + screen = new_screen({rgb=true, ext_messages=true}) + command('set laststatus=2 mouse=a') + command('resize -1') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {3:[No Name] }| + ]]) + meths.input_mouse('left', 'press', '', 0, 6, 10) + poke_eventloop() + meths.input_mouse('left', 'drag', '', 0, 5, 10) + screen:expect_unchanged() + end) end) diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index 03cd4bfd06..e261f0dfab 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -215,7 +215,7 @@ describe('ui/cursor', function() m.hl_id = 60 m.attr = {background = Screen.colors.DarkGray} end - if m.id_lm then m.id_lm = 61 end + if m.id_lm then m.id_lm = 62 end end -- Assert the new expectation. diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 789f1c6487..489c33d8b1 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -31,6 +31,8 @@ describe('decorations providers', function() [12] = {foreground = tonumber('0x990000')}; [13] = {background = Screen.colors.LightBlue}; [14] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue}; + [15] = {special = Screen.colors.Blue1, undercurl = true}, + [16] = {special = Screen.colors.Red, undercurl = true}, } end) @@ -56,7 +58,7 @@ describe('decorations providers', function() a.nvim_set_decoration_provider(_G.ns1, { on_start = on_do; on_buf = on_do; on_win = on_do; on_line = on_do; - on_end = on_do; + on_end = on_do; _on_spell_nav = on_do; }) return _G.ns1 ]]) @@ -95,7 +97,7 @@ describe('decorations providers', function() | ]]} check_trace { - { "start", 4, 40 }; + { "start", 4 }; { "win", 1000, 1, 0, 8 }; { "line", 1000, 1, 0 }; { "line", 1000, 1, 1 }; @@ -119,7 +121,7 @@ describe('decorations providers', function() | ]]} check_trace { - { "start", 5, 10 }; + { "start", 5 }; { "buf", 1 }; { "win", 1000, 1, 0, 8 }; { "line", 1000, 1, 6 }; @@ -156,6 +158,120 @@ describe('decorations providers', function() ]]} end) + it('can indicate spellchecked points', function() + exec [[ + set spell + set spelloptions=noplainbuffer + syntax off + ]] + + insert [[ + I am well written text. + i am not capitalized. + I am a speling mistakke. + ]] + + setup_provider [[ + local ns = a.nvim_create_namespace "spell" + beamtrace = {} + local function on_do(kind, ...) + if kind == 'win' or kind == 'spell' then + a.nvim_buf_set_extmark(0, ns, 0, 0, { + end_row = 2, + end_col = 23, + spell = true, + priority = 20, + ephemeral = true + }) + end + table.insert(beamtrace, {kind, ...}) + end + ]] + + check_trace { + { "start", 5 }; + { "win", 1000, 1, 0, 5 }; + { "line", 1000, 1, 0 }; + { "line", 1000, 1, 1 }; + { "line", 1000, 1, 2 }; + { "line", 1000, 1, 3 }; + { "end", 5 }; + } + + feed "gg0" + + screen:expect{grid=[[ + ^I am well written text. | + {15:i} am not capitalized. | + I am a {16:speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed "]s" + check_trace { + { "spell", 1000, 1, 1, 0, 1, -1 }; + } + screen:expect{grid=[[ + I am well written text. | + {15:^i} am not capitalized. | + I am a {16:speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed "]s" + check_trace { + { "spell", 1000, 1, 2, 7, 2, -1 }; + } + screen:expect{grid=[[ + I am well written text. | + {15:i} am not capitalized. | + I am a {16:^speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + -- spell=false with lower priority doesn't disable spell + local ns = meths.create_namespace "spell" + local id = helpers.curbufmeths.set_extmark(ns, 0, 0, { priority = 30, end_row = 2, end_col = 23, spell = false }) + + screen:expect{grid=[[ + I am well written text. | + i am not capitalized. | + I am a ^speling mistakke. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + -- spell=false with higher priority does disable spell + helpers.curbufmeths.set_extmark(ns, 0, 0, { id = id, priority = 10, end_row = 2, end_col = 23, spell = false }) + + screen:expect{grid=[[ + I am well written text. | + {15:i} am not capitalized. | + I am a {16:^speling} {16:mistakke}. | + | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + end) + it('can predefine highlights', function() screen:try_resize(40, 16) insert(mulholland) @@ -484,6 +600,7 @@ describe('extmark decorations', function() [24] = {bold = true}; [25] = {background = Screen.colors.LightRed}; [26] = {background=Screen.colors.DarkGrey, foreground=Screen.colors.LightGrey}; + [27] = {background = Screen.colors.Plum1}; } ns = meths.create_namespace 'test' @@ -606,15 +723,15 @@ end]] screen:expect{grid=[[ {5:^for} _,item {5:in} {6:ipairs}(items) {5:do} | - {5:local} text, hl_id_cell, count = unpack(item) | - {5:if} hl_id_cell ~= {13:nil} {5:then} | - hl_id = hl_id_cell | + {5:local} text, hl_id_cell, count {5:=} unpack(item) | + {5:if} hl_id_cell {5:~=} {13:nil} {5:then} | + hl_id {5:=} hl_id_cell | {5:end} | - {5:for} _ = {13:1}, (count {5:or} {13:1}) {5:do} | - {5:local} cell = line[colpos] | - cell.text = text | - cell.hl_id = hl_id | - colpos = colpos+{13:1} | + {5:for} _ {5:=} {13:1}, (count {5:or} {13:1}) {5:do} | + {5:local} cell {5:=} line[colpos] | + cell.text {5:=} text | + cell.hl_id {5:=} hl_id | + colpos {5:=} colpos{5:+}{13:1} | {5:end} | {5:end} | {1:~ }| @@ -633,15 +750,15 @@ end]] screen:expect{grid=[[ {5:^for} _,item {5:in} {6:ipairs}(items) {5:do} | - {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count = unpack(item) | - {5:i}{12:c}{11:ombining color} {13:nil} {5:then} | + {5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count {5:=} unpack(item) | + {5:i}{12:c}{11:ombining col}{12:or} {13:nil} {5:then} | {11:replacing color}d_cell | {5:e}{8:bl}{7:endy}{10: }{7:text}{10: }{7:-}{10: }{7:here} | - {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | + {5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | {11:replacing color} line[colpos] | - cell.text = text | - cell.hl_id = hl_id | - colpos = colpos+{13:1} | + cell.text {5:=} text | + cell.hl_id {5:=} hl_id | + colpos {5:=} colpos{5:+}{13:1} | {5:end} | {5:end} | {1:~ }| @@ -652,15 +769,15 @@ end]] feed 'V5G' screen:expect{grid=[[ {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} | - {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} | - {18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} | + {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)} | + {18: }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then} | {18: }{11:replacing color}{18:d_cell} | {18: }{5:^e}{17:nd} | - {5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | + {5:f}{12:co}{11:mbi}{12:n}{11:i}{16:n}{11:g color}t {5:or} {13:1}) {5:do} | {11:replacing color} line[colpos] | - cell.text = text | - cell.hl_id = hl_id | - colpos = colpos+{13:1} | + cell.text {5:=} text | + cell.hl_id {5:=} hl_id | + colpos {5:=} colpos{5:+}{13:1} | {5:end} | {5:end} | {1:~ }| @@ -671,15 +788,15 @@ end]] feed 'jj' screen:expect{grid=[[ {17:for}{18: _,item }{17:in}{18: }{19:ipairs}{18:(items) }{17:do} | - {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count = unpack(item)} | - {18: }{17:i}{12:c}{11:ombining color}{18: }{23:nil}{18: }{17:then} | + {18: }{17:l}{20:blen}{21:dy}{22:e}{21:text}{22:h}{21:-}{22:_}{21:here}{18:ell, count }{17:=}{18: unpack(item)} | + {18: }{17:i}{12:c}{11:ombining col}{12:or}{18: }{23:nil}{18: }{17:then} | {18: }{11:replacing color}{18:d_cell} | {18: }{17:end} | - {18: }{17:for}{18: _ = }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} | - {18: }^ {18: }{17:local}{18: cell = line[colpos]} | - cell.text = text | - cell.hl_id = hl_id | - colpos = colpos+{13:1} | + {18: }{17:for}{18: _ }{17:=}{18: }{23:1}{18:, (count }{17:or}{18: }{23:1}{18:) }{17:do} | + {18: }^ {18: }{17:local}{18: cell }{17:=}{18: line[colpos]} | + cell.text {5:=} text | + cell.hl_id {5:=} hl_id | + colpos {5:=} colpos{5:+}{13:1} | {5:end} | {5:end} | {1:~ }| @@ -879,6 +996,55 @@ end]] | ]]) end) + + it('avoids redraw issue #20651', function() + exec_lua[[ + vim.cmd.normal'10oXXX' + vim.cmd.normal'gg' + local ns = vim.api.nvim_create_namespace('ns') + + local bufnr = vim.api.nvim_create_buf(false, true) + vim.api.nvim_open_win(bufnr, false, { relative = 'win', height = 1, width = 1, row = 0, col = 0 }) + + vim.api.nvim_create_autocmd('CursorMoved', { callback = function() + local row = vim.api.nvim_win_get_cursor(0)[1] - 1 + vim.api.nvim_buf_set_extmark(0, ns, row, 0, { id = 1 }) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {}) + vim.schedule(function() + vim.api.nvim_buf_set_extmark(0, ns, row, 0, { + id = 1, + virt_text = {{'HELLO', 'Normal'}}, + }) + end) + end + }) + ]] + + for _ = 1, 3 do + helpers.sleep(10) + feed 'j' + end + + screen:expect{grid=[[ + {27: } | + XXX | + XXX | + ^XXX HELLO | + XXX | + XXX | + XXX | + XXX | + XXX | + XXX | + XXX | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + end) + end) describe('decorations: virtual lines', function() @@ -985,7 +1151,7 @@ if (h->n_buckets < new_n_buckets) { // expand ]]} meths.buf_set_extmark(0, ns, 5, 0, { - virt_lines = { {{"^^ REVIEW:", "Todo"}, {" new_vals variable seems unneccesary?", "Comment"}} }; + virt_lines = { {{"^^ REVIEW:", "Todo"}, {" new_vals variable seems unnecessary?", "Comment"}} }; }) -- TODO: what about the cursor?? screen:expect{grid=[[ @@ -998,7 +1164,7 @@ if (h->n_buckets < new_n_buckets) { // expand if (kh_is_map && val_size) { | ^char *new_vals = {3:krealloc}( h->vals_buf, new_n_| buckets * val_size); | - {5:^^ REVIEW:}{6: new_vals variable seems unneccesary?} | + {5:^^ REVIEW:}{6: new_vals variable seems unnecessary?} | h->vals_buf = new_vals; | | ]]} @@ -1201,6 +1367,110 @@ if (h->n_buckets < new_n_buckets) { // expand ]]} end) + it('works beyond end of the buffer with virt_lines_above', function() + insert(example_text) + feed 'G' + + screen:expect{grid=[[ + if (h->n_buckets < new_n_buckets) { // expand | + khkey_t *new_keys = (khkey_t *)krealloc((void *)| + h->keys, new_n_buckets * sizeof(khkey_t)); | + h->keys = new_keys; | + if (kh_is_map && val_size) { | + char *new_vals = krealloc( h->vals_buf, new_n_| + buckets * val_size); | + h->vals_buf = new_vals; | + } | + ^} | + {1:~ }| + | + ]]} + + local id = meths.buf_set_extmark(0, ns, 8, 0, { + virt_lines={{{"Grugg"}}}; + virt_lines_above = true, + }) + + screen:expect{grid=[[ + if (h->n_buckets < new_n_buckets) { // expand | + khkey_t *new_keys = (khkey_t *)krealloc((void *)| + h->keys, new_n_buckets * sizeof(khkey_t)); | + h->keys = new_keys; | + if (kh_is_map && val_size) { | + char *new_vals = krealloc( h->vals_buf, new_n_| + buckets * val_size); | + h->vals_buf = new_vals; | + } | + ^} | + Grugg | + | + ]]} + + feed('dd') + screen:expect{grid=[[ + if (h->n_buckets < new_n_buckets) { // expand | + khkey_t *new_keys = (khkey_t *)krealloc((void *)| + h->keys, new_n_buckets * sizeof(khkey_t)); | + h->keys = new_keys; | + if (kh_is_map && val_size) { | + char *new_vals = krealloc( h->vals_buf, new_n_| + buckets * val_size); | + h->vals_buf = new_vals; | + ^} | + Grugg | + {1:~ }| + | + ]]} + + feed('dk') + screen:expect{grid=[[ + if (h->n_buckets < new_n_buckets) { // expand | + khkey_t *new_keys = (khkey_t *)krealloc((void *)| + h->keys, new_n_buckets * sizeof(khkey_t)); | + h->keys = new_keys; | + if (kh_is_map && val_size) { | + ^char *new_vals = krealloc( h->vals_buf, new_n_| + buckets * val_size); | + Grugg | + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + + feed('dgg') + screen:expect{grid=[[ + ^ | + Grugg | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + --No lines in buffer-- | + ]]} + + meths.buf_del_extmark(0, ns, id) + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + --No lines in buffer-- | + ]]} + end) + it('does not cause syntax ml_get error at the end of a buffer #17816', function() command([[syntax region foo keepend start='^foo' end='^$']]) command('syntax sync minlines=100') @@ -1470,6 +1740,38 @@ if (h->n_buckets < new_n_buckets) { // expand } | | ]]} + + command 'set number' + screen:expect{grid=[[ + {9: 1 }^if (h->n_buckets < new_n_buckets) { // expand | + {9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((voi| + {9: }d *)h->keys, new_n_buckets * sizeof(khkey_t));| + {9: }{1:>>}{2: very tabby}text with tabs | + {9: 3 } h->keys = new_keys; | + {9: 4 } if (kh_is_map && val_size) { | + {9: 5 } char *new_vals = krealloc( h->vals_buf, ne| + {9: }w_n_buckets * val_size); | + {9: 6 } h->vals_buf = new_vals; | + {9: 7 } } | + {9: 8 }} | + | + ]]} + + command 'set tabstop&' + screen:expect{grid=[[ + {9: 1 }^if (h->n_buckets < new_n_buckets) { // expand | + {9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((voi| + {9: }d *)h->keys, new_n_buckets * sizeof(khkey_t));| + {9: }{1:>>}{2: very tabby}text with tabs | + {9: 3 } h->keys = new_keys; | + {9: 4 } if (kh_is_map && val_size) { | + {9: 5 } char *new_vals = krealloc( h->vals_buf, ne| + {9: }w_n_buckets * val_size); | + {9: 6 } h->vals_buf = new_vals; | + {9: 7 } } | + {9: 8 }} | + | + ]]} end) end) @@ -1869,4 +2171,39 @@ describe('decorations: virt_text', function() ]]} end) + it('redraws correctly when re-using extmark ids', function() + command 'normal 5ohello' + + screen:expect{grid=[[ + | + hello | + hello | + hello | + hello | + hell^o | + {3:~ }| + {3:~ }| + {3:~ }| + | + ]]} + + local ns = meths.create_namespace('ns') + for row = 1, 5 do + meths.buf_set_extmark(0, ns, row, 0, { id = 1, virt_text = {{'world', 'Normal'}} }) + end + + screen:expect{grid=[[ + | + hello | + hello | + hello | + hello | + hell^o world | + {3:~ }| + {3:~ }| + {3:~ }| + | + ]]} + end) + end) diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua index 36dc5addcd..dbdf3823ec 100644 --- a/test/functional/ui/diff_spec.lua +++ b/test/functional/ui/diff_spec.lua @@ -8,6 +8,8 @@ local insert = helpers.insert local write_file = helpers.write_file local dedent = helpers.dedent local exec = helpers.exec +local eq = helpers.eq +local meths = helpers.meths describe('Diff mode screen', function() local fname = 'Xtest-functional-diff-screen-1' @@ -1073,6 +1075,182 @@ int main(int argc, char **argv) :e | ]]) end) + + describe('line matching diff algorithm', function() + setup(function() + local f1 = [[if __name__ == "__main__": + import sys + app = QWidgets.QApplication(sys.args) + MainWindow = QtWidgets.QMainWindow() + ui = UI_MainWindow() + ui.setupUI(MainWindow) + MainWindow.show() + sys.exit(app.exec_())]] + write_file(fname, f1, false) + local f2 = [[if __name__ == "__main__": + import sys + comment these things + #app = QWidgets.QApplication(sys.args) + #MainWindow = QtWidgets.QMainWindow() + add a completely different line here + #ui = UI_MainWindow() + add another new line + ui.setupUI(MainWindow) + MainWindow.show() + sys.exit(app.exec_())]] + write_file(fname_2, f2, false) + end) + + it('diffopt+=linematch:20', function() + reread() + feed(':set diffopt=internal,filler<cr>') + screen:expect([[ + {1: }^if __name__ == "__│{1: }if __name__ == "_| + {1: } import sys │{1: } import sys | + {1: }{9: }{8:app = QWidgets}│{1: }{9: }{8:comment these}| + {1: }{9: }{8:MainWindow = Q}│{1: }{9: }{8:#app = QWidge}| + {1: }{9: }{8:ui = UI_}{9:MainWi}│{1: }{9: }{8:#MainWindow =}| + {1: }{2:------------------}│{1: }{4: add a complet}| + {1: }{2:------------------}│{1: }{4: #ui = UI_Main}| + {1: }{2:------------------}│{1: }{4: add another n}| + {1: } ui.setupUI(Mai│{1: } ui.setupUI(Ma| + {1: } MainWindow.sho│{1: } MainWindow.sh| + {1: } sys.exit(app.e│{1: } sys.exit(app.| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| + :set diffopt=internal,filler | + ]]) + + feed('G') + feed(':set diffopt+=linematch:20<cr>') + screen:expect([[ + {1: }if __name__ == "__│{1: }if __name__ == "_| + {1: } import sys │{1: } import sys | + {1: }{2:------------------}│{1: }{4: comment these}| + {1: }{9: app = QWidgets}│{1: }{9: }{8:#}{9:app = QWidge}| + {1: }{9: MainWindow = Q}│{1: }{9: }{8:#}{9:MainWindow =}| + {1: }{2:------------------}│{1: }{4: add a complet}| + {1: }{9: ui = UI_MainWi}│{1: }{9: }{8:#}{9:ui = UI_Main}| + {1: }{2:------------------}│{1: }{4: add another n}| + {1: } ui.setupUI(Mai│{1: } ui.setupUI(Ma| + {1: } MainWindow.sho│{1: } MainWindow.sh| + {1: } ^sys.exit(app.e│{1: } sys.exit(app.| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| + :set diffopt+=linematch:20 | + ]]) + end) + end) + + describe('line matching diff algorithm with icase', function() + setup(function() + local f1 = [[DDD +_aa]] + write_file(fname, f1, false) + local f2 = [[DDD +AAA +ccca]] + write_file(fname_2, f2, false) + end) + it('diffopt+=linematch:20,icase', function() + reread() + feed(':set diffopt=internal,filler,linematch:20<cr>') + screen:expect([[ + {1: }^DDD │{1: }DDD | + {1: }{2:------------------}│{1: }{4:AAA }| + {1: }{8:_a}{9:a }│{1: }{8:ccc}{9:a }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| + | + ]]) + feed(':set diffopt+=icase<cr>') + screen:expect([[ + {1: }^DDD │{1: }DDD | + {1: }{8:_}{9:aa }│{1: }{8:A}{9:AA }| + {1: }{2:------------------}│{1: }{4:ccca }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| + :set diffopt+=icase | + ]]) + end) + end) + + describe('line matching diff algorithm with iwhiteall', function() + setup(function() + local f1 = [[BB + AAA]] + write_file(fname, f1, false) + local f2 = [[BB + AAB +AAAB]] + write_file(fname_2, f2, false) + end) + it('diffopt+=linematch:20,iwhiteall', function() + reread() + feed(':set diffopt=internal,filler,linematch:20<cr>') + screen:expect{grid=[[ + {1: }^BB │{1: }BB | + {1: }{9: AA}{8:A}{9: }│{1: }{9: AA}{8:B}{9: }| + {1: }{2:------------------}│{1: }{4:AAAB }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| + | + ]]} + feed(':set diffopt+=iwhiteall<cr>') + screen:expect{grid=[[ + {1: }^BB │{1: }BB | + {1: }{2:------------------}│{1: }{4: AAB }| + {1: }{9: AAA }│{1: }{9:AAA}{8:B}{9: }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }| + :set diffopt+=iwhiteall | + ]]} + end) + end) end) it('win_update redraws lines properly', function() @@ -1315,6 +1493,26 @@ it('Align the filler lines when changing text in diff mode', function() ]]} end) +it("diff mode doesn't restore invalid 'foldcolumn' value #21647", function() + clear() + local screen = Screen.new(60, 6) + screen:set_default_attr_ids({ + [0] = {foreground = Screen.colors.Blue, bold = true}; + }) + screen:attach() + eq('0', meths.get_option_value('foldcolumn', {})) + command('diffsplit | bd') + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + eq('0', meths.get_option_value('foldcolumn', {})) +end) + -- oldtest: Test_diff_binary() it('diff mode works properly if file contains NUL bytes vim-patch:8.2.3925', function() clear() diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua index 92f5beebf5..cd2b48213d 100644 --- a/test/functional/ui/embed_spec.lua +++ b/test/functional/ui/embed_spec.lua @@ -51,7 +51,7 @@ local function test_embed(ext_linegrid) end) it("doesn't erase output when setting color scheme", function() - if 'openbsd' == helpers.uname() then + if helpers.is_os('openbsd') then pending('FIXME #10804') end startup('--cmd', 'echoerr "foo"', '--cmd', 'color default', '--cmd', 'echoerr "bar"') @@ -82,20 +82,6 @@ local function test_embed(ext_linegrid) eq(Screen.colors.Green, screen.default_colors.rgb_bg) end} end) - - it("set display-=msgsep before first redraw", function() - startup('--cmd', 'set display-=msgsep') - screen:expect{grid=[[ - ^ | - {3:~ }| - {3:~ }| - {3:~ }| - {3:~ }| - {3:~ }| - {3:~ }| - | - ]]} - end) end describe('--embed UI on startup (ext_linegrid=true)', function() test_embed(true) end) diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 5967b630f6..6759510ad1 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -25,36 +25,6 @@ describe('float window', function() clear() command('hi VertSplit gui=reverse') end) - local attrs = { - [0] = {bold=true, foreground=Screen.colors.Blue}, - [1] = {background = Screen.colors.LightMagenta}, - [2] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1}, - [3] = {bold = true}, - [4] = {bold = true, reverse = true}, - [5] = {reverse = true}, - [6] = {background = Screen.colors.LightMagenta, bold = true, reverse = true}, - [7] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [8] = {bold = true, foreground = Screen.colors.SeaGreen4}, - [9] = {background = Screen.colors.LightGrey, underline = true}, - [10] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta}, - [11] = {bold = true, foreground = Screen.colors.Magenta}, - [12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Blue1}, - [13] = {background = Screen.colors.WebGray}, - [14] = {foreground = Screen.colors.Brown}, - [15] = {background = Screen.colors.Grey20}, - [16] = {background = Screen.colors.Grey20, bold = true, foreground = Screen.colors.Blue1}, - [17] = {background = Screen.colors.Yellow}, - [18] = {foreground = Screen.colors.Brown, background = Screen.colors.Grey20}, - [19] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray}, - [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}; - [27] = {background = Screen.colors.LightGray}; - } it('behavior', function() -- Create three windows and test that ":wincmd <direction>" changes to the @@ -93,7 +63,7 @@ describe('float window', function() end) it('closed immediately by autocmd #11383', function() - eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately', + eq('Window was closed immediately', pcall_err(exec_lua, [[ local a = vim.api local function crashes(contents) @@ -118,7 +88,7 @@ describe('float window', function() end) it('closed immediately by autocmd after win_enter #15548', function() - eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately', + eq('Window was closed immediately', pcall_err(exec_lua, [[ vim.cmd "autocmd BufLeave * ++once quit!" local buf = vim.api.nvim_create_buf(true, true) @@ -198,6 +168,29 @@ describe('float window', function() eq(7, pos[2]) end) + it('opened with correct position relative to the mouse', function() + meths.input_mouse('left', 'press', '', 0, 10, 10) + local pos = exec_lua([[ + local bufnr = vim.api.nvim_create_buf(false, true) + + local opts = { + width = 10, + height = 10, + col = 1, + row = 2, + relative = 'mouse', + style = 'minimal' + } + + local win_id = vim.api.nvim_open_win(bufnr, false, opts) + + return vim.api.nvim_win_get_position(win_id) + ]]) + + eq(12, pos[1]) + eq(11, pos[2]) + end) + it('opened with correct position relative to the cursor', function() local pos = exec_lua([[ local bufnr = vim.api.nvim_create_buf(false, true) @@ -421,6 +414,15 @@ describe('float window', function() eq(winids, eval('winids')) end) + it('no crash with bufpos and non-existent window', function() + command('new') + local closed_win = meths.get_current_win().id + command('close') + local buf = meths.create_buf(false,false) + meths.open_win(buf, true, {relative='win', win=closed_win, width=1, height=1, bufpos={0,0}}) + assert_alive() + end) + it("no segfault when setting minimal style after clearing local 'fillchars' #19510", function() local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1} local float_win = meths.open_win(0, true, float_opts) @@ -430,6 +432,13 @@ describe('float window', function() assert_alive() end) + it("'scroll' is computed correctly when opening float with splitkeep=screen #20684", function() + meths.set_option('splitkeep', 'screen') + local float_opts = {relative = 'editor', row = 1, col = 1, width = 10, height = 10} + local float_win = meths.open_win(0, true, float_opts) + eq(5, meths.win_get_option(float_win, 'scroll')) + end) + describe('with only one tabpage,', function() local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1} local old_buf, old_win @@ -569,7 +578,7 @@ describe('float window', function() end) end) - describe('with mulitple tabpages but only one listed buffer,', function() + describe('with multiple tabpages but only one listed buffer,', function() local float_opts = {relative = 'editor', row = 1, col = 1, width = 1, height = 1} local unlisted_buf, old_buf, old_win before_each(function() @@ -596,6 +605,11 @@ describe('float window', function() meths.buf_delete(old_buf, {force = true}) eq(old_win, curwin().id) end) + it('if called from non-floating window in another tabpage', function() + command('tab split') + eq(3, #meths.list_tabpages()) + meths.buf_delete(old_buf, {force = true}) + end) it('if called from floating window with the same buffer', function() meths.set_current_win(same_buf_float) command('autocmd WinLeave * let g:win_leave = nvim_get_current_win()') @@ -712,10 +726,41 @@ describe('float window', function() end) local function with_ext_multigrid(multigrid) - local screen + local screen, attrs before_each(function() screen = Screen.new(40,7) screen:attach {ext_multigrid=multigrid} + attrs = { + [0] = {bold=true, foreground=Screen.colors.Blue}, + [1] = {background = Screen.colors.LightMagenta}, + [2] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1}, + [3] = {bold = true}, + [4] = {bold = true, reverse = true}, + [5] = {reverse = true}, + [6] = {background = Screen.colors.LightMagenta, bold = true, reverse = true}, + [7] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [8] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [9] = {background = Screen.colors.LightGrey, underline = true}, + [10] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta}, + [11] = {bold = true, foreground = Screen.colors.Magenta}, + [12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Blue1}, + [13] = {background = Screen.colors.WebGray}, + [14] = {foreground = Screen.colors.Brown}, + [15] = {background = Screen.colors.Grey20}, + [16] = {background = Screen.colors.Grey20, bold = true, foreground = Screen.colors.Blue1}, + [17] = {background = Screen.colors.Yellow}, + [18] = {foreground = Screen.colors.Brown, background = Screen.colors.Grey20}, + [19] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray}, + [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}; + [27] = {background = Screen.colors.LightGray}; + [28] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray}; + } screen:set_default_attr_ids(attrs) end) @@ -1307,6 +1352,54 @@ describe('float window', function() end end) + it("would not break 'minimal' style with statuscolumn set", function() + command('set number') + command('set signcolumn=yes') + command('set colorcolumn=1') + command('set cursorline') + command('set foldcolumn=1') + command('set statuscolumn=%l%s%C') + command('hi NormalFloat guibg=#333333') + feed('ix<cr>y<cr><esc>gg') + meths.open_win(0, false, {relative='editor', width=20, height=4, row=4, col=10, style='minimal'}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + {20:1}{19: }{20: }{22:^x}{21: }| + {14:2}{19: }{14: }{22:y} | + {14:3}{19: }{14: }{22: } | + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 4 + {15:x }| + {15:y }| + {15: }| + {15: }| + ]], float_pos={[4] = {{id = 1001}, "NW", 1, 4, 10, true}}} + else + screen:expect{grid=[[ + {20:1}{19: }{20: }{22:^x}{21: }| + {14:2}{19: }{14: }{22:y} | + {14:3}{19: }{14: }{22: } {15:x } | + {0:~ }{15:y }{0: }| + {0:~ }{15: }{0: }| + {0:~ }{15: }{0: }| + | + ]]} + end + end) + it('can have border', function() local buf = meths.create_buf(false, false) meths.buf_set_lines(buf, 0, -1, true, {' halloj! ', @@ -1704,6 +1797,222 @@ describe('float window', function() end end) + it('validates title title_pos', function() + local buf = meths.create_buf(false,false) + eq("title requires border to be set", + pcall_err(meths.open_win,buf, false, { + relative='editor', width=9, height=2, row=2, col=5, title='Title', + })) + eq("title_pos requires title to be set", + pcall_err(meths.open_win,buf, false, { + relative='editor', width=9, height=2, row=2, col=5, + border='single', title_pos='left', + })) + end) + + it('validate title_pos in nvim_win_get_config', function() + local title_pos = exec_lua([[ + local bufnr = vim.api.nvim_create_buf(false, false) + local opts = { + relative = 'editor', + col = 2, + row = 5, + height = 2, + width = 9, + border = 'double', + title = 'Test', + title_pos = 'center' + } + + local win_id = vim.api.nvim_open_win(bufnr, true, opts) + return vim.api.nvim_win_get_config(win_id).title_pos + ]]) + + eq('center', title_pos) + end) + + + it('border with title', function() + local buf = meths.create_buf(false, false) + meths.buf_set_lines(buf, 0, -1, true, {' halloj! ', + ' BORDAA '}) + local win = meths.open_win(buf, false, { + relative='editor', width=9, height=2, row=2, col=5, border="double", + title = "Left",title_pos = "left", + }) + + 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:╔}{11:Left}{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, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:╔}{11:Left}{5:═════╗}{0: }| + {0:~ }{5:║}{1: halloj! }{5:║}{0: }| + {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| + {0:~ }{5:╚═════════╝}{0: }| + | + ]]} + end + + meths.win_set_config(win, {title= "Center",title_pos="center"}) + 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:╔═}{11:Center}{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, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:╔═}{11:Center}{5:══╗}{0: }| + {0:~ }{5:║}{1: halloj! }{5:║}{0: }| + {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| + {0:~ }{5:╚═════════╝}{0: }| + | + ]]} + end + + meths.win_set_config(win, {title= "Right",title_pos="right"}) + 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:╔════}{11:Right}{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, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:╔════}{11:Right}{5:╗}{0: }| + {0:~ }{5:║}{1: halloj! }{5:║}{0: }| + {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| + {0:~ }{5:╚═════════╝}{0: }| + | + ]]} + end + + meths.win_set_config(win, {title= { {"🦄"},{"BB"}},title_pos="right"}) + 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:╔═════}🦄BB{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, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }{5:╔═════}🦄BB{5:╗}{0: }| + {0:~ }{5:║}{1: halloj! }{5:║}{0: }| + {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| + {0:~ }{5:╚═════════╝}{0: }| + | + ]]} + 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"}) @@ -2756,7 +3065,7 @@ describe('float window', function() }, "NW", 2, 1, 32, true } }} else - -- note: appears misalinged due to cursor + -- note: appears misaligned due to cursor screen:expect{grid=[[ ^example text that is wider than the window | {1:some info! } | @@ -2862,6 +3171,66 @@ describe('float window', function() ]]} end + command('set laststatus=0') + command('botright vnew') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----]{5:│}[6:--------------------]| + [2:----]{5:│}[6:--------------------]| + [2:----]{5:│}[6:--------------------]| + [2:----]{5:│}[6:--------------------]| + [2:----]{5:│}[6:--------------------]| + [2:----]{5:│}[6:--------------------]| + [2:----]{5:│}[6:--------------------]| + [2:----]{5:│}[6:--------------------]| + [2:----]{5:│}[6:--------------------]| + [3:-------------------------]| + ## grid 2 + exam| + ple | + text| + tha| + t is| + wid| + er t| + han | + the | + ## grid 3 + | + ## grid 5 + {1:some info! }| + ## grid 6 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ]], float_pos={ + [5] = { { + id = 1002 + }, "SW", 2, 8, 0, true } + }} + else + screen:expect{grid=[[ + exam{5:│}^ | + ple {5:│}{0:~ }| + text{5:│}{0:~ }| + tha{5:│}{0:~ }| + t is{5:│}{0:~ }| + wid{5:│}{0:~ }| + er t{5:│}{0:~ }| + {1:some info! }{0: }| + the {5:│}{0:~ }| + | + ]]} + end + command('close') + meths.win_set_config(win, {relative='win', bufpos={1,32}, anchor='NW', col=-2}) if multigrid then screen:expect{grid=[[ @@ -2957,6 +3326,54 @@ describe('float window', function() | ]]} end + + command('%fold') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [2:-------------------------]| + [3:-------------------------]| + ## grid 2 + {28:^+-- 5 lines: just some··}| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + {1:some info! }| + ]], float_pos={ + [5] = { { + id = 1002 + }, "NW", 2, 2, 0, true } + }} + else + screen:expect{grid=[[ + {28:^+-- 5 lines: just some··}| + {0:~ }| + {1:some info! }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + end end) it('validates cursor even when window is not entered', function() @@ -8147,6 +8564,394 @@ describe('float window', function() ]]} end end) + + it('it can be resized with messages and cmdheight=0 #20106', function() + screen:try_resize(40,9) + command 'set cmdheight=0' + local buf = meths.create_buf(false,true) + local win = meths.open_win(buf, false, {relative='editor', width=40, height=4, anchor='SW', row=9, col=0, style='minimal', border="single", noautocmd=true}) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + ## grid 5 + {5:┌────────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────────────────────────┘}| + ]], float_pos={ + [5] = {{id = 1002}, "SW", 1, 9, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {5:┌──────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└──────────────────────────────────────┘}| + ]]} + end + + exec_lua([[ + local win = ... + vim.api.nvim_win_set_height(win, 2) + vim.api.nvim_echo({ { "" } }, false, {}) + ]], win) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + ## grid 5 + {5:┌────────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────────────────────────┘}| + ]], float_pos={ + [5] = {{id = 1002}, "SW", 1, 9, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {5:┌──────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└──────────────────────────────────────┘}| + ]]} + + end + + meths.win_close(win, true) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ]]} + end + end) + + it('it can be resized with messages and cmdheight=1', function() + screen:try_resize(40,9) + local buf = meths.create_buf(false,true) + local win = meths.open_win(buf, false, {relative='editor', width=40, height=4, anchor='SW', row=8, col=0, style='minimal', border="single", noautocmd=true}) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + {5:┌────────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────────────────────────┘}| + ]], float_pos={ + [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {5:┌──────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└──────────────────────────────────────┘}| + | + ]]} + end + + exec_lua([[ + -- echo prompt is blocking, so schedule + local win = ... + vim.schedule(function() + vim.api.nvim_win_set_height(win, 2) + vim.api.nvim_echo({ { "\n" } }, false, {}) + end) + ]], win) + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + {8:Press ENTER or type command to continue}^ | + ## grid 5 + {5:┌────────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────────────────────────┘}| + ]], float_pos={ + [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + | + {0:~ }| + {5:┌──────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {4: }| + | + {8:Press ENTER or type command to continue}^ | + ]]} + end + + feed('<cr>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ## grid 5 + {5:┌────────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└────────────────────────────────────────┘}| + ]], float_pos={ + [5] = {{id = 1002}, "SW", 1, 8, 0, true, 50}; + }, win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {5:┌──────────────────────────────────────┐}| + {5:│}{1: }{5:│}| + {5:│}{1: }{5:│}| + {5:└──────────────────────────────────────┘}| + | + ]]} + end + + meths.win_close(win, true) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [3:----------------------------------------]| + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + | + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + + else + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + end + end) + + describe('no crash after moving and closing float window #21547', function() + local function test_float_move_close(cmd) + local float_opts = {relative = 'editor', row = 1, col = 1, width = 10, height = 10} + meths.open_win(meths.create_buf(false, false), true, float_opts) + if multigrid then + screen:expect({float_pos = {[4] = {{id = 1001}, 'NW', 1, 1, 1, true}}}) + end + command(cmd) + exec_lua([[ + vim.api.nvim_win_set_config(0, {relative = 'editor', row = 2, col = 2}) + vim.api.nvim_win_close(0, {}) + vim.api.nvim_echo({{''}}, false, {}) + ]]) + if multigrid then + screen:expect({float_pos = {}}) + end + assert_alive() + end + + it('if WinClosed autocommand flushes UI', function() + test_float_move_close('autocmd WinClosed * ++once redraw') + end) + + it('if closing buffer flushes UI', function() + test_float_move_close('autocmd BufWinLeave * ++once redraw') + end) + end) end describe('with ext_multigrid', function() diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index 6bb8bb81c6..46a478c1ea 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -4,9 +4,11 @@ local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq local command = helpers.command local feed_command = helpers.feed_command local insert = helpers.insert +local expect = helpers.expect local funcs = helpers.funcs local meths = helpers.meths -local source = helpers.source +local exec = helpers.exec +local exec_lua = helpers.exec_lua local assert_alive = helpers.assert_alive @@ -198,50 +200,6 @@ describe("folded lines", function() end end) - it("highlighting with relative line numbers", function() - command("set relativenumber cursorline cursorlineopt=number foldmethod=marker") - feed_command("set foldcolumn=2") - funcs.setline(1, '{{{1') - funcs.setline(2, 'line 1') - funcs.setline(3, '{{{1') - funcs.setline(4, 'line 2') - feed("j") - if multigrid then - screen:expect([[ - ## grid 1 - [2:---------------------------------------------]| - [2:---------------------------------------------]| - [2:---------------------------------------------]| - [2:---------------------------------------------]| - [2:---------------------------------------------]| - [2:---------------------------------------------]| - [2:---------------------------------------------]| - [3:---------------------------------------------]| - ## grid 2 - {7:+ }{8: 1 }{5:+-- 2 lines: ·························}| - {7:+ }{9: 0 }{5:^+-- 2 lines: ·························}| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - ## grid 3 - :set foldcolumn=2 | - ]]) - else - screen:expect([[ - {7:+ }{8: 1 }{5:+-- 2 lines: ·························}| - {7:+ }{9: 0 }{5:^+-- 2 lines: ·························}| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - :set foldcolumn=2 | - ]]) - end - end) - it("work with spell", function() command("set spell") insert(content1) @@ -1713,7 +1671,7 @@ describe("folded lines", function() end) it('does not crash when foldtext is longer than columns #12988', function() - source([[ + exec([[ function! MyFoldText() abort return repeat('-', &columns + 100) endfunction @@ -1760,7 +1718,7 @@ describe("folded lines", function() it('work correctly with :move #18668', function() screen:try_resize(45, 12) - source([[ + exec([[ set foldmethod=expr foldexpr=indent(v:lnum) let content = ['', '', 'Line1', ' Line2', ' Line3', \ 'Line4', ' Line5', ' Line6', @@ -1895,6 +1853,128 @@ describe("folded lines", function() ]]) end end) + + it('fold attached virtual lines are drawn correctly #21837', function() + funcs.setline(1, 'line 1') + funcs.setline(2, 'line 2') + funcs.setline(3, 'line 3') + funcs.setline(4, 'line 4') + feed("zfj") + exec_lua([[ + local ns = vim.api.nvim_create_namespace("ns") + vim.api.nvim_buf_set_extmark(0, ns, 0, 0, { virt_lines_above = true, virt_lines = {{{"virt_line above line 1", ""}}} }) + vim.api.nvim_buf_set_extmark(0, ns, 1, 0, { virt_lines = {{{"virt_line below line 2", ""}}} }) + vim.api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_lines_above = true, virt_lines = {{{"virt_line above line 3", ""}}} }) + vim.api.nvim_buf_set_extmark(0, ns, 3, 0, { virt_lines = {{{"virt_line below line 4", ""}}} }) + ]]) + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {5:^+-- 2 lines: line 1·························}| + virt_line above line 3 | + line 3 | + line 4 | + virt_line below line 4 | + {1:~ }| + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {5:^+-- 2 lines: line 1·························}| + virt_line above line 3 | + line 3 | + line 4 | + virt_line below line 4 | + {1:~ }| + {1:~ }| + | + ]]) + end + + feed('jzfj') + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + {5:+-- 2 lines: line 1·························}| + {5:^+-- 2 lines: line 3·························}| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + {5:+-- 2 lines: line 1·························}| + {5:^+-- 2 lines: line 3·························}| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end + + feed('kzo<C-Y>') + funcs.setline(5, 'line 5') + if multigrid then + screen:expect([[ + ## grid 1 + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [2:---------------------------------------------]| + [3:---------------------------------------------]| + ## grid 2 + virt_line above line 1 | + ^line 1 | + line 2 | + virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + line 5 | + {1:~ }| + ## grid 3 + | + ]]) + else + screen:expect([[ + virt_line above line 1 | + ^line 1 | + line 2 | + virt_line below line 2 | + {5:+-- 2 lines: line 3·························}| + line 5 | + {1:~ }| + | + ]]) + end + end) end describe("with ext_multigrid", function() @@ -1911,4 +1991,19 @@ describe("folded lines", function() command('%delete') eq(0, funcs.foldlevel(1)) end) + + it('multibyte fold markers work #20438', function() + meths.win_set_option(0, 'foldmethod', 'marker') + meths.win_set_option(0, 'foldmarker', '«,»') + insert([[ + bbbbb + bbbbb + bbbbb]]) + feed('zfgg') + expect([[ + bbbbb/*«*/ + bbbbb + bbbbb/*»*/]]) + eq(1, funcs.foldlevel(1)) + end) end) diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 4e3d62509c..288c2a214f 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -6,6 +6,7 @@ local command, exec = helpers.command, helpers.exec local eval = helpers.eval local feed_command, eq = helpers.feed_command, helpers.eq local curbufmeths = helpers.curbufmeths +local funcs = helpers.funcs local meths = helpers.meths describe('colorscheme compatibility', function() @@ -13,7 +14,9 @@ describe('colorscheme compatibility', function() clear() end) - it('t_Co is set to 256 by default', function() + it('&t_Co exists and is set to 256 by default', function() + eq(1, funcs.exists('&t_Co')) + eq(1, funcs.exists('+t_Co')) eq('256', eval('&t_Co')) end) end) @@ -1048,6 +1051,7 @@ describe('CursorLine and CursorLineNr highlights', function() ]]) end) + -- oldtest: Test_cursorline_after_yank() it('always updated. vim-patch:8.1.0849', function() local screen = Screen.new(50,5) screen:set_default_attr_ids({ @@ -1081,6 +1085,7 @@ describe('CursorLine and CursorLineNr highlights', function() ]]) end) + -- oldtest: Test_cursorline_with_visualmode() it('with visual area. vim-patch:8.1.1001', function() local screen = Screen.new(50,5) screen:set_default_attr_ids({ @@ -1108,6 +1113,7 @@ describe('CursorLine and CursorLineNr highlights', function() ]]) end) + -- 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:set_default_attr_ids({ @@ -1237,6 +1243,7 @@ describe('CursorLine and CursorLineNr highlights', function() }) end) + -- oldtest: Test_diff_with_cursorline_number() it('CursorLineNr shows correctly just below filler lines', function() local screen = Screen.new(50,12) screen:set_default_attr_ids({ @@ -1357,6 +1364,7 @@ describe('CursorColumn highlight', function() ]]) end) + -- oldtest: Test_cursorcolumn_callback() it('is updated if cursor is moved from timer', function() exec([[ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd']) @@ -1398,7 +1406,7 @@ describe('ColorColumn highlight', function() before_each(function() clear() screen = Screen.new(40, 15) - Screen:set_default_attr_ids({ + screen:set_default_attr_ids({ [1] = {background = Screen.colors.LightRed}, -- ColorColumn [2] = {background = Screen.colors.Grey90}, -- CursorLine [3] = {foreground = Screen.colors.Brown}, -- LineNr @@ -1412,6 +1420,7 @@ describe('ColorColumn highlight', function() screen:attach() end) + -- oldtest: Test_colorcolumn() it('when entering a buffer vim-patch:8.1.2073', function() exec([[ set nohidden @@ -1443,6 +1452,7 @@ describe('ColorColumn highlight', function() ]]) end) + -- oldtest: Test_colorcolumn_bri() it("in 'breakindent' vim-patch:8.2.1689", function() exec([[ call setline(1, 'The quick brown fox jumped over the lazy dogs') @@ -1467,6 +1477,7 @@ describe('ColorColumn highlight', function() ]]) end) + -- oldtest: Test_colorcolumn_sbr() it("in 'showbreak' vim-patch:8.2.1689", function() exec([[ call setline(1, 'The quick brown fox jumped over the lazy dogs') @@ -1560,17 +1571,6 @@ describe("MsgSeparator highlight and msgsep fillchar", function() 1 %a "[No Name]" line 1 | {3:Press ENTER or type command to continue}^ | ]]) - - -- when display doesn't contain msgsep, these options have no effect - feed_command("set display-=msgsep") - feed_command("ls") - screen:expect([[ - {1:~ }| - {1:~ }| - :ls | - 1 %a "[No Name]" line 1 | - {3:Press ENTER or type command to continue}^ | - ]]) end) it("and MsgArea", function() @@ -1697,6 +1697,7 @@ describe("'number' and 'relativenumber' highlight", function() ]]) end) + -- oldtest: Test_relativenumber_callback() it('relative number highlight is updated if cursor is moved from timer', function() local screen = Screen.new(50, 8) screen:set_default_attr_ids({ @@ -1745,38 +1746,40 @@ describe("'winhighlight' highlight", 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}, - [2] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Blue1}, - [3] = {bold = true, reverse = true}, - [4] = {reverse = true}, - [5] = {background = Screen.colors.DarkGreen}, - [6] = {background = Screen.colors.DarkGreen, bold = true, foreground = Screen.colors.Blue1}, - [7] = {background = Screen.colors.DarkMagenta}, - [8] = {background = Screen.colors.DarkMagenta, bold = true, foreground = Screen.colors.Blue1}, - [9] = {foreground = Screen.colors.Brown}, - [10] = {foreground = Screen.colors.Brown, background = Screen.colors.DarkBlue}, - [11] = {background = Screen.colors.DarkBlue, bold = true, reverse = true}, - [12] = {background = Screen.colors.DarkGreen, reverse = true}, - [13] = {background = Screen.colors.Magenta4, reverse = true}, - [14] = {background = Screen.colors.DarkBlue, reverse = true}, - [15] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, - [16] = {foreground = Screen.colors.Blue1}, - [17] = {background = Screen.colors.LightRed}, - [18] = {background = Screen.colors.Gray90}, - [19] = {foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray}, - [20] = {background = Screen.colors.LightGrey, underline = true}, - [21] = {bold = true}, - [22] = {bold = true, foreground = Screen.colors.SeaGreen4}, - [23] = {background = Screen.colors.LightMagenta}, - [24] = {background = Screen.colors.WebGray}, - [25] = {bold = true, foreground = Screen.colors.Green1}, - [26] = {background = Screen.colors.Red}, - [27] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Green1}, - [28] = {bold = true, foreground = Screen.colors.Brown}, + screen:set_default_attr_ids { + [0] = {bold=true, foreground=Screen.colors.Blue}; + [1] = {background = Screen.colors.DarkBlue}; + [2] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Blue1}; + [3] = {bold = true, reverse = true}; + [4] = {reverse = true}; + [5] = {background = Screen.colors.DarkGreen}; + [6] = {background = Screen.colors.DarkGreen, bold = true, foreground = Screen.colors.Blue1}; + [7] = {background = Screen.colors.DarkMagenta}; + [8] = {background = Screen.colors.DarkMagenta, bold = true, foreground = Screen.colors.Blue1}; + [9] = {foreground = Screen.colors.Brown}; + [10] = {foreground = Screen.colors.Brown, background = Screen.colors.DarkBlue}; + [11] = {background = Screen.colors.DarkBlue, bold = true, reverse = true}; + [12] = {background = Screen.colors.DarkGreen, reverse = true}; + [13] = {background = Screen.colors.Magenta4, reverse = true}; + [14] = {background = Screen.colors.DarkBlue, reverse = true}; + [15] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}; + [16] = {foreground = Screen.colors.Blue1}; + [17] = {background = Screen.colors.LightRed}; + [18] = {background = Screen.colors.Gray90}; + [19] = {foreground = Screen.colors.LightGrey, background = Screen.colors.DarkGray}; + [20] = {background = Screen.colors.LightGrey, underline = true}; + [21] = {bold = true}; + [22] = {bold = true, foreground = Screen.colors.SeaGreen4}; + [23] = {background = Screen.colors.LightMagenta}; + [24] = {background = Screen.colors.WebGray}; + [25] = {bold = true, foreground = Screen.colors.Green1}; + [26] = {background = Screen.colors.Red}; + [27] = {background = Screen.colors.DarkBlue, bold = true, foreground = Screen.colors.Green1}; + [28] = {bold = true, foreground = Screen.colors.Brown}; [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}; + } command("hi Background1 guibg=DarkBlue") command("hi Background2 guibg=DarkGreen") end) @@ -2021,6 +2024,33 @@ describe("'winhighlight' highlight", function() ]]) end) + it('updates background to changed linked group', function() + command("split") + command("setlocal winhl=Normal:FancyGroup") -- does not yet exist + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {3:[No Name] }| + | + {0:~ }| + {4:[No Name] }| + | + ]]} + + command("hi FancyGroup guibg=#FF8800") -- nice orange + screen:expect{grid=[[ + {30:^ }| + {31:~ }| + {31:~ }| + {3:[No Name] }| + | + {0:~ }| + {4:[No Name] }| + | + ]]} + end) + it('background applies also to non-text', function() command('set sidescroll=0') insert('Lorem ipsum dolor sit amet ') @@ -2333,6 +2363,51 @@ describe("'winhighlight' highlight", function() helpers.assert_alive() end) + + it('can redraw statusline on cursor movement', function() + screen:try_resize(40, 8) + exec [[ + set statusline=%f%=%#Background1#%l,%c%V\ %P + split + ]] + insert [[ + some text + more text]] + screen:expect{grid=[[ + some text | + more tex^t | + {0:~ }| + {3:[No Name] }{1:2,9 All}| + some text | + more text | + {4:[No Name] }{1:1,1 All}| + | + ]]} + + command 'set winhl=Background1:Background2' + screen:expect{grid=[[ + some text | + more tex^t | + {0:~ }| + {3:[No Name] }{5:2,9 All}| + some text | + more text | + {4:[No Name] }{1:1,1 All}| + | + ]]} + + feed 'k' + screen:expect{grid=[[ + some tex^t | + more text | + {0:~ }| + {3:[No Name] }{5:1,9 All}| + some text | + more text | + {4:[No Name] }{1:1,1 All}| + | + ]]} + end) end) describe('highlight namespaces', function() diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua index dc74d6d401..55f873e827 100644 --- a/test/functional/ui/hlstate_spec.lua +++ b/test/functional/ui/hlstate_spec.lua @@ -4,9 +4,10 @@ local Screen = require('test.functional.ui.screen') local clear, insert = helpers.clear, helpers.insert local command = helpers.command local meths = helpers.meths -local iswin = helpers.iswin local testprg = helpers.testprg local thelpers = require('test.functional.terminal.helpers') +local skip = helpers.skip +local is_os = helpers.is_os describe('ext_hlstate detailed highlights', function() local screen @@ -182,7 +183,7 @@ describe('ext_hlstate detailed highlights', function() end) it("work with :terminal", function() - if helpers.pending_win32(pending) then return end + skip(is_os('win')) screen:set_default_attr_ids({ [1] = {{}, {{hi_name = "TermCursorNC", ui_name = "TermCursorNC", kind = "ui"}}}, @@ -211,7 +212,7 @@ describe('ext_hlstate detailed highlights', function() thelpers.set_bold() thelpers.feed_data('z\n') -- TODO(bfredl): check if this distinction makes sense - if iswin() then + if is_os('win') then screen:expect([[ ^tty ready | x {5:y z} | @@ -237,7 +238,7 @@ describe('ext_hlstate detailed highlights', function() thelpers.feed_termcode("[A") thelpers.feed_termcode("[2C") - if iswin() then + if is_os('win') then screen:expect([[ ^tty ready | x {6:y}{5: z} | diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index 9ca4673efe..6fbf9b72c8 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -1190,6 +1190,8 @@ describe(":substitute, inccommand=split", function() end) it("deactivates if 'redrawtime' is exceeded #5602", function() + -- prevent redraws from 'incsearch' + meths.set_option('incsearch', false) -- Assert that 'inccommand' is ENABLED initially. eq("split", eval("&inccommand")) -- Set 'redrawtime' to minimal value, to ensure timeout is triggered. @@ -2972,6 +2974,59 @@ it(':substitute with inccommand, does not crash if range contains invalid marks' ]]) end) +it(':substitute with inccommand, no unnecessary redraw if preview is not shown', function() + local screen = Screen.new(60, 6) + clear() + common_setup(screen, 'split', 'test') + feed(':ls<CR>') + screen:expect([[ + test | + {15:~ }| + {11: }| + :ls | + 1 %a + "[No Name]" line 1 | + {13:Press ENTER or type command to continue}^ | + ]]) + feed(':s') + -- no unnecessary redraw, so messages are still shown + screen:expect([[ + test | + {15:~ }| + {11: }| + :ls | + 1 %a + "[No Name]" line 1 | + :s^ | + ]]) + feed('o') + screen:expect([[ + test | + {15:~ }| + {11: }| + :ls | + 1 %a + "[No Name]" line 1 | + :so^ | + ]]) + feed('<BS>') + screen:expect([[ + test | + {15:~ }| + {11: }| + :ls | + 1 %a + "[No Name]" line 1 | + :s^ | + ]]) + feed('/test') + -- now inccommand is shown, so screen is redrawn + screen:expect([[ + {12:test} | + {15:~ }| + {15:~ }| + {15:~ }| + {15:~ }| + :s/test^ | + ]]) +end) + it(":substitute doesn't crash with inccommand, if undo is empty #12932", function() local screen = Screen.new(10,5) clear() @@ -2992,6 +3047,43 @@ it(":substitute doesn't crash with inccommand, if undo is empty #12932", functio assert_alive() end) +it(':substitute with inccommand works properly if undo is not synced #20029', function() + local screen = Screen.new(30, 6) + clear() + common_setup(screen, 'nosplit', 'foo\nbar\nbaz') + meths.set_keymap('x', '<F2>', '<Esc>`<Oaaaaa asdf<Esc>`>obbbbb asdf<Esc>V`<k:s/asdf/', {}) + feed('gg0<C-V>lljj<F2>') + screen:expect([[ + aaaaa | + foo | + bar | + baz | + bbbbb | + :'<,'>s/asdf/^ | + ]]) + feed('hjkl') + screen:expect([[ + aaaaa {12:hjkl} | + foo | + bar | + baz | + bbbbb {12:hjkl} | + :'<,'>s/asdf/hjkl^ | + ]]) + feed('<CR>') + expect([[ + aaaaa hjkl + foo + bar + baz + bbbbb hjkl]]) + feed('u') + expect([[ + foo + bar + baz]]) +end) + it('long :%s/ with inccommand does not collapse cmdline', function() local screen = Screen.new(10,5) clear() diff --git a/test/functional/ui/inccommand_user_spec.lua b/test/functional/ui/inccommand_user_spec.lua index 0b25d4f8d2..43e9b94feb 100644 --- a/test/functional/ui/inccommand_user_spec.lua +++ b/test/functional/ui/inccommand_user_spec.lua @@ -220,7 +220,7 @@ local setup_replace_cmd = [[ end -- ":<range>Replace <pat1> <pat2>" - -- Replaces all occurences of <pat1> in <range> with <pat2> + -- Replaces all occurrences of <pat1> in <range> with <pat2> vim.api.nvim_create_user_command( 'Replace', replace, diff --git a/test/functional/ui/linematch_spec.lua b/test/functional/ui/linematch_spec.lua new file mode 100644 index 0000000000..697677aa67 --- /dev/null +++ b/test/functional/ui/linematch_spec.lua @@ -0,0 +1,995 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') + +local feed = helpers.feed +local clear = helpers.clear +local write_file = helpers.write_file + +describe('Diff mode screen with 3 diffs open', function() + local fname = 'Xtest-functional-diff-screen-1' + local fname_2 = fname .. '.2' + local fname_3 = fname .. '.3' + local screen + + local reread = function() + feed(':e<cr><c-w>w:e<cr><c-w>w:e<cr><c-w>w') + end + + setup(function() + clear() + os.remove(fname) + os.remove(fname_2) + os.remove(fname_3) + end) + + teardown(function() + os.remove(fname) + os.remove(fname_2) + os.remove(fname_3) + end) + + before_each(function() + clear() + feed(':set diffopt+=linematch:30<cr>') + feed(':e ' .. fname .. '<cr>') + feed(':vnew ' .. fname_2 .. '<cr>') + feed(':vnew ' .. fname_3 .. '<cr>') + feed(':windo diffthis<cr>') + + screen = Screen.new(100, 16) + screen:attach() + screen:set_default_attr_ids({ + [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray}; + [2] = {foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.LightCyan1}; + [3] = {reverse = true}; + [4] = {background = Screen.colors.LightBlue}; + [5] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray}; + [6] = {foreground = Screen.colors.Blue1, bold = true}; + [7] = {reverse = true, bold = true}; + [8] = {background = Screen.colors.Red1, bold = true}; + [10] = {foreground = Screen.colors.Brown}; + [9] = {background = Screen.colors.Plum1}; + }) + feed('<c-w>=') + feed(':windo set nu!<cr>') + end) + + describe('setup the diff screen to look like a merge conflict with 3 files in diff mode', function() + before_each(function() + + local f1 = [[ + + common line + AAA + AAA + AAA + ]] + local f2 = [[ + + common line + <<<<<<< HEAD + AAA + AAA + AAA + ======= + BBB + BBB + BBB + >>>>>>> branch1 + ]] + local f3 = [[ + + common line + BBB + BBB + BBB + ]] + + write_file(fname, f1, false) + write_file(fname_2, f2, false) + write_file(fname_3, f3, false) + reread() + end) + + it('get from window 1', function() + feed('1<c-w>w') + feed(':2,6diffget screen-1.2<cr>') + screen:expect([[ + {1: }{10: 1 }^ │{1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }{9:<<<<<<< HEAD }│{1: }{10: 3 }{9:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}| + {1: }{10: 4 } AAA │{1: }{10: 4 } AAA │{1: }{10: 3 } AAA | + {1: }{10: 5 } AAA │{1: }{10: 5 } AAA │{1: }{10: 4 } AAA | + {1: }{10: 6 } AAA │{1: }{10: 6 } AAA │{1: }{10: 5 } AAA | + {1: }{10: 7 }{9:======= }│{1: }{10: 7 }{9:======= }│{1: }{10: }{2:---------------------------}| + {1: }{10: 8 }{9: BBB }│{1: }{10: 8 }{9: BBB }│{1: }{10: }{2:---------------------------}| + {1: }{10: 9 }{9: BBB }│{1: }{10: 9 }{9: BBB }│{1: }{10: }{2:---------------------------}| + {1: }{10: 10 }{9: BBB }│{1: }{10: 10 }{9: BBB }│{1: }{10: }{2:---------------------------}| + {1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: }{2:---------------------------}| + {1: }{10: 12 } │{1: }{10: 12 } │{1: }{10: 6 } | + {6:~ }│{6:~ }│{6:~ }| + {6:~ }│{6:~ }│{6:~ }| + {7:<-functional-diff-screen-1.3 [+] }{3:<est-functional-diff-screen-1.2 Xtest-functional-diff-screen-1 }| + :2,6diffget screen-1.2 | + ]]) + end) + + it('get from window 2', function() + feed('2<c-w>w') + feed(':5,7diffget screen-1.3<cr>') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 }^ │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}| + {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }| + {1: }{10: 3 }{9: BBB }│{1: }{10: 5 }{9: BBB }│{1: }{10: }{2:---------------------------}| + {1: }{10: 4 }{9: }{8:BBB}{9: }│{1: }{10: 6 }{9: }{8:BBB}{9: }│{1: }{10: 4 }{9: }{8:AAA}{9: }| + {1: }{10: 5 }{9: }{8:BBB}{9: }│{1: }{10: 7 }{9: }{8:BBB}{9: }│{1: }{10: 5 }{9: }{8:AAA}{9: }| + {1: }{10: }{2:---------------------------}│{1: }{10: 8 }{4:>>>>>>> branch1 }│{1: }{10: }{2:---------------------------}| + {1: }{10: 6 } │{1: }{10: 9 } │{1: }{10: 6 } | + {6:~ }│{6:~ }│{6:~ }| + {6:~ }│{6:~ }│{6:~ }| + {6:~ }│{6:~ }│{6:~ }| + {6:~ }│{6:~ }│{6:~ }| + {6:~ }│{6:~ }│{6:~ }| + {3:<test-functional-diff-screen-1.3 }{7:<functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }| + :5,7diffget screen-1.3 | + ]]) + end) + + it('get from window 3', function() + feed('3<c-w>w') + feed(':5,6diffget screen-1.2<cr>') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } │{1: }{10: 1 }^ | + {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}| + {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }| + {1: }{10: }{2:---------------------------}│{1: }{10: 5 }{9: AAA }│{1: }{10: 4 }{9: AAA }| + {1: }{10: }{2:---------------------------}│{1: }{10: 6 }{9: AAA }│{1: }{10: 5 }{9: AAA }| + {1: }{10: }{2:---------------------------}│{1: }{10: 7 }{9:======= }│{1: }{10: 6 }{9:======= }| + {1: }{10: 3 } BBB │{1: }{10: 8 } BBB │{1: }{10: 7 } BBB | + {1: }{10: 4 } BBB │{1: }{10: 9 } BBB │{1: }{10: 8 } BBB | + {1: }{10: 5 } BBB │{1: }{10: 10 } BBB │{1: }{10: 9 } BBB | + {1: }{10: }{2:---------------------------}│{1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: 10 }{9:>>>>>>> branch1 }| + {1: }{10: 6 } │{1: }{10: 12 } │{1: }{10: 11 } | + {6:~ }│{6:~ }│{6:~ }| + {6:~ }│{6:~ }│{6:~ }| + {3:<test-functional-diff-screen-1.3 <est-functional-diff-screen-1.2 }{7:<st-functional-diff-screen-1 [+] }| + :5,6diffget screen-1.2 | + ]]) + end) + + it('put from window 2 - part', function() + feed('2<c-w>w') + feed(':6,8diffput screen-1<cr>') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 }^ │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}| + {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }| + {1: }{10: }{2:---------------------------}│{1: }{10: 5 }{9: AAA }│{1: }{10: 4 }{9: AAA }| + {1: }{10: }{2:---------------------------}│{1: }{10: 6 }{9: AAA }│{1: }{10: 5 }{9: AAA }| + {1: }{10: }{2:---------------------------}│{1: }{10: 7 }{9:======= }│{1: }{10: 6 }{9:======= }| + {1: }{10: 3 }{9: BBB }│{1: }{10: 8 }{9: BBB }│{1: }{10: }{2:---------------------------}| + {1: }{10: 4 }{9: BBB }│{1: }{10: 9 }{9: BBB }│{1: }{10: }{2:---------------------------}| + {1: }{10: 5 } BBB │{1: }{10: 10 } BBB │{1: }{10: 7 } BBB | + {1: }{10: }{2:---------------------------}│{1: }{10: 11 }{4:>>>>>>> branch1 }│{1: }{10: }{2:---------------------------}| + {1: }{10: 6 } │{1: }{10: 12 } │{1: }{10: 8 } | + {6:~ }│{6:~ }│{6:~ }| + {6:~ }│{6:~ }│{6:~ }| + {3:<test-functional-diff-screen-1.3 }{7:<est-functional-diff-screen-1.2 }{3:<st-functional-diff-screen-1 [+] }| + :6,8diffput screen-1 | + ]]) + + end) + it('put from window 2 - part to end', function() + feed('2<c-w>w') + feed(':6,11diffput screen-1<cr>') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 }^ │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}| + {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }| + {1: }{10: }{2:---------------------------}│{1: }{10: 5 }{9: AAA }│{1: }{10: 4 }{9: AAA }| + {1: }{10: }{2:---------------------------}│{1: }{10: 6 }{9: AAA }│{1: }{10: 5 }{9: AAA }| + {1: }{10: }{2:---------------------------}│{1: }{10: 7 }{9:======= }│{1: }{10: 6 }{9:======= }| + {1: }{10: 3 } BBB │{1: }{10: 8 } BBB │{1: }{10: 7 } BBB | + {1: }{10: 4 } BBB │{1: }{10: 9 } BBB │{1: }{10: 8 } BBB | + {1: }{10: 5 } BBB │{1: }{10: 10 } BBB │{1: }{10: 9 } BBB | + {1: }{10: }{2:---------------------------}│{1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: 10 }{9:>>>>>>> branch1 }| + {1: }{10: 6 } │{1: }{10: 12 } │{1: }{10: 11 } | + {6:~ }│{6:~ }│{6:~ }| + {6:~ }│{6:~ }│{6:~ }| + {3:<test-functional-diff-screen-1.3 }{7:<est-functional-diff-screen-1.2 }{3:<st-functional-diff-screen-1 [+] }| + :6,11diffput screen-1 | + ]]) + + end) + end) +end) + +describe('Diff mode screen with 2 diffs open', function() + local fname = 'Xtest-functional-diff-screen-1' + local fname_2 = fname .. '.2' + local screen + + local reread = function() + feed(':e<cr><c-w>w:e<cr><c-w>w:e<cr><c-w>w') + end + + setup(function() + clear() + os.remove(fname) + os.remove(fname_2) + end) + + teardown(function() + os.remove(fname) + os.remove(fname_2) + end) + + before_each(function() + clear() + feed(':e ' .. fname .. '<cr>') + feed(':vnew ' .. fname_2 .. '<cr>') + feed(':windo diffthis<cr>') + + screen = Screen.new(100, 20) + screen:attach() + screen:set_default_attr_ids({ + [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray}; + [2] = {foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.LightCyan1}; + [3] = {reverse = true}; + [4] = {background = Screen.colors.LightBlue}; + [5] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray}; + [6] = {foreground = Screen.colors.Blue1, bold = true}; + [7] = {reverse = true, bold = true}; + [8] = {background = Screen.colors.Red1, bold = true}; + [10] = {foreground = Screen.colors.Brown}; + [9] = {background = Screen.colors.Plum1}; + }) + feed('<c-w>=') + feed(':windo set nu!<cr>') + end) + + describe('setup a diff with 2 files and set linematch:30', function() + before_each(function() + feed(':set diffopt+=linematch:30<cr>') + local f1 = [[ + +common line +common line + +DEFabc +xyz +xyz +xyz +DEFabc +DEFabc +DEFabc +common line +common line +DEF +common line +DEF +something + ]] + local f2 = [[ + +common line +common line + +ABCabc +ABCabc +ABCabc +ABCabc +common line +common line +common line +something + ]] + write_file(fname, f1, false) + write_file(fname_2, f2, false) + reread() + end) + + it('get from window 1 from line 5 to 9', function() + feed('1<c-w>w') + feed(':5,9diffget<cr>') + screen:expect([[ + {1:+ }{10: 1 }{5:^+-- 7 lines: common line··················}│{1:+ }{10: 1 }{5:+-- 7 lines: common line···················}| + {1: }{10: 8 }xyz │{1: }{10: 8 }xyz | + {1: }{10: 9 }DEFabc │{1: }{10: 9 }DEFabc | + {1: }{10: 10 }DEFabc │{1: }{10: 10 }DEFabc | + {1: }{10: 11 }DEFabc │{1: }{10: 11 }DEFabc | + {1: }{10: 12 }common line │{1: }{10: 12 }common line | + {1: }{10: 13 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 14 }common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 15 }something │{1: }{10: 17 }something | + {1: }{10: 16 } │{1: }{10: 18 } | + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }| + :5,9diffget | + ]]) + end) + it('get from window 2 from line 5 to 10', function() + feed('2<c-w>w') + feed(':5,10diffget<cr>') + screen:expect([[ + {1:- }{10: 1 } │{1:- }{10: 1 }^ | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }ABCabc │{1: }{10: 5 }ABCabc | + {1: }{10: 6 }ABCabc │{1: }{10: 6 }ABCabc | + {1: }{10: 7 }ABCabc │{1: }{10: 7 }ABCabc | + {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 8 }{8:DEF}{9:abc }| + {1: }{10: 9 }common line │{1: }{10: 9 }common line | + {1: }{10: 10 }common line │{1: }{10: 10 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 11 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 12 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 13 }{4:DEF }| + {1: }{10: 12 }something │{1: }{10: 14 }something | + {1: }{10: 13 } │{1: }{10: 15 } | + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }| + :5,10diffget | + ]]) + end) + it('get all from window 2', function() + feed('2<c-w>w') + feed(':4,17diffget<cr>') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 }^ | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }ABCabc │{1: }{10: 5 }ABCabc | + {1: }{10: 6 }ABCabc │{1: }{10: 6 }ABCabc | + {1: }{10: 7 }ABCabc │{1: }{10: 7 }ABCabc | + {1: }{10: 8 }ABCabc │{1: }{10: 8 }ABCabc | + {1: }{10: 9 }common line │{1: }{10: 9 }common line | + {1: }{10: 10 }common line │{1: }{10: 10 }common line | + {1: }{10: 11 }common line │{1: }{10: 11 }common line | + {1: }{10: 12 }something │{1: }{10: 12 }something | + {1: }{10: 13 } │{1: }{10: 13 } | + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }| + :4,17diffget | + ]]) + + end) + it('get all from window 1', function() + feed('1<c-w>w') + feed(':4,12diffget<cr>') + screen:expect([[ + {1: }{10: 1 }^ │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }DEFabc │{1: }{10: 5 }DEFabc | + {1: }{10: 6 }xyz │{1: }{10: 6 }xyz | + {1: }{10: 7 }xyz │{1: }{10: 7 }xyz | + {1: }{10: 8 }xyz │{1: }{10: 8 }xyz | + {1: }{10: 9 }DEFabc │{1: }{10: 9 }DEFabc | + {1: }{10: 10 }DEFabc │{1: }{10: 10 }DEFabc | + {1: }{10: 11 }DEFabc │{1: }{10: 11 }DEFabc | + {1: }{10: 12 }common line │{1: }{10: 12 }common line | + {1: }{10: 13 }common line │{1: }{10: 13 }common line | + {1: }{10: 14 }DEF │{1: }{10: 14 }DEF | + {1: }{10: 15 }common line │{1: }{10: 15 }common line | + {1: }{10: 16 }DEF │{1: }{10: 16 }DEF | + {1: }{10: 17 }something │{1: }{10: 17 }something | + {1: }{10: 18 } │{1: }{10: 18 } | + {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }| + :4,12diffget | + ]]) + end) + it('get from window 1 using do 1 line 5', function() + feed('1<c-w>w') + feed('5gg') + feed('do') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }^DEFabc │{1: }{10: 5 }DEFabc | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }| + {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }| + {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }| + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 12 }something │{1: }{10: 17 }something | + {1: }{10: 13 } │{1: }{10: 18 } | + {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }| + :e | + ]]) + end) + it('get from window 1 using do 2 line 6', function() + feed('1<c-w>w') + feed('6gg') + feed('do') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }^DEFabc │{1: }{10: 9 }DEFabc | + {1: }{10: 7 }DEFabc │{1: }{10: 10 }DEFabc | + {1: }{10: 8 }DEFabc │{1: }{10: 11 }DEFabc | + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 12 }something │{1: }{10: 17 }something | + {1: }{10: 13 } │{1: }{10: 18 } | + {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }| + :e | + ]]) + end) + it('get from window 1 using do 2 line 7', function() + feed('1<c-w>w') + feed('7gg') + feed('do') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }DEFabc │{1: }{10: 9 }DEFabc | + {1: }{10: 7 }^DEFabc │{1: }{10: 10 }DEFabc | + {1: }{10: 8 }DEFabc │{1: }{10: 11 }DEFabc | + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 12 }something │{1: }{10: 17 }something | + {1: }{10: 13 } │{1: }{10: 18 } | + {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }| + :e | + ]]) + end) + it('get from window 1 using do 2 line 11', function() + feed('1<c-w>w') + feed('11gg') + feed('do') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }| + {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }| + {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }| + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: 11 }DEF │{1: }{10: 14 }DEF | + {1: }{10: 12 }^common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 13 }something │{1: }{10: 17 }something | + {1: }{10: 14 } │{1: }{10: 18 } | + {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }| + :e | + ]]) + end) + it('get from window 1 using do 2 line 12', function() + feed('1<c-w>w') + feed('12gg') + feed('do') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }| + {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }| + {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }| + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 15 }common line | + {1: }{10: 12 }DEF │{1: }{10: 16 }DEF | + {1: }{10: 13 }^something │{1: }{10: 17 }something | + {1: }{10: 14 } │{1: }{10: 18 } | + {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }| + :e | + ]]) + end) + it('put from window 1 using dp 1 line 5', function() + feed('1<c-w>w') + feed('5gg') + feed('dp') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }^ABCabc │{1: }{10: 5 }ABCabc | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }| + {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }| + {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }| + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 12 }something │{1: }{10: 17 }something | + {1: }{10: 13 } │{1: }{10: 18 } | + {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }| + :e | + ]]) + end) + it('put from window 1 using dp 2 line 6', function() + feed('1<c-w>w') + feed('6gg') + feed('dp') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }^ABCabc │{1: }{10: 9 }ABCabc | + {1: }{10: 7 }ABCabc │{1: }{10: 10 }ABCabc | + {1: }{10: 8 }ABCabc │{1: }{10: 11 }ABCabc | + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 12 }something │{1: }{10: 17 }something | + {1: }{10: 13 } │{1: }{10: 18 } | + {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }| + :e | + ]]) + end) + it('put from window 1 using dp 2 line 7', function() + feed('1<c-w>w') + feed('7gg') + feed('dp') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }ABCabc │{1: }{10: 9 }ABCabc | + {1: }{10: 7 }^ABCabc │{1: }{10: 10 }ABCabc | + {1: }{10: 8 }ABCabc │{1: }{10: 11 }ABCabc | + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 12 }something │{1: }{10: 17 }something | + {1: }{10: 13 } │{1: }{10: 18 } | + {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }| + :e | + ]]) + end) + it('put from window 1 using dp 2 line 11', function() + feed('1<c-w>w') + feed('11gg') + feed('dp') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }| + {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }| + {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }| + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: 11 }^common line │{1: }{10: 14 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 15 }{4:DEF }| + {1: }{10: 12 }something │{1: }{10: 16 }something | + {1: }{10: 13 } │{1: }{10: 17 } | + {6:~ }│{6:~ }| + {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }| + :e | + ]]) + end) + it('put from window 1 using dp 2 line 12', function() + feed('1<c-w>w') + feed('12gg') + feed('dp') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }| + {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }| + {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }| + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 15 }common line | + {1: }{10: 12 }^something │{1: }{10: 16 }something | + {1: }{10: 13 } │{1: }{10: 17 } | + {6:~ }│{6:~ }| + {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }| + :e | + ]]) + end) + it('put from window 2 using dp line 6', function() + feed('2<c-w>w') + feed('6gg') + feed('dp') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: 6 }xyz │{1: }{10: 6 }^xyz | + {1: }{10: 7 }xyz │{1: }{10: 7 }xyz | + {1: }{10: 8 }xyz │{1: }{10: 8 }xyz | + {1: }{10: 9 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }| + {1: }{10: 10 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }| + {1: }{10: 11 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }| + {1: }{10: 12 }common line │{1: }{10: 12 }common line | + {1: }{10: 13 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 14 }common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 15 }something │{1: }{10: 17 }something | + {1: }{10: 16 } │{1: }{10: 18 } | + {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }| + :e | + ]]) + end) + it('put from window 2 using dp line 8', function() + feed('2<c-w>w') + feed('8gg') + feed('dp') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: 6 }xyz │{1: }{10: 6 }xyz | + {1: }{10: 7 }xyz │{1: }{10: 7 }xyz | + {1: }{10: 8 }xyz │{1: }{10: 8 }^xyz | + {1: }{10: 9 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }| + {1: }{10: 10 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }| + {1: }{10: 11 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }| + {1: }{10: 12 }common line │{1: }{10: 12 }common line | + {1: }{10: 13 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 14 }common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 15 }something │{1: }{10: 17 }something | + {1: }{10: 16 } │{1: }{10: 18 } | + {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }| + :e | + ]]) + end) + it('put from window 2 using dp line 9', function() + feed('2<c-w>w') + feed('9gg') + feed('dp') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }DEFabc │{1: }{10: 9 }^DEFabc | + {1: }{10: 7 }DEFabc │{1: }{10: 10 }DEFabc | + {1: }{10: 8 }DEFabc │{1: }{10: 11 }DEFabc | + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 15 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }| + {1: }{10: 12 }something │{1: }{10: 17 }something | + {1: }{10: 13 } │{1: }{10: 18 } | + {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }| + :e | + ]]) + end) + it('put from window 2 using dp line 17', function() + feed('2<c-w>w') + feed('17gg') + feed('dp') + screen:expect([[ + {1: }{10: 1 } │{1: }{10: 1 } | + {1: }{10: 2 }common line │{1: }{10: 2 }common line | + {1: }{10: 3 }common line │{1: }{10: 3 }common line | + {1: }{10: 4 } │{1: }{10: 4 } | + {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }| + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }| + {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }| + {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }| + {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }| + {1: }{10: 9 }common line │{1: }{10: 12 }common line | + {1: }{10: 10 }common line │{1: }{10: 13 }common line | + {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }| + {1: }{10: 11 }common line │{1: }{10: 15 }common line | + {1: }{10: 12 }DEF │{1: }{10: 16 }DEF | + {1: }{10: 13 }something │{1: }{10: 17 }^something | + {1: }{10: 14 } │{1: }{10: 18 } | + {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }| + :e | + ]]) + + end) + end) + describe('setup a diff with 2 files and set linematch:10', function() + before_each(function() + feed(':set diffopt+=linematch:10<cr>') + local f1 = [[ +common line +HIL + +aABCabc +aABCabc +aABCabc +aABCabc +common line +HIL +common line +something + ]] + local f2 = [[ +common line +DEF +GHI +something + +aDEFabc +xyz +xyz +xyz +aDEFabc +aDEFabc +aDEFabc +common line +DEF +GHI +something else +common line +something + ]] + write_file(fname, f1, false) + write_file(fname_2, f2, false) + reread() + end) + + it('enable linematch for the longest diff block by increasing the number argument passed to linematch', function() + feed('1<c-w>w') + -- linematch is disabled for the longest diff because it's combined line length is over 10 + screen:expect([[ + {1: }{10: 1 }^common line │{1: }{10: 1 }common line | + {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }| + {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 5 } │{1: }{10: 3 } | + {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }| + {1: }{10: 7 }{8:xyz}{9: }│{1: }{10: 5 }{8:aABCabc}{9: }| + {1: }{10: 8 }{8:xyz}{9: }│{1: }{10: 6 }{8:aABCabc}{9: }| + {1: }{10: 9 }{8:xyz}{9: }│{1: }{10: 7 }{8:aABCabc}{9: }| + {1: }{10: 10 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 11 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 12 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 13 }common line │{1: }{10: 8 }common line | + {1: }{10: 14 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 15 }{8:GHI}{9: }│{1: }{10: 9 }{8:HIL}{9: }| + {1: }{10: 16 }{4:something else }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 17 }common line │{1: }{10: 10 }common line | + {1: }{10: 18 }something │{1: }{10: 11 }something | + {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 }| + :e | + ]]) + -- enable it by increasing the number + feed(":set diffopt-=linematch:10<cr>") + feed(":set diffopt+=linematch:30<cr>") + screen:expect([[ + {1: }{10: 1 }^common line │{1: }{10: 1 }common line | + {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }| + {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 5 } │{1: }{10: 3 } | + {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }| + {1: }{10: 7 }{4:xyz }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 8 }{4:xyz }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 9 }{4:xyz }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 10 }{9:a}{8:DEF}{9:abc }│{1: }{10: 5 }{9:a}{8:ABC}{9:abc }| + {1: }{10: 11 }{9:a}{8:DEF}{9:abc }│{1: }{10: 6 }{9:a}{8:ABC}{9:abc }| + {1: }{10: 12 }{9:a}{8:DEF}{9:abc }│{1: }{10: 7 }{9:a}{8:ABC}{9:abc }| + {1: }{10: 13 }common line │{1: }{10: 8 }common line | + {1: }{10: 14 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 15 }{8:GHI}{9: }│{1: }{10: 9 }{8:HIL}{9: }| + {1: }{10: 16 }{4:something else }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 17 }common line │{1: }{10: 10 }common line | + {1: }{10: 18 }something │{1: }{10: 11 }something | + {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 }| + :set diffopt+=linematch:30 | + ]]) + end) + it('get all from second window', function() + feed('2<c-w>w') + feed(':1,12diffget<cr>') + screen:expect([[ + {1: }{10: 1 }common line │{1: }{10: 1 }^common line | + {1: }{10: 2 }DEF │{1: }{10: 2 }DEF | + {1: }{10: 3 }GHI │{1: }{10: 3 }GHI | + {1: }{10: 4 }something │{1: }{10: 4 }something | + {1: }{10: 5 } │{1: }{10: 5 } | + {1: }{10: 6 }aDEFabc │{1: }{10: 6 }aDEFabc | + {1: }{10: 7 }xyz │{1: }{10: 7 }xyz | + {1: }{10: 8 }xyz │{1: }{10: 8 }xyz | + {1: }{10: 9 }xyz │{1: }{10: 9 }xyz | + {1: }{10: 10 }aDEFabc │{1: }{10: 10 }aDEFabc | + {1: }{10: 11 }aDEFabc │{1: }{10: 11 }aDEFabc | + {1: }{10: 12 }aDEFabc │{1: }{10: 12 }aDEFabc | + {1: }{10: 13 }common line │{1: }{10: 13 }common line | + {1: }{10: 14 }DEF │{1: }{10: 14 }DEF | + {1: }{10: 15 }GHI │{1: }{10: 15 }GHI | + {1: }{10: 16 }something else │{1: }{10: 16 }something else | + {1: }{10: 17 }common line │{1: }{10: 17 }common line | + {1: }{10: 18 }something │{1: }{10: 18 }something | + {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }| + :1,12diffget | + ]]) + end) + it('get all from first window', function() + feed('1<c-w>w') + feed(':1,19diffget<cr>') + screen:expect([[ + {1: }{10: 1 }^common line │{1: }{10: 1 }common line | + {1: }{10: 2 }HIL │{1: }{10: 2 }HIL | + {1: }{10: 3 } │{1: }{10: 3 } | + {1: }{10: 4 }aABCabc │{1: }{10: 4 }aABCabc | + {1: }{10: 5 }aABCabc │{1: }{10: 5 }aABCabc | + {1: }{10: 6 }aABCabc │{1: }{10: 6 }aABCabc | + {1: }{10: 7 }aABCabc │{1: }{10: 7 }aABCabc | + {1: }{10: 8 }common line │{1: }{10: 8 }common line | + {1: }{10: 9 }HIL │{1: }{10: 9 }HIL | + {1: }{10: 10 }common line │{1: }{10: 10 }common line | + {1: }{10: 11 }something │{1: }{10: 11 }something | + {1: }{10: 12 } │{1: }{10: 12 } | + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {6:~ }│{6:~ }| + {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }| + :1,19diffget | + ]]) + end) + it('get part of the non linematched diff block in window 2 line 7 - 8 (non line matched block)', function() + feed('2<c-w>w') + feed(':7,8diffget<cr>') + screen:expect([[ + {1: }{10: 1 }common line │{1: }{10: 1 }^common line | + {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }| + {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 5 } │{1: }{10: 3 } | + {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }| + {1: }{10: 7 }{8:xyz}{9: }│{1: }{10: 5 }{8:aABCabc}{9: }| + {1: }{10: 8 }{8:xyz}{9: }│{1: }{10: 6 }{8:aABCabc}{9: }| + {1: }{10: 9 }xyz │{1: }{10: 7 }xyz | + {1: }{10: 10 }aDEFabc │{1: }{10: 8 }aDEFabc | + {1: }{10: 11 }aDEFabc │{1: }{10: 9 }aDEFabc | + {1: }{10: 12 }aDEFabc │{1: }{10: 10 }aDEFabc | + {1: }{10: 13 }common line │{1: }{10: 11 }common line | + {1: }{10: 14 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 15 }{8:GHI}{9: }│{1: }{10: 12 }{8:HIL}{9: }| + {1: }{10: 16 }{4:something else }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 17 }common line │{1: }{10: 13 }common line | + {1: }{10: 18 }something │{1: }{10: 14 }something | + {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }| + :7,8diffget | + ]]) + end) + it('get part of the non linematched diff block in window 2 line 8 - 10 (line matched block)', function() + feed('2<c-w>w') + feed(':8,10diffget<cr>') + screen:expect([[ + {1: }{10: 1 }common line │{1: }{10: 1 }^common line | + {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }| + {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 5 } │{1: }{10: 3 } | + {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }| + {1: }{10: 7 }{8:xyz}{9: }│{1: }{10: 5 }{8:aABCabc}{9: }| + {1: }{10: 8 }{8:xyz}{9: }│{1: }{10: 6 }{8:aABCabc}{9: }| + {1: }{10: 9 }{8:xyz}{9: }│{1: }{10: 7 }{8:aABCabc}{9: }| + {1: }{10: 10 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 11 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 12 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}| + {1: }{10: 13 }common line │{1: }{10: 8 }common line | + {1: }{10: 14 }DEF │{1: }{10: 9 }DEF | + {1: }{10: 15 }GHI │{1: }{10: 10 }GHI | + {1: }{10: 16 }something else │{1: }{10: 11 }something else | + {1: }{10: 17 }common line │{1: }{10: 12 }common line | + {1: }{10: 18 }something │{1: }{10: 13 }something | + {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }| + :8,10diffget | + ]]) + end) + end) +end) + +describe('regressions', function() + local screen + + it("doesn't crash with long lines", function() + clear() + feed(':set diffopt+=linematch:30<cr>') + screen = Screen.new(100, 20) + screen:attach() + -- line must be greater than MATCH_CHAR_MAX_LEN + helpers.curbufmeths.set_lines(0, -1, false, { string.rep('a', 1000)..'hello' }) + helpers.exec 'vnew' + helpers.curbufmeths.set_lines(0, -1, false, { string.rep('a', 1010)..'world' }) + helpers.exec 'windo diffthis' + end) +end) diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 2cff7c1cf4..3052a74f38 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -9,10 +9,13 @@ local meths = helpers.meths local async_meths = helpers.async_meths local test_build_dir = helpers.test_build_dir local nvim_prog = helpers.nvim_prog -local iswin = helpers.iswin +local exec = helpers.exec local exc_exec = helpers.exc_exec local exec_lua = helpers.exec_lua local poke_eventloop = helpers.poke_eventloop +local assert_alive = helpers.assert_alive +local is_os = helpers.is_os +local is_ci = helpers.is_ci describe('ui/ext_messages', function() local screen @@ -869,7 +872,7 @@ stack traceback: {1:~ }| {1:~ }| ]], messages={ - { content = { { "wow, ", 7 }, { "such\n\nvery ", 2 }, { "color", 10 } }, kind = "" } + { content = { { "wow, ", 7 }, { "such\n\nvery ", 2 }, { "color", 10 } }, kind = "echomsg" } }} feed ':ls<cr>' @@ -880,7 +883,7 @@ stack traceback: {1:~ }| {1:~ }| ]], messages={ - { content = { { '\n 1 %a "[No Name]" line 1' } }, kind = "echomsg" } + { content = { { '\n 1 %a "[No Name]" line 1' } }, kind = "" } }} feed ':messages<cr>' @@ -905,6 +908,13 @@ stack traceback: {1:~ }| ]]} end) + + it('does not truncate messages', function() + command('write Xtest') + screen:expect({messages={ + {content = { { '"Xtest" [New] 0L, 0B written' } }, kind = "" } + }}) + end) end) describe('ui/builtin messages', function() @@ -1077,10 +1087,10 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim ]]} end) - it('redraws NOT_VALID correctly after message', function() - -- edge case: only one window was set NOT_VALID. Original report + it('redraws UPD_NOT_VALID correctly after message', function() + -- edge case: only one window was set UPD_NOT_VALID. Original report -- used :make, but fake it using one command to set the current - -- window NOT_VALID and another to show a long message. + -- window UPD_NOT_VALID and another to show a long message. command("set more") feed(':new<cr><c-w><c-w>') screen:expect{grid=[[ @@ -1200,28 +1210,6 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim it('prints lines in Ex mode correctly with a burst of carriage returns #19341', function() command('set number') meths.buf_set_lines(0, 0, 0, true, {'aaa', 'bbb', 'ccc'}) - command('set display-=msgsep') - feed('gggQ<CR><CR>1<CR><CR>vi') - screen:expect([[ - Entering Ex mode. Type "visual" to go to Normal mode. | - {11: 2 }bbb | - {11: 3 }ccc | - :1 | - {11: 1 }aaa | - {11: 2 }bbb | - :vi^ | - ]]) - feed('<CR>') - screen:expect([[ - {11: 1 }aaa | - {11: 2 }^bbb | - {11: 3 }ccc | - {11: 4 } | - {1:~ }| - {1:~ }| - | - ]]) - command('set display+=msgsep') feed('gggQ<CR><CR>1<CR><CR>vi') screen:expect([[ Entering Ex mode. Type "visual" to go to Normal mode. | @@ -1256,6 +1244,45 @@ vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vim bar^ | ]]) end) + + it('consecutive calls to win_move_statusline() work after multiline message #21014',function() + async_meths.exec([[ + echo "\n" + call win_move_statusline(0, -4) + call win_move_statusline(0, 4) + ]], false) + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {3: }| + | + {4:Press ENTER or type command to continue}^ | + ]]) + feed('<CR>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + eq(1, meths.get_option('cmdheight')) + end) +end) + +it('calling screenstring() after redrawing between messages without UI #20999', function() + clear() + exec([[ + echo repeat('a', 100) + redraw + echo "\n" + call screenstring(1, 1) + ]]) + assert_alive() end) describe('ui/ext_messages', function() @@ -1285,7 +1312,6 @@ describe('ui/ext_messages', function() {1:~ }| {1:~ }| {1:~ }| - {1:~ }| {MATCH:.*}| {1:~ }| {1:~ }Nvim is open source and freely distributable{1: }| @@ -1296,6 +1322,8 @@ describe('ui/ext_messages', function() {1:~ }type :q{5:<Enter>} to exit {1: }| {1:~ }type :help{5:<Enter>} for help {1: }| {1:~ }| + {1:~ }type :help news{5:<Enter>} to see changes in v{MATCH:%d+%.%d+}| + {1:~ }| {MATCH:.*}| {MATCH:.*}| {1:~ }| @@ -1303,7 +1331,6 @@ describe('ui/ext_messages', function() {1:~ }| {1:~ }| {1:~ }| - {1:~ }| ]]) feed("<c-l>") @@ -1341,7 +1368,6 @@ describe('ui/ext_messages', function() | | | - | {MATCH:.*}| | Nvim is open source and freely distributable | @@ -1352,6 +1378,8 @@ describe('ui/ext_messages', function() type :q{5:<Enter>} to exit | type :help{5:<Enter>} for help | | + type :help news{5:<Enter>} to see changes in v{MATCH:%d+%.%d+}| + | {MATCH:.*}| {MATCH:.*}| | @@ -1359,7 +1387,6 @@ describe('ui/ext_messages', function() | | | - | ]], messages={ {content = { { "Press ENTER or type command to continue", 4 } }, kind = "return_prompt" } }} @@ -1432,7 +1459,6 @@ describe('ui/ext_messages', function() feed(":set mouse=a<cr>") meths.input_mouse('left', 'press', '', 0, 12, 10) poke_eventloop() - meths.input_mouse('left', 'drag', '', 0, 12, 10) meths.input_mouse('left', 'drag', '', 0, 11, 10) feed("<c-l>") feed(":set cmdheight<cr>") @@ -1477,7 +1503,7 @@ describe('ui/msg_puts_printf', function() screen = Screen.new(25, 5) screen:attach() - if iswin() then + if is_os('win') then if os.execute('chcp 932 > NUL 2>&1') ~= 0 then pending('missing japanese language features', function() end) return @@ -1488,7 +1514,7 @@ describe('ui/msg_puts_printf', function() if (exc_exec('lang ja_JP.UTF-8') ~= 0) then pending('Locale ja_JP.UTF-8 not supported', function() end) return - elseif helpers.isCI() then + elseif is_ci() then -- Fails non--Windows CI. Message catalog directory issue? pending('fails on unix CI', function() end) return @@ -2020,4 +2046,55 @@ aliquip ex ea commodo consequat.]]) | ]]} end) + + it('with cmdheight=0 does not crash with g<', function() + command('set cmdheight=0') + feed(':ls<cr>') + screen:expect{grid=[[ + | + {1:~ }| + {12: }| + :ls | + 1 %a "[No Name]" | + line 1 | + {4:Press ENTER or type command to cont}| + {4:inue}^ | + ]]} + + feed('<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + + feed('g<lt>') + screen:expect{grid=[[ + | + {1:~ }| + {12: }| + :ls | + 1 %a "[No Name]" | + line 1 | + {4:Press ENTER or type command to cont}| + {4:inue}^ | + ]]} + + feed('<cr>') + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]]} + end) end) diff --git a/test/functional/ui/mode_spec.lua b/test/functional/ui/mode_spec.lua index 9390f268b3..cf4eb034e0 100644 --- a/test/functional/ui/mode_spec.lua +++ b/test/functional/ui/mode_spec.lua @@ -17,6 +17,7 @@ describe('ui mode_change event', function() [1] = {bold=true, reverse=true}, [2] = {bold=true}, [3] = {reverse=true}, + [4] = {background=Screen.colors.Red, foreground=Screen.colors.White}, -- ErrorMsg }) end) @@ -43,6 +44,25 @@ describe('ui mode_change event', function() {0:~ }| | ]], mode="normal"} + + screen:try_resize(50, 4) + command('set nomodifiable') + + feed('c') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + | + ]], mode="operator"} + + feed('c') + screen:expect{grid=[[ + ^ | + {0:~ }| + {0:~ }| + {4:E21: Cannot make changes, 'modifiable' is off} | + ]], mode="normal"} end) it('works in insert mode', function() diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 9896b11218..f705678bd5 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -4,6 +4,7 @@ local clear, feed, meths = helpers.clear, helpers.feed, helpers.meths local insert, feed_command = helpers.insert, helpers.feed_command local eq, funcs = helpers.eq, helpers.funcs local command = helpers.command +local exec = helpers.exec describe('ui/mouse/input', function() local screen @@ -648,8 +649,10 @@ describe('ui/mouse/input', function() ]]} end) - it('two clicks will select the word and enter VISUAL', function() - feed('<LeftMouse><2,2><LeftMouse><2,2>') + it('two clicks will enter VISUAL and dragging selects words', function() + feed('<LeftMouse><2,2>') + feed('<LeftRelease><2,2>') + feed('<LeftMouse><2,2>') screen:expect([[ testing | mouse | @@ -657,10 +660,38 @@ describe('ui/mouse/input', function() {0:~ }| {2:-- VISUAL --} | ]]) + feed('<LeftDrag><0,1>') + screen:expect([[ + testing | + ^m{1:ouse} | + {1:support} and selection | + {0:~ }| + {2:-- VISUAL --} | + ]]) + feed('<LeftDrag><4,0>') + screen:expect([[ + ^t{1:esting} | + {1:mouse} | + {1:support} and selection | + {0:~ }| + {2:-- VISUAL --} | + ]]) + feed('<LeftDrag><14,2>') + screen:expect([[ + testing | + mouse | + {1:support and selectio}^n | + {0:~ }| + {2:-- VISUAL --} | + ]]) end) - it('three clicks will select the line and enter VISUAL LINE', function() - feed('<LeftMouse><2,2><LeftMouse><2,2><LeftMouse><2,2>') + it('three clicks will enter VISUAL LINE and dragging selects lines', function() + feed('<LeftMouse><2,2>') + feed('<LeftRelease><2,2>') + feed('<LeftMouse><2,2>') + feed('<LeftRelease><2,2>') + feed('<LeftMouse><2,2>') screen:expect([[ testing | mouse | @@ -668,10 +699,40 @@ describe('ui/mouse/input', function() {0:~ }| {2:-- VISUAL LINE --} | ]]) + feed('<LeftDrag><0,1>') + screen:expect([[ + testing | + ^m{1:ouse} | + {1:support and selection} | + {0:~ }| + {2:-- VISUAL LINE --} | + ]]) + feed('<LeftDrag><4,0>') + screen:expect([[ + {1:test}^i{1:ng} | + {1:mouse} | + {1:support and selection} | + {0:~ }| + {2:-- VISUAL LINE --} | + ]]) + feed('<LeftDrag><14,2>') + screen:expect([[ + testing | + mouse | + {1:support and se}^l{1:ection} | + {0:~ }| + {2:-- VISUAL LINE --} | + ]]) end) - it('four clicks will enter VISUAL BLOCK', function() - feed('<LeftMouse><2,2><LeftMouse><2,2><LeftMouse><2,2><LeftMouse><2,2>') + it('four clicks will enter VISUAL BLOCK and dragging selects blockwise', function() + feed('<LeftMouse><2,2>') + feed('<LeftRelease><2,2>') + feed('<LeftMouse><2,2>') + feed('<LeftRelease><2,2>') + feed('<LeftMouse><2,2>') + feed('<LeftRelease><2,2>') + feed('<LeftMouse><2,2>') screen:expect([[ testing | mouse | @@ -679,6 +740,30 @@ describe('ui/mouse/input', function() {0:~ }| {2:-- VISUAL BLOCK --} | ]]) + feed('<LeftDrag><0,1>') + screen:expect([[ + testing | + ^m{1:ou}se | + {1:sup}port and selection | + {0:~ }| + {2:-- 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 --} | + ]]) + feed('<LeftDrag><14,2>') + screen:expect([[ + testing | + mouse | + su{1:pport and se}^lection | + {0:~ }| + {2:-- VISUAL BLOCK --} | + ]]) end) it('right click extends visual selection to the clicked location', function() @@ -883,6 +968,49 @@ describe('ui/mouse/input', function() ]]) end) + it("'sidescrolloff' applies to horizontal scrolling", function() + command('set nowrap') + command('set sidescrolloff=4') + + feed("I <esc>020ib<esc>0") + screen:expect([[ + testing | + mouse | + ^bbbbbbbbbbbbbbbbbbbb supp| + {0:~ }| + | + ]]) + + meths.input_mouse('wheel', 'right', '', 0, 0, 27) + screen:expect([[ + g | + | + bbbb^bbbbbbbbbb support an| + {0:~ }| + | + ]]) + + -- window-local 'sidescrolloff' should override global value. #21162 + command('setlocal sidescrolloff=2') + feed('0') + screen:expect([[ + testing | + mouse | + ^bbbbbbbbbbbbbbbbbbbb supp| + {0:~ }| + | + ]]) + + meths.input_mouse('wheel', 'right', '', 0, 0, 27) + screen:expect([[ + g | + | + bb^bbbbbbbbbbbb support an| + {0:~ }| + | + ]]) + end) + describe('on concealed text', function() -- Helpful for reading the test expectations: -- :match Error /\^/ @@ -1585,9 +1713,151 @@ describe('ui/mouse/input', function() eq(0, meths.get_var('mouse_up2')) end) - it('feeding <MouseMove> does not use uninitialized memory #19480', function() + it('<MouseMove> is not translated into multiclicks and can be mapped', function() + meths.set_var('mouse_move', 0) + meths.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>') + meths.input_mouse('move', '', '', 0, 0, 0) + meths.input_mouse('move', '', '', 0, 0, 0) + eq(4, meths.get_var('mouse_move')) + eq(0, meths.get_var('mouse_move2')) + end) + + it('feeding <MouseMove> in Normal mode does not use uninitialized memory #19480', function() feed('<MouseMove>') helpers.poke_eventloop() helpers.assert_alive() end) + + it('mousemodel=popup_setpos', function() + screen:try_resize(80, 24) + exec([[ + 5new + call setline(1, ['the dish ran away with the spoon', + \ 'the cow jumped over the moon' ]) + + set mouse=a mousemodel=popup_setpos + + aunmenu PopUp + nmenu PopUp.foo :let g:menustr = 'foo'<CR> + nmenu PopUp.bar :let g:menustr = 'bar'<CR> + nmenu PopUp.baz :let g:menustr = 'baz'<CR> + vmenu PopUp.foo y:<C-U>let g:menustr = 'foo'<CR> + vmenu PopUp.bar y:<C-U>let g:menustr = 'bar'<CR> + vmenu PopUp.baz y:<C-U>let g:menustr = 'baz'<CR> + ]]) + + meths.win_set_cursor(0, {1, 0}) + meths.input_mouse('right', 'press', '', 0, 0, 4) + meths.input_mouse('right', 'release', '', 0, 0, 4) + feed('<Down><Down><CR>') + eq('bar', meths.get_var('menustr')) + eq({1, 4}, meths.win_get_cursor(0)) + + -- Test for right click in visual mode inside the selection + funcs.setreg('"', '') + meths.win_set_cursor(0, {1, 9}) + feed('vee') + meths.input_mouse('right', 'press', '', 0, 0, 11) + meths.input_mouse('right', 'release', '', 0, 0, 11) + feed('<Down><CR>') + eq({1, 9}, meths.win_get_cursor(0)) + eq('ran away', funcs.getreg('"')) + + -- Test for right click in visual mode right before the selection + funcs.setreg('"', '') + meths.win_set_cursor(0, {1, 9}) + feed('vee') + meths.input_mouse('right', 'press', '', 0, 0, 8) + meths.input_mouse('right', 'release', '', 0, 0, 8) + feed('<Down><CR>') + eq({1, 8}, meths.win_get_cursor(0)) + eq('', funcs.getreg('"')) + + -- Test for right click in visual mode right after the selection + funcs.setreg('"', '') + meths.win_set_cursor(0, {1, 9}) + feed('vee') + meths.input_mouse('right', 'press', '', 0, 0, 17) + meths.input_mouse('right', 'release', '', 0, 0, 17) + feed('<Down><CR>') + eq({1, 17}, meths.win_get_cursor(0)) + eq('', funcs.getreg('"')) + + -- Test for right click in block-wise visual mode inside the selection + funcs.setreg('"', '') + meths.win_set_cursor(0, {1, 15}) + feed('<C-V>j3l') + meths.input_mouse('right', 'press', '', 0, 1, 16) + meths.input_mouse('right', 'release', '', 0, 1, 16) + feed('<Down><CR>') + eq({1, 15}, meths.win_get_cursor(0)) + eq('\0224', funcs.getregtype('"')) + + -- Test for right click in block-wise visual mode outside the selection + funcs.setreg('"', '') + meths.win_set_cursor(0, {1, 15}) + feed('<C-V>j3l') + meths.input_mouse('right', 'press', '', 0, 1, 1) + meths.input_mouse('right', 'release', '', 0, 1, 1) + feed('<Down><CR>') + eq({2, 1}, meths.win_get_cursor(0)) + eq('v', funcs.getregtype('"')) + eq('', funcs.getreg('"')) + + -- Test for right click in line-wise visual mode inside the selection + funcs.setreg('"', '') + meths.win_set_cursor(0, {1, 15}) + feed('V') + meths.input_mouse('right', 'press', '', 0, 0, 9) + meths.input_mouse('right', 'release', '', 0, 0, 9) + feed('<Down><CR>') + eq({1, 0}, meths.win_get_cursor(0)) -- After yanking, the cursor goes to 1,1 + eq('V', funcs.getregtype('"')) + eq(1, #funcs.getreg('"', 1, true)) + + -- Test for right click in multi-line line-wise visual mode inside the selection + funcs.setreg('"', '') + meths.win_set_cursor(0, {1, 15}) + feed('Vj') + meths.input_mouse('right', 'press', '', 0, 1, 19) + meths.input_mouse('right', 'release', '', 0, 1, 19) + feed('<Down><CR>') + eq({1, 0}, meths.win_get_cursor(0)) -- After yanking, the cursor goes to 1,1 + eq('V', funcs.getregtype('"')) + eq(2, #funcs.getreg('"', 1, true)) + + -- Test for right click in line-wise visual mode outside the selection + funcs.setreg('"', '') + meths.win_set_cursor(0, {1, 15}) + feed('V') + meths.input_mouse('right', 'press', '', 0, 1, 9) + meths.input_mouse('right', 'release', '', 0, 1, 9) + feed('<Down><CR>') + eq({2, 9}, meths.win_get_cursor(0)) + eq('', funcs.getreg('"')) + + -- Try clicking on the status line + funcs.setreg('"', '') + meths.win_set_cursor(0, {1, 9}) + feed('vee') + meths.input_mouse('right', 'press', '', 0, 5, 1) + meths.input_mouse('right', 'release', '', 0, 5, 1) + feed('<Down><CR>') + eq({1, 9}, meths.win_get_cursor(0)) + eq('ran away', funcs.getreg('"')) + + -- Try clicking outside the window + funcs.setreg('"', '') + meths.win_set_cursor(0, {2, 1}) + feed('vee') + meths.input_mouse('right', 'press', '', 0, 6, 1) + meths.input_mouse('right', 'release', '', 0, 6, 1) + feed('<Down><CR>') + eq(2, funcs.winnr()) + eq('', funcs.getreg('"')) + end) end) diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index b30aa67fd3..71adeb42a4 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -3,7 +3,9 @@ local Screen = require('test.functional.ui.screen') local clear = helpers.clear local feed, command, insert = helpers.feed, helpers.command, helpers.insert local eq = helpers.eq +local funcs = helpers.funcs local meths = helpers.meths +local curwin = helpers.curwin local poke_eventloop = helpers.poke_eventloop @@ -871,6 +873,15 @@ describe('ext_multigrid', function() before_each(function() screen:try_resize_grid(2, 60, 20) end) + + it('winwidth() winheight() getwininfo() return inner width and height #19743', function() + eq(60, funcs.winwidth(0)) + eq(20, funcs.winheight(0)) + local win_info = funcs.getwininfo(curwin().id)[1] + eq(60, win_info.width) + eq(20, win_info.height) + end) + it('gets written till grid width', function() insert(('a'):rep(60).."\n") @@ -2370,8 +2381,7 @@ describe('ext_multigrid', function() end) it('with winbar', function() - command 'split' - command 'setlocal winbar=very\\ bar' + command('split') screen:expect{grid=[[ ## grid 1 [4:-----------------------------------------------------]| @@ -2397,16 +2407,100 @@ describe('ext_multigrid', function() ## grid 3 | ## grid 4 - {7:very bar }| ^ | {1:~ }| {1:~ }| {1:~ }| {1:~ }| + {1:~ }| + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + + -- XXX: hack to get notifications. Could use next_msg() also. + local orig_handle_win_pos = screen._handle_win_pos + local win_pos = {} + function screen._handle_win_pos(self, grid, win, startrow, startcol, width, height) + table.insert(win_pos, {grid, win, startrow, startcol, width, height}) + orig_handle_win_pos(self, grid, win, startrow, startcol, width, height) + end + + command('setlocal winbar=very%=bar') + screen:expect{grid=[[ + ## grid 1 + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] }| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {12:[No Name] }| + [3:-----------------------------------------------------]| + ## grid 2 + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + {7:very bar}| + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ]], win_viewport={ + [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; + }} + eq({}, win_pos) + + command('setlocal winbar=') + screen:expect{grid=[[ + ## grid 1 + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + [4:-----------------------------------------------------]| + {11:[No Name] }| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + [2:-----------------------------------------------------]| + {12:[No Name] }| + [3:-----------------------------------------------------]| + ## grid 2 + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + | + ## grid 4 + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| ]], win_viewport={ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}; }} + eq({}, win_pos) end) it('with winbar dragging statusline with mouse works correctly', function() diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index 8d7c404637..9d20229ce1 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -19,10 +19,12 @@ describe('UI receives option updates', function() linespace=0, pumblend=0, mousefocus=false, + mousemoveevent=false, showtabline=1, termguicolors=false, ttimeout=true, ttimeoutlen=50, + verbose=0, ext_cmdline=false, ext_popupmenu=false, ext_tabline=false, @@ -131,6 +133,12 @@ describe('UI receives option updates', function() eq(expected, screen.options) end) + command("set mousemoveevent") + expected.mousemoveevent = true + screen:expect(function() + eq(expected, screen.options) + end) + command("set nottimeout") expected.ttimeout = false screen:expect(function() @@ -187,7 +195,7 @@ end) describe('UI can set terminal option', function() local screen before_each(function() - -- by default we implicity "--cmd 'set bg=light'" which ruins everything + -- by default we implicitly "--cmd 'set bg=light'" which ruins everything clear{args_rm={'--cmd'}} screen = Screen.new(20,5) end) diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index 9bb067ed8e..223844405e 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -6,13 +6,14 @@ local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdi local eq = helpers.eq local feed = helpers.feed local feed_command = helpers.feed_command -local iswin = helpers.iswin local clear = helpers.clear local command = helpers.command local testprg = helpers.testprg local nvim_dir = helpers.nvim_dir local has_powershell = helpers.has_powershell local set_shell_powershell = helpers.set_shell_powershell +local skip = helpers.skip +local is_os = helpers.is_os describe("shell command :!", function() local screen @@ -36,7 +37,7 @@ describe("shell command :!", function() end) it("displays output without LF/EOF. #4646 #4569 #3772", function() - if helpers.pending_win32(pending) then return end + skip(is_os('win')) -- NOTE: We use a child nvim (within a :term buffer) -- to avoid triggering a UI flush. child_session.feed_data(":!printf foo; sleep 200\n") @@ -52,9 +53,7 @@ describe("shell command :!", function() end) it("throttles shell-command output greater than ~10KB", function() - if 'openbsd' == helpers.uname() then - pending('FIXME #10804') - end + skip(is_os('openbsd'), 'FIXME #10804') child_session.feed_data((":!%s REP 30001 foo\n"):format(testprg('shell-test'))) -- If we observe any line starting with a dot, then throttling occurred. @@ -96,9 +95,7 @@ describe("shell command :!", function() end) it('handles control codes', function() - if iswin() then - pending('missing printf') - end + skip(is_os('win'), 'missing printf') local screen = Screen.new(50, 4) screen:set_default_attr_ids { [1] = {bold = true, reverse = true}; @@ -173,10 +170,10 @@ describe("shell command :!", function() end) it("doesn't truncate Last line of shell output #3269", function() - command(helpers.iswin() + command(is_os('win') and [[nnoremap <silent>\l :!dir /b bang_filter_spec<cr>]] or [[nnoremap <silent>\l :!ls bang_filter_spec<cr>]]) - local result = (helpers.iswin() + local result = (is_os('win') and [[:!dir /b bang_filter_spec]] or [[:!ls bang_filter_spec ]]) feed([[\l]]) @@ -215,7 +212,7 @@ describe("shell command :!", function() it('handles multibyte sequences split over buffer boundaries', function() command('cd '..nvim_dir) - local cmd = iswin() and '!shell-test UTF-8 ' or '!./shell-test UTF-8' + local cmd = is_os('win') and '!shell-test UTF-8 ' or '!./shell-test UTF-8' feed_command(cmd) -- Note: only the first example of split composed char works screen:expect([[ @@ -265,7 +262,7 @@ describe("shell command :!", function() | Press ENTER or type command to continue^ | ]]) - if iswin() then + if is_os('win') then feed_command([[!& 'cmd.exe' /c 'echo $a']]) screen:expect([[ :!& 'cmd.exe' /c 'echo $a' | diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index e11cd1e859..c681453294 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -259,174 +259,339 @@ describe('ui/ext_popupmenu', function() {2:-- INSERT --} | ]]) - command('imap <f1> <cmd>call nvim_select_popupmenu_item(2,v:true,v:false,{})<cr>') - command('imap <f2> <cmd>call nvim_select_popupmenu_item(-1,v:false,v:false,{})<cr>') - command('imap <f3> <cmd>call nvim_select_popupmenu_item(1,v:false,v:true,{})<cr>') - feed('<C-r>=TestComplete()<CR>') - screen:expect{grid=[[ + command('set wildmenu') + command('set wildoptions=pum') + local expected_wildpum = { + { "define", "", "", "" }, + { "jump", "", "", "" }, + { "list", "", "", "" }, + { "place", "", "", "" }, + { "undefine", "", "", "" }, + { "unplace", "", "", "" }, + } + feed('<Esc>:sign <Tab>') + screen:expect({grid = [[ + | | - foo^ | {1:~ }| {1:~ }| {1:~ }| {1:~ }| {1:~ }| - {2:-- INSERT --} | - ]], popupmenu={ - items=expected, - pos=0, - anchor={1,1,0}, - }} + :sign define^ | + ]], popupmenu = { + items = expected_wildpum, + pos = 0, + anchor = { 1, 7, 6 }, + }}) - feed('<f1>') - screen:expect{grid=[[ + meths.select_popupmenu_item(-1, true, false, {}) + screen:expect({grid = [[ + | | - spam^ | {1:~ }| {1:~ }| {1:~ }| {1:~ }| {1:~ }| - {2:-- INSERT --} | - ]], popupmenu={ - items=expected, - pos=2, - anchor={1,1,0}, - }} + :sign ^ | + ]], popupmenu = { + items = expected_wildpum, + pos = -1, + anchor = { 1, 7, 6 }, + }}) - feed('<f2>') - screen:expect{grid=[[ + meths.select_popupmenu_item(5, true, false, {}) + screen:expect({grid = [[ + | | - spam^ | {1:~ }| {1:~ }| {1:~ }| {1:~ }| {1:~ }| - {2:-- INSERT --} | - ]], popupmenu={ - items=expected, - pos=-1, - anchor={1,1,0}, - }} + :sign unplace^ | + ]], popupmenu = { + items = expected_wildpum, + pos = 5, + anchor = { 1, 7, 6 }, + }}) - feed('<f3>') - screen:expect([[ + meths.select_popupmenu_item(-1, true, true, {}) + screen:expect({grid = [[ + | | - bar^ | {1:~ }| {1:~ }| {1:~ }| {1:~ }| {1:~ }| - {2:-- INSERT --} | - ]]) + :sign ^ | + ]]}) - -- also should work for builtin popupmenu - screen:set_option('ext_popupmenu', false) - feed('<C-r>=TestComplete()<CR>') - screen:expect([[ + feed('<Tab>') + screen:expect({grid = [[ | - foo^ | - {6:fo x the foo }{1: }| - {7:bar }{1: }| - {7:spam }{1: }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) - - feed('<f1>') - screen:expect([[ | - spam^ | - {7:fo x the foo }{1: }| - {7:bar }{1: }| - {6:spam }{1: }| {1:~ }| {1:~ }| - {2:-- INSERT --} | - ]]) - - feed('<f2>') - screen:expect([[ - | - spam^ | - {7:fo x the foo }{1: }| - {7:bar }{1: }| - {7:spam }{1: }| {1:~ }| {1:~ }| - {2:-- INSERT --} | - ]]) + {1:~ }| + :sign define^ | + ]], popupmenu = { + items = expected_wildpum, + pos = 0, + anchor = { 1, 7, 6 }, + }}) - feed('<f3>') - screen:expect([[ + meths.select_popupmenu_item(5, true, true, {}) + screen:expect({grid = [[ + | | - bar^ | {1:~ }| {1:~ }| {1:~ }| {1:~ }| {1:~ }| - {2:-- INSERT --} | - ]]) + :sign unplace^ | + ]]}) - command('iunmap <f1>') - command('iunmap <f2>') - command('iunmap <f3>') - exec_lua([[ - vim.keymap.set('i', '<f1>', function() vim.api.nvim_select_popupmenu_item(2, true, false, {}) end) - vim.keymap.set('i', '<f2>', function() vim.api.nvim_select_popupmenu_item(-1, false, false, {}) end) - vim.keymap.set('i', '<f3>', function() vim.api.nvim_select_popupmenu_item(1, false, true, {}) end) - ]]) - feed('<C-r>=TestComplete()<CR>') - screen:expect([[ - | - foo^ | - {6:fo x the foo }{1: }| - {7:bar }{1: }| - {7:spam }{1: }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) + local function test_pum_select_mappings() + screen:set_option('ext_popupmenu', true) + feed('<Esc>A<C-r>=TestComplete()<CR>') + screen:expect{grid=[[ + | + foo^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]], popupmenu={ + items=expected, + pos=0, + anchor={1,1,0}, + }} - feed('<f1>') - screen:expect([[ - | - spam^ | - {7:fo x the foo }{1: }| - {7:bar }{1: }| - {6:spam }{1: }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) + feed('<f1>') + screen:expect{grid=[[ + | + spam^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]], popupmenu={ + items=expected, + pos=2, + anchor={1,1,0}, + }} - feed('<f2>') - screen:expect([[ - | - spam^ | - {7:fo x the foo }{1: }| - {7:bar }{1: }| - {7:spam }{1: }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | - ]]) + feed('<f2>') + screen:expect{grid=[[ + | + spam^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]], popupmenu={ + items=expected, + pos=-1, + anchor={1,1,0}, + }} - feed('<f3>') - screen:expect([[ - | - bar^ | - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {1:~ }| - {2:-- INSERT --} | + feed('<f3>') + screen:expect([[ + | + bar^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<Esc>:sign <Tab>') + screen:expect({grid = [[ + | + bar | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign define^ | + ]], popupmenu = { + items = expected_wildpum, + pos = 0, + anchor = { 1, 7, 6 }, + }}) + + feed('<f1>') + screen:expect({grid = [[ + | + bar | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign list^ | + ]], popupmenu = { + items = expected_wildpum, + pos = 2, + anchor = { 1, 7, 6 }, + }}) + + feed('<f2>') + screen:expect({grid = [[ + | + bar | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign ^ | + ]], popupmenu = { + items = expected_wildpum, + pos = -1, + anchor = { 1, 7, 6 }, + }}) + + feed('<f3>') + screen:expect({grid = [[ + | + bar | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign jump^ | + ]]}) + + -- also should work for builtin popupmenu + screen:set_option('ext_popupmenu', false) + feed('<Esc>A<C-r>=TestComplete()<CR>') + screen:expect([[ + | + foo^ | + {6:fo x the foo }{1: }| + {7:bar }{1: }| + {7:spam }{1: }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<f1>') + screen:expect([[ + | + spam^ | + {7:fo x the foo }{1: }| + {7:bar }{1: }| + {6:spam }{1: }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<f2>') + screen:expect([[ + | + spam^ | + {7:fo x the foo }{1: }| + {7:bar }{1: }| + {7:spam }{1: }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]]) + + feed('<f3>') + screen:expect([[ + | + bar^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- 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: }| + :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: }| + :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: }| + :sign ^ | + ]]) + + feed('<f3>') + screen:expect([[ + | + bar | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :sign jump^ | + ]]) + end + + command('map! <f1> <cmd>call nvim_select_popupmenu_item(2,v:true,v:false,{})<cr>') + command('map! <f2> <cmd>call nvim_select_popupmenu_item(-1,v:false,v:false,{})<cr>') + command('map! <f3> <cmd>call nvim_select_popupmenu_item(1,v:false,v:true,{})<cr>') + test_pum_select_mappings() + + command('unmap! <f1>') + command('unmap! <f2>') + command('unmap! <f3>') + exec_lua([[ + vim.keymap.set('!', '<f1>', function() vim.api.nvim_select_popupmenu_item(2, true, false, {}) end) + vim.keymap.set('!', '<f2>', function() vim.api.nvim_select_popupmenu_item(-1, false, false, {}) end) + vim.keymap.set('!', '<f3>', function() vim.api.nvim_select_popupmenu_item(1, false, true, {}) end) ]]) + test_pum_select_mappings() feed('<esc>ddiaa bb cc<cr>') feed('<c-x><c-n>') @@ -780,6 +945,82 @@ describe('ui/ext_popupmenu', function() }} end) + + it('does not interfere with mousemodel=popup', function() + exec([[ + set mouse=a mousemodel=popup + + aunmenu PopUp + menu PopUp.foo :let g:menustr = 'foo'<CR> + menu PopUp.bar :let g:menustr = 'bar'<CR> + menu PopUp.baz :let g:menustr = 'baz'<CR> + ]]) + feed('o<C-r>=TestComplete()<CR>') + screen:expect{grid=[[ + | + foo^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]], popupmenu={ + items=expected, + pos=0, + anchor={1,1,0}, + }} + + feed('<c-p>') + screen:expect{grid=[[ + | + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- INSERT --} | + ]], popupmenu={ + items=expected, + pos=-1, + anchor={1,1,0}, + }} + + feed('<esc>') + screen:expect{grid=[[ + | + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]} + feed('<RightMouse><0,0>') + screen:expect([[ + | + {7:^foo } | + {7:bar }{1: }| + {7:baz }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + feed('<esc>') + screen:expect([[ + | + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end) end) @@ -802,6 +1043,8 @@ describe('builtin popupmenu', function() [4] = {bold = true, reverse = true}, [5] = {bold = true, foreground = Screen.colors.SeaGreen}, [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [7] = {background = Screen.colors.Yellow}, -- Search + [8] = {foreground = Screen.colors.Red}, }) end) @@ -949,6 +1192,66 @@ describe('builtin popupmenu', function() ]]) end) + -- oldtest: Test_pum_with_preview_win() + it('preview window opened during completion', function() + exec([[ + funct Omni_test(findstart, base) + if a:findstart + return col(".") - 1 + endif + return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}] + endfunc + set omnifunc=Omni_test + set completeopt+=longest + ]]) + feed('Gi<C-X><C-O>') + screen:expect([[ + ^ | + {n:one }{1: }| + {n:two }{1: }| + {n:three }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:-- }{8:Back at original} | + ]]) + feed('<C-N>') + screen:expect([[ + 1info | + | + {1:~ }| + {3:[Scratch] [Preview] }| + one^ | + {s:one }{1: }| + {n:two }{1: }| + {n:three }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {4:[No Name] [+] }| + {2:-- }{5:match 1 of 3} | + ]]) + end) + it('with vsplits', function() insert('aaa aab aac\n') feed(':vsplit<cr>') @@ -1990,6 +2293,22 @@ describe('builtin popupmenu', function() efine unplace^ | ]]) + -- Pressing <Left> after that should move the cursor + feed('<Left>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {4: }| + :sign define jump list place und| + efine unplac^e | + ]]) + feed('<End>') + -- Pressing <C-D> when the popup menu is displayed should remove the popup -- menu feed('<C-U>sign <Tab><C-D>') @@ -2206,8 +2525,130 @@ describe('builtin popupmenu', function() {1:~ }{n: xyz }{1: }| :e あいう/123^ | ]]) + feed('<Esc>') - feed('<esc>') + -- Pressing <PageDown> should scroll the menu downward + feed(':sign <Tab><PageDown>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{s: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign undefine^ | + ]]) + feed('<PageDown>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{s: unplace }{1: }| + :sign unplace^ | + ]]) + feed('<PageDown>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign ^ | + ]]) + feed('<PageDown>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{s: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign define^ | + ]]) + feed('<C-U>sign <Tab><Right><Right><PageDown>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{s: unplace }{1: }| + :sign unplace^ | + ]]) + + -- Pressing <PageUp> should scroll the menu upward + feed('<C-U>sign <Tab><PageUp>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign ^ | + ]]) + feed('<PageUp>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{s: unplace }{1: }| + :sign unplace^ | + ]]) + feed('<PageUp>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{n: define }{1: }| + {1:~ }{s: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign jump^ | + ]]) + feed('<PageUp>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{s: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign define^ | + ]]) + + feed('<Esc>') -- check positioning with multibyte char in pattern command("e långfile1") @@ -2304,7 +2745,7 @@ describe('builtin popupmenu', function() ]]) end) - it('wildoptions=pum with scrolled messages ', function() + it('wildoptions=pum with scrolled messages', function() screen:try_resize(40,10) command('set wildmenu') command('set wildoptions=pum') @@ -2401,6 +2842,49 @@ describe('builtin popupmenu', function() ]]} end) + it('wildoptions=pum with a wrapped line in buffer vim-patch:8.2.4655', function() + screen:try_resize(32, 10) + meths.buf_set_lines(0, 0, -1, true, { ('a'):rep(100) }) + command('set wildoptions+=pum') + feed('$') + feed(':sign <Tab>') + screen:expect([[ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + aaaa {s: define } | + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign define^ | + ]]) + end) + + -- oldtest: Test_wildmenu_pum_clear_entries() + it('wildoptions=pum when using Ctrl-E as wildchar vim-patch:9.0.1030', function() + screen:try_resize(30, 10) + exec([[ + set wildoptions=pum + set wildchar=<C-E> + ]]) + feed(':sign <C-E><C-E>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }{s: define }{1: }| + {1:~ }{n: jump }{1: }| + {1:~ }{n: list }{1: }| + {1:~ }{n: place }{1: }| + {1:~ }{n: undefine }{1: }| + {1:~ }{n: unplace }{1: }| + :sign define^ | + ]]) + assert_alive() + end) + it("'pumblend' RGB-color", function() screen:try_resize(60,14) screen:set_default_attr_ids({ @@ -2739,7 +3223,7 @@ describe('builtin popupmenu', function() menu PopUp.bar :let g:menustr = 'bar'<CR> menu PopUp.baz :let g:menustr = 'baz'<CR> ]]) - meths.input_mouse('right', 'press', '', 0, 0, 4) + feed('<RightMouse><4,0>') screen:expect([[ ^popup menu test | {1:~ }{n: foo }{1: }| @@ -2776,7 +3260,7 @@ describe('builtin popupmenu', function() :let g:menustr = 'bar' | ]]) eq('bar', meths.get_var('menustr')) - meths.input_mouse('right', 'press', '', 0, 1, 20) + feed('<RightMouse><20,1>') screen:expect([[ ^popup menu test | {1:~ }| @@ -2785,7 +3269,7 @@ describe('builtin popupmenu', function() {1:~ }{n: baz }{1: }| :let g:menustr = 'bar' | ]]) - meths.input_mouse('left', 'press', '', 0, 4, 22) + feed('<LeftMouse><22,4>') screen:expect([[ ^popup menu test | {1:~ }| @@ -2795,7 +3279,7 @@ describe('builtin popupmenu', function() :let g:menustr = 'baz' | ]]) eq('baz', meths.get_var('menustr')) - meths.input_mouse('right', 'press', '', 0, 0, 4) + feed('<RightMouse><4,0>') screen:expect([[ ^popup menu test | {1:~ }{n: foo }{1: }| @@ -2804,7 +3288,7 @@ describe('builtin popupmenu', function() {1:~ }| :let g:menustr = 'baz' | ]]) - meths.input_mouse('right', 'drag', '', 0, 3, 6) + feed('<RightDrag><6,3>') screen:expect([[ ^popup menu test | {1:~ }{n: foo }{1: }| @@ -2813,7 +3297,7 @@ describe('builtin popupmenu', function() {1:~ }| :let g:menustr = 'baz' | ]]) - meths.input_mouse('right', 'release', '', 0, 1, 6) + feed('<RightRelease><6,1>') screen:expect([[ ^popup menu test | {1:~ }| @@ -2823,6 +3307,188 @@ describe('builtin popupmenu', function() :let g:menustr = 'foo' | ]]) eq('foo', meths.get_var('menustr')) + eq(false, screen.options.mousemoveevent) + feed('<RightMouse><4,0>') + screen:expect([[ + ^popup menu test | + {1:~ }{n: foo }{1: }| + {1:~ }{n: bar }{1: }| + {1:~ }{n: baz }{1: }| + {1:~ }| + :let g:menustr = 'foo' | + ]]) + eq(true, screen.options.mousemoveevent) + feed('<MouseMove><6,3>') + screen:expect([[ + ^popup menu test | + {1:~ }{n: foo }{1: }| + {1:~ }{n: bar }{1: }| + {1:~ }{s: baz }{1: }| + {1:~ }| + :let g:menustr = 'foo' | + ]]) + eq(true, screen.options.mousemoveevent) + feed('<LeftMouse><6,2>') + screen:expect([[ + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :let g:menustr = 'bar' | + ]]) + eq(false, screen.options.mousemoveevent) + eq('bar', meths.get_var('menustr')) + end) + + -- oldtest: Test_popup_command_dump() + it(':popup command', function() + exec([[ + func ChangeMenu() + aunmenu PopUp.&Paste + nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"<CR> + echomsg 'changed' + return "\<Ignore>" + endfunc + + let lines =<< trim END + one two three four five + and one two Xthree four five + one more two three four five + END + call setline(1, lines) + + aunmenu * + source $VIMRUNTIME/menu.vim + ]]) + feed('/X<CR>:popup PopUp<CR>') + screen:expect([[ + one two three four five | + and one two {7:^X}three four five | + one more tw{n: Undo } | + {1:~ }{n: }{1: }| + {1:~ }{n: Paste }{1: }| + {1:~ }{n: }{1: }| + {1:~ }{n: Select Word }{1: }| + {1:~ }{n: Select Sentence }{1: }| + {1:~ }{n: Select Paragraph }{1: }| + {1:~ }{n: Select Line }{1: }| + {1:~ }{n: Select Block }{1: }| + {1:~ }{n: Select All }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :popup PopUp | + ]]) + + -- go to the Paste entry in the menu + feed('jj') + screen:expect([[ + one two three four five | + and one two {7:^X}three four five | + one more tw{n: Undo } | + {1:~ }{n: }{1: }| + {1:~ }{s: Paste }{1: }| + {1:~ }{n: }{1: }| + {1:~ }{n: Select Word }{1: }| + {1:~ }{n: Select Sentence }{1: }| + {1:~ }{n: Select Paragraph }{1: }| + {1:~ }{n: Select Line }{1: }| + {1:~ }{n: Select Block }{1: }| + {1:~ }{n: Select All }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :popup PopUp | + ]]) + + -- Select a word + feed('j') + screen:expect([[ + one two three four five | + and one two {7:^X}three four five | + one more tw{n: Undo } | + {1:~ }{n: }{1: }| + {1:~ }{n: Paste }{1: }| + {1:~ }{n: }{1: }| + {1:~ }{s: Select Word }{1: }| + {1:~ }{n: Select Sentence }{1: }| + {1:~ }{n: Select Paragraph }{1: }| + {1:~ }{n: Select Line }{1: }| + {1:~ }{n: Select Block }{1: }| + {1:~ }{n: Select All }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + :popup PopUp | + ]]) + + feed('<Esc>') + + -- Set an <expr> mapping to change a menu entry while it's displayed. + -- The text should not change but the command does. + -- Also verify that "changed" shows up, which means the mapping triggered. + command('nnoremap <expr> <F2> ChangeMenu()') + feed('/X<CR>:popup PopUp<CR><F2>') + screen:expect([[ + one two three four five | + and one two {7:^X}three four five | + one more tw{n: Undo } | + {1:~ }{n: }{1: }| + {1:~ }{n: Paste }{1: }| + {1:~ }{n: }{1: }| + {1:~ }{n: Select Word }{1: }| + {1:~ }{n: Select Sentence }{1: }| + {1:~ }{n: Select Paragraph }{1: }| + {1:~ }{n: Select Line }{1: }| + {1:~ }{n: Select Block }{1: }| + {1:~ }{n: Select All }{1: }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + changed | + ]]) + + -- Select the Paste entry, executes the changed menu item. + feed('jj<CR>') + screen:expect([[ + one two three four five | + and one two {7:^X}three four five | + one more two three four five | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + pasted | + ]]) end) end) @@ -3031,5 +3697,72 @@ describe('builtin popupmenu with ui/ext_multigrid', function() :let g:menustr = 'foo' | ]]}) eq('foo', meths.get_var('menustr')) + eq(false, screen.options.mousemoveevent) + meths.input_mouse('right', 'press', '', 2, 0, 4) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'foo' | + ## grid 4 + {n: foo }| + {n: bar }| + {n: baz }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}}) + eq(true, screen.options.mousemoveevent) + meths.input_mouse('move', '', '', 2, 3, 6) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'foo' | + ## grid 4 + {n: foo }| + {n: bar }| + {s: baz }| + ]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 3, false, 100}}}) + eq(true, screen.options.mousemoveevent) + meths.input_mouse('left', 'press', '', 2, 2, 6) + screen:expect({grid=[[ + ## grid 1 + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [2:--------------------------------]| + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ## grid 3 + :let g:menustr = 'bar' | + ]]}) + eq(false, screen.options.mousemoveevent) + eq('bar', meths.get_var('menustr')) end) end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 6ee9e7b393..3b9cce0e6f 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -101,13 +101,10 @@ end local default_screen_timeout = default_timeout_factor * 3500 -do - local spawn, nvim_prog = helpers.spawn, helpers.nvim_prog - local session = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '-N', '--embed'}) +function Screen._init_colors(session) local status, rv = session:request('nvim_get_color_map') if not status then - print('failed to get color map') - os.exit(1) + error('failed to get color map') end local colors = rv local colornames = {} @@ -116,12 +113,15 @@ do -- this is just a helper to get any canonical name of a color colornames[rgb] = name end - session:close() Screen.colors = colors Screen.colornames = colornames end function Screen.new(width, height) + if not Screen.colors then + Screen._init_colors(get_session()) + end + if not width then width = 53 end @@ -519,7 +519,7 @@ function Screen:_wait(check, flags) end assert(timeout >= minimal_timeout) - local did_miminal_timeout = false + local did_minimal_timeout = false local function notification_cb(method, args) assert(method == 'redraw', string.format( @@ -536,7 +536,7 @@ function Screen:_wait(check, flags) if not err then success_seen = true - if did_miminal_timeout then + if did_minimal_timeout then self._session:stop() end elseif success_seen and #args > 0 then @@ -558,7 +558,7 @@ function Screen:_wait(check, flags) end if not success_seen and not eof then - did_miminal_timeout = true + did_minimal_timeout = true eof = run_session(self._session, flags.request_cb, notification_cb, nil, timeout-minimal_timeout) end @@ -769,6 +769,7 @@ end function Screen:_handle_grid_cursor_goto(grid, row, col) self._cursor.grid = grid + assert(row >= 0 and col >= 0) self._cursor.row = row + 1 self._cursor.col = col + 1 end @@ -1549,7 +1550,8 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id) attr_state.modified = true return id end - return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1]) + local kind = self._options.rgb and 1 or 2 + return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][kind]) else if self:_equal_attrs(attrs, {}) then -- ignore this attrs diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 6c872e52d3..3bd2289a73 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -5,8 +5,8 @@ local feed, command = helpers.feed, helpers.command local insert = helpers.insert local eq = helpers.eq local eval = helpers.eval -local iswin = helpers.iswin local funcs, meths, exec_lua = helpers.funcs, helpers.meths, helpers.exec_lua +local is_os = helpers.is_os describe('screen', function() local screen @@ -128,18 +128,18 @@ local function screen_tests(linegrid) end) it('has correct default title with named file', function() - local expected = (iswin() and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM') + local expected = (is_os('win') and 'myfile (C:\\mydir) - NVIM' or 'myfile (/mydir) - NVIM') command('set title') - command(iswin() and 'file C:\\mydir\\myfile' or 'file /mydir/myfile') + command(is_os('win') and 'file C:\\mydir\\myfile' or 'file /mydir/myfile') screen:expect(function() eq(expected, screen.title) end) end) describe('is not changed by', function() - local file1 = iswin() and 'C:\\mydir\\myfile1' or '/mydir/myfile1' - local file2 = iswin() and 'C:\\mydir\\myfile2' or '/mydir/myfile2' - local expected = (iswin() and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM') + local file1 = is_os('win') and 'C:\\mydir\\myfile1' or '/mydir/myfile1' + local file2 = is_os('win') and 'C:\\mydir\\myfile2' or '/mydir/myfile2' + local expected = (is_os('win') and 'myfile1 (C:\\mydir) - NVIM' or 'myfile1 (/mydir) - NVIM') local buf2 before_each(function() @@ -682,30 +682,7 @@ local function screen_tests(linegrid) ]]) end) - it('execute command with multi-line output without msgsep', function() - command("set display-=msgsep") - feed(':ls<cr>') - screen:expect([[ - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - :ls | - 1 %a "[No Name]" line 1 | - {7:Press ENTER or type command to continue}^ | - ]]) - feed('<cr>') -- skip the "Press ENTER..." state or tests will hang - end) - - it('execute command with multi-line output and with msgsep', function() - command("set display+=msgsep") + it('execute command with multi-line output', function() feed(':ls<cr>') screen:expect([[ | @@ -917,6 +894,31 @@ local function screen_tests(linegrid) :ls^ | ]]) end) + + it('VimResized autocommand does not cause invalid UI events #20692 #20759', function() + feed('<Esc>') + command([[autocmd VimResized * redrawtabline]]) + command([[autocmd VimResized * lua vim.api.nvim_echo({ { 'Hello' } }, false, {})]]) + command([[autocmd VimResized * let g:echospace = v:echospace]]) + meths.set_option('showtabline', 2) + screen:expect([[ + {2: + [No Name] }{3: }| + resiz^e | + {0:~ }| + {0:~ }| + | + ]]) + screen:try_resize(30, 6) + screen:expect([[ + {2: + [No Name] }{3: }| + resiz^e | + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + eq(29, meths.get_var('echospace')) + end) end) describe('press enter', function() @@ -1051,38 +1053,35 @@ describe('Screen default colors', function() end) end) - -describe('screen with msgsep deactivated on startup', function() - local screen - - before_each(function() - clear('--cmd', 'set display-=msgsep') - screen = Screen.new() - screen:attach() - screen:set_default_attr_ids { - [0] = {bold=true, foreground=255}; - [7] = {bold = true, foreground = Screen.colors.SeaGreen}; - } - end) - - it('execute command with multi-line output', function() - feed ':ls<cr>' - screen:expect([[ - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - {0:~ }| - :ls | - 1 %a "[No Name]" line 1 | - {7:Press ENTER or type command to continue}^ | - ]]) - feed '<cr>' -- skip the "Press ENTER..." state or tests will hang - 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, meths.get_option('lines')) + eq(99, meths.get_option('window')) + eq(99, meths.win_get_height(0)) + feed('1000o<Esc>') + eq(903, funcs.line('w0')) + feed('<C-B>') + eq(806, funcs.line('w0')) + feed('<C-B>') + eq(709, funcs.line('w0')) + feed('<C-F>') + eq(806, funcs.line('w0')) + feed('<C-F>') + eq(903, funcs.line('w0')) + feed('G') + screen:try_resize(50, 50) + eq(50, meths.get_option('lines')) + eq(49, meths.get_option('window')) + eq(49, meths.win_get_height(0)) + eq(953, funcs.line('w0')) + feed('<C-B>') + eq(906, funcs.line('w0')) + feed('<C-B>') + eq(859, funcs.line('w0')) + feed('<C-F>') + eq(906, funcs.line('w0')) + feed('<C-F>') + eq(953, funcs.line('w0')) end) diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua index c5c88323a2..18bbb56a61 100644 --- a/test/functional/ui/searchhl_spec.lua +++ b/test/functional/ui/searchhl_spec.lua @@ -221,10 +221,10 @@ describe('search highlighting', function() feed('gg/foo\\nbar<CR>') screen:expect([[ one | - {2:^foo} | + {2:^foo } | {2:bar} | baz | - {1:foo} | + {1:foo } | {1:bar} | /foo\nbar | ]]) @@ -232,20 +232,20 @@ describe('search highlighting', function() feed('gg/efg\\nhij<CR>') screen:expect([[ --- | - abcd{2:^efg} | + abcd{2:^efg } | {2:hij}kl | --- | - abcd{1:efg} | + abcd{1:efg } | {1:hij}kl | /efg\nhij | ]]) feed('n') screen:expect([[ --- | - abcd{1:efg} | + abcd{1:efg } | {1:hij}kl | --- | - abcd{2:^efg} | + abcd{2:^efg } | {2:hij}kl | /efg\nhij | ]]) @@ -548,9 +548,9 @@ describe('search highlighting', function() feed('/line\\na<cr>') screen:expect([[ | - a repeated {2:^line} | - {2:a} repeated {2:line} | - {2:a} repeated {2:line} | + a repeated {2:^line } | + {2:a} repeated {2:line } | + {2:a} repeated {2:line } | {2:a} repeated line | {1:~ }| {4:search hit BOTTOM, continuing at TOP} | @@ -560,9 +560,9 @@ describe('search highlighting', function() feed('4Grb') screen:expect([[ | - a repeated {2:line} | + a repeated {2:line } | {2:a} repeated line | - ^b repeated {2:line} | + ^b repeated {2:line } | {2:a} repeated line | {1:~ }| {4:search hit BOTTOM, continuing at TOP} | diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index dbc92ca222..7dcd4cff25 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, command = helpers.clear, helpers.feed, helpers.command local source = helpers.source +local meths = helpers.meths describe('Signs', function() local screen @@ -155,9 +156,12 @@ describe('Signs', function() {0:~ }| | ]]) + -- Check that 'statuscolumn' correctly applies numhl + command('set statuscolumn=%s%=%l\\ ') + screen:expect_unchanged() end) - it('higlights the cursorline sign with culhl', function() + it('highlights the cursorline sign with culhl', function() feed('ia<cr>b<cr>c<esc>') command('sign define piet text=>> texthl=Search culhl=ErrorMsg') command('sign place 1 line=1 name=piet buffer=1') @@ -232,11 +236,13 @@ describe('Signs', function() | ]]) command('set cursorlineopt=number') + command('hi! link SignColumn IncSearch') + feed('Go<esc>2G') screen:expect([[ {1:>>}a | {8:>>}^b | {1:>>}c | - {0:~ }| + {5: } | {0:~ }| {0:~ }| {0:~ }| @@ -248,6 +254,9 @@ describe('Signs', function() {0:~ }| | ]]) + -- Check that 'statuscolumn' cursorline/signcolumn highlights are the same (#21726) + command('set statuscolumn=%s') + screen:expect_unchanged() end) it('multiple signs #9295', function() @@ -592,4 +601,88 @@ describe('Signs', function() ]]) end) end) + + it('signcolumn width is updated when removing all signs after deleting lines', function() + meths.buf_set_lines(0, 0, 1, true, {'a', 'b', 'c', 'd', 'e'}) + command('sign define piet text=>>') + command('sign place 10001 line=1 name=piet') + command('sign place 10002 line=5 name=piet') + command('2delete') + command('sign unplace 10001') + screen:expect([[ + {2: }a | + {2: }^c | + {2: }d | + >>e | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + command('sign unplace 10002') + screen:expect([[ + a | + ^c | + d | + e | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) + + it('signcolumn width is updated when removing all signs after inserting lines', function() + meths.buf_set_lines(0, 0, 1, true, {'a', 'b', 'c', 'd', 'e'}) + command('sign define piet text=>>') + command('sign place 10001 line=1 name=piet') + command('sign place 10002 line=5 name=piet') + command('copy .') + command('sign unplace 10001') + screen:expect([[ + {2: }a | + {2: }^a | + {2: }b | + {2: }c | + {2: }d | + >>e | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + command('sign unplace 10002') + screen:expect([[ + a | + ^a | + b | + c | + d | + e | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end) end) diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua index de77100cc0..361f83d1ce 100644 --- a/test/functional/ui/spell_spec.lua +++ b/test/functional/ui/spell_spec.lua @@ -5,8 +5,8 @@ local Screen = require('test.functional.ui.screen') local clear = helpers.clear local feed = helpers.feed local insert = helpers.insert -local uname = helpers.uname local command = helpers.command +local is_os = helpers.is_os describe("'spell'", function() local screen @@ -19,11 +19,15 @@ describe("'spell'", function() [0] = {bold=true, foreground=Screen.colors.Blue}, [1] = {special = Screen.colors.Red, undercurl = true}, [2] = {special = Screen.colors.Blue1, undercurl = true}, + [3] = {foreground = tonumber('0x6a0dad')}, + [4] = {foreground = Screen.colors.Magenta}, + [5] = {bold = true, foreground = Screen.colors.SeaGreen}, + [6] = {foreground = Screen.colors.Red}, }) end) it('joins long lines #7937', function() - if uname() == 'openbsd' then pending('FIXME #12104', function() end) return end + if is_os('openbsd') then pending('FIXME #12104', function() end) return end command('set spell') insert([[ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod @@ -47,6 +51,7 @@ describe("'spell'", function() end) + -- oldtest: Test_spell_screendump() it('has correct highlight at start of line', function() insert([[ "This is some text without any spell errors. Everything", @@ -66,6 +71,96 @@ describe("'spell'", function() "with missing caps here.", | ^ | | - ]]) + ]]) + end) + + it('"noplainbuffer" and syntax #20385', function() + command('set filetype=c') + command('syntax on') + command('set spell') + insert([[ + #include <stdbool.h> + bool func(void);]]) + screen:expect([[ + {3:#include }{4:<stdbool.h>} | + {5:bool} func({5:void})^; | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + feed('[s') + screen:expect([[ + {3:#include }{4:<stdbool.h>} | + {5:bool} func({5:void})^; | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {6:search hit TOP, continuing at BOTTOM} | + ]]) + -- "noplainbuffer" shouldn't change spellchecking behavior with syntax enabled + command('set spelloptions+=noplainbuffer') + screen:expect_unchanged() + feed(']s') + screen:expect([[ + {3:#include }{4:<stdbool.h>} | + {5:bool} func({5:void})^; | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {6:search hit BOTTOM, continuing at TOP} | + ]]) + -- no spellchecking with "noplainbuffer" and syntax disabled + command('syntax off') + screen:expect([[ + #include <stdbool.h> | + bool func(void)^; | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {6:search hit BOTTOM, continuing at TOP} | + ]]) + feed('[s') + screen:expect([[ + #include <stdbool.h> | + bool func(void)^; | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {6:search hit TOP, continuing at BOTTOM} | + ]]) + -- everything is spellchecked without "noplainbuffer" with syntax disabled + command('set spelloptions&') + screen:expect([[ + #include <{1:stdbool}.h> | + {1:bool} {1:func}(void)^; | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {6:search hit TOP, continuing at BOTTOM} | + ]]) + feed(']s') + screen:expect([[ + #include <{1:^stdbool}.h> | + {1:bool} {1:func}(void); | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {6:search hit BOTTOM, continuing at TOP} | + ]]) end) end) diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua new file mode 100644 index 0000000000..ae3b95fb0f --- /dev/null +++ b/test/functional/ui/statuscolumn_spec.lua @@ -0,0 +1,462 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear = helpers.clear +local command = helpers.command +local eq = helpers.eq +local eval = helpers.eval +local exec_lua = helpers.exec_lua +local feed = helpers.feed +local meths = helpers.meths +local pcall_err = helpers.pcall_err + +describe('statuscolumn', function() + local screen + before_each(function() + clear('--cmd', 'set number nuw=1 | call setline(1, repeat(["aaaaa"], 16)) | norm GM') + screen = Screen.new() + screen:attach() + end) + + it("fails with invalid 'statuscolumn'", function() + command([[set stc=%{v:relnum?v:relnum:(v:lnum==5?invalid:v:lnum)}\ ]]) + screen:expect([[ + 4 aaaaa | + 3 aaaaa | + 2 aaaaa | + 1 aaaaa | + 8 ^aaaaa | + 1 aaaaa | + 2 aaaaa | + 3 aaaaa | + 4 aaaaa | + 5 aaaaa | + 6 aaaaa | + 7 aaaaa | + 8 aaaaa | + | + ]]) + command('norm 5G') + eq('Vim(redraw):E121: Undefined variable: invalid', pcall_err(command, 'redraw!')) + eq('', eval('&statuscolumn')) + end) + + it("widens with irregular 'statuscolumn' width", function() + command([[set stc=%{v:relnum?v:relnum:(v:lnum==5?'bbbbb':v:lnum)}]]) + command('norm 5G | redraw!') + screen:expect([[ + 1 aaaaa | + bbbbba^eaaa | + 1 aaaaa | + 2 aaaaa | + 3 aaaaa | + 4 aaaaa | + 5 aaaaa | + 6 aaaaa | + 7 aaaaa | + 8 aaaaa | + 9 aaaaa | + 10 aaaaa | + 11 aaaaa | + | + ]]) + end) + + it("works with 'number' and 'relativenumber'", function() + command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) + screen:expect([[ + 4 │aaaaa | + 5 │aaaaa | + 6 │aaaaa | + 7 │aaaaa | + 8 │^aaaaa | + 9 │aaaaa | + 10│aaaaa | + 11│aaaaa | + 12│aaaaa | + 13│aaaaa | + 14│aaaaa | + 15│aaaaa | + 16│aaaaa | + | + ]]) + command([[set stc=%l%=%{&rnu?'\ ':''}%r│]]) + screen:expect_unchanged() + command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) + command('set relativenumber') + screen:expect([[ + 4 4│aaaaa | + 5 3│aaaaa | + 6 2│aaaaa | + 7 1│aaaaa | + 8 0│^aaaaa | + 9 1│aaaaa | + 10 2│aaaaa | + 11 3│aaaaa | + 12 4│aaaaa | + 13 5│aaaaa | + 14 6│aaaaa | + 15 7│aaaaa | + 16 8│aaaaa | + | + ]]) + command([[set stc=%l%=%{&rnu?'\ ':''}%r│]]) + screen:expect_unchanged() + command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) + command('norm 12GH') + screen:expect([[ + 4 0│^aaaaa | + 5 1│aaaaa | + 6 2│aaaaa | + 7 3│aaaaa | + 8 4│aaaaa | + 9 5│aaaaa | + 10 6│aaaaa | + 11 7│aaaaa | + 12 8│aaaaa | + 13 9│aaaaa | + 14 10│aaaaa | + 15 11│aaaaa | + 16 12│aaaaa | + | + ]]) + command([[set stc=%l%=%{&rnu?'\ ':''}%r│]]) + screen:expect_unchanged() + command([[set stc=%{&nu?v:lnum:''}%=%{&rnu?'\ '.v:relnum:''}│]]) + end) + + it("works with highlighted 'statuscolumn'", function() + command([[set stc=%#NonText#%{&nu?v:lnum:''}]] .. + [[%=%{&rnu&&(v:lnum%2)?'\ '.v:relnum:''}]] .. + [[%#LineNr#%{&rnu&&!(v:lnum%2)?'\ '.v:relnum:''}│]]) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {foreground = Screen.colors.Brown}, + }) + screen:expect([[ + {0:4 }{1:│}aaaaa | + {0:5 }{1:│}aaaaa | + {0:6 }{1:│}aaaaa | + {0:7 }{1:│}aaaaa | + {0:8 }{1:│}^aaaaa | + {0:9 }{1:│}aaaaa | + {0:10}{1:│}aaaaa | + {0:11}{1:│}aaaaa | + {0:12}{1:│}aaaaa | + {0:13}{1:│}aaaaa | + {0:14}{1:│}aaaaa | + {0:15}{1:│}aaaaa | + {0:16}{1:│}aaaaa | + | + ]]) + command('set relativenumber') + screen:expect([[ + {0:4 }{1: 4│}aaaaa | + {0:5 3}{1:│}aaaaa | + {0:6 }{1: 2│}aaaaa | + {0:7 1}{1:│}aaaaa | + {0:8 }{1: 0│}^aaaaa | + {0:9 1}{1:│}aaaaa | + {0:10}{1: 2│}aaaaa | + {0:11 3}{1:│}aaaaa | + {0:12}{1: 4│}aaaaa | + {0:13 5}{1:│}aaaaa | + {0:14}{1: 6│}aaaaa | + {0:15 7}{1:│}aaaaa | + {0:16}{1: 8│}aaaaa | + | + ]]) + command('set nonumber') + screen:expect([[ + {1:4│}aaaaa | + {0:3}{1:│}aaaaa | + {1:2│}aaaaa | + {0:1}{1:│}aaaaa | + {1:0│}^aaaaa | + {0:1}{1:│}aaaaa | + {1:2│}aaaaa | + {0:3}{1:│}aaaaa | + {1:4│}aaaaa | + {0:5}{1:│}aaaaa | + {1:6│}aaaaa | + {0:7}{1:│}aaaaa | + {1:8│}aaaaa | + | + ]]) + end) + + 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] = {background = Screen.colors.Grey90}, + }) + 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:@@@}| + | + ]]) + command("set stc=%C%s%=%l│\\ ") + screen:expect_unchanged() + command('set signcolumn=auto:2 foldcolumn=auto') + command('sign define piet1 text=>> texthl=LineNr') + command('sign define piet2 text=>! texthl=NonText') + command('sign place 1 line=4 name=piet1 buffer=1') + command('sign place 2 line=5 name=piet2 buffer=1') + 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 | + {1:>>}{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:@@@}| + | + ]]) + 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 | + | + ]]) + 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: }{5:^+-- 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 | + | + ]]) + -- 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: }{5:^+-- 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 | + | + ]]) + -- v:relnum is the same value on wrapped lines + command([[set stc=%C%=\ %{v:relnum}│%s\ ]]) + screen:expect([[ + {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 4│}{2: }{1: }aaaaaa | + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 3│}{2: }{1: }aaaaaa | + {2: }{1: 2│>>}{0:>!}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 2│}{2: }{1: }aaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 1│}{2: }{1: }aaaaaa | + {2:+}{4: 0│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 1│}{2: }{1: }aaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: 2│}{2: }{1: }aaaaaa | + | + ]]) + command([[set stc=%C%=\ %{v:virtnum?'':v:relnum}│%s\ ]]) + screen:expect([[ + {2: }{1: 4│>>}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaa | + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaa | + {2: }{1: 2│>>}{0:>!}{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaa | + {2:+}{4: 0│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaa | + | + ]]) + -- Up to 9 signs in a line + command('set signcolumn=auto:9 foldcolumn=auto') + command('sign place 5 line=6 name=piet1 buffer=1') + command('sign place 6 line=6 name=piet2 buffer=1') + command('sign place 7 line=6 name=piet1 buffer=1') + command('sign place 8 line=6 name=piet2 buffer=1') + command('sign place 9 line=6 name=piet1 buffer=1') + 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: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 3│}{0:>!}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>>}{0:>!}{1:>> }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | + {2:+}{4: 0│}{2: }{4: }{5:^+-- 1 line: aaaaaaaaaaaaaaaaa}| + {2: }{1: 1│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | + {2: }{1: 2│}{2: }{1: }aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {2: }{1: │}{2: }{1: }aaaaaaaaaaaaaaaaaaaa | + | + ]]) + -- Status column is re-evaluated for virt_lines, buffer line, and wrapped line + exec_lua([[ + local ns = vim.api.nvim_create_namespace("ns") + vim.api.nvim_buf_set_extmark(0, ns, 5, 0, { + virt_lines_above = true, virt_lines = {{{"virt_line above", ""}}} }) + vim.api.nvim_buf_set_extmark(0, ns, 4, 0, { virt_lines = {{{"virt_line", ""}}} }) + ]]) + command('set foldcolumn=0 signcolumn=no') + 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-2 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}{5:^+-- 1 line: aaaaaaaaaaaaaaaaaaaaaaaaaaaaa}| + {1:buffer 0 9}aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa| + {1:wrapped 1 9}aaaaaaaa | + | + ]]) + end) + + it("works with 'statuscolumn' clicks", function() + command('set mousemodel=extend') + command([[ + function! MyClickFunc(minwid, clicks, button, mods) + let g:testvar = printf("%d %d %s %d", a:minwid, a:clicks, a:button, getmousepos().line) + if a:mods !=# ' ' + let g:testvar ..= '(' .. a:mods .. ')' + endif + endfunction + set stc=%0@MyClickFunc@%=%l%T + ]]) + meths.input_mouse('left', 'press', '', 0, 0, 0) + eq('0 1 l 4', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 0, 0) + eq('0 2 l 4', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 0, 0) + eq('0 3 l 4', eval("g:testvar")) + meths.input_mouse('left', 'press', '', 0, 0, 0) + eq('0 4 l 4', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 3, 0) + eq('0 1 r 7', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 3, 0) + eq('0 2 r 7', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 3, 0) + eq('0 3 r 7', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 3, 0) + eq('0 4 r 7', eval("g:testvar")) + command('set laststatus=2 winbar=%f') + command('let g:testvar=""') + -- Check that winbar click doesn't register as statuscolumn click + meths.input_mouse('right', 'press', '', 0, 0, 0) + eq('', eval("g:testvar")) + -- Check that statusline click doesn't register as statuscolumn click + meths.input_mouse('right', 'press', '', 0, 12, 0) + eq('', eval("g:testvar")) + end) + + it('click labels do not leak memory', function() + command([[ + set laststatus=2 + setlocal statuscolumn=%0@MyClickFunc@abcd%T + 4vsplit + setlocal statusline=abcd + redrawstatus + setlocal statusline= + only + redraw + ]]) + end) + + it('works with foldcolumn', function() + -- Fits maximum multibyte foldcolumn #21759 + command([[set stc=%C%=%l\ fdc=9 fillchars=foldsep:𒀀]]) + for _ = 0,8 do command('norm zfjzo') end + -- 'statuscolumn' is not drawn for `virt_lines_leftcol` lines + exec_lua([[ + local ns = vim.api.nvim_create_namespace("ns") + vim.api.nvim_buf_set_extmark(0, ns, 6, 0, { + virt_lines_leftcol = true, virt_lines = {{{"virt", ""}}} }) + vim.api.nvim_buf_set_extmark(0, ns, 7, 0, { + virt_lines_leftcol = true, virt_lines = {{{"virt", ""}}} }) + ]]) + feed('lh') -- force update wcol/row + screen:expect([[ + 4 aaaaa | + 5 aaaaa | + 6 aaaaa | + 7 aaaaa | + virt | + --------- 8 ^aaaaa | + virt | + 𒀀𒀀𒀀𒀀𒀀𒀀𒀀𒀀𒀀 9 aaaaa | + 10 aaaaa | + 11 aaaaa | + 12 aaaaa | + 13 aaaaa | + 14 aaaaa | + | + ]]) + command('set stc=') -- also for the default sign column + screen:expect_unchanged() + end) +end) diff --git a/test/functional/ui/statusline_spec.lua b/test/functional/ui/statusline_spec.lua index add5144e1b..1c184ff27d 100644 --- a/test/functional/ui/statusline_spec.lua +++ b/test/functional/ui/statusline_spec.lua @@ -164,6 +164,24 @@ describe('statusline clicks', function() meths.input_mouse('right', 'press', '', 0, 6, 5) eq('0 1 r', eval("g:testvar")) end) + + it('no memory leak with zero-width click labels', function() + command([[ + let &stl = '%@Test@%T%@MyClickFunc@%=%T%@Test@' + ]]) + meths.input_mouse('left', 'press', '', 0, 6, 0) + eq('0 1 l', eval("g:testvar")) + meths.input_mouse('right', 'press', '', 0, 6, 39) + eq('0 1 r', eval("g:testvar")) + end) + + it('no memory leak with truncated click labels', function() + command([[ + let &stl = '%@MyClickFunc@foo%X' .. repeat('a', 40) .. '%<t%@Test@bar%X%@Test@baz' + ]]) + meths.input_mouse('left', 'press', '', 0, 6, 2) + eq('0 1 l', eval("g:testvar")) + end) end) describe('global statusline', function() @@ -178,6 +196,7 @@ describe('global statusline', function() [2] = {bold = true, reverse = true}; [3] = {bold = true}; [4] = {reverse = true}; + [5] = {bold = true, foreground = Screen.colors.Fuchsia}; }) command('set laststatus=3') command('set ruler') @@ -398,6 +417,106 @@ describe('global statusline', function() meths.input_mouse('left', 'drag', '', 0, 14, 10) eq(1, meths.get_option('cmdheight')) end) + + it('cmdline row is correct after setting cmdheight #20514', function() + command('botright split test/functional/fixtures/bigfile.txt') + meths.set_option('cmdheight', 1) + feed('L') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ────────────────────────────────────────────────────────────| + 0000;<control>;Cc;0;BN;;;;;N;NULL;;;; | + 0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; | + 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; | + 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; | + 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}| + | + ]]) + feed('j') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ────────────────────────────────────────────────────────────| + 0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; | + 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; | + 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; | + 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; | + 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%}| + | + ]]) + meths.set_option('showtabline', 2) + screen:expect([[ + {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }| + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ────────────────────────────────────────────────────────────| + 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; | + 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; | + 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; | + 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%}| + | + ]]) + meths.set_option('cmdheight', 0) + screen:expect([[ + {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }| + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ────────────────────────────────────────────────────────────| + 0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;; | + 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; | + 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; | + 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; | + 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%}| + ]]) + meths.set_option('cmdheight', 1) + screen:expect([[ + {3: }{5:2}{3: t/f/f/bigfile.txt }{4: }| + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + ────────────────────────────────────────────────────────────| + 0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;; | + 0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;; | + 0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;; | + 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%}| + | + ]]) + end) end) it('statusline does not crash if it has Arabic characters #19447', function() @@ -444,3 +563,29 @@ it('statusline is redrawn with :resize from <Cmd> mapping #19629', function() | ]]) 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:~ }| + {0:~}│{0:~ }| + {0:~}│{0:~ }| + {0:~}│{0:~ }| + {0:~}│{0:~ }| + {1:< }{2:[No Name] }| + | + ]]) + feed('1234') + screen:expect_unchanged() +end) diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua index f790597140..1391985823 100644 --- a/test/functional/ui/syntax_conceal_spec.lua +++ b/test/functional/ui/syntax_conceal_spec.lua @@ -4,7 +4,7 @@ local clear, feed, command = helpers.clear, helpers.feed, helpers.command local eq = helpers.eq local insert = helpers.insert local poke_eventloop = helpers.poke_eventloop -local expect_exit = helpers.expect_exit +local exec = helpers.exec describe('Screen', function() local screen @@ -947,7 +947,7 @@ describe('Screen', function() {0:~ }| | ]]} - eq({{2, 0, {{'c', 0, 3}}}}, grid_lines) + eq({{2, 0, {{'c', 0, 3}, {' ', 0, 50}}}, {3, 0, {{' ', 0, 53}}}}, grid_lines) end) it('K_EVENT should not cause extra redraws with concealcursor #13196', function() @@ -994,31 +994,39 @@ describe('Screen', function() {0:~ }| | ]]} - eq({{2, 0, {{'c', 0, 3}}}}, grid_lines) + eq({{2, 0, {{'c', 0, 3}, {' ', 0, 50}}}}, grid_lines) + grid_lines = {} poke_eventloop() -- causes K_EVENT key screen:expect_unchanged() - eq({{2, 0, {{'c', 0, 3}}}}, grid_lines) + eq({}, grid_lines) -- no redraw was done end) - -- Copy of Test_cursor_column_in_concealed_line_after_window_scroll in - -- test/functional/ui/syntax_conceal_spec.lua. - describe('concealed line after window scroll', function() - after_each(function() - expect_exit(command, ':qall!') - os.remove('Xcolesearch') - end) - - it('has the correct cursor column', function() + describe('concealed line has the correct cursor column', function() + -- oldtest: Test_cursor_column_in_concealed_line_after_window_scroll() + it('after window scroll', function() insert([[ - 3split - let m = matchadd('Conceal', '=') - setl conceallevel=2 concealcursor=nc - normal gg - "==expr== - ]]) + 3split + let m = matchadd('Conceal', '=') + setl conceallevel=2 concealcursor=nc + normal gg + "==expr==]]) + feed('gg') + command('file Xcolesearch') + command('set nomodified') - command('write Xcolesearch') - feed(":so %<CR>") + command('so') + screen:expect{grid=[[ + ^3split | + let m matchadd('Conceal', '') | + setl conceallevel2 concealcursornc | + {2:Xcolesearch }| + 3split | + let m = matchadd('Conceal', '=') | + setl conceallevel=2 concealcursor=nc | + normal gg | + {3:Xcolesearch }| + | + ]]} -- Jump to something that is beyond the bottom of the window, -- so there's a scroll down. @@ -1032,13 +1040,42 @@ describe('Screen', function() normal gg | "{5:^expr} | {2:Xcolesearch }| + 3split | + let m = matchadd('Conceal', '=') | + setl conceallevel=2 concealcursor=nc | normal gg | - "=={5:expr}== | - | - {0:~ }| {3:Xcolesearch }| /expr | ]]} end) + + -- oldtest: Test_cursor_column_in_concealed_line_after_leftcol_change() + it('after leftcol change', function() + exec([[ + 0put = 'ab' .. repeat('-', &columns) .. 'c' + call matchadd('Conceal', '-') + set nowrap ss=0 cole=3 cocu=n + ]]) + + -- Go to the end of the line (3 columns beyond the end of the screen). + -- Horizontal scroll would center the cursor in the screen line, but conceal + -- makes it go to screen column 1. + feed('$') + + -- Are the concealed parts of the current line really hidden? + -- Is the window's cursor column properly updated for conceal? + screen:expect{grid=[[ + ^c | + | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]} + end) end) end) diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua index 809486d4db..2cdec62d01 100644 --- a/test/functional/ui/tabline_spec.lua +++ b/test/functional/ui/tabline_spec.lua @@ -84,3 +84,45 @@ describe('ui/ext_tabline', function() end} end) end) + +describe("tabline", function() + local screen + + before_each(function() + clear() + screen = Screen.new(42, 5) + screen:attach() + end) + + it('redraws when tabline option is set', function() + command('set tabline=asdf') + command('set showtabline=2') + screen:expect{grid=[[ + {1:asdf }| + ^ | + {2:~ }| + {2:~ }| + | + ]], attr_ids={ + [1] = {reverse = true}; + [2] = {bold = true, foreground = Screen.colors.Blue1}; + }} + command('set tabline=jkl') + screen:expect{grid=[[ + {1:jkl }| + ^ | + {2:~ }| + {2:~ }| + | + ]], attr_ids={ + [1] = {reverse = true}; + [2] = {bold = true, foreground = Screen.colors.Blue}; + }} + end) + + it('click definitions do not leak memory #21765', function() + command('set tabline=%@MyClickFunc@MyClickText%T') + command('set showtabline=2') + command('redrawtabline') + end) +end) diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 98398bc7a1..50466c9473 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -1,13 +1,13 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear, feed, command = helpers.clear, helpers.feed, helpers.command -local iswin = helpers.iswin local funcs = helpers.funcs local meths = helpers.meths local eq = helpers.eq local eval = helpers.eval local retry = helpers.retry local testprg = helpers.testprg +local is_os = helpers.is_os describe("'wildmenu'", function() local screen @@ -159,7 +159,7 @@ describe("'wildmenu'", function() -- must wait the full timeout. So make it reasonable. screen.timeout = 1000 - if not iswin() then + if not is_os('win') then command('set shell=sh') -- Need a predictable "$" prompt. command('let $PS1 = "$"') end @@ -169,7 +169,7 @@ describe("'wildmenu'", function() -- Check for a shell prompt to verify that the terminal loaded. retry(nil, nil, function() - if iswin() then + if is_os('win') then eq('Microsoft', eval("matchstr(join(getline(1, '$')), 'Microsoft')")) else eq('$', eval([[matchstr(getline(1), '\$')]])) @@ -184,11 +184,10 @@ describe("'wildmenu'", function() screen:expect_unchanged() end) - it('wildmode=list,full and display+=msgsep interaction #10092', function() + it('wildmode=list,full and messages interaction #10092', function() -- Need more than 5 rows, else tabline is covered and will be redrawn. screen:try_resize(25, 7) - command('set display+=msgsep') command('set wildmenu wildmode=list,full') command('set showtabline=2') feed(':set wildm<tab>') @@ -223,44 +222,6 @@ describe("'wildmenu'", function() ]]) end) - it('wildmode=list,full and display-=msgsep interaction', function() - -- Need more than 5 rows, else tabline is covered and will be redrawn. - screen:try_resize(25, 7) - - command('set display-=msgsep') - command('set wildmenu wildmode=list,full') - feed(':set wildm<tab>') - screen:expect([[ - ~ | - ~ | - ~ | - ~ | - :set wildm | - wildmenu wildmode | - :set wildm^ | - ]]) - feed('<tab>') -- trigger wildmode full - screen:expect([[ - ~ | - ~ | - ~ | - :set wildm | - wildmenu wildmode | - wildmenu wildmode | - :set wildmenu^ | - ]]) - feed('<Esc>') - screen:expect([[ - ^ | - ~ | - ~ | - ~ | - ~ | - ~ | - | - ]]) - end) - it('wildmode=longest,list', function() -- Need more than 5 rows, else tabline is covered and will be redrawn. screen:try_resize(25, 7) @@ -365,7 +326,6 @@ describe("'wildmenu'", function() screen:try_resize(25, 7) command('set laststatus=2') - command('set display+=msgsep') feed(':set wildm') feed('<c-d>') screen:expect([[ @@ -461,20 +421,20 @@ end) describe('command line completion', function() local screen before_each(function() + clear() screen = Screen.new(40, 5) screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, [2] = {foreground = Screen.colors.Grey0, background = Screen.colors.Yellow}, [3] = {bold = true, reverse = true}, }) + screen:attach() end) after_each(function() os.remove('Xtest-functional-viml-compl-dir') end) it('lists directories with empty PATH', function() - clear() - screen:attach() local tmp = funcs.tempname() command('e '.. tmp) command('cd %:h') @@ -491,8 +451,6 @@ describe('command line completion', function() end) it('completes env var names #9681', function() - clear() - screen:attach() command('let $XTEST_1 = "foo" | let $XTEST_2 = "bar"') command('set wildmenu wildmode=full') feed(':!echo $XTEST_<tab>') @@ -521,6 +479,58 @@ describe('command line completion', function() :!echo $XTEST_1AaあB^ | ]]) end) + + it('does not leak memory with <S-Tab> with wildmenu and only one match #19874', function() + meths.set_option('wildmenu', true) + meths.set_option('wildmode', 'full') + meths.set_option('wildoptions', 'pum') + + feed(':sign unpla<S-Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplace^ | + ]]) + + feed('<Space>buff<Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplace buffer=^ | + ]]) + end) + + it('does not show matches with <S-Tab> without wildmenu with wildmode=full', function() + meths.set_option('wildmenu', false) + meths.set_option('wildmode', 'full') + + feed(':sign <S-Tab>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + :sign unplace^ | + ]]) + end) + + it('shows matches with <S-Tab> without wildmenu with wildmode=list', function() + meths.set_option('wildmenu', false) + meths.set_option('wildmode', 'list') + + feed(':sign <S-Tab>') + screen:expect([[ + {3: }| + :sign define | + define list undefine | + jump place unplace | + :sign unplace^ | + ]]) + end) end) describe('ui/ext_wildmenu', function() diff --git a/test/functional/ui/winbar_spec.lua b/test/functional/ui/winbar_spec.lua index 8976c4371f..ece27ec3ff 100644 --- a/test/functional/ui/winbar_spec.lua +++ b/test/functional/ui/winbar_spec.lua @@ -7,6 +7,8 @@ local meths = helpers.meths local eq = helpers.eq local poke_eventloop = helpers.poke_eventloop local feed = helpers.feed +local funcs = helpers.funcs +local curwin = helpers.curwin local pcall_err = helpers.pcall_err describe('winbar', function() @@ -48,6 +50,11 @@ describe('winbar', function() {3:~ }| | ]]) + -- winbar is excluded from the heights returned by winheight() and getwininfo() + eq(11, funcs.winheight(0)) + local win_info = funcs.getwininfo(curwin().id)[1] + eq(11, win_info.height) + eq(1, win_info.winbar) end) it('works with custom \'fillchars\' value', function() |